Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 13 Jul 2019 22:57:37 +0000 (15:57 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 13 Jul 2019 22:57:37 +0000 (15:57 -0700)
Pull networking fixes from David Miller:

 1) Fix excessive stack usage in cxgb4, from Arnd Bergmann.

 2) Missing skb queue lock init in tipc, from Chris Packham.

 3) Fix some regressions in ipv6 flow label handling, from Eric Dumazet.

 4) Elide flow dissection of local packets in FIB rules, from Petar
    Penkov.

 5) Fix TLS support build failure in mlx5, from Tariq Toukab.

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (36 commits)
  ppp: mppe: Revert "ppp: mppe: Add softdep to arc4"
  net: dsa: qca8k: replace legacy gpio include
  net: hisilicon: Use devm_platform_ioremap_resource
  cxgb4: reduce kernel stack usage in cudbg_collect_mem_region()
  tipc: ensure head->lock is initialised
  tc-tests: updated skbedit tests
  nfp: flower: ensure ip protocol is specified for L4 matches
  nfp: flower: fix ethernet check on match fields
  net/mlx5e: Provide cb_list pointer when setting up tc block on rep
  net: phy: make exported variables non-static
  net: sched: Fix NULL-pointer dereference in tc_indr_block_ing_cmd()
  davinci_cpdma: don't cast dma_addr_t to pointer
  net: openvswitch: do not update max_headroom if new headroom is equal to old headroom
  net/mlx5e: Convert single case statement switch statements into if statements
  net/mlx5: E-Switch, Reduce ingress acl modify metadata stack usage
  net/mlx5e: Fix unused variable warning when CONFIG_MLX5_ESWITCH is off
  net/mlx5e: Fix compilation error in TLS code
  ipv6: fix static key imbalance in fl_create()
  ipv6: fix potential crash in ip6_datagram_dst_update()
  ipv6: tcp: fix flowlabels reflection for RST packets
  ...

2153 files changed:
Documentation/ABI/obsolete/sysfs-driver-hid-roccat-pyra
Documentation/ABI/stable/sysfs-driver-mlxreg-io
Documentation/ABI/testing/debugfs-cros-ec [new file with mode: 0644]
Documentation/ABI/testing/debugfs-driver-habanalabs
Documentation/ABI/testing/debugfs-wilco-ec
Documentation/ABI/testing/procfs-smaps_rollup
Documentation/ABI/testing/pstore
Documentation/ABI/testing/sysfs-bus-event_source-devices-format
Documentation/ABI/testing/sysfs-bus-i2c-devices-hm6352
Documentation/ABI/testing/sysfs-bus-iio
Documentation/ABI/testing/sysfs-bus-iio-cros-ec
Documentation/ABI/testing/sysfs-bus-iio-distance-srf08
Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4371 [new file with mode: 0644]
Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935
Documentation/ABI/testing/sysfs-bus-pci-devices-aer_stats
Documentation/ABI/testing/sysfs-bus-pci-devices-cciss
Documentation/ABI/testing/sysfs-bus-usb-devices-usbsevseg
Documentation/ABI/testing/sysfs-class-backlight-driver-lm3533
Documentation/ABI/testing/sysfs-class-cxl
Documentation/ABI/testing/sysfs-class-devfreq
Documentation/ABI/testing/sysfs-class-led-driver-lm3533
Documentation/ABI/testing/sysfs-class-leds-gt683r
Documentation/ABI/testing/sysfs-class-powercap
Documentation/ABI/testing/sysfs-class-uwb_rc
Documentation/ABI/testing/sysfs-driver-altera-cvp
Documentation/ABI/testing/sysfs-driver-habanalabs
Documentation/ABI/testing/sysfs-driver-hid
Documentation/ABI/testing/sysfs-driver-hid-roccat-kone
Documentation/ABI/testing/sysfs-driver-ppi
Documentation/ABI/testing/sysfs-driver-st
Documentation/ABI/testing/sysfs-driver-wacom
Documentation/ABI/testing/sysfs-fs-f2fs
Documentation/ABI/testing/sysfs-kernel-fscaps
Documentation/ABI/testing/sysfs-kernel-vmcoreinfo
Documentation/ABI/testing/sysfs-platform-wilco-ec [new file with mode: 0644]
Documentation/admin-guide/LSM/LoadPin.rst
Documentation/admin-guide/cgroup-v2.rst
Documentation/admin-guide/devices.txt
Documentation/admin-guide/kernel-parameters.txt
Documentation/arm64/booting.rst
Documentation/arm64/silicon-errata.rst
Documentation/core-api/kernel-api.rst
Documentation/dev-tools/kmemleak.rst
Documentation/device-mapper/snapshot.rst
Documentation/devicetree/bindings/Makefile
Documentation/devicetree/bindings/arm/al,alpine.txt [deleted file]
Documentation/devicetree/bindings/arm/al,alpine.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/arm-boards
Documentation/devicetree/bindings/arm/axxia.txt [deleted file]
Documentation/devicetree/bindings/arm/axxia.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt
Documentation/devicetree/bindings/arm/coresight.txt
Documentation/devicetree/bindings/arm/cpus.yaml
Documentation/devicetree/bindings/arm/digicolor.txt [deleted file]
Documentation/devicetree/bindings/arm/digicolor.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt
Documentation/devicetree/bindings/arm/idle-states.txt
Documentation/devicetree/bindings/arm/moxart.txt [deleted file]
Documentation/devicetree/bindings/arm/moxart.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/nxp/lpc32xx.txt [deleted file]
Documentation/devicetree/bindings/arm/nxp/lpc32xx.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/psci.txt [deleted file]
Documentation/devicetree/bindings/arm/psci.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/qcom.yaml
Documentation/devicetree/bindings/arm/rda.txt [deleted file]
Documentation/devicetree/bindings/arm/rda.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/common-properties.txt
Documentation/devicetree/bindings/display/simple-framebuffer.yaml
Documentation/devicetree/bindings/extcon/extcon-fsa9480.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/accel/adxl345.txt [deleted file]
Documentation/devicetree/bindings/iio/accel/adxl372.txt [deleted file]
Documentation/devicetree/bindings/iio/adc/adi,ad7124.txt [deleted file]
Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/adi,ad7780.txt [deleted file]
Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt
Documentation/devicetree/bindings/iio/chemical/sensirion,sps30.txt [deleted file]
Documentation/devicetree/bindings/iio/chemical/sensirion,sps30.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/frequency/adf4371.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/light/isl29018.txt [deleted file]
Documentation/devicetree/bindings/iio/light/isl29018.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/light/tsl2583.txt [deleted file]
Documentation/devicetree/bindings/iio/light/tsl2583.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/light/tsl2772.txt [deleted file]
Documentation/devicetree/bindings/iio/light/tsl2772.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/input/elan_i2c.txt
Documentation/devicetree/bindings/ipmi/npcm7xx-kcs-bmc.txt
Documentation/devicetree/bindings/leds/backlight/lm3630a-backlight.yaml
Documentation/devicetree/bindings/memory-controllers/ingenic,jz4780-nemc.txt
Documentation/devicetree/bindings/misc/xlnx,sd-fec.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/allwinner,sun4i-a10-mmc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt
Documentation/devicetree/bindings/mmc/mmc-controller.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/mmc.txt
Documentation/devicetree/bindings/mmc/renesas,sdhi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/sdhci-am654.txt
Documentation/devicetree/bindings/mmc/sdhci-sprd.txt
Documentation/devicetree/bindings/mmc/sunxi-mmc.txt [deleted file]
Documentation/devicetree/bindings/mmc/tmio_mmc.txt [deleted file]
Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml
Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
Documentation/devicetree/bindings/mtd/cadence-quadspi.txt
Documentation/devicetree/bindings/mtd/cypress,hyperflash.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/stm32-quadspi.txt [deleted file]
Documentation/devicetree/bindings/mtd/ti,am654-hbmc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mux/mmio-mux.txt [deleted file]
Documentation/devicetree/bindings/mux/reg-mux.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/allwinner,sun4i-a10-emac.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/net/allwinner,sun4i-a10-mdio.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/net/allwinner,sun4i-emac.txt [deleted file]
Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt [deleted file]
Documentation/devicetree/bindings/net/allwinner,sun7i-a20-gmac.txt [deleted file]
Documentation/devicetree/bindings/net/allwinner,sun7i-a20-gmac.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/net/dwmac-sun8i.txt [deleted file]
Documentation/devicetree/bindings/net/ethernet-controller.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/net/ethernet-phy.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/net/ethernet.txt
Documentation/devicetree/bindings/net/fixed-link.txt
Documentation/devicetree/bindings/net/mdio.txt
Documentation/devicetree/bindings/net/mdio.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/net/phy.txt
Documentation/devicetree/bindings/net/snps,dwmac.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/net/stmmac.txt
Documentation/devicetree/bindings/nvmem/allwinner,sun4i-a10-sid.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt [deleted file]
Documentation/devicetree/bindings/nvmem/imx-ocotp.txt
Documentation/devicetree/bindings/pci/83xx-512x-pci.txt
Documentation/devicetree/bindings/phy/mixel,mipi-dsi-phy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/mxs-usb-phy.txt
Documentation/devicetree/bindings/phy/nvidia,tegra124-xusb-padctl.txt
Documentation/devicetree/bindings/phy/phy-pxa-usb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/qcom-pcie2-phy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt
Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/bitmain,bm1880-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/brcm,bcm2835-gpio.txt
Documentation/devicetree/bindings/pinctrl/fsl,imx8mm-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/fsl,imx8mn-pinctrl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
Documentation/devicetree/bindings/pinctrl/microchip,pic32-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/nuvoton,npcm7xx-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/nvidia,tegra194-pinmux.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt [deleted file]
Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
Documentation/devicetree/bindings/pinctrl/qcom,apq8084-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/qcom,ipq8074-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/qcom,mdm9615-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/qcom,msm8916-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/qcom,msm8960-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/qcom,msm8994-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/qcom,qcs404-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/qcom,sdm660-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt [deleted file]
Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/property-units.txt
Documentation/devicetree/bindings/regulator/pv88060.txt
Documentation/devicetree/bindings/serial/8250.txt
Documentation/devicetree/bindings/serial/mtk-uart.txt
Documentation/devicetree/bindings/serial/st,stm32-usart.txt
Documentation/devicetree/bindings/sound/cs42l73.txt
Documentation/devicetree/bindings/usb/dwc2.txt
Documentation/devicetree/bindings/usb/dwc3.txt
Documentation/devicetree/bindings/usb/generic-ehci.yaml
Documentation/devicetree/bindings/usb/renesas,usb3.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/renesas,usbhs.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/renesas_usb3.txt [deleted file]
Documentation/devicetree/bindings/usb/renesas_usbhs.txt [deleted file]
Documentation/devicetree/bindings/vendor-prefixes.yaml
Documentation/driver-api/gpio/driver.rst
Documentation/driver-api/index.rst
Documentation/driver-api/ipmb.rst [new file with mode: 0644]
Documentation/driver-api/mei/hdcp.rst [new file with mode: 0644]
Documentation/driver-api/mei/iamt.rst [new file with mode: 0644]
Documentation/driver-api/mei/index.rst [new file with mode: 0644]
Documentation/driver-api/mei/mei-client-bus.rst [new file with mode: 0644]
Documentation/driver-api/mei/mei.rst [new file with mode: 0644]
Documentation/driver-api/mei/nfc.rst [new file with mode: 0644]
Documentation/driver-api/soundwire/locking.rst
Documentation/driver-model/binding.rst [new file with mode: 0644]
Documentation/driver-model/binding.txt [deleted file]
Documentation/driver-model/bus.rst [new file with mode: 0644]
Documentation/driver-model/bus.txt [deleted file]
Documentation/driver-model/class.rst [new file with mode: 0644]
Documentation/driver-model/class.txt [deleted file]
Documentation/driver-model/design-patterns.rst [new file with mode: 0644]
Documentation/driver-model/design-patterns.txt [deleted file]
Documentation/driver-model/device.rst [new file with mode: 0644]
Documentation/driver-model/device.txt [deleted file]
Documentation/driver-model/devres.rst [new file with mode: 0644]
Documentation/driver-model/devres.txt [deleted file]
Documentation/driver-model/driver.rst [new file with mode: 0644]
Documentation/driver-model/driver.txt [deleted file]
Documentation/driver-model/index.rst [new file with mode: 0644]
Documentation/driver-model/overview.rst [new file with mode: 0644]
Documentation/driver-model/overview.txt [deleted file]
Documentation/driver-model/platform.rst [new file with mode: 0644]
Documentation/driver-model/platform.txt [deleted file]
Documentation/driver-model/porting.rst [new file with mode: 0644]
Documentation/driver-model/porting.txt [deleted file]
Documentation/eisa.txt
Documentation/filesystems/debugfs.txt
Documentation/filesystems/f2fs.txt
Documentation/filesystems/proc.txt
Documentation/filesystems/xfs-self-describing-metadata.txt
Documentation/hid/hid-alps.rst [new file with mode: 0644]
Documentation/hid/hid-alps.txt [deleted file]
Documentation/hid/hid-sensor.rst [new file with mode: 0644]
Documentation/hid/hid-sensor.txt [deleted file]
Documentation/hid/hid-transport.rst [new file with mode: 0644]
Documentation/hid/hid-transport.txt [deleted file]
Documentation/hid/hiddev.rst [new file with mode: 0644]
Documentation/hid/hiddev.txt [deleted file]
Documentation/hid/hidraw.rst [new file with mode: 0644]
Documentation/hid/hidraw.txt [deleted file]
Documentation/hid/index.rst [new file with mode: 0644]
Documentation/hid/intel-ish-hid.rst [new file with mode: 0644]
Documentation/hid/intel-ish-hid.txt [deleted file]
Documentation/hid/uhid.rst [new file with mode: 0644]
Documentation/hid/uhid.txt [deleted file]
Documentation/hwmon/pxe1610 [new file with mode: 0644]
Documentation/hwmon/submitting-patches.rst
Documentation/iio/ep93xx_adc.rst [new file with mode: 0644]
Documentation/iio/ep93xx_adc.txt [deleted file]
Documentation/iio/iio_configfs.rst [new file with mode: 0644]
Documentation/iio/iio_configfs.txt [deleted file]
Documentation/iio/index.rst [new file with mode: 0644]
Documentation/index.rst
Documentation/input/input.rst
Documentation/kbuild/headers_install.rst
Documentation/kbuild/kbuild.rst
Documentation/kbuild/makefiles.rst
Documentation/misc-devices/eeprom [deleted file]
Documentation/misc-devices/eeprom.rst [new file with mode: 0644]
Documentation/misc-devices/ics932s401 [deleted file]
Documentation/misc-devices/ics932s401.rst [new file with mode: 0644]
Documentation/misc-devices/index.rst
Documentation/misc-devices/isl29003 [deleted file]
Documentation/misc-devices/isl29003.rst [new file with mode: 0644]
Documentation/misc-devices/lis3lv02d [deleted file]
Documentation/misc-devices/lis3lv02d.rst [new file with mode: 0644]
Documentation/misc-devices/max6875 [deleted file]
Documentation/misc-devices/max6875.rst [new file with mode: 0644]
Documentation/misc-devices/mei/mei-client-bus.txt [deleted file]
Documentation/misc-devices/mei/mei.txt [deleted file]
Documentation/scsi/osst.txt [deleted file]
Documentation/scsi/ufs.txt
Documentation/translations/zh_CN/arm64/booting.txt
Documentation/usb/WUSB-Design-overview.txt [deleted file]
Documentation/usb/acm.rst [new file with mode: 0644]
Documentation/usb/acm.txt [deleted file]
Documentation/usb/authorization.rst [new file with mode: 0644]
Documentation/usb/authorization.txt [deleted file]
Documentation/usb/chipidea.rst [new file with mode: 0644]
Documentation/usb/chipidea.txt [deleted file]
Documentation/usb/dwc3.rst [new file with mode: 0644]
Documentation/usb/dwc3.txt [deleted file]
Documentation/usb/ehci.rst [new file with mode: 0644]
Documentation/usb/ehci.txt [deleted file]
Documentation/usb/functionfs.rst [new file with mode: 0644]
Documentation/usb/functionfs.txt [deleted file]
Documentation/usb/gadget-testing.rst [new file with mode: 0644]
Documentation/usb/gadget-testing.txt [deleted file]
Documentation/usb/gadget_configfs.rst [new file with mode: 0644]
Documentation/usb/gadget_configfs.txt [deleted file]
Documentation/usb/gadget_hid.rst [new file with mode: 0644]
Documentation/usb/gadget_hid.txt [deleted file]
Documentation/usb/gadget_multi.rst [new file with mode: 0644]
Documentation/usb/gadget_multi.txt [deleted file]
Documentation/usb/gadget_printer.rst [new file with mode: 0644]
Documentation/usb/gadget_printer.txt [deleted file]
Documentation/usb/gadget_serial.rst [new file with mode: 0644]
Documentation/usb/gadget_serial.txt [deleted file]
Documentation/usb/index.rst [new file with mode: 0644]
Documentation/usb/iuu_phoenix.rst [new file with mode: 0644]
Documentation/usb/iuu_phoenix.txt [deleted file]
Documentation/usb/mass-storage.rst [new file with mode: 0644]
Documentation/usb/mass-storage.txt [deleted file]
Documentation/usb/misc_usbsevseg.rst [new file with mode: 0644]
Documentation/usb/misc_usbsevseg.txt [deleted file]
Documentation/usb/mtouchusb.rst [new file with mode: 0644]
Documentation/usb/mtouchusb.txt [deleted file]
Documentation/usb/ohci.rst [new file with mode: 0644]
Documentation/usb/ohci.txt [deleted file]
Documentation/usb/rio.rst [new file with mode: 0644]
Documentation/usb/rio.txt [deleted file]
Documentation/usb/text_files.rst [new file with mode: 0644]
Documentation/usb/usb-help.rst [new file with mode: 0644]
Documentation/usb/usb-help.txt [deleted file]
Documentation/usb/usb-serial.rst [new file with mode: 0644]
Documentation/usb/usb-serial.txt [deleted file]
Documentation/usb/usbip_protocol.rst [new file with mode: 0644]
Documentation/usb/usbip_protocol.txt [deleted file]
Documentation/usb/usbmon.rst [new file with mode: 0644]
Documentation/usb/usbmon.txt [deleted file]
Documentation/usb/wusb-design-overview.rst [new file with mode: 0644]
Documentation/virtual/index.rst [new file with mode: 0644]
Documentation/virtual/kvm/api.txt
Documentation/virtual/kvm/arm/psci.txt
Documentation/virtual/kvm/cpuid.rst [new file with mode: 0644]
Documentation/virtual/kvm/cpuid.txt [deleted file]
Documentation/virtual/kvm/hypercalls.txt
Documentation/virtual/kvm/index.rst [new file with mode: 0644]
Documentation/virtual/kvm/locking.txt
Documentation/virtual/kvm/msr.txt
Documentation/virtual/paravirt_ops.rst [new file with mode: 0644]
Documentation/virtual/paravirt_ops.txt [deleted file]
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/Makefile
arch/alpha/include/asm/pgalloc.h
arch/arc/Kconfig
arch/arc/Makefile
arch/arc/configs/tb10x_defconfig
arch/arc/mm/dma.c
arch/arm/Kconfig
arch/arm/boot/dts/rk3288-veyron.dtsi
arch/arm/include/asm/dma-mapping.h
arch/arm/include/asm/kvm_emulate.h
arch/arm/include/asm/kvm_host.h
arch/arm/include/asm/kvm_hyp.h
arch/arm/include/asm/pgalloc.h
arch/arm/include/asm/ptdump.h
arch/arm/include/uapi/asm/kvm.h
arch/arm/kernel/efi.c
arch/arm/mach-omap1/clock.c
arch/arm/mach-omap1/pm.c
arch/arm/mach-omap2/pm-debug.c
arch/arm/mm/dma-mapping-nommu.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/dump.c
arch/arm/mm/mmu.c
arch/arm/mm/pageattr.c
arch/arm/mm/ptdump_debugfs.c
arch/arm64/Kconfig
arch/arm64/Makefile
arch/arm64/boot/dts/freescale/imx8mn-pinfunc.h [new file with mode: 0644]
arch/arm64/include/asm/assembler.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/kvm_asm.h
arch/arm64/include/asm/kvm_emulate.h
arch/arm64/include/asm/kvm_host.h
arch/arm64/include/asm/kvm_hyp.h
arch/arm64/include/asm/pgalloc.h
arch/arm64/include/asm/ptrace.h
arch/arm64/include/asm/sysreg.h
arch/arm64/include/uapi/asm/kvm.h
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/efi.c
arch/arm64/kernel/setup.c
arch/arm64/kernel/smp.c
arch/arm64/kernel/traps.c
arch/arm64/kvm/hyp/entry.S
arch/arm64/kvm/hyp/hyp-entry.S
arch/arm64/kvm/hyp/switch.c
arch/arm64/kvm/hyp/sysreg-sr.c
arch/arm64/kvm/hyp/tlb.c
arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c
arch/arm64/kvm/regmap.c
arch/arm64/kvm/sys_regs.c
arch/arm64/kvm/va_layout.c
arch/arm64/mm/mmu.c
arch/arm64/mm/pageattr.c
arch/arm64/mm/pgd.c
arch/csky/Makefile
arch/csky/include/asm/pgalloc.h
arch/ia64/hp/sim/simserial.c
arch/m68k/include/asm/sun3_pgalloc.h
arch/m68k/mac/config.c
arch/mips/Kconfig
arch/mips/include/asm/page.h
arch/mips/include/asm/pgalloc.h
arch/mips/include/asm/pgtable.h
arch/mips/include/asm/ptrace.h
arch/mips/jazz/jazzdma.c
arch/mips/kvm/mips.c
arch/mips/mm/Makefile
arch/mips/mm/cache.c
arch/mips/mm/dma-noncoherent.c
arch/mips/mm/gup.c [deleted file]
arch/nds32/Kconfig
arch/nds32/Makefile
arch/nds32/configs/defconfig
arch/nds32/include/asm/pgalloc.h
arch/nds32/kernel/dma.c
arch/nios2/Kconfig
arch/nios2/Kconfig.debug
arch/nios2/configs/10m50_defconfig
arch/nios2/configs/3c120_defconfig
arch/nios2/include/asm/page.h
arch/nios2/include/asm/pgalloc.h
arch/nios2/mm/dma-mapping.c
arch/openrisc/kernel/dma.c
arch/parisc/Makefile
arch/parisc/configs/a500_defconfig
arch/parisc/configs/b180_defconfig
arch/parisc/configs/c3000_defconfig
arch/parisc/configs/default_defconfig
arch/parisc/include/asm/pgalloc.h
arch/parisc/kernel/pci-dma.c
arch/powerpc/Kconfig
arch/powerpc/configs/ppc6xx_defconfig
arch/powerpc/include/asm/pgtable.h
arch/powerpc/include/asm/ptrace.h
arch/powerpc/kvm/book3s_xics.c
arch/powerpc/kvm/powerpc.c
arch/powerpc/mm/book3s64/radix_tlb.c
arch/powerpc/mm/hugetlbpage.c
arch/powerpc/platforms/pseries/ibmebus.c
arch/riscv/Makefile
arch/riscv/include/asm/pgalloc.h
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/configs/debug_defconfig
arch/s390/include/asm/kvm_host.h
arch/s390/include/asm/pci_insn.h
arch/s390/include/asm/pgtable.h
arch/s390/include/asm/sclp.h
arch/s390/include/uapi/asm/dasd.h
arch/s390/kernel/early.c
arch/s390/kernel/ipl.c
arch/s390/kernel/perf_cpum_cf_events.c
arch/s390/kernel/unwind_bc.c
arch/s390/kvm/kvm-s390.c
arch/s390/pci/pci.c
arch/s390/pci/pci_sysfs.c
arch/sh/Kconfig
arch/sh/configs/hp6xx_defconfig
arch/sh/configs/sdk7786_defconfig
arch/sh/configs/sh2007_defconfig
arch/sh/include/asm/io.h
arch/sh/include/asm/pgtable-3level.h
arch/sh/include/asm/pgtable.h
arch/sh/include/asm/ptrace.h
arch/sh/kernel/kdebugfs.c
arch/sh/mm/Makefile
arch/sh/mm/asids-debugfs.c
arch/sh/mm/cache-debugfs.c
arch/sh/mm/gup.c [deleted file]
arch/sh/mm/pmb.c
arch/sh/mm/tlb-debugfs.c
arch/sparc/Kconfig
arch/sparc/include/asm/pgtable_64.h
arch/sparc/mm/Makefile
arch/sparc/mm/gup.c [deleted file]
arch/um/Makefile
arch/um/include/asm/pgalloc.h
arch/um/kernel/mem.c
arch/unicore32/Makefile
arch/unicore32/configs/defconfig [new file with mode: 0644]
arch/unicore32/configs/unicore32_defconfig [deleted file]
arch/unicore32/include/asm/pgalloc.h
arch/unicore32/include/mach/regs-gpio.h
arch/x86/Kconfig
arch/x86/entry/entry_32.S
arch/x86/ia32/ia32_signal.c
arch/x86/include/asm/bitops.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/mmu.h
arch/x86/include/asm/mshyperv.h
arch/x86/include/asm/pgalloc.h
arch/x86/include/asm/pgtable-3level.h
arch/x86/include/asm/pgtable_32.h
arch/x86/include/asm/pgtable_64.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/ptrace.h
arch/x86/include/asm/special_insns.h
arch/x86/include/uapi/asm/kvm.h
arch/x86/include/uapi/asm/kvm_para.h
arch/x86/include/uapi/asm/vmx.h
arch/x86/kernel/alternative.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/kdebugfs.c
arch/x86/kernel/kvm.c
arch/x86/kernel/signal.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/stacktrace.c
arch/x86/kernel/vmlinux.lds.S
arch/x86/kvm/Kconfig
arch/x86/kvm/cpuid.c
arch/x86/kvm/emulate.c
arch/x86/kvm/irq.h
arch/x86/kvm/irq_comm.c
arch/x86/kvm/lapic.c
arch/x86/kvm/lapic.h
arch/x86/kvm/mmu.c
arch/x86/kvm/mmutrace.h
arch/x86/kvm/paging_tmpl.h
arch/x86/kvm/pmu.c
arch/x86/kvm/pmu.h
arch/x86/kvm/svm.c
arch/x86/kvm/trace.h
arch/x86/kvm/vmx/evmcs.c
arch/x86/kvm/vmx/evmcs.h
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/vmx/nested.h
arch/x86/kvm/vmx/ops.h
arch/x86/kvm/vmx/vmcs.h
arch/x86/kvm/vmx/vmcs12.h
arch/x86/kvm/vmx/vmcs_shadow_fields.h
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/vmx/vmx.h
arch/x86/kvm/x86.c
arch/x86/kvm/x86.h
arch/x86/mm/debug_pagetables.c
arch/x86/mm/pgtable.c
arch/x86/platform/atom/punit_atom_debug.c
arch/x86/platform/intel-quark/imr.c
arch/x86/platform/intel/iosf_mbi.c
arch/x86/platform/uv/tlb_uv.c
arch/x86/xen/debugfs.c
arch/x86/xen/mmu_pv.c
arch/x86/xen/p2m.c
arch/x86/xen/smp_pv.c
arch/xtensa/kernel/pci-dma.c
crypto/ccm.c
drivers/acpi/acpi_amba.c
drivers/acpi/acpi_lpss.c
drivers/acpi/utils.c
drivers/amba/tegra-ahb.c
drivers/android/binder.c
drivers/android/binder_alloc.c
drivers/android/binder_alloc.h
drivers/base/arch_topology.c
drivers/base/bus.c
drivers/base/cacheinfo.c
drivers/base/core.c
drivers/base/dd.c
drivers/base/devcon.c
drivers/base/driver.c
drivers/base/firmware_loader/Kconfig
drivers/base/firmware_loader/fallback.c
drivers/base/firmware_loader/firmware.h
drivers/base/firmware_loader/main.c
drivers/base/node.c
drivers/base/platform.c
drivers/char/bsr.c
drivers/char/ipmi/Kconfig
drivers/char/ipmi/Makefile
drivers/char/ipmi/ipmb_dev_int.c [new file with mode: 0644]
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/ipmi/ipmi_si_platform.c
drivers/char/ipmi/ipmi_ssif.c
drivers/char/misc.c
drivers/clk/renesas/r8a77470-cpg-mssr.c
drivers/clocksource/timer-npcm7xx.c
drivers/counter/104-quad-8.c
drivers/counter/ftm-quaddec.c
drivers/dma/mxs-dma.c
drivers/extcon/Kconfig
drivers/extcon/Makefile
drivers/extcon/extcon-arizona.c
drivers/extcon/extcon-fsa9480.c [new file with mode: 0644]
drivers/firmware/arm_scmi/common.h
drivers/firmware/efi/dev-path-parser.c
drivers/firmware/google/coreboot_table.h
drivers/firmware/google/framebuffer-coreboot.c
drivers/firmware/google/memconsole-coreboot.c
drivers/firmware/google/memconsole.c
drivers/firmware/google/vpd.c
drivers/firmware/google/vpd_decode.c
drivers/firmware/ti_sci.h
drivers/fpga/Kconfig
drivers/fpga/dfl-fme-mgr.c
drivers/fpga/dfl-fme-pr.c
drivers/fpga/of-fpga-region.c
drivers/fsi/cf-fsi-fw.h
drivers/fsi/fsi-core.c
drivers/fsi/fsi-occ.c
drivers/fsi/fsi-sbefifo.c
drivers/gpio/gpio-cs5535.c
drivers/gpu/drm/drm_mipi_dsi.c
drivers/gpu/drm/i915/.gitignore [deleted file]
drivers/gpu/drm/i915/Makefile.header-test
drivers/gpu/drm/i915/i915_mm.c
drivers/gpu/drm/tegra/dc.c
drivers/hid/hid-ids.h
drivers/hid/hid-lg.c
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-logitech-hidpp.c
drivers/hid/hid-quirks.c
drivers/hid/hid-uclogic-core.c
drivers/hid/hid-uclogic-params.c
drivers/hid/intel-ish-hid/ipc/pci-ish.c
drivers/hid/wacom_sys.c
drivers/hid/wacom_wac.c
drivers/hid/wacom_wac.h
drivers/hv/vmbus_drv.c
drivers/hwmon/adm1029.c
drivers/hwmon/asus_atk0110.c
drivers/hwmon/gpio-fan.c
drivers/hwmon/hwmon.c
drivers/hwmon/ina3221.c
drivers/hwmon/lm90.c
drivers/hwmon/max6650.c
drivers/hwmon/nct7904.c
drivers/hwmon/occ/common.c
drivers/hwmon/occ/common.h
drivers/hwmon/pmbus/Kconfig
drivers/hwmon/pmbus/Makefile
drivers/hwmon/pmbus/adm1275.c
drivers/hwmon/pmbus/irps5401.c [new file with mode: 0644]
drivers/hwmon/pmbus/pxe1610.c [new file with mode: 0644]
drivers/hwmon/pwm-fan.c
drivers/hwmon/scpi-hwmon.c
drivers/hwmon/smsc47m1.c
drivers/hwtracing/coresight/Kconfig
drivers/hwtracing/coresight/Makefile
drivers/hwtracing/coresight/coresight-catu.c
drivers/hwtracing/coresight/coresight-catu.h
drivers/hwtracing/coresight/coresight-cpu-debug.c
drivers/hwtracing/coresight/coresight-etb10.c
drivers/hwtracing/coresight/coresight-etm-perf.c
drivers/hwtracing/coresight/coresight-etm.h
drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
drivers/hwtracing/coresight/coresight-etm3x.c
drivers/hwtracing/coresight/coresight-etm4x.c
drivers/hwtracing/coresight/coresight-etm4x.h
drivers/hwtracing/coresight/coresight-funnel.c
drivers/hwtracing/coresight/coresight-platform.c [new file with mode: 0644]
drivers/hwtracing/coresight/coresight-priv.h
drivers/hwtracing/coresight/coresight-replicator.c
drivers/hwtracing/coresight/coresight-stm.c
drivers/hwtracing/coresight/coresight-tmc-etf.c
drivers/hwtracing/coresight/coresight-tmc-etr.c
drivers/hwtracing/coresight/coresight-tmc.c
drivers/hwtracing/coresight/coresight-tmc.h
drivers/hwtracing/coresight/coresight-tpiu.c
drivers/hwtracing/coresight/coresight.c
drivers/hwtracing/coresight/of_coresight.c [deleted file]
drivers/hwtracing/intel_th/core.c
drivers/hwtracing/intel_th/msu.c
drivers/hwtracing/intel_th/pci.c
drivers/i2c/busses/i2c-amd-mp2-pci.c
drivers/i2c/i2c-core-acpi.c
drivers/i2c/i2c-core-of.c
drivers/iio/Kconfig
drivers/iio/accel/adis16201.c
drivers/iio/accel/adis16209.c
drivers/iio/accel/adxl372.c
drivers/iio/accel/adxl372_spi.c
drivers/iio/accel/kxcjk-1013.c
drivers/iio/accel/kxsd9-spi.c
drivers/iio/accel/sca3000.c
drivers/iio/accel/st_accel_buffer.c
drivers/iio/adc/Kconfig
drivers/iio/adc/ad7124.c
drivers/iio/adc/ad7606.c
drivers/iio/adc/ad7606.h
drivers/iio/adc/ad_sigma_delta.c
drivers/iio/adc/at91-sama5d2_adc.c
drivers/iio/adc/at91_adc.c
drivers/iio/adc/imx7d_adc.c
drivers/iio/adc/meson_saradc.c
drivers/iio/adc/mt6577_auxadc.c
drivers/iio/adc/rcar-gyroadc.c
drivers/iio/adc/stm32-adc-core.c
drivers/iio/adc/stm32-dfsdm-adc.c
drivers/iio/adc/stm32-dfsdm-core.c
drivers/iio/adc/stm32-dfsdm.h
drivers/iio/adc/stmpe-adc.c
drivers/iio/adc/sun4i-gpadc-iio.c
drivers/iio/amplifiers/Kconfig
drivers/iio/amplifiers/ad8366.c
drivers/iio/common/cros_ec_sensors/Kconfig
drivers/iio/common/cros_ec_sensors/Makefile
drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c [new file with mode: 0644]
drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
drivers/iio/dac/ad5758.c
drivers/iio/dac/ds4424.c
drivers/iio/frequency/Kconfig
drivers/iio/frequency/Makefile
drivers/iio/frequency/ad9523.c
drivers/iio/frequency/adf4371.c [new file with mode: 0644]
drivers/iio/humidity/dht11.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
drivers/iio/industrialio-core.c
drivers/iio/inkern.c
drivers/iio/light/bh1780.c
drivers/iio/light/stk3310.c
drivers/iio/pressure/Kconfig
drivers/iio/pressure/Makefile
drivers/iio/pressure/dps310.c [new file with mode: 0644]
drivers/iio/temperature/maxim_thermocouple.c
drivers/infiniband/core/uverbs_ioctl.c
drivers/infiniband/hw/hns/hns_roce_hw_v1.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/input/joydev.c
drivers/input/joystick/iforce/Kconfig
drivers/input/joystick/iforce/Makefile
drivers/input/joystick/iforce/iforce-ff.c
drivers/input/joystick/iforce/iforce-main.c
drivers/input/joystick/iforce/iforce-packets.c
drivers/input/joystick/iforce/iforce-serio.c
drivers/input/joystick/iforce/iforce-usb.c
drivers/input/joystick/iforce/iforce.h
drivers/input/keyboard/cros_ec_keyb.c
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/gpio_keys_polled.c
drivers/input/keyboard/imx_keypad.c
drivers/input/keyboard/tca8418_keypad.c
drivers/input/misc/da9063_onkey.c
drivers/input/misc/max77650-onkey.c
drivers/input/mouse/elan_i2c_core.c
drivers/input/mouse/elantech.c
drivers/input/mouse/elantech.h
drivers/input/mouse/synaptics.c
drivers/input/rmi4/rmi_f12.c
drivers/input/touchscreen/atmel_mxt_ts.c
drivers/input/touchscreen/edt-ft5x06.c
drivers/input/touchscreen/eeti_ts.c
drivers/input/touchscreen/imx6ul_tsc.c
drivers/input/touchscreen/iqs5xx.c
drivers/iommu/arm-smmu-v3.c
drivers/iommu/arm-smmu.c
drivers/iommu/dma-iommu.c
drivers/ipack/devices/ipoctal.h
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-renesas-rza1.c
drivers/mailbox/bcm-flexrm-mailbox.c
drivers/mailbox/bcm-pdc-mailbox.c
drivers/md/dm-bufio.c
drivers/md/dm-crypt.c
drivers/md/dm-integrity.c
drivers/md/dm-log-writes.c
drivers/md/dm-rq.c
drivers/md/dm-snap.c
drivers/md/dm-thin-metadata.c
drivers/memory/Kconfig
drivers/memory/jz4780-nemc.c
drivers/memstick/core/memstick.c
drivers/message/fusion/mptbase.c
drivers/mfd/altera-sysmgr.c
drivers/mfd/cros_ec.c
drivers/mfd/syscon.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/altera-stapl/Kconfig
drivers/misc/c2port/Kconfig
drivers/misc/cb710/Kconfig
drivers/misc/cxl/Kconfig
drivers/misc/cxl/cxl.h
drivers/misc/cxl/debugfs.c
drivers/misc/echo/Kconfig
drivers/misc/eeprom/ee1004.c
drivers/misc/eeprom/idt_89hpesx.c
drivers/misc/fsa9480.c [deleted file]
drivers/misc/genwqe/Kconfig
drivers/misc/genwqe/card_base.c
drivers/misc/genwqe/card_base.h
drivers/misc/genwqe/card_debugfs.c
drivers/misc/genwqe/card_dev.c
drivers/misc/habanalabs/asid.c
drivers/misc/habanalabs/command_submission.c
drivers/misc/habanalabs/context.c
drivers/misc/habanalabs/debugfs.c
drivers/misc/habanalabs/device.c
drivers/misc/habanalabs/firmware_if.c
drivers/misc/habanalabs/goya/goya.c
drivers/misc/habanalabs/goya/goyaP.h
drivers/misc/habanalabs/goya/goya_security.c
drivers/misc/habanalabs/habanalabs.h
drivers/misc/habanalabs/habanalabs_drv.c
drivers/misc/habanalabs/habanalabs_ioctl.c
drivers/misc/habanalabs/hw_queue.c
drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_0_masks.h [new file with mode: 0644]
drivers/misc/habanalabs/include/goya/asic_reg/goya_regs.h
drivers/misc/habanalabs/memory.c
drivers/misc/habanalabs/mmu.c
drivers/misc/habanalabs/pci.c
drivers/misc/habanalabs/sysfs.c
drivers/misc/isl29003.c
drivers/misc/lis3lv02d/Kconfig
drivers/misc/lkdtm/Makefile
drivers/misc/lkdtm/bugs.c
drivers/misc/lkdtm/core.c
drivers/misc/lkdtm/heap.c
drivers/misc/lkdtm/lkdtm.h
drivers/misc/mei/debugfs.c
drivers/misc/mei/hdcp/mei_hdcp.c
drivers/misc/mei/main.c
drivers/misc/mei/mei_dev.h
drivers/misc/mic/card/mic_debugfs.c
drivers/misc/mic/cosm/cosm_debugfs.c
drivers/misc/mic/host/mic_debugfs.c
drivers/misc/mic/scif/scif_debugfs.c
drivers/misc/mic/scif/scif_main.c
drivers/misc/mic/vop/vop_debugfs.c
drivers/misc/ocxl/Kconfig
drivers/misc/ocxl/context.c
drivers/misc/ocxl/link.c
drivers/misc/sgi-xp/xpc_partition.c
drivers/misc/ti-st/st_kim.c
drivers/misc/tsl2550.c
drivers/misc/vmw_balloon.c
drivers/misc/vmw_vmci/vmci_context.c
drivers/misc/vmw_vmci/vmci_handle_array.c
drivers/misc/vmw_vmci/vmci_handle_array.h
drivers/misc/xilinx_sdfec.c [new file with mode: 0644]
drivers/mmc/core/debugfs.c
drivers/mmc/core/mmc_test.c
drivers/mmc/core/queue.c
drivers/mmc/core/sdio.c
drivers/mmc/core/sdio_irq.c
drivers/mmc/host/Kconfig
drivers/mmc/host/alcor.c
drivers/mmc/host/android-goldfish.c
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/meson-gx-mmc.c
drivers/mmc/host/renesas_sdhi_core.c
drivers/mmc/host/s3cmci.c
drivers/mmc/host/s3cmci.h
drivers/mmc/host/sdhci-msm.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-pci-core.c
drivers/mmc/host/sdhci-pci-o2micro.c
drivers/mmc/host/sdhci-pci.h
drivers/mmc/host/sdhci-sprd.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sdhci_am654.c
drivers/mmc/host/tmio_mmc.c
drivers/mmc/host/tmio_mmc_core.c
drivers/mmc/host/uniphier-sd.c
drivers/mtd/Kconfig
drivers/mtd/Makefile
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/hyperbus/Kconfig [new file with mode: 0644]
drivers/mtd/hyperbus/Makefile [new file with mode: 0644]
drivers/mtd/hyperbus/hbmc-am654.c [new file with mode: 0644]
drivers/mtd/hyperbus/hyperbus-core.c [new file with mode: 0644]
drivers/mtd/mtdconcat.c
drivers/mtd/mtdcore.c
drivers/mtd/nand/onenand/onenand_base.c
drivers/mtd/nand/raw/brcmnand/brcmnand.c
drivers/mtd/nand/raw/fsmc_nand.c
drivers/mtd/nand/raw/gpmi-nand/Makefile
drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c [deleted file]
drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
drivers/mtd/nand/raw/mtk_ecc.c
drivers/mtd/nand/raw/mtk_ecc.h
drivers/mtd/nand/raw/mtk_nand.c
drivers/mtd/nand/raw/nand_base.c
drivers/mtd/nand/raw/nand_bch.c
drivers/mtd/nand/raw/nand_macronix.c
drivers/mtd/nand/raw/stm32_fmc2_nand.c
drivers/mtd/nand/spi/Makefile
drivers/mtd/nand/spi/core.c
drivers/mtd/nand/spi/gigadevice.c
drivers/mtd/nand/spi/paragon.c [new file with mode: 0644]
drivers/mtd/parsers/afs.c
drivers/mtd/spi-nor/Kconfig
drivers/mtd/spi-nor/Makefile
drivers/mtd/spi-nor/cadence-quadspi.c
drivers/mtd/spi-nor/intel-spi-pci.c
drivers/mtd/spi-nor/spi-nor.c
drivers/mtd/spi-nor/stm32-quadspi.c [deleted file]
drivers/mux/Kconfig
drivers/mux/mmio.c
drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/ti/cpsw-phy-sel.c
drivers/net/ethernet/ti/davinci_emac.c
drivers/net/ethernet/toshiba/tc35815.c
drivers/net/wireless/realtek/rtlwifi/wifi.h
drivers/nvme/host/fc.c
drivers/nvme/host/rdma.c
drivers/nvme/target/loop.c
drivers/nvmem/Kconfig
drivers/nvmem/Makefile
drivers/nvmem/core.c
drivers/nvmem/imx-ocotp-scu.c [new file with mode: 0644]
drivers/nvmem/imx-ocotp.c
drivers/of/fdt.c
drivers/of/of_mdio.c
drivers/of/of_reserved_mem.c
drivers/of/platform.c
drivers/of/unittest.c
drivers/pci/probe.c
drivers/pci/search.c
drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c
drivers/phy/broadcom/phy-brcm-usb.c
drivers/phy/freescale/Kconfig
drivers/phy/freescale/Makefile
drivers/phy/freescale/phy-fsl-imx8-mipi-dphy.c [new file with mode: 0644]
drivers/phy/qualcomm/Kconfig
drivers/phy/qualcomm/Makefile
drivers/phy/qualcomm/phy-qcom-pcie2.c [new file with mode: 0644]
drivers/phy/qualcomm/phy-qcom-qmp.c
drivers/phy/qualcomm/phy-qcom-qusb2.c
drivers/phy/renesas/phy-rcar-gen2.c
drivers/phy/renesas/phy-rcar-gen3-usb2.c
drivers/phy/samsung/phy-samsung-usb2.c
drivers/phy/tegra/xusb-tegra124.c
drivers/phy/tegra/xusb-tegra210.c
drivers/phy/ti/phy-am654-serdes.c
drivers/pinctrl/aspeed/Makefile
drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c
drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
drivers/pinctrl/aspeed/pinctrl-aspeed.c
drivers/pinctrl/aspeed/pinctrl-aspeed.h
drivers/pinctrl/aspeed/pinmux-aspeed.c [new file with mode: 0644]
drivers/pinctrl/aspeed/pinmux-aspeed.h [new file with mode: 0644]
drivers/pinctrl/bcm/Kconfig
drivers/pinctrl/bcm/pinctrl-ns2-mux.c
drivers/pinctrl/cirrus/pinctrl-cs47l35.c
drivers/pinctrl/cirrus/pinctrl-cs47l85.c
drivers/pinctrl/cirrus/pinctrl-cs47l90.c
drivers/pinctrl/cirrus/pinctrl-madera-core.c
drivers/pinctrl/cirrus/pinctrl-madera.h
drivers/pinctrl/core.c
drivers/pinctrl/devicetree.c
drivers/pinctrl/freescale/Kconfig
drivers/pinctrl/freescale/Makefile
drivers/pinctrl/freescale/pinctrl-imx8mn.c [new file with mode: 0644]
drivers/pinctrl/intel/pinctrl-baytrail.c
drivers/pinctrl/mediatek/pinctrl-mt8183.c
drivers/pinctrl/mediatek/pinctrl-paris.c
drivers/pinctrl/mediatek/pinctrl-paris.h
drivers/pinctrl/meson/pinctrl-meson-g12a.c
drivers/pinctrl/meson/pinctrl-meson.c
drivers/pinctrl/meson/pinctrl-meson.h
drivers/pinctrl/mvebu/pinctrl-kirkwood.c
drivers/pinctrl/pinconf-generic.c
drivers/pinctrl/pinctrl-bm1880.c
drivers/pinctrl/pinctrl-rockchip.c
drivers/pinctrl/pinctrl-stmfx.c
drivers/pinctrl/pinctrl-tb10x.c
drivers/pinctrl/qcom/Kconfig
drivers/pinctrl/qcom/Makefile
drivers/pinctrl/qcom/pinctrl-msm.c
drivers/pinctrl/qcom/pinctrl-msm.h
drivers/pinctrl/qcom/pinctrl-sdm845.c
drivers/pinctrl/qcom/pinctrl-sm8150.c [new file with mode: 0644]
drivers/pinctrl/sh-pfc/core.c
drivers/pinctrl/sh-pfc/pfc-emev2.c
drivers/pinctrl/sh-pfc/pfc-r8a73a4.c
drivers/pinctrl/sh-pfc/pfc-r8a7740.c
drivers/pinctrl/sh-pfc/pfc-r8a77470.c
drivers/pinctrl/sh-pfc/pfc-r8a7778.c
drivers/pinctrl/sh-pfc/pfc-r8a7779.c
drivers/pinctrl/sh-pfc/pfc-r8a7790.c
drivers/pinctrl/sh-pfc/pfc-r8a7791.c
drivers/pinctrl/sh-pfc/pfc-r8a7792.c
drivers/pinctrl/sh-pfc/pfc-r8a7794.c
drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c
drivers/pinctrl/sh-pfc/pfc-r8a7795.c
drivers/pinctrl/sh-pfc/pfc-r8a7796.c
drivers/pinctrl/sh-pfc/pfc-r8a77965.c
drivers/pinctrl/sh-pfc/pfc-r8a77970.c
drivers/pinctrl/sh-pfc/pfc-r8a77980.c
drivers/pinctrl/sh-pfc/pfc-r8a77990.c
drivers/pinctrl/sh-pfc/pfc-r8a77995.c
drivers/pinctrl/sh-pfc/pfc-sh73a0.c
drivers/pinctrl/sh-pfc/pfc-sh7734.c
drivers/pinctrl/sh-pfc/pinctrl.c
drivers/pinctrl/sh-pfc/sh_pfc.h
drivers/pinctrl/stm32/pinctrl-stm32.c
drivers/pinctrl/stm32/pinctrl-stm32.h
drivers/pinctrl/stm32/pinctrl-stm32mp157.c
drivers/pinctrl/tegra/Kconfig
drivers/pinctrl/tegra/Makefile
drivers/pinctrl/tegra/pinctrl-tegra.c
drivers/pinctrl/tegra/pinctrl-tegra.h
drivers/pinctrl/tegra/pinctrl-tegra114.c
drivers/pinctrl/tegra/pinctrl-tegra124.c
drivers/pinctrl/tegra/pinctrl-tegra194.c [new file with mode: 0644]
drivers/pinctrl/tegra/pinctrl-tegra20.c
drivers/pinctrl/tegra/pinctrl-tegra210.c
drivers/pinctrl/tegra/pinctrl-tegra30.c
drivers/platform/chrome/Kconfig
drivers/platform/chrome/Makefile
drivers/platform/chrome/cros_ec_debugfs.c
drivers/platform/chrome/cros_ec_ishtp.c [new file with mode: 0644]
drivers/platform/chrome/cros_ec_lightbar.c
drivers/platform/chrome/cros_ec_lpc.c
drivers/platform/chrome/cros_ec_lpc_mec.c
drivers/platform/chrome/cros_ec_lpc_reg.c [deleted file]
drivers/platform/chrome/cros_ec_lpc_reg.h [deleted file]
drivers/platform/chrome/cros_ec_spi.c
drivers/platform/chrome/cros_ec_sysfs.c
drivers/platform/chrome/cros_ec_vbc.c
drivers/platform/chrome/wilco_ec/Kconfig
drivers/platform/chrome/wilco_ec/Makefile
drivers/platform/chrome/wilco_ec/core.c
drivers/platform/chrome/wilco_ec/debugfs.c
drivers/platform/chrome/wilco_ec/event.c [new file with mode: 0644]
drivers/platform/chrome/wilco_ec/mailbox.c
drivers/platform/chrome/wilco_ec/properties.c [new file with mode: 0644]
drivers/platform/chrome/wilco_ec/sysfs.c [new file with mode: 0644]
drivers/platform/chrome/wilco_ec/telemetry.c [new file with mode: 0644]
drivers/platform/x86/Kconfig
drivers/s390/block/dasd.c
drivers/s390/block/dasd_devmap.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_eckd.h
drivers/s390/block/dasd_eer.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/dasd_fba.h
drivers/s390/block/dasd_int.h
drivers/s390/block/dasd_ioctl.c
drivers/s390/char/sclp_early.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/chsc_sch.c
drivers/s390/cio/css.c
drivers/s390/cio/device.c
drivers/s390/cio/scm.c
drivers/s390/crypto/ap_bus.c
drivers/s390/crypto/vfio_ap_ops.c
drivers/s390/scsi/zfcp_fc.c
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/NCR5380.c
drivers/scsi/NCR5380.h
drivers/scsi/advansys.c
drivers/scsi/aha152x.c
drivers/scsi/aic7xxx/aic7xxx.reg
drivers/scsi/aic94xx/aic94xx_dev.c
drivers/scsi/bnx2fc/bnx2fc.h
drivers/scsi/bnx2fc/bnx2fc_els.c
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/bnx2fc/bnx2fc_io.c
drivers/scsi/bnx2fc/bnx2fc_tgt.c
drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
drivers/scsi/esp_scsi.c
drivers/scsi/esp_scsi.h
drivers/scsi/fdomain.c [new file with mode: 0644]
drivers/scsi/fdomain.h [new file with mode: 0644]
drivers/scsi/fdomain_isa.c [new file with mode: 0644]
drivers/scsi/fdomain_pci.c [new file with mode: 0644]
drivers/scsi/hisi_sas/hisi_sas.h
drivers/scsi/hisi_sas/hisi_sas_main.c
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
drivers/scsi/hpsa.c
drivers/scsi/hpsa.h
drivers/scsi/hpsa_cmd.h
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/ibmvscsi/ibmvscsi.h
drivers/scsi/imm.c
drivers/scsi/ipr.c
drivers/scsi/isci/remote_device.c
drivers/scsi/isci/remote_device.h
drivers/scsi/isci/request.c
drivers/scsi/isci/task.c
drivers/scsi/libiscsi_tcp.c
drivers/scsi/libsas/sas_discover.c
drivers/scsi/libsas/sas_event.c
drivers/scsi/libsas/sas_expander.c
drivers/scsi/libsas/sas_init.c
drivers/scsi/libsas/sas_internal.h
drivers/scsi/libsas/sas_phy.c
drivers/scsi/libsas/sas_port.c
drivers/scsi/libsas/sas_scsi_host.c
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_bsg.c
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_ct.c
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_nvme.c
drivers/scsi/lpfc/lpfc_nvmet.c
drivers/scsi/lpfc/lpfc_nvmet.h
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli4.h
drivers/scsi/lpfc/lpfc_version.h
drivers/scsi/mac_scsi.c
drivers/scsi/megaraid/Kconfig.megaraid
drivers/scsi/megaraid/Makefile
drivers/scsi/megaraid/megaraid_sas.h
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/megaraid/megaraid_sas_debugfs.c [new file with mode: 0644]
drivers/scsi/megaraid/megaraid_sas_fp.c
drivers/scsi/megaraid/megaraid_sas_fusion.c
drivers/scsi/megaraid/megaraid_sas_fusion.h
drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
drivers/scsi/mpt3sas/mpt3sas_base.c
drivers/scsi/mpt3sas/mpt3sas_base.h
drivers/scsi/mpt3sas/mpt3sas_config.c
drivers/scsi/mpt3sas/mpt3sas_ctl.c
drivers/scsi/mpt3sas/mpt3sas_scsih.c
drivers/scsi/mpt3sas/mpt3sas_transport.c
drivers/scsi/mvsas/mv_sas.c
drivers/scsi/mvsas/mv_sas.h
drivers/scsi/mvumi.c
drivers/scsi/osst.c [deleted file]
drivers/scsi/osst.h [deleted file]
drivers/scsi/osst_detect.h [deleted file]
drivers/scsi/osst_options.h [deleted file]
drivers/scsi/pcmcia/Kconfig
drivers/scsi/pcmcia/Makefile
drivers/scsi/pcmcia/fdomain_cs.c [new file with mode: 0644]
drivers/scsi/pcmcia/nsp_cs.c
drivers/scsi/pm8001/pm8001_ctl.c
drivers/scsi/pm8001/pm8001_hwi.c
drivers/scsi/pm8001/pm8001_sas.c
drivers/scsi/pm8001/pm8001_sas.h
drivers/scsi/pm8001/pm80xx_hwi.c
drivers/scsi/pmcraid.c
drivers/scsi/ppa.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_nvme.c
drivers/scsi/qla2xxx/qla_nvme.h
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/scsi.c
drivers/scsi/scsi_debugfs.h
drivers/scsi/scsi_error.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_pm.c
drivers/scsi/scsi_priv.h
drivers/scsi/scsi_proc.c
drivers/scsi/scsi_sysfs.c
drivers/scsi/scsi_transport_fc.c
drivers/scsi/sd.c
drivers/scsi/ses.c
drivers/scsi/st.c
drivers/scsi/storvsc_drv.c
drivers/scsi/ufs/ufs-qcom.c
drivers/scsi/ufs/ufs-sysfs.c
drivers/scsi/ufs/ufs_bsg.c
drivers/scsi/ufs/ufshcd-pci.c
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshcd.h
drivers/scsi/ufs/ufshci.h
drivers/scsi/virtio_scsi.c
drivers/scsi/vmw_pvscsi.c
drivers/scsi/wd33c93.c
drivers/scsi/wd719x.c
drivers/slimbus/core.c
drivers/slimbus/qcom-ctrl.c
drivers/slimbus/stream.c
drivers/soc/qcom/qcom-geni-se.c
drivers/soundwire/bus.c
drivers/soundwire/cadence_master.c
drivers/soundwire/intel.c
drivers/soundwire/intel.h
drivers/soundwire/intel_init.c
drivers/soundwire/mipi_disco.c
drivers/soundwire/stream.c
drivers/spi/spi.c
drivers/staging/android/ion/Kconfig
drivers/staging/android/ion/Makefile
drivers/staging/android/ion/ion_carveout_heap.c [deleted file]
drivers/staging/android/ion/ion_chunk_heap.c [deleted file]
drivers/staging/comedi/comedi_buf.c
drivers/staging/comedi/comedi_fops.c
drivers/staging/comedi/drivers/amplc_dio200_common.c
drivers/staging/comedi/drivers/amplc_pci230.c
drivers/staging/comedi/drivers/dt282x.c
drivers/staging/comedi/drivers/mite.c
drivers/staging/comedi/drivers/usbdux.c
drivers/staging/erofs/Makefile
drivers/staging/erofs/compress.h [new file with mode: 0644]
drivers/staging/erofs/data.c
drivers/staging/erofs/decompressor.c [new file with mode: 0644]
drivers/staging/erofs/dir.c
drivers/staging/erofs/erofs_fs.h
drivers/staging/erofs/inode.c
drivers/staging/erofs/internal.h
drivers/staging/erofs/namei.c
drivers/staging/erofs/super.c
drivers/staging/erofs/unzip_pagevec.h
drivers/staging/erofs/unzip_vle.c
drivers/staging/erofs/unzip_vle.h
drivers/staging/erofs/unzip_vle_lz4.c [deleted file]
drivers/staging/erofs/utils.c
drivers/staging/erofs/zmap.c [new file with mode: 0644]
drivers/staging/fieldbus/anybuss/Kconfig
drivers/staging/fieldbus/anybuss/arcx-anybus.c
drivers/staging/fieldbus/dev_core.c
drivers/staging/fsl-dpaa2/Kconfig
drivers/staging/fsl-dpaa2/ethsw/ethsw.c
drivers/staging/gasket/gasket_core.c
drivers/staging/gasket/gasket_ioctl.c
drivers/staging/gasket/gasket_page_table.c
drivers/staging/greybus/tools/loopback_test.c
drivers/staging/iio/accel/adis16203.c
drivers/staging/iio/accel/adis16240.c
drivers/staging/iio/adc/Kconfig
drivers/staging/iio/addac/adt7316-spi.c
drivers/staging/iio/addac/adt7316.c
drivers/staging/iio/cdc/ad7150.c
drivers/staging/iio/cdc/ad7746.c
drivers/staging/iio/frequency/ad9834.c
drivers/staging/iio/resolver/ad2s1210.c
drivers/staging/kpc2000/Kconfig
drivers/staging/kpc2000/Makefile
drivers/staging/kpc2000/TODO
drivers/staging/kpc2000/kpc2000/Makefile
drivers/staging/kpc2000/kpc2000/cell_probe.c
drivers/staging/kpc2000/kpc2000/core.c
drivers/staging/kpc2000/kpc2000/dma_common_defs.h
drivers/staging/kpc2000/kpc2000/fileops.c [deleted file]
drivers/staging/kpc2000/kpc2000/kp2000_module.c [deleted file]
drivers/staging/kpc2000/kpc2000/pcie.h
drivers/staging/kpc2000/kpc2000/uapi.h
drivers/staging/kpc2000/kpc2000_i2c.c [new file with mode: 0644]
drivers/staging/kpc2000/kpc2000_spi.c [new file with mode: 0644]
drivers/staging/kpc2000/kpc_dma/dma.c
drivers/staging/kpc2000/kpc_dma/fileops.c
drivers/staging/kpc2000/kpc_dma/kpc_dma_driver.c
drivers/staging/kpc2000/kpc_dma/kpc_dma_driver.h
drivers/staging/kpc2000/kpc_i2c/Makefile [deleted file]
drivers/staging/kpc2000/kpc_i2c/fileops.c [deleted file]
drivers/staging/kpc2000/kpc_i2c/i2c_driver.c [deleted file]
drivers/staging/kpc2000/kpc_spi/Makefile [deleted file]
drivers/staging/kpc2000/kpc_spi/spi_driver.c [deleted file]
drivers/staging/kpc2000/kpc_spi/spi_parts.h [deleted file]
drivers/staging/ks7010/ks7010_sdio.c
drivers/staging/ks7010/ks_hostif.c
drivers/staging/most/Documentation/ABI/configfs-most.txt
drivers/staging/most/Documentation/driver_usage.txt
drivers/staging/most/Kconfig
drivers/staging/most/configfs.c
drivers/staging/most/core.c
drivers/staging/most/net/net.c
drivers/staging/most/video/video.c
drivers/staging/mt7621-dma/mtk-hsdma.c
drivers/staging/mt7621-dts/Kconfig
drivers/staging/mt7621-dts/Makefile
drivers/staging/mt7621-dts/TODO
drivers/staging/mt7621-dts/gbpc1.dts
drivers/staging/mt7621-dts/gbpc2.dts [new file with mode: 0644]
drivers/staging/mt7621-dts/mt7621.dtsi
drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c
drivers/staging/mt7621-pci/mediatek,mt7621-pci.txt
drivers/staging/mt7621-pci/pci-mt7621.c
drivers/staging/netlogic/xlr_net.c
drivers/staging/octeon-usb/octeon-hcd.c
drivers/staging/pi433/pi433_if.c
drivers/staging/pi433/rf69.c
drivers/staging/pi433/rf69_registers.h
drivers/staging/ralink-gdma/ralink-gdma.c
drivers/staging/rtl8188eu/Kconfig
drivers/staging/rtl8188eu/core/rtw_ieee80211.c
drivers/staging/rtl8188eu/core/rtw_mlme.c
drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
drivers/staging/rtl8188eu/core/rtw_recv.c
drivers/staging/rtl8188eu/core/rtw_wlan_util.c
drivers/staging/rtl8188eu/hal/hal_com.c
drivers/staging/rtl8188eu/hal/odm.c
drivers/staging/rtl8188eu/hal/odm_hwconfig.c
drivers/staging/rtl8188eu/hal/usb_halinit.c
drivers/staging/rtl8188eu/include/hal_com.h
drivers/staging/rtl8188eu/include/ieee80211.h
drivers/staging/rtl8188eu/include/odm_precomp.h
drivers/staging/rtl8188eu/include/rtw_eeprom.h
drivers/staging/rtl8188eu/include/rtw_mlme.h
drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
drivers/staging/rtl8188eu/os_dep/mlme_linux.c
drivers/staging/rtl8188eu/os_dep/os_intfs.c
drivers/staging/rtl8188eu/os_dep/rtw_android.c
drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
drivers/staging/rtl8192e/rtllib_module.c
drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c
drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
drivers/staging/rtl8192u/r8192U_core.c
drivers/staging/rtl8192u/r8192U_dm.c
drivers/staging/rtl8192u/r8192U_dm.h
drivers/staging/rtl8712/drv_types.h
drivers/staging/rtl8712/hal_init.c
drivers/staging/rtl8712/ieee80211.c
drivers/staging/rtl8712/mlme_linux.c
drivers/staging/rtl8712/os_intfs.c
drivers/staging/rtl8712/recv_linux.c
drivers/staging/rtl8712/rtl8712_efuse.c
drivers/staging/rtl8712/rtl8712_xmit.c
drivers/staging/rtl8712/rtl871x_cmd.c
drivers/staging/rtl8712/rtl871x_cmd.h
drivers/staging/rtl8712/rtl871x_eeprom.c
drivers/staging/rtl8712/rtl871x_io.c
drivers/staging/rtl8712/rtl871x_ioctl_linux.c
drivers/staging/rtl8712/rtl871x_ioctl_rtl.c
drivers/staging/rtl8712/rtl871x_ioctl_set.c
drivers/staging/rtl8712/rtl871x_mlme.c
drivers/staging/rtl8712/rtl871x_mlme.h
drivers/staging/rtl8712/rtl871x_mp.c
drivers/staging/rtl8712/rtl871x_mp_ioctl.c
drivers/staging/rtl8712/rtl871x_mp_ioctl.h
drivers/staging/rtl8712/rtl871x_recv.c
drivers/staging/rtl8712/rtl871x_security.c
drivers/staging/rtl8712/rtl871x_sta_mgt.c
drivers/staging/rtl8712/rtl871x_xmit.c
drivers/staging/rtl8712/rtl871x_xmit.h
drivers/staging/rtl8712/sta_info.h
drivers/staging/rtl8712/usb_halinit.c
drivers/staging/rtl8712/usb_intf.c
drivers/staging/rtl8712/usb_ops.c
drivers/staging/rtl8712/wifi.h
drivers/staging/rtl8712/xmit_linux.c
drivers/staging/rtl8723bs/Kconfig
drivers/staging/rtl8723bs/TODO
drivers/staging/rtl8723bs/core/rtw_ap.c
drivers/staging/rtl8723bs/core/rtw_btcoex.c
drivers/staging/rtl8723bs/core/rtw_cmd.c
drivers/staging/rtl8723bs/core/rtw_debug.c
drivers/staging/rtl8723bs/core/rtw_eeprom.c
drivers/staging/rtl8723bs/core/rtw_ieee80211.c
drivers/staging/rtl8723bs/core/rtw_ioctl_set.c
drivers/staging/rtl8723bs/core/rtw_mlme.c
drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
drivers/staging/rtl8723bs/core/rtw_pwrctrl.c
drivers/staging/rtl8723bs/core/rtw_recv.c
drivers/staging/rtl8723bs/core/rtw_wlan_util.c
drivers/staging/rtl8723bs/core/rtw_xmit.c
drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c
drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c
drivers/staging/rtl8723bs/hal/HalHWImg8723B_BB.c
drivers/staging/rtl8723bs/hal/HalHWImg8723B_MAC.c
drivers/staging/rtl8723bs/hal/HalHWImg8723B_RF.c
drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c
drivers/staging/rtl8723bs/hal/hal_btcoex.c
drivers/staging/rtl8723bs/hal/hal_com.c
drivers/staging/rtl8723bs/hal/hal_intf.c
drivers/staging/rtl8723bs/hal/hal_phy.c
drivers/staging/rtl8723bs/hal/odm_AntDiv.c [deleted file]
drivers/staging/rtl8723bs/hal/odm_AntDiv.h [deleted file]
drivers/staging/rtl8723bs/hal/odm_DIG.c
drivers/staging/rtl8723bs/hal/odm_HWConfig.c
drivers/staging/rtl8723bs/hal/odm_HWConfig.h
drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.h
drivers/staging/rtl8723bs/hal/odm_precomp.h
drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c
drivers/staging/rtl8723bs/hal/rtl8723b_dm.c
drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c
drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c
drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c
drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c
drivers/staging/rtl8723bs/hal/sdio_halinit.c
drivers/staging/rtl8723bs/hal/sdio_ops.c
drivers/staging/rtl8723bs/include/drv_types.h
drivers/staging/rtl8723bs/include/hal_btcoex.h
drivers/staging/rtl8723bs/include/hal_com.h
drivers/staging/rtl8723bs/include/hal_intf.h
drivers/staging/rtl8723bs/include/ieee80211.h
drivers/staging/rtl8723bs/include/osdep_intf.h
drivers/staging/rtl8723bs/include/osdep_service.h
drivers/staging/rtl8723bs/include/recv_osdep.h
drivers/staging/rtl8723bs/include/rtw_ap.h
drivers/staging/rtl8723bs/include/rtw_btcoex.h
drivers/staging/rtl8723bs/include/rtw_mlme.h
drivers/staging/rtl8723bs/include/rtw_mlme_ext.h
drivers/staging/rtl8723bs/include/sdio_ops.h
drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
drivers/staging/rtl8723bs/os_dep/ioctl_linux.c
drivers/staging/rtl8723bs/os_dep/mlme_linux.c
drivers/staging/rtl8723bs/os_dep/os_intfs.c
drivers/staging/rtl8723bs/os_dep/osdep_service.c
drivers/staging/rtl8723bs/os_dep/recv_linux.c
drivers/staging/rtl8723bs/os_dep/rtw_proc.c
drivers/staging/rtl8723bs/os_dep/sdio_intf.c
drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c
drivers/staging/rtl8723bs/os_dep/xmit_linux.c
drivers/staging/rts5208/TODO
drivers/staging/rts5208/rtsx_chip.c
drivers/staging/rts5208/sd.c
drivers/staging/rts5208/sd.h
drivers/staging/rts5208/xd.c
drivers/staging/speakup/serialio.h
drivers/staging/unisys/Kconfig
drivers/staging/unisys/visorhba/visorhba_main.c
drivers/staging/unisys/visornic/visornic_main.c
drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
drivers/staging/vc04_services/bcm2835-camera/controls.c
drivers/staging/vc04_services/bcm2835-camera/mmal-common.h
drivers/staging/vc04_services/bcm2835-camera/mmal-encodings.h
drivers/staging/vc04_services/bcm2835-camera/mmal-msg-common.h
drivers/staging/vc04_services/bcm2835-camera/mmal-msg-format.h
drivers/staging/vc04_services/bcm2835-camera/mmal-msg-port.h
drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.h
drivers/staging/vt6655/Kconfig
drivers/staging/vt6655/card.c
drivers/staging/vt6655/card.h
drivers/staging/vt6655/test
drivers/staging/vt6656/Kconfig
drivers/staging/vt6656/baseband.c
drivers/staging/vt6656/baseband.h
drivers/staging/vt6656/card.c
drivers/staging/vt6656/firmware.c
drivers/staging/vt6656/int.c
drivers/staging/vt6656/int.h
drivers/staging/vt6656/mac.c
drivers/staging/vt6656/mac.h
drivers/staging/vt6656/main_usb.c
drivers/staging/vt6656/rf.c
drivers/staging/vt6656/rf.h
drivers/staging/vt6656/usbpipe.c
drivers/staging/vt6656/usbpipe.h
drivers/staging/wilc1000/Makefile
drivers/staging/wilc1000/host_interface.c [deleted file]
drivers/staging/wilc1000/host_interface.h [deleted file]
drivers/staging/wilc1000/wilc_hif.c [new file with mode: 0644]
drivers/staging/wilc1000/wilc_hif.h [new file with mode: 0644]
drivers/staging/wilc1000/wilc_mon.c
drivers/staging/wilc1000/wilc_netdev.c
drivers/staging/wilc1000/wilc_sdio.c
drivers/staging/wilc1000/wilc_spi.c
drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
drivers/staging/wilc1000/wilc_wfi_cfgoperations.h
drivers/staging/wilc1000/wilc_wfi_netdevice.h
drivers/staging/wilc1000/wilc_wlan.c
drivers/staging/wilc1000/wilc_wlan.h
drivers/staging/wilc1000/wilc_wlan_if.h
drivers/staging/wlan-ng/cfg80211.c
drivers/target/iscsi/iscsi_target_nego.c
drivers/target/target_core_user.c
drivers/thermal/broadcom/bcm2835_thermal.c
drivers/thermal/intel/intel_powerclamp.c
drivers/thermal/intel/x86_pkg_temp_thermal.c
drivers/thermal/tegra/soctherm.c
drivers/thunderbolt/switch.c
drivers/tty/serial/8250/8250.h
drivers/tty/serial/8250/8250_core.c
drivers/tty/serial/8250/8250_dma.c
drivers/tty/serial/8250/8250_mtk.c
drivers/tty/serial/8250/8250_of.c
drivers/tty/serial/8250/8250_omap.c
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/8250/8250_pnp.c
drivers/tty/serial/8250/8250_port.c
drivers/tty/serial/8250/Kconfig
drivers/tty/serial/Kconfig
drivers/tty/serial/Makefile
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/cpm_uart/cpm_uart_core.c
drivers/tty/serial/digicolor-usart.c
drivers/tty/serial/fsl_lpuart.c
drivers/tty/serial/imx.c
drivers/tty/serial/max310x.c
drivers/tty/serial/mpsc.c [deleted file]
drivers/tty/serial/msm_serial.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/serial_mctrl_gpio.c
drivers/tty/serial/sh-sci.c
drivers/tty/serial/stm32-usart.c
drivers/tty/serial/stm32-usart.h
drivers/tty/serial/xilinx_uartps.c
drivers/tty/tty_io.c
drivers/usb/Kconfig
drivers/usb/Makefile
drivers/usb/atm/Kconfig
drivers/usb/atm/ueagle-atm.c
drivers/usb/chipidea/ci_hdrc_imx.c
drivers/usb/chipidea/ci_hdrc_msm.c
drivers/usb/chipidea/core.c
drivers/usb/chipidea/usbmisc_imx.c
drivers/usb/class/Kconfig
drivers/usb/class/cdc-wdm.c
drivers/usb/common/common.c
drivers/usb/common/common.h [new file with mode: 0644]
drivers/usb/common/led.c
drivers/usb/core/Kconfig
drivers/usb/core/buffer.c
drivers/usb/core/devio.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/notify.c
drivers/usb/core/usb.c
drivers/usb/core/usb.h
drivers/usb/dwc2/Kconfig
drivers/usb/dwc2/core.c
drivers/usb/dwc2/core.h
drivers/usb/dwc2/hcd.c
drivers/usb/dwc2/hcd.h
drivers/usb/dwc2/params.c
drivers/usb/dwc2/platform.c
drivers/usb/dwc3/Kconfig
drivers/usb/dwc3/core.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/dwc3-meson-g12a.c
drivers/usb/dwc3/dwc3-pci.c
drivers/usb/dwc3/dwc3-qcom.c
drivers/usb/dwc3/ep0.c
drivers/usb/dwc3/gadget.c
drivers/usb/dwc3/gadget.h
drivers/usb/gadget/Kconfig
drivers/usb/gadget/composite.c
drivers/usb/gadget/function/f_eem.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/f_mass_storage.c
drivers/usb/gadget/function/u_audio.c
drivers/usb/gadget/function/u_ether.c
drivers/usb/gadget/legacy/Kconfig
drivers/usb/gadget/udc/at91_udc.c
drivers/usb/gadget/udc/fotg210-udc.c
drivers/usb/gadget/udc/net2272.c
drivers/usb/gadget/udc/omap_udc.c
drivers/usb/gadget/udc/renesas_usb3.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-exynos.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-fsl.h
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-st.c
drivers/usb/host/fotg210-hcd.c
drivers/usb/host/fsl-mph-dr-of.c
drivers/usb/host/isp1362.h
drivers/usb/host/ohci-exynos.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-mem.c
drivers/usb/host/ohci-pci.c
drivers/usb/host/ohci-s3c2410.c
drivers/usb/host/ohci-sm501.c
drivers/usb/host/ohci-spear.c
drivers/usb/host/ohci-st.c
drivers/usb/host/ohci-tmio.c
drivers/usb/host/ohci.h
drivers/usb/host/u132-hcd.c
drivers/usb/host/uhci-hcd.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci-tegra.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/image/microtek.c
drivers/usb/image/microtek.h
drivers/usb/misc/Kconfig
drivers/usb/misc/adutux.c
drivers/usb/misc/ftdi-elan.c
drivers/usb/misc/sisusbvga/sisusb.c
drivers/usb/mon/Kconfig
drivers/usb/mtu3/mtu3_debugfs.c
drivers/usb/phy/phy-am335x-control.c
drivers/usb/phy/phy-isp1301.c
drivers/usb/phy/phy-mv-usb.c
drivers/usb/phy/phy-mxs-usb.c
drivers/usb/renesas_usbhs/Kconfig
drivers/usb/renesas_usbhs/Makefile
drivers/usb/renesas_usbhs/common.c
drivers/usb/renesas_usbhs/common.h
drivers/usb/renesas_usbhs/fifo.c
drivers/usb/renesas_usbhs/mod.c
drivers/usb/renesas_usbhs/mod.h
drivers/usb/renesas_usbhs/mod_gadget.c
drivers/usb/renesas_usbhs/rcar2.c
drivers/usb/renesas_usbhs/rcar2.h
drivers/usb/renesas_usbhs/rcar3.c
drivers/usb/renesas_usbhs/rcar3.h
drivers/usb/renesas_usbhs/rza.c
drivers/usb/renesas_usbhs/rza.h
drivers/usb/renesas_usbhs/rza2.c [new file with mode: 0644]
drivers/usb/serial/Kconfig
drivers/usb/serial/belkin_sa.c
drivers/usb/serial/belkin_sa.h
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/empeg.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/ir-usb.c
drivers/usb/serial/keyspan_pda.c
drivers/usb/serial/omninet.c
drivers/usb/serial/option.c
drivers/usb/serial/oti6858.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/visor.c
drivers/usb/serial/visor.h
drivers/usb/serial/whiteheat.c
drivers/usb/serial/whiteheat.h
drivers/usb/storage/scsiglue.c
drivers/usb/typec/tcpm/fusb302.c
drivers/usb/typec/tps6598x.c
drivers/usb/usbip/stub_main.c
drivers/usb/usbip/vhci_tx.c
drivers/usb/wusbcore/Kconfig
drivers/usb/wusbcore/crypto.c
drivers/video/fbdev/au1100fb.c
drivers/video/fbdev/au1100fb.h
drivers/visorbus/visorbus_main.c
drivers/w1/slaves/w1_ds2413.c
drivers/w1/slaves/w1_ds2805.c
drivers/watchdog/bcm_kona_wdt.c
drivers/watchdog/mei_wdt.c
drivers/xen/gntdev.c
drivers/xen/privcmd.c
drivers/xen/xlate_mmu.c
fs/9p/vfs_addr.c
fs/aio.c
fs/btrfs/ioctl.c
fs/btrfs/sysfs.c
fs/ceph/debugfs.c
fs/ceph/super.c
fs/ceph/super.h
fs/char_dev.c
fs/debugfs/file.c
fs/debugfs/inode.c
fs/dlm/debug_fs.c
fs/dlm/dlm_internal.h
fs/dlm/lockspace.c
fs/dlm/lowcomms.c
fs/dlm/main.c
fs/efivarfs/file.c
fs/ext2/ioctl.c
fs/ext4/ioctl.c
fs/f2fs/checkpoint.c
fs/f2fs/data.c
fs/f2fs/debug.c
fs/f2fs/dir.c
fs/f2fs/extent_cache.c
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/gc.c
fs/f2fs/inline.c
fs/f2fs/inode.c
fs/f2fs/namei.c
fs/f2fs/node.c
fs/f2fs/recovery.c
fs/f2fs/segment.c
fs/f2fs/segment.h
fs/f2fs/super.c
fs/f2fs/sysfs.c
fs/f2fs/xattr.c
fs/gfs2/file.c
fs/gfs2/sys.c
fs/hfsplus/ioctl.c
fs/inode.c
fs/io_uring.c
fs/jffs2/file.c
fs/jffs2/fs.c
fs/jffs2/os-linux.h
fs/jfs/ioctl.c
fs/nfsd/fault_inject.c
fs/nfsd/nfsctl.c
fs/nfsd/state.h
fs/nilfs2/ioctl.c
fs/notify/fanotify/fanotify.c
fs/notify/inotify/inotify_fsnotify.c
fs/ocfs2/alloc.c
fs/ocfs2/blockcheck.c
fs/ocfs2/blockcheck.h
fs/ocfs2/cluster/heartbeat.c
fs/ocfs2/cluster/heartbeat.h
fs/ocfs2/cluster/netdebug.c
fs/ocfs2/cluster/nodemanager.c
fs/ocfs2/cluster/quorum.c
fs/ocfs2/cluster/tcp.c
fs/ocfs2/cluster/tcp.h
fs/ocfs2/dlm/dlmdebug.c
fs/ocfs2/dlm/dlmdebug.h
fs/ocfs2/dlm/dlmdomain.c
fs/ocfs2/dlm/dlmmaster.c
fs/ocfs2/dlm/dlmrecovery.c
fs/ocfs2/dlmglue.c
fs/ocfs2/ioctl.c
fs/ocfs2/localalloc.c
fs/ocfs2/ocfs2.h
fs/ocfs2/super.c
fs/orangefs/file.c
fs/orangefs/orangefs-debugfs.c
fs/orangefs/orangefs-debugfs.h
fs/orangefs/orangefs-mod.c
fs/proc/base.c
fs/proc/meminfo.c
fs/proc/task_mmu.c
fs/proc/task_nommu.c
fs/pstore/ftrace.c
fs/pstore/inode.c
fs/pstore/ram.c
fs/reiserfs/ioctl.c
fs/splice.c
fs/ubifs/debug.c
fs/ubifs/debug.h
fs/ubifs/ioctl.c
fs/ubifs/super.c
fs/xfs/Makefile
fs/xfs/kmem.c
fs/xfs/kmem.h
fs/xfs/libxfs/xfs_ag.c
fs/xfs/libxfs/xfs_ag_resv.c
fs/xfs/libxfs/xfs_alloc.c
fs/xfs/libxfs/xfs_alloc_btree.c
fs/xfs/libxfs/xfs_attr.c
fs/xfs/libxfs/xfs_attr.h
fs/xfs/libxfs/xfs_attr_leaf.c
fs/xfs/libxfs/xfs_attr_remote.c
fs/xfs/libxfs/xfs_bit.c
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_bmap_btree.c
fs/xfs/libxfs/xfs_btree.c
fs/xfs/libxfs/xfs_btree.h
fs/xfs/libxfs/xfs_da_btree.c
fs/xfs/libxfs/xfs_da_format.c
fs/xfs/libxfs/xfs_defer.c
fs/xfs/libxfs/xfs_dir2.c
fs/xfs/libxfs/xfs_dir2_block.c
fs/xfs/libxfs/xfs_dir2_data.c
fs/xfs/libxfs/xfs_dir2_leaf.c
fs/xfs/libxfs/xfs_dir2_node.c
fs/xfs/libxfs/xfs_dir2_sf.c
fs/xfs/libxfs/xfs_dquot_buf.c
fs/xfs/libxfs/xfs_format.h
fs/xfs/libxfs/xfs_fs.h
fs/xfs/libxfs/xfs_health.h
fs/xfs/libxfs/xfs_ialloc.c
fs/xfs/libxfs/xfs_ialloc.h
fs/xfs/libxfs/xfs_ialloc_btree.c
fs/xfs/libxfs/xfs_ialloc_btree.h
fs/xfs/libxfs/xfs_iext_tree.c
fs/xfs/libxfs/xfs_inode_buf.c
fs/xfs/libxfs/xfs_inode_fork.c
fs/xfs/libxfs/xfs_log_rlimit.c
fs/xfs/libxfs/xfs_refcount.c
fs/xfs/libxfs/xfs_refcount_btree.c
fs/xfs/libxfs/xfs_rmap.c
fs/xfs/libxfs/xfs_rmap_btree.c
fs/xfs/libxfs/xfs_rtbitmap.c
fs/xfs/libxfs/xfs_sb.c
fs/xfs/libxfs/xfs_shared.h
fs/xfs/libxfs/xfs_symlink_remote.c
fs/xfs/libxfs/xfs_trans_resv.c
fs/xfs/libxfs/xfs_trans_space.h
fs/xfs/libxfs/xfs_types.c
fs/xfs/scrub/agheader.c
fs/xfs/scrub/agheader_repair.c
fs/xfs/scrub/alloc.c
fs/xfs/scrub/attr.c
fs/xfs/scrub/attr.h [new file with mode: 0644]
fs/xfs/scrub/bitmap.c
fs/xfs/scrub/bmap.c
fs/xfs/scrub/btree.c
fs/xfs/scrub/common.c
fs/xfs/scrub/dabtree.c
fs/xfs/scrub/dir.c
fs/xfs/scrub/fscounters.c
fs/xfs/scrub/health.c
fs/xfs/scrub/ialloc.c
fs/xfs/scrub/inode.c
fs/xfs/scrub/parent.c
fs/xfs/scrub/quota.c
fs/xfs/scrub/refcount.c
fs/xfs/scrub/repair.c
fs/xfs/scrub/rmap.c
fs/xfs/scrub/rtbitmap.c
fs/xfs/scrub/scrub.c
fs/xfs/scrub/symlink.c
fs/xfs/scrub/trace.c
fs/xfs/xfs_acl.c
fs/xfs/xfs_aops.c
fs/xfs/xfs_aops.h
fs/xfs/xfs_attr_inactive.c
fs/xfs/xfs_attr_list.c
fs/xfs/xfs_bio_io.c [new file with mode: 0644]
fs/xfs/xfs_bmap_item.c
fs/xfs/xfs_bmap_item.h
fs/xfs/xfs_bmap_util.c
fs/xfs/xfs_buf.c
fs/xfs/xfs_buf.h
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_buf_item.h
fs/xfs/xfs_dir2_readdir.c
fs/xfs/xfs_discard.c
fs/xfs/xfs_dquot.c
fs/xfs/xfs_dquot.h
fs/xfs/xfs_dquot_item.c
fs/xfs/xfs_dquot_item.h
fs/xfs/xfs_error.c
fs/xfs/xfs_export.c
fs/xfs/xfs_extfree_item.c
fs/xfs/xfs_extfree_item.h
fs/xfs/xfs_file.c
fs/xfs/xfs_filestream.c
fs/xfs/xfs_fsmap.c
fs/xfs/xfs_fsops.c
fs/xfs/xfs_globals.c
fs/xfs/xfs_health.c
fs/xfs/xfs_icache.c
fs/xfs/xfs_icreate_item.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode_item.c
fs/xfs/xfs_inode_item.h
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_ioctl.h
fs/xfs/xfs_ioctl32.c
fs/xfs/xfs_ioctl32.h
fs/xfs/xfs_iomap.c
fs/xfs/xfs_iops.c
fs/xfs/xfs_itable.c
fs/xfs/xfs_itable.h
fs/xfs/xfs_iwalk.c [new file with mode: 0644]
fs/xfs/xfs_iwalk.h [new file with mode: 0644]
fs/xfs/xfs_linux.h
fs/xfs/xfs_log.c
fs/xfs/xfs_log.h
fs/xfs/xfs_log_cil.c
fs/xfs/xfs_log_priv.h
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_message.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_mount.h
fs/xfs/xfs_ondisk.h
fs/xfs/xfs_pnfs.c
fs/xfs/xfs_pwork.c [new file with mode: 0644]
fs/xfs/xfs_pwork.h [new file with mode: 0644]
fs/xfs/xfs_qm.c
fs/xfs/xfs_qm_bhv.c
fs/xfs/xfs_qm_syscalls.c
fs/xfs/xfs_quotaops.c
fs/xfs/xfs_refcount_item.c
fs/xfs/xfs_refcount_item.h
fs/xfs/xfs_reflink.c
fs/xfs/xfs_rmap_item.c
fs/xfs/xfs_rmap_item.h
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_stats.c
fs/xfs/xfs_super.c
fs/xfs/xfs_super.h
fs/xfs/xfs_symlink.c
fs/xfs/xfs_sysctl.c
fs/xfs/xfs_sysctl.h
fs/xfs/xfs_sysfs.c
fs/xfs/xfs_trace.c
fs/xfs/xfs_trace.h
fs/xfs/xfs_trans.c
fs/xfs/xfs_trans.h
fs/xfs/xfs_trans_ail.c
fs/xfs/xfs_trans_bmap.c [deleted file]
fs/xfs/xfs_trans_buf.c
fs/xfs/xfs_trans_dquot.c
fs/xfs/xfs_trans_extfree.c [deleted file]
fs/xfs/xfs_trans_inode.c
fs/xfs/xfs_trans_priv.h
fs/xfs/xfs_trans_refcount.c [deleted file]
fs/xfs/xfs_trans_rmap.c [deleted file]
fs/xfs/xfs_xattr.c
include/Kbuild [new file with mode: 0644]
include/asm-generic/bitops-instrumented.h [new file with mode: 0644]
include/asm-generic/mshyperv.h [new file with mode: 0644]
include/asm-generic/pgalloc.h
include/asm-generic/ptrace.h [deleted file]
include/kvm/arm_pmu.h
include/linux/backing-dev-defs.h
include/linux/balloon_compaction.h
include/linux/ceph/debugfs.h
include/linux/coresight.h
include/linux/cpuhotplug.h
include/linux/debugfs.h
include/linux/device.h
include/linux/dma-contiguous.h
include/linux/dma-mapping.h
include/linux/dma-noncoherent.h
include/linux/dma/mxs-dma.h [new file with mode: 0644]
include/linux/dmar.h
include/linux/firmware/xlnx-zynqmp.h
include/linux/fs.h
include/linux/fsl_devices.h
include/linux/genalloc.h
include/linux/gpio.h
include/linux/gpio/driver.h
include/linux/hugetlb.h
include/linux/ide.h
include/linux/input/elan-i2c-ids.h [new file with mode: 0644]
include/linux/kasan-checks.h
include/linux/kasan.h
include/linux/kvm_host.h
include/linux/livepatch.h
include/linux/memcontrol.h
include/linux/mfd/cros_ec.h
include/linux/mfd/cros_ec_commands.h
include/linux/mfd/syscon.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/mmc/host.h
include/linux/mtd/cfi.h
include/linux/mtd/hyperbus.h [new file with mode: 0644]
include/linux/mtd/mtd.h
include/linux/mtd/onenand_regs.h
include/linux/mtd/rawnand.h
include/linux/mtd/spinand.h
include/linux/mv643xx.h
include/linux/of_fdt.h
include/linux/oom.h
include/linux/page-flags.h
include/linux/page-isolation.h
include/linux/page_ext.h
include/linux/pagemap.h
include/linux/pfn_t.h
include/linux/pinctrl/pinconf-generic.h
include/linux/pinctrl/pinconf.h
include/linux/pinctrl/pinctrl-state.h
include/linux/pinctrl/pinctrl.h
include/linux/pinctrl/pinmux.h
include/linux/platform_data/fsa9480.h [deleted file]
include/linux/platform_data/wilco-ec.h
include/linux/scatterlist.h
include/linux/serial_8250.h
include/linux/slab.h
include/linux/socket.h
include/linux/soundwire/sdw.h
include/linux/soundwire/sdw_type.h
include/linux/swap.h
include/linux/uio.h
include/linux/usb.h
include/linux/usb/chipidea.h
include/linux/usb/gadget.h
include/linux/usb/hcd.h
include/linux/usb/renesas_usbhs.h
include/linux/vmalloc.h
include/linux/vmpressure.h
include/linux/vmw_vmci_defs.h
include/scsi/fc/fc_fip.h
include/scsi/fc/fc_ms.h
include/scsi/iscsi_if.h
include/scsi/iscsi_proto.h
include/scsi/libiscsi_tcp.h
include/scsi/libsas.h
include/scsi/sas.h
include/scsi/scsi_transport.h
include/scsi/scsi_transport_fc.h
include/trace/events/f2fs.h
include/uapi/Kbuild [new file with mode: 0644]
include/uapi/linux/Kbuild [deleted file]
include/uapi/linux/io_uring.h
include/uapi/linux/kvm.h
include/uapi/linux/kvm_para.h
include/uapi/linux/nilfs2_ondisk.h
include/uapi/linux/serial_core.h
include/uapi/linux/usbdevice_fs.h
include/uapi/misc/habanalabs.h
include/uapi/mtd/mtd-abi.h
include/uapi/scsi/fc/fc_els.h
include/uapi/scsi/fc/fc_fs.h
include/uapi/scsi/fc/fc_gs.h
include/uapi/scsi/fc/fc_ns.h
include/uapi/scsi/scsi_bsg_fc.h
include/uapi/scsi/scsi_netlink.h
include/uapi/scsi/scsi_netlink_fc.h
init/Kconfig
init/main.c
kernel/dma/contiguous.c
kernel/dma/direct.c
kernel/dma/mapping.c
kernel/dma/remap.c
kernel/dma/swiotlb.c
kernel/fail_function.c
kernel/gcov/fs.c
kernel/gen_kheaders.sh
kernel/iomem.c
kernel/kprobes.c
kernel/livepatch/transition.c
kernel/stacktrace.c
kernel/time/vsyscall.c
kernel/trace/blktrace.c
kernel/trace/trace.c
lib/842/842_debugfs.h
lib/Kconfig.debug
lib/dynamic_debug.c
lib/fault-inject.c
lib/fonts/fonts.c
lib/genalloc.c
lib/iov_iter.c
lib/kobject.c
lib/notifier-error-inject.c
lib/raid6/Makefile
lib/scatterlist.c
lib/sg_pool.c
lib/test_kasan.c
mm/Kconfig
mm/Kconfig.debug
mm/Makefile
mm/backing-dev.c
mm/balloon_compaction.c
mm/cleancache.c
mm/dmapool.c
mm/failslab.c
mm/filemap.c
mm/gup.c
mm/hwpoison-inject.c
mm/kasan/common.c
mm/kasan/generic.c
mm/kasan/kasan.h
mm/kasan/report.c
mm/kasan/tags.c
mm/kmemleak.c
mm/list_lru.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory.c
mm/mincore.c
mm/mmu_notifier.c
mm/nommu.c
mm/oom_kill.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_ext.c
mm/page_io.c
mm/page_isolation.c
mm/slab.c
mm/slab.h
mm/slab_common.c
mm/slob.c
mm/slub.c
mm/swap_state.c
mm/swapfile.c
mm/util.c
mm/vmalloc.c
mm/vmscan.c
mm/z3fold.c
mm/zsmalloc.c
mm/zswap.c
net/9p/trans_virtio.c
net/9p/trans_xen.c
net/bpfilter/Kconfig
net/ceph/ceph_common.c
net/ceph/debugfs.c
net/compat.c
net/core/sock.c
net/socket.c
net/sunrpc/debugfs.c
net/sunrpc/xprtrdma/svc_rdma_rw.c
samples/Kconfig
samples/Makefile
scripts/Kbuild.include
scripts/Makefile
scripts/Makefile.build
scripts/Makefile.extrawarn
scripts/Makefile.headersinst
scripts/Makefile.host
scripts/Makefile.lib
scripts/Makefile.modbuiltin
scripts/basic/fixdep.c
scripts/coccinelle/api/kstrdup.cocci
scripts/coccinelle/api/stream_open.cocci
scripts/coccinelle/free/devm_free.cocci
scripts/coccinelle/free/put_device.cocci
scripts/decode_stacktrace.sh
scripts/dtc/Makefile.dtc
scripts/dtc/checks.c
scripts/dtc/dtc-lexer.l
scripts/dtc/dtc-parser.y
scripts/dtc/dtc.h
scripts/dtc/flattree.c
scripts/dtc/libfdt/Makefile.libfdt
scripts/dtc/libfdt/fdt.c
scripts/dtc/libfdt/fdt.h
scripts/dtc/libfdt/fdt_addresses.c
scripts/dtc/libfdt/fdt_empty_tree.c
scripts/dtc/libfdt/fdt_overlay.c
scripts/dtc/libfdt/fdt_ro.c
scripts/dtc/libfdt/fdt_rw.c
scripts/dtc/libfdt/fdt_strerror.c
scripts/dtc/libfdt/fdt_sw.c
scripts/dtc/libfdt/fdt_wip.c
scripts/dtc/libfdt/libfdt.h
scripts/dtc/libfdt/libfdt_env.h
scripts/dtc/libfdt/libfdt_internal.h
scripts/dtc/livetree.c
scripts/dtc/util.h
scripts/dtc/version_gen.h
scripts/gdb/linux/Makefile
scripts/genksyms/keywords.c
scripts/genksyms/parse.y
scripts/get_abi.pl [new file with mode: 0755]
scripts/headers.sh [deleted file]
scripts/headers_install.sh
scripts/kallsyms.c
scripts/kconfig/Makefile
scripts/kconfig/conf.c
scripts/kconfig/confdata.c
scripts/kconfig/lkc.h
scripts/kconfig/lkc_proto.h
scripts/kconfig/mconf.c
scripts/kconfig/nconf.c
scripts/kconfig/preprocess.c
scripts/kconfig/qconf.cc
scripts/kconfig/symbol.c
scripts/package/builddeb
scripts/package/mkspec
scripts/spelling.txt
scripts/tags.sh
security/Kconfig.hardening
security/loadpin/loadpin.c
sound/soc/codecs/cros_ec_codec.c
sound/soc/rockchip/rk3399_gru_sound.c
tools/firmware/Makefile
tools/iio/iio_utils.c
tools/include/uapi/linux/kvm.h
tools/testing/selftests/Makefile
tools/testing/selftests/cgroup/test_freezer.c
tools/testing/selftests/drivers/dma-buf/config [new file with mode: 0644]
tools/testing/selftests/firmware/fw_filesystem.sh
tools/testing/selftests/firmware/fw_lib.sh
tools/testing/selftests/firmware/fw_run_tests.sh
tools/testing/selftests/kvm/dirty_log_test.c
tools/testing/selftests/kvm/include/aarch64/processor.h
tools/testing/selftests/kvm/include/kvm_util.h
tools/testing/selftests/kvm/lib/aarch64/processor.c
tools/testing/selftests/kvm/lib/kvm_util.c
tools/testing/selftests/kvm/lib/kvm_util_internal.h
tools/testing/selftests/kvm/lib/ucall.c
tools/testing/selftests/kvm/lib/x86_64/processor.c
tools/testing/selftests/kvm/x86_64/evmcs_test.c
tools/testing/selftests/kvm/x86_64/kvm_create_max_vcpus.c
tools/testing/selftests/kvm/x86_64/smm_test.c
tools/testing/selftests/kvm/x86_64/state_test.c
tools/testing/selftests/lib.mk
tools/testing/selftests/networking/timestamping/timestamping.c
tools/testing/selftests/rseq/rseq-arm.h
tools/vm/slabinfo.c
usr/.gitignore
usr/Makefile
usr/include/.gitignore [new file with mode: 0644]
usr/include/Makefile [new file with mode: 0644]
virt/kvm/arm/arch_timer.c
virt/kvm/arm/arm.c
virt/kvm/arm/mmu.c
virt/kvm/arm/pmu.c
virt/kvm/arm/psci.c
virt/kvm/irqchip.c
virt/kvm/kvm_main.c

index 16020b3..5d41eba 100644 (file)
@@ -5,7 +5,7 @@ Description:    It is possible to switch the cpi setting of the mouse with the
                press of a button.
                When read, this file returns the raw number of the actual cpi
                setting reported by the mouse. This number has to be further
-               processed to receive the real dpi value.
+               processed to receive the real dpi value:
 
                VALUE DPI
                1     400
index 156319f..3544968 100644 (file)
@@ -1,5 +1,4 @@
-What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
-                                                       asic_health
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/asic_health
 
 Date:          June 2018
 KernelVersion: 4.19
@@ -9,9 +8,8 @@ Description:    This file shows ASIC health status. The possible values are:
 
                The files are read only.
 
-What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
-                                                       cpld1_version
-                                                       cpld2_version
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld1_version
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld2_version
 Date:          June 2018
 KernelVersion: 4.19
 Contact:       Vadim Pasternak <vadimpmellanox.com>
@@ -20,8 +18,7 @@ Description:  These files show with which CPLD versions have been burned
 
                The files are read only.
 
-What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
-                                                       fan_dir
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/fan_dir
 
 Date:          December 2018
 KernelVersion: 5.0
@@ -32,8 +29,7 @@ Description:  This file shows the system fans direction:
 
                The files are read only.
 
-What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
-                                                       jtag_enable
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/jtag_enable
 
 Date:          November 2018
 KernelVersion: 5.0
@@ -43,8 +39,7 @@ Description:  These files show with which CPLD versions have been burned
 
                The files are read only.
 
-What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
-                                                       jtag_enable
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/jtag_enable
 
 Date:          November 2018
 KernelVersion: 5.0
@@ -87,16 +82,15 @@ Description:        These files allow asserting system power cycling, switching
 
                The files are write only.
 
-What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
-                                                       reset_aux_pwr_or_ref
-                                                       reset_asic_thermal
-                                                       reset_hotswap_or_halt
-                                                       reset_hotswap_or_wd
-                                                       reset_fw_reset
-                                                       reset_long_pb
-                                                       reset_main_pwr_fail
-                                                       reset_short_pb
-                                                       reset_sw_reset
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_aux_pwr_or_ref
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_asic_thermal
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_hotswap_or_halt
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_hotswap_or_wd
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_fw_reset
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_long_pb
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_main_pwr_fail
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_short_pb
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_sw_reset
 Date:          June 2018
 KernelVersion: 4.19
 Contact:       Vadim Pasternak <vadimpmellanox.com>
@@ -110,11 +104,10 @@ Description:      These files show the system reset cause, as following: power
 
                The files are read only.
 
-What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
-                                               reset_comex_pwr_fail
-                                               reset_from_comex
-                                               reset_system
-                                               reset_voltmon_upgrade_fail
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_comex_pwr_fail
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_from_comex
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_system
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_voltmon_upgrade_fail
 
 Date:          November 2018
 KernelVersion: 5.0
diff --git a/Documentation/ABI/testing/debugfs-cros-ec b/Documentation/ABI/testing/debugfs-cros-ec
new file mode 100644 (file)
index 0000000..1fe0add
--- /dev/null
@@ -0,0 +1,56 @@
+What:          /sys/kernel/debug/<cros-ec-device>/console_log
+Date:          September 2017
+KernelVersion: 4.13
+Description:
+               If the EC supports the CONSOLE_READ command type, this file
+               can be used to grab the EC logs. The kernel polls for the log
+               and keeps its own buffer but userspace should grab this and
+               write it out to some logs.
+
+What:          /sys/kernel/debug/<cros-ec-device>/panicinfo
+Date:          September 2017
+KernelVersion: 4.13
+Description:
+               This file dumps the EC panic information from the previous
+               reboot. This file will only exist if the PANIC_INFO command
+               type is supported by the EC.
+
+What:          /sys/kernel/debug/<cros-ec-device>/pdinfo
+Date:          June 2018
+KernelVersion: 4.17
+Description:
+               This file provides the port role, muxes and power debug
+               information for all the USB PD/type-C ports available. If
+               the are no ports available, this file will be just an empty
+               file.
+
+What:          /sys/kernel/debug/<cros-ec-device>/uptime
+Date:          June 2019
+KernelVersion: 5.3
+Description:
+               A u32 providing the time since EC booted in ms. This is
+               is used for synchronizing the AP host time with the EC
+               log. An error is returned if the command is not supported
+               by the EC or there is a communication problem.
+
+What:          /sys/kernel/debug/<cros-ec-device>/last_resume_result
+Date:          June 2019
+KernelVersion: 5.3
+Description:
+               Some ECs have a feature where they will track transitions to
+               the (Intel) processor's SLP_S0 line, in order to detect cases
+               where a system failed to go into S0ix. When the system resumes,
+               an EC with this feature will return a summary of SLP_S0
+               transitions that occurred. The last_resume_result file returns
+               the most recent response from the AP's resume message to the EC.
+
+               The bottom 31 bits contain a count of the number of SLP_S0
+               transitions that occurred since the suspend message was
+               received. Bit 31 is set if the EC attempted to wake the
+               system due to a timeout when watching for SLP_S0 transitions.
+               Callers can use this to detect a wake from the EC due to
+               S0ix timeouts. The result will be zero if no suspend
+               transitions have been attempted, or the EC does not support
+               this feature.
+
+               Output will be in the format: "0x%08x\n".
index 2f5b80b..f0ac14b 100644 (file)
@@ -3,7 +3,10 @@ Date:           Jan 2019
 KernelVersion:  5.1
 Contact:        oded.gabbay@gmail.com
 Description:    Sets the device address to be used for read or write through
-                PCI bar. The acceptable value is a string that starts with "0x"
+                PCI bar, or the device VA of a host mapped memory to be read or
+                written directly from the host. The latter option is allowed
+                only when the IOMMU is disabled.
+                The acceptable value is a string that starts with "0x"
 
 What:           /sys/kernel/debug/habanalabs/hl<n>/command_buffers
 Date:           Jan 2019
@@ -33,10 +36,12 @@ Contact:        oded.gabbay@gmail.com
 Description:    Allows the root user to read or write directly through the
                 device's PCI bar. Writing to this file generates a write
                 transaction while reading from the file generates a read
-                transcation. This custom interface is needed (instead of using
+                transaction. This custom interface is needed (instead of using
                 the generic Linux user-space PCI mapping) because the DDR bar
                 is very small compared to the DDR memory and only the driver can
-                move the bar before and after the transaction
+                move the bar before and after the transaction.
+                If the IOMMU is disabled, it also allows the root user to read
+                or write from the host a device VA of a host mapped memory
 
 What:           /sys/kernel/debug/habanalabs/hl<n>/device
 Date:           Jan 2019
@@ -46,6 +51,13 @@ Description:    Enables the root user to set the device to specific state.
                 Valid values are "disable", "enable", "suspend", "resume".
                 User can read this property to see the valid values
 
+What:           /sys/kernel/debug/habanalabs/hl<n>/engines
+Date:           Jul 2019
+KernelVersion:  5.3
+Contact:        oded.gabbay@gmail.com
+Description:    Displays the status registers values of the device engines and
+                their derived idle status
+
 What:           /sys/kernel/debug/habanalabs/hl<n>/i2c_addr
 Date:           Jan 2019
 KernelVersion:  5.1
index 73a5a66..9d8d9d2 100644 (file)
@@ -23,11 +23,9 @@ Description:
 
                For writing, bytes 0-1 indicate the message type, one of enum
                wilco_ec_msg_type. Byte 2+ consist of the data passed in the
-               request, starting at MBOX[0]
-
-               At least three bytes are required for writing, two for the type
-               and at least a single byte of data. Only the first
-               EC_MAILBOX_DATA_SIZE bytes of MBOX will be used.
+               request, starting at MBOX[0]. At least three bytes are required
+               for writing, two for the type and at least a single byte of
+               data.
 
                Example:
                // Request EC info type 3 (EC firmware build date)
@@ -40,7 +38,7 @@ Description:
                $ cat /sys/kernel/debug/wilco_ec/raw
                00 00 31 32 2f 32 31 2f 31 38 00 38 00 01 00 2f 00  ..12/21/18.8...
 
-               Note that the first 32 bytes of the received MBOX[] will be
-               printed, even if some of the data is junk. It is up to you to
-               know how many of the first bytes of data are the actual
-               response.
+               Note that the first 16 bytes of the received MBOX[] will be
+               printed, even if some of the data is junk, and skipping bytes
+               17 to 32. It is up to you to know how many of the first bytes of
+               data are the actual response.
index 0a54ed0..274df44 100644 (file)
@@ -3,18 +3,28 @@ Date:         August 2017
 Contact:       Daniel Colascione <dancol@google.com>
 Description:
                This file provides pre-summed memory information for a
-               process.  The format is identical to /proc/pid/smaps,
+               process.  The format is almost identical to /proc/pid/smaps,
                except instead of an entry for each VMA in a process,
                smaps_rollup has a single entry (tagged "[rollup]")
                for which each field is the sum of the corresponding
                fields from all the maps in /proc/pid/smaps.
-               For more details, see the procfs man page.
+               Additionally, the fields Pss_Anon, Pss_File and Pss_Shmem
+               are not present in /proc/pid/smaps.  These fields represent
+               the sum of the Pss field of each type (anon, file, shmem).
+               For more details, see Documentation/filesystems/proc.txt
+               and the procfs man page.
 
                Typical output looks like this:
 
                00100000-ff709000 ---p 00000000 00:00 0          [rollup]
+               Size:               1192 kB
+               KernelPageSize:        4 kB
+               MMUPageSize:           4 kB
                Rss:                 884 kB
                Pss:                 385 kB
+               Pss_Anon:            301 kB
+               Pss_File:             80 kB
+               Pss_Shmem:             4 kB
                Shared_Clean:        696 kB
                Shared_Dirty:          0 kB
                Private_Clean:       120 kB
index 5fca9f5..d45209a 100644 (file)
@@ -1,6 +1,6 @@
-Where:         /sys/fs/pstore/... (or /dev/pstore/...)
+What:          /sys/fs/pstore/... (or /dev/pstore/...)
 Date:          March 2011
-Kernel Version: 2.6.39
+KernelVersion: 2.6.39
 Contact:       tony.luck@intel.com
 Description:   Generic interface to platform dependent persistent storage.
 
index 77f47ff..5bb793e 100644 (file)
@@ -1,6 +1,6 @@
-Where:         /sys/bus/event_source/devices/<dev>/format
+What:          /sys/bus/event_source/devices/<dev>/format
 Date:          January 2012
-Kernel Version: 3.3
+KernelVersion: 3.3
 Contact:       Jiri Olsa <jolsa@redhat.com>
 Description:
                Attribute group to describe the magic bits that go into
index feb2e4a..4a251b7 100644 (file)
@@ -1,20 +1,20 @@
-Where:         /sys/bus/i2c/devices/.../heading0_input
+What:          /sys/bus/i2c/devices/.../heading0_input
 Date:          April 2010
-Kernel Version: 2.6.36?
+KernelVersion: 2.6.36?
 Contact:       alan.cox@intel.com
 Description:   Reports the current heading from the compass as a floating
                point value in degrees.
 
-Where:         /sys/bus/i2c/devices/.../power_state
+What:          /sys/bus/i2c/devices/.../power_state
 Date:          April 2010
-Kernel Version: 2.6.36?
+KernelVersion: 2.6.36?
 Contact:       alan.cox@intel.com
 Description:   Sets the power state of the device. 0 sets the device into
                sleep mode, 1 wakes it up.
 
-Where:         /sys/bus/i2c/devices/.../calibration
+What:          /sys/bus/i2c/devices/.../calibration
 Date:          April 2010
-Kernel Version: 2.6.36?
+KernelVersion: 2.6.36?
 Contact:       alan.cox@intel.com
 Description:   Sets the calibration on or off (1 = on, 0 = off). See the
                chip data sheet.
index 6aef7db..6804516 100644 (file)
@@ -61,8 +61,11 @@ What:                /sys/bus/iio/devices/triggerX/sampling_frequency_available
 KernelVersion: 2.6.35
 Contact:       linux-iio@vger.kernel.org
 Description:
-               When the internal sampling clock can only take a small
-               discrete set of values, this file lists those available.
+               When the internal sampling clock can only take a specific set of
+               frequencies, we can specify the available values with:
+               - a small discrete set of values like "0 2 4 6 8"
+               - a range with minimum, step and maximum frequencies like
+                 "[min step max]"
 
 What:          /sys/bus/iio/devices/iio:deviceX/oversampling_ratio
 KernelVersion: 2.6.38
index 0e95c2c..6158f83 100644 (file)
@@ -18,11 +18,11 @@ Description:
                values are 'base' and 'lid'.
 
 What:          /sys/bus/iio/devices/iio:deviceX/id
-Date:          Septembre 2017
+Date:          September 2017
 KernelVersion: 4.14
 Contact:       linux-iio@vger.kernel.org
 Description:
-               This attribute is exposed by the CrOS EC legacy accelerometer
-               driver and represents the sensor ID as exposed by the EC. This
-               ID is used by the Android sensor service hardware abstraction
-               layer (sensor HAL) through the Android container on ChromeOS.
+               This attribute is exposed by the CrOS EC sensors driver and
+               represents the sensor ID as exposed by the EC. This ID is used
+               by the Android sensor service hardware abstraction layer (sensor
+               HAL) through the Android container on ChromeOS.
index 0a1ca14..a133fd8 100644 (file)
@@ -1,4 +1,4 @@
-What           /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity
+What:          /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity
 Date:          January 2017
 KernelVersion: 4.11
 Contact:       linux-iio@vger.kernel.org
@@ -6,7 +6,7 @@ Description:
                Show or set the gain boost of the amp, from 0-31 range.
                default 31
 
-What           /sys/bus/iio/devices/iio:deviceX/sensor_max_range
+What:          /sys/bus/iio/devices/iio:deviceX/sensor_max_range
 Date:          January 2017
 KernelVersion: 4.11
 Contact:       linux-iio@vger.kernel.org
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4371 b/Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4371
new file mode 100644 (file)
index 0000000..302de64
--- /dev/null
@@ -0,0 +1,44 @@
+What:          /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_frequency
+KernelVersion:
+Contact:       linux-iio@vger.kernel.org
+Description:
+               Stores the PLL frequency in Hz for channel Y.
+               Reading returns the actual frequency in Hz.
+               The ADF4371 has an integrated VCO with fundamendal output
+               frequency ranging from 4000000000 Hz 8000000000 Hz.
+
+               out_altvoltage0_frequency:
+                       A divide by 1, 2, 4, 8, 16, 32 or circuit generates
+                       frequencies from 62500000 Hz to 8000000000 Hz.
+               out_altvoltage1_frequency:
+                       This channel duplicates the channel 0 frequency
+               out_altvoltage2_frequency:
+                       A frequency doubler generates frequencies from
+                       8000000000 Hz to 16000000000 Hz.
+               out_altvoltage3_frequency:
+                       A frequency quadrupler generates frequencies from
+                       16000000000 Hz to 32000000000 Hz.
+
+               Note: writes to one of the channels will affect the frequency of
+               all the other channels, since it involves changing the VCO
+               fundamental output frequency.
+
+What:          /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_name
+KernelVersion:
+Contact:       linux-iio@vger.kernel.org
+Description:
+               Reading returns the datasheet name for channel Y:
+
+               out_altvoltage0_name: RF8x
+               out_altvoltage1_name: RFAUX8x
+               out_altvoltage2_name: RF16x
+               out_altvoltage3_name: RF32x
+
+What:          /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_powerdown
+KernelVersion:
+Contact:       linux-iio@vger.kernel.org
+Description:
+               This attribute allows the user to power down the PLL and it's
+               RFOut buffers.
+               Writing 1 causes the specified channel to power down.
+               Clearing returns to normal operation.
index 9a17ab5..c59d953 100644 (file)
@@ -1,4 +1,4 @@
-What           /sys/bus/iio/devices/iio:deviceX/in_proximity_input
+What:          /sys/bus/iio/devices/iio:deviceX/in_proximity_input
 Date:          March 2014
 KernelVersion: 3.15
 Contact:       Matt Ranostay <matt.ranostay@konsulko.com>
@@ -6,7 +6,7 @@ Description:
                Get the current distance in meters of storm (1km steps)
                1000-40000 = distance in meters
 
-What           /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity
+What:          /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity
 Date:          March 2014
 KernelVersion: 3.15
 Contact:       Matt Ranostay <matt.ranostay@konsulko.com>
index 4b0318c..3c9a8c4 100644 (file)
@@ -9,9 +9,9 @@ errors may be "seen" / reported by the link partner and not the
 problematic endpoint itself (which may report all counters as 0 as it never
 saw any problems).
 
-Where:         /sys/bus/pci/devices/<dev>/aer_dev_correctable
+What:          /sys/bus/pci/devices/<dev>/aer_dev_correctable
 Date:          July 2018
-Kernel Version: 4.19.0
+KernelVersion: 4.19.0
 Contact:       linux-pci@vger.kernel.org, rajatja@google.com
 Description:   List of correctable errors seen and reported by this
                PCI device using ERR_COR. Note that since multiple errors may
@@ -31,9 +31,9 @@ Header Log Overflow 0
 TOTAL_ERR_COR 2
 -------------------------------------------------------------------------
 
-Where:         /sys/bus/pci/devices/<dev>/aer_dev_fatal
+What:          /sys/bus/pci/devices/<dev>/aer_dev_fatal
 Date:          July 2018
-Kernel Version: 4.19.0
+KernelVersion: 4.19.0
 Contact:       linux-pci@vger.kernel.org, rajatja@google.com
 Description:   List of uncorrectable fatal errors seen and reported by this
                PCI device using ERR_FATAL. Note that since multiple errors may
@@ -62,9 +62,9 @@ TLP Prefix Blocked Error 0
 TOTAL_ERR_FATAL 0
 -------------------------------------------------------------------------
 
-Where:         /sys/bus/pci/devices/<dev>/aer_dev_nonfatal
+What:          /sys/bus/pci/devices/<dev>/aer_dev_nonfatal
 Date:          July 2018
-Kernel Version: 4.19.0
+KernelVersion: 4.19.0
 Contact:       linux-pci@vger.kernel.org, rajatja@google.com
 Description:   List of uncorrectable nonfatal errors seen and reported by this
                PCI device using ERR_NONFATAL. Note that since multiple errors
@@ -103,20 +103,20 @@ collectors) that are AER capable. These indicate the number of error messages as
 device, so these counters include them and are thus cumulative of all the error
 messages on the PCI hierarchy originating at that root port.
 
-Where:         /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_cor
+What:          /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_cor
 Date:          July 2018
-Kernel Version: 4.19.0
+KernelVersion: 4.19.0
 Contact:       linux-pci@vger.kernel.org, rajatja@google.com
 Description:   Total number of ERR_COR messages reported to rootport.
 
-Where:     /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_fatal
+What:      /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_fatal
 Date:          July 2018
-Kernel Version: 4.19.0
+KernelVersion: 4.19.0
 Contact:       linux-pci@vger.kernel.org, rajatja@google.com
 Description:   Total number of ERR_FATAL messages reported to rootport.
 
-Where:     /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_nonfatal
+What:      /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_nonfatal
 Date:          July 2018
-Kernel Version: 4.19.0
+KernelVersion: 4.19.0
 Contact:       linux-pci@vger.kernel.org, rajatja@google.com
 Description:   Total number of ERR_NONFATAL messages reported to rootport.
index 53d99ed..92a94e1 100644 (file)
@@ -1,68 +1,68 @@
-Where:         /sys/bus/pci/devices/<dev>/ccissX/cXdY/model
+What:          /sys/bus/pci/devices/<dev>/ccissX/cXdY/model
 Date:          March 2009
-Kernel Version: 2.6.30
+KernelVersion: 2.6.30
 Contact:       iss_storagedev@hp.com
 Description:   Displays the SCSI INQUIRY page 0 model for logical drive
                Y of controller X.
 
-Where:         /sys/bus/pci/devices/<dev>/ccissX/cXdY/rev
+What:          /sys/bus/pci/devices/<dev>/ccissX/cXdY/rev
 Date:          March 2009
-Kernel Version: 2.6.30
+KernelVersion: 2.6.30
 Contact:       iss_storagedev@hp.com
 Description:   Displays the SCSI INQUIRY page 0 revision for logical
                drive Y of controller X.
 
-Where:         /sys/bus/pci/devices/<dev>/ccissX/cXdY/unique_id
+What:          /sys/bus/pci/devices/<dev>/ccissX/cXdY/unique_id
 Date:          March 2009
-Kernel Version: 2.6.30
+KernelVersion: 2.6.30
 Contact:       iss_storagedev@hp.com
 Description:   Displays the SCSI INQUIRY page 83 serial number for logical
                drive Y of controller X.
 
-Where:         /sys/bus/pci/devices/<dev>/ccissX/cXdY/vendor
+What:          /sys/bus/pci/devices/<dev>/ccissX/cXdY/vendor
 Date:          March 2009
-Kernel Version: 2.6.30
+KernelVersion: 2.6.30
 Contact:       iss_storagedev@hp.com
 Description:   Displays the SCSI INQUIRY page 0 vendor for logical drive
                Y of controller X.
 
-Where:         /sys/bus/pci/devices/<dev>/ccissX/cXdY/block:cciss!cXdY
+What:          /sys/bus/pci/devices/<dev>/ccissX/cXdY/block:cciss!cXdY
 Date:          March 2009
-Kernel Version: 2.6.30
+KernelVersion: 2.6.30
 Contact:       iss_storagedev@hp.com
 Description:   A symbolic link to /sys/block/cciss!cXdY
 
-Where:         /sys/bus/pci/devices/<dev>/ccissX/rescan
+What:          /sys/bus/pci/devices/<dev>/ccissX/rescan
 Date:          August 2009
-Kernel Version:        2.6.31
+KernelVersion: 2.6.31
 Contact:       iss_storagedev@hp.com
 Description:   Kicks of a rescan of the controller to discover logical
                drive topology changes.
 
-Where:         /sys/bus/pci/devices/<dev>/ccissX/cXdY/lunid
+What:          /sys/bus/pci/devices/<dev>/ccissX/cXdY/lunid
 Date:          August 2009
-Kernel Version: 2.6.31
+KernelVersion: 2.6.31
 Contact:       iss_storagedev@hp.com
 Description:   Displays the 8-byte LUN ID used to address logical
                drive Y of controller X.
 
-Where:         /sys/bus/pci/devices/<dev>/ccissX/cXdY/raid_level
+What:          /sys/bus/pci/devices/<dev>/ccissX/cXdY/raid_level
 Date:          August 2009
-Kernel Version: 2.6.31
+KernelVersion: 2.6.31
 Contact:       iss_storagedev@hp.com
 Description:   Displays the RAID level of logical drive Y of
                controller X.
 
-Where:         /sys/bus/pci/devices/<dev>/ccissX/cXdY/usage_count
+What:          /sys/bus/pci/devices/<dev>/ccissX/cXdY/usage_count
 Date:          August 2009
-Kernel Version: 2.6.31
+KernelVersion: 2.6.31
 Contact:       iss_storagedev@hp.com
 Description:   Displays the usage count (number of opens) of logical drive Y
                of controller X.
 
-Where:         /sys/bus/pci/devices/<dev>/ccissX/resettable
+What:          /sys/bus/pci/devices/<dev>/ccissX/resettable
 Date:          February 2011
-Kernel Version:        2.6.38
+KernelVersion: 2.6.38
 Contact:       iss_storagedev@hp.com
 Description:   Value of 1 indicates the controller can honor the reset_devices
                kernel parameter.  Value of 0 indicates reset_devices cannot be
@@ -71,9 +71,9 @@ Description:  Value of 1 indicates the controller can honor the reset_devices
                a dump device, as kdump requires resetting the device in order
                to work reliably.
 
-Where:         /sys/bus/pci/devices/<dev>/ccissX/transport_mode
+What:          /sys/bus/pci/devices/<dev>/ccissX/transport_mode
 Date:          July 2011
-Kernel Version:        3.0
+KernelVersion: 3.0
 Contact:       iss_storagedev@hp.com
 Description:   Value of "simple" indicates that the controller has been placed
                in "simple mode". Value of "performant" indicates that the
index 70d00df..9ade80f 100644 (file)
@@ -1,14 +1,14 @@
-Where:         /sys/bus/usb/.../powered
+What:          /sys/bus/usb/.../powered
 Date:          August 2008
-Kernel Version:        2.6.26
+KernelVersion: 2.6.26
 Contact:       Harrison Metzger <harrisonmetz@gmail.com>
 Description:   Controls whether the device's display will powered.
                A value of 0 is off and a non-zero value is on.
 
-Where:         /sys/bus/usb/.../mode_msb
-Where:         /sys/bus/usb/.../mode_lsb
+What:          /sys/bus/usb/.../mode_msb
+What:          /sys/bus/usb/.../mode_lsb
 Date:          August 2008
-Kernel Version:        2.6.26
+KernelVersion: 2.6.26
 Contact:       Harrison Metzger <harrisonmetz@gmail.com>
 Description:   Controls the devices display mode.
                For a 6 character display the values are
@@ -16,24 +16,24 @@ Description:        Controls the devices display mode.
                for an 8 character display the values are
                        MSB 0x08; LSB 0xFF.
 
-Where:         /sys/bus/usb/.../textmode
+What:          /sys/bus/usb/.../textmode
 Date:          August 2008
-Kernel Version:        2.6.26
+KernelVersion: 2.6.26
 Contact:       Harrison Metzger <harrisonmetz@gmail.com>
 Description:   Controls the way the device interprets its text buffer.
                raw:    each character controls its segment manually
                hex:    each character is between 0-15
                ascii:  each character is between '0'-'9' and 'A'-'F'.
 
-Where:         /sys/bus/usb/.../text
+What:          /sys/bus/usb/.../text
 Date:          August 2008
-Kernel Version:        2.6.26
+KernelVersion: 2.6.26
 Contact:       Harrison Metzger <harrisonmetz@gmail.com>
 Description:   The text (or data) for the device to display
 
-Where:         /sys/bus/usb/.../decimals
+What:          /sys/bus/usb/.../decimals
 Date:          August 2008
-Kernel Version:        2.6.26
+KernelVersion: 2.6.26
 Contact:       Harrison Metzger <harrisonmetz@gmail.com>
 Description:   Controls the decimal places on the device.
                To set the nth decimal place, give this field
index 77cf7ac..c0e0a9a 100644 (file)
@@ -4,7 +4,7 @@ KernelVersion:  3.5
 Contact:       Johan Hovold <jhovold@gmail.com>
 Description:
                Get the ALS output channel used as input in
-               ALS-current-control mode (0, 1), where
+               ALS-current-control mode (0, 1), where:
 
                0 - out_current0 (backlight 0)
                1 - out_current1 (backlight 1)
@@ -28,7 +28,7 @@ Date:         April 2012
 KernelVersion: 3.5
 Contact:       Johan Hovold <jhovold@gmail.com>
 Description:
-               Set the brightness-mapping mode (0, 1), where
+               Set the brightness-mapping mode (0, 1), where:
 
                0 - exponential mode
                1 - linear mode
@@ -38,7 +38,7 @@ Date:         April 2012
 KernelVersion: 3.5
 Contact:       Johan Hovold <jhovold@gmail.com>
 Description:
-               Set the PWM-input control mask (5 bits), where
+               Set the PWM-input control mask (5 bits), where:
 
                bit 5 - PWM-input enabled in Zone 4
                bit 4 - PWM-input enabled in Zone 3
index bbbabff..7970e37 100644 (file)
@@ -1,6 +1,6 @@
-Note: Attributes that are shared between devices are stored in the directory
-pointed to by the symlink device/.
-Example: The real path of the attribute /sys/class/cxl/afu0.0s/irqs_max is
+Please note that attributes that are shared between devices are stored in
+the directory pointed to by the symlink device/.
+For example, the real path of the attribute /sys/class/cxl/afu0.0s/irqs_max is
 /sys/class/cxl/afu0.0s/device/irqs_max, i.e. /sys/class/cxl/afu0.0/irqs_max.
 
 
index ee39aca..01196e1 100644 (file)
@@ -47,7 +47,7 @@ Description:
 What:          /sys/class/devfreq/.../trans_stat
 Date:          October 2012
 Contact:       MyungJoo Ham <myungjoo.ham@samsung.com>
-Descrtiption:
+Description:
                This ABI shows the statistics of devfreq behavior on a
                specific device. It shows the time spent in each state and
                the number of transitions between states.
index 620ebb3..e4c89b2 100644 (file)
@@ -4,7 +4,7 @@ KernelVersion:  3.5
 Contact:       Johan Hovold <jhovold@gmail.com>
 Description:
                Set the ALS output channel to use as input in
-               ALS-current-control mode (1, 2), where
+               ALS-current-control mode (1, 2), where:
 
                1 - out_current1
                2 - out_current2
@@ -22,7 +22,7 @@ Date:         April 2012
 KernelVersion: 3.5
 Contact:       Johan Hovold <jhovold@gmail.com>
 Description:
-               Set the pattern generator fall and rise times (0..7), where
+               Set the pattern generator fall and rise times (0..7), where:
 
                0 - 2048 us
                1 - 262 ms
@@ -45,7 +45,7 @@ Date:         April 2012
 KernelVersion: 3.5
 Contact:       Johan Hovold <jhovold@gmail.com>
 Description:
-               Set the brightness-mapping mode (0, 1), where
+               Set the brightness-mapping mode (0, 1), where:
 
                0 - exponential mode
                1 - linear mode
@@ -55,7 +55,7 @@ Date:         April 2012
 KernelVersion: 3.5
 Contact:       Johan Hovold <jhovold@gmail.com>
 Description:
-               Set the PWM-input control mask (5 bits), where
+               Set the PWM-input control mask (5 bits), where:
 
                bit 5 - PWM-input enabled in Zone 4
                bit 4 - PWM-input enabled in Zone 3
index e4fae60..6adab27 100644 (file)
@@ -5,7 +5,7 @@ Contact:        Janne Kanniainen <janne.kanniainen@gmail.com>
 Description:
                Set the mode of LEDs. You should notice that changing the mode
                of one LED will update the mode of its two sibling devices as
-               well.
+               well. Possible values are:
 
                0 - normal
                1 - audio
@@ -13,4 +13,4 @@ Description:
 
                Normal: LEDs are fully on when enabled
                Audio:  LEDs brightness depends on sound level
-               Breathing: LEDs brightness varies at human breathing rate
\ No newline at end of file
+               Breathing: LEDs brightness varies at human breathing rate
index db3b3ff..f333a0c 100644 (file)
@@ -147,6 +147,6 @@ What:               /sys/class/powercap/.../<power zone>/enabled
 Date:          September 2013
 KernelVersion: 3.13
 Contact:       linux-pm@vger.kernel.org
-Description
+Description:
                This allows to enable/disable power capping at power zone level.
                This applies to current power zone and its children.
index 85f4875..a057875 100644 (file)
@@ -125,12 +125,6 @@ Description:
                 The EUI-48 of this device in colon separated hex
                 octets.
 
-What:           /sys/class/uwb_rc/uwbN/<EUI-48>/BPST
-Date:           July 2008
-KernelVersion:  2.6.27
-Contact:        linux-usb@vger.kernel.org
-Description:
-
 What:           /sys/class/uwb_rc/uwbN/<EUI-48>/IEs
 Date:           July 2008
 KernelVersion:  2.6.27
index 8cde64a..fbd8078 100644 (file)
@@ -1,6 +1,6 @@
 What:          /sys/bus/pci/drivers/altera-cvp/chkcfg
 Date:          May 2017
-Kernel Version:        4.13
+KernelVersion: 4.13
 Contact:       Anatolij Gustschin <agust@denx.de>
 Description:
                Contains either 1 or 0 and controls if configuration
index 78b2bcf..f433fc6 100644 (file)
@@ -62,18 +62,20 @@ What:           /sys/class/habanalabs/hl<n>/ic_clk
 Date:           Jan 2019
 KernelVersion:  5.1
 Contact:        oded.gabbay@gmail.com
-Description:    Allows the user to set the maximum clock frequency of the
-                Interconnect fabric. Writes to this parameter affect the device
-                only when the power management profile is set to "manual" mode.
-                The device IC clock might be set to lower value then the
+Description:    Allows the user to set the maximum clock frequency, in Hz, of
+                the Interconnect fabric. Writes to this parameter affect the
+                device only when the power management profile is set to "manual"
+                mode. The device IC clock might be set to lower value than the
                 maximum. The user should read the ic_clk_curr to see the actual
-                frequency value of the IC
+                frequency value of the IC. This property is valid only for the
+                Goya ASIC family
 
 What:           /sys/class/habanalabs/hl<n>/ic_clk_curr
 Date:           Jan 2019
 KernelVersion:  5.1
 Contact:        oded.gabbay@gmail.com
-Description:    Displays the current clock frequency of the Interconnect fabric
+Description:    Displays the current clock frequency, in Hz, of the Interconnect
+                fabric. This property is valid only for the Goya ASIC family
 
 What:           /sys/class/habanalabs/hl<n>/infineon_ver
 Date:           Jan 2019
@@ -92,18 +94,20 @@ What:           /sys/class/habanalabs/hl<n>/mme_clk
 Date:           Jan 2019
 KernelVersion:  5.1
 Contact:        oded.gabbay@gmail.com
-Description:    Allows the user to set the maximum clock frequency of the
-                MME compute engine. Writes to this parameter affect the device
-                only when the power management profile is set to "manual" mode.
-                The device MME clock might be set to lower value then the
+Description:    Allows the user to set the maximum clock frequency, in Hz, of
+                the MME compute engine. Writes to this parameter affect the
+                device only when the power management profile is set to "manual"
+                mode. The device MME clock might be set to lower value than the
                 maximum. The user should read the mme_clk_curr to see the actual
-                frequency value of the MME
+                frequency value of the MME. This property is valid only for the
+                Goya ASIC family
 
 What:           /sys/class/habanalabs/hl<n>/mme_clk_curr
 Date:           Jan 2019
 KernelVersion:  5.1
 Contact:        oded.gabbay@gmail.com
-Description:    Displays the current clock frequency of the MME compute engine
+Description:    Displays the current clock frequency, in Hz, of the MME compute
+                engine. This property is valid only for the Goya ASIC family
 
 What:           /sys/class/habanalabs/hl<n>/pci_addr
 Date:           Jan 2019
@@ -163,18 +167,20 @@ What:           /sys/class/habanalabs/hl<n>/tpc_clk
 Date:           Jan 2019
 KernelVersion:  5.1
 Contact:        oded.gabbay@gmail.com
-Description:    Allows the user to set the maximum clock frequency of the
-                TPC compute engines. Writes to this parameter affect the device
-                only when the power management profile is set to "manual" mode.
-                The device TPC clock might be set to lower value then the
+Description:    Allows the user to set the maximum clock frequency, in Hz, of
+                the TPC compute engines. Writes to this parameter affect the
+                device only when the power management profile is set to "manual"
+                mode. The device TPC clock might be set to lower value than the
                 maximum. The user should read the tpc_clk_curr to see the actual
-                frequency value of the TPC
+                frequency value of the TPC. This property is valid only for
+                Goya ASIC family
 
 What:           /sys/class/habanalabs/hl<n>/tpc_clk_curr
 Date:           Jan 2019
 KernelVersion:  5.1
 Contact:        oded.gabbay@gmail.com
-Description:    Displays the current clock frequency of the TPC compute engines
+Description:    Displays the current clock frequency, in Hz, of the TPC compute
+                engines. This property is valid only for the Goya ASIC family
 
 What:           /sys/class/habanalabs/hl<n>/uboot_ver
 Date:           Jan 2019
index 48942ca..a595334 100644 (file)
@@ -1,6 +1,6 @@
-What:          For USB devices : /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/report_descriptor
-               For BT devices  : /sys/class/bluetooth/hci<addr>/<hid-bus>:<vendor-id>:<product-id>.<num>/report_descriptor
-               Symlink         : /sys/class/hidraw/hidraw<num>/device/report_descriptor
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/report_descriptor
+What:          /sys/class/bluetooth/hci<addr>/<hid-bus>:<vendor-id>:<product-id>.<num>/report_descriptor
+What:          /sys/class/hidraw/hidraw<num>/device/report_descriptor
 Date:          Jan 2011
 KernelVersion: 2.0.39
 Contact:       Alan Ott <alan@signal11.us>
@@ -9,9 +9,9 @@ Description:    When read, this file returns the device's raw binary HID
                This file cannot be written.
 Users:         HIDAPI library (http://www.signal11.us/oss/hidapi)
 
-What:          For USB devices : /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/country
-               For BT devices  : /sys/class/bluetooth/hci<addr>/<hid-bus>:<vendor-id>:<product-id>.<num>/country
-               Symlink         : /sys/class/hidraw/hidraw<num>/device/country
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/country
+What:          /sys/class/bluetooth/hci<addr>/<hid-bus>:<vendor-id>:<product-id>.<num>/country
+What:          /sys/class/hidraw/hidraw<num>/device/country
 Date:          February 2015
 KernelVersion: 3.19
 Contact:       Olivier Gay <ogay@logitech.com>
index 3ca3971..8f7982c 100644 (file)
@@ -5,7 +5,7 @@ Description:    It is possible to switch the dpi setting of the mouse with the
                press of a button.
                When read, this file returns the raw number of the actual dpi
                setting reported by the mouse. This number has to be further
-               processed to receive the real dpi value.
+               processed to receive the real dpi value:
 
                VALUE DPI
                1     800
index 9921ef2..1a56fc5 100644 (file)
@@ -1,6 +1,6 @@
 What:          /sys/class/tpm/tpmX/ppi/
 Date:          August 2012
-Kernel Version:        3.6
+KernelVersion: 3.6
 Contact:       xiaoyan.zhang@intel.com
 Description:
                This folder includes the attributes related with PPI (Physical
index ba5d770..88cab66 100644 (file)
@@ -1,6 +1,6 @@
 What:          /sys/bus/scsi/drivers/st/debug_flag
 Date:          October 2015
-Kernel Version:        ?.?
+KernelVersion: ?.?
 Contact:       shane.seymour@hpe.com
 Description:
                This file allows you to turn debug output from the st driver
index 2aa5503..afc48fc 100644 (file)
@@ -1,6 +1,6 @@
 What:          /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/speed
 Date:          April 2010
-Kernel Version:        2.6.35
+KernelVersion: 2.6.35
 Contact:       linux-bluetooth@vger.kernel.org
 Description:
                The /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/speed file
index 91822ce..dca326e 100644 (file)
@@ -243,3 +243,11 @@ Description:
                 - Del: echo '[h/c]!extension' > /sys/fs/f2fs/<disk>/extension_list
                 - [h] means add/del hot file extension
                 - [c] means add/del cold file extension
+
+What:          /sys/fs/f2fs/<disk>/unusable
+Date           April 2019
+Contact:       "Daniel Rosenberg" <drosen@google.com>
+Description:
+               If checkpoint=disable, it displays the number of blocks that are unusable.
+                If checkpoint=enable it displays the enumber of blocks that would be unusable
+                if checkpoint=disable were to be set.
index 50a3033..bcff346 100644 (file)
@@ -2,7 +2,7 @@ What:           /sys/kernel/fscaps
 Date:          February 2011
 KernelVersion: 2.6.38
 Contact:       Ludwig Nussel <ludwig.nussel@suse.de>
-Description
+Description:
                Shows whether file system capabilities are honored
                when executing a binary
 
index 7bd8116..1f1087a 100644 (file)
@@ -4,7 +4,7 @@ KernelVersion:  2.6.24
 Contact:       Ken'ichi Ohmichi <oomichi@mxs.nes.nec.co.jp>
                Kexec Mailing List <kexec@lists.infradead.org>
                Vivek Goyal <vgoyal@redhat.com>
-Description
+Description:
                Shows physical address and size of vmcoreinfo ELF note.
                First value contains physical address of note in hex and
                second value contains the size of note in hex. This ELF
diff --git a/Documentation/ABI/testing/sysfs-platform-wilco-ec b/Documentation/ABI/testing/sysfs-platform-wilco-ec
new file mode 100644 (file)
index 0000000..8827a73
--- /dev/null
@@ -0,0 +1,40 @@
+What:          /sys/bus/platform/devices/GOOG000C\:00/boot_on_ac
+Date:          April 2019
+KernelVersion: 5.3
+Description:
+               Boot on AC is a policy which makes the device boot from S5
+               when AC power is connected. This is useful for users who
+               want to run their device headless or with a dock.
+
+               Input should be parseable by kstrtou8() to 0 or 1.
+
+What:          /sys/bus/platform/devices/GOOG000C\:00/build_date
+Date:          May 2019
+KernelVersion: 5.3
+Description:
+               Display Wilco Embedded Controller firmware build date.
+               Output will a MM/DD/YY string.
+
+What:          /sys/bus/platform/devices/GOOG000C\:00/build_revision
+Date:          May 2019
+KernelVersion: 5.3
+Description:
+               Display Wilco Embedded Controller build revision.
+               Output will a version string be similar to the example below:
+               d2592cae0
+
+What:          /sys/bus/platform/devices/GOOG000C\:00/model_number
+Date:          May 2019
+KernelVersion: 5.3
+Description:
+               Display Wilco Embedded Controller model number.
+               Output will a version string be similar to the example below:
+               08B6
+
+What:          /sys/bus/platform/devices/GOOG000C\:00/version
+Date:          May 2019
+KernelVersion: 5.3
+Description:
+               Display Wilco Embedded Controller firmware version.
+               The format of the string is x.y.z. Where x is major, y is minor
+               and z is the build number. For example: 95.00.06
index 3207076..716ad9b 100644 (file)
@@ -19,3 +19,13 @@ block device backing the filesystem is not read-only, a sysctl is
 created to toggle pinning: ``/proc/sys/kernel/loadpin/enabled``. (Having
 a mutable filesystem means pinning is mutable too, but having the
 sysctl allows for easy testing on systems with a mutable filesystem.)
+
+It's also possible to exclude specific file types from LoadPin using kernel
+command line option "``loadpin.exclude``". By default, all files are
+included, but they can be excluded using kernel command line option such
+as "``loadpin.exclude=kernel-module,kexec-image``". This allows to use
+different mechanisms such as ``CONFIG_MODULE_SIG`` and
+``CONFIG_KEXEC_VERIFY_SIG`` to verify kernel module and kernel image while
+still use LoadPin to protect the integrity of other files kernel loads. The
+full list of valid file types can be found in ``kernel_read_file_str``
+defined in ``include/linux/fs.h``.
index a5c8453..a9548de 100644 (file)
@@ -1146,6 +1146,11 @@ PAGE_SIZE multiple when read back.
        otherwise, a value change in this file generates a file
        modified event.
 
+       Note that all fields in this file are hierarchical and the
+       file modified event can be generated due to an event down the
+       hierarchy. For for the local events at the cgroup level see
+       memory.events.local.
+
          low
                The number of times the cgroup is reclaimed due to
                high memory pressure even though its usage is under
@@ -1185,6 +1190,11 @@ PAGE_SIZE multiple when read back.
                The number of processes belonging to this cgroup
                killed by any kind of OOM killer.
 
+  memory.events.local
+       Similar to memory.events but the fields in the file are local
+       to the cgroup i.e. not hierarchical. The file modified event
+       generated on this file reflects only the local events.
+
   memory.stat
        A read-only flat-keyed file which exists on non-root cgroups.
 
index 1649117..e56e006 100644 (file)
                 41 = /dev/ttySMX0              Motorola i.MX - port 0
                 42 = /dev/ttySMX1              Motorola i.MX - port 1
                 43 = /dev/ttySMX2              Motorola i.MX - port 2
-                44 = /dev/ttyMM0               Marvell MPSC - port 0
-                45 = /dev/ttyMM1               Marvell MPSC - port 1
+                44 = /dev/ttyMM0               Marvell MPSC - port 0 (obsolete unused)
+                45 = /dev/ttyMM1               Marvell MPSC - port 1 (obsolete unused)
                 46 = /dev/ttyCPM0              PPC CPM (SCC or SMC) - port 0
                    ...
                 47 = /dev/ttyCPM5              PPC CPM (SCC or SMC) - port 5
index f1c433d..099c5a4 100644 (file)
                        tracking down these problems.
 
        debug_pagealloc=
-                       [KNL] When CONFIG_DEBUG_PAGEALLOC is set, this
-                       parameter enables the feature at boot time. In
-                       default, it is disabled. We can avoid allocating huge
-                       chunk of memory for debug pagealloc if we don't enable
-                       it at boot time and the system will work mostly same
-                       with the kernel built without CONFIG_DEBUG_PAGEALLOC.
+                       [KNL] When CONFIG_DEBUG_PAGEALLOC is set, this parameter
+                       enables the feature at boot time. By default, it is
+                       disabled and the system will work mostly the same as a
+                       kernel built without CONFIG_DEBUG_PAGEALLOC.
                        on: enable the feature
 
        debugpat        [X86] Enable PAT debugging
 
        initrd=         [BOOT] Specify the location of the initial ramdisk
 
+       init_on_alloc=  [MM] Fill newly allocated pages and heap objects with
+                       zeroes.
+                       Format: 0 | 1
+                       Default set by CONFIG_INIT_ON_ALLOC_DEFAULT_ON.
+
+       init_on_free=   [MM] Fill freed pages and heap objects with zeroes.
+                       Format: 0 | 1
+                       Default set by CONFIG_INIT_ON_FREE_DEFAULT_ON.
+
        init_pkru=      [x86] Specify the default memory protection keys rights
                        register contents for all processes.  0x55555554 by
                        default (disallow access to all but pkey 0).  Can
index 3d041d0..d3f3a60 100644 (file)
@@ -284,7 +284,7 @@ following manner:
   processors") to bring CPUs into the kernel.
 
   The device tree should contain a 'psci' node, as described in
-  Documentation/devicetree/bindings/arm/psci.txt.
+  Documentation/devicetree/bindings/arm/psci.yaml.
 
 - Secondary CPU general-purpose register settings
   x0 = 0 (reserved for future use)
index c792774..3e57d09 100644 (file)
@@ -86,6 +86,8 @@ stable kernels.
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Neoverse-N1     | #1188873,1418040| ARM64_ERRATUM_1418040       |
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Neoverse-N1     | #1349291        | N/A                         |
++----------------+-----------------+-----------------+-----------------------------+
 | ARM            | MMU-500         | #841119,826419  | N/A                         |
 +----------------+-----------------+-----------------+-----------------------------+
 +----------------+-----------------+-----------------+-----------------------------+
index 824f24c..08af5ca 100644 (file)
@@ -54,7 +54,7 @@ The Linux kernel provides more basic utility functions.
 Bit Operations
 --------------
 
-.. kernel-doc:: arch/x86/include/asm/bitops.h
+.. kernel-doc:: include/asm-generic/bitops-instrumented.h
    :internal:
 
 Bitmap Operations
index e6f5126..3621cd5 100644 (file)
@@ -2,8 +2,8 @@ Kernel Memory Leak Detector
 ===========================
 
 Kmemleak provides a way of detecting possible kernel memory leaks in a
-way similar to a tracing garbage collector
-(https://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29#Tracing_garbage_collectors),
+way similar to a `tracing garbage collector
+<https://en.wikipedia.org/wiki/Tracing_garbage_collection>`_,
 with the difference that the orphan objects are not freed but only
 reported via /sys/kernel/debug/kmemleak. A similar method is used by the
 Valgrind tool (``memcheck --leak-check``) to detect the memory leaks in
@@ -15,10 +15,13 @@ Usage
 
 CONFIG_DEBUG_KMEMLEAK in "Kernel hacking" has to be enabled. A kernel
 thread scans the memory every 10 minutes (by default) and prints the
-number of new unreferenced objects found. To display the details of all
-the possible memory leaks::
+number of new unreferenced objects found. If the ``debugfs`` isn't already
+mounted, mount with::
 
   # mount -t debugfs nodev /sys/kernel/debug/
+
+To display the details of all the possible scanned memory leaks::
+
   # cat /sys/kernel/debug/kmemleak
 
 To trigger an intermediate memory scan::
@@ -72,6 +75,9 @@ If CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF are enabled, the kmemleak is
 disabled by default. Passing ``kmemleak=on`` on the kernel command
 line enables the function. 
 
+If you are getting errors like "Error while writing to stdout" or "write_loop:
+Invalid argument", make sure kmemleak is properly enabled.
+
 Basic Algorithm
 ---------------
 
@@ -218,3 +224,37 @@ the pointer is calculated by other methods than the usual container_of
 macro or the pointer is stored in a location not scanned by kmemleak.
 
 Page allocations and ioremap are not tracked.
+
+Testing with kmemleak-test
+--------------------------
+
+To check if you have all set up to use kmemleak, you can use the kmemleak-test
+module, a module that deliberately leaks memory. Set CONFIG_DEBUG_KMEMLEAK_TEST
+as module (it can't be used as bult-in) and boot the kernel with kmemleak
+enabled. Load the module and perform a scan with::
+
+        # modprobe kmemleak-test
+        # echo scan > /sys/kernel/debug/kmemleak
+
+Note that the you may not get results instantly or on the first scanning. When
+kmemleak gets results, it'll log ``kmemleak: <count of leaks> new suspected
+memory leaks``. Then read the file to see then::
+
+        # cat /sys/kernel/debug/kmemleak
+        unreferenced object 0xffff89862ca702e8 (size 32):
+          comm "modprobe", pid 2088, jiffies 4294680594 (age 375.486s)
+          hex dump (first 32 bytes):
+            6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
+            6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5  kkkkkkkkkkkkkkk.
+          backtrace:
+            [<00000000e0a73ec7>] 0xffffffffc01d2036
+            [<000000000c5d2a46>] do_one_initcall+0x41/0x1df
+            [<0000000046db7e0a>] do_init_module+0x55/0x200
+            [<00000000542b9814>] load_module+0x203c/0x2480
+            [<00000000c2850256>] __do_sys_finit_module+0xba/0xe0
+            [<000000006564e7ef>] do_syscall_64+0x43/0x110
+            [<000000007c873fa6>] entry_SYSCALL_64_after_hwframe+0x44/0xa9
+        ...
+
+Removing the module with ``rmmod kmemleak_test`` should also trigger some
+kmemleak results.
index 4c53304..ccdd8b5 100644 (file)
@@ -32,6 +32,7 @@ its visible content unchanged, at least until the <COW device> fills up.
 
 
 -  snapshot <origin> <COW device> <persistent?> <chunksize>
+   [<# feature args> [<arg>]*]
 
 A snapshot of the <origin> block device is created. Changed chunks of
 <chunksize> sectors will be stored on the <COW device>.  Writes will
@@ -54,8 +55,23 @@ When loading or unloading the snapshot target, the corresponding
 snapshot-origin or snapshot-merge target must be suspended. A failure to
 suspend the origin target could result in data corruption.
 
+Optional features:
 
-* snapshot-merge <origin> <COW device> <persistent> <chunksize>
+   discard_zeroes_cow - a discard issued to the snapshot device that
+   maps to entire chunks to will zero the corresponding exception(s) in
+   the snapshot's exception store.
+
+   discard_passdown_origin - a discard to the snapshot device is passed
+   down to the snapshot-origin's underlying device.  This doesn't cause
+   copy-out to the snapshot exception store because the snapshot-origin
+   target is bypassed.
+
+   The discard_passdown_origin feature depends on the discard_zeroes_cow
+   feature being enabled.
+
+
+-  snapshot-merge <origin> <COW device> <persistent> <chunksize>
+   [<# feature args> [<arg>]*]
 
 takes the same table arguments as the snapshot target except it only
 works with persistent snapshots.  This target assumes the role of the
index 8a2774b..6b0dfd5 100644 (file)
@@ -25,7 +25,7 @@ DT_DOCS = $(shell \
 DT_SCHEMA_FILES ?= $(addprefix $(src)/,$(DT_DOCS))
 
 extra-y += $(patsubst $(src)/%.yaml,%.example.dts, $(DT_SCHEMA_FILES))
-extra-y += $(patsubst $(src)/%.yaml,%.example.dtb, $(DT_SCHEMA_FILES))
+extra-y += $(patsubst $(src)/%.yaml,%.example.dt.yaml, $(DT_SCHEMA_FILES))
 
 $(obj)/$(DT_TMP_SCHEMA): $(DT_SCHEMA_FILES) FORCE
        $(call if_changed,mk_schema)
diff --git a/Documentation/devicetree/bindings/arm/al,alpine.txt b/Documentation/devicetree/bindings/arm/al,alpine.txt
deleted file mode 100644 (file)
index d00debe..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-Annapurna Labs Alpine Platform Device Tree Bindings
----------------------------------------------------------------
-
-Boards in the Alpine family shall have the following properties:
-
-* Required root node properties:
-compatible: must contain "al,alpine"
-
-* Example:
-
-/ {
-       model = "Annapurna Labs Alpine Dev Board";
-       compatible = "al,alpine";
-
-       ...
-}
diff --git a/Documentation/devicetree/bindings/arm/al,alpine.yaml b/Documentation/devicetree/bindings/arm/al,alpine.yaml
new file mode 100644 (file)
index 0000000..a70dff2
--- /dev/null
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/al,alpine.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Annapurna Labs Alpine Platform Device Tree Bindings
+
+maintainers:
+  - Tsahee Zidenberg <tsahee@annapurnalabs.com>
+  - Antoine Tenart <antoine.tenart@bootlin.com>
+
+properties:
+  compatible:
+    items:
+      - const: al,alpine
+  model:
+    items:
+      - const: "Annapurna Labs Alpine Dev Board"
+
+...
index abff8d8..6758ece 100644 (file)
@@ -197,7 +197,7 @@ Required nodes:
 The description for the board must include:
    - a "psci" node describing the boot method used for the secondary CPUs.
      A detailed description of the bindings used for "psci" nodes is present
-     in the psci.txt file.
+     in the psci.yaml file.
    - a "cpus" node describing the available cores and their associated
      "enable-method"s. For more details see cpus.txt file.
 
diff --git a/Documentation/devicetree/bindings/arm/axxia.txt b/Documentation/devicetree/bindings/arm/axxia.txt
deleted file mode 100644 (file)
index 7b4ef9c..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-Axxia AXM55xx device tree bindings
-
-Boards using the AXM55xx SoC need to have the following properties:
-
-Required root node property:
-
-  - compatible = "lsi,axm5516"
-
-Boards:
-
-  LSI AXM5516 Validation board (Amarillo)
-       compatible = "lsi,axm5516-amarillo", "lsi,axm5516"
diff --git a/Documentation/devicetree/bindings/arm/axxia.yaml b/Documentation/devicetree/bindings/arm/axxia.yaml
new file mode 100644 (file)
index 0000000..98780a5
--- /dev/null
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/axxia.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Axxia AXM55xx device tree bindings
+
+maintainers:
+  - Anders Berg <anders.berg@lsi.com>
+
+properties:
+  compatible:
+    description: LSI AXM5516 Validation board (Amarillo)
+    items:
+      - const: lsi,axm5516-amarillo
+      - const: lsi,axm5516
+
+...
index 2982912..f1de324 100644 (file)
@@ -26,8 +26,8 @@ Required properties:
                processor core is clocked by the internal CPU clock, so it
                is enabled with CPU clock by default.
 
-- cpu : the CPU phandle the debug module is affined to. When omitted
-       the module is considered to belong to CPU0.
+- cpu : the CPU phandle the debug module is affined to. Do not assume it
+        to default to CPU0 if omitted.
 
 Optional properties:
 
index 8a88dde..fcc3bac 100644 (file)
@@ -59,6 +59,11 @@ its hardware characteristcs.
 
        * port or ports: see "Graph bindings for Coresight" below.
 
+* Additional required property for Embedded Trace Macrocell (version 3.x and
+  version 4.x):
+       * cpu: the cpu phandle this ETM/PTM is affined to. Do not
+         assume it to default to CPU0 if omitted.
+
 * Additional required properties for System Trace Macrocells (STM):
        * reg: along with the physical base address and length of the register
          set as described above, another entry is required to describe the
@@ -87,9 +92,6 @@ its hardware characteristcs.
        * arm,cp14: must be present if the system accesses ETM/PTM management
          registers via co-processor 14.
 
-       * cpu: the cpu phandle this ETM/PTM is affined to. When omitted the
-         source is considered to belong to CPU0.
-
 * Optional property for TMC:
 
        * arm,buffer-size: size of contiguous buffer space for TMC ETR
index 591bbd0..aa40b07 100644 (file)
@@ -39,281 +39,242 @@ description: |+
   described below.
 
 properties:
-  $nodename:
-    const: cpus
-    description: Container of cpu nodes
-
-  '#address-cells':
-    enum: [1, 2]
+  reg:
+    maxItems: 1
     description: |
-      Definition depends on ARM architecture version and configuration:
+      Usage and definition depend on ARM architecture version and
+      configuration:
 
       On uniprocessor ARM architectures previous to v7
-        value must be 1, to enable a simple enumeration
-        scheme for processors that do not have a HW CPU
-        identification register.
-      On 32-bit ARM 11 MPcore, ARM v7 or later systems
-        value must be 1, that corresponds to CPUID/MPIDR
-        registers sizes.
-      On ARM v8 64-bit systems value should be set to 2,
-        that corresponds to the MPIDR_EL1 register size.
-        If MPIDR_EL1[63:32] value is equal to 0 on all CPUs
-        in the system, #address-cells can be set to 1, since
-        MPIDR_EL1[63:32] bits are not used for CPUs
-        identification.
-
-  '#size-cells':
-    const: 0
-
-patternProperties:
-  '^cpu@[0-9a-f]+$':
-    type: object
-    properties:
-      device_type:
-        const: cpu
-
-      reg:
-        maxItems: 1
-        description: |
-          Usage and definition depend on ARM architecture version and
-          configuration:
-
-          On uniprocessor ARM architectures previous to v7
-          this property is required and must be set to 0.
-
-          On ARM 11 MPcore based systems this property is
-            required and matches the CPUID[11:0] register bits.
-
-            Bits [11:0] in the reg cell must be set to
-            bits [11:0] in CPU ID register.
-
-            All other bits in the reg cell must be set to 0.
-
-          On 32-bit ARM v7 or later systems this property is
-            required and matches the CPU MPIDR[23:0] register
-            bits.
-
-            Bits [23:0] in the reg cell must be set to
-            bits [23:0] in MPIDR.
-
-            All other bits in the reg cell must be set to 0.
-
-          On ARM v8 64-bit systems this property is required
-            and matches the MPIDR_EL1 register affinity bits.
+      this property is required and must be set to 0.
+
+      On ARM 11 MPcore based systems this property is
+        required and matches the CPUID[11:0] register bits.
+
+        Bits [11:0] in the reg cell must be set to
+        bits [11:0] in CPU ID register.
+
+        All other bits in the reg cell must be set to 0.
+
+      On 32-bit ARM v7 or later systems this property is
+        required and matches the CPU MPIDR[23:0] register
+        bits.
+
+        Bits [23:0] in the reg cell must be set to
+        bits [23:0] in MPIDR.
+
+        All other bits in the reg cell must be set to 0.
+
+      On ARM v8 64-bit systems this property is required
+        and matches the MPIDR_EL1 register affinity bits.
+
+        * If cpus node's #address-cells property is set to 2
+
+          The first reg cell bits [7:0] must be set to
+          bits [39:32] of MPIDR_EL1.
+
+          The second reg cell bits [23:0] must be set to
+          bits [23:0] of MPIDR_EL1.
+
+        * If cpus node's #address-cells property is set to 1
+
+          The reg cell bits [23:0] must be set to bits [23:0]
+          of MPIDR_EL1.
+
+      All other bits in the reg cells must be set to 0.
+
+  compatible:
+    enum:
+      - arm,arm710t
+      - arm,arm720t
+      - arm,arm740t
+      - arm,arm7ej-s
+      - arm,arm7tdmi
+      - arm,arm7tdmi-s
+      - arm,arm9es
+      - arm,arm9ej-s
+      - arm,arm920t
+      - arm,arm922t
+      - arm,arm925
+      - arm,arm926e-s
+      - arm,arm926ej-s
+      - arm,arm940t
+      - arm,arm946e-s
+      - arm,arm966e-s
+      - arm,arm968e-s
+      - arm,arm9tdmi
+      - arm,arm1020e
+      - arm,arm1020t
+      - arm,arm1022e
+      - arm,arm1026ej-s
+      - arm,arm1136j-s
+      - arm,arm1136jf-s
+      - arm,arm1156t2-s
+      - arm,arm1156t2f-s
+      - arm,arm1176jzf
+      - arm,arm1176jz-s
+      - arm,arm1176jzf-s
+      - arm,arm11mpcore
+      - arm,armv8 # Only for s/w models
+      - arm,cortex-a5
+      - arm,cortex-a7
+      - arm,cortex-a8
+      - arm,cortex-a9
+      - arm,cortex-a12
+      - arm,cortex-a15
+      - arm,cortex-a17
+      - arm,cortex-a53
+      - arm,cortex-a57
+      - arm,cortex-a72
+      - arm,cortex-a73
+      - arm,cortex-m0
+      - arm,cortex-m0+
+      - arm,cortex-m1
+      - arm,cortex-m3
+      - arm,cortex-m4
+      - arm,cortex-r4
+      - arm,cortex-r5
+      - arm,cortex-r7
+      - brcm,brahma-b15
+      - brcm,brahma-b53
+      - brcm,vulcan
+      - cavium,thunder
+      - cavium,thunder2
+      - faraday,fa526
+      - intel,sa110
+      - intel,sa1100
+      - marvell,feroceon
+      - marvell,mohawk
+      - marvell,pj4a
+      - marvell,pj4b
+      - marvell,sheeva-v5
+      - marvell,sheeva-v7
+      - nvidia,tegra132-denver
+      - nvidia,tegra186-denver
+      - nvidia,tegra194-carmel
+      - qcom,krait
+      - qcom,kryo
+      - qcom,kryo385
+      - qcom,scorpion
+
+  enable-method:
+    allOf:
+      - $ref: '/schemas/types.yaml#/definitions/string'
+      - oneOf:
+          # On ARM v8 64-bit this property is required
+          - enum:
+              - psci
+              - spin-table
+          # On ARM 32-bit systems this property is optional
+          - enum:
+              - actions,s500-smp
+              - allwinner,sun6i-a31
+              - allwinner,sun8i-a23
+              - allwinner,sun9i-a80-smp
+              - allwinner,sun8i-a83t-smp
+              - amlogic,meson8-smp
+              - amlogic,meson8b-smp
+              - arm,realview-smp
+              - brcm,bcm11351-cpu-method
+              - brcm,bcm23550
+              - brcm,bcm2836-smp
+              - brcm,bcm63138
+              - brcm,bcm-nsp-smp
+              - brcm,brahma-b15
+              - marvell,armada-375-smp
+              - marvell,armada-380-smp
+              - marvell,armada-390-smp
+              - marvell,armada-xp-smp
+              - marvell,98dx3236-smp
+              - mediatek,mt6589-smp
+              - mediatek,mt81xx-tz-smp
+              - qcom,gcc-msm8660
+              - qcom,kpss-acc-v1
+              - qcom,kpss-acc-v2
+              - renesas,apmu
+              - renesas,r9a06g032-smp
+              - rockchip,rk3036-smp
+              - rockchip,rk3066-smp
+              - socionext,milbeaut-m10v-smp
+              - ste,dbx500-smp
+
+  cpu-release-addr:
+    $ref: '/schemas/types.yaml#/definitions/uint64'
+
+    description:
+      Required for systems that have an "enable-method"
+        property value of "spin-table".
+      On ARM v8 64-bit systems must be a two cell
+        property identifying a 64-bit zero-initialised
+        memory location.
+
+  cpu-idle-states:
+    $ref: '/schemas/types.yaml#/definitions/phandle-array'
+    description: |
+      List of phandles to idle state nodes supported
+      by this cpu (see ./idle-states.txt).
+
+  capacity-dmips-mhz:
+    $ref: '/schemas/types.yaml#/definitions/uint32'
+    description:
+      u32 value representing CPU capacity (see ./cpu-capacity.txt) in
+      DMIPS/MHz, relative to highest capacity-dmips-mhz
+      in the system.
+
+  dynamic-power-coefficient:
+    $ref: '/schemas/types.yaml#/definitions/uint32'
+    description:
+      A u32 value that represents the running time dynamic
+      power coefficient in units of uW/MHz/V^2. The
+      coefficient can either be calculated from power
+      measurements or derived by analysis.
+
+      The dynamic power consumption of the CPU  is
+      proportional to the square of the Voltage (V) and
+      the clock frequency (f). The coefficient is used to
+      calculate the dynamic power as below -
+
+      Pdyn = dynamic-power-coefficient * V^2 * f
+
+      where voltage is in V, frequency is in MHz.
+
+  qcom,saw:
+    $ref: '/schemas/types.yaml#/definitions/phandle'
+    description: |
+      Specifies the SAW* node associated with this CPU.
 
-            * If cpus node's #address-cells property is set to 2
+      Required for systems that have an "enable-method" property
+      value of "qcom,kpss-acc-v1" or "qcom,kpss-acc-v2"
 
-              The first reg cell bits [7:0] must be set to
-              bits [39:32] of MPIDR_EL1.
+      * arm/msm/qcom,saw2.txt
 
-              The second reg cell bits [23:0] must be set to
-              bits [23:0] of MPIDR_EL1.
+  qcom,acc:
+    $ref: '/schemas/types.yaml#/definitions/phandle'
+    description: |
+      Specifies the ACC* node associated with this CPU.
 
-            * If cpus node's #address-cells property is set to 1
+      Required for systems that have an "enable-method" property
+      value of "qcom,kpss-acc-v1" or "qcom,kpss-acc-v2"
 
-              The reg cell bits [23:0] must be set to bits [23:0]
-              of MPIDR_EL1.
+      * arm/msm/qcom,kpss-acc.txt
 
-          All other bits in the reg cells must be set to 0.
+  rockchip,pmu:
+    $ref: '/schemas/types.yaml#/definitions/phandle'
+    description: |
+      Specifies the syscon node controlling the cpu core power domains.
 
-      compatible:
-        items:
-          - enum:
-              - arm,arm710t
-              - arm,arm720t
-              - arm,arm740t
-              - arm,arm7ej-s
-              - arm,arm7tdmi
-              - arm,arm7tdmi-s
-              - arm,arm9es
-              - arm,arm9ej-s
-              - arm,arm920t
-              - arm,arm922t
-              - arm,arm925
-              - arm,arm926e-s
-              - arm,arm926ej-s
-              - arm,arm940t
-              - arm,arm946e-s
-              - arm,arm966e-s
-              - arm,arm968e-s
-              - arm,arm9tdmi
-              - arm,arm1020e
-              - arm,arm1020t
-              - arm,arm1022e
-              - arm,arm1026ej-s
-              - arm,arm1136j-s
-              - arm,arm1136jf-s
-              - arm,arm1156t2-s
-              - arm,arm1156t2f-s
-              - arm,arm1176jzf
-              - arm,arm1176jz-s
-              - arm,arm1176jzf-s
-              - arm,arm11mpcore
-              - arm,armv8 # Only for s/w models
-              - arm,cortex-a5
-              - arm,cortex-a7
-              - arm,cortex-a8
-              - arm,cortex-a9
-              - arm,cortex-a12
-              - arm,cortex-a15
-              - arm,cortex-a17
-              - arm,cortex-a53
-              - arm,cortex-a57
-              - arm,cortex-a72
-              - arm,cortex-a73
-              - arm,cortex-m0
-              - arm,cortex-m0+
-              - arm,cortex-m1
-              - arm,cortex-m3
-              - arm,cortex-m4
-              - arm,cortex-r4
-              - arm,cortex-r5
-              - arm,cortex-r7
-              - brcm,brahma-b15
-              - brcm,brahma-b53
-              - brcm,vulcan
-              - cavium,thunder
-              - cavium,thunder2
-              - faraday,fa526
-              - intel,sa110
-              - intel,sa1100
-              - marvell,feroceon
-              - marvell,mohawk
-              - marvell,pj4a
-              - marvell,pj4b
-              - marvell,sheeva-v5
-              - marvell,sheeva-v7
-              - nvidia,tegra132-denver
-              - nvidia,tegra186-denver
-              - nvidia,tegra194-carmel
-              - qcom,krait
-              - qcom,kryo
-              - qcom,kryo385
-              - qcom,scorpion
-
-      enable-method:
-        allOf:
-          - $ref: '/schemas/types.yaml#/definitions/string'
-          - oneOf:
-            # On ARM v8 64-bit this property is required
-            - enum:
-                - psci
-                - spin-table
-            # On ARM 32-bit systems this property is optional
-            - enum:
-                - actions,s500-smp
-                - allwinner,sun6i-a31
-                - allwinner,sun8i-a23
-                - allwinner,sun9i-a80-smp
-                - allwinner,sun8i-a83t-smp
-                - amlogic,meson8-smp
-                - amlogic,meson8b-smp
-                - arm,realview-smp
-                - brcm,bcm11351-cpu-method
-                - brcm,bcm23550
-                - brcm,bcm2836-smp
-                - brcm,bcm63138
-                - brcm,bcm-nsp-smp
-                - brcm,brahma-b15
-                - marvell,armada-375-smp
-                - marvell,armada-380-smp
-                - marvell,armada-390-smp
-                - marvell,armada-xp-smp
-                - marvell,98dx3236-smp
-                - mediatek,mt6589-smp
-                - mediatek,mt81xx-tz-smp
-                - qcom,gcc-msm8660
-                - qcom,kpss-acc-v1
-                - qcom,kpss-acc-v2
-                - renesas,apmu
-                - renesas,r9a06g032-smp
-                - rockchip,rk3036-smp
-                - rockchip,rk3066-smp
-                - socionext,milbeaut-m10v-smp
-                - ste,dbx500-smp
-
-      cpu-release-addr:
-        $ref: '/schemas/types.yaml#/definitions/uint64'
-
-        description:
-          Required for systems that have an "enable-method"
-            property value of "spin-table".
-          On ARM v8 64-bit systems must be a two cell
-            property identifying a 64-bit zero-initialised
-            memory location.
-
-      cpu-idle-states:
-        $ref: '/schemas/types.yaml#/definitions/phandle-array'
-        description: |
-          List of phandles to idle state nodes supported
-          by this cpu (see ./idle-states.txt).
-
-      capacity-dmips-mhz:
-        $ref: '/schemas/types.yaml#/definitions/uint32'
-        description:
-          u32 value representing CPU capacity (see ./cpu-capacity.txt) in
-          DMIPS/MHz, relative to highest capacity-dmips-mhz
-          in the system.
-
-      dynamic-power-coefficient:
-        $ref: '/schemas/types.yaml#/definitions/uint32'
-        description:
-          A u32 value that represents the running time dynamic
-          power coefficient in units of uW/MHz/V^2. The
-          coefficient can either be calculated from power
-          measurements or derived by analysis.
-
-          The dynamic power consumption of the CPU  is
-          proportional to the square of the Voltage (V) and
-          the clock frequency (f). The coefficient is used to
-          calculate the dynamic power as below -
-
-          Pdyn = dynamic-power-coefficient * V^2 * f
-
-          where voltage is in V, frequency is in MHz.
-
-      qcom,saw:
-        $ref: '/schemas/types.yaml#/definitions/phandle'
-        description: |
-          Specifies the SAW* node associated with this CPU.
-
-          Required for systems that have an "enable-method" property
-          value of "qcom,kpss-acc-v1" or "qcom,kpss-acc-v2"
-
-          * arm/msm/qcom,saw2.txt
-
-      qcom,acc:
-        $ref: '/schemas/types.yaml#/definitions/phandle'
-        description: |
-          Specifies the ACC* node associated with this CPU.
-
-          Required for systems that have an "enable-method" property
-          value of "qcom,kpss-acc-v1" or "qcom,kpss-acc-v2"
-
-          * arm/msm/qcom,kpss-acc.txt
-
-      rockchip,pmu:
-        $ref: '/schemas/types.yaml#/definitions/phandle'
-        description: |
-          Specifies the syscon node controlling the cpu core power domains.
-
-          Optional for systems that have an "enable-method"
-          property value of "rockchip,rk3066-smp"
-          While optional, it is the preferred way to get access to
-          the cpu-core power-domains.
-
-    required:
-      - device_type
-      - reg
-      - compatible
-
-    dependencies:
-      cpu-release-addr: [enable-method]
-      rockchip,pmu: [enable-method]
+      Optional for systems that have an "enable-method"
+      property value of "rockchip,rk3066-smp"
+      While optional, it is the preferred way to get access to
+      the cpu-core power-domains.
 
 required:
-  - '#address-cells'
-  - '#size-cells'
+  - device_type
+  - reg
+  - compatible
+
+dependencies:
+  rockchip,pmu: [enable-method]
 
 examples:
   - |
diff --git a/Documentation/devicetree/bindings/arm/digicolor.txt b/Documentation/devicetree/bindings/arm/digicolor.txt
deleted file mode 100644 (file)
index 658553f..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-Conexant Digicolor Platforms Device Tree Bindings
-
-Each device tree must specify which Conexant Digicolor SoC it uses.
-Must be the following compatible string:
-
-  cnxt,cx92755
diff --git a/Documentation/devicetree/bindings/arm/digicolor.yaml b/Documentation/devicetree/bindings/arm/digicolor.yaml
new file mode 100644 (file)
index 0000000..d9c80b8
--- /dev/null
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/digicolor.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Conexant Digicolor Platforms Device Tree Bindings
+
+maintainers:
+  - Baruch Siach <baruch@tkos.co.il>
+
+properties:
+  compatible:
+    const: cnxt,cx92755
+
+...
index 5d7dbab..f378922 100644 (file)
@@ -133,6 +133,18 @@ RTC bindings based on SCU Message Protocol
 Required properties:
 - compatible: should be "fsl,imx8qxp-sc-rtc";
 
+OCOTP bindings based on SCU Message Protocol
+------------------------------------------------------------
+Required properties:
+- compatible:          Should be "fsl,imx8qxp-scu-ocotp"
+- #address-cells:      Must be 1. Contains byte index
+- #size-cells:         Must be 1. Contains byte length
+
+Optional Child nodes:
+
+- Data cells of ocotp:
+  Detailed bindings are described in bindings/nvmem/nvmem.txt
+
 Example (imx8qxp):
 -------------
 aliases {
@@ -177,6 +189,16 @@ firmware {
                        ...
                };
 
+               ocotp: imx8qx-ocotp {
+                       compatible = "fsl,imx8qxp-scu-ocotp";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       fec_mac0: mac@2c4 {
+                               reg = <0x2c4 8>;
+                       };
+               };
+
                pd: imx8qx-pd {
                        compatible = "fsl,imx8qxp-scu-pd", "fsl,scu-pd";
                        #power-domain-cells = <1>;
index 45730ba..326f29b 100644 (file)
@@ -241,9 +241,13 @@ processor idle states, defined as device tree nodes, are listed.
                           - "psci"
                        # On ARM 32-bit systems this property is optional
 
-The nodes describing the idle states (state) can only be defined within the
-idle-states node, any other configuration is considered invalid and therefore
-must be ignored.
+This assumes that the "enable-method" property is set to "psci" in the cpu
+node[6] that is responsible for setting up CPU idle management in the OS
+implementation.
+
+The nodes describing the idle states (state) can only be defined
+within the idle-states node, any other configuration is considered invalid
+and therefore must be ignored.
 
 ===========================================
 4 - state node
@@ -687,7 +691,7 @@ cpus {
     Documentation/devicetree/bindings/arm/cpus.yaml
 
 [2] ARM Linux Kernel documentation - PSCI bindings
-    Documentation/devicetree/bindings/arm/psci.txt
+    Documentation/devicetree/bindings/arm/psci.yaml
 
 [3] ARM Server Base System Architecture (SBSA)
     http://infocenter.arm.com/help/index.jsp
@@ -697,3 +701,6 @@ cpus {
 
 [5] Devicetree Specification
     https://www.devicetree.org/specifications/
+
+[6] ARM Linux Kernel documentation - Booting AArch64 Linux
+    Documentation/arm64/booting.txt
diff --git a/Documentation/devicetree/bindings/arm/moxart.txt b/Documentation/devicetree/bindings/arm/moxart.txt
deleted file mode 100644 (file)
index 11087ed..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-MOXA ART device tree bindings
-
-Boards with the MOXA ART SoC shall have the following properties:
-
-Required root node property:
-
-compatible = "moxa,moxart";
-
-Boards:
-
-- UC-7112-LX: embedded computer
-  compatible = "moxa,moxart-uc-7112-lx", "moxa,moxart"
diff --git a/Documentation/devicetree/bindings/arm/moxart.yaml b/Documentation/devicetree/bindings/arm/moxart.yaml
new file mode 100644 (file)
index 0000000..c068df5
--- /dev/null
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/moxart.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MOXA ART device tree bindings
+
+maintainers:
+  - Jonas Jensen <jonas.jensen@gmail.com>
+
+properties:
+  compatible:
+    description: UC-7112-LX embedded computer
+    items:
+      - const: moxa,moxart-uc-7112-lx
+      - const: moxa,moxart
+
+...
diff --git a/Documentation/devicetree/bindings/arm/nxp/lpc32xx.txt b/Documentation/devicetree/bindings/arm/nxp/lpc32xx.txt
deleted file mode 100644 (file)
index 56ec8dd..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-NXP LPC32xx Platforms Device Tree Bindings
-------------------------------------------
-
-Boards with the NXP LPC32xx SoC shall have the following properties:
-
-Required root node property:
-
-compatible: must be "nxp,lpc3220", "nxp,lpc3230", "nxp,lpc3240" or "nxp,lpc3250"
diff --git a/Documentation/devicetree/bindings/arm/nxp/lpc32xx.yaml b/Documentation/devicetree/bindings/arm/nxp/lpc32xx.yaml
new file mode 100644 (file)
index 0000000..07f39d3
--- /dev/null
@@ -0,0 +1,25 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/nxp/lpc32xx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP LPC32xx Platforms Device Tree Bindings
+
+maintainers:
+  - Roland Stigge <stigge@antcom.de>
+
+properties:
+  compatible:
+    oneOf:
+      - enum:
+          - nxp,lpc3220
+          - nxp,lpc3230
+          - nxp,lpc3240
+      - items:
+        - enum:
+            - ea,ea3250
+            - phytec,phy3250
+        - const: nxp,lpc3250
+
+...
diff --git a/Documentation/devicetree/bindings/arm/psci.txt b/Documentation/devicetree/bindings/arm/psci.txt
deleted file mode 100644 (file)
index a2c4f1d..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-* Power State Coordination Interface (PSCI)
-
-Firmware implementing the PSCI functions described in ARM document number
-ARM DEN 0022A ("Power State Coordination Interface System Software on ARM
-processors") can be used by Linux to initiate various CPU-centric power
-operations.
-
-Issue A of the specification describes functions for CPU suspend, hotplug
-and migration of secure software.
-
-Functions are invoked by trapping to the privilege level of the PSCI
-firmware (specified as part of the binding below) and passing arguments
-in a manner similar to that specified by AAPCS:
-
-        r0             => 32-bit Function ID / return value
-       {r1 - r3}       => Parameters
-
-Note that the immediate field of the trapping instruction must be set
-to #0.
-
-
-Main node required properties:
-
- - compatible    : should contain at least one of:
-
-     * "arm,psci"     : For implementations complying to PSCI versions prior
-                       to 0.2.
-                       For these cases function IDs must be provided.
-
-     * "arm,psci-0.2" : For implementations complying to PSCI 0.2.
-                       Function IDs are not required and should be ignored by
-                       an OS with PSCI 0.2 support, but are permitted to be
-                       present for compatibility with existing software when
-                       "arm,psci" is later in the compatible list.
-
-     * "arm,psci-1.0" : For implementations complying to PSCI 1.0.
-                       PSCI 1.0 is backward compatible with PSCI 0.2 with
-                       minor specification updates, as defined in the PSCI
-                       specification[2].
-
- - method        : The method of calling the PSCI firmware. Permitted
-                   values are:
-
-                   "smc" : SMC #0, with the register assignments specified
-                          in this binding.
-
-                   "hvc" : HVC #0, with the register assignments specified
-                          in this binding.
-
-Main node optional properties:
-
- - cpu_suspend   : Function ID for CPU_SUSPEND operation
-
- - cpu_off       : Function ID for CPU_OFF operation
-
- - cpu_on        : Function ID for CPU_ON operation
-
- - migrate       : Function ID for MIGRATE operation
-
-Device tree nodes that require usage of PSCI CPU_SUSPEND function (ie idle
-state nodes, as per bindings in [1]) must specify the following properties:
-
-- arm,psci-suspend-param
-               Usage: Required for state nodes[1] if the corresponding
-                       idle-states node entry-method property is set
-                       to "psci".
-               Value type: <u32>
-               Definition: power_state parameter to pass to the PSCI
-                           suspend call.
-
-Example:
-
-Case 1: PSCI v0.1 only.
-
-       psci {
-               compatible      = "arm,psci";
-               method          = "smc";
-               cpu_suspend     = <0x95c10000>;
-               cpu_off         = <0x95c10001>;
-               cpu_on          = <0x95c10002>;
-               migrate         = <0x95c10003>;
-       };
-
-Case 2: PSCI v0.2 only
-
-       psci {
-               compatible      = "arm,psci-0.2";
-               method          = "smc";
-       };
-
-Case 3: PSCI v0.2 and PSCI v0.1.
-
-       A DTB may provide IDs for use by kernels without PSCI 0.2 support,
-       enabling firmware and hypervisors to support existing and new kernels.
-       These IDs will be ignored by kernels with PSCI 0.2 support, which will
-       use the standard PSCI 0.2 IDs exclusively.
-
-       psci {
-               compatible = "arm,psci-0.2", "arm,psci";
-               method = "hvc";
-
-               cpu_on = < arbitrary value >;
-               cpu_off = < arbitrary value >;
-
-               ...
-       };
-
-[1] Kernel documentation - ARM idle states bindings
-    Documentation/devicetree/bindings/arm/idle-states.txt
-[2] Power State Coordination Interface (PSCI) specification
-    http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf
diff --git a/Documentation/devicetree/bindings/arm/psci.yaml b/Documentation/devicetree/bindings/arm/psci.yaml
new file mode 100644 (file)
index 0000000..7abdf58
--- /dev/null
@@ -0,0 +1,163 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/psci.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Power State Coordination Interface (PSCI)
+
+maintainers:
+  - Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+
+description: |+
+  Firmware implementing the PSCI functions described in ARM document number
+  ARM DEN 0022A ("Power State Coordination Interface System Software on ARM
+  processors") can be used by Linux to initiate various CPU-centric power
+  operations.
+
+  Issue A of the specification describes functions for CPU suspend, hotplug
+  and migration of secure software.
+
+  Functions are invoked by trapping to the privilege level of the PSCI
+  firmware (specified as part of the binding below) and passing arguments
+  in a manner similar to that specified by AAPCS:
+
+     r0       => 32-bit Function ID / return value
+    {r1 - r3}  => Parameters
+
+  Note that the immediate field of the trapping instruction must be set
+  to #0.
+
+  [2] Power State Coordination Interface (PSCI) specification
+    http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf
+
+properties:
+  compatible:
+    oneOf:
+      - description:
+          For implementations complying to PSCI versions prior to 0.2.
+        const: arm,psci
+
+      - description:
+          For implementations complying to PSCI 0.2.
+        const: arm,psci-0.2
+
+      - description:
+          For implementations complying to PSCI 0.2.
+          Function IDs are not required and should be ignored by an OS with
+          PSCI 0.2 support, but are permitted to be present for compatibility
+          with existing software when "arm,psci" is later in the compatible
+          list.
+        items:
+          - const: arm,psci-0.2
+          - const: arm,psci
+
+      - description:
+          For implementations complying to PSCI 1.0.
+        const: arm,psci-1.0
+
+      - description:
+          For implementations complying to PSCI 1.0.
+          PSCI 1.0 is backward compatible with PSCI 0.2 with minor
+          specification updates, as defined in the PSCI specification[2].
+        items:
+          - const: arm,psci-1.0
+          - const: arm,psci-0.2
+
+  method:
+    description: The method of calling the PSCI firmware.
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/string-array
+      - enum:
+          # SMC #0, with the register assignments specified in this binding.
+          - smc
+          # HVC #0, with the register assignments specified in this binding.
+          - hvc
+
+  cpu_suspend:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Function ID for CPU_SUSPEND operation
+
+  cpu_off:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Function ID for CPU_OFF operation
+
+  cpu_on:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Function ID for CPU_ON operation
+
+  migrate:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Function ID for MIGRATE operation
+
+  arm,psci-suspend-param:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: |
+      power_state parameter to pass to the PSCI suspend call.
+
+      Device tree nodes that require usage of PSCI CPU_SUSPEND function (ie
+      idle state nodes with entry-method property is set to "psci", as per
+      bindings in [1]) must specify this property.
+
+      [1] Kernel documentation - ARM idle states bindings
+        Documentation/devicetree/bindings/arm/idle-states.txt
+
+
+required:
+  - compatible
+  - method
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: arm,psci
+    then:
+      required:
+        - cpu_off
+        - cpu_on
+
+examples:
+  - |+
+
+    // Case 1: PSCI v0.1 only.
+
+    psci {
+      compatible      = "arm,psci";
+      method          = "smc";
+      cpu_suspend     = <0x95c10000>;
+      cpu_off         = <0x95c10001>;
+      cpu_on          = <0x95c10002>;
+      migrate         = <0x95c10003>;
+    };
+
+  - |+
+
+    // Case 2: PSCI v0.2 only
+
+    psci {
+      compatible      = "arm,psci-0.2";
+      method          = "smc";
+    };
+
+
+  - |+
+
+    // Case 3: PSCI v0.2 and PSCI v0.1.
+
+    /*
+     * A DTB may provide IDs for use by kernels without PSCI 0.2 support,
+     * enabling firmware and hypervisors to support existing and new kernels.
+     * These IDs will be ignored by kernels with PSCI 0.2 support, which will
+     * use the standard PSCI 0.2 IDs exclusively.
+     */
+
+    psci {
+      compatible = "arm,psci-0.2", "arm,psci";
+      method = "hvc";
+
+      cpu_on = <0x95c10002>;
+      cpu_off = <0x95c10001>;
+    };
+...
index f6316ab..54ef6b6 100644 (file)
@@ -101,6 +101,15 @@ properties:
               - qcom,msm8960-cdp
           - const: qcom,msm8960
 
+      - items:
+          - enum:
+              - fairphone,fp2
+              - lge,hammerhead
+              - sony,xperia-amami
+              - sony,xperia-castor
+              - sony,xperia-honami
+          - const: qcom,msm8974
+
       - items:
           - const: qcom,msm8916-mtp/1
           - const: qcom,msm8916-mtp
@@ -110,6 +119,11 @@ properties:
           - const: qcom,msm8996-mtp
 
       - items:
+          - enum:
+              - qcom,ipq4019-ap-dk04.1-c3
+              - qcom,ipq4019-ap-dk07.1-c1
+              - qcom,ipq4019-ap-dk07.1-c2
+              - qcom,ipq4019-dk04.1-c1
           - const: qcom,ipq4019
 
       - items:
diff --git a/Documentation/devicetree/bindings/arm/rda.txt b/Documentation/devicetree/bindings/arm/rda.txt
deleted file mode 100644 (file)
index 43c8076..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-RDA Micro platforms device tree bindings
-----------------------------------------
-
-RDA8810PL SoC
-=============
-
-Required root node properties:
-
- - compatible :  must contain "rda,8810pl"
-
-
-Boards:
-
-Root node property compatible must contain, depending on board:
-
- - Orange Pi 2G-IoT: "xunlong,orangepi-2g-iot"
- - Orange Pi i96: "xunlong,orangepi-i96"
diff --git a/Documentation/devicetree/bindings/arm/rda.yaml b/Documentation/devicetree/bindings/arm/rda.yaml
new file mode 100644 (file)
index 0000000..51cec2b
--- /dev/null
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/rda.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: RDA Micro platforms device tree bindings
+
+maintainers:
+  - Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - xunlong,orangepi-2g-iot     # Orange Pi 2G-IoT
+          - xunlong,orangepi-i96        # Orange Pi i96
+      - const: rda,8810pl
+
+...
index a3448bf..98a2813 100644 (file)
@@ -5,30 +5,29 @@ Endianness
 ----------
 
 The Devicetree Specification does not define any properties related to hardware
-byteswapping, but endianness issues show up frequently in porting Linux to
+byte swapping, but endianness issues show up frequently in porting drivers to
 different machine types.  This document attempts to provide a consistent
-way of handling byteswapping across drivers.
+way of handling byte swapping across drivers.
 
 Optional properties:
  - big-endian: Boolean; force big endian register accesses
    unconditionally (e.g. ioread32be/iowrite32be).  Use this if you
-   know the peripheral always needs to be accessed in BE mode.
+   know the peripheral always needs to be accessed in big endian (BE) mode.
  - little-endian: Boolean; force little endian register accesses
    unconditionally (e.g. readl/writel).  Use this if you know the
-   peripheral always needs to be accessed in LE mode.
+   peripheral always needs to be accessed in little endian (LE) mode.
  - native-endian: Boolean; always use register accesses matched to the
    endianness of the kernel binary (e.g. LE vmlinux -> readl/writel,
-   BE vmlinux -> ioread32be/iowrite32be).  In this case no byteswaps
+   BE vmlinux -> ioread32be/iowrite32be).  In this case no byte swaps
    will ever be performed.  Use this if the hardware "self-adjusts"
    register endianness based on the CPU's configured endianness.
 
 If a binding supports these properties, then the binding should also
 specify the default behavior if none of these properties are present.
 In such cases, little-endian is the preferred default, but it is not
-a requirement.  The of_device_is_big_endian() and of_fdt_is_big_endian()
-helper functions do assume that little-endian is the default, because
-most existing (PCI-based) drivers implicitly default to LE by using
-readl/writel for MMIO accesses.
+a requirement.  Some implementations assume that little-endian is
+the default, because most existing (PCI-based) drivers implicitly
+default to LE for their MMIO accesses.
 
 Examples:
 Scenario 1 : CPU in LE mode & device in LE mode.
index b052d76..678776b 100644 (file)
@@ -126,6 +126,28 @@ required:
   # but usually they will be filled by the bootloader.
   - compatible
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: allwinner,simple-framebuffer
+
+    then:
+      required:
+        - allwinner,pipeline
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: amlogic,simple-framebuffer
+
+    then:
+      required:
+        - amlogic,pipeline
+
+
 additionalProperties: false
 
 examples:
@@ -139,7 +161,8 @@ examples:
       #size-cells = <1>;
       stdout-path = "display0";
       framebuffer0: framebuffer@1d385000 {
-        compatible = "simple-framebuffer";
+        compatible = "allwinner,simple-framebuffer", "simple-framebuffer";
+        allwinner,pipeline = "de_be0-lcd0";
         reg = <0x1d385000 3840000>;
         width = <1600>;
         height = <1200>;
diff --git a/Documentation/devicetree/bindings/extcon/extcon-fsa9480.txt b/Documentation/devicetree/bindings/extcon/extcon-fsa9480.txt
new file mode 100644 (file)
index 0000000..d592c21
--- /dev/null
@@ -0,0 +1,19 @@
+FAIRCHILD SEMICONDUCTOR FSA9480 MICROUSB SWITCH
+
+The FSA9480 is a USB port accessory detector and switch. The FSA9480 is fully
+controlled using I2C and enables USB data, stereo and mono audio, video,
+microphone, and UART data to use a common connector port.
+
+Required properties:
+ - compatible : Must be "fcs,fsa9480"
+ - reg : Specifies i2c slave address. Must be 0x25.
+ - interrupts : Should contain one entry specifying interrupt signal of
+   interrupt parent to which interrupt pin of the chip is connected.
+
+ Example:
+       musb@25 {
+               compatible = "fcs,fsa9480";
+               reg = <0x25>;
+               interrupt-parent = <&gph2>;
+               interrupts = <7 0>;
+       };
diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml
new file mode 100644 (file)
index 0000000..7ba167e
--- /dev/null
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/accelerometers/adi,adxl345.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices ADXL345/ADXL375 3-Axis Digital Accelerometers
+
+maintainers:
+  - Michael Hennerich <michael.hennerich@analog.com>
+
+description: |
+  Analog Devices ADXL345/ADXL375 3-Axis Digital Accelerometers that supports
+  both I2C & SPI interfaces.
+    http://www.analog.com/en/products/mems/accelerometers/adxl345.html
+    http://www.analog.com/en/products/sensors-mems/accelerometers/adxl375.html
+
+properties:
+  compatible:
+    enum:
+      - adi,adxl345
+      - adi,adxl375
+
+  reg:
+    maxItems: 1
+
+  spi-cpha: true
+
+  spi-cpol: true
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    i2c0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        /* Example for a I2C device node */
+        accelerometer@2a {
+            compatible = "adi,adxl345";
+            reg = <0x53>;
+            interrupt-parent = <&gpio0>;
+            interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
+        };
+    };
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    spi0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        /* Example for a SPI device node */
+        accelerometer@0 {
+            compatible = "adi,adxl345";
+            reg = <0>;
+            spi-max-frequency = <5000000>;
+            spi-cpol;
+            spi-cpha;
+            interrupt-parent = <&gpio0>;
+            interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml
new file mode 100644 (file)
index 0000000..a7fafb9
--- /dev/null
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/accelerometers/adi,adxl372.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices ADXL372 3-Axis, +/-(200g) Digital Accelerometer
+
+maintainers:
+  - Stefan Popa <stefan.popa@analog.com>
+
+description: |
+  Analog Devices ADXL372 3-Axis, +/-(200g) Digital Accelerometer that supports
+  both I2C & SPI interfaces
+    https://www.analog.com/en/products/adxl372.html
+
+properties:
+  compatible:
+    enum:
+      - adi,adxl372
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+examples:
+  - |
+        #include <dt-bindings/gpio/gpio.h>
+        #include <dt-bindings/interrupt-controller/irq.h>
+        i2c0 {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                /* Example for a I2C device node */
+                accelerometer@53 {
+                        compatible = "adi,adxl372";
+                        reg = <0x53>;
+                        interrupt-parent = <&gpio>;
+                        interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+                };
+        };
+  - |
+        #include <dt-bindings/gpio/gpio.h>
+        #include <dt-bindings/interrupt-controller/irq.h>
+        spi0 {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                accelerometer@0 {
+                        compatible = "adi,adxl372";
+                        reg = <0>;
+                        spi-max-frequency = <1000000>;
+                        interrupt-parent = <&gpio>;
+                        interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+                };
+        };
diff --git a/Documentation/devicetree/bindings/iio/accel/adxl345.txt b/Documentation/devicetree/bindings/iio/accel/adxl345.txt
deleted file mode 100644 (file)
index f9525f6..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-Analog Devices ADXL345/ADXL375 3-Axis Digital Accelerometers
-
-http://www.analog.com/en/products/mems/accelerometers/adxl345.html
-http://www.analog.com/en/products/sensors-mems/accelerometers/adxl375.html
-
-Required properties:
- - compatible : should be one of
-               "adi,adxl345"
-               "adi,adxl375"
- - reg : the I2C address or SPI chip select number of the sensor
-
-Required properties for SPI bus usage:
- - spi-max-frequency : set maximum clock frequency, must be 5000000
- - spi-cpol and spi-cpha : must be defined for adxl345 to enable SPI mode 3
-
-Optional properties:
- - interrupts: interrupt mapping for IRQ as documented in
-   Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
-
-Example for a I2C device node:
-
-       accelerometer@2a {
-               compatible = "adi,adxl345";
-               reg = <0x53>;
-               interrupt-parent = <&gpio1>;
-               interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
-       };
-
-Example for a SPI device node:
-
-       accelerometer@0 {
-               compatible = "adi,adxl345";
-               reg = <0>;
-               spi-max-frequency = <5000000>;
-               spi-cpol;
-               spi-cpha;
-               interrupt-parent = <&gpio1>;
-               interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
-       };
diff --git a/Documentation/devicetree/bindings/iio/accel/adxl372.txt b/Documentation/devicetree/bindings/iio/accel/adxl372.txt
deleted file mode 100644 (file)
index a289964..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-Analog Devices ADXL372 3-Axis, +/-(200g) Digital Accelerometer
-
-http://www.analog.com/media/en/technical-documentation/data-sheets/adxl372.pdf
-
-Required properties:
- - compatible : should be "adi,adxl372"
- - reg: the I2C address or SPI chip select number for the device
-
-Required properties for SPI bus usage:
- - spi-max-frequency: Max SPI frequency to use
-
-Optional properties:
- - interrupts: interrupt mapping for IRQ as documented in
-   Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
-
-Example for a I2C device node:
-
-       accelerometer@53 {
-               compatible = "adi,adxl372";
-               reg = <0x53>;
-               interrupt-parent = <&gpio>;
-               interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
-       };
-
-Example for a SPI device node:
-
-       accelerometer@0 {
-               compatible = "adi,adxl372";
-               reg = <0>;
-               spi-max-frequency = <1000000>;
-               interrupt-parent = <&gpio>;
-               interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
-       };
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7124.txt b/Documentation/devicetree/bindings/iio/adc/adi,ad7124.txt
deleted file mode 100644 (file)
index 416273d..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-Analog Devices AD7124 ADC device driver
-
-Required properties for the AD7124:
-       - compatible: Must be one of "adi,ad7124-4" or "adi,ad7124-8"
-       - reg: SPI chip select number for the device
-       - spi-max-frequency: Max SPI frequency to use
-               see: Documentation/devicetree/bindings/spi/spi-bus.txt
-       - clocks: phandle to the master clock (mclk)
-               see: Documentation/devicetree/bindings/clock/clock-bindings.txt
-       - clock-names: Must be "mclk".
-       - interrupts: IRQ line for the ADC
-               see: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
-
-         Required properties:
-               * #address-cells: Must be 1.
-               * #size-cells: Must be 0.
-
-         Subnode(s) represent the external channels which are connected to the ADC.
-         Each subnode represents one channel and has the following properties:
-               Required properties:
-                       * reg: The channel number. It can have up to 4 channels on ad7124-4
-                         and 8 channels on ad7124-8, numbered from 0 to 15.
-                       * diff-channels: see: Documentation/devicetree/bindings/iio/adc/adc.txt
-
-               Optional properties:
-                       * bipolar: see: Documentation/devicetree/bindings/iio/adc/adc.txt
-                       * adi,reference-select: Select the reference source to use when
-                         converting on the the specific channel. Valid values are:
-                         0: REFIN1(+)/REFIN1(−).
-                         1: REFIN2(+)/REFIN2(−).
-                         3: AVDD
-                         If this field is left empty, internal reference is selected.
-
-Optional properties:
-       - refin1-supply: refin1 supply can be used as reference for conversion.
-       - refin2-supply: refin2 supply can be used as reference for conversion.
-       - avdd-supply: avdd supply can be used as reference for conversion.
-
-Example:
-       adc@0 {
-               compatible = "adi,ad7124-4";
-               reg = <0>;
-               spi-max-frequency = <5000000>;
-               interrupts = <25 2>;
-               interrupt-parent = <&gpio>;
-               refin1-supply = <&adc_vref>;
-               clocks = <&ad7124_mclk>;
-               clock-names = "mclk";
-
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               channel@0 {
-                       reg = <0>;
-                       diff-channels = <0 1>;
-                       adi,reference-select = <0>;
-               };
-
-               channel@1 {
-                       reg = <1>;
-                       bipolar;
-                       diff-channels = <2 3>;
-                       adi,reference-select = <0>;
-               };
-
-               channel@2 {
-                       reg = <2>;
-                       diff-channels = <4 5>;
-               };
-
-               channel@3 {
-                       reg = <3>;
-                       diff-channels = <6 7>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml
new file mode 100644 (file)
index 0000000..cf494a0
--- /dev/null
@@ -0,0 +1,155 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2019 Analog Devices Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/bindings/iio/adc/adi,ad7124.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD7124 ADC device driver
+
+maintainers:
+  - Stefan Popa <stefan.popa@analog.com>
+
+description: |
+  Bindings for the Analog Devices AD7124 ADC device. Datasheet can be
+  found here:
+    https://www.analog.com/media/en/technical-documentation/data-sheets/AD7124-8.pdf
+
+properties:
+  compatible:
+    enum:
+      - adi,ad7124-4
+      - adi,ad7124-8
+
+  reg:
+    description: SPI chip select number for the device
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+    description: phandle to the master clock (mclk)
+
+  clock-names:
+    items:
+      - const: mclk
+
+  interrupts:
+    description: IRQ line for the ADC
+    maxItems: 1
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+  refin1-supply:
+    description: refin1 supply can be used as reference for conversion.
+    maxItems: 1
+
+  refin2-supply:
+    description: refin2 supply can be used as reference for conversion.
+    maxItems: 1
+
+  avdd-supply:
+    description: avdd supply can be used as reference for conversion.
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - interrupts
+
+patternProperties:
+  "^channel@([0-9]|1[0-5])$":
+    type: object
+    description: |
+      Represents the external channels which are connected to the ADC.
+      See Documentation/devicetree/bindings/iio/adc/adc.txt.
+
+    properties:
+      reg:
+        description: |
+          The channel number. It can have up to 8 channels on ad7124-4
+          and 16 channels on ad7124-8, numbered from 0 to 15.
+        items:
+         minimum: 0
+         maximum: 15
+
+      adi,reference-select:
+        description: |
+          Select the reference source to use when converting on
+          the specific channel. Valid values are:
+          0: REFIN1(+)/REFIN1(−).
+          1: REFIN2(+)/REFIN2(−).
+          3: AVDD
+          If this field is left empty, internal reference is selected.
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32
+          - enum: [0, 1, 3]
+
+      diff-channels:
+        description: see Documentation/devicetree/bindings/iio/adc/adc.txt
+        items:
+          minimum: 0
+          maximum: 15
+
+      bipolar:
+        description: see Documentation/devicetree/bindings/iio/adc/adc.txt
+        type: boolean
+
+      adi,buffered-positive:
+        description: Enable buffered mode for positive input.
+        type: boolean
+
+      adi,buffered-negative:
+        description: Enable buffered mode for negative input.
+        type: boolean
+
+    required:
+      - reg
+      - diff-channels
+
+examples:
+  - |
+    adc@0 {
+      compatible = "adi,ad7124-4";
+      reg = <0>;
+      spi-max-frequency = <5000000>;
+      interrupts = <25 2>;
+      interrupt-parent = <&gpio>;
+      refin1-supply = <&adc_vref>;
+      clocks = <&ad7124_mclk>;
+      clock-names = "mclk";
+
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      channel@0 {
+        reg = <0>;
+        diff-channels = <0 1>;
+        adi,reference-select = <0>;
+        adi,buffered-positive;
+      };
+
+      channel@1 {
+        reg = <1>;
+        bipolar;
+        diff-channels = <2 3>;
+        adi,reference-select = <0>;
+        adi,buffered-positive;
+        adi,buffered-negative;
+      };
+
+      channel@2 {
+        reg = <2>;
+        diff-channels = <4 5>;
+      };
+
+      channel@3 {
+        reg = <3>;
+        diff-channels = <6 7>;
+      };
+    };
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7780.txt b/Documentation/devicetree/bindings/iio/adc/adi,ad7780.txt
deleted file mode 100644 (file)
index 440e525..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-* Analog Devices AD7170/AD7171/AD7780/AD7781
-
-Data sheets:
-
-- AD7170:
-       * https://www.analog.com/media/en/technical-documentation/data-sheets/AD7170.pdf
-- AD7171:
-       * https://www.analog.com/media/en/technical-documentation/data-sheets/AD7171.pdf
-- AD7780:
-       * https://www.analog.com/media/en/technical-documentation/data-sheets/ad7780.pdf
-- AD7781:
-       * https://www.analog.com/media/en/technical-documentation/data-sheets/AD7781.pdf
-
-Required properties:
-
-- compatible: should be one of
-       * "adi,ad7170"
-       * "adi,ad7171"
-       * "adi,ad7780"
-       * "adi,ad7781"
-- reg: spi chip select number for the device
-- vref-supply: the regulator supply for the ADC reference voltage
-
-Optional properties:
-
-- powerdown-gpios:  must be the device tree identifier of the PDRST pin. If
-                   specified, it will be asserted during driver probe. As the
-                   line is active high, it should be marked GPIO_ACTIVE_HIGH.
-- adi,gain-gpios:   must be the device tree identifier of the GAIN pin. Only for
-                   the ad778x chips. If specified, it will be asserted during
-                   driver probe. As the line is active low, it should be marked
-                   GPIO_ACTIVE_LOW.
-- adi,filter-gpios: must be the device tree identifier of the FILTER pin. Only
-                   for the ad778x chips. If specified, it will be asserted
-                   during driver probe. As the line is active low, it should be
-                   marked GPIO_ACTIVE_LOW.
-
-Example:
-
-adc@0 {
-       compatible =  "adi,ad7780";
-       reg =         <0>;
-       vref-supply = <&vdd_supply>
-
-       powerdown-gpios  = <&gpio 12 GPIO_ACTIVE_HIGH>;
-       adi,gain-gpios   = <&gpio  5 GPIO_ACTIVE_LOW>;
-       adi,filter-gpios = <&gpio 15 GPIO_ACTIVE_LOW>;
-};
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml
new file mode 100644 (file)
index 0000000..d110941
--- /dev/null
@@ -0,0 +1,87 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/adi,ad7780.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD7170/AD7171/AD7780/AD7781 analog to digital converters
+
+maintainers:
+  - Michael Hennerich <michael.hennerich@analog.com>
+
+description: |
+  The ad7780 is a sigma-delta analog to digital converter. This driver provides
+  reading voltage values and status bits from both the ad778x and ad717x series.
+  Its interface also allows writing on the FILTER and GAIN GPIO pins on the
+  ad778x.
+
+  Specifications on the converters can be found at:
+    AD7170:
+      https://www.analog.com/media/en/technical-documentation/data-sheets/AD7170.pdf
+    AD7171:
+      https://www.analog.com/media/en/technical-documentation/data-sheets/AD7171.pdf
+    AD7780:
+      https://www.analog.com/media/en/technical-documentation/data-sheets/ad7780.pdf
+    AD7781:
+      https://www.analog.com/media/en/technical-documentation/data-sheets/AD7781.pdf
+
+properties:
+  compatible:
+    enum:
+      - adi,ad7170
+      - adi,ad7171
+      - adi,ad7780
+      - adi,ad7781
+
+  reg:
+    maxItems: 1
+
+  avdd-supply:
+    description:
+      The regulator supply for the ADC reference voltage.
+    maxItems: 1
+
+  powerdown-gpios:
+    description:
+      Must be the device tree identifier of the PDRST pin. If
+      specified, it will be asserted during driver probe. As the
+      line is active high, it should be marked GPIO_ACTIVE_HIGH.
+    maxItems: 1
+
+  adi,gain-gpios:
+    description:
+      Must be the device tree identifier of the GAIN pin. Only for
+      the ad778x chips. If specified, it will be asserted during
+      driver probe. As the line is active low, it should be marked
+      GPIO_ACTIVE_LOW.
+    maxItems: 1
+
+  adi,filter-gpios:
+    description:
+      Must be the device tree identifier of the FILTER pin. Only
+      for the ad778x chips. If specified, it will be asserted
+      during driver probe. As the line is active low, it should be
+      marked GPIO_ACTIVE_LOW.
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    spi0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        adc@0 {
+            compatible = "adi,ad7780";
+            reg = <0>;
+
+            avdd-supply      = <&vdd_supply>;
+            powerdown-gpios  = <&gpio0 12 GPIO_ACTIVE_HIGH>;
+            adi,gain-gpios   = <&gpio1  5 GPIO_ACTIVE_LOW>;
+            adi,filter-gpios = <&gpio2 15 GPIO_ACTIVE_LOW>;
+        };
+    };
index 0df9bef..78c06e0 100644 (file)
@@ -13,8 +13,10 @@ Required properties:
   - compatible: Should be one of:
     - "mediatek,mt2701-auxadc": For MT2701 family of SoCs
     - "mediatek,mt2712-auxadc": For MT2712 family of SoCs
+    - "mediatek,mt6765-auxadc": For MT6765 family of SoCs
     - "mediatek,mt7622-auxadc": For MT7622 family of SoCs
     - "mediatek,mt8173-auxadc": For MT8173 family of SoCs
+    - "mediatek,mt8183-auxadc", "mediatek,mt8173-auxadc": For MT8183 family of SoCs
   - reg: Address range of the AUXADC unit.
   - clocks: Should contain a clock specifier for each entry in clock-names
   - clock-names: Should contain "main".
index 8346bcb..93a0bd2 100644 (file)
@@ -38,6 +38,7 @@ Required properties:
     It's required on stm32h7.
 - clock-names: Must be "adc" and/or "bus" depending on part used.
 - interrupt-controller: Identifies the controller node as interrupt-parent
+- vdda-supply: Phandle to the vdda input analog voltage.
 - vref-supply: Phandle to the vref input analog reference voltage.
 - #interrupt-cells = <1>;
 - #address-cells = <1>;
diff --git a/Documentation/devicetree/bindings/iio/chemical/sensirion,sps30.txt b/Documentation/devicetree/bindings/iio/chemical/sensirion,sps30.txt
deleted file mode 100644 (file)
index 6eee270..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-* Sensirion SPS30 particulate matter sensor
-
-Required properties:
-- compatible: must be "sensirion,sps30"
-- reg: the I2C address of the sensor
-
-Example:
-
-sps30@69 {
-       compatible = "sensirion,sps30";
-       reg = <0x69>;
-};
diff --git a/Documentation/devicetree/bindings/iio/chemical/sensirion,sps30.yaml b/Documentation/devicetree/bindings/iio/chemical/sensirion,sps30.yaml
new file mode 100644 (file)
index 0000000..50a50a0
--- /dev/null
@@ -0,0 +1,39 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/chemical/sensirion,sps30.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sensirion SPS30 particulate matter sensor
+
+maintainers:
+  - Tomasz Duszynski <tduszyns@gmail.com>
+
+description: |
+  Air pollution sensor capable of measuring mass concentration of dust
+  particles.
+
+properties:
+  compatible:
+    enum:
+      - sensirion,sps30
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      air-pollution-sensor@69 {
+        compatible = "sensirion,sps30";
+        reg = <0x69>;
+      };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml b/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml
new file mode 100644 (file)
index 0000000..7ec3ec9
--- /dev/null
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/frequency/adf4371.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices ADF4371/ADF4372 Wideband Synthesizers
+
+maintainers:
+  - Popa Stefan <stefan.popa@analog.com>
+
+description: |
+  Analog Devices ADF4371/ADF4372 SPI Wideband Synthesizers
+  https://www.analog.com/media/en/technical-documentation/data-sheets/adf4371.pdf
+  https://www.analog.com/media/en/technical-documentation/data-sheets/adf4372.pdf
+
+properties:
+  compatible:
+    enum:
+      - adi,adf4371
+      - adi,adf4372
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    description:
+      Definition of the external clock (see clock/clock-bindings.txt)
+    maxItems: 1
+
+  clock-names:
+    description:
+      Must be "clkin"
+    maxItems: 1
+
+  adi,mute-till-lock-en:
+    type: boolean
+    description:
+      If this property is present, then the supply current to RF8P and RF8N
+      output stage will shut down until the ADF4371/ADF4372 achieves lock as
+      measured by the digital lock detect circuitry.
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+
+examples:
+  - |
+    spi0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        frequency@0 {
+                compatible = "adi,adf4371";
+                reg = <0>;
+                spi-max-frequency = <1000000>;
+                clocks = <&adf4371_clkin>;
+                clock-names = "clkin";
+        };
+    };
+...
diff --git a/Documentation/devicetree/bindings/iio/light/isl29018.txt b/Documentation/devicetree/bindings/iio/light/isl29018.txt
deleted file mode 100644 (file)
index b9bbde3..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-* ISL 29018/29023/29035 I2C ALS, Proximity, and Infrared sensor
-
-Required properties:
-
-  - compatible: Should be one of
-               "isil,isl29018"
-               "isil,isl29023"
-               "isil,isl29035"
-  - reg: the I2C address of the device
-
-Optional properties:
-
-  - interrupts: the sole interrupt generated by the device
-
-  Refer to interrupt-controller/interrupts.txt for generic interrupt client
-  node bindings.
-
-  - vcc-supply: phandle to the regulator that provides power to the sensor.
-
-Example:
-
-isl29018@44 {
-       compatible = "isil,isl29018";
-       reg = <0x44>;
-       interrupt-parent = <&gpio>;
-       interrupts = <TEGRA_GPIO(Z, 2) IRQ_TYPE_LEVEL_HIGH>;
-};
diff --git a/Documentation/devicetree/bindings/iio/light/isl29018.yaml b/Documentation/devicetree/bindings/iio/light/isl29018.yaml
new file mode 100644 (file)
index 0000000..cbb00be
--- /dev/null
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/light/isl29018.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: |
+  Intersil 29018/29023/29035 Ambient Light, Infrared Light, and Proximity Sensor
+
+maintainers:
+  - Brian Masney <masneyb@onstation.org>
+
+description: |
+  Ambient and infrared light sensing with proximity detection over an i2c
+  interface.
+
+  https://www.renesas.com/us/en/www/doc/datasheet/isl29018.pdf
+  https://www.renesas.com/us/en/www/doc/datasheet/isl29023.pdf
+  https://www.renesas.com/us/en/www/doc/datasheet/isl29035.pdf
+
+properties:
+  compatible:
+    enum:
+      - isil,isl29018
+      - isil,isl29023
+      - isil,isl29035
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  vcc-supply:
+    description: Regulator that provides power to the sensor
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        sensor@44 {
+                compatible = "isil,isl29018";
+                reg = <0x44>;
+                interrupts-extended = <&msmgpio 61 IRQ_TYPE_LEVEL_HIGH>;
+        };
+    };
+...
diff --git a/Documentation/devicetree/bindings/iio/light/tsl2583.txt b/Documentation/devicetree/bindings/iio/light/tsl2583.txt
deleted file mode 100644 (file)
index 059dffa..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-* TAOS TSL 2580/2581/2583 ALS sensor
-
-Required properties:
-
-  - compatible: Should be one of
-               "amstaos,tsl2580"
-               "amstaos,tsl2581"
-               "amstaos,tsl2583"
-  - reg: the I2C address of the device
-
-Optional properties:
-
-  - interrupts: the sole interrupt generated by the device
-
-  Refer to interrupt-controller/interrupts.txt for generic interrupt client
-  node bindings.
-
-  - vcc-supply: phandle to the regulator that provides power to the sensor.
-
-Example:
-
-tsl2581@29 {
-       compatible = "amstaos,tsl2581";
-       reg = <0x29>;
-};
diff --git a/Documentation/devicetree/bindings/iio/light/tsl2583.yaml b/Documentation/devicetree/bindings/iio/light/tsl2583.yaml
new file mode 100644 (file)
index 0000000..e86ef64
--- /dev/null
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/light/tsl2583.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: AMS/TAOS Ambient Light Sensor (ALS)
+
+maintainers:
+  - Brian Masney <masneyb@onstation.org>
+
+description: |
+  Ambient light sensing with an i2c interface.
+
+properties:
+  compatible:
+    enum:
+      - amstaos,tsl2580
+      - amstaos,tsl2581
+      - amstaos,tsl2583
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  vcc-supply:
+    description: Regulator that provides power to the sensor
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        light-sensor@29 {
+                compatible = "amstaos,tsl2581";
+                reg = <0x29>;
+        };
+    };
+...
diff --git a/Documentation/devicetree/bindings/iio/light/tsl2772.txt b/Documentation/devicetree/bindings/iio/light/tsl2772.txt
deleted file mode 100644 (file)
index 1c5e6f1..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-* AMS/TAOS ALS and proximity sensor
-
-Required properties:
-
-  - compatible: Should be one of
-               "amstaos,tsl2571"
-               "amstaos,tsl2671"
-               "amstaos,tmd2671"
-               "amstaos,tsl2771"
-               "amstaos,tmd2771"
-               "amstaos,tsl2572"
-               "amstaos,tsl2672"
-               "amstaos,tmd2672"
-               "amstaos,tsl2772"
-               "amstaos,tmd2772"
-               "avago,apds9930"
-  - reg: the I2C address of the device
-
-Optional properties:
-
-  - amstaos,proximity-diodes - proximity diodes to enable. <0>, <1>, or <0 1>
-                               are the only valid values.
-  - led-max-microamp - current for the proximity LED. Must be 100000, 50000,
-                       25000, or 13000.
-  - vdd-supply: phandle to the regulator that provides power to the sensor.
-  - vddio-supply: phandle to the regulator that provides power to the bus.
-  - interrupts: the sole interrupt generated by the device
-
-  Refer to interrupt-controller/interrupts.txt for generic interrupt client
-  node bindings.
-
-Example:
-
-tsl2772@39 {
-       compatible = "amstaos,tsl2772";
-       reg = <0x39>;
-       interrupts-extended = <&msmgpio 61 IRQ_TYPE_EDGE_FALLING>;
-       vdd-supply = <&pm8941_l17>;
-       vddio-supply = <&pm8941_lvs1>;
-       amstaos,proximity-diodes = <0>;
-       led-max-microamp = <100000>;
-};
diff --git a/Documentation/devicetree/bindings/iio/light/tsl2772.yaml b/Documentation/devicetree/bindings/iio/light/tsl2772.yaml
new file mode 100644 (file)
index 0000000..ed2c3d5
--- /dev/null
@@ -0,0 +1,83 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/light/tsl2772.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: AMS/TAOS Ambient Light Sensor (ALS) and Proximity Detector
+
+maintainers:
+  - Brian Masney <masneyb@onstation.org>
+
+description: |
+  Ambient light sensing and proximity detection with an i2c interface.
+  https://ams.com/documents/20143/36005/TSL2772_DS000181_2-00.pdf
+
+properties:
+  compatible:
+    enum:
+      - amstaos,tsl2571
+      - amstaos,tsl2671
+      - amstaos,tmd2671
+      - amstaos,tsl2771
+      - amstaos,tmd2771
+      - amstaos,tsl2572
+      - amstaos,tsl2672
+      - amstaos,tmd2672
+      - amstaos,tsl2772
+      - amstaos,tmd2772
+      - avago,apds9930
+
+  reg:
+    maxItems: 1
+
+  amstaos,proximity-diodes:
+    description: Proximity diodes to enable
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32-array
+      - minItems: 1
+        maxItems: 2
+        items:
+          minimum: 0
+          maximum: 1
+
+  interrupts:
+    maxItems: 1
+
+  led-max-microamp:
+    description: Current for the proximity LED
+    enum:
+      - 13000
+      - 25000
+      - 50000
+      - 100000
+
+  vdd-supply:
+    description: Regulator that provides power to the sensor
+
+  vddio-supply:
+    description: Regulator that provides power to the bus
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        sensor@39 {
+                compatible = "amstaos,tsl2772";
+                reg = <0x39>;
+                interrupts-extended = <&msmgpio 61 IRQ_TYPE_EDGE_FALLING>;
+                vdd-supply = <&pm8941_l17>;
+                vddio-supply = <&pm8941_lvs1>;
+                amstaos,proximity-diodes = <0>;
+                led-max-microamp = <100000>;
+        };
+    };
+...
index 7976074..9963247 100644 (file)
@@ -13,9 +13,20 @@ Optional properties:
   pinctrl binding [1]).
 - vcc-supply: a phandle for the regulator supplying 3.3V power.
 - elan,trackpoint: touchpad can support a trackpoint (boolean)
+- elan,clickpad: touchpad is a clickpad (the entire surface is a button)
+- elan,middle-button: touchpad has a physical middle button
+- elan,x_traces: number of antennas on the x axis
+- elan,y_traces: number of antennas on the y axis
+- some generic touchscreen properties [2]:
+  * touchscreen-size-x
+  * touchscreen-size-y
+  * touchscreen-x-mm
+  * touchscreen-y-mm
+
 
 [0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
 [1]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+[2]: Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt
 
 Example:
        &i2c1 {
index 3538a21..352f5e9 100644 (file)
@@ -36,4 +36,4 @@ Example:
             kcs_chan = <2>;
             status = "disabled";
         };
-    };
\ No newline at end of file
+    };
index 4d61fe0..dc129d9 100644 (file)
@@ -23,16 +23,17 @@ properties:
   reg:
     maxItems: 1
 
-  ti,linear-mapping-mode:
-    description: |
-      Enable linear mapping mode. If disabled, then it will use exponential
-      mapping mode in which the ramp up/down appears to have a more uniform
-      transition to the human eye.
-    type: boolean
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
 
 required:
   - compatible
   - reg
+  - '#address-cells'
+  - '#size-cells'
 
 patternProperties:
   "^led@[01]$":
@@ -48,7 +49,6 @@ patternProperties:
           in this property. The two current sinks can be controlled
           independently with both banks, or bank A can be configured to control
           both sinks with the led-sources property.
-        maxItems: 1
         minimum: 0
         maximum: 1
 
@@ -73,6 +73,13 @@ patternProperties:
         minimum: 0
         maximum: 255
 
+      ti,linear-mapping-mode:
+        description: |
+          Enable linear mapping mode. If disabled, then it will use exponential
+          mapping mode in which the ramp up/down appears to have a more uniform
+          transition to the human eye.
+        type: boolean
+
     required:
       - reg
 
index f936b55..59b8dcc 100644 (file)
@@ -5,6 +5,7 @@ controller in Ingenic JZ4780
 
 Required properties:
 - compatible: Should be set to one of:
+    "ingenic,jz4740-nemc" (JZ4740)
     "ingenic,jz4780-nemc" (JZ4780)
 - reg: Should specify the NEMC controller registers location and length.
 - clocks: Clock for the NEMC controller.
diff --git a/Documentation/devicetree/bindings/misc/xlnx,sd-fec.txt b/Documentation/devicetree/bindings/misc/xlnx,sd-fec.txt
new file mode 100644 (file)
index 0000000..e328963
--- /dev/null
@@ -0,0 +1,58 @@
+* Xilinx SDFEC(16nm) IP *
+
+The Soft Decision Forward Error Correction (SDFEC) Engine is a Hard IP block
+which provides high-throughput LDPC and Turbo Code implementations.
+The LDPC decode & encode functionality is capable of covering a range of
+customer specified Quasi-cyclic (QC) codes. The Turbo decode functionality
+principally covers codes used by LTE. The FEC Engine offers significant
+power and area savings versus implementations done in the FPGA fabric.
+
+
+Required properties:
+- compatible: Must be "xlnx,sd-fec-1.1"
+- clock-names : List of input clock names from the following:
+    - "core_clk", Main processing clock for processing core (required)
+    - "s_axi_aclk", AXI4-Lite memory-mapped slave interface clock (required)
+    - "s_axis_din_aclk", DIN AXI4-Stream Slave interface clock (optional)
+    - "s_axis_din_words-aclk", DIN_WORDS AXI4-Stream Slave interface clock (optional)
+    - "s_axis_ctrl_aclk",  Control input AXI4-Stream Slave interface clock (optional)
+    - "m_axis_dout_aclk", DOUT AXI4-Stream Master interface clock (optional)
+    - "m_axis_dout_words_aclk", DOUT_WORDS AXI4-Stream Master interface clock (optional)
+    - "m_axis_status_aclk", Status output AXI4-Stream Master interface clock (optional)
+- clocks : Clock phandles (see clock_bindings.txt for details).
+- reg: Should contain Xilinx SDFEC 16nm Hardened IP block registers
+  location and length.
+- xlnx,sdfec-code : Should contain "ldpc" or "turbo" to describe the codes
+  being used.
+- xlnx,sdfec-din-words : A value 0 indicates that the DIN_WORDS interface is
+  driven with a fixed value and is not present on the device, a value of 1
+  configures the DIN_WORDS to be block based, while a value of 2 configures the
+  DIN_WORDS input to be supplied for each AXI transaction.
+- xlnx,sdfec-din-width : Configures the DIN AXI stream where a value of 1
+  configures a width of "1x128b", 2 a width of "2x128b" and 4 configures a width
+  of "4x128b".
+- xlnx,sdfec-dout-words : A value 0 indicates that the DOUT_WORDS interface is
+  driven with a fixed value and is not present on the device, a value of 1
+  configures the DOUT_WORDS to be block based, while a value of 2 configures the
+  DOUT_WORDS input to be supplied for each AXI transaction.
+- xlnx,sdfec-dout-width : Configures the DOUT AXI stream where a value of 1
+  configures a width of "1x128b", 2 a width of "2x128b" and 4 configures a width
+  of "4x128b".
+Optional properties:
+- interrupts: should contain SDFEC interrupt number
+
+Example
+---------------------------------------
+       sd_fec_0: sd-fec@a0040000 {
+               compatible = "xlnx,sd-fec-1.1";
+               clock-names = "core_clk","s_axi_aclk","s_axis_ctrl_aclk","s_axis_din_aclk","m_axis_status_aclk","m_axis_dout_aclk";
+               clocks = <&misc_clk_2>,<&misc_clk_0>,<&misc_clk_1>,<&misc_clk_1>,<&misc_clk_1>, <&misc_clk_1>;
+               reg = <0x0 0xa0040000 0x0 0x40000>;
+               interrupt-parent = <&axi_intc>;
+               interrupts = <1 0>;
+               xlnx,sdfec-code = "ldpc";
+               xlnx,sdfec-din-words = <0>;
+               xlnx,sdfec-din-width = <2>;
+               xlnx,sdfec-dout-words = <0>;
+               xlnx,sdfec-dout-width = <1>;
+       };
diff --git a/Documentation/devicetree/bindings/mmc/allwinner,sun4i-a10-mmc.yaml b/Documentation/devicetree/bindings/mmc/allwinner,sun4i-a10-mmc.yaml
new file mode 100644 (file)
index 0000000..df0280e
--- /dev/null
@@ -0,0 +1,98 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mmc/allwinner,sun4i-a10-mmc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A10 MMC Controller Device Tree Bindings
+
+allOf:
+  - $ref: "mmc-controller.yaml"
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+properties:
+  "#address-cells": true
+  "#size-cells": true
+
+  compatible:
+    oneOf:
+      - const: allwinner,sun4i-a10-mmc
+      - const: allwinner,sun5i-a13-mmc
+      - const: allwinner,sun7i-a20-mmc
+      - const: allwinner,sun8i-a83t-emmc
+      - const: allwinner,sun9i-a80-mmc
+      - const: allwinner,sun50i-a64-emmc
+      - const: allwinner,sun50i-a64-mmc
+      - items:
+          - const: allwinner,sun8i-a83t-mmc
+          - const: allwinner,sun7i-a20-mmc
+      - items:
+          - const: allwinner,sun50i-h6-emmc
+          - const: allwinner,sun50i-a64-emmc
+      - items:
+          - const: allwinner,sun50i-h6-mmc
+          - const: allwinner,sun50i-a64-mmc
+      - items:
+          - const: allwinner,sun8i-r40-emmc
+          - const: allwinner,sun50i-a64-emmc
+      - items:
+          - const: allwinner,sun8i-r40-mmc
+          - const: allwinner,sun50i-a64-mmc
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    minItems: 2
+    maxItems: 4
+    items:
+      - description: Bus Clock
+      - description: Module Clock
+      - description: Output Clock
+      - description: Sample Clock
+
+  clock-names:
+    minItems: 2
+    maxItems: 4
+    items:
+      - const: ahb
+      - const: mmc
+      - const: output
+      - const: sample
+
+  resets:
+    maxItems: 1
+
+  reset-names:
+    const: ahb
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+examples:
+  - |
+    mmc0: mmc@1c0f000 {
+        compatible = "allwinner,sun5i-a13-mmc";
+        reg = <0x01c0f000 0x1000>;
+        clocks = <&ahb_gates 8>, <&mmc0_clk>;
+        clock-names = "ahb", "mmc";
+        interrupts = <32>;
+        bus-width = <4>;
+        cd-gpios = <&pio 7 1 0>;
+    };
+
+# FIXME: We should set it, but it would report all the generic
+# properties as additional properties.
+# additionalProperties: false
+
+...
index 13e7040..ccc5358 100644 (file)
@@ -22,6 +22,10 @@ Required properties:
   clock rate requested by the MMC core.
 - resets     : phandle of the internal reset line
 
+Optional properties:
+- amlogic,dram-access-quirk: set when controller's internal DMA engine cannot access the
+  DRAM memory, like on the G12A dedicated SDIO controller.
+
 Example:
 
        sd_emmc_a: mmc@70000 {
diff --git a/Documentation/devicetree/bindings/mmc/mmc-controller.yaml b/Documentation/devicetree/bindings/mmc/mmc-controller.yaml
new file mode 100644 (file)
index 0000000..080754e
--- /dev/null
@@ -0,0 +1,374 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mmc/mmc-controller.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MMC Controller Generic Binding
+
+maintainers:
+  - Ulf Hansson <ulf.hansson@linaro.org>
+
+description: |
+  These properties are common to multiple MMC host controllers. Any host
+  that requires the respective functionality should implement them using
+  these definitions.
+
+properties:
+  $nodename:
+    pattern: "^mmc(@.*)?$"
+
+  "#address-cells":
+    const: 1
+    description: |
+      The cell is the slot ID if a function subnode is used.
+
+  "#size-cells":
+    const: 0
+
+  # Card Detection.
+  # If none of these properties are supplied, the host native card
+  # detect will be used. Only one of them should be provided.
+
+  broken-cd:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      There is no card detection available; polling must be used.
+
+  cd-gpios:
+    description:
+      The card detection will be done using the GPIO provided.
+
+  non-removable:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      Non-removable slot (like eMMC); assume always present.
+
+  # *NOTE* on CD and WP polarity. To use common for all SD/MMC host
+  # controllers line polarity properties, we have to fix the meaning
+  # of the "normal" and "inverted" line levels. We choose to follow
+  # the SDHCI standard, which specifies both those lines as "active
+  # low." Therefore, using the "cd-inverted" property means, that the
+  # CD line is active high, i.e. it is high, when a card is
+  # inserted. Similar logic applies to the "wp-inverted" property.
+  #
+  # CD and WP lines can be implemented on the hardware in one of two
+  # ways: as GPIOs, specified in cd-gpios and wp-gpios properties, or
+  # as dedicated pins. Polarity of dedicated pins can be specified,
+  # using *-inverted properties. GPIO polarity can also be specified
+  # using the GPIO_ACTIVE_LOW flag. This creates an ambiguity in the
+  # latter case. We choose to use the XOR logic for GPIO CD and WP
+  # lines.  This means, the two properties are "superimposed," for
+  # example leaving the GPIO_ACTIVE_LOW flag clear and specifying the
+  # respective *-inverted property property results in a
+  # double-inversion and actually means the "normal" line polarity is
+  # in effect.
+  wp-inverted:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      The Write Protect line polarity is inverted.
+
+  cd-inverted:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      The CD line polarity is inverted.
+
+  # Other properties
+
+  bus-width:
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - enum: [1, 4, 8]
+        default: 1
+    description:
+      Number of data lines.
+
+  max-frequency:
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - minimum: 400000
+      - maximum: 200000000
+    description:
+      Maximum operating frequency of the bus.
+
+  disable-wp:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      When set, no physical write-protect line is present. This
+      property should only be specified when the controller has a
+      dedicated write-protect detection logic. If a GPIO is always
+      used for the write-protect detection. If a GPIO is always used
+      for the write-protect detection logic, it is sufficient to not
+      specify the wp-gpios property in the absence of a write-protect
+      line.
+
+  wp-gpios:
+    description:
+      GPIO to use for the write-protect detection.
+
+  cd-debounce-delay-ms:
+    description:
+      Set delay time before detecting card after card insert
+      interrupt.
+
+  no-1-8-v:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      When specified, denotes that 1.8V card voltage is not supported
+      on this system, even if the controller claims it.
+
+  cap-sd-highspeed:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      SD high-speed timing is supported.
+
+  cap-mmc-highspeed:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      MMC high-speed timing is supported.
+
+  sd-uhs-sdr12:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      SD UHS SDR12 speed is supported.
+
+  sd-uhs-sdr25:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      SD UHS SDR25 speed is supported.
+
+  sd-uhs-sdr50:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      SD UHS SDR50 speed is supported.
+
+  sd-uhs-sdr104:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      SD UHS SDR104 speed is supported.
+
+  sd-uhs-ddr50:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      SD UHS DDR50 speed is supported.
+
+  cap-power-off-card:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      Powering off the card is safe.
+
+  cap-mmc-hw-reset:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      eMMC hardware reset is supported
+
+  cap-sdio-irq:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      enable SDIO IRQ signalling on this interface
+
+  full-pwr-cycle:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      Full power cycle of the card is supported.
+
+  mmc-ddr-1_2v:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      eMMC high-speed DDR mode (1.2V I/O) is supported.
+
+  mmc-ddr-1_8v:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      eMMC high-speed DDR mode (1.8V I/O) is supported.
+
+  mmc-ddr-3_3v:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      eMMC high-speed DDR mode (3.3V I/O) is supported.
+
+  mmc-hs200-1_2v:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      eMMC HS200 mode (1.2V I/O) is supported.
+
+  mmc-hs200-1_8v:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      eMMC HS200 mode (1.8V I/O) is supported.
+
+  mmc-hs400-1_2v:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      eMMC HS400 mode (1.2V I/O) is supported.
+
+  mmc-hs400-1_8v:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      eMMC HS400 mode (1.8V I/O) is supported.
+
+  mmc-hs400-enhanced-strobe:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      eMMC HS400 enhanced strobe mode is supported
+
+  dsr:
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - minimum: 0
+      - maximum: 0xffff
+    description:
+      Value the card Driver Stage Register (DSR) should be programmed
+      with.
+
+  no-sdio:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      Controller is limited to send SDIO commands during
+      initialization.
+
+  no-sd:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      Controller is limited to send SD commands during initialization.
+
+  no-mmc:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      Controller is limited to send MMC commands during
+      initialization.
+
+  fixed-emmc-driver-type:
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - minimum: 0
+      - maximum: 4
+    description:
+      For non-removable eMMC, enforce this driver type. The value is
+      the driver type as specified in the eMMC specification (table
+      206 in spec version 5.1)
+
+  post-power-on-delay-ms:
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - default: 10
+    description:
+      It was invented for MMC pwrseq-simple which could be referred to
+      mmc-pwrseq-simple.txt. But now it\'s reused as a tunable delay
+      waiting for I/O signalling and card power supply to be stable,
+      regardless of whether pwrseq-simple is used. Default to 10ms if
+      no available.
+
+  supports-cqe:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      The presence of this property indicates that the corresponding
+      MMC host controller supports HW command queue feature.
+
+  disable-cqe-dcmd:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      The presence of this property indicates that the MMC
+      controller\'s command queue engine (CQE) does not support direct
+      commands (DCMDs).
+
+  keep-power-in-suspend:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      SDIO only. Preserves card power during a suspend/resume cycle.
+
+  # Deprecated: enable-sdio-wakeup
+  wakeup-source:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      SDIO only. Enables wake up of host system on SDIO IRQ assertion.
+
+  vmmc-supply:
+    description:
+      Supply for the card power
+
+  vqmmc-supply:
+    description:
+      Supply for the bus IO line power
+
+  mmc-pwrseq:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      System-on-Chip designs may specify a specific MMC power
+      sequence. To successfully detect an (e)MMC/SD/SDIO card, that
+      power sequence must be maintained while initializing the card.
+
+patternProperties:
+  "^.*@[0-9]+$":
+    type: object
+    description: |
+      On embedded systems the cards connected to a host may need
+      additional properties. These can be specified in subnodes to the
+      host controller node. The subnodes are identified by the
+      standard \'reg\' property. Which information exactly can be
+      specified depends on the bindings for the SDIO function driver
+      for the subnode, as specified by the compatible string.
+
+    properties:
+      compatible:
+        description: |
+          Name of SDIO function following generic names recommended
+          practice
+
+      reg:
+        items:
+          - minimum: 0
+            maximum: 7
+            description:
+              Must contain the SDIO function number of the function this
+              subnode describes. A value of 0 denotes the memory SD
+              function, values from 1 to 7 denote the SDIO functions.
+
+      broken-hpi:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          Use this to indicate that the mmc-card has a broken hpi
+          implementation, and that hpi should not be used.
+
+    required:
+      - reg
+
+dependencies:
+  cd-debounce-delay-ms: [ cd-gpios ]
+  fixed-emmc-driver-type: [ non-removable ]
+
+examples:
+  - |
+    sdhci@ab000000 {
+        compatible = "sdhci";
+        reg = <0xab000000 0x200>;
+        interrupts = <23>;
+        bus-width = <4>;
+        cd-gpios = <&gpio 69 0>;
+        cd-inverted;
+        wp-gpios = <&gpio 70 0>;
+        max-frequency = <50000000>;
+        keep-power-in-suspend;
+        wakeup-source;
+        mmc-pwrseq = <&sdhci0_pwrseq>;
+    };
+
+  - |
+    mmc3: mmc@1c12000 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        pinctrl-names = "default";
+        pinctrl-0 = <&mmc3_pins_a>;
+        vmmc-supply = <&reg_vmmc3>;
+        bus-width = <4>;
+        non-removable;
+        mmc-pwrseq = <&sdhci0_pwrseq>;
+
+        brcmf: bcrmf@1 {
+            reg = <1>;
+            compatible = "brcm,bcm43xx-fmac";
+            interrupt-parent = <&pio>;
+            interrupts = <10 8>;
+            interrupt-names = "host-wake";
+        };
+    };
index c269dbe..bf9d7d3 100644 (file)
@@ -1,177 +1 @@
-These properties are common to multiple MMC host controllers. Any host
-that requires the respective functionality should implement them using
-these definitions.
-
-Interpreted by the OF core:
-- reg: Registers location and length.
-- interrupts: Interrupts used by the MMC controller.
-
-Card detection:
-If no property below is supplied, host native card detect is used.
-Only one of the properties in this section should be supplied:
-  - broken-cd: There is no card detection available; polling must be used.
-  - cd-gpios: Specify GPIOs for card detection, see gpio binding
-  - non-removable: non-removable slot (like eMMC); assume always present.
-
-Optional properties:
-- bus-width: Number of data lines, can be <1>, <4>, or <8>.  The default
-  will be <1> if the property is absent.
-- wp-gpios: Specify GPIOs for write protection, see gpio binding
-- cd-inverted: when present, polarity on the CD line is inverted. See the note
-  below for the case, when a GPIO is used for the CD line
-- cd-debounce-delay-ms: Set delay time before detecting card after card insert interrupt.
-  It's only valid when cd-gpios is present.
-- wp-inverted: when present, polarity on the WP line is inverted. See the note
-  below for the case, when a GPIO is used for the WP line
-- disable-wp: When set no physical WP line is present. This property should
-  only be specified when the controller has a dedicated write-protect
-  detection logic. If a GPIO is always used for the write-protect detection
-  logic it is sufficient to not specify wp-gpios property in the absence of a WP
-  line.
-- max-frequency: maximum operating clock frequency
-- no-1-8-v: when present, denotes that 1.8v card voltage is not supported on
-  this system, even if the controller claims it is.
-- cap-sd-highspeed: SD high-speed timing is supported
-- cap-mmc-highspeed: MMC high-speed timing is supported
-- sd-uhs-sdr12: SD UHS SDR12 speed is supported
-- sd-uhs-sdr25: SD UHS SDR25 speed is supported
-- sd-uhs-sdr50: SD UHS SDR50 speed is supported
-- sd-uhs-sdr104: SD UHS SDR104 speed is supported
-- sd-uhs-ddr50: SD UHS DDR50 speed is supported
-- cap-power-off-card: powering off the card is safe
-- cap-mmc-hw-reset: eMMC hardware reset is supported
-- cap-sdio-irq: enable SDIO IRQ signalling on this interface
-- full-pwr-cycle: full power cycle of the card is supported
-- mmc-ddr-3_3v: eMMC high-speed DDR mode(3.3V I/O) is supported
-- mmc-ddr-1_8v: eMMC high-speed DDR mode(1.8V I/O) is supported
-- mmc-ddr-1_2v: eMMC high-speed DDR mode(1.2V I/O) is supported
-- mmc-hs200-1_8v: eMMC HS200 mode(1.8V I/O) is supported
-- mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
-- mmc-hs400-1_8v: eMMC HS400 mode(1.8V I/O) is supported
-- mmc-hs400-1_2v: eMMC HS400 mode(1.2V I/O) is supported
-- mmc-hs400-enhanced-strobe: eMMC HS400 enhanced strobe mode is supported
-- dsr: Value the card's (optional) Driver Stage Register (DSR) should be
-  programmed with. Valid range: [0 .. 0xffff].
-- no-sdio: controller is limited to send sdio cmd during initialization
-- no-sd: controller is limited to send sd cmd during initialization
-- no-mmc: controller is limited to send mmc cmd during initialization
-- fixed-emmc-driver-type: for non-removable eMMC, enforce this driver type.
-  The value <n> is the driver type as specified in the eMMC specification
-  (table 206 in spec version 5.1).
-- post-power-on-delay-ms : It was invented for MMC pwrseq-simple which could
-  be referred to mmc-pwrseq-simple.txt. But now it's reused as a tunable delay
-  waiting for I/O signalling and card power supply to be stable, regardless of
-  whether pwrseq-simple is used. Default to 10ms if no available.
-- supports-cqe : The presence of this property indicates that the corresponding
-  MMC host controller supports HW command queue feature.
-- disable-cqe-dcmd: This property indicates that the MMC controller's command
-  queue engine (CQE) does not support direct commands (DCMDs).
-
-*NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
-polarity properties, we have to fix the meaning of the "normal" and "inverted"
-line levels. We choose to follow the SDHCI standard, which specifies both those
-lines as "active low." Therefore, using the "cd-inverted" property means, that
-the CD line is active high, i.e. it is high, when a card is inserted. Similar
-logic applies to the "wp-inverted" property.
-
-CD and WP lines can be implemented on the hardware in one of two ways: as GPIOs,
-specified in cd-gpios and wp-gpios properties, or as dedicated pins. Polarity of
-dedicated pins can be specified, using *-inverted properties. GPIO polarity can
-also be specified using the GPIO_ACTIVE_LOW flag. This creates an ambiguity
-in the latter case. We choose to use the XOR logic for GPIO CD and WP lines.
-This means, the two properties are "superimposed," for example leaving the
-GPIO_ACTIVE_LOW flag clear and specifying the respective *-inverted property
-property results in a double-inversion and actually means the "normal" line
-polarity is in effect.
-
-Optional SDIO properties:
-- keep-power-in-suspend: Preserves card power during a suspend/resume cycle
-- wakeup-source: Enables wake up of host system on SDIO IRQ assertion
-                (Legacy property supported: "enable-sdio-wakeup")
-
-MMC power
----------
-
-Controllers may implement power control from both the connected cards and
-the IO signaling (for example to change to high-speed 1.8V signalling). If
-the system supports this, then the following two properties should point
-to valid regulator nodes:
-
-- vqmmc-supply: supply node for IO line power
-- vmmc-supply: supply node for card's power
-
-
-MMC power sequences:
---------------------
-
-System on chip designs may specify a specific MMC power sequence. To
-successfully detect an (e)MMC/SD/SDIO card, that power sequence must be
-maintained while initializing the card.
-
-Optional property:
-- mmc-pwrseq: phandle to the MMC power sequence node. See "mmc-pwrseq-*"
-       for documentation of MMC power sequence bindings.
-
-
-Use of Function subnodes
-------------------------
-
-On embedded systems the cards connected to a host may need additional
-properties. These can be specified in subnodes to the host controller node.
-The subnodes are identified by the standard 'reg' property.
-Which information exactly can be specified depends on the bindings for the
-SDIO function driver for the subnode, as specified by the compatible string.
-
-Required host node properties when using function subnodes:
-- #address-cells: should be one. The cell is the slot id.
-- #size-cells: should be zero.
-
-Required function subnode properties:
-- reg: Must contain the SDIO function number of the function this subnode
-       describes. A value of 0 denotes the memory SD function, values from
-       1 to 7 denote the SDIO functions.
-
-Optional function subnode properties:
-- compatible: name of SDIO function following generic names recommended practice
-
-
-Examples
---------
-
-Basic example:
-
-sdhci@ab000000 {
-       compatible = "sdhci";
-       reg = <0xab000000 0x200>;
-       interrupts = <23>;
-       bus-width = <4>;
-       cd-gpios = <&gpio 69 0>;
-       cd-inverted;
-       wp-gpios = <&gpio 70 0>;
-       max-frequency = <50000000>;
-       keep-power-in-suspend;
-       wakeup-source;
-       mmc-pwrseq = <&sdhci0_pwrseq>
-}
-
-Example with sdio function subnode:
-
-mmc3: mmc@1c12000 {
-       #address-cells = <1>;
-       #size-cells = <0>;
-
-       pinctrl-names = "default";
-       pinctrl-0 = <&mmc3_pins_a>;
-       vmmc-supply = <&reg_vmmc3>;
-       bus-width = <4>;
-       non-removable;
-       mmc-pwrseq = <&sdhci0_pwrseq>
-
-       brcmf: bcrmf@1 {
-               reg = <1>;
-               compatible = "brcm,bcm43xx-fmac";
-               interrupt-parent = <&pio>;
-               interrupts = <10 8>; /* PH10 / EINT10 */
-               interrupt-names = "host-wake";
-       };
-};
+This file has moved to mmc-controller.yaml.
diff --git a/Documentation/devicetree/bindings/mmc/renesas,sdhi.txt b/Documentation/devicetree/bindings/mmc/renesas,sdhi.txt
new file mode 100644 (file)
index 0000000..dd08d03
--- /dev/null
@@ -0,0 +1,111 @@
+* Renesas SDHI SD/MMC controller
+
+Required properties:
+- compatible: should contain one or more of the following:
+               "renesas,sdhi-sh73a0" - SDHI IP on SH73A0 SoC
+               "renesas,sdhi-r7s72100" - SDHI IP on R7S72100 SoC
+               "renesas,sdhi-r7s9210" - SDHI IP on R7S9210 SoC
+               "renesas,sdhi-r8a73a4" - SDHI IP on R8A73A4 SoC
+               "renesas,sdhi-r8a7740" - SDHI IP on R8A7740 SoC
+               "renesas,sdhi-r8a7743" - SDHI IP on R8A7743 SoC
+               "renesas,sdhi-r8a7744" - SDHI IP on R8A7744 SoC
+               "renesas,sdhi-r8a7745" - SDHI IP on R8A7745 SoC
+               "renesas,sdhi-r8a774a1" - SDHI IP on R8A774A1 SoC
+               "renesas,sdhi-r8a774c0" - SDHI IP on R8A774C0 SoC
+               "renesas,sdhi-r8a77470" - SDHI IP on R8A77470 SoC
+               "renesas,sdhi-mmc-r8a77470" - SDHI/MMC IP on R8A77470 SoC
+               "renesas,sdhi-r8a7778" - SDHI IP on R8A7778 SoC
+               "renesas,sdhi-r8a7779" - SDHI IP on R8A7779 SoC
+               "renesas,sdhi-r8a7790" - SDHI IP on R8A7790 SoC
+               "renesas,sdhi-r8a7791" - SDHI IP on R8A7791 SoC
+               "renesas,sdhi-r8a7792" - SDHI IP on R8A7792 SoC
+               "renesas,sdhi-r8a7793" - SDHI IP on R8A7793 SoC
+               "renesas,sdhi-r8a7794" - SDHI IP on R8A7794 SoC
+               "renesas,sdhi-r8a7795" - SDHI IP on R8A7795 SoC
+               "renesas,sdhi-r8a7796" - SDHI IP on R8A7796 SoC
+               "renesas,sdhi-r8a77965" - SDHI IP on R8A77965 SoC
+               "renesas,sdhi-r8a77970" - SDHI IP on R8A77970 SoC
+               "renesas,sdhi-r8a77980" - SDHI IP on R8A77980 SoC
+               "renesas,sdhi-r8a77990" - SDHI IP on R8A77990 SoC
+               "renesas,sdhi-r8a77995" - SDHI IP on R8A77995 SoC
+               "renesas,sdhi-shmobile" - a generic sh-mobile SDHI controller
+               "renesas,rcar-gen1-sdhi" - a generic R-Car Gen1 SDHI controller
+               "renesas,rcar-gen2-sdhi" - a generic R-Car Gen2 and RZ/G1 SDHI
+                                          (not SDHI/MMC) controller
+               "renesas,rcar-gen3-sdhi" - a generic R-Car Gen3 or RZ/G2
+                                          SDHI controller
+
+
+               When compatible with the generic version, nodes must list
+               the SoC-specific version corresponding to the platform
+               first followed by the generic version.
+
+- clocks: Most controllers only have 1 clock source per channel. However, on
+         some variations of this controller, the internal card detection
+         logic that exists in this controller is sectioned off to be run by a
+         separate second clock source to allow the main core clock to be turned
+         off to save power.
+         If 2 clocks are specified by the hardware, you must name them as
+         "core" and "cd". If the controller only has 1 clock, naming is not
+         required.
+         Devices which have more than 1 clock are listed below:
+         2: R7S72100, R7S9210
+
+Optional properties:
+- pinctrl-names: should be "default", "state_uhs"
+- pinctrl-0: should contain default/high speed pin ctrl
+- pinctrl-1: should contain uhs mode pin ctrl
+
+Example: R8A7790 (R-Car H2) SDHI controller nodes
+
+       sdhi0: sd@ee100000 {
+               compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
+               reg = <0 0xee100000 0 0x328>;
+               interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cpg CPG_MOD 314>;
+               dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
+                      <&dmac1 0xcd>, <&dmac1 0xce>;
+               dma-names = "tx", "rx", "tx", "rx";
+               max-frequency = <195000000>;
+               power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+               resets = <&cpg 314>;
+       };
+
+       sdhi1: sd@ee120000 {
+               compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
+               reg = <0 0xee120000 0 0x328>;
+               interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cpg CPG_MOD 313>;
+               dmas = <&dmac0 0xc9>, <&dmac0 0xca>,
+                      <&dmac1 0xc9>, <&dmac1 0xca>;
+               dma-names = "tx", "rx", "tx", "rx";
+               max-frequency = <195000000>;
+               power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+               resets = <&cpg 313>;
+       };
+
+       sdhi2: sd@ee140000 {
+               compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
+               reg = <0 0xee140000 0 0x100>;
+               interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cpg CPG_MOD 312>;
+               dmas = <&dmac0 0xc1>, <&dmac0 0xc2>,
+                      <&dmac1 0xc1>, <&dmac1 0xc2>;
+               dma-names = "tx", "rx", "tx", "rx";
+               max-frequency = <97500000>;
+               power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+               resets = <&cpg 312>;
+       };
+
+       sdhi3: sd@ee160000 {
+               compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
+               reg = <0 0xee160000 0 0x100>;
+               interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cpg CPG_MOD 311>;
+               dmas = <&dmac0 0xd3>, <&dmac0 0xd4>,
+                      <&dmac1 0xd3>, <&dmac1 0xd4>;
+               dma-names = "tx", "rx", "tx", "rx";
+               max-frequency = <97500000>;
+               power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+               resets = <&cpg 311>;
+       };
index 15dbbba..50e87df 100644 (file)
@@ -8,7 +8,10 @@ Only deviations are documented here.
   [3] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
 
 Required Properties:
-       - compatible: should be "ti,am654-sdhci-5.1"
+       - compatible: should be one of:
+                       "ti,am654-sdhci-5.1": SDHCI on AM654 device.
+                       "ti,j721e-sdhci-8bit": 8 bit SDHCI on J721E device.
+                       "ti,j721e-sdhci-4bit": 4 bit SDHCI on J721E device.
        - reg: Must be two entries.
                - The first should be the sdhci register space
                - The second should the subsystem/phy register space
@@ -16,9 +19,13 @@ Required Properties:
        - clock-names: Tuple including "clk_xin" and "clk_ahb"
        - interrupts: Interrupt specifiers
        - ti,otap-del-sel: Output Tap Delay select
+
+Optional Properties (Required for ti,am654-sdhci-5.1 and ti,j721e-sdhci-8bit):
        - ti,trm-icp: DLL trim select
        - ti,driver-strength-ohm: driver strength in ohms.
                                  Valid values are 33, 40, 50, 66 and 100 ohms.
+Optional Properties:
+       - ti,strobe-sel: strobe select delay for HS400 speed mode. Default value: 0x0.
 
 Example:
 
index 45c9978..eb7eb1b 100644 (file)
@@ -14,10 +14,31 @@ Required properties:
 - clock-names: Should contain the following:
        "sdio" - SDIO source clock (required)
        "enable" - gate clock which used for enabling/disabling the device (required)
+       "2x_enable" - gate clock controlling the device for some special platforms (optional)
 
 Optional properties:
 - assigned-clocks: the same with "sdio" clock
 - assigned-clock-parents: the default parent of "sdio" clock
+- pinctrl-names: should be "default", "state_uhs"
+- pinctrl-0: should contain default/high speed pin control
+- pinctrl-1: should contain uhs mode pin control
+
+PHY DLL delays are used to delay the data valid window, and align the window
+to sampling clock. PHY DLL delays can be configured by following properties,
+and each property contains 4 cells which are used to configure the clock data
+write line delay value, clock read command line delay value, clock read data
+positive edge delay value and clock read data negative edge delay value.
+Each cell's delay value unit is cycle of the PHY clock.
+
+- sprd,phy-delay-legacy: Delay value for legacy timing.
+- sprd,phy-delay-sd-highspeed: Delay value for SD high-speed timing.
+- sprd,phy-delay-sd-uhs-sdr50: Delay value for SD UHS SDR50 timing.
+- sprd,phy-delay-sd-uhs-sdr104: Delay value for SD UHS SDR50 timing.
+- sprd,phy-delay-mmc-highspeed: Delay value for MMC high-speed timing.
+- sprd,phy-delay-mmc-ddr52: Delay value for MMC DDR52 timing.
+- sprd,phy-delay-mmc-hs200: Delay value for MMC HS200 timing.
+- sprd,phy-delay-mmc-hs400: Delay value for MMC HS400 timing.
+- sprd,phy-delay-mmc-hs400es: Delay value for MMC HS400 enhanced strobe timing.
 
 Examples:
 
@@ -32,6 +53,11 @@ sdio0: sdio@20600000 {
        assigned-clocks = <&ap_clk CLK_EMMC_2X>;
        assigned-clock-parents = <&rpll CLK_RPLL_390M>;
 
+       pinctrl-names = "default", "state_uhs";
+       pinctrl-0 = <&sd0_pins_default>;
+       pinctrl-1 = <&sd0_pins_uhs>;
+
+       sprd,phy-delay-sd-uhs-sdr104 = <0x3f 0x7f 0x2e 0x2e>;
        bus-width = <8>;
        non-removable;
        no-sdio;
diff --git a/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt b/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt
deleted file mode 100644 (file)
index e9cb3ec..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-* Allwinner sunxi MMC controller
-
-The highspeed MMC host controller on Allwinner SoCs provides an interface
-for MMC, SD and SDIO types of memory cards.
-
-Supported maximum speeds are the ones of the eMMC standard 4.5 as well
-as the speed of SD standard 3.0.
-Absolute maximum transfer rate is 200MB/s
-
-Required properties:
- - compatible : should be one of:
-   * "allwinner,sun4i-a10-mmc"
-   * "allwinner,sun5i-a13-mmc"
-   * "allwinner,sun7i-a20-mmc"
-   * "allwinner,sun8i-a83t-emmc"
-   * "allwinner,sun9i-a80-mmc"
-   * "allwinner,sun50i-a64-emmc"
-   * "allwinner,sun50i-a64-mmc"
-   * "allwinner,sun50i-h6-emmc", "allwinner.sun50i-a64-emmc"
-   * "allwinner,sun50i-h6-mmc", "allwinner.sun50i-a64-mmc"
- - reg : mmc controller base registers
- - clocks : a list with 4 phandle + clock specifier pairs
- - clock-names : must contain "ahb", "mmc", "output" and "sample"
- - interrupts : mmc controller interrupt
-
-Optional properties:
- - resets : phandle + reset specifier pair
- - reset-names : must contain "ahb"
- - for cd, bus-width and additional generic mmc parameters
-   please refer to mmc.txt within this directory
-
-Examples:
-       - Within .dtsi:
-       mmc0: mmc@1c0f000 {
-               compatible = "allwinner,sun5i-a13-mmc";
-               reg = <0x01c0f000 0x1000>;
-               clocks = <&ahb_gates 8>, <&mmc0_clk>, <&mmc0_output_clk>, <&mmc0_sample_clk>;
-               clock-names = "ahb", "mod", "output", "sample";
-               interrupts = <0 32 4>;
-               status = "disabled";
-       };
-
-       - Within dts:
-       mmc0: mmc@1c0f000 {
-               pinctrl-names = "default", "default";
-               pinctrl-0 = <&mmc0_pins_a>;
-               pinctrl-1 = <&mmc0_cd_pin_reference_design>;
-               bus-width = <4>;
-               cd-gpios = <&pio 7 1 0>; /* PH1 */
-               cd-inverted;
-               status = "okay";
-       };
diff --git a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
deleted file mode 100644 (file)
index 2b4f17c..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-* Toshiba Mobile IO SD/MMC controller
-
-The tmio-mmc driver doesn't probe its devices actively, instead its binding to
-devices is managed by either MFD drivers or by the sh_mobile_sdhi platform
-driver. Those drivers supply the tmio-mmc driver with platform data, that either
-describe hardware capabilities, known to them, or are obtained by them from
-their own platform data or from their DT information. In the latter case all
-compulsory and any optional properties, common to all SD/MMC drivers, as
-described in mmc.txt, can be used. Additionally the following tmio_mmc-specific
-optional bindings can be used.
-
-Required properties:
-- compatible: should contain one or more of the following:
-               "renesas,sdhi-sh73a0" - SDHI IP on SH73A0 SoC
-               "renesas,sdhi-r7s72100" - SDHI IP on R7S72100 SoC
-               "renesas,sdhi-r7s9210" - SDHI IP on R7S9210 SoC
-               "renesas,sdhi-r8a73a4" - SDHI IP on R8A73A4 SoC
-               "renesas,sdhi-r8a7740" - SDHI IP on R8A7740 SoC
-               "renesas,sdhi-r8a7743" - SDHI IP on R8A7743 SoC
-               "renesas,sdhi-r8a7744" - SDHI IP on R8A7744 SoC
-               "renesas,sdhi-r8a7745" - SDHI IP on R8A7745 SoC
-               "renesas,sdhi-r8a774a1" - SDHI IP on R8A774A1 SoC
-               "renesas,sdhi-r8a774c0" - SDHI IP on R8A774C0 SoC
-               "renesas,sdhi-r8a77470" - SDHI IP on R8A77470 SoC
-               "renesas,sdhi-mmc-r8a77470" - SDHI/MMC IP on R8A77470 SoC
-               "renesas,sdhi-r8a7778" - SDHI IP on R8A7778 SoC
-               "renesas,sdhi-r8a7779" - SDHI IP on R8A7779 SoC
-               "renesas,sdhi-r8a7790" - SDHI IP on R8A7790 SoC
-               "renesas,sdhi-r8a7791" - SDHI IP on R8A7791 SoC
-               "renesas,sdhi-r8a7792" - SDHI IP on R8A7792 SoC
-               "renesas,sdhi-r8a7793" - SDHI IP on R8A7793 SoC
-               "renesas,sdhi-r8a7794" - SDHI IP on R8A7794 SoC
-               "renesas,sdhi-r8a7795" - SDHI IP on R8A7795 SoC
-               "renesas,sdhi-r8a7796" - SDHI IP on R8A7796 SoC
-               "renesas,sdhi-r8a77965" - SDHI IP on R8A77965 SoC
-               "renesas,sdhi-r8a77970" - SDHI IP on R8A77970 SoC
-               "renesas,sdhi-r8a77980" - SDHI IP on R8A77980 SoC
-               "renesas,sdhi-r8a77990" - SDHI IP on R8A77990 SoC
-               "renesas,sdhi-r8a77995" - SDHI IP on R8A77995 SoC
-               "renesas,sdhi-shmobile" - a generic sh-mobile SDHI controller
-               "renesas,rcar-gen1-sdhi" - a generic R-Car Gen1 SDHI controller
-               "renesas,rcar-gen2-sdhi" - a generic R-Car Gen2 and RZ/G1 SDHI
-                                          (not SDHI/MMC) controller
-               "renesas,rcar-gen3-sdhi" - a generic R-Car Gen3 or RZ/G2
-                                          SDHI controller
-
-
-               When compatible with the generic version, nodes must list
-               the SoC-specific version corresponding to the platform
-               first followed by the generic version.
-
-- clocks: Most controllers only have 1 clock source per channel. However, on
-         some variations of this controller, the internal card detection
-         logic that exists in this controller is sectioned off to be run by a
-         separate second clock source to allow the main core clock to be turned
-         off to save power.
-         If 2 clocks are specified by the hardware, you must name them as
-         "core" and "cd". If the controller only has 1 clock, naming is not
-         required.
-         Devices which have more than 1 clock are listed below:
-         2: R7S72100, R7S9210
-
-Optional properties:
-- pinctrl-names: should be "default", "state_uhs"
-- pinctrl-0: should contain default/high speed pin ctrl
-- pinctrl-1: should contain uhs mode pin ctrl
-
-Example: R8A7790 (R-Car H2) SDHI controller nodes
-
-       sdhi0: sd@ee100000 {
-               compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
-               reg = <0 0xee100000 0 0x328>;
-               interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&cpg CPG_MOD 314>;
-               dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
-                      <&dmac1 0xcd>, <&dmac1 0xce>;
-               dma-names = "tx", "rx", "tx", "rx";
-               max-frequency = <195000000>;
-               power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-               resets = <&cpg 314>;
-       };
-
-       sdhi1: sd@ee120000 {
-               compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
-               reg = <0 0xee120000 0 0x328>;
-               interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&cpg CPG_MOD 313>;
-               dmas = <&dmac0 0xc9>, <&dmac0 0xca>,
-                      <&dmac1 0xc9>, <&dmac1 0xca>;
-               dma-names = "tx", "rx", "tx", "rx";
-               max-frequency = <195000000>;
-               power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-               resets = <&cpg 313>;
-       };
-
-       sdhi2: sd@ee140000 {
-               compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
-               reg = <0 0xee140000 0 0x100>;
-               interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&cpg CPG_MOD 312>;
-               dmas = <&dmac0 0xc1>, <&dmac0 0xc2>,
-                      <&dmac1 0xc1>, <&dmac1 0xc2>;
-               dma-names = "tx", "rx", "tx", "rx";
-               max-frequency = <97500000>;
-               power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-               resets = <&cpg 312>;
-       };
-
-       sdhi3: sd@ee160000 {
-               compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
-               reg = <0 0xee160000 0 0x100>;
-               interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&cpg CPG_MOD 311>;
-               dmas = <&dmac0 0xd3>, <&dmac0 0xd4>,
-                      <&dmac1 0xd3>, <&dmac1 0xd4>;
-               dma-names = "tx", "rx", "tx", "rx";
-               max-frequency = <97500000>;
-               power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-               resets = <&cpg 311>;
-       };
index fbd4da3..e5a4115 100644 (file)
@@ -57,7 +57,6 @@ patternProperties:
   "^nand@[a-f0-9]+$":
     properties:
       reg:
-        maxItems: 1
         minimum: 0
         maximum: 7
 
index 0b7c373..82156dc 100644 (file)
@@ -28,6 +28,7 @@ Required properties:
                          brcm,brcmnand-v7.0
                          brcm,brcmnand-v7.1
                          brcm,brcmnand-v7.2
+                         brcm,brcmnand-v7.3
                          brcm,brcmnand
 - reg              : the register start and length for NAND register region.
                      (optional) Flash DMA register range (if present)
@@ -101,10 +102,10 @@ Required properties:
                               number (e.g., 0, 1, 2, etc.)
 - #address-cells            : see partition.txt
 - #size-cells               : see partition.txt
-- nand-ecc-strength         : see nand-controller.yaml
-- nand-ecc-step-size        : must be 512 or 1024. See nand-controller.yaml
 
 Optional properties:
+- nand-ecc-strength         : see nand-controller.yaml
+- nand-ecc-step-size        : must be 512 or 1024. See nand-controller.yaml
 - nand-on-flash-bbt         : boolean, to enable the on-flash BBT for this
                               chip-select. See nand-controller.yaml
 - brcm,nand-oob-sector-size : integer, to denote the spare area sector size
index 4345c3a..945be7d 100644 (file)
@@ -35,6 +35,9 @@ custom properties:
                  (qspi_n_ss_out).
 - cdns,tslch-ns : Delay in nanoseconds between setting qspi_n_ss_out low
                   and first bit transfer.
+- resets       : Must contain an entry for each entry in reset-names.
+                 See ../reset/reset.txt for details.
+- reset-names  : Must include either "qspi" and/or "qspi-ocp".
 
 Example:
 
@@ -50,6 +53,8 @@ Example:
                cdns,fifo-depth = <128>;
                cdns,fifo-width = <4>;
                cdns,trigger-address = <0x00000000>;
+               resets = <&rst QSPI_RESET>, <&rst QSPI_OCP_RESET>;
+               reset-names = "qspi", "qspi-ocp";
 
                flash0: n25q00@0 {
                        ...
diff --git a/Documentation/devicetree/bindings/mtd/cypress,hyperflash.txt b/Documentation/devicetree/bindings/mtd/cypress,hyperflash.txt
new file mode 100644 (file)
index 0000000..ad42f4d
--- /dev/null
@@ -0,0 +1,13 @@
+Bindings for HyperFlash NOR flash chips compliant with Cypress HyperBus
+specification and supports Cypress CFI specification 1.5 command set.
+
+Required properties:
+- compatible : "cypress,hyperflash", "cfi-flash" for HyperFlash NOR chips
+- reg : Address of flash's memory map
+
+Example:
+
+       flash@0 {
+               compatible = "cypress,hyperflash", "cfi-flash";
+               reg = <0x0 0x4000000>;
+       };
diff --git a/Documentation/devicetree/bindings/mtd/stm32-quadspi.txt b/Documentation/devicetree/bindings/mtd/stm32-quadspi.txt
deleted file mode 100644 (file)
index ddd18c1..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-* STMicroelectronics Quad Serial Peripheral Interface(QuadSPI)
-
-Required properties:
-- compatible: should be "st,stm32f469-qspi"
-- reg: the first contains the register location and length.
-       the second contains the memory mapping address and length
-- reg-names: should contain the reg names "qspi" "qspi_mm"
-- interrupts: should contain the interrupt for the device
-- clocks: the phandle of the clock needed by the QSPI controller
-- A pinctrl must be defined to set pins in mode of operation for QSPI transfer
-
-Optional properties:
-- resets: must contain the phandle to the reset controller.
-
-A spi flash must be a child of the nor_flash node and could have some
-properties. Also see jedec,spi-nor.txt.
-
-Required properties:
-- reg: chip-Select number (QSPI controller may connect 2 nor flashes)
-- spi-max-frequency: max frequency of spi bus
-
-Optional property:
-- spi-rx-bus-width: see ../spi/spi-bus.txt for the description
-
-Example:
-
-qspi: spi@a0001000 {
-       compatible = "st,stm32f469-qspi";
-       reg = <0xa0001000 0x1000>, <0x90000000 0x10000000>;
-       reg-names = "qspi", "qspi_mm";
-       interrupts = <91>;
-       resets = <&rcc STM32F4_AHB3_RESET(QSPI)>;
-       clocks = <&rcc 0 STM32F4_AHB3_CLOCK(QSPI)>;
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_qspi0>;
-
-       flash@0 {
-               reg = <0>;
-               spi-rx-bus-width = <4>;
-               spi-max-frequency = <108000000>;
-               ...
-       };
-};
diff --git a/Documentation/devicetree/bindings/mtd/ti,am654-hbmc.txt b/Documentation/devicetree/bindings/mtd/ti,am654-hbmc.txt
new file mode 100644 (file)
index 0000000..faa81c2
--- /dev/null
@@ -0,0 +1,51 @@
+Bindings for HyperBus Memory Controller (HBMC) on TI's K3 family of SoCs
+
+Required properties:
+- compatible : "ti,am654-hbmc" for AM654 SoC
+- reg : Two entries:
+       First entry pointed to the register space of HBMC controller
+       Second entry pointing to the memory map region dedicated for
+       MMIO access to attached flash devices
+- ranges : Address translation from offset within CS to allocated MMIO
+          space in SoC
+
+Optional properties:
+- mux-controls : phandle to the multiplexer that controls selection of
+                HBMC vs OSPI inside Flash SubSystem (FSS). Default is OSPI,
+                if property is absent.
+                See Documentation/devicetree/bindings/mux/reg-mux.txt
+                for mmio-mux binding details
+
+Example:
+
+       system-controller@47000000 {
+               compatible = "syscon", "simple-mfd";
+               reg = <0x0 0x47000000 0x0 0x100>;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               hbmc_mux: multiplexer {
+                       compatible = "mmio-mux";
+                       #mux-control-cells = <1>;
+                       mux-reg-masks = <0x4 0x2>; /* 0: reg 0x4, bit 1 */
+               };
+       };
+
+       hbmc: hyperbus@47034000 {
+               compatible = "ti,am654-hbmc";
+               reg = <0x0 0x47034000 0x0 0x100>,
+                       <0x5 0x00000000 0x1 0x0000000>;
+               power-domains = <&k3_pds 55>;
+               #address-cells = <2>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0 0x5 0x00000000 0x4000000>, /* CS0 - 64MB */
+                        <0x1 0x0 0x5 0x04000000 0x4000000>; /* CS1 - 64MB */
+               mux-controls = <&hbmc_mux 0>;
+
+               /* Slave flash node */
+               flash@0,0 {
+                       compatible = "cypress,hyperflash", "cfi-flash";
+                       reg = <0x0 0x0 0x4000000>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/mux/mmio-mux.txt b/Documentation/devicetree/bindings/mux/mmio-mux.txt
deleted file mode 100644 (file)
index a9bfb4d..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-MMIO register bitfield-based multiplexer controller bindings
-
-Define register bitfields to be used to control multiplexers. The parent
-device tree node must be a syscon node to provide register access.
-
-Required properties:
-- compatible : "mmio-mux"
-- #mux-control-cells : <1>
-- mux-reg-masks : an array of register offset and pre-shifted bitfield mask
-                  pairs, each describing a single mux control.
-* Standard mux-controller bindings as decribed in mux-controller.txt
-
-Optional properties:
-- idle-states : if present, the state the muxes will have when idle. The
-               special state MUX_IDLE_AS_IS is the default.
-
-The multiplexer state of each multiplexer is defined as the value of the
-bitfield described by the corresponding register offset and bitfield mask pair
-in the mux-reg-masks array, accessed through the parent syscon.
-
-Example:
-
-       syscon {
-               compatible = "syscon";
-
-               mux: mux-controller {
-                       compatible = "mmio-mux";
-                       #mux-control-cells = <1>;
-
-                       mux-reg-masks = <0x3 0x30>, /* 0: reg 0x3, bits 5:4 */
-                                       <0x3 0x40>, /* 1: reg 0x3, bit 6 */
-                       idle-states = <MUX_IDLE_AS_IS>, <0>;
-               };
-       };
-
-       video-mux {
-               compatible = "video-mux";
-               mux-controls = <&mux 0>;
-
-               ports {
-                       /* inputs 0..3 */
-                       port@0 {
-                               reg = <0>;
-                       };
-                       port@1 {
-                               reg = <1>;
-                       };
-                       port@2 {
-                               reg = <2>;
-                       };
-                       port@3 {
-                               reg = <3>;
-                       };
-
-                       /* output */
-                       port@4 {
-                               reg = <4>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/mux/reg-mux.txt b/Documentation/devicetree/bindings/mux/reg-mux.txt
new file mode 100644 (file)
index 0000000..4afd7ba
--- /dev/null
@@ -0,0 +1,129 @@
+Generic register bitfield-based multiplexer controller bindings
+
+Define register bitfields to be used to control multiplexers. The parent
+device tree node must be a device node to provide register r/w access.
+
+Required properties:
+- compatible : should be one of
+       "reg-mux" : if parent device of mux controller is not syscon device
+       "mmio-mux" : if parent device of mux controller is syscon device
+- #mux-control-cells : <1>
+- mux-reg-masks : an array of register offset and pre-shifted bitfield mask
+                  pairs, each describing a single mux control.
+* Standard mux-controller bindings as decribed in mux-controller.txt
+
+Optional properties:
+- idle-states : if present, the state the muxes will have when idle. The
+               special state MUX_IDLE_AS_IS is the default.
+
+The multiplexer state of each multiplexer is defined as the value of the
+bitfield described by the corresponding register offset and bitfield mask
+pair in the mux-reg-masks array.
+
+Example 1:
+The parent device of mux controller is not a syscon device.
+
+&i2c0 {
+       fpga@66 { // fpga connected to i2c
+               compatible = "fsl,lx2160aqds-fpga", "fsl,fpga-qixis-i2c",
+                            "simple-mfd";
+               reg = <0x66>;
+
+               mux: mux-controller {
+                       compatible = "reg-mux";
+                       #mux-control-cells = <1>;
+                       mux-reg-masks = <0x54 0xf8>, /* 0: reg 0x54, bits 7:3 */
+                                       <0x54 0x07>; /* 1: reg 0x54, bits 2:0 */
+               };
+       };
+};
+
+mdio-mux-1 {
+       compatible = "mdio-mux-multiplexer";
+       mux-controls = <&mux 0>;
+       mdio-parent-bus = <&emdio1>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       mdio@0 {
+               reg = <0x0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+       mdio@8 {
+               reg = <0x8>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+       ..
+       ..
+};
+
+mdio-mux-2 {
+       compatible = "mdio-mux-multiplexer";
+       mux-controls = <&mux 1>;
+       mdio-parent-bus = <&emdio2>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       mdio@0 {
+               reg = <0x0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+       mdio@1 {
+               reg = <0x1>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+       ..
+       ..
+};
+
+Example 2:
+The parent device of mux controller is syscon device.
+
+syscon {
+       compatible = "syscon";
+
+       mux: mux-controller {
+               compatible = "mmio-mux";
+               #mux-control-cells = <1>;
+
+               mux-reg-masks = <0x3 0x30>, /* 0: reg 0x3, bits 5:4 */
+                               <0x3 0x40>, /* 1: reg 0x3, bit 6 */
+               idle-states = <MUX_IDLE_AS_IS>, <0>;
+       };
+};
+
+video-mux {
+       compatible = "video-mux";
+       mux-controls = <&mux 0>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       ports {
+               /* inputs 0..3 */
+               port@0 {
+                       reg = <0>;
+               };
+               port@1 {
+                       reg = <1>;
+               };
+               port@2 {
+                       reg = <2>;
+               };
+               port@3 {
+                       reg = <3>;
+               };
+
+               /* output */
+               port@4 {
+                       reg = <4>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/net/allwinner,sun4i-a10-emac.yaml b/Documentation/devicetree/bindings/net/allwinner,sun4i-a10-emac.yaml
new file mode 100644 (file)
index 0000000..792196b
--- /dev/null
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/allwinner,sun4i-a10-emac.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A10 EMAC Ethernet Controller Device Tree Bindings
+
+allOf:
+  - $ref: "ethernet-controller.yaml#"
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+properties:
+  compatible:
+    const: allwinner,sun4i-a10-emac
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  allwinner,sram:
+    description: Phandle to the device SRAM
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - phy-handle
+  - allwinner,sram
+
+examples:
+  - |
+    emac: ethernet@1c0b000 {
+        compatible = "allwinner,sun4i-a10-emac";
+        reg = <0x01c0b000 0x1000>;
+        interrupts = <55>;
+        clocks = <&ahb_gates 17>;
+        phy-handle = <&phy0>;
+        allwinner,sram = <&emac_sram 1>;
+    };
+
+# FIXME: We should set it, but it would report all the generic
+# properties as additional properties.
+# additionalProperties: false
+
+...
diff --git a/Documentation/devicetree/bindings/net/allwinner,sun4i-a10-mdio.yaml b/Documentation/devicetree/bindings/net/allwinner,sun4i-a10-mdio.yaml
new file mode 100644 (file)
index 0000000..df24d9d
--- /dev/null
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/allwinner,sun4i-a10-mdio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A10 MDIO Controller Device Tree Bindings
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+allOf:
+  - $ref: "mdio.yaml#"
+
+# Select every compatible, including the deprecated ones. This way, we
+# will be able to report a warning when we have that compatible, since
+# we will validate the node thanks to the select, but won't report it
+# as a valid value in the compatible property description
+select:
+  properties:
+    compatible:
+      enum:
+        - allwinner,sun4i-a10-mdio
+
+        # Deprecated
+        - allwinner,sun4i-mdio
+
+  required:
+    - compatible
+
+properties:
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+  compatible:
+    const: allwinner,sun4i-a10-mdio
+
+  reg:
+    maxItems: 1
+
+  phy-supply:
+    description: PHY regulator
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    mdio@1c0b080 {
+        compatible = "allwinner,sun4i-a10-mdio";
+        reg = <0x01c0b080 0x14>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+        phy-supply = <&reg_emac_3v3>;
+
+        phy0: ethernet-phy@0 {
+            reg = <0>;
+        };
+    };
+
+# FIXME: We should set it, but it would report all the generic
+# properties as additional properties.
+# additionalProperties: false
+
+...
diff --git a/Documentation/devicetree/bindings/net/allwinner,sun4i-emac.txt b/Documentation/devicetree/bindings/net/allwinner,sun4i-emac.txt
deleted file mode 100644 (file)
index e98118a..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-* Allwinner EMAC ethernet controller
-
-Required properties:
-- compatible: should be "allwinner,sun4i-a10-emac" (Deprecated:
-              "allwinner,sun4i-emac")
-- reg: address and length of the register set for the device.
-- interrupts: interrupt for the device
-- phy: see ethernet.txt file in the same directory.
-- clocks: A phandle to the reference clock for this device
-
-Example:
-
-emac: ethernet@1c0b000 {
-       compatible = "allwinner,sun4i-a10-emac";
-       reg = <0x01c0b000 0x1000>;
-       interrupts = <55>;
-       clocks = <&ahb_gates 17>;
-       phy = <&phy0>;
-};
diff --git a/Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt b/Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt
deleted file mode 100644 (file)
index ab5b861..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-* Allwinner A10 MDIO Ethernet Controller interface
-
-Required properties:
-- compatible: should be "allwinner,sun4i-a10-mdio"
-              (Deprecated: "allwinner,sun4i-mdio").
-- reg: address and length of the register set for the device.
-
-Optional properties:
-- phy-supply: phandle to a regulator if the PHY needs one
-
-Example at the SoC level:
-mdio@1c0b080 {
-       compatible = "allwinner,sun4i-a10-mdio";
-       reg = <0x01c0b080 0x14>;
-       #address-cells = <1>;
-       #size-cells = <0>;
-};
-
-And at the board level:
-
-mdio@1c0b080 {
-       phy-supply = <&reg_emac_3v3>;
-
-       phy0: ethernet-phy@0 {
-               reg = <0>;
-       };
-};
diff --git a/Documentation/devicetree/bindings/net/allwinner,sun7i-a20-gmac.txt b/Documentation/devicetree/bindings/net/allwinner,sun7i-a20-gmac.txt
deleted file mode 100644 (file)
index 8b3f953..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-* Allwinner GMAC ethernet controller
-
-This device is a platform glue layer for stmmac.
-Please see stmmac.txt for the other unchanged properties.
-
-Required properties:
- - compatible:  Should be "allwinner,sun7i-a20-gmac"
- - clocks: Should contain the GMAC main clock, and tx clock
-   The tx clock type should be "allwinner,sun7i-a20-gmac-clk"
- - clock-names: Should contain the clock names "stmmaceth",
-   and "allwinner_gmac_tx"
-
-Optional properties:
-- phy-supply: phandle to a regulator if the PHY needs one
-
-Examples:
-
-       gmac: ethernet@1c50000 {
-               compatible = "allwinner,sun7i-a20-gmac";
-               reg = <0x01c50000 0x10000>,
-                     <0x01c20164 0x4>;
-               interrupts = <0 85 1>;
-               interrupt-names = "macirq";
-               clocks = <&ahb_gates 49>, <&gmac_tx>;
-               clock-names = "stmmaceth", "allwinner_gmac_tx";
-               phy-mode = "mii";
-       };
diff --git a/Documentation/devicetree/bindings/net/allwinner,sun7i-a20-gmac.yaml b/Documentation/devicetree/bindings/net/allwinner,sun7i-a20-gmac.yaml
new file mode 100644 (file)
index 0000000..06b1cc8
--- /dev/null
@@ -0,0 +1,65 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/allwinner,sun7i-a20-gmac.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A20 GMAC Device Tree Bindings
+
+allOf:
+  - $ref: "snps,dwmac.yaml#"
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+properties:
+  compatible:
+    const: allwinner,sun7i-a20-gmac
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-names:
+    const: macirq
+
+  clocks:
+    items:
+      - description: GMAC main clock
+      - description: TX clock
+
+  clock-names:
+    items:
+      - const: stmmaceth
+      - const: allwinner_gmac_tx
+
+  phy-supply:
+    description:
+      PHY regulator
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-names
+  - clocks
+  - clock-names
+  - phy-mode
+
+examples:
+  - |
+    gmac: ethernet@1c50000 {
+        compatible = "allwinner,sun7i-a20-gmac";
+        reg = <0x01c50000 0x10000>;
+        interrupts = <0 85 1>;
+        interrupt-names = "macirq";
+        clocks = <&ahb_gates 49>, <&gmac_tx>;
+        clock-names = "stmmaceth", "allwinner_gmac_tx";
+        phy-mode = "mii";
+    };
+
+# FIXME: We should set it, but it would report all the generic
+# properties as additional properties.
+# additionalProperties: false
+
+...
diff --git a/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml b/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml
new file mode 100644 (file)
index 0000000..d4084c1
--- /dev/null
@@ -0,0 +1,321 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/allwinner,sun8i-a83t-gmac.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A83t EMAC Device Tree Bindings
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+properties:
+  compatible:
+    oneOf:
+      - const: allwinner,sun8i-a83t-emac
+      - const: allwinner,sun8i-h3-emac
+      - const: allwinner,sun8i-r40-emac
+      - const: allwinner,sun8i-v3s-emac
+      - const: allwinner,sun50i-a64-emac
+      - items:
+        - const: allwinner,sun50i-h6-emac
+        - const: allwinner,sun50i-a64-emac
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-names:
+    const: macirq
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: stmmaceth
+
+  syscon:
+    $ref: /schemas/types.yaml#definitions/phandle
+    description:
+      Phandle to the device containing the EMAC or GMAC clock
+      register
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-names
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - phy-handle
+  - phy-mode
+  - syscon
+
+allOf:
+  - $ref: "snps,dwmac.yaml#"
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - allwinner,sun8i-a83t-emac
+              - allwinner,sun8i-h3-emac
+              - allwinner,sun8i-v3s-emac
+              - allwinner,sun50i-a64-emac
+
+    then:
+      properties:
+        allwinner,tx-delay-ps:
+          default: 0
+          minimum: 0
+          maximum: 700
+          multipleOf: 100
+          description:
+            External RGMII PHY TX clock delay chain value in ps.
+
+        allwinner,rx-delay-ps:
+          default: 0
+          minimum: 0
+          maximum: 3100
+          multipleOf: 100
+          description:
+            External RGMII PHY TX clock delay chain value in ps.
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - allwinner,sun8i-r40-emac
+
+    then:
+      properties:
+        allwinner,rx-delay-ps:
+          default: 0
+          minimum: 0
+          maximum: 700
+          multipleOf: 100
+          description:
+            External RGMII PHY TX clock delay chain value in ps.
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - allwinner,sun8i-h3-emac
+              - allwinner,sun8i-v3s-emac
+
+    then:
+      properties:
+        allwinner,leds-active-low:
+          $ref: /schemas/types.yaml#definitions/flag
+          description:
+            EPHY LEDs are active low.
+
+        mdio-mux:
+          type: object
+
+          properties:
+            compatible:
+              const: allwinner,sun8i-h3-mdio-mux
+
+            mdio-parent-bus:
+              $ref: /schemas/types.yaml#definitions/phandle
+              description:
+                Phandle to EMAC MDIO.
+
+            mdio@1:
+              type: object
+              description: Internal MDIO Bus
+
+              properties:
+                "#address-cells":
+                  const: 1
+
+                "#size-cells":
+                  const: 0
+
+                compatible:
+                  const: allwinner,sun8i-h3-mdio-internal
+
+                reg:
+                  const: 1
+
+              patternProperties:
+                "^ethernet-phy@[0-9a-f]$":
+                  type: object
+                  description:
+                    Integrated PHY node
+
+                  properties:
+                    clocks:
+                      maxItems: 1
+
+                    resets:
+                      maxItems: 1
+
+                  required:
+                    - clocks
+                    - resets
+
+
+            mdio@2:
+              type: object
+              description: External MDIO Bus (H3 only)
+
+              properties:
+                "#address-cells":
+                  const: 1
+
+                "#size-cells":
+                  const: 0
+
+                reg:
+                  const: 2
+
+          required:
+            - compatible
+            - mdio-parent-bus
+            - mdio@1
+
+examples:
+  - |
+    ethernet@1c0b000 {
+        compatible = "allwinner,sun8i-h3-emac";
+        syscon = <&syscon>;
+        reg = <0x01c0b000 0x104>;
+        interrupts = <0 82 1>;
+        interrupt-names = "macirq";
+        resets = <&ccu 12>;
+        reset-names = "stmmaceth";
+        clocks = <&ccu 27>;
+        clock-names = "stmmaceth";
+
+        phy-handle = <&int_mii_phy>;
+        phy-mode = "mii";
+        allwinner,leds-active-low;
+
+        mdio1: mdio {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            compatible = "snps,dwmac-mdio";
+        };
+
+        mdio-mux {
+            compatible = "allwinner,sun8i-h3-mdio-mux";
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            mdio-parent-bus = <&mdio1>;
+
+            int_mii_phy: mdio@1 {
+                compatible = "allwinner,sun8i-h3-mdio-internal";
+                reg = <1>;
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                ethernet-phy@1 {
+                    reg = <1>;
+                    clocks = <&ccu 67>;
+                    resets = <&ccu 39>;
+                    phy-is-integrated;
+                };
+            };
+
+            mdio@2 {
+                reg = <2>;
+                #address-cells = <1>;
+                #size-cells = <0>;
+            };
+        };
+    };
+
+  - |
+    ethernet@1c0b000 {
+        compatible = "allwinner,sun8i-h3-emac";
+        syscon = <&syscon>;
+        reg = <0x01c0b000 0x104>;
+        interrupts = <0 82 1>;
+        interrupt-names = "macirq";
+        resets = <&ccu 12>;
+        reset-names = "stmmaceth";
+        clocks = <&ccu 27>;
+        clock-names = "stmmaceth";
+
+        phy-handle = <&ext_rgmii_phy>;
+        phy-mode = "rgmii";
+        allwinner,leds-active-low;
+
+        mdio2: mdio {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            compatible = "snps,dwmac-mdio";
+        };
+
+        mdio-mux {
+            compatible = "allwinner,sun8i-h3-mdio-mux";
+            #address-cells = <1>;
+            #size-cells = <0>;
+            mdio-parent-bus = <&mdio2>;
+
+            mdio@1 {
+                compatible = "allwinner,sun8i-h3-mdio-internal";
+                reg = <1>;
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                ethernet-phy@1 {
+                    reg = <1>;
+                    clocks = <&ccu 67>;
+                    resets = <&ccu 39>;
+                };
+            };
+
+            mdio@2 {
+                reg = <2>;
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                ext_rgmii_phy: ethernet-phy@1 {
+                    reg = <1>;
+                };
+            };
+        };
+    };
+
+  - |
+    ethernet@1c0b000 {
+        compatible = "allwinner,sun8i-a83t-emac";
+        syscon = <&syscon>;
+        reg = <0x01c0b000 0x104>;
+        interrupts = <0 82 1>;
+        interrupt-names = "macirq";
+        resets = <&ccu 13>;
+        reset-names = "stmmaceth";
+        clocks = <&ccu 27>;
+        clock-names = "stmmaceth";
+        phy-handle = <&ext_rgmii_phy1>;
+        phy-mode = "rgmii";
+
+        mdio {
+            compatible = "snps,dwmac-mdio";
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            ext_rgmii_phy1: ethernet-phy@1 {
+                reg = <1>;
+            };
+        };
+    };
+
+# FIXME: We should set it, but it would report all the generic
+# properties as additional properties.
+# additionalProperties: false
+
+...
diff --git a/Documentation/devicetree/bindings/net/dwmac-sun8i.txt b/Documentation/devicetree/bindings/net/dwmac-sun8i.txt
deleted file mode 100644 (file)
index 54c66d0..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-* Allwinner sun8i GMAC ethernet controller
-
-This device is a platform glue layer for stmmac.
-Please see stmmac.txt for the other unchanged properties.
-
-Required properties:
-- compatible: must be one of the following string:
-               "allwinner,sun8i-a83t-emac"
-               "allwinner,sun8i-h3-emac"
-               "allwinner,sun8i-r40-gmac"
-               "allwinner,sun8i-v3s-emac"
-               "allwinner,sun50i-a64-emac"
-               "allwinner,sun50i-h6-emac", "allwinner-sun50i-a64-emac"
-- reg: address and length of the register for the device.
-- interrupts: interrupt for the device
-- interrupt-names: must be "macirq"
-- clocks: A phandle to the reference clock for this device
-- clock-names: must be "stmmaceth"
-- resets: A phandle to the reset control for this device
-- reset-names: must be "stmmaceth"
-- phy-mode: See ethernet.txt
-- phy-handle: See ethernet.txt
-- syscon: A phandle to the device containing the EMAC or GMAC clock register
-
-Optional properties:
-- allwinner,tx-delay-ps: TX clock delay chain value in ps.
-                        Range is 0-700. Default is 0.
-                        Unavailable for allwinner,sun8i-r40-gmac
-- allwinner,rx-delay-ps: RX clock delay chain value in ps.
-                        Range is 0-3100. Default is 0.
-                        Range is 0-700 for allwinner,sun8i-r40-gmac
-Both delay properties need to be a multiple of 100. They control the
-clock delay for external RGMII PHY. They do not apply to the internal
-PHY or external non-RGMII PHYs.
-
-Optional properties for the following compatibles:
-  - "allwinner,sun8i-h3-emac",
-  - "allwinner,sun8i-v3s-emac":
-- allwinner,leds-active-low: EPHY LEDs are active low
-
-Required child node of emac:
-- mdio bus node: should be named mdio with compatible "snps,dwmac-mdio"
-
-Required properties of the mdio node:
-- #address-cells: shall be 1
-- #size-cells: shall be 0
-
-The device node referenced by "phy" or "phy-handle" must be a child node
-of the mdio node. See phy.txt for the generic PHY bindings.
-
-The following compatibles require that the emac node have a mdio-mux child
-node called "mdio-mux":
-  - "allwinner,sun8i-h3-emac"
-  - "allwinner,sun8i-v3s-emac":
-Required properties for the mdio-mux node:
-  - compatible = "allwinner,sun8i-h3-mdio-mux"
-  - mdio-parent-bus: a phandle to EMAC mdio
-  - one child mdio for the integrated mdio with the compatible
-    "allwinner,sun8i-h3-mdio-internal"
-  - one child mdio for the external mdio if present (V3s have none)
-Required properties for the mdio-mux children node:
-  - reg: 1 for internal MDIO bus, 2 for external MDIO bus
-
-The following compatibles require a PHY node representing the integrated
-PHY, under the integrated MDIO bus node if an mdio-mux node is used:
-  - "allwinner,sun8i-h3-emac",
-  - "allwinner,sun8i-v3s-emac":
-
-Additional information regarding generic multiplexer properties can be found
-at Documentation/devicetree/bindings/net/mdio-mux.txt
-
-Required properties of the integrated phy node:
-- clocks: a phandle to the reference clock for the EPHY
-- resets: a phandle to the reset control for the EPHY
-- Must be a child of the integrated mdio
-
-Example with integrated PHY:
-emac: ethernet@1c0b000 {
-       compatible = "allwinner,sun8i-h3-emac";
-       syscon = <&syscon>;
-       reg = <0x01c0b000 0x104>;
-       interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
-       interrupt-names = "macirq";
-       resets = <&ccu RST_BUS_EMAC>;
-       reset-names = "stmmaceth";
-       clocks = <&ccu CLK_BUS_EMAC>;
-       clock-names = "stmmaceth";
-
-       phy-handle = <&int_mii_phy>;
-       phy-mode = "mii";
-       allwinner,leds-active-low;
-
-       mdio: mdio {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "snps,dwmac-mdio";
-       };
-
-       mdio-mux {
-               compatible = "mdio-mux", "allwinner,sun8i-h3-mdio-mux";
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               mdio-parent-bus = <&mdio>;
-
-               int_mdio: mdio@1 {
-                       compatible = "allwinner,sun8i-h3-mdio-internal";
-                       reg = <1>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       int_mii_phy: ethernet-phy@1 {
-                               reg = <1>;
-                               clocks = <&ccu CLK_BUS_EPHY>;
-                               resets = <&ccu RST_BUS_EPHY>;
-                               phy-is-integrated;
-                       };
-               };
-               ext_mdio: mdio@2 {
-                       reg = <2>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-               };
-       };
-};
-
-Example with external PHY:
-emac: ethernet@1c0b000 {
-       compatible = "allwinner,sun8i-h3-emac";
-       syscon = <&syscon>;
-       reg = <0x01c0b000 0x104>;
-       interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
-       interrupt-names = "macirq";
-       resets = <&ccu RST_BUS_EMAC>;
-       reset-names = "stmmaceth";
-       clocks = <&ccu CLK_BUS_EMAC>;
-       clock-names = "stmmaceth";
-
-       phy-handle = <&ext_rgmii_phy>;
-       phy-mode = "rgmii";
-       allwinner,leds-active-low;
-
-       mdio: mdio {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "snps,dwmac-mdio";
-       };
-
-       mdio-mux {
-               compatible = "allwinner,sun8i-h3-mdio-mux";
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               mdio-parent-bus = <&mdio>;
-
-               int_mdio: mdio@1 {
-                       compatible = "allwinner,sun8i-h3-mdio-internal";
-                       reg = <1>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       int_mii_phy: ethernet-phy@1 {
-                               reg = <1>;
-                               clocks = <&ccu CLK_BUS_EPHY>;
-                               resets = <&ccu RST_BUS_EPHY>;
-                       };
-               };
-               ext_mdio: mdio@2 {
-                       reg = <2>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       ext_rgmii_phy: ethernet-phy@1 {
-                               reg = <1>;
-                       };
-               }:
-       };
-};
-
-Example with SoC without integrated PHY
-
-emac: ethernet@1c0b000 {
-       compatible = "allwinner,sun8i-a83t-emac";
-       syscon = <&syscon>;
-       reg = <0x01c0b000 0x104>;
-       interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
-       interrupt-names = "macirq";
-       resets = <&ccu RST_BUS_EMAC>;
-       reset-names = "stmmaceth";
-       clocks = <&ccu CLK_BUS_EMAC>;
-       clock-names = "stmmaceth";
-
-       phy-handle = <&ext_rgmii_phy>;
-       phy-mode = "rgmii";
-
-       mdio: mdio {
-               compatible = "snps,dwmac-mdio";
-               #address-cells = <1>;
-               #size-cells = <0>;
-               ext_rgmii_phy: ethernet-phy@1 {
-                       reg = <1>;
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/net/ethernet-controller.yaml b/Documentation/devicetree/bindings/net/ethernet-controller.yaml
new file mode 100644 (file)
index 0000000..0e7c317
--- /dev/null
@@ -0,0 +1,206 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/ethernet-controller.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Ethernet Controller Generic Binding
+
+maintainers:
+  - David S. Miller <davem@davemloft.net>
+
+properties:
+  $nodename:
+    pattern: "^ethernet(@.*)?$"
+
+  local-mac-address:
+    allOf:
+      - $ref: /schemas/types.yaml#definitions/uint8-array
+      - items:
+          - minItems: 6
+            maxItems: 6
+    description:
+      Specifies the MAC address that was assigned to the network device.
+
+  mac-address:
+    allOf:
+      - $ref: /schemas/types.yaml#definitions/uint8-array
+      - items:
+          - minItems: 6
+            maxItems: 6
+    description:
+      Specifies the MAC address that was last used by the boot
+      program; should be used in cases where the MAC address assigned
+      to the device by the boot program is different from the
+      local-mac-address property.
+
+  max-frame-size:
+    $ref: /schemas/types.yaml#definitions/uint32
+    description:
+      Maximum transfer unit (IEEE defined MTU), rather than the
+      maximum frame size (there\'s contradiction in the Devicetree
+      Specification).
+
+  max-speed:
+    $ref: /schemas/types.yaml#definitions/uint32
+    description:
+      Specifies maximum speed in Mbit/s supported by the device.
+
+  nvmem-cells:
+    maxItems: 1
+    description:
+      Reference to an nvmem node for the MAC address
+
+  nvmem-cells-names:
+    const: mac-address
+
+  phy-connection-type:
+    description:
+      Operation mode of the PHY interface
+    enum:
+      # There is not a standard bus between the MAC and the PHY,
+      # something proprietary is being used to embed the PHY in the
+      # MAC.
+      - internal
+      - mii
+      - gmii
+      - sgmii
+      - qsgmii
+      - tbi
+      - rev-mii
+      - rmii
+
+      # RX and TX delays are added by the MAC when required
+      - rgmii
+
+      # RGMII with internal RX and TX delays provided by the PHY,
+      # the MAC should not add the RX or TX delays in this case
+      - rgmii-id
+
+      # RGMII with internal RX delay provided by the PHY, the MAC
+      # should not add an RX delay in this case
+      - rgmii-rxid
+
+      # RGMII with internal TX delay provided by the PHY, the MAC
+      # should not add an TX delay in this case
+      - rgmii-txid
+      - rtbi
+      - smii
+      - xgmii
+      - trgmii
+      - 1000base-x
+      - 2500base-x
+      - rxaui
+      - xaui
+
+      # 10GBASE-KR, XFI, SFI
+      - 10gbase-kr
+      - usxgmii
+
+  phy-mode:
+    $ref: "#/properties/phy-connection-type"
+
+  phy-handle:
+    $ref: /schemas/types.yaml#definitions/phandle
+    description:
+      Specifies a reference to a node representing a PHY device.
+
+  phy:
+    $ref: "#/properties/phy-handle"
+    deprecated: true
+
+  phy-device:
+    $ref: "#/properties/phy-handle"
+    deprecated: true
+
+  rx-fifo-depth:
+    $ref: /schemas/types.yaml#definitions/uint32
+    description:
+      The size of the controller\'s receive fifo in bytes. This is used
+      for components that can have configurable receive fifo sizes,
+      and is useful for determining certain configuration settings
+      such as flow control thresholds.
+
+  tx-fifo-depth:
+    $ref: /schemas/types.yaml#definitions/uint32
+    description:
+      The size of the controller\'s transmit fifo in bytes. This
+      is used for components that can have configurable fifo sizes.
+
+  managed:
+    allOf:
+      - $ref: /schemas/types.yaml#definitions/string
+      - default: auto
+        enum:
+          - auto
+          - in-band-status
+    description:
+      Specifies the PHY management type. If auto is set and fixed-link
+      is not specified, it uses MDIO for management.
+
+  fixed-link:
+    allOf:
+      - if:
+          type: array
+        then:
+          deprecated: true
+          minItems: 1
+          maxItems: 1
+          items:
+            items:
+              - minimum: 0
+                maximum: 31
+                description:
+                  Emulated PHY ID, choose any but unique to the all
+                  specified fixed-links
+
+              - enum: [0, 1]
+                description:
+                  Duplex configuration. 0 for half duplex or 1 for
+                  full duplex
+
+              - enum: [10, 100, 1000]
+                description:
+                  Link speed in Mbits/sec.
+
+              - enum: [0, 1]
+                description:
+                  Pause configuration. 0 for no pause, 1 for pause
+
+              - enum: [0, 1]
+                description:
+                  Asymmetric pause configuration. 0 for no asymmetric
+                  pause, 1 for asymmetric pause
+
+
+      - if:
+          type: object
+        then:
+          properties:
+            speed:
+              allOf:
+                - $ref: /schemas/types.yaml#definitions/uint32
+                - enum: [10, 100, 1000]
+              description:
+                Link speed.
+
+            full-duplex:
+              $ref: /schemas/types.yaml#definitions/flag
+              description:
+                Indicates that full-duplex is used. When absent, half
+                duplex is assumed.
+
+            asym-pause:
+              $ref: /schemas/types.yaml#definitions/flag
+              description:
+                Indicates that asym_pause should be enabled.
+
+            link-gpios:
+              maxItems: 1
+              description:
+                GPIO to determine if the link is up
+
+          required:
+            - speed
+
+...
diff --git a/Documentation/devicetree/bindings/net/ethernet-phy.yaml b/Documentation/devicetree/bindings/net/ethernet-phy.yaml
new file mode 100644 (file)
index 0000000..f70f18f
--- /dev/null
@@ -0,0 +1,177 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/ethernet-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Ethernet PHY Generic Binding
+
+maintainers:
+  - Andrew Lunn <andrew@lunn.ch>
+  - Florian Fainelli <f.fainelli@gmail.com>
+  - Heiner Kallweit <hkallweit1@gmail.com>
+
+# The dt-schema tools will generate a select statement first by using
+# the compatible, and second by using the node name if any. In our
+# case, the node name is the one we want to match on, while the
+# compatible is optional.
+select:
+  properties:
+    $nodename:
+      pattern: "^ethernet-phy(@[a-f0-9]+)?$"
+
+  required:
+    - $nodename
+
+properties:
+  $nodename:
+    pattern: "^ethernet-phy(@[a-f0-9]+)?$"
+
+  compatible:
+    oneOf:
+      - const: ethernet-phy-ieee802.3-c22
+        description: PHYs that implement IEEE802.3 clause 22
+      - const: ethernet-phy-ieee802.3-c45
+        description: PHYs that implement IEEE802.3 clause 45
+      - pattern: "^ethernet-phy-id[a-f0-9]{4}\\.[a-f0-9]{4}$"
+        description:
+          If the PHY reports an incorrect ID (or none at all) then the
+          compatible list may contain an entry with the correct PHY ID
+          in the above form.
+          The first group of digits is the 16 bit Phy Identifier 1
+          register, this is the chip vendor OUI bits 3:18. The
+          second group of digits is the Phy Identifier 2 register,
+          this is the chip vendor OUI bits 19:24, followed by 10
+          bits of a vendor specific ID.
+      - items:
+          - pattern: "^ethernet-phy-id[a-f0-9]{4}\\.[a-f0-9]{4}$"
+          - const: ethernet-phy-ieee802.3-c45
+
+  reg:
+    minimum: 0
+    maximum: 31
+    description:
+      The ID number for the PHY.
+
+  interrupts:
+    maxItems: 1
+
+  max-speed:
+    enum:
+      - 10
+      - 100
+      - 1000
+      - 2500
+      - 5000
+      - 10000
+      - 20000
+      - 25000
+      - 40000
+      - 50000
+      - 56000
+      - 100000
+      - 200000
+    description:
+      Maximum PHY supported speed in Mbits / seconds.
+
+  broken-turn-around:
+    $ref: /schemas/types.yaml#definitions/flag
+    description:
+      If set, indicates the PHY device does not correctly release
+      the turn around line low at the end of a MDIO transaction.
+
+  enet-phy-lane-swap:
+    $ref: /schemas/types.yaml#definitions/flag
+    description:
+      If set, indicates the PHY will swap the TX/RX lanes to
+      compensate for the board being designed with the lanes
+      swapped.
+
+  eee-broken-100tx:
+    $ref: /schemas/types.yaml#definitions/flag
+    description:
+      Mark the corresponding energy efficient ethernet mode as
+      broken and request the ethernet to stop advertising it.
+
+  eee-broken-1000t:
+    $ref: /schemas/types.yaml#definitions/flag
+    description:
+      Mark the corresponding energy efficient ethernet mode as
+      broken and request the ethernet to stop advertising it.
+
+  eee-broken-10gt:
+    $ref: /schemas/types.yaml#definitions/flag
+    description:
+      Mark the corresponding energy efficient ethernet mode as
+      broken and request the ethernet to stop advertising it.
+
+  eee-broken-1000kx:
+    $ref: /schemas/types.yaml#definitions/flag
+    description:
+      Mark the corresponding energy efficient ethernet mode as
+      broken and request the ethernet to stop advertising it.
+
+  eee-broken-10gkx4:
+    $ref: /schemas/types.yaml#definitions/flag
+    description:
+      Mark the corresponding energy efficient ethernet mode as
+      broken and request the ethernet to stop advertising it.
+
+  eee-broken-10gkr:
+    $ref: /schemas/types.yaml#definitions/flag
+    description:
+      Mark the corresponding energy efficient ethernet mode as
+      broken and request the ethernet to stop advertising it.
+
+  phy-is-integrated:
+    $ref: /schemas/types.yaml#definitions/flag
+    description:
+      If set, indicates that the PHY is integrated into the same
+      physical package as the Ethernet MAC. If needed, muxers
+      should be configured to ensure the integrated PHY is
+      used. The absence of this property indicates the muxers
+      should be configured so that the external PHY is used.
+
+  resets:
+    maxItems: 1
+
+  reset-names:
+    const: phy
+
+  reset-gpios:
+    maxItems: 1
+    description:
+      The GPIO phandle and specifier for the PHY reset signal.
+
+  reset-assert-us:
+    description:
+      Delay after the reset was asserted in microseconds. If this
+      property is missing the delay will be skipped.
+
+  reset-deassert-us:
+    description:
+      Delay after the reset was deasserted in microseconds. If
+      this property is missing the delay will be skipped.
+
+required:
+  - reg
+
+examples:
+  - |
+    ethernet {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        ethernet-phy@0 {
+            compatible = "ethernet-phy-id0141.0e90", "ethernet-phy-ieee802.3-c45";
+            interrupt-parent = <&PIC>;
+            interrupts = <35 1>;
+            reg = <0>;
+
+            resets = <&rst 8>;
+            reset-names = "phy";
+            reset-gpios = <&gpio1 4 1>;
+            reset-assert-us = <1000>;
+            reset-deassert-us = <2000>;
+        };
+    };
index 5475682..5df413d 100644 (file)
@@ -1,68 +1 @@
-The following properties are common to the Ethernet controllers:
-
-NOTE: All 'phy*' properties documented below are Ethernet specific. For the
-generic PHY 'phys' property, see
-Documentation/devicetree/bindings/phy/phy-bindings.txt.
-
-- mac-address: array of 6 bytes, specifies the MAC address that was last used by
-  the boot program; should be used in cases where the MAC address assigned to
-  the device by the boot program is different from the "local-mac-address"
-  property;
-- local-mac-address: array of 6 bytes, specifies the MAC address that was
-  assigned to the network device;
-- nvmem-cells: phandle, reference to an nvmem node for the MAC address
-- nvmem-cell-names: string, should be "mac-address" if nvmem is to be used
-- max-speed: number, specifies maximum speed in Mbit/s supported by the device;
-- max-frame-size: number, maximum transfer unit (IEEE defined MTU), rather than
-  the maximum frame size (there's contradiction in the Devicetree
-  Specification).
-- phy-mode: string, operation mode of the PHY interface. This is now a de-facto
-  standard property; supported values are:
-  * "internal" (Internal means there is not a standard bus between the MAC and
-     the PHY, something proprietary is being used to embed the PHY in the MAC.)
-  * "mii"
-  * "gmii"
-  * "sgmii"
-  * "qsgmii"
-  * "tbi"
-  * "rev-mii"
-  * "rmii"
-  * "rgmii" (RX and TX delays are added by the MAC when required)
-  * "rgmii-id" (RGMII with internal RX and TX delays provided by the PHY, the
-     MAC should not add the RX or TX delays in this case)
-  * "rgmii-rxid" (RGMII with internal RX delay provided by the PHY, the MAC
-     should not add an RX delay in this case)
-  * "rgmii-txid" (RGMII with internal TX delay provided by the PHY, the MAC
-     should not add an TX delay in this case)
-  * "rtbi"
-  * "smii"
-  * "xgmii"
-  * "trgmii"
-  * "1000base-x",
-  * "2500base-x",
-  * "rxaui"
-  * "xaui"
-  * "10gbase-kr" (10GBASE-KR, XFI, SFI)
-  * "usxgmii"
-- phy-connection-type: the same as "phy-mode" property but described in the
-  Devicetree Specification;
-- phy-handle: phandle, specifies a reference to a node representing a PHY
-  device; this property is described in the Devicetree Specification and so
-  preferred;
-- phy: the same as "phy-handle" property, not recommended for new bindings.
-- phy-device: the same as "phy-handle" property, not recommended for new
-  bindings.
-- rx-fifo-depth: the size of the controller's receive fifo in bytes. This
-  is used for components that can have configurable receive fifo sizes,
-  and is useful for determining certain configuration settings such as
-  flow control thresholds.
-- tx-fifo-depth: the size of the controller's transmit fifo in bytes. This
-  is used for components that can have configurable fifo sizes.
-- managed: string, specifies the PHY management type. Supported values are:
-  "auto", "in-band-status". "auto" is the default, it usess MDIO for
-  management if fixed-link is not specified.
-
-Child nodes of the Ethernet controller are typically the individual PHY devices
-connected via the MDIO bus (sometimes the MDIO bus controller is separate).
-They are described in the phy.txt file in this same directory.
-For non-MDIO PHY management see fixed-link.txt.
+This file has moved to ethernet-controller.yaml.
index ec5d889..5df413d 100644 (file)
@@ -1,54 +1 @@
-Fixed link Device Tree binding
-------------------------------
-
-Some Ethernet MACs have a "fixed link", and are not connected to a
-normal MDIO-managed PHY device. For those situations, a Device Tree
-binding allows to describe a "fixed link".
-
-Such a fixed link situation is described by creating a 'fixed-link'
-sub-node of the Ethernet MAC device node, with the following
-properties:
-
-* 'speed' (integer, mandatory), to indicate the link speed. Accepted
-  values are 10, 100 and 1000
-* 'full-duplex' (boolean, optional), to indicate that full duplex is
-  used. When absent, half duplex is assumed.
-* 'pause' (boolean, optional), to indicate that pause should be
-  enabled.
-* 'asym-pause' (boolean, optional), to indicate that asym_pause should
-  be enabled.
-* 'link-gpios' ('gpio-list', optional), to indicate if a gpio can be read
-  to determine if the link is up.
-
-Old, deprecated 'fixed-link' binding:
-
-* A 'fixed-link' property in the Ethernet MAC node, with 5 cells, of the
-  form <a b c d e> with the following accepted values:
-  - a: emulated PHY ID, choose any but but unique to the all specified
-    fixed-links, from 0 to 31
-  - b: duplex configuration: 0 for half duplex, 1 for full duplex
-  - c: link speed in Mbits/sec, accepted values are: 10, 100 and 1000
-  - d: pause configuration: 0 for no pause, 1 for pause
-  - e: asymmetric pause configuration: 0 for no asymmetric pause, 1 for
-    asymmetric pause
-
-Examples:
-
-ethernet@0 {
-       ...
-       fixed-link {
-             speed = <1000>;
-             full-duplex;
-       };
-       ...
-};
-
-ethernet@1 {
-       ...
-       fixed-link {
-             speed = <1000>;
-             pause;
-             link-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>;
-       };
-       ...
-};
+This file has moved to ethernet-controller.yaml.
index e3e1603..cf8a010 100644 (file)
@@ -1,37 +1 @@
-Common MDIO bus properties.
-
-These are generic properties that can apply to any MDIO bus.
-
-Optional properties:
-- reset-gpios: One GPIO that control the RESET lines of all PHYs on that MDIO
-  bus.
-- reset-delay-us: RESET pulse width in microseconds.
-
-A list of child nodes, one per device on the bus is expected. These
-should follow the generic phy.txt, or a device specific binding document.
-
-The 'reset-delay-us' indicates the RESET signal pulse width in microseconds and
-applies to all PHY devices. It must therefore be appropriately determined based
-on all PHY requirements (maximum value of all per-PHY RESET pulse widths).
-
-Example :
-This example shows these optional properties, plus other properties
-required for the TI Davinci MDIO driver.
-
-       davinci_mdio: ethernet@5c030000 {
-               compatible = "ti,davinci_mdio";
-               reg = <0x5c030000 0x1000>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               reset-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>;
-               reset-delay-us = <2>;
-
-               ethphy0: ethernet-phy@1 {
-                       reg = <1>;
-               };
-
-               ethphy1: ethernet-phy@3 {
-                       reg = <3>;
-               };
-       };
+This file has moved to mdio.yaml.
diff --git a/Documentation/devicetree/bindings/net/mdio.yaml b/Documentation/devicetree/bindings/net/mdio.yaml
new file mode 100644 (file)
index 0000000..5d08d2f
--- /dev/null
@@ -0,0 +1,74 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/mdio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MDIO Bus Generic Binding
+
+maintainers:
+  - Andrew Lunn <andrew@lunn.ch>
+  - Florian Fainelli <f.fainelli@gmail.com>
+  - Heiner Kallweit <hkallweit1@gmail.com>
+
+description:
+  These are generic properties that can apply to any MDIO bus. Any
+  MDIO bus must have a list of child nodes, one per device on the
+  bus. These should follow the generic ethernet-phy.yaml document, or
+  a device specific binding document.
+
+properties:
+  $nodename:
+    pattern: "^mdio(@.*)?"
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+  reset-gpios:
+    maxItems: 1
+    description:
+      The phandle and specifier for the GPIO that controls the RESET
+      lines of all PHYs on that MDIO bus.
+
+  reset-delay-us:
+    description:
+      RESET pulse width in microseconds. It applies to all PHY devices
+      and must therefore be appropriately determined based on all PHY
+      requirements (maximum value of all per-PHY RESET pulse widths).
+
+patternProperties:
+  "^ethernet-phy@[0-9a-f]+$":
+    type: object
+
+    properties:
+      reg:
+        minimum: 0
+        maximum: 31
+        description:
+          The ID number for the PHY.
+
+    required:
+      - reg
+
+examples:
+  - |
+    davinci_mdio: mdio@5c030000 {
+        compatible = "ti,davinci_mdio";
+        reg = <0x5c030000 0x1000>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        reset-gpios = <&gpio2 5 1>;
+        reset-delay-us = <2>;
+
+        ethphy0: ethernet-phy@1 {
+            reg = <1>;
+        };
+
+        ethphy1: ethernet-phy@3 {
+            reg = <3>;
+        };
+    };
index 9b9e5b1..2399ee6 100644 (file)
@@ -1,79 +1 @@
-PHY nodes
-
-Required properties:
-
- - interrupts : interrupt specifier for the sole interrupt.
- - reg : The ID number for the phy, usually a small integer
-
-Optional Properties:
-
-- compatible: Compatible list, may contain
-  "ethernet-phy-ieee802.3-c22" or "ethernet-phy-ieee802.3-c45" for
-  PHYs that implement IEEE802.3 clause 22 or IEEE802.3 clause 45
-  specifications. If neither of these are specified, the default is to
-  assume clause 22.
-
-  If the PHY reports an incorrect ID (or none at all) then the
-  "compatible" list may contain an entry with the correct PHY ID in the
-  form: "ethernet-phy-idAAAA.BBBB" where
-     AAAA - The value of the 16 bit Phy Identifier 1 register as
-            4 hex digits. This is the chip vendor OUI bits 3:18
-     BBBB - The value of the 16 bit Phy Identifier 2 register as
-            4 hex digits. This is the chip vendor OUI bits 19:24,
-            followed by 10 bits of a vendor specific ID.
-
-  The compatible list should not contain other values than those
-  listed here.
-
-- max-speed: Maximum PHY supported speed (10, 100, 1000...)
-
-- broken-turn-around: If set, indicates the PHY device does not correctly
-  release the turn around line low at the end of a MDIO transaction.
-
-- enet-phy-lane-swap: If set, indicates the PHY will swap the TX/RX lanes to
-  compensate for the board being designed with the lanes swapped.
-
-- enet-phy-lane-no-swap: If set, indicates that PHY will disable swap of the
-  TX/RX lanes. This property allows the PHY to work correcly after e.g. wrong
-  bootstrap configuration caused by issues in PCB layout design.
-
-- eee-broken-100tx:
-- eee-broken-1000t:
-- eee-broken-10gt:
-- eee-broken-1000kx:
-- eee-broken-10gkx4:
-- eee-broken-10gkr:
-  Mark the corresponding energy efficient ethernet mode as broken and
-  request the ethernet to stop advertising it.
-
-- phy-is-integrated: If set, indicates that the PHY is integrated into the same
-  physical package as the Ethernet MAC. If needed, muxers should be configured
-  to ensure the integrated PHY is used. The absence of this property indicates
-  the muxers should be configured so that the external PHY is used.
-
-- resets: The reset-controller phandle and specifier for the PHY reset signal.
-
-- reset-names: Must be "phy" for the PHY reset signal.
-
-- reset-gpios: The GPIO phandle and specifier for the PHY reset signal.
-
-- reset-assert-us: Delay after the reset was asserted in microseconds.
-  If this property is missing the delay will be skipped.
-
-- reset-deassert-us: Delay after the reset was deasserted in microseconds.
-  If this property is missing the delay will be skipped.
-
-Example:
-
-ethernet-phy@0 {
-       compatible = "ethernet-phy-id0141.0e90", "ethernet-phy-ieee802.3-c22";
-       interrupt-parent = <&PIC>;
-       interrupts = <35 IRQ_TYPE_EDGE_RISING>;
-       reg = <0>;
-
-       resets = <&rst 8>;
-       reset-names = "phy";
-       reset-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
-       reset-assert-us = <1000>;
-       reset-deassert-us = <2000>;
-};
+This file has moved to ethernet-phy.yaml.
diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml
new file mode 100644 (file)
index 0000000..76fea2b
--- /dev/null
@@ -0,0 +1,411 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/snps,dwmac.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Synopsys DesignWare MAC Device Tree Bindings
+
+maintainers:
+  - Alexandre Torgue <alexandre.torgue@st.com>
+  - Giuseppe Cavallaro <peppe.cavallaro@st.com>
+  - Jose Abreu <joabreu@synopsys.com>
+
+# Select every compatible, including the deprecated ones. This way, we
+# will be able to report a warning when we have that compatible, since
+# we will validate the node thanks to the select, but won't report it
+# as a valid value in the compatible property description
+select:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - snps,dwmac
+          - snps,dwmac-3.50a
+          - snps,dwmac-3.610
+          - snps,dwmac-3.70a
+          - snps,dwmac-3.710
+          - snps,dwmac-4.00
+          - snps,dwmac-4.10a
+          - snps,dwxgmac
+          - snps,dwxgmac-2.10
+
+          # Deprecated
+          - st,spear600-gmac
+
+  required:
+    - compatible
+
+properties:
+
+  # We need to include all the compatibles from schemas that will
+  # include that schemas, otherwise compatible won't validate for
+  # those.
+  compatible:
+    contains:
+      enum:
+        - allwinner,sun7i-a20-gmac
+        - allwinner,sun8i-a83t-emac
+        - allwinner,sun8i-h3-emac
+        - allwinner,sun8i-r40-emac
+        - allwinner,sun8i-v3s-emac
+        - allwinner,sun50i-a64-emac
+        - snps,dwmac
+        - snps,dwmac-3.50a
+        - snps,dwmac-3.610
+        - snps,dwmac-3.70a
+        - snps,dwmac-3.710
+        - snps,dwmac-4.00
+        - snps,dwmac-4.10a
+        - snps,dwxgmac
+        - snps,dwxgmac-2.10
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    minItems: 1
+    maxItems: 3
+    items:
+      - description: Combined signal for various interrupt events
+      - description: The interrupt to manage the remote wake-up packet detection
+      - description: The interrupt that occurs when Rx exits the LPI state
+
+  interrupt-names:
+    minItems: 1
+    maxItems: 3
+    items:
+      - const: macirq
+      - const: eth_wake_irq
+      - const: eth_lpi
+
+  clocks:
+    minItems: 1
+    maxItems: 3
+    items:
+      - description: GMAC main clock
+      - description: Peripheral registers interface clock
+      - description:
+          PTP reference clock. This clock is used for programming the
+          Timestamp Addend Register. If not passed then the system
+          clock will be used and this is fine on some platforms.
+
+  clock-names:
+    additionalItems: true
+    contains:
+      enum:
+        - stmmaceth
+        - pclk
+        - ptp_ref
+
+  resets:
+    maxItems: 1
+    description:
+      MAC Reset signal.
+
+  reset-names:
+    const: stmmaceth
+
+  snps,axi-config:
+    $ref: /schemas/types.yaml#definitions/phandle
+    description:
+      AXI BUS Mode parameters. Phandle to a node that can contain the
+      following properties
+        * snps,lpi_en, enable Low Power Interface
+        * snps,xit_frm, unlock on WoL
+        * snps,wr_osr_lmt, max write outstanding req. limit
+        * snps,rd_osr_lmt, max read outstanding req. limit
+        * snps,kbbe, do not cross 1KiB boundary.
+        * snps,blen, this is a vector of supported burst length.
+        * snps,fb, fixed-burst
+        * snps,mb, mixed-burst
+        * snps,rb, rebuild INCRx Burst
+
+  snps,mtl-rx-config:
+    $ref: /schemas/types.yaml#definitions/phandle
+    description:
+      Multiple RX Queues parameters. Phandle to a node that can
+      contain the following properties
+        * snps,rx-queues-to-use, number of RX queues to be used in the
+          driver
+        * Choose one of these RX scheduling algorithms
+          * snps,rx-sched-sp, Strict priority
+          * snps,rx-sched-wsp, Weighted Strict priority
+        * For each RX queue
+          * Choose one of these modes
+            * snps,dcb-algorithm, Queue to be enabled as DCB
+            * snps,avb-algorithm, Queue to be enabled as AVB
+          * snps,map-to-dma-channel, Channel to map
+          * Specifiy specific packet routing
+            * snps,route-avcp, AV Untagged Control packets
+            * snps,route-ptp, PTP Packets
+            * snps,route-dcbcp, DCB Control Packets
+            * snps,route-up, Untagged Packets
+            * snps,route-multi-broad, Multicast & Broadcast Packets
+          * snps,priority, RX queue priority (Range 0x0 to 0xF)
+
+  snps,mtl-tx-config:
+    $ref: /schemas/types.yaml#definitions/phandle
+    description:
+      Multiple TX Queues parameters. Phandle to a node that can
+      contain the following properties
+        * snps,tx-queues-to-use, number of TX queues to be used in the
+          driver
+        * Choose one of these TX scheduling algorithms
+          * snps,tx-sched-wrr, Weighted Round Robin
+          * snps,tx-sched-wfq, Weighted Fair Queuing
+          * snps,tx-sched-dwrr, Deficit Weighted Round Robin
+          * snps,tx-sched-sp, Strict priority
+        * For each TX queue
+          * snps,weight, TX queue weight (if using a DCB weight
+            algorithm)
+          * Choose one of these modes
+            * snps,dcb-algorithm, TX queue will be working in DCB
+            * snps,avb-algorithm, TX queue will be working in AVB
+              [Attention] Queue 0 is reserved for legacy traffic
+                          and so no AVB is available in this queue.
+          * Configure Credit Base Shaper (if AVB Mode selected)
+            * snps,send_slope, enable Low Power Interface
+            * snps,idle_slope, unlock on WoL
+            * snps,high_credit, max write outstanding req. limit
+            * snps,low_credit, max read outstanding req. limit
+          * snps,priority, TX queue priority (Range 0x0 to 0xF)
+
+  snps,reset-gpio:
+    deprecated: true
+    maxItems: 1
+    description:
+      PHY Reset GPIO
+
+  snps,reset-active-low:
+    deprecated: true
+    $ref: /schemas/types.yaml#definitions/flag
+    description:
+      Indicates that the PHY Reset is active low
+
+  snps,reset-delays-us:
+    deprecated: true
+    allOf:
+      - $ref: /schemas/types.yaml#definitions/uint32-array
+      - minItems: 3
+        maxItems: 3
+    description:
+      Triplet of delays. The 1st cell is reset pre-delay in micro
+      seconds. The 2nd cell is reset pulse in micro seconds. The 3rd
+      cell is reset post-delay in micro seconds.
+
+  snps,aal:
+    $ref: /schemas/types.yaml#definitions/flag
+    description:
+      Use Address-Aligned Beats
+
+  snps,fixed-burst:
+    $ref: /schemas/types.yaml#definitions/flag
+    description:
+      Program the DMA to use the fixed burst mode
+
+  snps,mixed-burst:
+    $ref: /schemas/types.yaml#definitions/flag
+    description:
+      Program the DMA to use the mixed burst mode
+
+  snps,force_thresh_dma_mode:
+    $ref: /schemas/types.yaml#definitions/flag
+    description:
+      Force DMA to use the threshold mode for both tx and rx
+
+  snps,force_sf_dma_mode:
+    $ref: /schemas/types.yaml#definitions/flag
+    description:
+      Force DMA to use the Store and Forward mode for both tx and
+      rx. This flag is ignored if force_thresh_dma_mode is set.
+
+  snps,en-tx-lpi-clockgating:
+    $ref: /schemas/types.yaml#definitions/flag
+    description:
+      Enable gating of the MAC TX clock during TX low-power mode
+
+  snps,multicast-filter-bins:
+    $ref: /schemas/types.yaml#definitions/uint32
+    description:
+      Number of multicast filter hash bins supported by this device
+      instance
+
+  snps,perfect-filter-entries:
+    $ref: /schemas/types.yaml#definitions/uint32
+    description:
+      Number of perfect filter entries supported by this device
+      instance
+
+  snps,ps-speed:
+    $ref: /schemas/types.yaml#definitions/uint32
+    description:
+      Port selection speed that can be passed to the core when PCS
+      is supported. For example, this is used in case of SGMII and
+      MAC2MAC connection.
+
+  mdio:
+    type: object
+    description:
+      Creates and registers an MDIO bus.
+
+    properties:
+      compatible:
+        const: snps,dwmac-mdio
+
+    required:
+      - compatible
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-names
+  - phy-mode
+
+dependencies:
+  snps,reset-active-low: ["snps,reset-gpio"]
+  snps,reset-delay-us: ["snps,reset-gpio"]
+
+allOf:
+  - $ref: "ethernet-controller.yaml#"
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - allwinner,sun7i-a20-gmac
+              - allwinner,sun8i-a83t-emac
+              - allwinner,sun8i-h3-emac
+              - allwinner,sun8i-r40-emac
+              - allwinner,sun8i-v3s-emac
+              - allwinner,sun50i-a64-emac
+              - snps,dwxgmac
+              - snps,dwxgmac-2.10
+              - st,spear600-gmac
+
+    then:
+      properties:
+        snps,pbl:
+          allOf:
+            - $ref: /schemas/types.yaml#definitions/uint32
+            - enum: [2, 4, 8]
+          description:
+            Programmable Burst Length (tx and rx)
+
+        snps,txpbl:
+          allOf:
+            - $ref: /schemas/types.yaml#definitions/uint32
+            - enum: [2, 4, 8]
+          description:
+            Tx Programmable Burst Length. If set, DMA tx will use this
+            value rather than snps,pbl.
+
+        snps,rxpbl:
+          allOf:
+            - $ref: /schemas/types.yaml#definitions/uint32
+            - enum: [2, 4, 8]
+          description:
+            Rx Programmable Burst Length. If set, DMA rx will use this
+            value rather than snps,pbl.
+
+        snps,no-pbl-x8:
+          $ref: /schemas/types.yaml#definitions/flag
+          description:
+            Don\'t multiply the pbl/txpbl/rxpbl values by 8. For core
+            rev < 3.50, don\'t multiply the values by 4.
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - allwinner,sun7i-a20-gmac
+              - allwinner,sun8i-a83t-emac
+              - allwinner,sun8i-h3-emac
+              - allwinner,sun8i-r40-emac
+              - allwinner,sun8i-v3s-emac
+              - allwinner,sun50i-a64-emac
+              - snps,dwmac-4.00
+              - snps,dwmac-4.10a
+              - snps,dwxgmac
+              - snps,dwxgmac-2.10
+              - st,spear600-gmac
+
+    then:
+        snps,tso:
+          $ref: /schemas/types.yaml#definitions/flag
+          description:
+            Enables the TSO feature otherwise it will be managed by
+            MAC HW capability register.
+
+examples:
+  - |
+    stmmac_axi_setup: stmmac-axi-config {
+        snps,wr_osr_lmt = <0xf>;
+        snps,rd_osr_lmt = <0xf>;
+        snps,blen = <256 128 64 32 0 0 0>;
+    };
+
+    mtl_rx_setup: rx-queues-config {
+        snps,rx-queues-to-use = <1>;
+        snps,rx-sched-sp;
+        queue0 {
+            snps,dcb-algorithm;
+            snps,map-to-dma-channel = <0x0>;
+            snps,priority = <0x0>;
+        };
+    };
+
+    mtl_tx_setup: tx-queues-config {
+        snps,tx-queues-to-use = <2>;
+        snps,tx-sched-wrr;
+        queue0 {
+            snps,weight = <0x10>;
+            snps,dcb-algorithm;
+            snps,priority = <0x0>;
+        };
+
+        queue1 {
+            snps,avb-algorithm;
+            snps,send_slope = <0x1000>;
+            snps,idle_slope = <0x1000>;
+            snps,high_credit = <0x3E800>;
+            snps,low_credit = <0xFFC18000>;
+            snps,priority = <0x1>;
+        };
+    };
+
+    gmac0: ethernet@e0800000 {
+        compatible = "snps,dwxgmac-2.10", "snps,dwxgmac";
+        reg = <0xe0800000 0x8000>;
+        interrupt-parent = <&vic1>;
+        interrupts = <24 23 22>;
+        interrupt-names = "macirq", "eth_wake_irq", "eth_lpi";
+        mac-address = [000000000000]; /* Filled in by U-Boot */
+        max-frame-size = <3800>;
+        phy-mode = "gmii";
+        snps,multicast-filter-bins = <256>;
+        snps,perfect-filter-entries = <128>;
+        rx-fifo-depth = <16384>;
+        tx-fifo-depth = <16384>;
+        clocks = <&clock>;
+        clock-names = "stmmaceth";
+        snps,axi-config = <&stmmac_axi_setup>;
+        snps,mtl-rx-config = <&mtl_rx_setup>;
+        snps,mtl-tx-config = <&mtl_tx_setup>;
+        mdio0 {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            compatible = "snps,dwmac-mdio";
+            phy1: ethernet-phy@0 {
+                reg = <0>;
+            };
+        };
+    };
+
+# FIXME: We should set it, but it would report all the generic
+# properties as additional properties.
+# additionalProperties: false
+
+...
index cb69406..7d48782 100644 (file)
@@ -1,178 +1 @@
-* STMicroelectronics 10/100/1000/2500/10000 Ethernet (GMAC/XGMAC)
-
-Required properties:
-- compatible: Should be "snps,dwmac-<ip_version>", "snps,dwmac" or
-       "snps,dwxgmac-<ip_version>", "snps,dwxgmac".
-       For backwards compatibility: "st,spear600-gmac" is also supported.
-- reg: Address and length of the register set for the device
-- interrupts: Should contain the STMMAC interrupts
-- interrupt-names: Should contain a list of interrupt names corresponding to
-       the interrupts in the interrupts property, if available.
-       Valid interrupt names are:
-  - "macirq" (combined signal for various interrupt events)
-  - "eth_wake_irq" (the interrupt to manage the remote wake-up packet detection)
-  - "eth_lpi" (the interrupt that occurs when Rx exits the LPI state)
-- phy-mode: See ethernet.txt file in the same directory.
-- snps,reset-gpio      gpio number for phy reset.
-- snps,reset-active-low boolean flag to indicate if phy reset is active low.
-- snps,reset-delays-us  is triplet of delays
-       The 1st cell is reset pre-delay in micro seconds.
-       The 2nd cell is reset pulse in micro seconds.
-       The 3rd cell is reset post-delay in micro seconds.
-
-Optional properties:
-- resets: Should contain a phandle to the STMMAC reset signal, if any
-- reset-names: Should contain the reset signal name "stmmaceth", if a
-       reset phandle is given
-- max-frame-size: See ethernet.txt file in the same directory
-- clocks: If present, the first clock should be the GMAC main clock and
-  the second clock should be peripheral's register interface clock. Further
-  clocks may be specified in derived bindings.
-- clock-names: One name for each entry in the clocks property, the
-  first one should be "stmmaceth" and the second one should be "pclk".
-- ptp_ref: this is the PTP reference clock; in case of the PTP is available
-  this clock is used for programming the Timestamp Addend Register. If not
-  passed then the system clock will be used and this is fine on some
-  platforms.
-- tx-fifo-depth: See ethernet.txt file in the same directory
-- rx-fifo-depth: See ethernet.txt file in the same directory
-- snps,pbl             Programmable Burst Length (tx and rx)
-- snps,txpbl           Tx Programmable Burst Length. Only for GMAC and newer.
-                       If set, DMA tx will use this value rather than snps,pbl.
-- snps,rxpbl           Rx Programmable Burst Length. Only for GMAC and newer.
-                       If set, DMA rx will use this value rather than snps,pbl.
-- snps,no-pbl-x8       Don't multiply the pbl/txpbl/rxpbl values by 8.
-                       For core rev < 3.50, don't multiply the values by 4.
-- snps,aal             Address-Aligned Beats
-- snps,fixed-burst     Program the DMA to use the fixed burst mode
-- snps,mixed-burst     Program the DMA to use the mixed burst mode
-- snps,force_thresh_dma_mode   Force DMA to use the threshold mode for
-                               both tx and rx
-- snps,force_sf_dma_mode       Force DMA to use the Store and Forward
-                               mode for both tx and rx. This flag is
-                               ignored if force_thresh_dma_mode is set.
-- snps,en-tx-lpi-clockgating   Enable gating of the MAC TX clock during
-                               TX low-power mode
-- snps,multicast-filter-bins:  Number of multicast filter hash bins
-                               supported by this device instance
-- snps,perfect-filter-entries: Number of perfect filter entries supported
-                               by this device instance
-- snps,ps-speed: port selection speed that can be passed to the core when
-                PCS is supported. For example, this is used in case of SGMII
-                and MAC2MAC connection.
-- snps,tso: this enables the TSO feature otherwise it will be managed by
-                MAC HW capability register. Only for GMAC4 and newer.
-- AXI BUS Mode parameters: below the list of all the parameters to program the
-                          AXI register inside the DMA module:
-       - snps,lpi_en: enable Low Power Interface
-       - snps,xit_frm: unlock on WoL
-       - snps,wr_osr_lmt: max write outstanding req. limit
-       - snps,rd_osr_lmt: max read outstanding req. limit
-       - snps,kbbe: do not cross 1KiB boundary.
-       - snps,blen: this is a vector of supported burst length.
-       - snps,fb: fixed-burst
-       - snps,mb: mixed-burst
-       - snps,rb: rebuild INCRx Burst
-- mdio: with compatible = "snps,dwmac-mdio", create and register mdio bus.
-- Multiple RX Queues parameters: below the list of all the parameters to
-                                configure the multiple RX queues:
-       - snps,rx-queues-to-use: number of RX queues to be used in the driver
-       - Choose one of these RX scheduling algorithms:
-               - snps,rx-sched-sp: Strict priority
-               - snps,rx-sched-wsp: Weighted Strict priority
-       - For each RX queue
-               - Choose one of these modes:
-                       - snps,dcb-algorithm: Queue to be enabled as DCB
-                       - snps,avb-algorithm: Queue to be enabled as AVB
-               - snps,map-to-dma-channel: Channel to map
-               - Specifiy specific packet routing:
-                       - snps,route-avcp: AV Untagged Control packets
-                       - snps,route-ptp: PTP Packets
-                       - snps,route-dcbcp: DCB Control Packets
-                       - snps,route-up: Untagged Packets
-                       - snps,route-multi-broad: Multicast & Broadcast Packets
-               - snps,priority: RX queue priority (Range: 0x0 to 0xF)
-- Multiple TX Queues parameters: below the list of all the parameters to
-                                configure the multiple TX queues:
-       - snps,tx-queues-to-use: number of TX queues to be used in the driver
-       - Choose one of these TX scheduling algorithms:
-               - snps,tx-sched-wrr: Weighted Round Robin
-               - snps,tx-sched-wfq: Weighted Fair Queuing
-               - snps,tx-sched-dwrr: Deficit Weighted Round Robin
-               - snps,tx-sched-sp: Strict priority
-       - For each TX queue
-               - snps,weight: TX queue weight (if using a DCB weight algorithm)
-               - Choose one of these modes:
-                       - snps,dcb-algorithm: TX queue will be working in DCB
-                       - snps,avb-algorithm: TX queue will be working in AVB
-                         [Attention] Queue 0 is reserved for legacy traffic
-                         and so no AVB is available in this queue.
-               - Configure Credit Base Shaper (if AVB Mode selected):
-                       - snps,send_slope: enable Low Power Interface
-                       - snps,idle_slope: unlock on WoL
-                       - snps,high_credit: max write outstanding req. limit
-                       - snps,low_credit: max read outstanding req. limit
-               - snps,priority: TX queue priority (Range: 0x0 to 0xF)
-Examples:
-
-       stmmac_axi_setup: stmmac-axi-config {
-               snps,wr_osr_lmt = <0xf>;
-               snps,rd_osr_lmt = <0xf>;
-               snps,blen = <256 128 64 32 0 0 0>;
-       };
-
-       mtl_rx_setup: rx-queues-config {
-               snps,rx-queues-to-use = <1>;
-               snps,rx-sched-sp;
-               queue0 {
-                       snps,dcb-algorithm;
-                       snps,map-to-dma-channel = <0x0>;
-                       snps,priority = <0x0>;
-               };
-       };
-
-       mtl_tx_setup: tx-queues-config {
-               snps,tx-queues-to-use = <2>;
-               snps,tx-sched-wrr;
-               queue0 {
-                       snps,weight = <0x10>;
-                       snps,dcb-algorithm;
-                       snps,priority = <0x0>;
-               };
-
-               queue1 {
-                       snps,avb-algorithm;
-                       snps,send_slope = <0x1000>;
-                       snps,idle_slope = <0x1000>;
-                       snps,high_credit = <0x3E800>;
-                       snps,low_credit = <0xFFC18000>;
-                       snps,priority = <0x1>;
-               };
-       };
-
-       gmac0: ethernet@e0800000 {
-               compatible = "st,spear600-gmac";
-               reg = <0xe0800000 0x8000>;
-               interrupt-parent = <&vic1>;
-               interrupts = <24 23 22>;
-               interrupt-names = "macirq", "eth_wake_irq", "eth_lpi";
-               mac-address = [000000000000]; /* Filled in by U-Boot */
-               max-frame-size = <3800>;
-               phy-mode = "gmii";
-               snps,multicast-filter-bins = <256>;
-               snps,perfect-filter-entries = <128>;
-               rx-fifo-depth = <16384>;
-               tx-fifo-depth = <16384>;
-               clocks = <&clock>;
-               clock-names = "stmmaceth";
-               snps,axi-config = <&stmmac_axi_setup>;
-               mdio0 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "snps,dwmac-mdio";
-                       phy1: ethernet-phy@0 {
-                       };
-               };
-               snps,mtl-rx-config = <&mtl_rx_setup>;
-               snps,mtl-tx-config = <&mtl_tx_setup>;
-       };
+This file has moved to snps,dwmac.yaml.
diff --git a/Documentation/devicetree/bindings/nvmem/allwinner,sun4i-a10-sid.yaml b/Documentation/devicetree/bindings/nvmem/allwinner,sun4i-a10-sid.yaml
new file mode 100644 (file)
index 0000000..c9efd6e
--- /dev/null
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/allwinner,sun4i-a10-sid.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A10 Security ID Device Tree Bindings
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+allOf:
+  - $ref: "nvmem.yaml#"
+
+properties:
+  compatible:
+    enum:
+      - allwinner,sun4i-a10-sid
+      - allwinner,sun7i-a20-sid
+      - allwinner,sun8i-a83t-sid
+      - allwinner,sun8i-h3-sid
+      - allwinner,sun50i-a64-sid
+      - allwinner,sun50i-h5-sid
+      - allwinner,sun50i-h6-sid
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+# FIXME: We should set it, but it would report all the generic
+# properties as additional properties.
+# additionalProperties: false
+
+examples:
+  - |
+    sid@1c23800 {
+        compatible = "allwinner,sun4i-a10-sid";
+        reg = <0x01c23800 0x10>;
+    };
+
+  - |
+    sid@1c23800 {
+        compatible = "allwinner,sun7i-a20-sid";
+        reg = <0x01c23800 0x200>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt
deleted file mode 100644 (file)
index cfb18b4..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-Allwinner sunxi-sid
-
-Required properties:
-- compatible: Should be one of the following:
-  "allwinner,sun4i-a10-sid"
-  "allwinner,sun7i-a20-sid"
-  "allwinner,sun8i-a83t-sid"
-  "allwinner,sun8i-h3-sid"
-  "allwinner,sun50i-a64-sid"
-  "allwinner,sun50i-h5-sid"
-  "allwinner,sun50i-h6-sid"
-
-- reg: Should contain registers location and length
-
-= Data cells =
-Are child nodes of sunxi-sid, bindings of which as described in
-bindings/nvmem/nvmem.txt
-
-Example for sun4i:
-       sid@1c23800 {
-               compatible = "allwinner,sun4i-a10-sid";
-               reg = <0x01c23800 0x10>
-       };
-
-Example for sun7i:
-       sid@1c23800 {
-               compatible = "allwinner,sun7i-a20-sid";
-               reg = <0x01c23800 0x200>
-       };
index 68f7d6f..96ffd06 100644 (file)
@@ -15,6 +15,7 @@ Required properties:
        "fsl,imx6sll-ocotp" (i.MX6SLL),
        "fsl,imx7ulp-ocotp" (i.MX7ULP),
        "fsl,imx8mq-ocotp" (i.MX8MQ),
+       "fsl,imx8mm-ocotp" (i.MX8MM),
        followed by "syscon".
 - #address-cells : Should be 1
 - #size-cells : Should be 1
index b9165b7..3abeecf 100644 (file)
@@ -9,7 +9,6 @@ Freescale 83xx and 512x SOCs include the same PCI bridge core.
 
 Example (MPC8313ERDB)
        pci0: pci@e0008500 {
-               cell-index = <1>;
                interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
                interrupt-map = <
                                /* IDSEL 0x0E -mini PCI */
diff --git a/Documentation/devicetree/bindings/phy/mixel,mipi-dsi-phy.txt b/Documentation/devicetree/bindings/phy/mixel,mipi-dsi-phy.txt
new file mode 100644 (file)
index 0000000..9b23407
--- /dev/null
@@ -0,0 +1,29 @@
+Mixel DSI PHY for i.MX8
+
+The Mixel MIPI-DSI PHY IP block is e.g. found on i.MX8 platforms (along the
+MIPI-DSI IP from Northwest Logic). It represents the physical layer for the
+electrical signals for DSI.
+
+Required properties:
+- compatible: Must be:
+  - "fsl,imx8mq-mipi-dphy"
+- clocks: Must contain an entry for each entry in clock-names.
+- clock-names: Must contain the following entries:
+  - "phy_ref": phandle and specifier referring to the DPHY ref clock
+- reg: the register range of the PHY controller
+- #phy-cells: number of cells in PHY, as defined in
+  Documentation/devicetree/bindings/phy/phy-bindings.txt
+  this must be <0>
+
+Optional properties:
+- power-domains: phandle to power domain
+
+Example:
+       dphy: dphy@30a0030 {
+               compatible = "fsl,imx8mq-mipi-dphy";
+               clocks = <&clk IMX8MQ_CLK_DSI_PHY_REF>;
+               clock-names = "phy_ref";
+               reg = <0x30a00300 0x100>;
+               power-domains = <&pd_mipi0>;
+               #phy-cells = <0>;
+        };
index 6ac98b3..c9f5c0c 100644 (file)
@@ -7,6 +7,7 @@ Required properties:
        * "fsl,imx6sl-usbphy" for imx6sl
        * "fsl,vf610-usbphy" for Vybrid vf610
        * "fsl,imx6sx-usbphy" for imx6sx
+       * "fsl,imx7ulp-usbphy" for imx7ulp
   "fsl,imx23-usbphy" is still a fallback for other strings
 - reg: Should contain registers location and length
 - interrupts: Should contain phy interrupt
@@ -23,7 +24,7 @@ Optional properties:
   the 17.78mA TX reference current. Default: 100
 
 Example:
-usbphy1: usbphy@20c9000 {
+usbphy1: usb-phy@20c9000 {
        compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy";
        reg = <0x020c9000 0x1000>;
        interrupts = <0 44 0x04>;
index daedb15..9fb682e 100644 (file)
@@ -42,6 +42,18 @@ Required properties:
 - reset-names: Must include the following entries:
   - "padctl"
 
+For Tegra124:
+- avdd-pll-utmip-supply: UTMI PLL power supply. Must supply 1.8 V.
+- avdd-pll-erefe-supply: PLLE reference PLL power supply. Must supply 1.05 V.
+- avdd-pex-pll-supply: PCIe/USB3 PLL power supply. Must supply 1.05 V.
+- hvdd-pex-pll-e-supply: High-voltage PLLE power supply. Must supply 3.3 V.
+
+For Tegra210:
+- avdd-pll-utmip-supply: UTMI PLL power supply. Must supply 1.8 V.
+- avdd-pll-uerefe-supply: PLLE reference PLL power supply. Must supply 1.05 V.
+- dvdd-pex-pll-supply: PCIe/USB3 PLL power supply. Must supply 1.05 V.
+- hvdd-pex-pll-e-supply: High-voltage PLLE power supply. Must supply 1.8 V.
+
 For Tegra186:
 - avdd-pll-erefeut-supply: UPHY brick and reference clock as well as UTMI PHY
   power supply. Must supply 1.8 V.
diff --git a/Documentation/devicetree/bindings/phy/phy-pxa-usb.txt b/Documentation/devicetree/bindings/phy/phy-pxa-usb.txt
new file mode 100644 (file)
index 0000000..93fc09c
--- /dev/null
@@ -0,0 +1,18 @@
+Marvell PXA USB PHY
+-------------------
+
+Required properties:
+- compatible: one of: "marvell,mmp2-usb-phy", "marvell,pxa910-usb-phy",
+       "marvell,pxa168-usb-phy",
+- #phy-cells: must be 0
+
+Example:
+       usb-phy: usbphy@d4207000 {
+               compatible = "marvell,mmp2-usb-phy";
+               reg = <0xd4207000 0x40>;
+               #phy-cells = <0>;
+               status = "okay";
+       };
+
+This document explains the device tree binding. For general
+information about PHY subsystem refer to Documentation/phy.txt
diff --git a/Documentation/devicetree/bindings/phy/qcom-pcie2-phy.txt b/Documentation/devicetree/bindings/phy/qcom-pcie2-phy.txt
new file mode 100644 (file)
index 0000000..3006425
--- /dev/null
@@ -0,0 +1,42 @@
+Qualcomm PCIe2 PHY controller
+=============================
+
+The Qualcomm PCIe2 PHY is a Synopsys based phy found in a number of Qualcomm
+platforms.
+
+Required properties:
+ - compatible: compatible list, should be:
+              "qcom,qcs404-pcie2-phy", "qcom,pcie2-phy"
+
+ - reg: offset and length of the PHY register set.
+ - #phy-cells: must be 0.
+
+ - clocks: a clock-specifier pair for the "pipe" clock
+
+ - vdda-vp-supply: phandle to low voltage regulator
+ - vdda-vph-supply: phandle to high voltage regulator
+
+ - resets: reset-specifier pairs for the "phy" and "pipe" resets
+ - reset-names: list of resets, should contain:
+               "phy" and "pipe"
+
+ - clock-output-names: name of the outgoing clock signal from the PHY PLL
+ - #clock-cells: must be 0
+
+Example:
+ phy@7786000 {
+       compatible = "qcom,qcs404-pcie2-phy", "qcom,pcie2-phy";
+       reg = <0x07786000 0xb8>;
+
+       clocks = <&gcc GCC_PCIE_0_PIPE_CLK>;
+       resets = <&gcc GCC_PCIEPHY_0_PHY_BCR>,
+                <&gcc GCC_PCIE_0_PIPE_ARES>;
+       reset-names = "phy", "pipe";
+
+       vdda-vp-supply = <&vreg_l3_1p05>;
+       vdda-vph-supply = <&vreg_l5_1p8>;
+
+       clock-output-names = "pcie_0_pipe_clk";
+       #clock-cells = <0>;
+       #phy-cells = <0>;
+ };
index d46188f..503a8cf 100644 (file)
@@ -1,10 +1,12 @@
 * Renesas R-Car generation 3 USB 2.0 PHY
 
 This file provides information on what the device node for the R-Car generation
-3, RZ/G1C and RZ/G2 USB 2.0 PHY contain.
+3, RZ/G1C, RZ/G2 and RZ/A2 USB 2.0 PHY contain.
 
 Required properties:
-- compatible: "renesas,usb2-phy-r8a77470" if the device is a part of an R8A77470
+- compatible: "renesas,usb2-phy-r7s9210" if the device is a part of an R7S9210
+             SoC.
+             "renesas,usb2-phy-r8a77470" if the device is a part of an R8A77470
              SoC.
              "renesas,usb2-phy-r8a774a1" if the device is a part of an R8A774A1
              SoC.
@@ -20,8 +22,8 @@ Required properties:
              R8A77990 SoC.
              "renesas,usb2-phy-r8a77995" if the device is a part of an
              R8A77995 SoC.
-             "renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 or RZ/G2
-             compatible device.
+             "renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3, RZ/G2 or
+             RZ/A2 compatible device.
 
              When compatible with the generic version, nodes must list the
              SoC-specific version corresponding to the platform first
@@ -46,6 +48,9 @@ channel as USB OTG:
               regulator will be managed during the PHY power on/off sequence.
 - renesas,no-otg-pins: boolean, specify when a board does not provide proper
                       otg pins.
+- dr_mode: string, indicates the working mode for the PHY. Can be "host",
+           "peripheral", or "otg". Should be set if otg controller is not used.
+
 
 Example (R-Car H3):
 
index cf96b7c..328585c 100644 (file)
@@ -24,6 +24,8 @@ Required properties:
   "allwinner,sun8i-h3-pinctrl"
   "allwinner,sun8i-h3-r-pinctrl"
   "allwinner,sun8i-r40-pinctrl"
+  "allwinner,sun8i-v3-pinctrl"
+  "allwinner,sun8i-v3s-pinctrl"
   "allwinner,sun50i-a64-pinctrl"
   "allwinner,sun50i-a64-r-pinctrl"
   "allwinner,sun50i-h5-pinctrl"
diff --git a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml
new file mode 100644 (file)
index 0000000..61a110a
--- /dev/null
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/aspeed,ast2400-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ASPEED AST2400 Pin Controller
+
+maintainers:
+  - Andrew Jeffery <andrew@aj.id.au>
+
+description: |+
+  The pin controller node should be the child of a syscon node with the
+  required property:
+
+  - compatible:     Should be one of the following:
+                    "aspeed,ast2400-scu", "syscon", "simple-mfd"
+                    "aspeed,g4-scu", "syscon", "simple-mfd"
+
+  Refer to the the bindings described in
+  Documentation/devicetree/bindings/mfd/syscon.txt
+
+properties:
+  compatible:
+    enum: [ aspeed,ast2400-pinctrl, aspeed,g4-pinctrl ]
+
+patternProperties:
+  '^.*$':
+    if:
+      type: object
+    then:
+      patternProperties:
+        "^function|groups$":
+          allOf:
+            - $ref: "/schemas/types.yaml#/definitions/string"
+            - enum: [ "ACPI", "ADC0", "ADC1", "ADC10", "ADC11", "ADC12", "ADC13",
+              "ADC14", "ADC15", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC7",
+              "ADC8", "ADC9", "BMCINT", "DDCCLK", "DDCDAT", "EXTRST", "FLACK",
+              "FLBUSY", "FLWP", "GPID", "GPID0", "GPID2", "GPID4", "GPID6",
+              "GPIE0", "GPIE2", "GPIE4", "GPIE6", "I2C10", "I2C11", "I2C12",
+              "I2C13", "I2C14", "I2C3", "I2C4", "I2C5", "I2C6", "I2C7", "I2C8",
+              "I2C9", "LPCPD", "LPCPME", "LPCRST", "LPCSMI", "MAC1LINK",
+              "MAC2LINK", "MDIO1", "MDIO2", "NCTS1", "NCTS2", "NCTS3", "NCTS4",
+              "NDCD1", "NDCD2", "NDCD3", "NDCD4", "NDSR1", "NDSR2", "NDSR3",
+              "NDSR4", "NDTR1", "NDTR2", "NDTR3", "NDTR4", "NDTS4", "NRI1",
+              "NRI2", "NRI3", "NRI4", "NRTS1", "NRTS2", "NRTS3", "OSCCLK",
+              "PWM0", "PWM1", "PWM2", "PWM3", "PWM4", "PWM5", "PWM6", "PWM7",
+              "RGMII1", "RGMII2", "RMII1", "RMII2", "ROM16", "ROM8", "ROMCS1",
+              "ROMCS2", "ROMCS3", "ROMCS4", "RXD1", "RXD2", "RXD3", "RXD4",
+              "SALT1", "SALT2", "SALT3", "SALT4", "SD1", "SD2", "SGPMCK",
+              "SGPMI", "SGPMLD", "SGPMO", "SGPSCK", "SGPSI0", "SGPSI1", "SGPSLD",
+              "SIOONCTRL", "SIOPBI", "SIOPBO", "SIOPWREQ", "SIOPWRGD", "SIOS3",
+              "SIOS5", "SIOSCI", "SPI1", "SPI1DEBUG", "SPI1PASSTHRU", "SPICS1",
+              "TIMER3", "TIMER4", "TIMER5", "TIMER6", "TIMER7", "TIMER8", "TXD1",
+              "TXD2", "TXD3", "TXD4", "UART6", "USB11D1", "USB11H2", "USB2D1",
+              "USB2H1", "USBCKI", "VGABIOS_ROM", "VGAHS", "VGAVS", "VPI18",
+              "VPI24", "VPI30", "VPO12", "VPO24", "WDTRST1", "WDTRST2" ]
+
+required:
+  - compatible
+
+examples:
+  - |
+    syscon: scu@1e6e2000 {
+        compatible = "aspeed,ast2400-scu", "syscon", "simple-mfd";
+        reg = <0x1e6e2000 0x1a8>;
+
+        pinctrl: pinctrl {
+            compatible = "aspeed,g4-pinctrl";
+
+            pinctrl_i2c3_default: i2c3_default {
+                function = "I2C3";
+                groups = "I2C3";
+            };
+
+            pinctrl_gpioh0_unbiased_default: gpioh0 {
+                pins = "A8";
+                bias-disable;
+            };
+        };
+    };
diff --git a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml
new file mode 100644 (file)
index 0000000..cf561bd
--- /dev/null
@@ -0,0 +1,134 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/aspeed,ast2500-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ASPEED AST2500 Pin Controller
+
+maintainers:
+  - Andrew Jeffery <andrew@aj.id.au>
+
+description: |+
+  The pin controller node should be the child of a syscon node with the
+  required property:
+
+  - compatible:        Should be one of the following:
+                       "aspeed,ast2500-scu", "syscon", "simple-mfd"
+                       "aspeed,g5-scu", "syscon", "simple-mfd"
+
+  Refer to the the bindings described in
+  Documentation/devicetree/bindings/mfd/syscon.txt
+
+properties:
+  compatible:
+    enum: [ aspeed,ast2500-pinctrl, aspeed,g5-pinctrl ]
+  aspeed,external-nodes:
+    minItems: 2
+    maxItems: 2
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/phandle-array
+    description: |
+      A cell of phandles to external controller nodes:
+      0: compatible with "aspeed,ast2500-gfx", "syscon"
+      1: compatible with "aspeed,ast2500-lhc", "syscon"
+
+patternProperties:
+  '^.*$':
+    if:
+      type: object
+    then:
+      patternProperties:
+        "^function|groups$":
+          allOf:
+            - $ref: "/schemas/types.yaml#/definitions/string"
+            - enum: [ "ACPI", "ADC0", "ADC1", "ADC10", "ADC11", "ADC12", "ADC13",
+              "ADC14", "ADC15", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC7",
+              "ADC8", "ADC9", "BMCINT", "DDCCLK", "DDCDAT", "ESPI", "FWSPICS1",
+              "FWSPICS2", "GPID0", "GPID2", "GPID4", "GPID6", "GPIE0", "GPIE2",
+              "GPIE4", "GPIE6", "I2C10", "I2C11", "I2C12", "I2C13", "I2C14",
+              "I2C3", "I2C4", "I2C5", "I2C6", "I2C7", "I2C8", "I2C9", "LAD0",
+              "LAD1", "LAD2", "LAD3", "LCLK", "LFRAME", "LPCHC", "LPCPD",
+              "LPCPLUS", "LPCPME", "LPCRST", "LPCSMI", "LSIRQ", "MAC1LINK",
+              "MAC2LINK", "MDIO1", "MDIO2", "NCTS1", "NCTS2", "NCTS3", "NCTS4",
+              "NDCD1", "NDCD2", "NDCD3", "NDCD4", "NDSR1", "NDSR2", "NDSR3",
+              "NDSR4", "NDTR1", "NDTR2", "NDTR3", "NDTR4", "NRI1", "NRI2",
+              "NRI3", "NRI4", "NRTS1", "NRTS2", "NRTS3", "NRTS4", "OSCCLK",
+              "PEWAKE", "PNOR", "PWM0", "PWM1", "PWM2", "PWM3", "PWM4", "PWM5",
+              "PWM6", "PWM7", "RGMII1", "RGMII2", "RMII1", "RMII2", "RXD1",
+              "RXD2", "RXD3", "RXD4", "SALT1", "SALT10", "SALT11", "SALT12",
+              "SALT13", "SALT14", "SALT2", "SALT3", "SALT4", "SALT5", "SALT6",
+              "SALT7", "SALT8", "SALT9", "SCL1", "SCL2", "SD1", "SD2", "SDA1",
+              "SDA2", "SGPS1", "SGPS2", "SIOONCTRL", "SIOPBI", "SIOPBO",
+              "SIOPWREQ", "SIOPWRGD", "SIOS3", "SIOS5", "SIOSCI", "SPI1",
+              "SPI1CS1", "SPI1DEBUG", "SPI1PASSTHRU", "SPI2CK", "SPI2CS0",
+              "SPI2CS1", "SPI2MISO", "SPI2MOSI", "TIMER3", "TIMER4", "TIMER5",
+              "TIMER6", "TIMER7", "TIMER8", "TXD1", "TXD2", "TXD3", "TXD4",
+              "UART6", "USB11BHID", "USB2AD", "USB2AH", "USB2BD", "USB2BH",
+              "USBCKI", "VGABIOSROM", "VGAHS", "VGAVS", "VPI24", "VPO",
+              "WDTRST1", "WDTRST2", ]
+
+required:
+  - compatible
+  - aspeed,external-nodes
+
+examples:
+  - |
+    compatible = "simple-bus";
+    ranges;
+
+    apb {
+        compatible = "simple-bus";
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges;
+
+        syscon: scu@1e6e2000 {
+            compatible = "aspeed,ast2500-scu", "syscon", "simple-mfd";
+            reg = <0x1e6e2000 0x1a8>;
+
+            pinctrl: pinctrl {
+                compatible = "aspeed,g5-pinctrl";
+                aspeed,external-nodes = <&gfx &lhc>;
+
+                pinctrl_i2c3_default: i2c3_default {
+                    function = "I2C3";
+                    groups = "I2C3";
+                };
+
+                pinctrl_gpioh0_unbiased_default: gpioh0 {
+                    pins = "A18";
+                    bias-disable;
+                };
+            };
+        };
+
+        gfx: display@1e6e6000 {
+            compatible = "aspeed,ast2500-gfx", "syscon";
+            reg = <0x1e6e6000 0x1000>;
+        };
+    };
+
+    lpc: lpc@1e789000 {
+        compatible = "aspeed,ast2500-lpc", "simple-mfd";
+        reg = <0x1e789000 0x1000>;
+
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges = <0x0 0x1e789000 0x1000>;
+
+        lpc_host: lpc-host@80 {
+            compatible = "aspeed,ast2500-lpc-host", "simple-mfd", "syscon";
+            reg = <0x80 0x1e0>;
+            reg-io-width = <4>;
+
+            #address-cells = <1>;
+            #size-cells = <1>;
+            ranges = <0x0 0x80 0x1e0>;
+
+            lhc: lhc@20 {
+                   compatible = "aspeed,ast2500-lhc";
+                   reg = <0x20 0x24 0x48 0x8>;
+            };
+        };
+    };
index ed34bb1..4980776 100644 (file)
@@ -14,7 +14,8 @@ phrase "pin configuration node".
 The pin configuration nodes act as a container for an arbitrary number of
 subnodes. Each of these subnodes represents some desired configuration for a
 pin, a group, or a list of pins or groups. This configuration for BM1880 SoC
-includes only pinmux as there is no pinconf support available in SoC.
+includes pinmux and various pin configuration parameters, such as pull-up,
+slew rate etc...
 
 Each configuration node can consist of multiple nodes describing the pinmux
 options. The name of each subnode is not important; all subnodes should be
@@ -84,10 +85,37 @@ Required Properties:
                   gpio66, gpio67, eth1, i2s0, i2s0_mclkin, i2s1, i2s1_mclkin,
                   spi0
 
+Optional Properties:
+
+- bias-disable:  No arguments. Disable pin bias.
+- bias-pull-down: No arguments. The specified pins should be configured as
+                  pull down.
+- bias-pull-up:   No arguments. The specified pins should be configured as
+                  pull up.
+- input-schmitt-enable: No arguments: Enable schmitt trigger for the specified
+                  pins
+- input-schmitt-disable: No arguments: Disable schmitt trigger for the specified
+                  pins
+- slew-rate:      Integer. Sets slew rate for the specified pins.
+                  Valid values are:
+                  <0>  - Slow
+                  <1>  - Fast
+- drive-strength: Integer. Selects the drive strength for the specified
+                  pins in mA.
+                  Valid values are:
+                  <4>
+                  <8>
+                  <12>
+                  <16>
+                  <20>
+                  <24>
+                  <28>
+                  <32>
+
 Example:
-        pinctrl: pinctrl@50 {
+        pinctrl: pinctrl@400 {
                 compatible = "bitmain,bm1880-pinctrl";
-                reg = <0x50 0x4B0>;
+                reg = <0x400 0x120>;
 
                 pinctrl_uart0_default: uart0-default {
                         pinmux {
index 3fac0a0..ac6d614 100644 (file)
@@ -5,6 +5,9 @@ controller, and pinmux/control device.
 
 Required properties:
 - compatible: "brcm,bcm2835-gpio"
+- compatible: should be one of:
+  "brcm,bcm2835-gpio" - BCM2835 compatible pinctrl
+  "brcm,bcm7211-gpio" - BCM7211 compatible pinctrl
 - reg: Should contain the physical address of the GPIO module's registers.
 - gpio-controller: Marks the device node as a GPIO controller.
 - #gpio-cells : Should be two. The first cell is the pin number and the
index 524a16f..e4e01c0 100644 (file)
@@ -12,7 +12,7 @@ Required properties in sub-nodes:
 - fsl,pins: each entry consists of 6 integers and represents the mux and config
   setting for one pin.  The first 5 integers <mux_reg conf_reg input_reg mux_val
   input_val> are specified using a PIN_FUNC_ID macro, which can be found in
-  <dt-bindings/pinctrl/imx8mm-pinfunc.h>. The last integer CONFIG is
+  <arch/arm64/boot/dts/freescale/imx8mm-pinfunc.h>. The last integer CONFIG is
   the pad setting value like pull-up on this pin.  Please refer to i.MX8M Mini
   Reference Manual for detailed CONFIG settings.
 
diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx8mn-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx8mn-pinctrl.txt
new file mode 100644 (file)
index 0000000..330716c
--- /dev/null
@@ -0,0 +1,39 @@
+* Freescale IMX8MN IOMUX Controller
+
+Please refer to fsl,imx-pinctrl.txt and pinctrl-bindings.txt in this directory
+for common binding part and usage.
+
+Required properties:
+- compatible: "fsl,imx8mn-iomuxc"
+- reg: should contain the base physical address and size of the iomuxc
+  registers.
+
+Required properties in sub-nodes:
+- fsl,pins: each entry consists of 6 integers and represents the mux and config
+  setting for one pin.  The first 5 integers <mux_reg conf_reg input_reg mux_val
+  input_val> are specified using a PIN_FUNC_ID macro, which can be found in
+  <arch/arm64/boot/dts/freescale/imx8mn-pinfunc.h>. The last integer CONFIG is
+  the pad setting value like pull-up on this pin. Please refer to i.MX8M Nano
+  Reference Manual for detailed CONFIG settings.
+
+Examples:
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+};
+
+iomuxc: pinctrl@30330000 {
+        compatible = "fsl,imx8mn-iomuxc";
+        reg = <0x0 0x30330000 0x0 0x10000>;
+
+        pinctrl_uart1: uart1grp {
+                fsl,pins = <
+                       MX8MN_IOMUXC_UART1_RXD_UART1_DCE_RX     0x140
+                       MX8MN_IOMUXC_UART1_TXD_UART1_DCE_TX     0x140
+                       MX8MN_IOMUXC_UART3_RXD_UART1_DCE_CTS_B  0x140
+                       MX8MN_IOMUXC_UART3_TXD_UART1_DCE_RTS_B  0x140
+                       MX8MN_IOMUXC_SD1_DATA4_GPIO2_IO6        0x19
+                >;
+        };
+};
index 6c0ea15..2932f17 100644 (file)
@@ -6,8 +6,8 @@ part and usage.
 Required properties:
 - compatible: "marvell,88f6180-pinctrl",
               "marvell,88f6190-pinctrl", "marvell,88f6192-pinctrl",
-              "marvell,88f6281-pinctrl", "marvell,88f6282-pinctrl"
-              "marvell,98dx4122-pinctrl"
+              "marvell,88f6281-pinctrl", "marvell,88f6282-pinctrl",
+              "marvell,98dx4122-pinctrl", "marvell,98dx1135-pinctrl"
 - reg: register specifier of MPP registers
 
 This driver supports all kirkwood variants, i.e. 88f6180, 88f619x, and 88f628x.
@@ -317,3 +317,43 @@ mpp44         44       gpio
 mpp45         45       gpio
 mpp49         49       gpio
 
+* Marvell Poncat2 98dx1135
+
+name          pins     functions
+================================================================================
+
+mpp0          0        gpio, nand(io2), spi(cs)
+mpp1          1        gpo, nand(io3), spi(mosi)
+mpp2          2        gpo, nand(io4), spi(sck)
+mpp3          3        gpo, nand(io5), spi(miso)
+mpp4          4        gpio, nand(io6), uart0(rxd)
+mpp5          5        gpo, nand(io7), uart0(txd)
+mpp6          6        sysrst(out)
+mpp7          7        gpo, spi(cs)
+mpp8          8        gpio, twsi0(sda), uart1(rts)
+mpp9          9        gpio, twsi(sck), uart1(cts)
+mpp10         10       gpo, uart0(txd)
+mpp11         11       gpio, uart0(rxd)
+mpp13         13       gpio, uart1(txd)
+mpp14         14       gpio, uart1(rxd)
+mpp15         15       gpio, uart0(rts)
+mpp16         16       gpio, uart0(cts)
+mpp17         17       gpio, nand(cle)
+mpp18         18       gpo, nand(io0)
+mpp19         19       gpo, nand(io1)
+mpp20         20       gpio
+mpp21         21       gpio
+mpp22         22       gpio
+mpp23         23       gpio
+mpp24         24       gpio
+mpp25         25       gpio
+mpp26         26       gpio
+mpp27         27       gpio
+mpp28         28       gpio, nand(ren)
+mpp29         29       gpio, nand(wen)
+mpp30         30       gpio
+mpp31         31       gpio
+mpp32         32       gpio
+mpp33         33       gpio
+mpp34         34       gpio, nand(ale)
+mpp35         35       gpio, nand(cen)
index a47dd99..10dc4f7 100644 (file)
@@ -47,9 +47,19 @@ Required properties for pinmux nodes are:
 Required properties for configuration nodes:
  - pins: a list of pin names
 
-Configuration nodes support the generic properties "bias-disable",
-"bias-pull-up" and "bias-pull-down", described in file
-pinctrl-bindings.txt
+Configuration nodes support the following generic properties, as
+described in file pinctrl-bindings.txt:
+ - "bias-disable"
+ - "bias-pull-up"
+ - "bias-pull-down"
+ - "output-enable"
+ - "output-disable"
+ - "output-low"
+ - "output-high"
+
+Optional properties :
+ - drive-strength-microamp: Drive strength for the specified pins in uA.
+                           This property is only valid for G12A and newer.
 
 === Example ===
 
index 29b72e3..51efd20 100644 (file)
@@ -5,7 +5,7 @@ Please refer to pinctrl-bindings.txt, ../gpio/gpio.txt, and
 pin controller, GPIO, and interrupt bindings.
 
 PIC32 'pin configuration node' is a node of a group of pins which can be
-used for a specific device or function. This node represents configuraions of
+used for a specific device or function. This node represents configurations of
 pins, optional function, and optional mux related configuration.
 
 Required properties for pin controller node:
index 83f4bba..a1264cc 100644 (file)
@@ -213,4 +213,4 @@ pinctrl: pinctrl@f0800000 {
                groups = "clkreq";
                function = "clkreq";
        };
-};
\ No newline at end of file
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra194-pinmux.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra194-pinmux.txt
new file mode 100644 (file)
index 0000000..8763f44
--- /dev/null
@@ -0,0 +1,107 @@
+NVIDIA Tegra194 pinmux controller
+
+Required properties:
+- compatible: "nvidia,tegra194-pinmux"
+- reg: Should contain a list of base address and size pairs for:
+  - first entry: The APB_MISC_GP_*_PADCTRL registers (pad control)
+  - second entry: The PINMUX_AUX_* registers (pinmux)
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+Tegra's pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin, a group, or a list of pins or groups. This configuration can include the
+mux function to select on those pin(s)/group(s), and various pin configuration
+parameters, such as pull-up, tristate, drive strength, etc.
+
+See the TRM to determine which properties and values apply to each pin/group.
+Macro values for property values are defined in
+include/dt-binding/pinctrl/pinctrl-tegra.h.
+
+Required subnode-properties:
+- nvidia,pins : An array of strings. Each string contains the name of a pin or
+    group. Valid values for these names are listed below.
+
+Optional subnode-properties:
+- nvidia,function: A string containing the name of the function to mux to the
+    pin or group.
+- nvidia,pull: Integer, representing the pull-down/up to apply to the pin.
+    0: none, 1: down, 2: up.
+- nvidia,tristate: Integer.
+    0: drive, 1: tristate.
+- nvidia,enable-input: Integer. Enable the pin's input path.
+    enable :TEGRA_PIN_ENABLE and
+    disable or output only: TEGRA_PIN_DISABLE.
+- nvidia,open-drain: Integer.
+    enable: TEGRA_PIN_ENABLE.
+    disable: TEGRA_PIN_DISABLE.
+- nvidia,lock: Integer. Lock the pin configuration against further changes
+    until reset.
+    enable: TEGRA_PIN_ENABLE.
+    disable: TEGRA_PIN_DISABLE.
+- nvidia,io-hv: Integer. Select high-voltage receivers.
+    normal: TEGRA_PIN_DISABLE
+    high: TEGRA_PIN_ENABLE
+- nvidia,schmitt: Integer. Enables Schmitt Trigger on the input.
+    normal: TEGRA_PIN_DISABLE
+    high: TEGRA_PIN_ENABLE
+- nvidia,drive-type: Integer. Valid range 0...3.
+- nvidia,pull-down-strength: Integer. Controls drive strength. 0 is weakest.
+    The range of valid values depends on the pingroup. See "CAL_DRVDN" in the
+    Tegra TRM.
+- nvidia,pull-up-strength: Integer. Controls drive strength. 0 is weakest.
+    The range of valid values depends on the pingroup. See "CAL_DRVUP" in the
+    Tegra TRM.
+
+Valid values for pin and group names (nvidia,pin) are:
+
+    These correspond to Tegra PADCTL_* (pinmux) registers.
+
+  Mux groups:
+
+    These correspond to Tegra PADCTL_* (pinmux) registers. Any property
+    that exists in those registers may be set for the following pin names.
+
+    pex_l5_clkreq_n_pgg0, pex_l5_rst_n_pgg1
+
+  Drive groups:
+
+    These registers controls a single pin for which a mux group exists.
+    See the list above for the pin name to use when configuring the pinmux.
+
+    pex_l5_clkreq_n_pgg0, pex_l5_rst_n_pgg1
+
+Valid values for nvidia,functions are:
+
+    pe5
+
+Power Domain:
+    pex_l5_clkreq_n_pgg0 and pex_l5_rst_n_pgg1 are part of PCIE C5 power
+    partition. Client devices must enable this partition before accessing
+    these pins here.
+
+
+Example:
+
+               tegra_pinctrl: pinmux: pinmux@2430000 {
+                       compatible = "nvidia,tegra194-pinmux";
+                       reg = <0x2430000 0x17000
+                              0xc300000 0x4000>;
+
+                       pinctrl-names = "pex_rst";
+                       pinctrl-0 = <&pex_rst_c5_out_state>;
+
+                       pex_rst_c5_out_state: pex_rst_c5_out {
+                               pex_rst {
+                                       nvidia,pins = "pex_l5_rst_n_pgg1";
+                                       nvidia,schmitt = <TEGRA_PIN_DISABLE>;
+                                       nvidia,lpdr = <TEGRA_PIN_ENABLE>;
+                                       nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                                       nvidia,io-high-voltage = <TEGRA_PIN_ENABLE>;
+                                       nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                                       nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               };
+                       };
+               };
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt
deleted file mode 100644 (file)
index 3b7266c..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-======================
-Aspeed Pin Controllers
-======================
-
-The Aspeed SoCs vary in functionality inside a generation but have a common mux
-device register layout.
-
-Required properties for g4:
-- compatible :                         Should be one of the following:
-                               "aspeed,ast2400-pinctrl"
-                               "aspeed,g4-pinctrl"
-
-Required properties for g5:
-- compatible :                         Should be one of the following:
-                               "aspeed,ast2500-pinctrl"
-                               "aspeed,g5-pinctrl"
-
-- aspeed,external-nodes:       A cell of phandles to external controller nodes:
-                               0: compatible with "aspeed,ast2500-gfx", "syscon"
-                               1: compatible with "aspeed,ast2500-lhc", "syscon"
-
-The pin controller node should be the child of a syscon node with the required
-property:
-
-- compatible :                 Should be one of the following:
-                       "aspeed,ast2400-scu", "syscon", "simple-mfd"
-                       "aspeed,g4-scu", "syscon", "simple-mfd"
-                       "aspeed,ast2500-scu", "syscon", "simple-mfd"
-                       "aspeed,g5-scu", "syscon", "simple-mfd"
-
-Refer to the the bindings described in
-Documentation/devicetree/bindings/mfd/syscon.txt
-
-Subnode Format
-==============
-
-The required properties of pinmux child nodes are:
-- function: the mux function to select
-- groups  : the list of groups to select with this function
-
-Required properties of pinconf child nodes are:
-- groups: A list of groups to select (either this or "pins" must be
-          specified)
-- pins  : A list of ball names as strings, eg "D14" (either this or "groups"
-          must be specified)
-
-Optional properties of pinconf child nodes are:
-- bias-disable  : disable any pin bias
-- bias-pull-down: pull down the pin
-- drive-strength: sink or source at most X mA
-
-Definitions are as specified in
-Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt, with any
-further limitations as described above.
-
-For pinmux, each mux function has only one associated pin group. Each group is
-named by its function. The following values for the function and groups
-properties are supported:
-
-aspeed,ast2400-pinctrl, aspeed,g4-pinctrl:
-
-ACPI ADC0 ADC1 ADC10 ADC11 ADC12 ADC13 ADC14 ADC15 ADC2 ADC3 ADC4 ADC5 ADC6
-ADC7 ADC8 ADC9 BMCINT DDCCLK DDCDAT EXTRST FLACK FLBUSY FLWP GPID GPID0 GPID2
-GPID4 GPID6 GPIE0 GPIE2 GPIE4 GPIE6 I2C10 I2C11 I2C12 I2C13 I2C14 I2C3 I2C4
-I2C5 I2C6 I2C7 I2C8 I2C9 LPCPD LPCPME LPCRST LPCSMI MAC1LINK MAC2LINK MDIO1
-MDIO2 NCTS1 NCTS2 NCTS3 NCTS4 NDCD1 NDCD2 NDCD3 NDCD4 NDSR1 NDSR2 NDSR3 NDSR4
-NDTR1 NDTR2 NDTR3 NDTR4 NDTS4 NRI1 NRI2 NRI3 NRI4 NRTS1 NRTS2 NRTS3 OSCCLK PWM0
-PWM1 PWM2 PWM3 PWM4 PWM5 PWM6 PWM7 RGMII1 RGMII2 RMII1 RMII2 ROM16 ROM8 ROMCS1
-ROMCS2 ROMCS3 ROMCS4 RXD1 RXD2 RXD3 RXD4 SALT1 SALT2 SALT3 SALT4 SD1 SD2 SGPMCK
-SGPMI SGPMLD SGPMO SGPSCK SGPSI0 SGPSI1 SGPSLD SIOONCTRL SIOPBI SIOPBO SIOPWREQ
-SIOPWRGD SIOS3 SIOS5 SIOSCI SPI1 SPI1DEBUG SPI1PASSTHRU SPICS1 TIMER3 TIMER4
-TIMER5 TIMER6 TIMER7 TIMER8 TXD1 TXD2 TXD3 TXD4 UART6 USB11D1 USB11H2 USB2D1
-USB2H1 USBCKI VGABIOS_ROM VGAHS VGAVS VPI18 VPI24 VPI30 VPO12 VPO24 WDTRST1
-WDTRST2
-
-aspeed,ast2500-pinctrl, aspeed,g5-pinctrl:
-
-ACPI ADC0 ADC1 ADC10 ADC11 ADC12 ADC13 ADC14 ADC15 ADC2 ADC3 ADC4 ADC5 ADC6
-ADC7 ADC8 ADC9 BMCINT DDCCLK DDCDAT ESPI FWSPICS1 FWSPICS2 GPID0 GPID2 GPID4
-GPID6 GPIE0 GPIE2 GPIE4 GPIE6 I2C10 I2C11 I2C12 I2C13 I2C14 I2C3 I2C4 I2C5 I2C6
-I2C7 I2C8 I2C9 LAD0 LAD1 LAD2 LAD3 LCLK LFRAME LPCHC LPCPD LPCPLUS LPCPME
-LPCRST LPCSMI LSIRQ MAC1LINK MAC2LINK MDIO1 MDIO2 NCTS1 NCTS2 NCTS3 NCTS4 NDCD1
-NDCD2 NDCD3 NDCD4 NDSR1 NDSR2 NDSR3 NDSR4 NDTR1 NDTR2 NDTR3 NDTR4 NRI1 NRI2
-NRI3 NRI4 NRTS1 NRTS2 NRTS3 NRTS4 OSCCLK PEWAKE PNOR PWM0 PWM1 PWM2 PWM3 PWM4
-PWM5 PWM6 PWM7 RGMII1 RGMII2 RMII1 RMII2 RXD1 RXD2 RXD3 RXD4 SALT1 SALT10
-SALT11 SALT12 SALT13 SALT14 SALT2 SALT3 SALT4 SALT5 SALT6 SALT7 SALT8 SALT9
-SCL1 SCL2 SD1 SD2 SDA1 SDA2 SGPS1 SGPS2 SIOONCTRL SIOPBI SIOPBO SIOPWREQ
-SIOPWRGD SIOS3 SIOS5 SIOSCI SPI1 SPI1CS1 SPI1DEBUG SPI1PASSTHRU SPI2CK SPI2CS0
-SPI2CS1 SPI2MISO SPI2MOSI TIMER3 TIMER4 TIMER5 TIMER6 TIMER7 TIMER8 TXD1 TXD2
-TXD3 TXD4 UART6 USB11BHID USB2AD USB2AH USB2BD USB2BH USBCKI VGABIOSROM VGAHS
-VGAVS VPI24 VPO WDTRST1 WDTRST2
-
-Examples
-========
-
-g4 Example
-----------
-
-syscon: scu@1e6e2000 {
-       compatible = "aspeed,ast2400-scu", "syscon", "simple-mfd";
-       reg = <0x1e6e2000 0x1a8>;
-
-       pinctrl: pinctrl {
-               compatible = "aspeed,g4-pinctrl";
-
-               pinctrl_i2c3_default: i2c3_default {
-                       function = "I2C3";
-                       groups = "I2C3";
-               };
-
-               pinctrl_gpioh0_unbiased_default: gpioh0 {
-                       pins = "A8";
-                       bias-disable;
-               };
-       };
-};
-
-g5 Example
-----------
-
-ahb {
-       apb {
-               syscon: scu@1e6e2000 {
-                       compatible = "aspeed,ast2500-scu", "syscon", "simple-mfd";
-                       reg = <0x1e6e2000 0x1a8>;
-
-                       pinctrl: pinctrl {
-                               compatible = "aspeed,g5-pinctrl";
-                               aspeed,external-nodes = <&gfx &lhc>;
-
-                               pinctrl_i2c3_default: i2c3_default {
-                                       function = "I2C3";
-                                       groups = "I2C3";
-                               };
-
-                               pinctrl_gpioh0_unbiased_default: gpioh0 {
-                                       pins = "A18";
-                                       bias-disable;
-                               };
-                       };
-               };
-
-               gfx: display@1e6e6000 {
-                       compatible = "aspeed,ast2500-gfx", "syscon";
-                       reg = <0x1e6e6000 0x1000>;
-               };
-       };
-
-       lpc: lpc@1e789000 {
-               compatible = "aspeed,ast2500-lpc", "simple-mfd";
-               reg = <0x1e789000 0x1000>;
-
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges = <0x0 0x1e789000 0x1000>;
-
-               lpc_host: lpc-host@80 {
-                       compatible = "aspeed,ast2500-lpc-host", "simple-mfd", "syscon";
-                       reg = <0x80 0x1e0>;
-                       reg-io-width = <4>;
-
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       ranges = <0x0 0x80 0x1e0>;
-
-                       lhc: lhc@20 {
-                              compatible = "aspeed,ast2500-lhc";
-                              reg = <0x20 0x24 0x48 0x8>;
-                       };
-               };
-       };
-};
index cef2b58..fcd37e9 100644 (file)
@@ -258,6 +258,7 @@ drive-push-pull             - drive actively high and low
 drive-open-drain       - drive with open drain
 drive-open-source      - drive with open source
 drive-strength         - sink or source at most X mA
+drive-strength-microamp        - sink or source at most X uA
 input-enable           - enable input on pin (no effect on output, such as
                          enabling an input buffer)
 input-disable          - disable input on pin (no effect on output, such as
@@ -326,6 +327,8 @@ arguments are described below.
 
 - drive-strength takes as argument the target strength in mA.
 
+- drive-strength-microamp takes as argument the target strength in uA.
+
 - input-debounce takes the debounce time in usec as argument
   or 0 to disable debouncing
 
index 68e93d5..c978239 100644 (file)
@@ -122,17 +122,17 @@ to specify in a pin configuration subnode:
 - bias-disable:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as no pull.
+       Definition: The specified pins should be configured as no pull.
 
 - bias-pull-down:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull down.
+       Definition: The specified pins should be configured as pull down.
 
 - bias-pull-up:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull up.
+       Definition: The specified pins should be configured as pull up.
 
 - output-high:
        Usage: optional
index 6dd72f8..7b15189 100644 (file)
@@ -118,17 +118,17 @@ to specify in a pin configuration subnode:
 - bias-disable:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as no pull.
+       Definition: The specified pins should be configured as no pull.
 
 - bias-pull-down:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull down.
+       Definition: The specified pins should be configured as pull down.
 
 - bias-pull-up:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull up.
+       Definition: The specified pins should be configured as pull up.
 
 - output-high:
        Usage: optional
index 86ecdcf..d469739 100644 (file)
@@ -97,17 +97,17 @@ to specify in a pin configuration subnode:
 - bias-disable:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as no pull.
+       Definition: The specified pins should be configured as no pull.
 
 - bias-pull-down:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull down.
+       Definition: The specified pins should be configured as pull down.
 
 - bias-pull-up:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull up.
+       Definition: The specified pins should be configured as pull up.
 
 - output-high:
        Usage: optional
index 195a7a0..3354a63 100644 (file)
@@ -130,17 +130,17 @@ to specify in a pin configuration subnode:
 - bias-disable:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as no pull.
+       Definition: The specified pins should be configured as no pull.
 
 - bias-pull-down:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull down.
+       Definition: The specified pins should be configured as pull down.
 
 - bias-pull-up:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull up.
+       Definition: The specified pins should be configured as pull up.
 
 - output-high:
        Usage: optional
index 5034eb6..a7dd213 100644 (file)
@@ -124,17 +124,17 @@ to specify in a pin configuration subnode:
 - bias-disable:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as no pull.
+       Definition: The specified pins should be configured as no pull.
 
 - bias-pull-down:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull down.
+       Definition: The specified pins should be configured as pull down.
 
 - bias-pull-up:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull up.
+       Definition: The specified pins should be configured as pull up.
 
 - output-high:
        Usage: optional
index f15443f..da52df6 100644 (file)
@@ -128,17 +128,17 @@ to specify in a pin configuration subnode:
 - bias-disable:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as no pull.
+       Definition: The specified pins should be configured as no pull.
 
 - bias-pull-down:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull down.
+       Definition: The specified pins should be configured as pull down.
 
 - bias-pull-up:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull up.
+       Definition: The specified pins should be configured as pull up.
 
 - output-high:
        Usage: optional
index fa97f60..a56cb88 100644 (file)
@@ -149,17 +149,17 @@ to specify in a pin configuration subnode:
 - bias-disable:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as no pull.
+       Definition: The specified pins should be configured as no pull.
 
 - bias-pull-down:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull down.
+       Definition: The specified pins should be configured as pull down.
 
 - bias-pull-up:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull up.
+       Definition: The specified pins should be configured as pull up.
 
 - output-high:
        Usage: optional
index e70c79b..cdec1ee 100644 (file)
@@ -40,6 +40,14 @@ MSM8998 platform.
        Definition: must be 2. Specifying the pin number and flags, as defined
                    in <dt-bindings/gpio/gpio.h>
 
+- gpio-ranges:
+       Usage: required
+       Definition:  see ../gpio/gpio.txt
+
+- gpio-reserved-ranges:
+       Usage: optional
+       Definition: see ../gpio/gpio.txt
+
 Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for
 a general description of GPIO and interrupt bindings.
 
@@ -135,17 +143,17 @@ to specify in a pin configuration subnode:
 - bias-disable:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as no pull.
+       Definition: The specified pins should be configured as no pull.
 
 - bias-pull-down:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull down.
+       Definition: The specified pins should be configured as pull down.
 
 - bias-pull-up:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull up.
+       Definition: The specified pins should be configured as pull up.
 
 - output-high:
        Usage: optional
@@ -175,6 +183,8 @@ Example:
                interrupts = <0 208 0>;
                gpio-controller;
                #gpio-cells = <2>;
+               gpio-ranges = <&tlmm 0 0 175>;
+               gpio-reserved-ranges = <0 4>, <81 4>;
                interrupt-controller;
                #interrupt-cells = <2>;
 
index 2b8f777..a50e746 100644 (file)
@@ -150,17 +150,17 @@ to specify in a pin configuration subnode:
 - bias-disable:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as no pull.
+       Definition: The specified pins should be configured as no pull.
 
 - bias-pull-down:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull down.
+       Definition: The specified pins should be configured as pull down.
 
 - bias-pull-up:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull up.
+       Definition: The specified pins should be configured as pull up.
 
 - output-high:
        Usage: optional
index 769ca83..be034d3 100644 (file)
@@ -142,17 +142,17 @@ to specify in a pin configuration subnode:
 - bias-disable:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as no pull.
+       Definition: The specified pins should be configured as no pull.
 
 - bias-pull-down:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull down.
+       Definition: The specified pins should be configured as pull down.
 
 - bias-pull-up:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull up.
+       Definition: The specified pins should be configured as pull up.
 
 - output-high:
        Usage: optional
index 665aadb..7462e37 100644 (file)
@@ -79,7 +79,7 @@ to specify in a pin configuration subnode:
                      gpio0-gpio149
                        Supports mux, bias and drive-strength
 
-                     sdc2_clk, sdc2_cmd, sdc2_data
+                     sdc2_clk, sdc2_cmd, sdc2_data, ufs_reset
                        Supports bias and drive-strength
 
 - function:
@@ -118,17 +118,17 @@ to specify in a pin configuration subnode:
 - bias-disable:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as no pull.
+       Definition: The specified pins should be configured as no pull.
 
 - bias-pull-down:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull down.
+       Definition: The specified pins should be configured as pull down.
 
 - bias-pull-up:
        Usage: optional
        Value type: <none>
-       Definition: The specified pins should be configued as pull up.
+       Definition: The specified pins should be configured as pull up.
 
 - output-high:
        Usage: optional
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl.txt
new file mode 100644 (file)
index 0000000..fa37733
--- /dev/null
@@ -0,0 +1,190 @@
+Qualcomm SM8150 TLMM block
+
+This binding describes the Top Level Mode Multiplexer block found in the
+QCS404 platform.
+
+- compatible:
+       Usage: required
+       Value type: <string>
+       Definition: must be "qcom,sm8150-pinctrl"
+
+- reg:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: the base address and size of the north, south, west
+                   and east TLMM tiles.
+
+- reg-names:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Defintiion: names for the cells of reg, must contain "north", "south"
+                   "west" and "east".
+
+- interrupts:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: should specify the TLMM summary IRQ.
+
+- interrupt-controller:
+       Usage: required
+       Value type: <none>
+       Definition: identifies this node as an interrupt controller
+
+- #interrupt-cells:
+       Usage: required
+       Value type: <u32>
+       Definition: must be 2. Specifying the pin number and flags, as defined
+                   in <dt-bindings/interrupt-controller/irq.h>
+
+- gpio-controller:
+       Usage: required
+       Value type: <none>
+       Definition: identifies this node as a gpio controller
+
+- #gpio-cells:
+       Usage: required
+       Value type: <u32>
+       Definition: must be 2. Specifying the pin number and flags, as defined
+                   in <dt-bindings/gpio/gpio.h>
+
+- gpio-ranges:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition:  see ../gpio/gpio.txt
+
+- gpio-reserved-ranges:
+       Usage: optional
+       Value type: <prop-encoded-array>
+       Definition: see ../gpio/gpio.txt
+
+Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for
+a general description of GPIO and interrupt bindings.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+The pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin, a group, or a list of pins or groups. This configuration can include the
+mux function to select on those pin(s)/group(s), and various pin configuration
+parameters, such as pull-up, drive strength, etc.
+
+
+PIN CONFIGURATION NODES:
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Each subnode only affects those parameters that are explicitly listed. In
+other words, a subnode that lists a mux function but no pin configuration
+parameters implies no information about any pin configuration parameters.
+Similarly, a pin subnode that describes a pullup parameter implies no
+information about e.g. the mux function.
+
+
+The following generic properties as defined in pinctrl-bindings.txt are valid
+to specify in a pin configuration subnode:
+
+- pins:
+       Usage: required
+       Value type: <string-array>
+       Definition: List of gpio pins affected by the properties specified in
+                   this subnode.
+
+                   Valid pins are:
+                     gpio0-gpio149
+                       Supports mux, bias and drive-strength
+
+                     sdc1_clk, sdc1_cmd, sdc1_data sdc2_clk, sdc2_cmd,
+                     sdc2_data sdc1_rclk
+                       Supports bias and drive-strength
+
+                     ufs_reset
+                       Supports bias and drive-strength
+
+- function:
+       Usage: required
+       Value type: <string>
+       Definition: Specify the alternative function to be configured for the
+                   specified pins. Functions are only valid for gpio pins.
+                   Valid values are:
+
+                   adsp_ext, agera_pll, aoss_cti, ddr_pxi2, atest_char,
+                   atest_char0, atest_char1, atest_char2, atest_char3,
+                   audio_ref, atest_usb1, atest_usb2, atest_usb10,
+                   atest_usb11, atest_usb12, atest_usb13, atest_usb20,
+                   atest_usb21, atest_usb22, atest_usb2, atest_usb23,
+                   btfm_slimbus, cam_mclk, cci_async, cci_i2c, cci_timer0,
+                   cci_timer1, cci_timer2, cci_timer3, cci_timer4,
+                   cri_trng, cri_trng0, cri_trng1, dbg_out, ddr_bist,
+                   ddr_pxi0, ddr_pxi1, ddr_pxi3, edp_hot, edp_lcd,
+                   emac_phy, emac_pps, gcc_gp1, gcc_gp2, gcc_gp3, gpio,
+                   hs1_mi2s, hs2_mi2s, hs3_mi2s, jitter_bist,
+                   lpass_slimbus, mdp_vsync, mdp_vsync0, mdp_vsync1,
+                   mdp_vsync2, mdp_vsync3, mss_lte, m_voc, nav_pps,
+                   pa_indicator, pci_e0, phase_flag, pll_bypassnl,
+                   pll_bist, pci_e1, pll_reset, pri_mi2s, pri_mi2s_ws,
+                   prng_rosc, qdss, qdss_cti, qlink_request, qlink_enable,
+                   qspi0, qspi1, qspi2, qspi3, qspi_clk, qspi_cs, qua_mi2s,
+                   qup0, qup1, qup2, qup3, qup4, qup5, qup6, qup7, qup8,
+                   qup9, qup10, qup11, qup12, qup13, qup14, qup15, qup16,
+                   qup17, qup18, qup19, qup_l4, qup_l5, qup_l6, rgmii,
+                   sdc4, sd_write, sec_mi2s, spkr_i2s, sp_cmu, ter_mi2s,
+                   tgu_ch0, tgu_ch1, tgu_ch2, tgu_ch3, tsense_pwm1,
+                   tsense_pwm2, tsif1, tsif2, uim1, uim2, uim_batt,
+                   usb2phy_ac, usb_phy, vfr_1, vsense_trigger, wlan1_adc0,
+                   wlan1_adc1, wlan2_adc0, wlan2_adc1, wmss_reset
+
+- bias-disable:
+       Usage: optional
+       Value type: <none>
+       Definition: The specified pins should be configued as no pull.
+
+- bias-pull-down:
+       Usage: optional
+       Value type: <none>
+       Definition: The specified pins should be configued as pull down.
+
+- bias-pull-up:
+       Usage: optional
+       Value type: <none>
+       Definition: The specified pins should be configued as pull up.
+
+- output-high:
+       Usage: optional
+       Value type: <none>
+       Definition: The specified pins are configured in output mode, driven
+                   high.
+                   Not valid for sdc pins.
+
+- output-low:
+       Usage: optional
+       Value type: <none>
+       Definition: The specified pins are configured in output mode, driven
+                   low.
+                   Not valid for sdc pins.
+
+- drive-strength:
+       Usage: optional
+       Value type: <u32>
+       Definition: Selects the drive strength for the specified pins, in mA.
+                   Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16
+
+Example:
+
+       tlmm: pinctrl@3000000 {
+               compatible = "qcom,sm8150-pinctrl";
+               reg = <0x03100000 0x300000>,
+                     <0x03500000 0x300000>,
+                     <0x03900000 0x300000>,
+                     <0x03D00000 0x300000>;
+               reg-names = "west", "east", "north", "south";
+               interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               gpio-ranges = <&tlmm 0 0 175>;
+               gpio-reserved-ranges = <0 4>, <126 4>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
+       };
diff --git a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt
deleted file mode 100644 (file)
index 0016925..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-* STM32 GPIO and Pin Mux/Config controller
-
-STMicroelectronics's STM32 MCUs intregrate a GPIO and Pin mux/config hardware
-controller. It controls the input/output settings on the available pins and
-also provides ability to multiplex and configure the output of various on-chip
-controllers onto these pads.
-
-Pin controller node:
-Required properies:
- - compatible: value should be one of the following:
-   "st,stm32f429-pinctrl"
-   "st,stm32f469-pinctrl"
-   "st,stm32f746-pinctrl"
-   "st,stm32f769-pinctrl"
-   "st,stm32h743-pinctrl"
-   "st,stm32mp157-pinctrl"
-   "st,stm32mp157-z-pinctrl"
- - #address-cells: The value of this property must be 1
- - #size-cells : The value of this property must be 1
- - ranges      : defines mapping between pin controller node (parent) to
-   gpio-bank node (children).
- - pins-are-numbered: Specify the subnodes are using numbered pinmux to
-   specify pins.
-
-GPIO controller/bank node:
-Required properties:
- - gpio-controller : Indicates this device is a GPIO controller
- - #gpio-cells   : Should be two.
-                       The first cell is the pin number
-                       The second one is the polarity:
-                               - 0 for active high
-                               - 1 for active low
- - reg           : The gpio address range, relative to the pinctrl range
- - clocks        : clock that drives this bank
- - st,bank-name          : Should be a name string for this bank as specified in
-   the datasheet
-
-Optional properties:
- - reset:        : Reference to the reset controller
- - st,syscfg: Should be phandle/offset/mask.
-       -The phandle to the syscon node which includes IRQ mux selection register.
-       -The offset of the IRQ mux selection register
-       -The field mask of IRQ mux, needed if different of 0xf.
- - gpio-ranges: Define a dedicated mapping between a pin-controller and
-   a gpio controller. Format is <&phandle a b c> with:
-       -(phandle): phandle of pin-controller.
-       -(a): gpio base offset in range.
-       -(b): pin base offset in range.
-       -(c): gpio count in range
-   This entry has to be used either if there are holes inside a bank:
-       GPIOB0/B1/B2/B14/B15 (see example 2)
-   or if banks are not contiguous:
-       GPIOA/B/C/E...
-   NOTE: If "gpio-ranges" is used for a gpio controller, all gpio-controller
-   have to use a "gpio-ranges" entry.
-   More details in Documentation/devicetree/bindings/gpio/gpio.txt.
- - st,bank-ioport: should correspond to the EXTI IOport selection (EXTI line
-   used to select GPIOs as interrupts).
- - hwlocks: reference to a phandle of a hardware spinlock provider node.
- - st,package: Indicates the SOC package used.
-   More details in include/dt-bindings/pinctrl/stm32-pinfunc.h
-
-Example 1:
-#include <dt-bindings/pinctrl/stm32f429-pinfunc.h>
-...
-
-       pin-controller {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "st,stm32f429-pinctrl";
-               ranges = <0 0x40020000 0x3000>;
-               pins-are-numbered;
-
-               gpioa: gpio@40020000 {
-                       gpio-controller;
-                       #gpio-cells = <2>;
-                       reg = <0x0 0x400>;
-                       resets = <&reset_ahb1 0>;
-                       st,bank-name = "GPIOA";
-               };
-               ...
-               pin-functions nodes follow...
-       };
-
-Example 2:
-#include <dt-bindings/pinctrl/stm32f429-pinfunc.h>
-...
-
-       pinctrl: pin-controller {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "st,stm32f429-pinctrl";
-               ranges = <0 0x40020000 0x3000>;
-               pins-are-numbered;
-
-               gpioa: gpio@40020000 {
-                       gpio-controller;
-                       #gpio-cells = <2>;
-                       reg = <0x0 0x400>;
-                       resets = <&reset_ahb1 0>;
-                       st,bank-name = "GPIOA";
-                       gpio-ranges = <&pinctrl 0 0 16>;
-               };
-
-               gpiob: gpio@40020400 {
-                       gpio-controller;
-                       #gpio-cells = <2>;
-                       reg = <0x0 0x400>;
-                       resets = <&reset_ahb1 0>;
-                       st,bank-name = "GPIOB";
-                       ngpios = 4;
-                       gpio-ranges = <&pinctrl 0 16 3>,
-                                     <&pinctrl 14 30 2>;
-               };
-
-
-               ...
-               pin-functions nodes follow...
-       };
-
-
-Contents of function subnode node:
-----------------------------------
-Subnode format
-A pinctrl node should contain at least one subnode representing the
-pinctrl group available on the machine. Each subnode will list the
-pins it needs, and how they should be configured, with regard to muxer
-configuration, pullups, drive, output high/low and output speed.
-
-    node {
-       pinmux = <PIN_NUMBER_PINMUX>;
-       GENERIC_PINCONFIG;
-    };
-
-Required properties:
-- pinmux: integer array, represents gpio pin number and mux setting.
-  Supported pin number and mux varies for different SoCs, and are defined in
-  dt-bindings/pinctrl/<soc>-pinfunc.h directly.
-  These defines are calculated as:
-    ((port * 16 + line) << 8) | function
-  With:
-    - port: The gpio port index (PA = 0, PB = 1, ..., PK = 11)
-    - line: The line offset within the port (PA0 = 0, PA1 = 1, ..., PA15 = 15)
-    - function: The function number, can be:
-      * 0 : GPIO
-      * 1 : Alternate Function 0
-      * 2 : Alternate Function 1
-      * 3 : Alternate Function 2
-      * ...
-      * 16 : Alternate Function 15
-      * 17 : Analog
-
-  To simplify the usage, macro is available to generate "pinmux" field.
-  This macro is available here:
-    - include/dt-bindings/pinctrl/stm32-pinfunc.h
-
-  Some examples of using macro:
-    /* GPIO A9 set as alernate function 2 */
-    ... {
-               pinmux = <STM32_PINMUX('A', 9, AF2)>;
-    };
-    /* GPIO A9 set as GPIO  */
-    ... {
-               pinmux = <STM32_PINMUX('A', 9, GPIO)>;
-    };
-    /* GPIO A9 set as analog */
-    ... {
-               pinmux = <STM32_PINMUX('A', 9, ANALOG)>;
-    };
-
-Optional properties:
-- GENERIC_PINCONFIG: is the generic pinconfig options to use.
-  Available options are:
-   - bias-disable,
-   - bias-pull-down,
-   - bias-pull-up,
-   - drive-push-pull,
-   - drive-open-drain,
-   - output-low
-   - output-high
-   - slew-rate = <x>, with x being:
-       < 0 > : Low speed
-       < 1 > : Medium speed
-       < 2 > : Fast speed
-       < 3 > : High speed
-
-Example:
-
-pin-controller {
-...
-       usart1_pins_a: usart1@0 {
-               pins1 {
-                       pinmux = <STM32_PINMUX('A', 9, AF7)>;
-                       bias-disable;
-                       drive-push-pull;
-                       slew-rate = <0>;
-               };
-               pins2 {
-                       pinmux = <STM32_PINMUX('A', 10, AF7)>;
-                       bias-disable;
-               };
-       };
-};
-
-&usart1 {
-       pinctrl-0 = <&usart1_pins_a>;
-       pinctrl-names = "default";
-};
diff --git a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml
new file mode 100644 (file)
index 0000000..06c4b66
--- /dev/null
@@ -0,0 +1,264 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (C) STMicroelectronics 2019.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/st,stm32-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STM32 GPIO and Pin Mux/Config controller
+
+maintainers:
+  - Alexandre TORGUE <alexandre.torgue@st.com>
+
+description: |
+  STMicroelectronics's STM32 MCUs intregrate a GPIO and Pin mux/config hardware
+  controller. It controls the input/output settings on the available pins and
+  also provides ability to multiplex and configure the output of various
+  on-chip controllers onto these pads.
+
+properties:
+  compatible:
+    enum:
+      - st,stm32f429-pinctrl
+      - st,stm32f469-pinctrl
+      - st,stm32f746-pinctrl
+      - st,stm32f769-pinctrl
+      - st,stm32h743-pinctrl
+      - st,stm32mp157-pinctrl
+      - st,stm32mp157-z-pinctrl
+
+  '#address-cells':
+    const: 1
+  '#size-cells':
+    const: 1
+
+  ranges: true
+  pins-are-numbered: true
+  hwlocks: true
+
+  st,syscfg:
+    $ref: "/schemas/types.yaml#/definitions/phandle-array"
+    description: Should be phandle/offset/mask
+    items:
+      - description: Phandle to the syscon node which includes IRQ mux selection.
+      - description: The offset of the IRQ mux selection register.
+      - description: The field mask of IRQ mux, needed if different of 0xf.
+
+  st,package:
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - enum: [1, 2, 4, 8]
+    description:
+     Indicates the SOC package used.
+     More details in include/dt-bindings/pinctrl/stm32-pinfunc.h
+
+
+patternProperties:
+  '^gpio@[0-9a-f]*$':
+    properties:
+      gpio-controller: true
+      '#gpio-cells':
+        const: 2
+
+      reg:
+        maxItems: 1
+      clocks:
+        maxItems: 1
+      reset:
+        minItems: 1
+        maxItems: 1
+      gpio-ranges:
+        minItems: 1
+        maxItems: 16
+      ngpios:
+        description:
+          Number of available gpios in a bank.
+        minimum: 1
+        maximum: 16
+
+      st,bank-name:
+        allOf:
+          - $ref: "/schemas/types.yaml#/definitions/string"
+          - enum:
+            - GPIOA
+            - GPIOB
+            - GPIOC
+            - GPIOD
+            - GPIOE
+            - GPIOF
+            - GPIOG
+            - GPIOH
+            - GPIOI
+            - GPIOJ
+            - GPIOK
+            - GPIOZ
+        description:
+          Should be a name string for this bank as specified in the datasheet.
+
+      st,bank-ioport:
+        allOf:
+          - $ref: "/schemas/types.yaml#/definitions/uint32"
+          - minimum: 0
+          - maximum: 11
+
+        description:
+          Should correspond to the EXTI IOport selection (EXTI line used
+          to select GPIOs as interrupts).
+
+    required:
+      - gpio-controller
+      - '#gpio-cells'
+      - reg
+      - clocks
+      - st,bank-name
+
+  '-[0-9]*$':
+    patternProperties:
+      '^pins':
+        description: |
+          A pinctrl node should contain at least one subnode representing the
+          pinctrl group available on the machine. Each subnode will list the
+          pins it needs, and how they should be configured, with regard to muxer
+          configuration, pullups, drive, output high/low and output speed.
+        properties:
+          pinmux:
+            allOf:
+              - $ref: "/schemas/types.yaml#/definitions/uint32-array"
+            description: |
+              Integer array, represents gpio pin number and mux setting.
+              Supported pin number and mux varies for different SoCs, and are
+              defined in dt-bindings/pinctrl/<soc>-pinfunc.h directly.
+              These defines are calculated as: ((port * 16 + line) << 8) | function
+              With:
+              - port: The gpio port index (PA = 0, PB = 1, ..., PK = 11)
+              - line: The line offset within the port (PA0 = 0, PA1 = 1, ..., PA15 = 15)
+              - function: The function number, can be:
+              * 0 : GPIO
+              * 1 : Alternate Function 0
+              * 2 : Alternate Function 1
+              * 3 : Alternate Function 2
+              * ...
+              * 16 : Alternate Function 15
+              * 17 : Analog
+              To simplify the usage, macro is available to generate "pinmux" field.
+              This macro is available here:
+                - include/dt-bindings/pinctrl/stm32-pinfunc.h
+              Some examples of using macro:
+               /* GPIO A9 set as alernate function 2 */
+               ... {
+                          pinmux = <STM32_PINMUX('A', 9, AF2)>;
+               };
+               /* GPIO A9 set as GPIO  */
+               ... {
+                          pinmux = <STM32_PINMUX('A', 9, GPIO)>;
+               };
+               /* GPIO A9 set as analog */
+               ... {
+                          pinmux = <STM32_PINMUX('A', 9, ANALOG)>;
+               };
+
+          bias-disable:
+            type: boolean
+          bias-pull-down:
+            type: boolean
+          bias-pull-up:
+            type: boolean
+          drive-push-pull:
+            type: boolean
+          drive-open-drain:
+            type: boolean
+          output-low:
+            type: boolean
+          output-high:
+            type: boolean
+          slew-rate:
+            description: |
+              0: Low speed
+              1: Medium speed
+              2: Fast speed
+              3: High speed
+            allOf:
+              - $ref: /schemas/types.yaml#/definitions/uint32
+              - enum: [0, 1, 2, 3]
+
+        required:
+          - pinmux
+
+required:
+  - compatible
+  - '#address-cells'
+  - '#size-cells'
+  - ranges
+  - pins-are-numbered
+
+examples:
+  - |
+    #include <dt-bindings/pinctrl/stm32-pinfunc.h>
+    //Example 1
+      pinctrl@40020000 {
+              #address-cells = <1>;
+              #size-cells = <1>;
+              compatible = "st,stm32f429-pinctrl";
+              ranges = <0 0x40020000 0x3000>;
+              pins-are-numbered;
+
+              gpioa: gpio@0 {
+                      gpio-controller;
+                      #gpio-cells = <2>;
+                      reg = <0x0 0x400>;
+                      resets = <&reset_ahb1 0>;
+                      st,bank-name = "GPIOA";
+              };
+       };
+
+    //Example 2 (using gpio-ranges)
+      pinctrl@50020000 {
+              #address-cells = <1>;
+              #size-cells = <1>;
+              compatible = "st,stm32f429-pinctrl";
+              ranges = <0 0x50020000 0x3000>;
+              pins-are-numbered;
+
+              gpiob: gpio@1000 {
+                      gpio-controller;
+                      #gpio-cells = <2>;
+                      reg = <0x1000 0x400>;
+                      resets = <&reset_ahb1 0>;
+                      st,bank-name = "GPIOB";
+                      gpio-ranges = <&pinctrl 0 0 16>;
+              };
+
+              gpioc: gpio@2000 {
+                      gpio-controller;
+                      #gpio-cells = <2>;
+                      reg = <0x2000 0x400>;
+                      resets = <&reset_ahb1 0>;
+                      st,bank-name = "GPIOC";
+                      ngpios = <5>;
+                      gpio-ranges = <&pinctrl 0 16 3>,
+                                    <&pinctrl 14 30 2>;
+              };
+      };
+
+    //Example 3 pin groups
+      pinctrl@60020000 {
+        usart1_pins_a: usart1-0 {
+                pins1 {
+                        pinmux = <STM32_PINMUX('A', 9, AF7)>;
+                        bias-disable;
+                        drive-push-pull;
+                        slew-rate = <0>;
+                };
+                pins2 {
+                        pinmux = <STM32_PINMUX('A', 10, AF7)>;
+                        bias-disable;
+                };
+        };
+    };
+
+    usart1 {
+                pinctrl-0 = <&usart1_pins_a>;
+                pinctrl-names = "default";
+    };
+
+...
index bfd3373..e9b8360 100644 (file)
@@ -12,32 +12,32 @@ unit prefixes.
 Time/Frequency
 ----------------------------------------
 -mhz           : megahertz
--hz            : Hertz (preferred)
--sec           : seconds
--ms            : milliseconds
--us            : microseconds
--ns            : nanoseconds
+-hz            : hertz (preferred)
+-sec           : second
+-ms            : millisecond
+-us            : microsecond
+-ns            : nanosecond
 
 Distance
 ----------------------------------------
--mm            : millimeters
+-mm            : millimeter
 
 Electricity
 ----------------------------------------
--microamp      : micro amps
--microamp-hours : micro amp-hours
--ohms          : Ohms
--micro-ohms    : micro Ohms
--microwatt-hours: micro Watt-hours
--microvolt     : micro volts
--picofarads    : picofarads
--femtofarads   : femtofarads
+-microamp      : microampere
+-microamp-hours : microampere hour
+-ohms          : ohm
+-micro-ohms    : microohm
+-microwatt-hours: microwatt hour
+-microvolt     : microvolt
+-picofarads    : picofarad
+-femtofarads   : femtofarad
 
 Temperature
 ----------------------------------------
--celsius       : Degrees Celsius
--millicelsius  : Degreee milli-Celsius
+-celsius       : degree Celsius
+-millicelsius  : millidegree Celsius
 
 Pressure
 ----------------------------------------
--kpascal       : kiloPascal
+-kpascal       : kilopascal
index 10a6dad..6a7c8a9 100644 (file)
@@ -121,4 +121,4 @@ Example
                                regulator-max-microvolt = <5000000>;
                        };
                };
-       };
\ No newline at end of file
+       };
index 3cba12f..20d351f 100644 (file)
@@ -53,6 +53,9 @@ Optional properties:
   programmable TX FIFO thresholds.
 - resets : phandle + reset specifier pairs
 - overrun-throttle-ms : how long to pause uart rx when input overrun is encountered.
+- {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD
+  line respectively. It will use specified GPIO instead of the peripheral
+  function pin for the UART feature. If unsure, don't specify this property.
 
 Note:
 * fsl,ns16550:
@@ -74,3 +77,19 @@ Example:
                interrupts = <10>;
                reg-shift = <2>;
        };
+
+Example for OMAP UART using GPIO-based modem control signals:
+
+       uart4: serial@49042000 {
+               compatible = "ti,omap3-uart";
+               reg = <0x49042000 0x400>;
+               interrupts = <80>;
+               ti,hwmods = "uart4";
+               clock-frequency = <48000000>;
+               cts-gpios = <&gpio3 5 GPIO_ACTIVE_LOW>;
+               rts-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>;
+               dtr-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
+               dsr-gpios = <&gpio1 13 GPIO_ACTIVE_LOW>;
+               dcd-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
+               rng-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
+       };
index c6b5262..6fdffb7 100644 (file)
@@ -23,7 +23,12 @@ Required properties:
 
 - reg: The base address of the UART register bank.
 
-- interrupts: A single interrupt specifier.
+- interrupts:
+  index 0: an interrupt specifier for the UART controller itself
+  index 1: optional, an interrupt specifier with edge sensitivity on Rx pin to
+           support Rx in-band wake up. If one would like to use this feature,
+           one must create an addtional pinctrl to reconfigure Rx pin to normal
+           GPIO before suspend.
 
 - clocks : Must contain an entry for each entry in clock-names.
   See ../clocks/clock-bindings.txt for details.
@@ -39,7 +44,11 @@ Example:
        uart0: serial@11006000 {
                compatible = "mediatek,mt6589-uart", "mediatek,mt6577-uart";
                reg = <0x11006000 0x400>;
-               interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>;
+               interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_SPI 52 IRQ_TYPE_EDGE_FALLING>;
                clocks = <&uart_clk>, <&bus_clk>;
                clock-names = "baud", "bus";
+               pinctrl-names = "default", "sleep";
+               pinctrl-0 = <&uart_pin>;
+               pinctrl-1 = <&uart_pin_sleep>;
        };
index 9d3efed..a6b1948 100644 (file)
@@ -13,6 +13,7 @@ Required properties:
 - clocks: The input clock of the USART instance
 
 Optional properties:
+- resets: Must contain the phandle to the reset controller.
 - pinctrl: The reference on the pins configuration
 - st,hw-flow-ctrl: bool flag to enable hardware flow control.
 - rs485-rts-delay, rs485-rx-during-tx, rs485-rts-active-low,
index 80ae910..47b868b 100644 (file)
@@ -19,4 +19,4 @@ codec: cs42l73@4a {
        reg = <0x4a>;
        reset_gpio = <&gpio 10 0>;
        chgfreq = <0x05>;
-};
\ No newline at end of file
+};
index 49eac0d..aafff3a 100644 (file)
@@ -42,6 +42,8 @@ Refer to phy/phy-bindings.txt for generic phy consumer properties
 - g-rx-fifo-size: size of rx fifo size in gadget mode.
 - g-np-tx-fifo-size: size of non-periodic tx fifo size in gadget mode.
 - g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) in gadget mode.
+- snps,need-phy-for-wake: If present indicates that the phy needs to be left
+                          on for remote wakeup during suspend.
 - snps,reset-phy-on-wake: If present indicates that we need to reset the PHY when
                           we detect a wakeup.  This is due to a hardware errata.
 
@@ -58,4 +60,5 @@ Example:
                clock-names = "otg";
                phys = <&usbphy>;
                phy-names = "usb2-phy";
+               snps,need-phy-for-wake;
         };
index 8e5265e..66780a4 100644 (file)
@@ -64,6 +64,8 @@ Optional properties:
  - snps,dis_u2_susphy_quirk: when set core will disable USB2 suspend phy.
  - snps,dis_enblslpm_quirk: when set clears the enblslpm in GUSB2PHYCFG,
                        disabling the suspend signal to the PHY.
+ - snps,dis-u1-entry-quirk: set if link entering into U1 needs to be disabled.
+ - snps,dis-u2-entry-quirk: set if link entering into U2 needs to be disabled.
  - snps,dis_rxdet_inp3_quirk: when set core will disable receiver detection
                        in PHY P3 power state.
  - snps,dis-u2-freeclk-exists-quirk: when set, clear the u2_freeclk_exists
index d3b4f64..059f6ef 100644 (file)
@@ -74,7 +74,7 @@ additionalProperties: false
 
 examples:
   - |
-    ehci@e0000300 {
+    usb@e0000300 {
         compatible = "ibm,usb-ehci-440epx", "generic-ehci";
         interrupt-parent = <&UIC0>;
         interrupts = <0x1a 4>;
@@ -89,7 +89,6 @@ examples:
         interrupts = <39>;
         clocks = <&ahb_gates 1>;
         phys = <&usbphy 1>;
-        phy-names = "usb";
     };
 
 ...
diff --git a/Documentation/devicetree/bindings/usb/renesas,usb3.txt b/Documentation/devicetree/bindings/usb/renesas,usb3.txt
new file mode 100644 (file)
index 0000000..35039e7
--- /dev/null
@@ -0,0 +1,41 @@
+Renesas Electronics USB3.0 Peripheral driver
+
+Required properties:
+  - compatible: Must contain one of the following:
+       - "renesas,r8a774a1-usb3-peri"
+       - "renesas,r8a774c0-usb3-peri"
+       - "renesas,r8a7795-usb3-peri"
+       - "renesas,r8a7796-usb3-peri"
+       - "renesas,r8a77965-usb3-peri"
+       - "renesas,r8a77990-usb3-peri"
+       - "renesas,rcar-gen3-usb3-peri" for a generic R-Car Gen3 or RZ/G2
+         compatible device
+
+    When compatible with the generic version, nodes must list the
+    SoC-specific version corresponding to the platform first
+    followed by the generic version.
+
+  - reg: Base address and length of the register for the USB3.0 Peripheral
+  - interrupts: Interrupt specifier for the USB3.0 Peripheral
+  - clocks: clock phandle and specifier pair
+
+Optional properties:
+  - phys: phandle + phy specifier pair
+  - phy-names: must be "usb"
+
+Example of R-Car H3 ES1.x:
+       usb3_peri0: usb@ee020000 {
+               compatible = "renesas,r8a7795-usb3-peri",
+                            "renesas,rcar-gen3-usb3-peri";
+               reg = <0 0xee020000 0 0x400>;
+               interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cpg CPG_MOD 328>;
+       };
+
+       usb3_peri1: usb@ee060000 {
+               compatible = "renesas,r8a7795-usb3-peri",
+                            "renesas,rcar-gen3-usb3-peri";
+               reg = <0 0xee060000 0 0x400>;
+               interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cpg CPG_MOD 327>;
+       };
diff --git a/Documentation/devicetree/bindings/usb/renesas,usbhs.txt b/Documentation/devicetree/bindings/usb/renesas,usbhs.txt
new file mode 100644 (file)
index 0000000..e39255e
--- /dev/null
@@ -0,0 +1,57 @@
+Renesas Electronics USBHS driver
+
+Required properties:
+  - compatible: Must contain one or more of the following:
+
+       - "renesas,usbhs-r8a7743" for r8a7743 (RZ/G1M) compatible device
+       - "renesas,usbhs-r8a7744" for r8a7744 (RZ/G1N) compatible device
+       - "renesas,usbhs-r8a7745" for r8a7745 (RZ/G1E) compatible device
+       - "renesas,usbhs-r8a77470" for r8a77470 (RZ/G1C) compatible device
+       - "renesas,usbhs-r8a774a1" for r8a774a1 (RZ/G2M) compatible device
+       - "renesas,usbhs-r8a774c0" for r8a774c0 (RZ/G2E) compatible device
+       - "renesas,usbhs-r8a7790" for r8a7790 (R-Car H2) compatible device
+       - "renesas,usbhs-r8a7791" for r8a7791 (R-Car M2-W) compatible device
+       - "renesas,usbhs-r8a7792" for r8a7792 (R-Car V2H) compatible device
+       - "renesas,usbhs-r8a7793" for r8a7793 (R-Car M2-N) compatible device
+       - "renesas,usbhs-r8a7794" for r8a7794 (R-Car E2) compatible device
+       - "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device
+       - "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3-W) compatible device
+       - "renesas,usbhs-r8a77965" for r8a77965 (R-Car M3-N) compatible device
+       - "renesas,usbhs-r8a77990" for r8a77990 (R-Car E3) compatible device
+       - "renesas,usbhs-r8a77995" for r8a77995 (R-Car D3) compatible device
+       - "renesas,usbhs-r7s72100" for r7s72100 (RZ/A1) compatible device
+       - "renesas,usbhs-r7s9210" for r7s9210 (RZ/A2) compatible device
+       - "renesas,rcar-gen2-usbhs" for R-Car Gen2 or RZ/G1 compatible devices
+       - "renesas,rcar-gen3-usbhs" for R-Car Gen3 or RZ/G2 compatible devices
+       - "renesas,rza1-usbhs" for RZ/A1 compatible device
+       - "renesas,rza2-usbhs" for RZ/A2 compatible device
+
+       When compatible with the generic version, nodes must list the
+       SoC-specific version corresponding to the platform first followed
+       by the generic version.
+
+  - reg: Base address and length of the register for the USBHS
+  - interrupts: Interrupt specifier for the USBHS
+  - clocks: A list of phandle + clock specifier pairs.
+           - In case of "renesas,rcar-gen3-usbhs", two clocks are required.
+             First clock should be peripheral and second one should be host.
+           - In case of except above, one clock is required. First clock
+             should be peripheral.
+
+Optional properties:
+  - renesas,buswait: Integer to use BUSWAIT register
+  - renesas,enable-gpio: A gpio specifier to check GPIO determining if USB
+                        function should be enabled
+  - phys: phandle + phy specifier pair
+  - phy-names: must be "usb"
+  - dmas: Must contain a list of references to DMA specifiers.
+  - dma-names : named "ch%d", where %d is the channel number ranging from zero
+                to the number of channels (DnFIFOs) minus one.
+
+Example:
+       usbhs: usb@e6590000 {
+               compatible = "renesas,usbhs-r8a7790", "renesas,rcar-gen2-usbhs";
+               reg = <0 0xe6590000 0 0x100>;
+               interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp7_clks R8A7790_CLK_HSUSB>;
+       };
diff --git a/Documentation/devicetree/bindings/usb/renesas_usb3.txt b/Documentation/devicetree/bindings/usb/renesas_usb3.txt
deleted file mode 100644 (file)
index 35039e7..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-Renesas Electronics USB3.0 Peripheral driver
-
-Required properties:
-  - compatible: Must contain one of the following:
-       - "renesas,r8a774a1-usb3-peri"
-       - "renesas,r8a774c0-usb3-peri"
-       - "renesas,r8a7795-usb3-peri"
-       - "renesas,r8a7796-usb3-peri"
-       - "renesas,r8a77965-usb3-peri"
-       - "renesas,r8a77990-usb3-peri"
-       - "renesas,rcar-gen3-usb3-peri" for a generic R-Car Gen3 or RZ/G2
-         compatible device
-
-    When compatible with the generic version, nodes must list the
-    SoC-specific version corresponding to the platform first
-    followed by the generic version.
-
-  - reg: Base address and length of the register for the USB3.0 Peripheral
-  - interrupts: Interrupt specifier for the USB3.0 Peripheral
-  - clocks: clock phandle and specifier pair
-
-Optional properties:
-  - phys: phandle + phy specifier pair
-  - phy-names: must be "usb"
-
-Example of R-Car H3 ES1.x:
-       usb3_peri0: usb@ee020000 {
-               compatible = "renesas,r8a7795-usb3-peri",
-                            "renesas,rcar-gen3-usb3-peri";
-               reg = <0 0xee020000 0 0x400>;
-               interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&cpg CPG_MOD 328>;
-       };
-
-       usb3_peri1: usb@ee060000 {
-               compatible = "renesas,r8a7795-usb3-peri",
-                            "renesas,rcar-gen3-usb3-peri";
-               reg = <0 0xee060000 0 0x400>;
-               interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&cpg CPG_MOD 327>;
-       };
diff --git a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt
deleted file mode 100644 (file)
index b8acc2a..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-Renesas Electronics USBHS driver
-
-Required properties:
-  - compatible: Must contain one or more of the following:
-
-       - "renesas,usbhs-r8a7743" for r8a7743 (RZ/G1M) compatible device
-       - "renesas,usbhs-r8a7744" for r8a7744 (RZ/G1N) compatible device
-       - "renesas,usbhs-r8a7745" for r8a7745 (RZ/G1E) compatible device
-       - "renesas,usbhs-r8a77470" for r8a77470 (RZ/G1C) compatible device
-       - "renesas,usbhs-r8a774a1" for r8a774a1 (RZ/G2M) compatible device
-       - "renesas,usbhs-r8a774c0" for r8a774c0 (RZ/G2E) compatible device
-       - "renesas,usbhs-r8a7790" for r8a7790 (R-Car H2) compatible device
-       - "renesas,usbhs-r8a7791" for r8a7791 (R-Car M2-W) compatible device
-       - "renesas,usbhs-r8a7792" for r8a7792 (R-Car V2H) compatible device
-       - "renesas,usbhs-r8a7793" for r8a7793 (R-Car M2-N) compatible device
-       - "renesas,usbhs-r8a7794" for r8a7794 (R-Car E2) compatible device
-       - "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device
-       - "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3-W) compatible device
-       - "renesas,usbhs-r8a77965" for r8a77965 (R-Car M3-N) compatible device
-       - "renesas,usbhs-r8a77990" for r8a77990 (R-Car E3) compatible device
-       - "renesas,usbhs-r8a77995" for r8a77995 (R-Car D3) compatible device
-       - "renesas,usbhs-r7s72100" for r7s72100 (RZ/A1) compatible device
-       - "renesas,rcar-gen2-usbhs" for R-Car Gen2 or RZ/G1 compatible devices
-       - "renesas,rcar-gen3-usbhs" for R-Car Gen3 or RZ/G2 compatible devices
-       - "renesas,rza1-usbhs" for RZ/A1 compatible device
-
-       When compatible with the generic version, nodes must list the
-       SoC-specific version corresponding to the platform first followed
-       by the generic version.
-
-  - reg: Base address and length of the register for the USBHS
-  - interrupts: Interrupt specifier for the USBHS
-  - clocks: A list of phandle + clock specifier pairs.
-           - In case of "renesas,rcar-gen3-usbhs", two clocks are required.
-             First clock should be peripheral and second one should be host.
-           - In case of except above, one clock is required. First clock
-             should be peripheral.
-
-Optional properties:
-  - renesas,buswait: Integer to use BUSWAIT register
-  - renesas,enable-gpio: A gpio specifier to check GPIO determining if USB
-                        function should be enabled
-  - phys: phandle + phy specifier pair
-  - phy-names: must be "usb"
-  - dmas: Must contain a list of references to DMA specifiers.
-  - dma-names : named "ch%d", where %d is the channel number ranging from zero
-                to the number of channels (DnFIFOs) minus one.
-
-Example:
-       usbhs: usb@e6590000 {
-               compatible = "renesas,usbhs-r8a7790", "renesas,rcar-gen2-usbhs";
-               reg = <0 0xe6590000 0 0x100>;
-               interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&mstp7_clks R8A7790_CLK_HSUSB>;
-       };
index 1acf806..18b79c4 100644 (file)
@@ -149,6 +149,8 @@ patternProperties:
     description: Broadcom Corporation
   "^buffalo,.*":
     description: Buffalo, Inc.
+  "^bur,.*":
+    description: B&R Industrial Automation GmbH
   "^bticino,.*":
     description: Bticino International
   "^calxeda,.*":
@@ -177,6 +179,8 @@ patternProperties:
     description: Common Hardware Reference Platform
   "^chunghwa,.*":
     description: Chunghwa Picture Tubes Ltd.
+  "^chuwi,.*":
+    description: Chuwi Innovation Ltd.
   "^ciaa,.*":
     description: Computadora Industrial Abierta Argentina
   "^cirrus,.*":
@@ -187,8 +191,12 @@ patternProperties:
     description: Chips&Media, Inc.
   "^cnxt,.*":
     description: Conexant Systems, Inc.
+  "^colorfly,.*":
+    description: Colorful GRP, Shenzhen Xueyushi Technology Ltd.
   "^compulab,.*":
     description: CompuLab Ltd.
+  "^corpro,.*":
+    description: Chengdu Corpro Technology Co., Ltd.
   "^cortina,.*":
     description: Cortina Systems, Inc.
   "^cosmic,.*":
@@ -201,6 +209,8 @@ patternProperties:
     description: Crystalfontz America, Inc.
   "^csky,.*":
     description: Hangzhou C-SKY Microsystems Co., Ltd
+  "^csq,.*":
+    description: Shenzen Chuangsiqi Technology Co.,Ltd.
   "^cubietech,.*":
     description: Cubietech, Ltd.
   "^cypress,.*":
@@ -221,6 +231,8 @@ patternProperties:
     description: Devantech, Ltd.
   "^dh,.*":
     description: DH electronics GmbH
+  "^difrnce,.*":
+    description: Shenzhen Yagu Electronic Technology Co., Ltd.
   "^digi,.*":
     description: Digi International Inc.
   "^digilent,.*":
@@ -243,6 +255,8 @@ patternProperties:
     description: DPTechnics
   "^dragino,.*":
     description: Dragino Technology Co., Limited
+  "^dserve,.*":
+    description: dServe Technology B.V.
   "^ea,.*":
     description: Embedded Artists AB
   "^ebs-systart,.*":
@@ -265,6 +279,8 @@ patternProperties:
     description: Emlid, Ltd.
   "^emmicro,.*":
     description: EM Microelectronic
+  "^empire-electronix,.*":
+    description: Empire Electronix
   "^emtrion,.*":
     description: emtrion GmbH
   "^endless,.*":
@@ -279,6 +295,8 @@ patternProperties:
     description: Ecole Polytechnique Fédérale de Lausanne
   "^epson,.*":
     description: Seiko Epson Corp.
+  "^esp,.*":
+    description: Espressif Systems Co. Ltd.
   "^est,.*":
     description: ESTeem Wireless Modems
   "^ettus,.*":
@@ -329,6 +347,8 @@ patternProperties:
     description: GE Fanuc Intelligent Platforms Embedded Systems, Inc.
   "^GEFanuc,.*":
     description: GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+  "^gemei,.*":
+    description: Gemei Digital Technology Co., Ltd.
   "^geniatech,.*":
     description: Geniatech, Inc.
   "^giantec,.*":
@@ -375,10 +395,14 @@ patternProperties:
     description: Honeywell
   "^hp,.*":
     description: Hewlett Packard
+  "^hsg,.*":
+    description: HannStar Display Co.
   "^holtek,.*":
     description: Holtek Semiconductor, Inc.
   "^hwacom,.*":
     description: HwaCom Systems Inc.
+  "^hyundai,.*":
+    description: Hyundai Technology
   "^i2se,.*":
     description: I2SE GmbH
   "^ibm,.*":
@@ -393,6 +417,10 @@ patternProperties:
     description: ILI Technology Corporation (ILITEK)
   "^img,.*":
     description: Imagination Technologies Ltd.
+  "^incircuit,.*":
+    description: In-Circuit GmbH
+  "^inet-tek,.*":
+    description: Shenzhen iNet Mobile Internet Technology Co., Ltd
   "^infineon,.*":
     description: Infineon Technologies
   "^inforce,.*":
@@ -427,6 +455,8 @@ patternProperties:
     description: Japan Display Inc.
   "^jedec,.*":
     description: JEDEC Solid State Technology Association
+  "^jesurun,.*":
+    description: Shenzhen Jesurun Electronics Business Dept.
   "^jianda,.*":
     description: Jiandangjing Technology Co., Ltd.
   "^karo,.*":
@@ -451,6 +481,8 @@ patternProperties:
     description: Rakuten Kobo Inc.
   "^koe,.*":
     description: Kaohsiung Opto-Electronics Inc.
+  "^kontron,.*":
+    description: Kontron S&T AG
   "^kosagi,.*":
     description: Sutajio Ko-Usagi PTE Ltd.
   "^kyo,.*":
@@ -459,6 +491,8 @@ patternProperties:
     description: LaCie
   "^laird,.*":
     description: Laird PLC
+  "^lamobo,.*":
+    description: Ketai Huajie Technology Co., Ltd.
   "^lantiq,.*":
     description: Lantiq Semiconductor
   "^lattice,.*":
@@ -477,6 +511,8 @@ patternProperties:
     description: Lichee Pi
   "^linaro,.*":
     description: Linaro Limited
+  "^linksprite,.*":
+    description: LinkSprite Technologies, Inc.
   "^linksys,.*":
     description: Belkin International, Inc. (Linksys)
   "^linux,.*":
@@ -493,6 +529,8 @@ patternProperties:
     description: Liebherr-Werk Nenzing GmbH
   "^macnica,.*":
     description: Macnica Americas
+  "^mapleboard,.*":
+    description: Mapleboard.org
   "^marvell,.*":
     description: Marvell Technology Group Ltd.
   "^maxbotix,.*":
@@ -533,6 +571,8 @@ patternProperties:
     description: Micron Technology Inc.
   "^mikroe,.*":
     description: MikroElektronika d.o.o.
+  "^miniand,.*":
+    description: Miniand Tech
   "^minix,.*":
     description: MINIX Technology Ltd.
   "^miramems,.*":
@@ -663,24 +703,32 @@ patternProperties:
     description: Picochip Ltd
   "^pine64,.*":
     description: Pine64
+  "^pineriver,.*":
+    description: Shenzhen PineRiver Designs Co., Ltd.
   "^pixcir,.*":
     description: PIXCIR MICROELECTRONICS Co., Ltd
   "^plantower,.*":
     description: Plantower Co., Ltd
   "^plathome,.*":
-    description: Plat'Home Co., Ltd.
+    description: Plat\'Home Co., Ltd.
   "^plda,.*":
     description: PLDA
   "^plx,.*":
     description: Broadcom Corporation (formerly PLX Technology)
   "^pni,.*":
     description: PNI Sensor Corporation
+  "^polaroid,.*":
+    description: Polaroid Corporation
   "^portwell,.*":
     description: Portwell Inc.
   "^poslab,.*":
     description: Poslab Technology Co., Ltd.
+  "^pov,.*":
+    description: Point of View International B.V.
   "^powervr,.*":
     description: PowerVR (deprecated, use img)
+  "^primux,.*":
+    description: Primux Trading, S.L.
   "^probox2,.*":
     description: PROBOX2 (by W2COMP Co., Ltd.)
   "^pulsedlight,.*":
@@ -693,6 +741,8 @@ patternProperties:
     description: QEMU, a generic and open source machine emulator and virtualizer
   "^qi,.*":
     description: Qi Hardware
+  "^qihua,.*":
+    description: Chengdu Kaixuan Information Technology Co., Ltd.
   "^qiaodian,.*":
     description: QiaoDian XianShi Corporation
   "^qnap,.*":
@@ -715,6 +765,8 @@ patternProperties:
     description: Realtek Semiconductor Corp.
   "^renesas,.*":
     description: Renesas Electronics Corporation
+  "^rervision,.*":
+    description: Shenzhen Rervision Technology Co., Ltd.
   "^richtek,.*":
     description: Richtek Technology Corporation
   "^ricoh,.*":
@@ -783,8 +835,14 @@ patternProperties:
     description: Silergy Corp.
   "^siliconmitus,.*":
     description: Silicon Mitus, Inc.
-  "^simte,.*":
-    description: k
+  "^simtek,.*":
+    description: Cypress Semiconductor Corporation (Simtek Corporation)
+  "^sinlinx,.*":
+    description: Sinlinx Electronics Technology Co., LTD
+  "^sinovoip,.*":
+    description: SinoVoip Co., Ltd
+  "^sipeed,.*":
+    description: Shenzhen Sipeed Technology Co., Ltd.
   "^sirf,.*":
     description: SiRF Technology, Inc.
   "^sis,.*":
@@ -797,6 +855,8 @@ patternProperties:
     description: Standard Microsystems Corporation
   "^snps,.*":
     description: Synopsys, Inc.
+  "^sochip,.*":
+    description: Shenzhen SoChip Technology Co., Ltd.
   "^socionext,.*":
     description: Socionext Inc.
   "^solidrun,.*":
@@ -903,6 +963,8 @@ patternProperties:
     description: United Radiant Technology Corporation
   "^usi,.*":
     description: Universal Scientific Industrial Co., Ltd.
+  "^utoo,.*":
+    description: Aigo Digital Technology Co., Ltd.
   "^v3,.*":
     description: V3 Semiconductor
   "^vamrs,.*":
@@ -939,10 +1001,14 @@ patternProperties:
     description: Winbond Electronics corp.
   "^winstar,.*":
     description: Winstar Display Corp.
+  "^wits,.*":
+    description: Shenzhen Merrii Technology Co., Ltd. (WITS)
   "^wlf,.*":
     description: Wolfson Microelectronics
   "^wm,.*":
     description: Wondermedia Technologies, Inc.
+  "^wobo,.*":
+    description: Wobo
   "^x-powers,.*":
     description: X-Powers
   "^xes,.*":
@@ -953,6 +1019,8 @@ patternProperties:
     description: Xilinx
   "^xunlong,.*":
     description: Shenzhen Xunlong Software CO.,Limited
+  "^yones-toptech,.*":
+    description: Yones Toptech Co., Ltd.
   "^ysoft,.*":
     description: Y Soft Corporation a.s.
   "^zarlink,.*":
@@ -970,7 +1038,7 @@ patternProperties:
 
   # Normal property name match without a comma
   # These should catch all node/property names without a prefix
-  "^[a-zA-Z0-9#][a-zA-Z0-9+\\-._@]{0,63}$": true
+  "^[a-zA-Z0-9#_][a-zA-Z0-9+\\-._@]{0,63}$": true
   "^[a-zA-Z0-9+\\-._]*@[0-9a-zA-Z,]*$": true
   "^#.*": true
 
index 4af9aae..349f2dc 100644 (file)
@@ -399,7 +399,7 @@ symbol:
   will pass the struct gpio_chip* for the chip to all IRQ callbacks, so the
   callbacks need to embed the gpio_chip in its state container and obtain a
   pointer to the container using container_of().
-  (See Documentation/driver-model/design-patterns.txt)
+  (See Documentation/driver-model/design-patterns.rst)
 
 - gpiochip_irqchip_add_nested(): adds a nested cascaded irqchip to a gpiochip,
   as discussed above regarding different types of cascaded irqchips. The
index d26308a..6cd750a 100644 (file)
@@ -34,6 +34,7 @@ available subsections can be seen below.
    pci/index
    spi
    i2c
+   ipmb
    i3c/index
    hsi
    edac
@@ -42,6 +43,7 @@ available subsections can be seen below.
    target
    mtdnand
    miscellaneous
+   mei/index
    w1
    rapidio
    s390-drivers
diff --git a/Documentation/driver-api/ipmb.rst b/Documentation/driver-api/ipmb.rst
new file mode 100644 (file)
index 0000000..7e22651
--- /dev/null
@@ -0,0 +1,105 @@
+==============================
+IPMB Driver for a Satellite MC
+==============================
+
+The Intelligent Platform Management Bus or IPMB, is an
+I2C bus that provides a standardized interconnection between
+different boards within a chassis. This interconnection is
+between the baseboard management (BMC) and chassis electronics.
+IPMB is also associated with the messaging protocol through the
+IPMB bus.
+
+The devices using the IPMB are usually management
+controllers that perform management functions such as servicing
+the front panel interface, monitoring the baseboard,
+hot-swapping disk drivers in the system chassis, etc...
+
+When an IPMB is implemented in the system, the BMC serves as
+a controller to give system software access to the IPMB. The BMC
+sends IPMI requests to a device (usually a Satellite Management
+Controller or Satellite MC) via IPMB and the device
+sends a response back to the BMC.
+
+For more information on IPMB and the format of an IPMB message,
+refer to the IPMB and IPMI specifications.
+
+IPMB driver for Satellite MC
+----------------------------
+
+ipmb-dev-int - This is the driver needed on a Satellite MC to
+receive IPMB messages from a BMC and send a response back.
+This driver works with the I2C driver and a userspace
+program such as OpenIPMI:
+
+1) It is an I2C slave backend driver. So, it defines a callback
+   function to set the Satellite MC as an I2C slave.
+   This callback function handles the received IPMI requests.
+
+2) It defines the read and write functions to enable a user
+   space program (such as OpenIPMI) to communicate with the kernel.
+
+
+Load the IPMB driver
+--------------------
+
+The driver needs to be loaded at boot time or manually first.
+First, make sure you have the following in your config file:
+CONFIG_IPMB_DEVICE_INTERFACE=y
+
+1) If you want the driver to be loaded at boot time:
+
+a) Add this entry to your ACPI table, under the appropriate SMBus::
+
+     Device (SMB0) // Example SMBus host controller
+     {
+     Name (_HID, "<Vendor-Specific HID>") // Vendor-Specific HID
+     Name (_UID, 0) // Unique ID of particular host controller
+     :
+     :
+       Device (IPMB)
+       {
+         Name (_HID, "IPMB0001") // IPMB device interface
+         Name (_UID, 0) // Unique device identifier
+       }
+     }
+
+b) Example for device tree::
+
+     &i2c2 {
+            status = "okay";
+
+            ipmb@10 {
+                    compatible = "ipmb-dev";
+                    reg = <0x10>;
+            };
+     };
+
+2) Manually from Linux::
+
+     modprobe ipmb-dev-int
+
+
+Instantiate the device
+----------------------
+
+After loading the driver, you can instantiate the device as
+described in 'Documentation/i2c/instantiating-devices'.
+If you have multiple BMCs, each connected to your Satellite MC via
+a different I2C bus, you can instantiate a device for each of
+those BMCs.
+
+The name of the instantiated device contains the I2C bus number
+associated with it as follows::
+
+  BMC1 ------ IPMB/I2C bus 1 ---------|   /dev/ipmb-1
+                               Satellite MC
+  BMC1 ------ IPMB/I2C bus 2 ---------|   /dev/ipmb-2
+
+For instance, you can instantiate the ipmb-dev-int device from
+user space at the 7 bit address 0x10 on bus 2::
+
+  # echo ipmb-dev 0x1010 > /sys/bus/i2c/devices/i2c-2/new_device
+
+This will create the device file /dev/ipmb-2, which can be accessed
+by the user space program. The device needs to be instantiated
+before running the user space program.
diff --git a/Documentation/driver-api/mei/hdcp.rst b/Documentation/driver-api/mei/hdcp.rst
new file mode 100644 (file)
index 0000000..e85a065
--- /dev/null
@@ -0,0 +1,32 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+HDCP:
+=====
+
+ME FW as a security engine provides the capability for setting up
+HDCP2.2 protocol negotiation between the Intel graphics device and
+an HDC2.2 sink.
+
+ME FW prepares HDCP2.2 negotiation parameters, signs and encrypts them
+according the HDCP 2.2 spec. The Intel graphics sends the created blob
+to the HDCP2.2 sink.
+
+Similarly, the HDCP2.2 sink's response is transferred to ME FW
+for decryption and verification.
+
+Once all the steps of HDCP2.2 negotiation are completed,
+upon request ME FW will configure the port as authenticated and supply
+the HDCP encryption keys to Intel graphics hardware.
+
+
+mei_hdcp driver
+---------------
+.. kernel-doc:: drivers/misc/mei/hdcp/mei_hdcp.c
+    :doc: MEI_HDCP Client Driver
+
+mei_hdcp api
+------------
+
+.. kernel-doc:: drivers/misc/mei/hdcp/mei_hdcp.c
+    :functions:
+
diff --git a/Documentation/driver-api/mei/iamt.rst b/Documentation/driver-api/mei/iamt.rst
new file mode 100644 (file)
index 0000000..6ef3e61
--- /dev/null
@@ -0,0 +1,101 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Intel(R) Active Management Technology (Intel AMT)
+=================================================
+
+Prominent usage of the Intel ME Interface is to communicate with Intel(R)
+Active Management Technology (Intel AMT) implemented in firmware running on
+the Intel ME.
+
+Intel AMT provides the ability to manage a host remotely out-of-band (OOB)
+even when the operating system running on the host processor has crashed or
+is in a sleep state.
+
+Some examples of Intel AMT usage are:
+   - Monitoring hardware state and platform components
+   - Remote power off/on (useful for green computing or overnight IT
+     maintenance)
+   - OS updates
+   - Storage of useful platform information such as software assets
+   - Built-in hardware KVM
+   - Selective network isolation of Ethernet and IP protocol flows based
+     on policies set by a remote management console
+   - IDE device redirection from remote management console
+
+Intel AMT (OOB) communication is based on SOAP (deprecated
+starting with Release 6.0) over HTTP/S or WS-Management protocol over
+HTTP/S that are received from a remote management console application.
+
+For more information about Intel AMT:
+https://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/default.htm
+
+
+Intel AMT Applications
+----------------------
+
+    1) Intel Local Management Service (Intel LMS)
+
+       Applications running locally on the platform communicate with Intel AMT Release
+       2.0 and later releases in the same way that network applications do via SOAP
+       over HTTP (deprecated starting with Release 6.0) or with WS-Management over
+       SOAP over HTTP. This means that some Intel AMT features can be accessed from a
+       local application using the same network interface as a remote application
+       communicating with Intel AMT over the network.
+
+       When a local application sends a message addressed to the local Intel AMT host
+       name, the Intel LMS, which listens for traffic directed to the host name,
+       intercepts the message and routes it to the Intel MEI.
+       For more information:
+       https://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/default.htm
+       Under "About Intel AMT" => "Local Access"
+
+       For downloading Intel LMS:
+       https://github.com/intel/lms
+
+       The Intel LMS opens a connection using the Intel MEI driver to the Intel LMS
+       firmware feature using a defined GUID and then communicates with the feature
+       using a protocol called Intel AMT Port Forwarding Protocol (Intel APF protocol).
+       The protocol is used to maintain multiple sessions with Intel AMT from a
+       single application.
+
+       See the protocol specification in the Intel AMT Software Development Kit (SDK)
+       https://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/default.htm
+       Under "SDK Resources" => "Intel(R) vPro(TM) Gateway (MPS)"
+       => "Information for Intel(R) vPro(TM) Gateway Developers"
+       => "Description of the Intel AMT Port Forwarding (APF) Protocol"
+
+    2) Intel AMT Remote configuration using a Local Agent
+
+       A Local Agent enables IT personnel to configure Intel AMT out-of-the-box
+       without requiring installing additional data to enable setup. The remote
+       configuration process may involve an ISV-developed remote configuration
+       agent that runs on the host.
+       For more information:
+       https://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/default.htm
+       Under "Setup and Configuration of Intel AMT" =>
+       "SDK Tools Supporting Setup and Configuration" =>
+       "Using the Local Agent Sample"
+
+Intel AMT OS Health Watchdog
+----------------------------
+
+The Intel AMT Watchdog is an OS Health (Hang/Crash) watchdog.
+Whenever the OS hangs or crashes, Intel AMT will send an event
+to any subscriber to this event. This mechanism means that
+IT knows when a platform crashes even when there is a hard failure on the host.
+
+The Intel AMT Watchdog is composed of two parts:
+    1) Firmware feature - receives the heartbeats
+       and sends an event when the heartbeats stop.
+    2) Intel MEI iAMT watchdog driver - connects to the watchdog feature,
+       configures the watchdog and sends the heartbeats.
+
+The Intel iAMT watchdog MEI driver uses the kernel watchdog API to configure
+the Intel AMT Watchdog and to send heartbeats to it. The default timeout of the
+watchdog is 120 seconds.
+
+If the Intel AMT is not enabled in the firmware then the watchdog client won't enumerate
+on the me client bus and watchdog devices won't be exposed.
+
+---
+linux-mei@linux.intel.com
diff --git a/Documentation/driver-api/mei/index.rst b/Documentation/driver-api/mei/index.rst
new file mode 100644 (file)
index 0000000..3a22b52
--- /dev/null
@@ -0,0 +1,23 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: <isonum.txt>
+
+===================================================
+Intel(R) Management Engine Interface (Intel(R) MEI)
+===================================================
+
+**Copyright** |copy| 2019 Intel Corporation
+
+
+.. only:: html
+
+   .. class:: toc-title
+
+        Table of Contents
+
+.. toctree::
+   :maxdepth: 3
+
+   mei
+   mei-client-bus
+   iamt
diff --git a/Documentation/driver-api/mei/mei-client-bus.rst b/Documentation/driver-api/mei/mei-client-bus.rst
new file mode 100644 (file)
index 0000000..f242b3f
--- /dev/null
@@ -0,0 +1,168 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==============================================
+Intel(R) Management Engine (ME) Client bus API
+==============================================
+
+
+Rationale
+=========
+
+The MEI character device is useful for dedicated applications to send and receive
+data to the many FW appliance found in Intel's ME from the user space.
+However, for some of the ME functionalities it makes sense to leverage existing software
+stack and expose them through existing kernel subsystems.
+
+In order to plug seamlessly into the kernel device driver model we add kernel virtual
+bus abstraction on top of the MEI driver. This allows implementing Linux kernel drivers
+for the various MEI features as a stand alone entities found in their respective subsystem.
+Existing device drivers can even potentially be re-used by adding an MEI CL bus layer to
+the existing code.
+
+
+MEI CL bus API
+==============
+
+A driver implementation for an MEI Client is very similar to any other existing bus
+based device drivers. The driver registers itself as an MEI CL bus driver through
+the ``struct mei_cl_driver`` structure defined in :file:`include/linux/mei_cl_bus.c`
+
+.. code-block:: C
+
+        struct mei_cl_driver {
+                struct device_driver driver;
+                const char *name;
+
+                const struct mei_cl_device_id *id_table;
+
+                int (*probe)(struct mei_cl_device *dev, const struct mei_cl_id *id);
+                int (*remove)(struct mei_cl_device *dev);
+        };
+
+
+
+The mei_cl_device_id structure defined in :file:`include/linux/mod_devicetable.h` allows a
+driver to bind itself against a device name.
+
+.. code-block:: C
+
+        struct mei_cl_device_id {
+                char name[MEI_CL_NAME_SIZE];
+                uuid_le uuid;
+                __u8    version;
+                kernel_ulong_t driver_info;
+        };
+
+To actually register a driver on the ME Client bus one must call the :c:func:`mei_cl_add_driver`
+API. This is typically called at module initialization time.
+
+Once the driver is registered and bound to the device, a driver will typically
+try to do some I/O on this bus and this should be done through the :c:func:`mei_cl_send`
+and :c:func:`mei_cl_recv` functions. More detailed information is in :ref:`api` section.
+
+In order for a driver to be notified about pending traffic or event, the driver
+should register a callback via :c:func:`mei_cl_devev_register_rx_cb` and
+:c:func:`mei_cldev_register_notify_cb` function respectively.
+
+.. _api:
+
+API:
+----
+.. kernel-doc:: drivers/misc/mei/bus.c
+    :export: drivers/misc/mei/bus.c
+
+
+
+Example
+=======
+
+As a theoretical example let's pretend the ME comes with a "contact" NFC IP.
+The driver init and exit routines for this device would look like:
+
+.. code-block:: C
+
+        #define CONTACT_DRIVER_NAME "contact"
+
+        static struct mei_cl_device_id contact_mei_cl_tbl[] = {
+                { CONTACT_DRIVER_NAME, },
+
+                /* required last entry */
+                { }
+        };
+        MODULE_DEVICE_TABLE(mei_cl, contact_mei_cl_tbl);
+
+        static struct mei_cl_driver contact_driver = {
+                .id_table = contact_mei_tbl,
+                .name = CONTACT_DRIVER_NAME,
+
+                .probe = contact_probe,
+                .remove = contact_remove,
+        };
+
+        static int contact_init(void)
+        {
+                int r;
+
+                r = mei_cl_driver_register(&contact_driver);
+                if (r) {
+                        pr_err(CONTACT_DRIVER_NAME ": driver registration failed\n");
+                        return r;
+                }
+
+                return 0;
+        }
+
+        static void __exit contact_exit(void)
+        {
+                mei_cl_driver_unregister(&contact_driver);
+        }
+
+        module_init(contact_init);
+        module_exit(contact_exit);
+
+And the driver's simplified probe routine would look like that:
+
+.. code-block:: C
+
+        int contact_probe(struct mei_cl_device *dev, struct mei_cl_device_id *id)
+        {
+                [...]
+                mei_cldev_enable(dev);
+
+                mei_cldev_register_rx_cb(dev, contact_rx_cb);
+
+                return 0;
+        }
+
+In the probe routine the driver first enable the MEI device and then registers
+an rx handler which is as close as it can get to registering a threaded IRQ handler.
+The handler implementation will typically call :c:func:`mei_cldev_recv` and then
+process received data.
+
+.. code-block:: C
+
+        #define MAX_PAYLOAD 128
+        #define HDR_SIZE 4
+        static void conntact_rx_cb(struct mei_cl_device *cldev)
+        {
+                struct contact *c = mei_cldev_get_drvdata(cldev);
+                unsigned char payload[MAX_PAYLOAD];
+                ssize_t payload_sz;
+
+                payload_sz = mei_cldev_recv(cldev, payload,  MAX_PAYLOAD)
+                if (reply_size < HDR_SIZE) {
+                        return;
+                }
+
+                c->process_rx(payload);
+
+        }
+
+MEI Client Bus Drivers
+======================
+
+.. toctree::
+   :maxdepth: 2
+
+   hdcp
+   nfc
diff --git a/Documentation/driver-api/mei/mei.rst b/Documentation/driver-api/mei/mei.rst
new file mode 100644 (file)
index 0000000..c800d8e
--- /dev/null
@@ -0,0 +1,176 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Introduction
+============
+
+The Intel Management Engine (Intel ME) is an isolated and protected computing
+resource (Co-processor) residing inside certain Intel chipsets. The Intel ME
+provides support for computer/IT management and security features.
+The actual feature set depends on the Intel chipset SKU.
+
+The Intel Management Engine Interface (Intel MEI, previously known as HECI)
+is the interface between the Host and Intel ME. This interface is exposed
+to the host as a PCI device, actually multiple PCI devices might be exposed.
+The Intel MEI Driver is in charge of the communication channel between
+a host application and the Intel ME features.
+
+Each Intel ME feature, or Intel ME Client is addressed by a unique GUID and
+each client has its own protocol. The protocol is message-based with a
+header and payload up to maximal number of bytes advertised by the client,
+upon connection.
+
+Intel MEI Driver
+================
+
+The driver exposes a character device with device nodes /dev/meiX.
+
+An application maintains communication with an Intel ME feature while
+/dev/meiX is open. The binding to a specific feature is performed by calling
+:c:macro:`MEI_CONNECT_CLIENT_IOCTL`, which passes the desired GUID.
+The number of instances of an Intel ME feature that can be opened
+at the same time depends on the Intel ME feature, but most of the
+features allow only a single instance.
+
+The driver is transparent to data that are passed between firmware feature
+and host application.
+
+Because some of the Intel ME features can change the system
+configuration, the driver by default allows only a privileged
+user to access it.
+
+The session is terminated calling :c:func:`close(int fd)`.
+
+A code snippet for an application communicating with Intel AMTHI client:
+
+.. code-block:: C
+
+       struct mei_connect_client_data data;
+       fd = open(MEI_DEVICE);
+
+       data.d.in_client_uuid = AMTHI_GUID;
+
+       ioctl(fd, IOCTL_MEI_CONNECT_CLIENT, &data);
+
+       printf("Ver=%d, MaxLen=%ld\n",
+              data.d.in_client_uuid.protocol_version,
+              data.d.in_client_uuid.max_msg_length);
+
+       [...]
+
+       write(fd, amthi_req_data, amthi_req_data_len);
+
+       [...]
+
+       read(fd, &amthi_res_data, amthi_res_data_len);
+
+       [...]
+       close(fd);
+
+
+User space API
+
+IOCTLs:
+=======
+
+The Intel MEI Driver supports the following IOCTL commands:
+
+IOCTL_MEI_CONNECT_CLIENT
+-------------------------
+Connect to firmware Feature/Client.
+
+.. code-block:: none
+
+       Usage:
+
+        struct mei_connect_client_data client_data;
+
+        ioctl(fd, IOCTL_MEI_CONNECT_CLIENT, &client_data);
+
+       Inputs:
+
+        struct mei_connect_client_data - contain the following
+       Input field:
+
+               in_client_uuid -        GUID of the FW Feature that needs
+                                       to connect to.
+         Outputs:
+               out_client_properties - Client Properties: MTU and Protocol Version.
+
+         Error returns:
+
+                ENOTTY  No such client (i.e. wrong GUID) or connection is not allowed.
+               EINVAL  Wrong IOCTL Number
+               ENODEV  Device or Connection is not initialized or ready.
+               ENOMEM  Unable to allocate memory to client internal data.
+               EFAULT  Fatal Error (e.g. Unable to access user input data)
+               EBUSY   Connection Already Open
+
+:Note:
+        max_msg_length (MTU) in client properties describes the maximum
+        data that can be sent or received. (e.g. if MTU=2K, can send
+        requests up to bytes 2k and received responses up to 2k bytes).
+
+
+IOCTL_MEI_NOTIFY_SET
+---------------------
+Enable or disable event notifications.
+
+
+.. code-block:: none
+
+       Usage:
+
+               uint32_t enable;
+
+               ioctl(fd, IOCTL_MEI_NOTIFY_SET, &enable);
+
+
+               uint32_t enable = 1;
+               or
+               uint32_t enable[disable] = 0;
+
+       Error returns:
+
+
+               EINVAL  Wrong IOCTL Number
+               ENODEV  Device  is not initialized or the client not connected
+               ENOMEM  Unable to allocate memory to client internal data.
+               EFAULT  Fatal Error (e.g. Unable to access user input data)
+               EOPNOTSUPP if the device doesn't support the feature
+
+:Note:
+       The client must be connected in order to enable notification events
+
+
+IOCTL_MEI_NOTIFY_GET
+--------------------
+Retrieve event
+
+.. code-block:: none
+
+       Usage:
+               uint32_t event;
+               ioctl(fd, IOCTL_MEI_NOTIFY_GET, &event);
+
+       Outputs:
+               1 - if an event is pending
+               0 - if there is no even pending
+
+       Error returns:
+               EINVAL  Wrong IOCTL Number
+               ENODEV  Device is not initialized or the client not connected
+               ENOMEM  Unable to allocate memory to client internal data.
+               EFAULT  Fatal Error (e.g. Unable to access user input data)
+               EOPNOTSUPP if the device doesn't support the feature
+
+:Note:
+       The client must be connected and event notification has to be enabled
+       in order to receive an event
+
+
+
+Supported Chipsets
+==================
+82X38/X48 Express and newer
+
+linux-mei@linux.intel.com
diff --git a/Documentation/driver-api/mei/nfc.rst b/Documentation/driver-api/mei/nfc.rst
new file mode 100644 (file)
index 0000000..b5b6fc9
--- /dev/null
@@ -0,0 +1,28 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+MEI NFC
+-------
+
+Some Intel 8 and 9 Serieses chipsets supports NFC devices connected behind
+the Intel Management Engine controller.
+MEI client bus exposes the NFC chips as NFC phy devices and enables
+binding with Microread and NXP PN544 NFC device driver from the Linux NFC
+subsystem.
+
+.. kernel-render:: DOT
+   :alt: MEI NFC digraph
+   :caption: **MEI NFC** Stack
+
+   digraph NFC {
+    cl_nfc -> me_cl_nfc;
+    "drivers/nfc/mei_phy" -> cl_nfc [lhead=bus];
+    "drivers/nfc/microread/mei" -> cl_nfc;
+    "drivers/nfc/microread/mei" -> "drivers/nfc/mei_phy";
+    "drivers/nfc/pn544/mei" -> cl_nfc;
+    "drivers/nfc/pn544/mei" -> "drivers/nfc/mei_phy";
+    "net/nfc" -> "drivers/nfc/microread/mei";
+    "net/nfc" -> "drivers/nfc/pn544/mei";
+    "neard" -> "net/nfc";
+    cl_nfc [label="mei/bus(nfc)"];
+    me_cl_nfc [label="me fw (nfc)"];
+   }
index 253f735..3a7ffb3 100644 (file)
@@ -44,7 +44,9 @@ Message transfer.
      b. Transfer message (Read/Write) to Slave1 or broadcast message on
         Bus in case of bank switch.
 
-     c. Release Message lock ::
+     c. Release Message lock
+
+     ::
 
        +----------+                    +---------+
        |          |                    |         |
diff --git a/Documentation/driver-model/binding.rst b/Documentation/driver-model/binding.rst
new file mode 100644 (file)
index 0000000..7ea1d7a
--- /dev/null
@@ -0,0 +1,98 @@
+==============
+Driver Binding
+==============
+
+Driver binding is the process of associating a device with a device
+driver that can control it. Bus drivers have typically handled this
+because there have been bus-specific structures to represent the
+devices and the drivers. With generic device and device driver
+structures, most of the binding can take place using common code.
+
+
+Bus
+~~~
+
+The bus type structure contains a list of all devices that are on that bus
+type in the system. When device_register is called for a device, it is
+inserted into the end of this list. The bus object also contains a
+list of all drivers of that bus type. When driver_register is called
+for a driver, it is inserted at the end of this list. These are the
+two events which trigger driver binding.
+
+
+device_register
+~~~~~~~~~~~~~~~
+
+When a new device is added, the bus's list of drivers is iterated over
+to find one that supports it. In order to determine that, the device
+ID of the device must match one of the device IDs that the driver
+supports. The format and semantics for comparing IDs is bus-specific.
+Instead of trying to derive a complex state machine and matching
+algorithm, it is up to the bus driver to provide a callback to compare
+a device against the IDs of a driver. The bus returns 1 if a match was
+found; 0 otherwise.
+
+int match(struct device * dev, struct device_driver * drv);
+
+If a match is found, the device's driver field is set to the driver
+and the driver's probe callback is called. This gives the driver a
+chance to verify that it really does support the hardware, and that
+it's in a working state.
+
+Device Class
+~~~~~~~~~~~~
+
+Upon the successful completion of probe, the device is registered with
+the class to which it belongs. Device drivers belong to one and only one
+class, and that is set in the driver's devclass field.
+devclass_add_device is called to enumerate the device within the class
+and actually register it with the class, which happens with the
+class's register_dev callback.
+
+
+Driver
+~~~~~~
+
+When a driver is attached to a device, the device is inserted into the
+driver's list of devices.
+
+
+sysfs
+~~~~~
+
+A symlink is created in the bus's 'devices' directory that points to
+the device's directory in the physical hierarchy.
+
+A symlink is created in the driver's 'devices' directory that points
+to the device's directory in the physical hierarchy.
+
+A directory for the device is created in the class's directory. A
+symlink is created in that directory that points to the device's
+physical location in the sysfs tree.
+
+A symlink can be created (though this isn't done yet) in the device's
+physical directory to either its class directory, or the class's
+top-level directory. One can also be created to point to its driver's
+directory also.
+
+
+driver_register
+~~~~~~~~~~~~~~~
+
+The process is almost identical for when a new driver is added.
+The bus's list of devices is iterated over to find a match. Devices
+that already have a driver are skipped. All the devices are iterated
+over, to bind as many devices as possible to the driver.
+
+
+Removal
+~~~~~~~
+
+When a device is removed, the reference count for it will eventually
+go to 0. When it does, the remove callback of the driver is called. It
+is removed from the driver's list of devices and the reference count
+of the driver is decremented. All symlinks between the two are removed.
+
+When a driver is removed, the list of devices that it supports is
+iterated over, and the driver's remove callback is called for each
+one. The device is removed from that list and the symlinks removed.
diff --git a/Documentation/driver-model/binding.txt b/Documentation/driver-model/binding.txt
deleted file mode 100644 (file)
index abfc8e2..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-
-Driver Binding
-
-Driver binding is the process of associating a device with a device
-driver that can control it. Bus drivers have typically handled this
-because there have been bus-specific structures to represent the
-devices and the drivers. With generic device and device driver
-structures, most of the binding can take place using common code.
-
-
-Bus
-~~~
-
-The bus type structure contains a list of all devices that are on that bus
-type in the system. When device_register is called for a device, it is
-inserted into the end of this list. The bus object also contains a
-list of all drivers of that bus type. When driver_register is called
-for a driver, it is inserted at the end of this list. These are the
-two events which trigger driver binding.
-
-
-device_register
-~~~~~~~~~~~~~~~
-
-When a new device is added, the bus's list of drivers is iterated over
-to find one that supports it. In order to determine that, the device
-ID of the device must match one of the device IDs that the driver
-supports. The format and semantics for comparing IDs is bus-specific. 
-Instead of trying to derive a complex state machine and matching
-algorithm, it is up to the bus driver to provide a callback to compare
-a device against the IDs of a driver. The bus returns 1 if a match was
-found; 0 otherwise.
-
-int match(struct device * dev, struct device_driver * drv);
-
-If a match is found, the device's driver field is set to the driver
-and the driver's probe callback is called. This gives the driver a
-chance to verify that it really does support the hardware, and that
-it's in a working state. 
-
-Device Class
-~~~~~~~~~~~~
-
-Upon the successful completion of probe, the device is registered with
-the class to which it belongs. Device drivers belong to one and only one
-class, and that is set in the driver's devclass field. 
-devclass_add_device is called to enumerate the device within the class
-and actually register it with the class, which happens with the
-class's register_dev callback.
-
-
-Driver
-~~~~~~
-
-When a driver is attached to a device, the device is inserted into the
-driver's list of devices. 
-
-
-sysfs
-~~~~~
-
-A symlink is created in the bus's 'devices' directory that points to
-the device's directory in the physical hierarchy.
-
-A symlink is created in the driver's 'devices' directory that points
-to the device's directory in the physical hierarchy.
-
-A directory for the device is created in the class's directory. A
-symlink is created in that directory that points to the device's
-physical location in the sysfs tree. 
-
-A symlink can be created (though this isn't done yet) in the device's
-physical directory to either its class directory, or the class's
-top-level directory. One can also be created to point to its driver's
-directory also. 
-
-
-driver_register
-~~~~~~~~~~~~~~~
-
-The process is almost identical for when a new driver is added. 
-The bus's list of devices is iterated over to find a match. Devices
-that already have a driver are skipped. All the devices are iterated
-over, to bind as many devices as possible to the driver.
-
-
-Removal
-~~~~~~~
-
-When a device is removed, the reference count for it will eventually
-go to 0. When it does, the remove callback of the driver is called. It
-is removed from the driver's list of devices and the reference count
-of the driver is decremented. All symlinks between the two are removed.
-
-When a driver is removed, the list of devices that it supports is
-iterated over, and the driver's remove callback is called for each
-one. The device is removed from that list and the symlinks removed. 
-
diff --git a/Documentation/driver-model/bus.rst b/Documentation/driver-model/bus.rst
new file mode 100644 (file)
index 0000000..016b15a
--- /dev/null
@@ -0,0 +1,146 @@
+=========
+Bus Types
+=========
+
+Definition
+~~~~~~~~~~
+See the kerneldoc for the struct bus_type.
+
+int bus_register(struct bus_type * bus);
+
+
+Declaration
+~~~~~~~~~~~
+
+Each bus type in the kernel (PCI, USB, etc) should declare one static
+object of this type. They must initialize the name field, and may
+optionally initialize the match callback::
+
+   struct bus_type pci_bus_type = {
+          .name        = "pci",
+          .match       = pci_bus_match,
+   };
+
+The structure should be exported to drivers in a header file:
+
+extern struct bus_type pci_bus_type;
+
+
+Registration
+~~~~~~~~~~~~
+
+When a bus driver is initialized, it calls bus_register. This
+initializes the rest of the fields in the bus object and inserts it
+into a global list of bus types. Once the bus object is registered,
+the fields in it are usable by the bus driver.
+
+
+Callbacks
+~~~~~~~~~
+
+match(): Attaching Drivers to Devices
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The format of device ID structures and the semantics for comparing
+them are inherently bus-specific. Drivers typically declare an array
+of device IDs of devices they support that reside in a bus-specific
+driver structure.
+
+The purpose of the match callback is to give the bus an opportunity to
+determine if a particular driver supports a particular device by
+comparing the device IDs the driver supports with the device ID of a
+particular device, without sacrificing bus-specific functionality or
+type-safety.
+
+When a driver is registered with the bus, the bus's list of devices is
+iterated over, and the match callback is called for each device that
+does not have a driver associated with it.
+
+
+
+Device and Driver Lists
+~~~~~~~~~~~~~~~~~~~~~~~
+
+The lists of devices and drivers are intended to replace the local
+lists that many buses keep. They are lists of struct devices and
+struct device_drivers, respectively. Bus drivers are free to use the
+lists as they please, but conversion to the bus-specific type may be
+necessary.
+
+The LDM core provides helper functions for iterating over each list::
+
+  int bus_for_each_dev(struct bus_type * bus, struct device * start,
+                      void * data,
+                      int (*fn)(struct device *, void *));
+
+  int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
+                      void * data, int (*fn)(struct device_driver *, void *));
+
+These helpers iterate over the respective list, and call the callback
+for each device or driver in the list. All list accesses are
+synchronized by taking the bus's lock (read currently). The reference
+count on each object in the list is incremented before the callback is
+called; it is decremented after the next object has been obtained. The
+lock is not held when calling the callback.
+
+
+sysfs
+~~~~~~~~
+There is a top-level directory named 'bus'.
+
+Each bus gets a directory in the bus directory, along with two default
+directories::
+
+       /sys/bus/pci/
+       |-- devices
+       `-- drivers
+
+Drivers registered with the bus get a directory in the bus's drivers
+directory::
+
+       /sys/bus/pci/
+       |-- devices
+       `-- drivers
+           |-- Intel ICH
+           |-- Intel ICH Joystick
+           |-- agpgart
+           `-- e100
+
+Each device that is discovered on a bus of that type gets a symlink in
+the bus's devices directory to the device's directory in the physical
+hierarchy::
+
+       /sys/bus/pci/
+       |-- devices
+       |   |-- 00:00.0 -> ../../../root/pci0/00:00.0
+       |   |-- 00:01.0 -> ../../../root/pci0/00:01.0
+       |   `-- 00:02.0 -> ../../../root/pci0/00:02.0
+       `-- drivers
+
+
+Exporting Attributes
+~~~~~~~~~~~~~~~~~~~~
+
+::
+
+  struct bus_attribute {
+       struct attribute        attr;
+       ssize_t (*show)(struct bus_type *, char * buf);
+       ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
+  };
+
+Bus drivers can export attributes using the BUS_ATTR_RW macro that works
+similarly to the DEVICE_ATTR_RW macro for devices. For example, a
+definition like this::
+
+       static BUS_ATTR_RW(debug);
+
+is equivalent to declaring::
+
+       static bus_attribute bus_attr_debug;
+
+This can then be used to add and remove the attribute from the bus's
+sysfs directory using::
+
+       int bus_create_file(struct bus_type *, struct bus_attribute *);
+       void bus_remove_file(struct bus_type *, struct bus_attribute *);
diff --git a/Documentation/driver-model/bus.txt b/Documentation/driver-model/bus.txt
deleted file mode 100644 (file)
index c247b48..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-
-Bus Types 
-
-Definition
-~~~~~~~~~~
-See the kerneldoc for the struct bus_type.
-
-int bus_register(struct bus_type * bus);
-
-
-Declaration
-~~~~~~~~~~~
-
-Each bus type in the kernel (PCI, USB, etc) should declare one static
-object of this type. They must initialize the name field, and may
-optionally initialize the match callback.
-
-struct bus_type pci_bus_type = {
-       .name   = "pci",
-       .match  = pci_bus_match,
-};
-
-The structure should be exported to drivers in a header file:
-
-extern struct bus_type pci_bus_type;
-
-
-Registration
-~~~~~~~~~~~~
-
-When a bus driver is initialized, it calls bus_register. This
-initializes the rest of the fields in the bus object and inserts it
-into a global list of bus types. Once the bus object is registered, 
-the fields in it are usable by the bus driver. 
-
-
-Callbacks
-~~~~~~~~~
-
-match(): Attaching Drivers to Devices
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The format of device ID structures and the semantics for comparing
-them are inherently bus-specific. Drivers typically declare an array
-of device IDs of devices they support that reside in a bus-specific
-driver structure. 
-
-The purpose of the match callback is to give the bus an opportunity to
-determine if a particular driver supports a particular device by
-comparing the device IDs the driver supports with the device ID of a
-particular device, without sacrificing bus-specific functionality or
-type-safety. 
-
-When a driver is registered with the bus, the bus's list of devices is
-iterated over, and the match callback is called for each device that
-does not have a driver associated with it. 
-
-
-
-Device and Driver Lists
-~~~~~~~~~~~~~~~~~~~~~~~
-
-The lists of devices and drivers are intended to replace the local
-lists that many buses keep. They are lists of struct devices and
-struct device_drivers, respectively. Bus drivers are free to use the
-lists as they please, but conversion to the bus-specific type may be
-necessary. 
-
-The LDM core provides helper functions for iterating over each list.
-
-int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data,
-                    int (*fn)(struct device *, void *));
-
-int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, 
-                    void * data, int (*fn)(struct device_driver *, void *));
-
-These helpers iterate over the respective list, and call the callback
-for each device or driver in the list. All list accesses are
-synchronized by taking the bus's lock (read currently). The reference
-count on each object in the list is incremented before the callback is
-called; it is decremented after the next object has been obtained. The
-lock is not held when calling the callback. 
-
-
-sysfs
-~~~~~~~~
-There is a top-level directory named 'bus'.
-
-Each bus gets a directory in the bus directory, along with two default
-directories:
-
-       /sys/bus/pci/
-       |-- devices
-       `-- drivers
-
-Drivers registered with the bus get a directory in the bus's drivers
-directory:
-
-       /sys/bus/pci/
-       |-- devices
-       `-- drivers
-           |-- Intel ICH
-           |-- Intel ICH Joystick
-           |-- agpgart
-           `-- e100
-
-Each device that is discovered on a bus of that type gets a symlink in
-the bus's devices directory to the device's directory in the physical
-hierarchy:
-
-       /sys/bus/pci/
-       |-- devices
-       |   |-- 00:00.0 -> ../../../root/pci0/00:00.0
-       |   |-- 00:01.0 -> ../../../root/pci0/00:01.0
-       |   `-- 00:02.0 -> ../../../root/pci0/00:02.0
-       `-- drivers
-
-
-Exporting Attributes
-~~~~~~~~~~~~~~~~~~~~
-struct bus_attribute {
-       struct attribute        attr;
-       ssize_t (*show)(struct bus_type *, char * buf);
-       ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
-};
-
-Bus drivers can export attributes using the BUS_ATTR_RW macro that works
-similarly to the DEVICE_ATTR_RW macro for devices. For example, a
-definition like this:
-
-static BUS_ATTR_RW(debug);
-
-is equivalent to declaring:
-
-static bus_attribute bus_attr_debug;
-
-This can then be used to add and remove the attribute from the bus's
-sysfs directory using:
-
-int bus_create_file(struct bus_type *, struct bus_attribute *);
-void bus_remove_file(struct bus_type *, struct bus_attribute *);
-
-
diff --git a/Documentation/driver-model/class.rst b/Documentation/driver-model/class.rst
new file mode 100644 (file)
index 0000000..fff55b8
--- /dev/null
@@ -0,0 +1,149 @@
+==============
+Device Classes
+==============
+
+Introduction
+~~~~~~~~~~~~
+A device class describes a type of device, like an audio or network
+device. The following device classes have been identified:
+
+<Insert List of Device Classes Here>
+
+
+Each device class defines a set of semantics and a programming interface
+that devices of that class adhere to. Device drivers are the
+implementation of that programming interface for a particular device on
+a particular bus.
+
+Device classes are agnostic with respect to what bus a device resides
+on.
+
+
+Programming Interface
+~~~~~~~~~~~~~~~~~~~~~
+The device class structure looks like::
+
+
+  typedef int (*devclass_add)(struct device *);
+  typedef void (*devclass_remove)(struct device *);
+
+See the kerneldoc for the struct class.
+
+A typical device class definition would look like::
+
+  struct device_class input_devclass = {
+        .name          = "input",
+        .add_device    = input_add_device,
+       .remove_device  = input_remove_device,
+  };
+
+Each device class structure should be exported in a header file so it
+can be used by drivers, extensions and interfaces.
+
+Device classes are registered and unregistered with the core using::
+
+  int devclass_register(struct device_class * cls);
+  void devclass_unregister(struct device_class * cls);
+
+
+Devices
+~~~~~~~
+As devices are bound to drivers, they are added to the device class
+that the driver belongs to. Before the driver model core, this would
+typically happen during the driver's probe() callback, once the device
+has been initialized. It now happens after the probe() callback
+finishes from the core.
+
+The device is enumerated in the class. Each time a device is added to
+the class, the class's devnum field is incremented and assigned to the
+device. The field is never decremented, so if the device is removed
+from the class and re-added, it will receive a different enumerated
+value.
+
+The class is allowed to create a class-specific structure for the
+device and store it in the device's class_data pointer.
+
+There is no list of devices in the device class. Each driver has a
+list of devices that it supports. The device class has a list of
+drivers of that particular class. To access all of the devices in the
+class, iterate over the device lists of each driver in the class.
+
+
+Device Drivers
+~~~~~~~~~~~~~~
+Device drivers are added to device classes when they are registered
+with the core. A driver specifies the class it belongs to by setting
+the struct device_driver::devclass field.
+
+
+sysfs directory structure
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+There is a top-level sysfs directory named 'class'.
+
+Each class gets a directory in the class directory, along with two
+default subdirectories::
+
+        class/
+        `-- input
+            |-- devices
+            `-- drivers
+
+
+Drivers registered with the class get a symlink in the drivers/ directory
+that points to the driver's directory (under its bus directory)::
+
+   class/
+   `-- input
+       |-- devices
+       `-- drivers
+           `-- usb:usb_mouse -> ../../../bus/drivers/usb_mouse/
+
+
+Each device gets a symlink in the devices/ directory that points to the
+device's directory in the physical hierarchy::
+
+   class/
+   `-- input
+       |-- devices
+       |   `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/
+       `-- drivers
+
+
+Exporting Attributes
+~~~~~~~~~~~~~~~~~~~~
+
+::
+
+  struct devclass_attribute {
+        struct attribute        attr;
+        ssize_t (*show)(struct device_class *, char * buf, size_t count, loff_t off);
+        ssize_t (*store)(struct device_class *, const char * buf, size_t count, loff_t off);
+  };
+
+Class drivers can export attributes using the DEVCLASS_ATTR macro that works
+similarly to the DEVICE_ATTR macro for devices. For example, a definition
+like this::
+
+  static DEVCLASS_ATTR(debug,0644,show_debug,store_debug);
+
+is equivalent to declaring::
+
+  static devclass_attribute devclass_attr_debug;
+
+The bus driver can add and remove the attribute from the class's
+sysfs directory using::
+
+  int devclass_create_file(struct device_class *, struct devclass_attribute *);
+  void devclass_remove_file(struct device_class *, struct devclass_attribute *);
+
+In the example above, the file will be named 'debug' in placed in the
+class's directory in sysfs.
+
+
+Interfaces
+~~~~~~~~~~
+There may exist multiple mechanisms for accessing the same device of a
+particular class type. Device interfaces describe these mechanisms.
+
+When a device is added to a device class, the core attempts to add it
+to every interface that is registered with the device class.
diff --git a/Documentation/driver-model/class.txt b/Documentation/driver-model/class.txt
deleted file mode 100644 (file)
index 1fefc48..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-
-Device Classes
-
-
-Introduction
-~~~~~~~~~~~~
-A device class describes a type of device, like an audio or network
-device. The following device classes have been identified:
-
-<Insert List of Device Classes Here>
-
-
-Each device class defines a set of semantics and a programming interface
-that devices of that class adhere to. Device drivers are the
-implementation of that programming interface for a particular device on
-a particular bus. 
-
-Device classes are agnostic with respect to what bus a device resides
-on. 
-
-
-Programming Interface
-~~~~~~~~~~~~~~~~~~~~~
-The device class structure looks like: 
-
-
-typedef int (*devclass_add)(struct device *);
-typedef void (*devclass_remove)(struct device *);
-
-See the kerneldoc for the struct class.
-
-A typical device class definition would look like: 
-
-struct device_class input_devclass = {
-        .name          = "input",
-        .add_device    = input_add_device,
-       .remove_device  = input_remove_device,
-};
-
-Each device class structure should be exported in a header file so it
-can be used by drivers, extensions and interfaces.
-
-Device classes are registered and unregistered with the core using: 
-
-int devclass_register(struct device_class * cls);
-void devclass_unregister(struct device_class * cls);
-
-
-Devices
-~~~~~~~
-As devices are bound to drivers, they are added to the device class
-that the driver belongs to. Before the driver model core, this would
-typically happen during the driver's probe() callback, once the device
-has been initialized. It now happens after the probe() callback
-finishes from the core. 
-
-The device is enumerated in the class. Each time a device is added to
-the class, the class's devnum field is incremented and assigned to the
-device. The field is never decremented, so if the device is removed
-from the class and re-added, it will receive a different enumerated
-value. 
-
-The class is allowed to create a class-specific structure for the
-device and store it in the device's class_data pointer. 
-
-There is no list of devices in the device class. Each driver has a
-list of devices that it supports. The device class has a list of
-drivers of that particular class. To access all of the devices in the
-class, iterate over the device lists of each driver in the class.
-
-
-Device Drivers
-~~~~~~~~~~~~~~
-Device drivers are added to device classes when they are registered
-with the core. A driver specifies the class it belongs to by setting
-the struct device_driver::devclass field. 
-
-
-sysfs directory structure
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-There is a top-level sysfs directory named 'class'. 
-
-Each class gets a directory in the class directory, along with two
-default subdirectories:
-
-        class/
-        `-- input
-            |-- devices
-            `-- drivers
-
-
-Drivers registered with the class get a symlink in the drivers/ directory 
-that points to the driver's directory (under its bus directory):
-
-   class/
-   `-- input
-       |-- devices
-       `-- drivers
-           `-- usb:usb_mouse -> ../../../bus/drivers/usb_mouse/
-
-
-Each device gets a symlink in the devices/ directory that points to the 
-device's directory in the physical hierarchy:
-
-   class/
-   `-- input
-       |-- devices
-       |   `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/
-       `-- drivers
-
-
-Exporting Attributes
-~~~~~~~~~~~~~~~~~~~~
-struct devclass_attribute {
-        struct attribute        attr;
-        ssize_t (*show)(struct device_class *, char * buf, size_t count, loff_t off);
-        ssize_t (*store)(struct device_class *, const char * buf, size_t count, loff_t off);
-};
-
-Class drivers can export attributes using the DEVCLASS_ATTR macro that works
-similarly to the DEVICE_ATTR macro for devices. For example, a definition 
-like this:
-
-static DEVCLASS_ATTR(debug,0644,show_debug,store_debug);
-
-is equivalent to declaring:
-
-static devclass_attribute devclass_attr_debug;
-
-The bus driver can add and remove the attribute from the class's
-sysfs directory using:
-
-int devclass_create_file(struct device_class *, struct devclass_attribute *);
-void devclass_remove_file(struct device_class *, struct devclass_attribute *);
-
-In the example above, the file will be named 'debug' in placed in the
-class's directory in sysfs. 
-
-
-Interfaces
-~~~~~~~~~~
-There may exist multiple mechanisms for accessing the same device of a
-particular class type. Device interfaces describe these mechanisms. 
-
-When a device is added to a device class, the core attempts to add it
-to every interface that is registered with the device class.
-
diff --git a/Documentation/driver-model/design-patterns.rst b/Documentation/driver-model/design-patterns.rst
new file mode 100644 (file)
index 0000000..41eb8f4
--- /dev/null
@@ -0,0 +1,116 @@
+=============================
+Device Driver Design Patterns
+=============================
+
+This document describes a few common design patterns found in device drivers.
+It is likely that subsystem maintainers will ask driver developers to
+conform to these design patterns.
+
+1. State Container
+2. container_of()
+
+
+1. State Container
+~~~~~~~~~~~~~~~~~~
+
+While the kernel contains a few device drivers that assume that they will
+only be probed() once on a certain system (singletons), it is custom to assume
+that the device the driver binds to will appear in several instances. This
+means that the probe() function and all callbacks need to be reentrant.
+
+The most common way to achieve this is to use the state container design
+pattern. It usually has this form::
+
+  struct foo {
+      spinlock_t lock; /* Example member */
+      (...)
+  };
+
+  static int foo_probe(...)
+  {
+      struct foo *foo;
+
+      foo = devm_kzalloc(dev, sizeof(*foo), GFP_KERNEL);
+      if (!foo)
+          return -ENOMEM;
+      spin_lock_init(&foo->lock);
+      (...)
+  }
+
+This will create an instance of struct foo in memory every time probe() is
+called. This is our state container for this instance of the device driver.
+Of course it is then necessary to always pass this instance of the
+state around to all functions that need access to the state and its members.
+
+For example, if the driver is registering an interrupt handler, you would
+pass around a pointer to struct foo like this::
+
+  static irqreturn_t foo_handler(int irq, void *arg)
+  {
+      struct foo *foo = arg;
+      (...)
+  }
+
+  static int foo_probe(...)
+  {
+      struct foo *foo;
+
+      (...)
+      ret = request_irq(irq, foo_handler, 0, "foo", foo);
+  }
+
+This way you always get a pointer back to the correct instance of foo in
+your interrupt handler.
+
+
+2. container_of()
+~~~~~~~~~~~~~~~~~
+
+Continuing on the above example we add an offloaded work::
+
+  struct foo {
+      spinlock_t lock;
+      struct workqueue_struct *wq;
+      struct work_struct offload;
+      (...)
+  };
+
+  static void foo_work(struct work_struct *work)
+  {
+      struct foo *foo = container_of(work, struct foo, offload);
+
+      (...)
+  }
+
+  static irqreturn_t foo_handler(int irq, void *arg)
+  {
+      struct foo *foo = arg;
+
+      queue_work(foo->wq, &foo->offload);
+      (...)
+  }
+
+  static int foo_probe(...)
+  {
+      struct foo *foo;
+
+      foo->wq = create_singlethread_workqueue("foo-wq");
+      INIT_WORK(&foo->offload, foo_work);
+      (...)
+  }
+
+The design pattern is the same for an hrtimer or something similar that will
+return a single argument which is a pointer to a struct member in the
+callback.
+
+container_of() is a macro defined in <linux/kernel.h>
+
+What container_of() does is to obtain a pointer to the containing struct from
+a pointer to a member by a simple subtraction using the offsetof() macro from
+standard C, which allows something similar to object oriented behaviours.
+Notice that the contained member must not be a pointer, but an actual member
+for this to work.
+
+We can see here that we avoid having global pointers to our struct foo *
+instance this way, while still keeping the number of parameters passed to the
+work function to a single pointer.
diff --git a/Documentation/driver-model/design-patterns.txt b/Documentation/driver-model/design-patterns.txt
deleted file mode 100644 (file)
index ba7b2df..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-
-Device Driver Design Patterns
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This document describes a few common design patterns found in device drivers.
-It is likely that subsystem maintainers will ask driver developers to
-conform to these design patterns.
-
-1. State Container
-2. container_of()
-
-
-1. State Container
-~~~~~~~~~~~~~~~~~~
-
-While the kernel contains a few device drivers that assume that they will
-only be probed() once on a certain system (singletons), it is custom to assume
-that the device the driver binds to will appear in several instances. This
-means that the probe() function and all callbacks need to be reentrant.
-
-The most common way to achieve this is to use the state container design
-pattern. It usually has this form:
-
-struct foo {
-    spinlock_t lock; /* Example member */
-    (...)
-};
-
-static int foo_probe(...)
-{
-    struct foo *foo;
-
-    foo = devm_kzalloc(dev, sizeof(*foo), GFP_KERNEL);
-    if (!foo)
-        return -ENOMEM;
-    spin_lock_init(&foo->lock);
-    (...)
-}
-
-This will create an instance of struct foo in memory every time probe() is
-called. This is our state container for this instance of the device driver.
-Of course it is then necessary to always pass this instance of the
-state around to all functions that need access to the state and its members.
-
-For example, if the driver is registering an interrupt handler, you would
-pass around a pointer to struct foo like this:
-
-static irqreturn_t foo_handler(int irq, void *arg)
-{
-    struct foo *foo = arg;
-    (...)
-}
-
-static int foo_probe(...)
-{
-    struct foo *foo;
-
-    (...)
-    ret = request_irq(irq, foo_handler, 0, "foo", foo);
-}
-
-This way you always get a pointer back to the correct instance of foo in
-your interrupt handler.
-
-
-2. container_of()
-~~~~~~~~~~~~~~~~~
-
-Continuing on the above example we add an offloaded work:
-
-struct foo {
-    spinlock_t lock;
-    struct workqueue_struct *wq;
-    struct work_struct offload;
-    (...)
-};
-
-static void foo_work(struct work_struct *work)
-{
-    struct foo *foo = container_of(work, struct foo, offload);
-
-    (...)
-}
-
-static irqreturn_t foo_handler(int irq, void *arg)
-{
-    struct foo *foo = arg;
-
-    queue_work(foo->wq, &foo->offload);
-    (...)
-}
-
-static int foo_probe(...)
-{
-    struct foo *foo;
-
-    foo->wq = create_singlethread_workqueue("foo-wq");
-    INIT_WORK(&foo->offload, foo_work);
-    (...)
-}
-
-The design pattern is the same for an hrtimer or something similar that will
-return a single argument which is a pointer to a struct member in the
-callback.
-
-container_of() is a macro defined in <linux/kernel.h>
-
-What container_of() does is to obtain a pointer to the containing struct from
-a pointer to a member by a simple subtraction using the offsetof() macro from
-standard C, which allows something similar to object oriented behaviours.
-Notice that the contained member must not be a pointer, but an actual member
-for this to work.
-
-We can see here that we avoid having global pointers to our struct foo *
-instance this way, while still keeping the number of parameters passed to the
-work function to a single pointer.
diff --git a/Documentation/driver-model/device.rst b/Documentation/driver-model/device.rst
new file mode 100644 (file)
index 0000000..2b868d4
--- /dev/null
@@ -0,0 +1,109 @@
+==========================
+The Basic Device Structure
+==========================
+
+See the kerneldoc for the struct device.
+
+
+Programming Interface
+~~~~~~~~~~~~~~~~~~~~~
+The bus driver that discovers the device uses this to register the
+device with the core::
+
+  int device_register(struct device * dev);
+
+The bus should initialize the following fields:
+
+    - parent
+    - name
+    - bus_id
+    - bus
+
+A device is removed from the core when its reference count goes to
+0. The reference count can be adjusted using::
+
+  struct device * get_device(struct device * dev);
+  void put_device(struct device * dev);
+
+get_device() will return a pointer to the struct device passed to it
+if the reference is not already 0 (if it's in the process of being
+removed already).
+
+A driver can access the lock in the device structure using::
+
+  void lock_device(struct device * dev);
+  void unlock_device(struct device * dev);
+
+
+Attributes
+~~~~~~~~~~
+
+::
+
+  struct device_attribute {
+       struct attribute        attr;
+       ssize_t (*show)(struct device *dev, struct device_attribute *attr,
+                       char *buf);
+       ssize_t (*store)(struct device *dev, struct device_attribute *attr,
+                        const char *buf, size_t count);
+  };
+
+Attributes of devices can be exported by a device driver through sysfs.
+
+Please see Documentation/filesystems/sysfs.txt for more information
+on how sysfs works.
+
+As explained in Documentation/kobject.txt, device attributes must be
+created before the KOBJ_ADD uevent is generated. The only way to realize
+that is by defining an attribute group.
+
+Attributes are declared using a macro called DEVICE_ATTR::
+
+  #define DEVICE_ATTR(name,mode,show,store)
+
+Example:::
+
+  static DEVICE_ATTR(type, 0444, show_type, NULL);
+  static DEVICE_ATTR(power, 0644, show_power, store_power);
+
+This declares two structures of type struct device_attribute with respective
+names 'dev_attr_type' and 'dev_attr_power'. These two attributes can be
+organized as follows into a group::
+
+  static struct attribute *dev_attrs[] = {
+       &dev_attr_type.attr,
+       &dev_attr_power.attr,
+       NULL,
+  };
+
+  static struct attribute_group dev_attr_group = {
+       .attrs = dev_attrs,
+  };
+
+  static const struct attribute_group *dev_attr_groups[] = {
+       &dev_attr_group,
+       NULL,
+  };
+
+This array of groups can then be associated with a device by setting the
+group pointer in struct device before device_register() is invoked::
+
+        dev->groups = dev_attr_groups;
+        device_register(dev);
+
+The device_register() function will use the 'groups' pointer to create the
+device attributes and the device_unregister() function will use this pointer
+to remove the device attributes.
+
+Word of warning:  While the kernel allows device_create_file() and
+device_remove_file() to be called on a device at any time, userspace has
+strict expectations on when attributes get created.  When a new device is
+registered in the kernel, a uevent is generated to notify userspace (like
+udev) that a new device is available.  If attributes are added after the
+device is registered, then userspace won't get notified and userspace will
+not know about the new attributes.
+
+This is important for device driver that need to publish additional
+attributes for a device at driver probe time.  If the device driver simply
+calls device_create_file() on the device structure passed to it, then
+userspace will never be notified of the new attributes.
diff --git a/Documentation/driver-model/device.txt b/Documentation/driver-model/device.txt
deleted file mode 100644 (file)
index 2403eb8..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-
-The Basic Device Structure
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-See the kerneldoc for the struct device.
-
-
-Programming Interface
-~~~~~~~~~~~~~~~~~~~~~
-The bus driver that discovers the device uses this to register the
-device with the core:
-
-int device_register(struct device * dev);
-
-The bus should initialize the following fields:
-
-    - parent
-    - name
-    - bus_id
-    - bus
-
-A device is removed from the core when its reference count goes to
-0. The reference count can be adjusted using:
-
-struct device * get_device(struct device * dev);
-void put_device(struct device * dev);
-
-get_device() will return a pointer to the struct device passed to it
-if the reference is not already 0 (if it's in the process of being
-removed already).
-
-A driver can access the lock in the device structure using: 
-
-void lock_device(struct device * dev);
-void unlock_device(struct device * dev);
-
-
-Attributes
-~~~~~~~~~~
-struct device_attribute {
-       struct attribute        attr;
-       ssize_t (*show)(struct device *dev, struct device_attribute *attr,
-                       char *buf);
-       ssize_t (*store)(struct device *dev, struct device_attribute *attr,
-                        const char *buf, size_t count);
-};
-
-Attributes of devices can be exported by a device driver through sysfs.
-
-Please see Documentation/filesystems/sysfs.txt for more information
-on how sysfs works.
-
-As explained in Documentation/kobject.txt, device attributes must be
-created before the KOBJ_ADD uevent is generated. The only way to realize
-that is by defining an attribute group.
-
-Attributes are declared using a macro called DEVICE_ATTR:
-
-#define DEVICE_ATTR(name,mode,show,store)
-
-Example:
-
-static DEVICE_ATTR(type, 0444, show_type, NULL);
-static DEVICE_ATTR(power, 0644, show_power, store_power);
-
-This declares two structures of type struct device_attribute with respective
-names 'dev_attr_type' and 'dev_attr_power'. These two attributes can be
-organized as follows into a group:
-
-static struct attribute *dev_attrs[] = {
-       &dev_attr_type.attr,
-       &dev_attr_power.attr,
-       NULL,
-};
-
-static struct attribute_group dev_attr_group = {
-       .attrs = dev_attrs,
-};
-
-static const struct attribute_group *dev_attr_groups[] = {
-       &dev_attr_group,
-       NULL,
-};
-
-This array of groups can then be associated with a device by setting the
-group pointer in struct device before device_register() is invoked:
-
-      dev->groups = dev_attr_groups;
-      device_register(dev);
-
-The device_register() function will use the 'groups' pointer to create the
-device attributes and the device_unregister() function will use this pointer
-to remove the device attributes.
-
-Word of warning:  While the kernel allows device_create_file() and
-device_remove_file() to be called on a device at any time, userspace has
-strict expectations on when attributes get created.  When a new device is
-registered in the kernel, a uevent is generated to notify userspace (like
-udev) that a new device is available.  If attributes are added after the
-device is registered, then userspace won't get notified and userspace will
-not know about the new attributes.
-
-This is important for device driver that need to publish additional
-attributes for a device at driver probe time.  If the device driver simply
-calls device_create_file() on the device structure passed to it, then
-userspace will never be notified of the new attributes.
diff --git a/Documentation/driver-model/devres.rst b/Documentation/driver-model/devres.rst
new file mode 100644 (file)
index 0000000..4ac9912
--- /dev/null
@@ -0,0 +1,414 @@
+================================
+Devres - Managed Device Resource
+================================
+
+Tejun Heo      <teheo@suse.de>
+
+First draft    10 January 2007
+
+.. contents
+
+   1. Intro                    : Huh? Devres?
+   2. Devres                   : Devres in a nutshell
+   3. Devres Group             : Group devres'es and release them together
+   4. Details                  : Life time rules, calling context, ...
+   5. Overhead                 : How much do we have to pay for this?
+   6. List of managed interfaces: Currently implemented managed interfaces
+
+
+1. Intro
+--------
+
+devres came up while trying to convert libata to use iomap.  Each
+iomapped address should be kept and unmapped on driver detach.  For
+example, a plain SFF ATA controller (that is, good old PCI IDE) in
+native mode makes use of 5 PCI BARs and all of them should be
+maintained.
+
+As with many other device drivers, libata low level drivers have
+sufficient bugs in ->remove and ->probe failure path.  Well, yes,
+that's probably because libata low level driver developers are lazy
+bunch, but aren't all low level driver developers?  After spending a
+day fiddling with braindamaged hardware with no document or
+braindamaged document, if it's finally working, well, it's working.
+
+For one reason or another, low level drivers don't receive as much
+attention or testing as core code, and bugs on driver detach or
+initialization failure don't happen often enough to be noticeable.
+Init failure path is worse because it's much less travelled while
+needs to handle multiple entry points.
+
+So, many low level drivers end up leaking resources on driver detach
+and having half broken failure path implementation in ->probe() which
+would leak resources or even cause oops when failure occurs.  iomap
+adds more to this mix.  So do msi and msix.
+
+
+2. Devres
+---------
+
+devres is basically linked list of arbitrarily sized memory areas
+associated with a struct device.  Each devres entry is associated with
+a release function.  A devres can be released in several ways.  No
+matter what, all devres entries are released on driver detach.  On
+release, the associated release function is invoked and then the
+devres entry is freed.
+
+Managed interface is created for resources commonly used by device
+drivers using devres.  For example, coherent DMA memory is acquired
+using dma_alloc_coherent().  The managed version is called
+dmam_alloc_coherent().  It is identical to dma_alloc_coherent() except
+for the DMA memory allocated using it is managed and will be
+automatically released on driver detach.  Implementation looks like
+the following::
+
+  struct dma_devres {
+       size_t          size;
+       void            *vaddr;
+       dma_addr_t      dma_handle;
+  };
+
+  static void dmam_coherent_release(struct device *dev, void *res)
+  {
+       struct dma_devres *this = res;
+
+       dma_free_coherent(dev, this->size, this->vaddr, this->dma_handle);
+  }
+
+  dmam_alloc_coherent(dev, size, dma_handle, gfp)
+  {
+       struct dma_devres *dr;
+       void *vaddr;
+
+       dr = devres_alloc(dmam_coherent_release, sizeof(*dr), gfp);
+       ...
+
+       /* alloc DMA memory as usual */
+       vaddr = dma_alloc_coherent(...);
+       ...
+
+       /* record size, vaddr, dma_handle in dr */
+       dr->vaddr = vaddr;
+       ...
+
+       devres_add(dev, dr);
+
+       return vaddr;
+  }
+
+If a driver uses dmam_alloc_coherent(), the area is guaranteed to be
+freed whether initialization fails half-way or the device gets
+detached.  If most resources are acquired using managed interface, a
+driver can have much simpler init and exit code.  Init path basically
+looks like the following::
+
+  my_init_one()
+  {
+       struct mydev *d;
+
+       d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL);
+       if (!d)
+               return -ENOMEM;
+
+       d->ring = dmam_alloc_coherent(...);
+       if (!d->ring)
+               return -ENOMEM;
+
+       if (check something)
+               return -EINVAL;
+       ...
+
+       return register_to_upper_layer(d);
+  }
+
+And exit path::
+
+  my_remove_one()
+  {
+       unregister_from_upper_layer(d);
+       shutdown_my_hardware();
+  }
+
+As shown above, low level drivers can be simplified a lot by using
+devres.  Complexity is shifted from less maintained low level drivers
+to better maintained higher layer.  Also, as init failure path is
+shared with exit path, both can get more testing.
+
+Note though that when converting current calls or assignments to
+managed devm_* versions it is up to you to check if internal operations
+like allocating memory, have failed. Managed resources pertains to the
+freeing of these resources *only* - all other checks needed are still
+on you. In some cases this may mean introducing checks that were not
+necessary before moving to the managed devm_* calls.
+
+
+3. Devres group
+---------------
+
+Devres entries can be grouped using devres group.  When a group is
+released, all contained normal devres entries and properly nested
+groups are released.  One usage is to rollback series of acquired
+resources on failure.  For example::
+
+  if (!devres_open_group(dev, NULL, GFP_KERNEL))
+       return -ENOMEM;
+
+  acquire A;
+  if (failed)
+       goto err;
+
+  acquire B;
+  if (failed)
+       goto err;
+  ...
+
+  devres_remove_group(dev, NULL);
+  return 0;
+
+ err:
+  devres_release_group(dev, NULL);
+  return err_code;
+
+As resource acquisition failure usually means probe failure, constructs
+like above are usually useful in midlayer driver (e.g. libata core
+layer) where interface function shouldn't have side effect on failure.
+For LLDs, just returning error code suffices in most cases.
+
+Each group is identified by `void *id`.  It can either be explicitly
+specified by @id argument to devres_open_group() or automatically
+created by passing NULL as @id as in the above example.  In both
+cases, devres_open_group() returns the group's id.  The returned id
+can be passed to other devres functions to select the target group.
+If NULL is given to those functions, the latest open group is
+selected.
+
+For example, you can do something like the following::
+
+  int my_midlayer_create_something()
+  {
+       if (!devres_open_group(dev, my_midlayer_create_something, GFP_KERNEL))
+               return -ENOMEM;
+
+       ...
+
+       devres_close_group(dev, my_midlayer_create_something);
+       return 0;
+  }
+
+  void my_midlayer_destroy_something()
+  {
+       devres_release_group(dev, my_midlayer_create_something);
+  }
+
+
+4. Details
+----------
+
+Lifetime of a devres entry begins on devres allocation and finishes
+when it is released or destroyed (removed and freed) - no reference
+counting.
+
+devres core guarantees atomicity to all basic devres operations and
+has support for single-instance devres types (atomic
+lookup-and-add-if-not-found).  Other than that, synchronizing
+concurrent accesses to allocated devres data is caller's
+responsibility.  This is usually non-issue because bus ops and
+resource allocations already do the job.
+
+For an example of single-instance devres type, read pcim_iomap_table()
+in lib/devres.c.
+
+All devres interface functions can be called without context if the
+right gfp mask is given.
+
+
+5. Overhead
+-----------
+
+Each devres bookkeeping info is allocated together with requested data
+area.  With debug option turned off, bookkeeping info occupies 16
+bytes on 32bit machines and 24 bytes on 64bit (three pointers rounded
+up to ull alignment).  If singly linked list is used, it can be
+reduced to two pointers (8 bytes on 32bit, 16 bytes on 64bit).
+
+Each devres group occupies 8 pointers.  It can be reduced to 6 if
+singly linked list is used.
+
+Memory space overhead on ahci controller with two ports is between 300
+and 400 bytes on 32bit machine after naive conversion (we can
+certainly invest a bit more effort into libata core layer).
+
+
+6. List of managed interfaces
+-----------------------------
+
+CLOCK
+  devm_clk_get()
+  devm_clk_get_optional()
+  devm_clk_put()
+  devm_clk_hw_register()
+  devm_of_clk_add_hw_provider()
+  devm_clk_hw_register_clkdev()
+
+DMA
+  dmaenginem_async_device_register()
+  dmam_alloc_coherent()
+  dmam_alloc_attrs()
+  dmam_free_coherent()
+  dmam_pool_create()
+  dmam_pool_destroy()
+
+DRM
+  devm_drm_dev_init()
+
+GPIO
+  devm_gpiod_get()
+  devm_gpiod_get_index()
+  devm_gpiod_get_index_optional()
+  devm_gpiod_get_optional()
+  devm_gpiod_put()
+  devm_gpiod_unhinge()
+  devm_gpiochip_add_data()
+  devm_gpio_request()
+  devm_gpio_request_one()
+  devm_gpio_free()
+
+I2C
+  devm_i2c_new_dummy_device()
+
+IIO
+  devm_iio_device_alloc()
+  devm_iio_device_free()
+  devm_iio_device_register()
+  devm_iio_device_unregister()
+  devm_iio_kfifo_allocate()
+  devm_iio_kfifo_free()
+  devm_iio_triggered_buffer_setup()
+  devm_iio_triggered_buffer_cleanup()
+  devm_iio_trigger_alloc()
+  devm_iio_trigger_free()
+  devm_iio_trigger_register()
+  devm_iio_trigger_unregister()
+  devm_iio_channel_get()
+  devm_iio_channel_release()
+  devm_iio_channel_get_all()
+  devm_iio_channel_release_all()
+
+INPUT
+  devm_input_allocate_device()
+
+IO region
+  devm_release_mem_region()
+  devm_release_region()
+  devm_release_resource()
+  devm_request_mem_region()
+  devm_request_region()
+  devm_request_resource()
+
+IOMAP
+  devm_ioport_map()
+  devm_ioport_unmap()
+  devm_ioremap()
+  devm_ioremap_nocache()
+  devm_ioremap_wc()
+  devm_ioremap_resource() : checks resource, requests memory region, ioremaps
+  devm_iounmap()
+  pcim_iomap()
+  pcim_iomap_regions() : do request_region() and iomap() on multiple BARs
+  pcim_iomap_table()   : array of mapped addresses indexed by BAR
+  pcim_iounmap()
+
+IRQ
+  devm_free_irq()
+  devm_request_any_context_irq()
+  devm_request_irq()
+  devm_request_threaded_irq()
+  devm_irq_alloc_descs()
+  devm_irq_alloc_desc()
+  devm_irq_alloc_desc_at()
+  devm_irq_alloc_desc_from()
+  devm_irq_alloc_descs_from()
+  devm_irq_alloc_generic_chip()
+  devm_irq_setup_generic_chip()
+  devm_irq_sim_init()
+
+LED
+  devm_led_classdev_register()
+  devm_led_classdev_unregister()
+
+MDIO
+  devm_mdiobus_alloc()
+  devm_mdiobus_alloc_size()
+  devm_mdiobus_free()
+
+MEM
+  devm_free_pages()
+  devm_get_free_pages()
+  devm_kasprintf()
+  devm_kcalloc()
+  devm_kfree()
+  devm_kmalloc()
+  devm_kmalloc_array()
+  devm_kmemdup()
+  devm_kstrdup()
+  devm_kvasprintf()
+  devm_kzalloc()
+
+MFD
+  devm_mfd_add_devices()
+
+MUX
+  devm_mux_chip_alloc()
+  devm_mux_chip_register()
+  devm_mux_control_get()
+
+PER-CPU MEM
+  devm_alloc_percpu()
+  devm_free_percpu()
+
+PCI
+  devm_pci_alloc_host_bridge()  : managed PCI host bridge allocation
+  devm_pci_remap_cfgspace()    : ioremap PCI configuration space
+  devm_pci_remap_cfg_resource()        : ioremap PCI configuration space resource
+  pcim_enable_device()         : after success, all PCI ops become managed
+  pcim_pin_device()            : keep PCI device enabled after release
+
+PHY
+  devm_usb_get_phy()
+  devm_usb_put_phy()
+
+PINCTRL
+  devm_pinctrl_get()
+  devm_pinctrl_put()
+  devm_pinctrl_register()
+  devm_pinctrl_unregister()
+
+POWER
+  devm_reboot_mode_register()
+  devm_reboot_mode_unregister()
+
+PWM
+  devm_pwm_get()
+  devm_pwm_put()
+
+REGULATOR
+  devm_regulator_bulk_get()
+  devm_regulator_get()
+  devm_regulator_put()
+  devm_regulator_register()
+
+RESET
+  devm_reset_control_get()
+  devm_reset_controller_register()
+
+SERDEV
+  devm_serdev_device_open()
+
+SLAVE DMA ENGINE
+  devm_acpi_dma_controller_register()
+
+SPI
+  devm_spi_register_master()
+
+WATCHDOG
+  devm_watchdog_register_device()
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
deleted file mode 100644 (file)
index 69c7fa7..0000000
+++ /dev/null
@@ -1,412 +0,0 @@
-Devres - Managed Device Resource
-================================
-
-Tejun Heo      <teheo@suse.de>
-
-First draft    10 January 2007
-
-
-1. Intro                       : Huh? Devres?
-2. Devres                      : Devres in a nutshell
-3. Devres Group                        : Group devres'es and release them together
-4. Details                     : Life time rules, calling context, ...
-5. Overhead                    : How much do we have to pay for this?
-6. List of managed interfaces  : Currently implemented managed interfaces
-
-
-  1. Intro
-  --------
-
-devres came up while trying to convert libata to use iomap.  Each
-iomapped address should be kept and unmapped on driver detach.  For
-example, a plain SFF ATA controller (that is, good old PCI IDE) in
-native mode makes use of 5 PCI BARs and all of them should be
-maintained.
-
-As with many other device drivers, libata low level drivers have
-sufficient bugs in ->remove and ->probe failure path.  Well, yes,
-that's probably because libata low level driver developers are lazy
-bunch, but aren't all low level driver developers?  After spending a
-day fiddling with braindamaged hardware with no document or
-braindamaged document, if it's finally working, well, it's working.
-
-For one reason or another, low level drivers don't receive as much
-attention or testing as core code, and bugs on driver detach or
-initialization failure don't happen often enough to be noticeable.
-Init failure path is worse because it's much less travelled while
-needs to handle multiple entry points.
-
-So, many low level drivers end up leaking resources on driver detach
-and having half broken failure path implementation in ->probe() which
-would leak resources or even cause oops when failure occurs.  iomap
-adds more to this mix.  So do msi and msix.
-
-
-  2. Devres
-  ---------
-
-devres is basically linked list of arbitrarily sized memory areas
-associated with a struct device.  Each devres entry is associated with
-a release function.  A devres can be released in several ways.  No
-matter what, all devres entries are released on driver detach.  On
-release, the associated release function is invoked and then the
-devres entry is freed.
-
-Managed interface is created for resources commonly used by device
-drivers using devres.  For example, coherent DMA memory is acquired
-using dma_alloc_coherent().  The managed version is called
-dmam_alloc_coherent().  It is identical to dma_alloc_coherent() except
-for the DMA memory allocated using it is managed and will be
-automatically released on driver detach.  Implementation looks like
-the following.
-
-  struct dma_devres {
-       size_t          size;
-       void            *vaddr;
-       dma_addr_t      dma_handle;
-  };
-
-  static void dmam_coherent_release(struct device *dev, void *res)
-  {
-       struct dma_devres *this = res;
-
-       dma_free_coherent(dev, this->size, this->vaddr, this->dma_handle);
-  }
-
-  dmam_alloc_coherent(dev, size, dma_handle, gfp)
-  {
-       struct dma_devres *dr;
-       void *vaddr;
-
-       dr = devres_alloc(dmam_coherent_release, sizeof(*dr), gfp);
-       ...
-
-       /* alloc DMA memory as usual */
-       vaddr = dma_alloc_coherent(...);
-       ...
-
-       /* record size, vaddr, dma_handle in dr */
-       dr->vaddr = vaddr;
-       ...
-
-       devres_add(dev, dr);
-
-       return vaddr;
-  }
-
-If a driver uses dmam_alloc_coherent(), the area is guaranteed to be
-freed whether initialization fails half-way or the device gets
-detached.  If most resources are acquired using managed interface, a
-driver can have much simpler init and exit code.  Init path basically
-looks like the following.
-
-  my_init_one()
-  {
-       struct mydev *d;
-
-       d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL);
-       if (!d)
-               return -ENOMEM;
-
-       d->ring = dmam_alloc_coherent(...);
-       if (!d->ring)
-               return -ENOMEM;
-
-       if (check something)
-               return -EINVAL;
-       ...
-
-       return register_to_upper_layer(d);
-  }
-
-And exit path,
-
-  my_remove_one()
-  {
-       unregister_from_upper_layer(d);
-       shutdown_my_hardware();
-  }
-
-As shown above, low level drivers can be simplified a lot by using
-devres.  Complexity is shifted from less maintained low level drivers
-to better maintained higher layer.  Also, as init failure path is
-shared with exit path, both can get more testing.
-
-Note though that when converting current calls or assignments to
-managed devm_* versions it is up to you to check if internal operations
-like allocating memory, have failed. Managed resources pertains to the
-freeing of these resources *only* - all other checks needed are still
-on you. In some cases this may mean introducing checks that were not
-necessary before moving to the managed devm_* calls.
-
-
-  3. Devres group
-  ---------------
-
-Devres entries can be grouped using devres group.  When a group is
-released, all contained normal devres entries and properly nested
-groups are released.  One usage is to rollback series of acquired
-resources on failure.  For example,
-
-  if (!devres_open_group(dev, NULL, GFP_KERNEL))
-       return -ENOMEM;
-
-  acquire A;
-  if (failed)
-       goto err;
-
-  acquire B;
-  if (failed)
-       goto err;
-  ...
-
-  devres_remove_group(dev, NULL);
-  return 0;
-
- err:
-  devres_release_group(dev, NULL);
-  return err_code;
-
-As resource acquisition failure usually means probe failure, constructs
-like above are usually useful in midlayer driver (e.g. libata core
-layer) where interface function shouldn't have side effect on failure.
-For LLDs, just returning error code suffices in most cases.
-
-Each group is identified by void *id.  It can either be explicitly
-specified by @id argument to devres_open_group() or automatically
-created by passing NULL as @id as in the above example.  In both
-cases, devres_open_group() returns the group's id.  The returned id
-can be passed to other devres functions to select the target group.
-If NULL is given to those functions, the latest open group is
-selected.
-
-For example, you can do something like the following.
-
-  int my_midlayer_create_something()
-  {
-       if (!devres_open_group(dev, my_midlayer_create_something, GFP_KERNEL))
-               return -ENOMEM;
-
-       ...
-
-       devres_close_group(dev, my_midlayer_create_something);
-       return 0;
-  }
-
-  void my_midlayer_destroy_something()
-  {
-       devres_release_group(dev, my_midlayer_create_something);
-  }
-
-
-  4. Details
-  ----------
-
-Lifetime of a devres entry begins on devres allocation and finishes
-when it is released or destroyed (removed and freed) - no reference
-counting.
-
-devres core guarantees atomicity to all basic devres operations and
-has support for single-instance devres types (atomic
-lookup-and-add-if-not-found).  Other than that, synchronizing
-concurrent accesses to allocated devres data is caller's
-responsibility.  This is usually non-issue because bus ops and
-resource allocations already do the job.
-
-For an example of single-instance devres type, read pcim_iomap_table()
-in lib/devres.c.
-
-All devres interface functions can be called without context if the
-right gfp mask is given.
-
-
-  5. Overhead
-  -----------
-
-Each devres bookkeeping info is allocated together with requested data
-area.  With debug option turned off, bookkeeping info occupies 16
-bytes on 32bit machines and 24 bytes on 64bit (three pointers rounded
-up to ull alignment).  If singly linked list is used, it can be
-reduced to two pointers (8 bytes on 32bit, 16 bytes on 64bit).
-
-Each devres group occupies 8 pointers.  It can be reduced to 6 if
-singly linked list is used.
-
-Memory space overhead on ahci controller with two ports is between 300
-and 400 bytes on 32bit machine after naive conversion (we can
-certainly invest a bit more effort into libata core layer).
-
-
-  6. List of managed interfaces
-  -----------------------------
-
-CLOCK
-  devm_clk_get()
-  devm_clk_get_optional()
-  devm_clk_put()
-  devm_clk_hw_register()
-  devm_of_clk_add_hw_provider()
-  devm_clk_hw_register_clkdev()
-
-DMA
-  dmaenginem_async_device_register()
-  dmam_alloc_coherent()
-  dmam_alloc_attrs()
-  dmam_free_coherent()
-  dmam_pool_create()
-  dmam_pool_destroy()
-
-DRM
-  devm_drm_dev_init()
-
-GPIO
-  devm_gpiod_get()
-  devm_gpiod_get_index()
-  devm_gpiod_get_index_optional()
-  devm_gpiod_get_optional()
-  devm_gpiod_put()
-  devm_gpiod_unhinge()
-  devm_gpiochip_add_data()
-  devm_gpio_request()
-  devm_gpio_request_one()
-  devm_gpio_free()
-
-I2C
-  devm_i2c_new_dummy_device()
-
-IIO
-  devm_iio_device_alloc()
-  devm_iio_device_free()
-  devm_iio_device_register()
-  devm_iio_device_unregister()
-  devm_iio_kfifo_allocate()
-  devm_iio_kfifo_free()
-  devm_iio_triggered_buffer_setup()
-  devm_iio_triggered_buffer_cleanup()
-  devm_iio_trigger_alloc()
-  devm_iio_trigger_free()
-  devm_iio_trigger_register()
-  devm_iio_trigger_unregister()
-  devm_iio_channel_get()
-  devm_iio_channel_release()
-  devm_iio_channel_get_all()
-  devm_iio_channel_release_all()
-
-INPUT
-  devm_input_allocate_device()
-
-IO region
-  devm_release_mem_region()
-  devm_release_region()
-  devm_release_resource()
-  devm_request_mem_region()
-  devm_request_region()
-  devm_request_resource()
-
-IOMAP
-  devm_ioport_map()
-  devm_ioport_unmap()
-  devm_ioremap()
-  devm_ioremap_nocache()
-  devm_ioremap_wc()
-  devm_ioremap_resource() : checks resource, requests memory region, ioremaps
-  devm_iounmap()
-  pcim_iomap()
-  pcim_iomap_regions() : do request_region() and iomap() on multiple BARs
-  pcim_iomap_table()   : array of mapped addresses indexed by BAR
-  pcim_iounmap()
-
-IRQ
-  devm_free_irq()
-  devm_request_any_context_irq()
-  devm_request_irq()
-  devm_request_threaded_irq()
-  devm_irq_alloc_descs()
-  devm_irq_alloc_desc()
-  devm_irq_alloc_desc_at()
-  devm_irq_alloc_desc_from()
-  devm_irq_alloc_descs_from()
-  devm_irq_alloc_generic_chip()
-  devm_irq_setup_generic_chip()
-  devm_irq_sim_init()
-
-LED
-  devm_led_classdev_register()
-  devm_led_classdev_unregister()
-
-MDIO
-  devm_mdiobus_alloc()
-  devm_mdiobus_alloc_size()
-  devm_mdiobus_free()
-
-MEM
-  devm_free_pages()
-  devm_get_free_pages()
-  devm_kasprintf()
-  devm_kcalloc()
-  devm_kfree()
-  devm_kmalloc()
-  devm_kmalloc_array()
-  devm_kmemdup()
-  devm_kstrdup()
-  devm_kvasprintf()
-  devm_kzalloc()
-
-MFD
-  devm_mfd_add_devices()
-
-MUX
-  devm_mux_chip_alloc()
-  devm_mux_chip_register()
-  devm_mux_control_get()
-
-PER-CPU MEM
-  devm_alloc_percpu()
-  devm_free_percpu()
-
-PCI
-  devm_pci_alloc_host_bridge()  : managed PCI host bridge allocation
-  devm_pci_remap_cfgspace()    : ioremap PCI configuration space
-  devm_pci_remap_cfg_resource()        : ioremap PCI configuration space resource
-  pcim_enable_device()         : after success, all PCI ops become managed
-  pcim_pin_device()            : keep PCI device enabled after release
-
-PHY
-  devm_usb_get_phy()
-  devm_usb_put_phy()
-
-PINCTRL
-  devm_pinctrl_get()
-  devm_pinctrl_put()
-  devm_pinctrl_register()
-  devm_pinctrl_unregister()
-
-POWER
-  devm_reboot_mode_register()
-  devm_reboot_mode_unregister()
-
-PWM
-  devm_pwm_get()
-  devm_pwm_put()
-
-REGULATOR
-  devm_regulator_bulk_get()
-  devm_regulator_get()
-  devm_regulator_put()
-  devm_regulator_register()
-
-RESET
-  devm_reset_control_get()
-  devm_reset_controller_register()
-
-SERDEV
-  devm_serdev_device_open()
-
-SLAVE DMA ENGINE
-  devm_acpi_dma_controller_register()
-
-SPI
-  devm_spi_register_master()
-
-WATCHDOG
-  devm_watchdog_register_device()
diff --git a/Documentation/driver-model/driver.rst b/Documentation/driver-model/driver.rst
new file mode 100644 (file)
index 0000000..11d2815
--- /dev/null
@@ -0,0 +1,223 @@
+==============
+Device Drivers
+==============
+
+See the kerneldoc for the struct device_driver.
+
+
+Allocation
+~~~~~~~~~~
+
+Device drivers are statically allocated structures. Though there may
+be multiple devices in a system that a driver supports, struct
+device_driver represents the driver as a whole (not a particular
+device instance).
+
+Initialization
+~~~~~~~~~~~~~~
+
+The driver must initialize at least the name and bus fields. It should
+also initialize the devclass field (when it arrives), so it may obtain
+the proper linkage internally. It should also initialize as many of
+the callbacks as possible, though each is optional.
+
+Declaration
+~~~~~~~~~~~
+
+As stated above, struct device_driver objects are statically
+allocated. Below is an example declaration of the eepro100
+driver. This declaration is hypothetical only; it relies on the driver
+being converted completely to the new model::
+
+  static struct device_driver eepro100_driver = {
+         .name         = "eepro100",
+         .bus          = &pci_bus_type,
+
+         .probe                = eepro100_probe,
+         .remove               = eepro100_remove,
+         .suspend              = eepro100_suspend,
+         .resume               = eepro100_resume,
+  };
+
+Most drivers will not be able to be converted completely to the new
+model because the bus they belong to has a bus-specific structure with
+bus-specific fields that cannot be generalized.
+
+The most common example of this are device ID structures. A driver
+typically defines an array of device IDs that it supports. The format
+of these structures and the semantics for comparing device IDs are
+completely bus-specific. Defining them as bus-specific entities would
+sacrifice type-safety, so we keep bus-specific structures around.
+
+Bus-specific drivers should include a generic struct device_driver in
+the definition of the bus-specific driver. Like this::
+
+  struct pci_driver {
+         const struct pci_device_id *id_table;
+         struct device_driver    driver;
+  };
+
+A definition that included bus-specific fields would look like
+(using the eepro100 driver again)::
+
+  static struct pci_driver eepro100_driver = {
+         .id_table       = eepro100_pci_tbl,
+         .driver              = {
+               .name           = "eepro100",
+               .bus            = &pci_bus_type,
+               .probe          = eepro100_probe,
+               .remove         = eepro100_remove,
+               .suspend        = eepro100_suspend,
+               .resume         = eepro100_resume,
+         },
+  };
+
+Some may find the syntax of embedded struct initialization awkward or
+even a bit ugly. So far, it's the best way we've found to do what we want...
+
+Registration
+~~~~~~~~~~~~
+
+::
+
+  int driver_register(struct device_driver *drv);
+
+The driver registers the structure on startup. For drivers that have
+no bus-specific fields (i.e. don't have a bus-specific driver
+structure), they would use driver_register and pass a pointer to their
+struct device_driver object.
+
+Most drivers, however, will have a bus-specific structure and will
+need to register with the bus using something like pci_driver_register.
+
+It is important that drivers register their driver structure as early as
+possible. Registration with the core initializes several fields in the
+struct device_driver object, including the reference count and the
+lock. These fields are assumed to be valid at all times and may be
+used by the device model core or the bus driver.
+
+
+Transition Bus Drivers
+~~~~~~~~~~~~~~~~~~~~~~
+
+By defining wrapper functions, the transition to the new model can be
+made easier. Drivers can ignore the generic structure altogether and
+let the bus wrapper fill in the fields. For the callbacks, the bus can
+define generic callbacks that forward the call to the bus-specific
+callbacks of the drivers.
+
+This solution is intended to be only temporary. In order to get class
+information in the driver, the drivers must be modified anyway. Since
+converting drivers to the new model should reduce some infrastructural
+complexity and code size, it is recommended that they are converted as
+class information is added.
+
+Access
+~~~~~~
+
+Once the object has been registered, it may access the common fields of
+the object, like the lock and the list of devices::
+
+  int driver_for_each_dev(struct device_driver *drv, void *data,
+                         int (*callback)(struct device *dev, void *data));
+
+The devices field is a list of all the devices that have been bound to
+the driver. The LDM core provides a helper function to operate on all
+the devices a driver controls. This helper locks the driver on each
+node access, and does proper reference counting on each device as it
+accesses it.
+
+
+sysfs
+~~~~~
+
+When a driver is registered, a sysfs directory is created in its
+bus's directory. In this directory, the driver can export an interface
+to userspace to control operation of the driver on a global basis;
+e.g. toggling debugging output in the driver.
+
+A future feature of this directory will be a 'devices' directory. This
+directory will contain symlinks to the directories of devices it
+supports.
+
+
+
+Callbacks
+~~~~~~~~~
+
+::
+
+       int     (*probe)        (struct device *dev);
+
+The probe() entry is called in task context, with the bus's rwsem locked
+and the driver partially bound to the device.  Drivers commonly use
+container_of() to convert "dev" to a bus-specific type, both in probe()
+and other routines.  That type often provides device resource data, such
+as pci_dev.resource[] or platform_device.resources, which is used in
+addition to dev->platform_data to initialize the driver.
+
+This callback holds the driver-specific logic to bind the driver to a
+given device.  That includes verifying that the device is present, that
+it's a version the driver can handle, that driver data structures can
+be allocated and initialized, and that any hardware can be initialized.
+Drivers often store a pointer to their state with dev_set_drvdata().
+When the driver has successfully bound itself to that device, then probe()
+returns zero and the driver model code will finish its part of binding
+the driver to that device.
+
+A driver's probe() may return a negative errno value to indicate that
+the driver did not bind to this device, in which case it should have
+released all resources it allocated::
+
+       int     (*remove)       (struct device *dev);
+
+remove is called to unbind a driver from a device. This may be
+called if a device is physically removed from the system, if the
+driver module is being unloaded, during a reboot sequence, or
+in other cases.
+
+It is up to the driver to determine if the device is present or
+not. It should free any resources allocated specifically for the
+device; i.e. anything in the device's driver_data field.
+
+If the device is still present, it should quiesce the device and place
+it into a supported low-power state::
+
+       int     (*suspend)      (struct device *dev, pm_message_t state);
+
+suspend is called to put the device in a low power state::
+
+       int     (*resume)       (struct device *dev);
+
+Resume is used to bring a device back from a low power state.
+
+
+Attributes
+~~~~~~~~~~
+
+::
+
+  struct driver_attribute {
+          struct attribute        attr;
+          ssize_t (*show)(struct device_driver *driver, char *buf);
+          ssize_t (*store)(struct device_driver *, const char *buf, size_t count);
+  };
+
+Device drivers can export attributes via their sysfs directories.
+Drivers can declare attributes using a DRIVER_ATTR_RW and DRIVER_ATTR_RO
+macro that works identically to the DEVICE_ATTR_RW and DEVICE_ATTR_RO
+macros.
+
+Example::
+
+       DRIVER_ATTR_RW(debug);
+
+This is equivalent to declaring::
+
+       struct driver_attribute driver_attr_debug;
+
+This can then be used to add and remove the attribute from the
+driver's directory using::
+
+  int driver_create_file(struct device_driver *, const struct driver_attribute *);
+  void driver_remove_file(struct device_driver *, const struct driver_attribute *);
diff --git a/Documentation/driver-model/driver.txt b/Documentation/driver-model/driver.txt
deleted file mode 100644 (file)
index d661e6f..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-
-Device Drivers
-
-See the kerneldoc for the struct device_driver.
-
-
-Allocation
-~~~~~~~~~~
-
-Device drivers are statically allocated structures. Though there may
-be multiple devices in a system that a driver supports, struct
-device_driver represents the driver as a whole (not a particular
-device instance).
-
-Initialization
-~~~~~~~~~~~~~~
-
-The driver must initialize at least the name and bus fields. It should
-also initialize the devclass field (when it arrives), so it may obtain
-the proper linkage internally. It should also initialize as many of
-the callbacks as possible, though each is optional.
-
-Declaration
-~~~~~~~~~~~
-
-As stated above, struct device_driver objects are statically
-allocated. Below is an example declaration of the eepro100
-driver. This declaration is hypothetical only; it relies on the driver
-being converted completely to the new model. 
-
-static struct device_driver eepro100_driver = {
-       .name           = "eepro100",
-       .bus            = &pci_bus_type,
-       
-       .probe          = eepro100_probe,
-       .remove         = eepro100_remove,
-       .suspend                = eepro100_suspend,
-       .resume         = eepro100_resume,
-};
-
-Most drivers will not be able to be converted completely to the new
-model because the bus they belong to has a bus-specific structure with
-bus-specific fields that cannot be generalized. 
-
-The most common example of this are device ID structures. A driver
-typically defines an array of device IDs that it supports. The format
-of these structures and the semantics for comparing device IDs are
-completely bus-specific. Defining them as bus-specific entities would
-sacrifice type-safety, so we keep bus-specific structures around. 
-
-Bus-specific drivers should include a generic struct device_driver in
-the definition of the bus-specific driver. Like this:
-
-struct pci_driver {
-       const struct pci_device_id *id_table;
-       struct device_driver      driver;
-};
-
-A definition that included bus-specific fields would look like
-(using the eepro100 driver again):
-
-static struct pci_driver eepro100_driver = {
-       .id_table       = eepro100_pci_tbl,
-       .driver        = {
-               .name           = "eepro100",
-               .bus            = &pci_bus_type,
-               .probe          = eepro100_probe,
-               .remove         = eepro100_remove,
-               .suspend        = eepro100_suspend,
-               .resume         = eepro100_resume,
-       },
-};
-
-Some may find the syntax of embedded struct initialization awkward or
-even a bit ugly. So far, it's the best way we've found to do what we want...
-
-Registration
-~~~~~~~~~~~~
-
-int driver_register(struct device_driver * drv);
-
-The driver registers the structure on startup. For drivers that have
-no bus-specific fields (i.e. don't have a bus-specific driver
-structure), they would use driver_register and pass a pointer to their
-struct device_driver object. 
-
-Most drivers, however, will have a bus-specific structure and will
-need to register with the bus using something like pci_driver_register.
-
-It is important that drivers register their driver structure as early as
-possible. Registration with the core initializes several fields in the
-struct device_driver object, including the reference count and the
-lock. These fields are assumed to be valid at all times and may be
-used by the device model core or the bus driver.
-
-
-Transition Bus Drivers
-~~~~~~~~~~~~~~~~~~~~~~
-
-By defining wrapper functions, the transition to the new model can be
-made easier. Drivers can ignore the generic structure altogether and
-let the bus wrapper fill in the fields. For the callbacks, the bus can
-define generic callbacks that forward the call to the bus-specific
-callbacks of the drivers. 
-
-This solution is intended to be only temporary. In order to get class
-information in the driver, the drivers must be modified anyway. Since
-converting drivers to the new model should reduce some infrastructural
-complexity and code size, it is recommended that they are converted as
-class information is added.
-
-Access
-~~~~~~
-
-Once the object has been registered, it may access the common fields of
-the object, like the lock and the list of devices. 
-
-int driver_for_each_dev(struct device_driver * drv, void * data, 
-                       int (*callback)(struct device * dev, void * data));
-
-The devices field is a list of all the devices that have been bound to
-the driver. The LDM core provides a helper function to operate on all
-the devices a driver controls. This helper locks the driver on each
-node access, and does proper reference counting on each device as it
-accesses it. 
-
-
-sysfs
-~~~~~
-
-When a driver is registered, a sysfs directory is created in its
-bus's directory. In this directory, the driver can export an interface
-to userspace to control operation of the driver on a global basis;
-e.g. toggling debugging output in the driver.
-
-A future feature of this directory will be a 'devices' directory. This
-directory will contain symlinks to the directories of devices it
-supports.
-
-
-
-Callbacks
-~~~~~~~~~
-
-       int     (*probe)        (struct device * dev);
-
-The probe() entry is called in task context, with the bus's rwsem locked
-and the driver partially bound to the device.  Drivers commonly use
-container_of() to convert "dev" to a bus-specific type, both in probe()
-and other routines.  That type often provides device resource data, such
-as pci_dev.resource[] or platform_device.resources, which is used in
-addition to dev->platform_data to initialize the driver.
-
-This callback holds the driver-specific logic to bind the driver to a
-given device.  That includes verifying that the device is present, that
-it's a version the driver can handle, that driver data structures can
-be allocated and initialized, and that any hardware can be initialized.
-Drivers often store a pointer to their state with dev_set_drvdata().
-When the driver has successfully bound itself to that device, then probe()
-returns zero and the driver model code will finish its part of binding
-the driver to that device.
-
-A driver's probe() may return a negative errno value to indicate that
-the driver did not bind to this device, in which case it should have
-released all resources it allocated.
-
-       int     (*remove)       (struct device * dev);
-
-remove is called to unbind a driver from a device. This may be
-called if a device is physically removed from the system, if the
-driver module is being unloaded, during a reboot sequence, or
-in other cases.
-
-It is up to the driver to determine if the device is present or
-not. It should free any resources allocated specifically for the
-device; i.e. anything in the device's driver_data field. 
-
-If the device is still present, it should quiesce the device and place
-it into a supported low-power state.
-
-       int     (*suspend)      (struct device * dev, pm_message_t state);
-
-suspend is called to put the device in a low power state.
-
-       int     (*resume)       (struct device * dev);
-
-Resume is used to bring a device back from a low power state.
-
-
-Attributes
-~~~~~~~~~~
-struct driver_attribute {
-        struct attribute        attr;
-        ssize_t (*show)(struct device_driver *driver, char *buf);
-        ssize_t (*store)(struct device_driver *, const char * buf, size_t count);
-};
-
-Device drivers can export attributes via their sysfs directories. 
-Drivers can declare attributes using a DRIVER_ATTR_RW and DRIVER_ATTR_RO
-macro that works identically to the DEVICE_ATTR_RW and DEVICE_ATTR_RO
-macros.
-
-Example:
-
-DRIVER_ATTR_RW(debug);
-
-This is equivalent to declaring:
-
-struct driver_attribute driver_attr_debug;
-
-This can then be used to add and remove the attribute from the
-driver's directory using:
-
-int driver_create_file(struct device_driver *, const struct driver_attribute *);
-void driver_remove_file(struct device_driver *, const struct driver_attribute *);
diff --git a/Documentation/driver-model/index.rst b/Documentation/driver-model/index.rst
new file mode 100644 (file)
index 0000000..9f85d57
--- /dev/null
@@ -0,0 +1,26 @@
+:orphan:
+
+============
+Driver Model
+============
+
+.. toctree::
+   :maxdepth: 1
+
+   binding
+   bus
+   class
+   design-patterns
+   device
+   devres
+   driver
+   overview
+   platform
+   porting
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
diff --git a/Documentation/driver-model/overview.rst b/Documentation/driver-model/overview.rst
new file mode 100644 (file)
index 0000000..d4d1e9b
--- /dev/null
@@ -0,0 +1,124 @@
+=============================
+The Linux Kernel Device Model
+=============================
+
+Patrick Mochel <mochel@digitalimplant.org>
+
+Drafted 26 August 2002
+Updated 31 January 2006
+
+
+Overview
+~~~~~~~~
+
+The Linux Kernel Driver Model is a unification of all the disparate driver
+models that were previously used in the kernel. It is intended to augment the
+bus-specific drivers for bridges and devices by consolidating a set of data
+and operations into globally accessible data structures.
+
+Traditional driver models implemented some sort of tree-like structure
+(sometimes just a list) for the devices they control. There wasn't any
+uniformity across the different bus types.
+
+The current driver model provides a common, uniform data model for describing
+a bus and the devices that can appear under the bus. The unified bus
+model includes a set of common attributes which all busses carry, and a set
+of common callbacks, such as device discovery during bus probing, bus
+shutdown, bus power management, etc.
+
+The common device and bridge interface reflects the goals of the modern
+computer: namely the ability to do seamless device "plug and play", power
+management, and hot plug. In particular, the model dictated by Intel and
+Microsoft (namely ACPI) ensures that almost every device on almost any bus
+on an x86-compatible system can work within this paradigm.  Of course,
+not every bus is able to support all such operations, although most
+buses support most of those operations.
+
+
+Downstream Access
+~~~~~~~~~~~~~~~~~
+
+Common data fields have been moved out of individual bus layers into a common
+data structure. These fields must still be accessed by the bus layers,
+and sometimes by the device-specific drivers.
+
+Other bus layers are encouraged to do what has been done for the PCI layer.
+struct pci_dev now looks like this::
+
+  struct pci_dev {
+       ...
+
+       struct device dev;     /* Generic device interface */
+       ...
+  };
+
+Note first that the struct device dev within the struct pci_dev is
+statically allocated. This means only one allocation on device discovery.
+
+Note also that that struct device dev is not necessarily defined at the
+front of the pci_dev structure.  This is to make people think about what
+they're doing when switching between the bus driver and the global driver,
+and to discourage meaningless and incorrect casts between the two.
+
+The PCI bus layer freely accesses the fields of struct device. It knows about
+the structure of struct pci_dev, and it should know the structure of struct
+device. Individual PCI device drivers that have been converted to the current
+driver model generally do not and should not touch the fields of struct device,
+unless there is a compelling reason to do so.
+
+The above abstraction prevents unnecessary pain during transitional phases.
+If it were not done this way, then when a field was renamed or removed, every
+downstream driver would break.  On the other hand, if only the bus layer
+(and not the device layer) accesses the struct device, it is only the bus
+layer that needs to change.
+
+
+User Interface
+~~~~~~~~~~~~~~
+
+By virtue of having a complete hierarchical view of all the devices in the
+system, exporting a complete hierarchical view to userspace becomes relatively
+easy. This has been accomplished by implementing a special purpose virtual
+file system named sysfs.
+
+Almost all mainstream Linux distros mount this filesystem automatically; you
+can see some variation of the following in the output of the "mount" command::
+
+  $ mount
+  ...
+  none on /sys type sysfs (rw,noexec,nosuid,nodev)
+  ...
+  $
+
+The auto-mounting of sysfs is typically accomplished by an entry similar to
+the following in the /etc/fstab file::
+
+  none         /sys    sysfs    defaults               0 0
+
+or something similar in the /lib/init/fstab file on Debian-based systems::
+
+  none            /sys    sysfs    nodev,noexec,nosuid    0 0
+
+If sysfs is not automatically mounted, you can always do it manually with::
+
+       # mount -t sysfs sysfs /sys
+
+Whenever a device is inserted into the tree, a directory is created for it.
+This directory may be populated at each layer of discovery - the global layer,
+the bus layer, or the device layer.
+
+The global layer currently creates two files - 'name' and 'power'. The
+former only reports the name of the device. The latter reports the
+current power state of the device. It will also be used to set the current
+power state.
+
+The bus layer may also create files for the devices it finds while probing the
+bus. For example, the PCI layer currently creates 'irq' and 'resource' files
+for each PCI device.
+
+A device-specific driver may also export files in its directory to expose
+device-specific data or tunable interfaces.
+
+More information about the sysfs directory layout can be found in
+the other documents in this directory and in the file
+Documentation/filesystems/sysfs.txt.
diff --git a/Documentation/driver-model/overview.txt b/Documentation/driver-model/overview.txt
deleted file mode 100644 (file)
index 6a8f9a8..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-The Linux Kernel Device Model
-
-Patrick Mochel <mochel@digitalimplant.org>
-
-Drafted 26 August 2002
-Updated 31 January 2006
-
-
-Overview
-~~~~~~~~
-
-The Linux Kernel Driver Model is a unification of all the disparate driver
-models that were previously used in the kernel. It is intended to augment the
-bus-specific drivers for bridges and devices by consolidating a set of data
-and operations into globally accessible data structures.
-
-Traditional driver models implemented some sort of tree-like structure
-(sometimes just a list) for the devices they control. There wasn't any
-uniformity across the different bus types.
-
-The current driver model provides a common, uniform data model for describing
-a bus and the devices that can appear under the bus. The unified bus
-model includes a set of common attributes which all busses carry, and a set
-of common callbacks, such as device discovery during bus probing, bus
-shutdown, bus power management, etc.
-
-The common device and bridge interface reflects the goals of the modern
-computer: namely the ability to do seamless device "plug and play", power
-management, and hot plug. In particular, the model dictated by Intel and
-Microsoft (namely ACPI) ensures that almost every device on almost any bus
-on an x86-compatible system can work within this paradigm.  Of course,
-not every bus is able to support all such operations, although most
-buses support most of those operations.
-
-
-Downstream Access
-~~~~~~~~~~~~~~~~~
-
-Common data fields have been moved out of individual bus layers into a common
-data structure. These fields must still be accessed by the bus layers,
-and sometimes by the device-specific drivers.
-
-Other bus layers are encouraged to do what has been done for the PCI layer.
-struct pci_dev now looks like this:
-
-struct pci_dev {
-       ...
-
-       struct device dev;     /* Generic device interface */
-       ...
-};
-
-Note first that the struct device dev within the struct pci_dev is
-statically allocated. This means only one allocation on device discovery.
-
-Note also that that struct device dev is not necessarily defined at the
-front of the pci_dev structure.  This is to make people think about what
-they're doing when switching between the bus driver and the global driver,
-and to discourage meaningless and incorrect casts between the two.
-
-The PCI bus layer freely accesses the fields of struct device. It knows about
-the structure of struct pci_dev, and it should know the structure of struct
-device. Individual PCI device drivers that have been converted to the current
-driver model generally do not and should not touch the fields of struct device,
-unless there is a compelling reason to do so.
-
-The above abstraction prevents unnecessary pain during transitional phases.
-If it were not done this way, then when a field was renamed or removed, every
-downstream driver would break.  On the other hand, if only the bus layer
-(and not the device layer) accesses the struct device, it is only the bus
-layer that needs to change.
-
-
-User Interface
-~~~~~~~~~~~~~~
-
-By virtue of having a complete hierarchical view of all the devices in the
-system, exporting a complete hierarchical view to userspace becomes relatively
-easy. This has been accomplished by implementing a special purpose virtual
-file system named sysfs.
-
-Almost all mainstream Linux distros mount this filesystem automatically; you
-can see some variation of the following in the output of the "mount" command:
-
-$ mount
-...
-none on /sys type sysfs (rw,noexec,nosuid,nodev)
-...
-$
-
-The auto-mounting of sysfs is typically accomplished by an entry similar to
-the following in the /etc/fstab file:
-
-none           /sys    sysfs    defaults               0 0
-
-or something similar in the /lib/init/fstab file on Debian-based systems:
-
-none            /sys    sysfs    nodev,noexec,nosuid    0 0
-
-If sysfs is not automatically mounted, you can always do it manually with:
-
-# mount -t sysfs sysfs /sys
-
-Whenever a device is inserted into the tree, a directory is created for it.
-This directory may be populated at each layer of discovery - the global layer,
-the bus layer, or the device layer.
-
-The global layer currently creates two files - 'name' and 'power'. The
-former only reports the name of the device. The latter reports the
-current power state of the device. It will also be used to set the current
-power state. 
-
-The bus layer may also create files for the devices it finds while probing the
-bus. For example, the PCI layer currently creates 'irq' and 'resource' files
-for each PCI device.
-
-A device-specific driver may also export files in its directory to expose
-device-specific data or tunable interfaces.
-
-More information about the sysfs directory layout can be found in
-the other documents in this directory and in the file 
-Documentation/filesystems/sysfs.txt.
-
diff --git a/Documentation/driver-model/platform.rst b/Documentation/driver-model/platform.rst
new file mode 100644 (file)
index 0000000..334dd40
--- /dev/null
@@ -0,0 +1,246 @@
+============================
+Platform Devices and Drivers
+============================
+
+See <linux/platform_device.h> for the driver model interface to the
+platform bus:  platform_device, and platform_driver.  This pseudo-bus
+is used to connect devices on busses with minimal infrastructure,
+like those used to integrate peripherals on many system-on-chip
+processors, or some "legacy" PC interconnects; as opposed to large
+formally specified ones like PCI or USB.
+
+
+Platform devices
+~~~~~~~~~~~~~~~~
+Platform devices are devices that typically appear as autonomous
+entities in the system. This includes legacy port-based devices and
+host bridges to peripheral buses, and most controllers integrated
+into system-on-chip platforms.  What they usually have in common
+is direct addressing from a CPU bus.  Rarely, a platform_device will
+be connected through a segment of some other kind of bus; but its
+registers will still be directly addressable.
+
+Platform devices are given a name, used in driver binding, and a
+list of resources such as addresses and IRQs::
+
+  struct platform_device {
+       const char      *name;
+       u32             id;
+       struct device   dev;
+       u32             num_resources;
+       struct resource *resource;
+  };
+
+
+Platform drivers
+~~~~~~~~~~~~~~~~
+Platform drivers follow the standard driver model convention, where
+discovery/enumeration is handled outside the drivers, and drivers
+provide probe() and remove() methods.  They support power management
+and shutdown notifications using the standard conventions::
+
+  struct platform_driver {
+       int (*probe)(struct platform_device *);
+       int (*remove)(struct platform_device *);
+       void (*shutdown)(struct platform_device *);
+       int (*suspend)(struct platform_device *, pm_message_t state);
+       int (*suspend_late)(struct platform_device *, pm_message_t state);
+       int (*resume_early)(struct platform_device *);
+       int (*resume)(struct platform_device *);
+       struct device_driver driver;
+  };
+
+Note that probe() should in general verify that the specified device hardware
+actually exists; sometimes platform setup code can't be sure.  The probing
+can use device resources, including clocks, and device platform_data.
+
+Platform drivers register themselves the normal way::
+
+       int platform_driver_register(struct platform_driver *drv);
+
+Or, in common situations where the device is known not to be hot-pluggable,
+the probe() routine can live in an init section to reduce the driver's
+runtime memory footprint::
+
+       int platform_driver_probe(struct platform_driver *drv,
+                         int (*probe)(struct platform_device *))
+
+Kernel modules can be composed of several platform drivers. The platform core
+provides helpers to register and unregister an array of drivers::
+
+       int __platform_register_drivers(struct platform_driver * const *drivers,
+                                     unsigned int count, struct module *owner);
+       void platform_unregister_drivers(struct platform_driver * const *drivers,
+                                        unsigned int count);
+
+If one of the drivers fails to register, all drivers registered up to that
+point will be unregistered in reverse order. Note that there is a convenience
+macro that passes THIS_MODULE as owner parameter::
+
+       #define platform_register_drivers(drivers, count)
+
+
+Device Enumeration
+~~~~~~~~~~~~~~~~~~
+As a rule, platform specific (and often board-specific) setup code will
+register platform devices::
+
+       int platform_device_register(struct platform_device *pdev);
+
+       int platform_add_devices(struct platform_device **pdevs, int ndev);
+
+The general rule is to register only those devices that actually exist,
+but in some cases extra devices might be registered.  For example, a kernel
+might be configured to work with an external network adapter that might not
+be populated on all boards, or likewise to work with an integrated controller
+that some boards might not hook up to any peripherals.
+
+In some cases, boot firmware will export tables describing the devices
+that are populated on a given board.   Without such tables, often the
+only way for system setup code to set up the correct devices is to build
+a kernel for a specific target board.  Such board-specific kernels are
+common with embedded and custom systems development.
+
+In many cases, the memory and IRQ resources associated with the platform
+device are not enough to let the device's driver work.  Board setup code
+will often provide additional information using the device's platform_data
+field to hold additional information.
+
+Embedded systems frequently need one or more clocks for platform devices,
+which are normally kept off until they're actively needed (to save power).
+System setup also associates those clocks with the device, so that that
+calls to clk_get(&pdev->dev, clock_name) return them as needed.
+
+
+Legacy Drivers:  Device Probing
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Some drivers are not fully converted to the driver model, because they take
+on a non-driver role:  the driver registers its platform device, rather than
+leaving that for system infrastructure.  Such drivers can't be hotplugged
+or coldplugged, since those mechanisms require device creation to be in a
+different system component than the driver.
+
+The only "good" reason for this is to handle older system designs which, like
+original IBM PCs, rely on error-prone "probe-the-hardware" models for hardware
+configuration.  Newer systems have largely abandoned that model, in favor of
+bus-level support for dynamic configuration (PCI, USB), or device tables
+provided by the boot firmware (e.g. PNPACPI on x86).  There are too many
+conflicting options about what might be where, and even educated guesses by
+an operating system will be wrong often enough to make trouble.
+
+This style of driver is discouraged.  If you're updating such a driver,
+please try to move the device enumeration to a more appropriate location,
+outside the driver.  This will usually be cleanup, since such drivers
+tend to already have "normal" modes, such as ones using device nodes that
+were created by PNP or by platform device setup.
+
+None the less, there are some APIs to support such legacy drivers.  Avoid
+using these calls except with such hotplug-deficient drivers::
+
+       struct platform_device *platform_device_alloc(
+                       const char *name, int id);
+
+You can use platform_device_alloc() to dynamically allocate a device, which
+you will then initialize with resources and platform_device_register().
+A better solution is usually::
+
+       struct platform_device *platform_device_register_simple(
+                       const char *name, int id,
+                       struct resource *res, unsigned int nres);
+
+You can use platform_device_register_simple() as a one-step call to allocate
+and register a device.
+
+
+Device Naming and Driver Binding
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The platform_device.dev.bus_id is the canonical name for the devices.
+It's built from two components:
+
+    * platform_device.name ... which is also used to for driver matching.
+
+    * platform_device.id ... the device instance number, or else "-1"
+      to indicate there's only one.
+
+These are concatenated, so name/id "serial"/0 indicates bus_id "serial.0", and
+"serial/3" indicates bus_id "serial.3"; both would use the platform_driver
+named "serial".  While "my_rtc"/-1 would be bus_id "my_rtc" (no instance id)
+and use the platform_driver called "my_rtc".
+
+Driver binding is performed automatically by the driver core, invoking
+driver probe() after finding a match between device and driver.  If the
+probe() succeeds, the driver and device are bound as usual.  There are
+three different ways to find such a match:
+
+    - Whenever a device is registered, the drivers for that bus are
+      checked for matches.  Platform devices should be registered very
+      early during system boot.
+
+    - When a driver is registered using platform_driver_register(), all
+      unbound devices on that bus are checked for matches.  Drivers
+      usually register later during booting, or by module loading.
+
+    - Registering a driver using platform_driver_probe() works just like
+      using platform_driver_register(), except that the driver won't
+      be probed later if another device registers.  (Which is OK, since
+      this interface is only for use with non-hotpluggable devices.)
+
+
+Early Platform Devices and Drivers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The early platform interfaces provide platform data to platform device
+drivers early on during the system boot. The code is built on top of the
+early_param() command line parsing and can be executed very early on.
+
+Example: "earlyprintk" class early serial console in 6 steps
+
+1. Registering early platform device data
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The architecture code registers platform device data using the function
+early_platform_add_devices(). In the case of early serial console this
+should be hardware configuration for the serial port. Devices registered
+at this point will later on be matched against early platform drivers.
+
+2. Parsing kernel command line
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The architecture code calls parse_early_param() to parse the kernel
+command line. This will execute all matching early_param() callbacks.
+User specified early platform devices will be registered at this point.
+For the early serial console case the user can specify port on the
+kernel command line as "earlyprintk=serial.0" where "earlyprintk" is
+the class string, "serial" is the name of the platform driver and
+0 is the platform device id. If the id is -1 then the dot and the
+id can be omitted.
+
+3. Installing early platform drivers belonging to a certain class
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The architecture code may optionally force registration of all early
+platform drivers belonging to a certain class using the function
+early_platform_driver_register_all(). User specified devices from
+step 2 have priority over these. This step is omitted by the serial
+driver example since the early serial driver code should be disabled
+unless the user has specified port on the kernel command line.
+
+4. Early platform driver registration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Compiled-in platform drivers making use of early_platform_init() are
+automatically registered during step 2 or 3. The serial driver example
+should use early_platform_init("earlyprintk", &platform_driver).
+
+5. Probing of early platform drivers belonging to a certain class
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The architecture code calls early_platform_driver_probe() to match
+registered early platform devices associated with a certain class with
+registered early platform drivers. Matched devices will get probed().
+This step can be executed at any point during the early boot. As soon
+as possible may be good for the serial port case.
+
+6. Inside the early platform driver probe()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The driver code needs to take special care during early boot, especially
+when it comes to memory allocation and interrupt registration. The code
+in the probe() function can use is_early_platform_device() to check if
+it is called at early platform device or at the regular platform device
+time. The early serial driver performs register_console() at this point.
+
+For further information, see <linux/platform_device.h>.
diff --git a/Documentation/driver-model/platform.txt b/Documentation/driver-model/platform.txt
deleted file mode 100644 (file)
index 9d9e47d..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-Platform Devices and Drivers
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-See <linux/platform_device.h> for the driver model interface to the
-platform bus:  platform_device, and platform_driver.  This pseudo-bus
-is used to connect devices on busses with minimal infrastructure,
-like those used to integrate peripherals on many system-on-chip
-processors, or some "legacy" PC interconnects; as opposed to large
-formally specified ones like PCI or USB.
-
-
-Platform devices
-~~~~~~~~~~~~~~~~
-Platform devices are devices that typically appear as autonomous
-entities in the system. This includes legacy port-based devices and
-host bridges to peripheral buses, and most controllers integrated
-into system-on-chip platforms.  What they usually have in common
-is direct addressing from a CPU bus.  Rarely, a platform_device will
-be connected through a segment of some other kind of bus; but its
-registers will still be directly addressable.
-
-Platform devices are given a name, used in driver binding, and a
-list of resources such as addresses and IRQs.
-
-struct platform_device {
-       const char      *name;
-       u32             id;
-       struct device   dev;
-       u32             num_resources;
-       struct resource *resource;
-};
-
-
-Platform drivers
-~~~~~~~~~~~~~~~~
-Platform drivers follow the standard driver model convention, where
-discovery/enumeration is handled outside the drivers, and drivers
-provide probe() and remove() methods.  They support power management
-and shutdown notifications using the standard conventions.
-
-struct platform_driver {
-       int (*probe)(struct platform_device *);
-       int (*remove)(struct platform_device *);
-       void (*shutdown)(struct platform_device *);
-       int (*suspend)(struct platform_device *, pm_message_t state);
-       int (*suspend_late)(struct platform_device *, pm_message_t state);
-       int (*resume_early)(struct platform_device *);
-       int (*resume)(struct platform_device *);
-       struct device_driver driver;
-};
-
-Note that probe() should in general verify that the specified device hardware
-actually exists; sometimes platform setup code can't be sure.  The probing
-can use device resources, including clocks, and device platform_data.
-
-Platform drivers register themselves the normal way:
-
-       int platform_driver_register(struct platform_driver *drv);
-
-Or, in common situations where the device is known not to be hot-pluggable,
-the probe() routine can live in an init section to reduce the driver's
-runtime memory footprint:
-
-       int platform_driver_probe(struct platform_driver *drv,
-                         int (*probe)(struct platform_device *))
-
-Kernel modules can be composed of several platform drivers. The platform core
-provides helpers to register and unregister an array of drivers:
-
-       int __platform_register_drivers(struct platform_driver * const *drivers,
-                                     unsigned int count, struct module *owner);
-       void platform_unregister_drivers(struct platform_driver * const *drivers,
-                                        unsigned int count);
-
-If one of the drivers fails to register, all drivers registered up to that
-point will be unregistered in reverse order. Note that there is a convenience
-macro that passes THIS_MODULE as owner parameter:
-
-       #define platform_register_drivers(drivers, count)
-
-
-Device Enumeration
-~~~~~~~~~~~~~~~~~~
-As a rule, platform specific (and often board-specific) setup code will
-register platform devices:
-
-       int platform_device_register(struct platform_device *pdev);
-
-       int platform_add_devices(struct platform_device **pdevs, int ndev);
-
-The general rule is to register only those devices that actually exist,
-but in some cases extra devices might be registered.  For example, a kernel
-might be configured to work with an external network adapter that might not
-be populated on all boards, or likewise to work with an integrated controller
-that some boards might not hook up to any peripherals.
-
-In some cases, boot firmware will export tables describing the devices
-that are populated on a given board.   Without such tables, often the
-only way for system setup code to set up the correct devices is to build
-a kernel for a specific target board.  Such board-specific kernels are
-common with embedded and custom systems development.
-
-In many cases, the memory and IRQ resources associated with the platform
-device are not enough to let the device's driver work.  Board setup code
-will often provide additional information using the device's platform_data
-field to hold additional information.
-
-Embedded systems frequently need one or more clocks for platform devices,
-which are normally kept off until they're actively needed (to save power).
-System setup also associates those clocks with the device, so that that
-calls to clk_get(&pdev->dev, clock_name) return them as needed.
-
-
-Legacy Drivers:  Device Probing
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Some drivers are not fully converted to the driver model, because they take
-on a non-driver role:  the driver registers its platform device, rather than
-leaving that for system infrastructure.  Such drivers can't be hotplugged
-or coldplugged, since those mechanisms require device creation to be in a
-different system component than the driver.
-
-The only "good" reason for this is to handle older system designs which, like
-original IBM PCs, rely on error-prone "probe-the-hardware" models for hardware
-configuration.  Newer systems have largely abandoned that model, in favor of
-bus-level support for dynamic configuration (PCI, USB), or device tables
-provided by the boot firmware (e.g. PNPACPI on x86).  There are too many
-conflicting options about what might be where, and even educated guesses by
-an operating system will be wrong often enough to make trouble.
-
-This style of driver is discouraged.  If you're updating such a driver,
-please try to move the device enumeration to a more appropriate location,
-outside the driver.  This will usually be cleanup, since such drivers
-tend to already have "normal" modes, such as ones using device nodes that
-were created by PNP or by platform device setup.
-
-None the less, there are some APIs to support such legacy drivers.  Avoid
-using these calls except with such hotplug-deficient drivers.
-
-       struct platform_device *platform_device_alloc(
-                       const char *name, int id);
-
-You can use platform_device_alloc() to dynamically allocate a device, which
-you will then initialize with resources and platform_device_register().
-A better solution is usually:
-
-       struct platform_device *platform_device_register_simple(
-                       const char *name, int id,
-                       struct resource *res, unsigned int nres);
-
-You can use platform_device_register_simple() as a one-step call to allocate
-and register a device.
-
-
-Device Naming and Driver Binding
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The platform_device.dev.bus_id is the canonical name for the devices.
-It's built from two components:
-
-    * platform_device.name ... which is also used to for driver matching.
-
-    * platform_device.id ... the device instance number, or else "-1"
-      to indicate there's only one.
-
-These are concatenated, so name/id "serial"/0 indicates bus_id "serial.0", and
-"serial/3" indicates bus_id "serial.3"; both would use the platform_driver
-named "serial".  While "my_rtc"/-1 would be bus_id "my_rtc" (no instance id)
-and use the platform_driver called "my_rtc".
-
-Driver binding is performed automatically by the driver core, invoking
-driver probe() after finding a match between device and driver.  If the
-probe() succeeds, the driver and device are bound as usual.  There are
-three different ways to find such a match:
-
-    - Whenever a device is registered, the drivers for that bus are
-      checked for matches.  Platform devices should be registered very
-      early during system boot.
-
-    - When a driver is registered using platform_driver_register(), all
-      unbound devices on that bus are checked for matches.  Drivers
-      usually register later during booting, or by module loading.
-
-    - Registering a driver using platform_driver_probe() works just like
-      using platform_driver_register(), except that the driver won't
-      be probed later if another device registers.  (Which is OK, since
-      this interface is only for use with non-hotpluggable devices.)
-
-
-Early Platform Devices and Drivers
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The early platform interfaces provide platform data to platform device
-drivers early on during the system boot. The code is built on top of the
-early_param() command line parsing and can be executed very early on.
-
-Example: "earlyprintk" class early serial console in 6 steps
-
-1. Registering early platform device data
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The architecture code registers platform device data using the function
-early_platform_add_devices(). In the case of early serial console this
-should be hardware configuration for the serial port. Devices registered
-at this point will later on be matched against early platform drivers.
-
-2. Parsing kernel command line
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The architecture code calls parse_early_param() to parse the kernel
-command line. This will execute all matching early_param() callbacks.
-User specified early platform devices will be registered at this point.
-For the early serial console case the user can specify port on the
-kernel command line as "earlyprintk=serial.0" where "earlyprintk" is
-the class string, "serial" is the name of the platform driver and
-0 is the platform device id. If the id is -1 then the dot and the
-id can be omitted.
-
-3. Installing early platform drivers belonging to a certain class
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The architecture code may optionally force registration of all early
-platform drivers belonging to a certain class using the function
-early_platform_driver_register_all(). User specified devices from
-step 2 have priority over these. This step is omitted by the serial
-driver example since the early serial driver code should be disabled
-unless the user has specified port on the kernel command line.
-
-4. Early platform driver registration
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Compiled-in platform drivers making use of early_platform_init() are
-automatically registered during step 2 or 3. The serial driver example
-should use early_platform_init("earlyprintk", &platform_driver).
-
-5. Probing of early platform drivers belonging to a certain class
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The architecture code calls early_platform_driver_probe() to match
-registered early platform devices associated with a certain class with
-registered early platform drivers. Matched devices will get probed().
-This step can be executed at any point during the early boot. As soon
-as possible may be good for the serial port case.
-
-6. Inside the early platform driver probe()
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The driver code needs to take special care during early boot, especially
-when it comes to memory allocation and interrupt registration. The code
-in the probe() function can use is_early_platform_device() to check if
-it is called at early platform device or at the regular platform device
-time. The early serial driver performs register_console() at this point.
-
-For further information, see <linux/platform_device.h>.
diff --git a/Documentation/driver-model/porting.rst b/Documentation/driver-model/porting.rst
new file mode 100644 (file)
index 0000000..ae4bf84
--- /dev/null
@@ -0,0 +1,448 @@
+=======================================
+Porting Drivers to the New Driver Model
+=======================================
+
+Patrick Mochel
+
+7 January 2003
+
+
+Overview
+
+Please refer to `Documentation/driver-model/*.rst` for definitions of
+various driver types and concepts.
+
+Most of the work of porting devices drivers to the new model happens
+at the bus driver layer. This was intentional, to minimize the
+negative effect on kernel drivers, and to allow a gradual transition
+of bus drivers.
+
+In a nutshell, the driver model consists of a set of objects that can
+be embedded in larger, bus-specific objects. Fields in these generic
+objects can replace fields in the bus-specific objects.
+
+The generic objects must be registered with the driver model core. By
+doing so, they will exported via the sysfs filesystem. sysfs can be
+mounted by doing::
+
+       # mount -t sysfs sysfs /sys
+
+
+
+The Process
+
+Step 0: Read include/linux/device.h for object and function definitions.
+
+Step 1: Registering the bus driver.
+
+
+- Define a struct bus_type for the bus driver::
+
+    struct bus_type pci_bus_type = {
+          .name           = "pci",
+    };
+
+
+- Register the bus type.
+
+  This should be done in the initialization function for the bus type,
+  which is usually the module_init(), or equivalent, function::
+
+    static int __init pci_driver_init(void)
+    {
+            return bus_register(&pci_bus_type);
+    }
+
+    subsys_initcall(pci_driver_init);
+
+
+  The bus type may be unregistered (if the bus driver may be compiled
+  as a module) by doing::
+
+     bus_unregister(&pci_bus_type);
+
+
+- Export the bus type for others to use.
+
+  Other code may wish to reference the bus type, so declare it in a
+  shared header file and export the symbol.
+
+From include/linux/pci.h::
+
+  extern struct bus_type pci_bus_type;
+
+
+From file the above code appears in::
+
+  EXPORT_SYMBOL(pci_bus_type);
+
+
+
+- This will cause the bus to show up in /sys/bus/pci/ with two
+  subdirectories: 'devices' and 'drivers'::
+
+    # tree -d /sys/bus/pci/
+    /sys/bus/pci/
+    |-- devices
+    `-- drivers
+
+
+
+Step 2: Registering Devices.
+
+struct device represents a single device. It mainly contains metadata
+describing the relationship the device has to other entities.
+
+
+- Embed a struct device in the bus-specific device type::
+
+
+    struct pci_dev {
+           ...
+           struct  device  dev;            /* Generic device interface */
+           ...
+    };
+
+  It is recommended that the generic device not be the first item in
+  the struct to discourage programmers from doing mindless casts
+  between the object types. Instead macros, or inline functions,
+  should be created to convert from the generic object type::
+
+
+    #define to_pci_dev(n) container_of(n, struct pci_dev, dev)
+
+    or
+
+    static inline struct pci_dev * to_pci_dev(struct kobject * kobj)
+    {
+       return container_of(n, struct pci_dev, dev);
+    }
+
+  This allows the compiler to verify type-safety of the operations
+  that are performed (which is Good).
+
+
+- Initialize the device on registration.
+
+  When devices are discovered or registered with the bus type, the
+  bus driver should initialize the generic device. The most important
+  things to initialize are the bus_id, parent, and bus fields.
+
+  The bus_id is an ASCII string that contains the device's address on
+  the bus. The format of this string is bus-specific. This is
+  necessary for representing devices in sysfs.
+
+  parent is the physical parent of the device. It is important that
+  the bus driver sets this field correctly.
+
+  The driver model maintains an ordered list of devices that it uses
+  for power management. This list must be in order to guarantee that
+  devices are shutdown before their physical parents, and vice versa.
+  The order of this list is determined by the parent of registered
+  devices.
+
+  Also, the location of the device's sysfs directory depends on a
+  device's parent. sysfs exports a directory structure that mirrors
+  the device hierarchy. Accurately setting the parent guarantees that
+  sysfs will accurately represent the hierarchy.
+
+  The device's bus field is a pointer to the bus type the device
+  belongs to. This should be set to the bus_type that was declared
+  and initialized before.
+
+  Optionally, the bus driver may set the device's name and release
+  fields.
+
+  The name field is an ASCII string describing the device, like
+
+     "ATI Technologies Inc Radeon QD"
+
+  The release field is a callback that the driver model core calls
+  when the device has been removed, and all references to it have
+  been released. More on this in a moment.
+
+
+- Register the device.
+
+  Once the generic device has been initialized, it can be registered
+  with the driver model core by doing::
+
+       device_register(&dev->dev);
+
+  It can later be unregistered by doing::
+
+       device_unregister(&dev->dev);
+
+  This should happen on buses that support hotpluggable devices.
+  If a bus driver unregisters a device, it should not immediately free
+  it. It should instead wait for the driver model core to call the
+  device's release method, then free the bus-specific object.
+  (There may be other code that is currently referencing the device
+  structure, and it would be rude to free the device while that is
+  happening).
+
+
+  When the device is registered, a directory in sysfs is created.
+  The PCI tree in sysfs looks like::
+
+    /sys/devices/pci0/
+    |-- 00:00.0
+    |-- 00:01.0
+    |   `-- 01:00.0
+    |-- 00:02.0
+    |   `-- 02:1f.0
+    |       `-- 03:00.0
+    |-- 00:1e.0
+    |   `-- 04:04.0
+    |-- 00:1f.0
+    |-- 00:1f.1
+    |   |-- ide0
+    |   |   |-- 0.0
+    |   |   `-- 0.1
+    |   `-- ide1
+    |       `-- 1.0
+    |-- 00:1f.2
+    |-- 00:1f.3
+    `-- 00:1f.5
+
+  Also, symlinks are created in the bus's 'devices' directory
+  that point to the device's directory in the physical hierarchy::
+
+    /sys/bus/pci/devices/
+    |-- 00:00.0 -> ../../../devices/pci0/00:00.0
+    |-- 00:01.0 -> ../../../devices/pci0/00:01.0
+    |-- 00:02.0 -> ../../../devices/pci0/00:02.0
+    |-- 00:1e.0 -> ../../../devices/pci0/00:1e.0
+    |-- 00:1f.0 -> ../../../devices/pci0/00:1f.0
+    |-- 00:1f.1 -> ../../../devices/pci0/00:1f.1
+    |-- 00:1f.2 -> ../../../devices/pci0/00:1f.2
+    |-- 00:1f.3 -> ../../../devices/pci0/00:1f.3
+    |-- 00:1f.5 -> ../../../devices/pci0/00:1f.5
+    |-- 01:00.0 -> ../../../devices/pci0/00:01.0/01:00.0
+    |-- 02:1f.0 -> ../../../devices/pci0/00:02.0/02:1f.0
+    |-- 03:00.0 -> ../../../devices/pci0/00:02.0/02:1f.0/03:00.0
+    `-- 04:04.0 -> ../../../devices/pci0/00:1e.0/04:04.0
+
+
+
+Step 3: Registering Drivers.
+
+struct device_driver is a simple driver structure that contains a set
+of operations that the driver model core may call.
+
+
+- Embed a struct device_driver in the bus-specific driver.
+
+  Just like with devices, do something like::
+
+    struct pci_driver {
+           ...
+           struct device_driver    driver;
+    };
+
+
+- Initialize the generic driver structure.
+
+  When the driver registers with the bus (e.g. doing pci_register_driver()),
+  initialize the necessary fields of the driver: the name and bus
+  fields.
+
+
+- Register the driver.
+
+  After the generic driver has been initialized, call::
+
+       driver_register(&drv->driver);
+
+  to register the driver with the core.
+
+  When the driver is unregistered from the bus, unregister it from the
+  core by doing::
+
+        driver_unregister(&drv->driver);
+
+  Note that this will block until all references to the driver have
+  gone away. Normally, there will not be any.
+
+
+- Sysfs representation.
+
+  Drivers are exported via sysfs in their bus's 'driver's directory.
+  For example::
+
+    /sys/bus/pci/drivers/
+    |-- 3c59x
+    |-- Ensoniq AudioPCI
+    |-- agpgart-amdk7
+    |-- e100
+    `-- serial
+
+
+Step 4: Define Generic Methods for Drivers.
+
+struct device_driver defines a set of operations that the driver model
+core calls. Most of these operations are probably similar to
+operations the bus already defines for drivers, but taking different
+parameters.
+
+It would be difficult and tedious to force every driver on a bus to
+simultaneously convert their drivers to generic format. Instead, the
+bus driver should define single instances of the generic methods that
+forward call to the bus-specific drivers. For instance::
+
+
+  static int pci_device_remove(struct device * dev)
+  {
+          struct pci_dev * pci_dev = to_pci_dev(dev);
+          struct pci_driver * drv = pci_dev->driver;
+
+          if (drv) {
+                  if (drv->remove)
+                          drv->remove(pci_dev);
+                  pci_dev->driver = NULL;
+          }
+          return 0;
+  }
+
+
+The generic driver should be initialized with these methods before it
+is registered::
+
+        /* initialize common driver fields */
+        drv->driver.name = drv->name;
+        drv->driver.bus = &pci_bus_type;
+        drv->driver.probe = pci_device_probe;
+        drv->driver.resume = pci_device_resume;
+        drv->driver.suspend = pci_device_suspend;
+        drv->driver.remove = pci_device_remove;
+
+        /* register with core */
+        driver_register(&drv->driver);
+
+
+Ideally, the bus should only initialize the fields if they are not
+already set. This allows the drivers to implement their own generic
+methods.
+
+
+Step 5: Support generic driver binding.
+
+The model assumes that a device or driver can be dynamically
+registered with the bus at any time. When registration happens,
+devices must be bound to a driver, or drivers must be bound to all
+devices that it supports.
+
+A driver typically contains a list of device IDs that it supports. The
+bus driver compares these IDs to the IDs of devices registered with it.
+The format of the device IDs, and the semantics for comparing them are
+bus-specific, so the generic model does attempt to generalize them.
+
+Instead, a bus may supply a method in struct bus_type that does the
+comparison::
+
+  int (*match)(struct device * dev, struct device_driver * drv);
+
+match should return positive value if the driver supports the device,
+and zero otherwise. It may also return error code (for example
+-EPROBE_DEFER) if determining that given driver supports the device is
+not possible.
+
+When a device is registered, the bus's list of drivers is iterated
+over. bus->match() is called for each one until a match is found.
+
+When a driver is registered, the bus's list of devices is iterated
+over. bus->match() is called for each device that is not already
+claimed by a driver.
+
+When a device is successfully bound to a driver, device->driver is
+set, the device is added to a per-driver list of devices, and a
+symlink is created in the driver's sysfs directory that points to the
+device's physical directory::
+
+  /sys/bus/pci/drivers/
+  |-- 3c59x
+  |   `-- 00:0b.0 -> ../../../../devices/pci0/00:0b.0
+  |-- Ensoniq AudioPCI
+  |-- agpgart-amdk7
+  |   `-- 00:00.0 -> ../../../../devices/pci0/00:00.0
+  |-- e100
+  |   `-- 00:0c.0 -> ../../../../devices/pci0/00:0c.0
+  `-- serial
+
+
+This driver binding should replace the existing driver binding
+mechanism the bus currently uses.
+
+
+Step 6: Supply a hotplug callback.
+
+Whenever a device is registered with the driver model core, the
+userspace program /sbin/hotplug is called to notify userspace.
+Users can define actions to perform when a device is inserted or
+removed.
+
+The driver model core passes several arguments to userspace via
+environment variables, including
+
+- ACTION: set to 'add' or 'remove'
+- DEVPATH: set to the device's physical path in sysfs.
+
+A bus driver may also supply additional parameters for userspace to
+consume. To do this, a bus must implement the 'hotplug' method in
+struct bus_type::
+
+     int (*hotplug) (struct device *dev, char **envp,
+                     int num_envp, char *buffer, int buffer_size);
+
+This is called immediately before /sbin/hotplug is executed.
+
+
+Step 7: Cleaning up the bus driver.
+
+The generic bus, device, and driver structures provide several fields
+that can replace those defined privately to the bus driver.
+
+- Device list.
+
+struct bus_type contains a list of all devices registered with the bus
+type. This includes all devices on all instances of that bus type.
+An internal list that the bus uses may be removed, in favor of using
+this one.
+
+The core provides an iterator to access these devices::
+
+  int bus_for_each_dev(struct bus_type * bus, struct device * start,
+                       void * data, int (*fn)(struct device *, void *));
+
+
+- Driver list.
+
+struct bus_type also contains a list of all drivers registered with
+it. An internal list of drivers that the bus driver maintains may
+be removed in favor of using the generic one.
+
+The drivers may be iterated over, like devices::
+
+  int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
+                       void * data, int (*fn)(struct device_driver *, void *));
+
+
+Please see drivers/base/bus.c for more information.
+
+
+- rwsem
+
+struct bus_type contains an rwsem that protects all core accesses to
+the device and driver lists. This can be used by the bus driver
+internally, and should be used when accessing the device or driver
+lists the bus maintains.
+
+
+- Device and driver fields.
+
+Some of the fields in struct device and struct device_driver duplicate
+fields in the bus-specific representations of these objects. Feel free
+to remove the bus-specific ones and favor the generic ones. Note
+though, that this will likely mean fixing up all the drivers that
+reference the bus-specific fields (though those should all be 1-line
+changes).
diff --git a/Documentation/driver-model/porting.txt b/Documentation/driver-model/porting.txt
deleted file mode 100644 (file)
index 453053f..0000000
+++ /dev/null
@@ -1,447 +0,0 @@
-
-Porting Drivers to the New Driver Model
-
-Patrick Mochel
-
-7 January 2003
-
-
-Overview
-
-Please refer to Documentation/driver-model/*.txt for definitions of
-various driver types and concepts. 
-
-Most of the work of porting devices drivers to the new model happens
-at the bus driver layer. This was intentional, to minimize the
-negative effect on kernel drivers, and to allow a gradual transition
-of bus drivers.
-
-In a nutshell, the driver model consists of a set of objects that can
-be embedded in larger, bus-specific objects. Fields in these generic
-objects can replace fields in the bus-specific objects. 
-
-The generic objects must be registered with the driver model core. By
-doing so, they will exported via the sysfs filesystem. sysfs can be
-mounted by doing 
-
-       # mount -t sysfs sysfs /sys
-
-
-
-The Process
-
-Step 0: Read include/linux/device.h for object and function definitions. 
-
-Step 1: Registering the bus driver. 
-
-
-- Define a struct bus_type for the bus driver.
-
-struct bus_type pci_bus_type = {
-        .name           = "pci",
-};
-
-
-- Register the bus type.
-  This should be done in the initialization function for the bus type,
-  which is usually the module_init(), or equivalent, function. 
-
-static int __init pci_driver_init(void)
-{
-        return bus_register(&pci_bus_type);
-}
-
-subsys_initcall(pci_driver_init);
-
-
-  The bus type may be unregistered (if the bus driver may be compiled
-  as a module) by doing:
-
-     bus_unregister(&pci_bus_type);
-
-
-- Export the bus type for others to use. 
-
-  Other code may wish to reference the bus type, so declare it in a 
-  shared header file and export the symbol.
-
-From include/linux/pci.h:
-
-extern struct bus_type pci_bus_type;
-
-
-From file the above code appears in:
-
-EXPORT_SYMBOL(pci_bus_type);
-
-
-
-- This will cause the bus to show up in /sys/bus/pci/ with two
-  subdirectories: 'devices' and 'drivers'.
-
-# tree -d /sys/bus/pci/
-/sys/bus/pci/
-|-- devices
-`-- drivers
-
-
-
-Step 2: Registering Devices. 
-
-struct device represents a single device. It mainly contains metadata
-describing the relationship the device has to other entities. 
-
-
-- Embed a struct device in the bus-specific device type. 
-
-
-struct pci_dev {
-       ...
-       struct  device  dev;            /* Generic device interface */
-       ...
-};
-
-  It is recommended that the generic device not be the first item in 
-  the struct to discourage programmers from doing mindless casts
-  between the object types. Instead macros, or inline functions,
-  should be created to convert from the generic object type.
-
-
-#define to_pci_dev(n) container_of(n, struct pci_dev, dev)
-
-or 
-
-static inline struct pci_dev * to_pci_dev(struct kobject * kobj)
-{
-       return container_of(n, struct pci_dev, dev);
-}
-
-  This allows the compiler to verify type-safety of the operations 
-  that are performed (which is Good).
-
-
-- Initialize the device on registration.
-
-  When devices are discovered or registered with the bus type, the 
-  bus driver should initialize the generic device. The most important
-  things to initialize are the bus_id, parent, and bus fields.
-
-  The bus_id is an ASCII string that contains the device's address on
-  the bus. The format of this string is bus-specific. This is
-  necessary for representing devices in sysfs. 
-
-  parent is the physical parent of the device. It is important that
-  the bus driver sets this field correctly. 
-
-  The driver model maintains an ordered list of devices that it uses
-  for power management. This list must be in order to guarantee that
-  devices are shutdown before their physical parents, and vice versa.
-  The order of this list is determined by the parent of registered
-  devices.
-
-  Also, the location of the device's sysfs directory depends on a
-  device's parent. sysfs exports a directory structure that mirrors 
-  the device hierarchy. Accurately setting the parent guarantees that
-  sysfs will accurately represent the hierarchy.
-
-  The device's bus field is a pointer to the bus type the device
-  belongs to. This should be set to the bus_type that was declared
-  and initialized before. 
-
-  Optionally, the bus driver may set the device's name and release
-  fields.
-
-  The name field is an ASCII string describing the device, like
-
-     "ATI Technologies Inc Radeon QD"
-
-  The release field is a callback that the driver model core calls 
-  when the device has been removed, and all references to it have 
-  been released. More on this in a moment.
-
-
-- Register the device. 
-
-  Once the generic device has been initialized, it can be registered
-  with the driver model core by doing:
-
-       device_register(&dev->dev);
-
-  It can later be unregistered by doing: 
-
-       device_unregister(&dev->dev);
-
-  This should happen on buses that support hotpluggable devices. 
-  If a bus driver unregisters a device, it should not immediately free
-  it. It should instead wait for the driver model core to call the 
-  device's release method, then free the bus-specific object. 
-  (There may be other code that is currently referencing the device
-  structure, and it would be rude to free the device while that is 
-  happening).
-
-
-  When the device is registered, a directory in sysfs is created. 
-  The PCI tree in sysfs looks like: 
-
-/sys/devices/pci0/
-|-- 00:00.0
-|-- 00:01.0
-|   `-- 01:00.0
-|-- 00:02.0
-|   `-- 02:1f.0
-|       `-- 03:00.0
-|-- 00:1e.0
-|   `-- 04:04.0
-|-- 00:1f.0
-|-- 00:1f.1
-|   |-- ide0
-|   |   |-- 0.0
-|   |   `-- 0.1
-|   `-- ide1
-|       `-- 1.0
-|-- 00:1f.2
-|-- 00:1f.3
-`-- 00:1f.5
-
-  Also, symlinks are created in the bus's 'devices' directory
-  that point to the device's directory in the physical hierarchy. 
-
-/sys/bus/pci/devices/
-|-- 00:00.0 -> ../../../devices/pci0/00:00.0
-|-- 00:01.0 -> ../../../devices/pci0/00:01.0
-|-- 00:02.0 -> ../../../devices/pci0/00:02.0
-|-- 00:1e.0 -> ../../../devices/pci0/00:1e.0
-|-- 00:1f.0 -> ../../../devices/pci0/00:1f.0
-|-- 00:1f.1 -> ../../../devices/pci0/00:1f.1
-|-- 00:1f.2 -> ../../../devices/pci0/00:1f.2
-|-- 00:1f.3 -> ../../../devices/pci0/00:1f.3
-|-- 00:1f.5 -> ../../../devices/pci0/00:1f.5
-|-- 01:00.0 -> ../../../devices/pci0/00:01.0/01:00.0
-|-- 02:1f.0 -> ../../../devices/pci0/00:02.0/02:1f.0
-|-- 03:00.0 -> ../../../devices/pci0/00:02.0/02:1f.0/03:00.0
-`-- 04:04.0 -> ../../../devices/pci0/00:1e.0/04:04.0
-
-
-
-Step 3: Registering Drivers.
-
-struct device_driver is a simple driver structure that contains a set
-of operations that the driver model core may call. 
-
-
-- Embed a struct device_driver in the bus-specific driver. 
-
-  Just like with devices, do something like:
-
-struct pci_driver {
-       ...
-       struct device_driver    driver;
-};
-
-
-- Initialize the generic driver structure. 
-
-  When the driver registers with the bus (e.g. doing pci_register_driver()),
-  initialize the necessary fields of the driver: the name and bus
-  fields. 
-
-
-- Register the driver.
-
-  After the generic driver has been initialized, call
-
-       driver_register(&drv->driver);
-
-  to register the driver with the core.
-
-  When the driver is unregistered from the bus, unregister it from the
-  core by doing:
-
-        driver_unregister(&drv->driver);
-
-  Note that this will block until all references to the driver have
-  gone away. Normally, there will not be any.
-
-
-- Sysfs representation.
-
-  Drivers are exported via sysfs in their bus's 'driver's directory. 
-  For example:
-
-/sys/bus/pci/drivers/
-|-- 3c59x
-|-- Ensoniq AudioPCI
-|-- agpgart-amdk7
-|-- e100
-`-- serial
-
-
-Step 4: Define Generic Methods for Drivers.
-
-struct device_driver defines a set of operations that the driver model
-core calls. Most of these operations are probably similar to
-operations the bus already defines for drivers, but taking different
-parameters. 
-
-It would be difficult and tedious to force every driver on a bus to
-simultaneously convert their drivers to generic format. Instead, the
-bus driver should define single instances of the generic methods that
-forward call to the bus-specific drivers. For instance: 
-
-
-static int pci_device_remove(struct device * dev)
-{
-        struct pci_dev * pci_dev = to_pci_dev(dev);
-        struct pci_driver * drv = pci_dev->driver;
-
-        if (drv) {
-                if (drv->remove)
-                        drv->remove(pci_dev);
-                pci_dev->driver = NULL;
-        }
-        return 0;
-}
-
-
-The generic driver should be initialized with these methods before it
-is registered. 
-
-        /* initialize common driver fields */
-        drv->driver.name = drv->name;
-        drv->driver.bus = &pci_bus_type;
-        drv->driver.probe = pci_device_probe;
-        drv->driver.resume = pci_device_resume;
-        drv->driver.suspend = pci_device_suspend;
-        drv->driver.remove = pci_device_remove;
-
-        /* register with core */
-        driver_register(&drv->driver);
-
-
-Ideally, the bus should only initialize the fields if they are not
-already set. This allows the drivers to implement their own generic
-methods. 
-
-
-Step 5: Support generic driver binding. 
-
-The model assumes that a device or driver can be dynamically
-registered with the bus at any time. When registration happens,
-devices must be bound to a driver, or drivers must be bound to all
-devices that it supports. 
-
-A driver typically contains a list of device IDs that it supports. The
-bus driver compares these IDs to the IDs of devices registered with it. 
-The format of the device IDs, and the semantics for comparing them are
-bus-specific, so the generic model does attempt to generalize them. 
-
-Instead, a bus may supply a method in struct bus_type that does the
-comparison: 
-
-  int (*match)(struct device * dev, struct device_driver * drv);
-
-match should return positive value if the driver supports the device,
-and zero otherwise. It may also return error code (for example
--EPROBE_DEFER) if determining that given driver supports the device is
-not possible.
-
-When a device is registered, the bus's list of drivers is iterated
-over. bus->match() is called for each one until a match is found. 
-
-When a driver is registered, the bus's list of devices is iterated
-over. bus->match() is called for each device that is not already
-claimed by a driver. 
-
-When a device is successfully bound to a driver, device->driver is
-set, the device is added to a per-driver list of devices, and a
-symlink is created in the driver's sysfs directory that points to the
-device's physical directory:
-
-/sys/bus/pci/drivers/
-|-- 3c59x
-|   `-- 00:0b.0 -> ../../../../devices/pci0/00:0b.0
-|-- Ensoniq AudioPCI
-|-- agpgart-amdk7
-|   `-- 00:00.0 -> ../../../../devices/pci0/00:00.0
-|-- e100
-|   `-- 00:0c.0 -> ../../../../devices/pci0/00:0c.0
-`-- serial
-
-
-This driver binding should replace the existing driver binding
-mechanism the bus currently uses. 
-
-
-Step 6: Supply a hotplug callback.
-
-Whenever a device is registered with the driver model core, the
-userspace program /sbin/hotplug is called to notify userspace. 
-Users can define actions to perform when a device is inserted or
-removed. 
-
-The driver model core passes several arguments to userspace via
-environment variables, including
-
-- ACTION: set to 'add' or 'remove'
-- DEVPATH: set to the device's physical path in sysfs. 
-
-A bus driver may also supply additional parameters for userspace to
-consume. To do this, a bus must implement the 'hotplug' method in
-struct bus_type:
-
-     int (*hotplug) (struct device *dev, char **envp, 
-                     int num_envp, char *buffer, int buffer_size);
-
-This is called immediately before /sbin/hotplug is executed. 
-
-
-Step 7: Cleaning up the bus driver.
-
-The generic bus, device, and driver structures provide several fields
-that can replace those defined privately to the bus driver. 
-
-- Device list.
-
-struct bus_type contains a list of all devices registered with the bus
-type. This includes all devices on all instances of that bus type.
-An internal list that the bus uses may be removed, in favor of using
-this one.
-
-The core provides an iterator to access these devices. 
-
-int bus_for_each_dev(struct bus_type * bus, struct device * start, 
-                     void * data, int (*fn)(struct device *, void *));
-
-
-- Driver list.
-
-struct bus_type also contains a list of all drivers registered with
-it. An internal list of drivers that the bus driver maintains may 
-be removed in favor of using the generic one. 
-
-The drivers may be iterated over, like devices: 
-
-int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
-                     void * data, int (*fn)(struct device_driver *, void *));
-
-
-Please see drivers/base/bus.c for more information.
-
-
-- rwsem 
-
-struct bus_type contains an rwsem that protects all core accesses to
-the device and driver lists. This can be used by the bus driver
-internally, and should be used when accessing the device or driver
-lists the bus maintains. 
-
-
-- Device and driver fields. 
-
-Some of the fields in struct device and struct device_driver duplicate
-fields in the bus-specific representations of these objects. Feel free
-to remove the bus-specific ones and favor the generic ones. Note
-though, that this will likely mean fixing up all the drivers that
-reference the bus-specific fields (though those should all be 1-line
-changes).
-
index 2806e55..f388545 100644 (file)
@@ -103,7 +103,7 @@ id_table    an array of NULL terminated EISA id strings,
                (driver_data).
 
 driver         a generic driver, such as described in
-               Documentation/driver-model/driver.txt. Only .name,
+               Documentation/driver-model/driver.rst. Only .name,
                .probe and .remove members are mandatory.
 =============== ====================================================
 
@@ -152,7 +152,7 @@ state    set of flags indicating the state of the device. Current
         flags are EISA_CONFIG_ENABLED and EISA_CONFIG_FORCED.
 res     set of four 256 bytes I/O regions allocated to this device
 dma_mask DMA mask set from the parent device.
-dev     generic device (see Documentation/driver-model/device.txt)
+dev     generic device (see Documentation/driver-model/device.rst)
 ======== ============================================================
 
 You can get the 'struct eisa_device' from 'struct device' using the
index 4a0a9c3..9e27c84 100644 (file)
@@ -169,7 +169,7 @@ byte offsets over a base for the register block.
 
 If you want to dump an u32 array in debugfs, you can create file with:
 
-    struct dentry *debugfs_create_u32_array(const char *name, umode_t mode,
+    void debugfs_create_u32_array(const char *name, umode_t mode,
                        struct dentry *parent,
                        u32 *array, u32 elements);
 
index f7b5e4f..496fa28 100644 (file)
@@ -214,11 +214,22 @@ fsync_mode=%s          Control the policy of fsync. Currently supports "posix",
                        non-atomic files likewise "nobarrier" mount option.
 test_dummy_encryption  Enable dummy encryption, which provides a fake fscrypt
                        context. The fake fscrypt context is used by xfstests.
-checkpoint=%s          Set to "disable" to turn off checkpointing. Set to "enable"
+checkpoint=%s[:%u[%]]     Set to "disable" to turn off checkpointing. Set to "enable"
                        to reenable checkpointing. Is enabled by default. While
                        disabled, any unmounting or unexpected shutdowns will cause
                        the filesystem contents to appear as they did when the
                        filesystem was mounted with that option.
+                       While mounting with checkpoint=disabled, the filesystem must
+                       run garbage collection to ensure that all available space can
+                       be used. If this takes too much time, the mount may return
+                       EAGAIN. You may optionally add a value to indicate how much
+                       of the disk you would be willing to temporarily give up to
+                       avoid additional garbage collection. This can be given as a
+                       number of blocks, or as a percent. For instance, mounting
+                       with checkpoint=disable:100% would always succeed, but it may
+                       hide up to all remaining free space. The actual space that
+                       would be unusable can be viewed at /sys/fs/f2fs/<disk>/unusable
+                       This space is reclaimed once checkpoint=enable.
 
 ================================================================================
 DEBUGFS ENTRIES
@@ -246,11 +257,14 @@ Files in /sys/fs/f2fs/<devname>
 ..............................................................................
  File                         Content
 
- gc_max_sleep_time            This tuning parameter controls the maximum sleep
+ gc_urgent_sleep_time         This parameter controls sleep time for gc_urgent.
+                              500 ms is set by default. See above gc_urgent.
+
+ gc_min_sleep_time            This tuning parameter controls the minimum sleep
                               time for the garbage collection thread. Time is
                               in milliseconds.
 
- gc_min_sleep_time            This tuning parameter controls the minimum sleep
+ gc_max_sleep_time            This tuning parameter controls the maximum sleep
                               time for the garbage collection thread. Time is
                               in milliseconds.
 
@@ -270,9 +284,6 @@ Files in /sys/fs/f2fs/<devname>
                               to 1, background thread starts to do GC by given
                               gc_urgent_sleep_time interval.
 
- gc_urgent_sleep_time         This parameter controls sleep time for gc_urgent.
-                              500 ms is set by default. See above gc_urgent.
-
  reclaim_segments             This parameter controls the number of prefree
                               segments to be reclaimed. If the number of prefree
                              segments is larger than the number of segments
@@ -287,7 +298,16 @@ Files in /sys/fs/f2fs/<devname>
                              checkpoint is triggered, and issued during the
                              checkpoint. By default, it is disabled with 0.
 
- trim_sections                This parameter controls the number of sections
+ discard_granularity         This parameter controls the granularity of discard
+                             command size. It will issue discard commands iif
+                             the size is larger than given granularity. Its
+                             unit size is 4KB, and 4 (=16KB) is set by default.
+                             The maximum value is 128 (=512KB).
+
+ reserved_blocks             This parameter indicates the number of blocks that
+                             f2fs reserves internally for root.
+
+ batched_trim_sections       This parameter controls the number of sections
                               to be trimmed out in batch mode when FITRIM
                               conducts. 32 sections is set by default.
 
@@ -309,11 +329,35 @@ Files in /sys/fs/f2fs/<devname>
                              the number is less than this value, it triggers
                              in-place-updates.
 
+ min_seq_blocks                      This parameter controls the threshold to serialize
+                             write IOs issued by multiple threads in parallel.
+
+ min_hot_blocks                      This parameter controls the threshold to allocate
+                             a hot data log for pending data blocks to write.
+
+ min_ssr_sections            This parameter adds the threshold when deciding
+                             SSR block allocation. If this is large, SSR mode
+                             will be enabled early.
+
+ ram_thresh                   This parameter controls the memory footprint used
+                             by free nids and cached nat entries. By default,
+                             10 is set, which indicates 10 MB / 1 GB RAM.
+
+ ra_nid_pages                When building free nids, F2FS reads NAT blocks
+                             ahead for speed up. Default is 0.
+
+ dirty_nats_ratio            Given dirty ratio of cached nat entries, F2FS
+                             determines flushing them in background.
+
  max_victim_search           This parameter controls the number of trials to
                              find a victim segment when conducting SSR and
                              cleaning operations. The default value is 4096
                              which covers 8GB block address range.
 
+ migration_granularity       For large-sized sections, F2FS can stop GC given
+                             this granularity instead of reclaiming entire
+                             section.
+
  dir_level                    This parameter controls the directory level to
                              support large directory. If a directory has a
                              number of files, it can reduce the file lookup
@@ -321,9 +365,53 @@ Files in /sys/fs/f2fs/<devname>
                              Otherwise, it needs to decrease this value to
                              reduce the space overhead. The default value is 0.
 
- ram_thresh                   This parameter controls the memory footprint used
-                             by free nids and cached nat entries. By default,
-                             10 is set, which indicates 10 MB / 1 GB RAM.
+ cp_interval                 F2FS tries to do checkpoint periodically, 60 secs
+                             by default.
+
+ idle_interval               F2FS detects system is idle, if there's no F2FS
+                             operations during given interval, 5 secs by
+                             default.
+
+ discard_idle_interval       F2FS detects the discard thread is idle, given
+                             time interval. Default is 5 secs.
+
+ gc_idle_interval            F2FS detects the GC thread is idle, given time
+                             interval. Default is 5 secs.
+
+ umount_discard_timeout       When unmounting the disk, F2FS waits for finishing
+                             queued discard commands which can take huge time.
+                             This gives time out for it, 5 secs by default.
+
+ iostat_enable               This controls to enable/disable iostat in F2FS.
+
+ readdir_ra                  This enables/disabled readahead of inode blocks
+                             in readdir, and default is enabled.
+
+ gc_pin_file_thresh          This indicates how many GC can be failed for the
+                             pinned file. If it exceeds this, F2FS doesn't
+                             guarantee its pinning state. 2048 trials is set
+                             by default.
+
+ extension_list                      This enables to change extension_list for hot/cold
+                             files in runtime.
+
+ inject_rate                 This controls injection rate of arbitrary faults.
+
+ inject_type                 This controls injection type of arbitrary faults.
+
+ dirty_segments              This shows # of dirty segments.
+
+ lifetime_write_kbytes       This shows # of data written to the disk.
+
+ features                    This shows current features enabled on F2FS.
+
+ current_reserved_blocks      This shows # of blocks currently reserved.
+
+ unusable                     If checkpoint=disable, this shows the number of
+                              blocks that are unusable.
+                              If checkpoint=enable it shows the number of blocks
+                              that would be unusable if checkpoint=disable were
+                              to be set.
 
 ================================================================================
 USAGE
@@ -716,3 +804,28 @@ WRITE_LIFE_NOT_SET    WARM_DATA                WRITE_LIFE_NOT_SET
 WRITE_LIFE_NONE       "                        WRITE_LIFE_NONE
 WRITE_LIFE_MEDIUM     "                        WRITE_LIFE_MEDIUM
 WRITE_LIFE_LONG       "                        WRITE_LIFE_LONG
+
+Fallocate(2) Policy
+-------------------
+
+The default policy follows the below posix rule.
+
+Allocating disk space
+    The default operation (i.e., mode is zero) of fallocate() allocates
+    the disk space within the range specified by offset and len.  The
+    file size (as reported by stat(2)) will be changed if offset+len is
+    greater than the file size.  Any subregion within the range specified
+    by offset and len that did not contain data before the call will be
+    initialized to zero.  This default behavior closely resembles the
+    behavior of the posix_fallocate(3) library function, and is intended
+    as a method of optimally implementing that function.
+
+However, once F2FS receives ioctl(fd, F2FS_IOC_SET_PIN_FILE) in prior to
+fallocate(fd, DEFAULT_MODE), it allocates on-disk blocks addressess having
+zero or random data, which is useful to the below scenario where:
+ 1. create(fd)
+ 2. ioctl(fd, F2FS_IOC_SET_PIN_FILE)
+ 3. fallocate(fd, 0, 0, size)
+ 4. address = fibmap(fd, offset)
+ 5. open(blkdev)
+ 6. write(blkdev, address)
index a226061..d750b69 100644 (file)
@@ -154,9 +154,11 @@ Table 1-1: Process specific entries in /proc
                symbol the task is blocked in - or "0" if not blocked.
  pagemap       Page table
  stack         Report full stack trace, enable via CONFIG_STACKTRACE
- smaps         an extension based on maps, showing the memory consumption of
+ smaps         An extension based on maps, showing the memory consumption of
                each mapping and flags associated with it
- numa_maps     an extension based on maps, showing the memory locality and
+ smaps_rollup  Accumulated smaps stats for all mappings of the process.  This
+               can be derived from smaps, but is faster and more convenient
+ numa_maps     An extension based on maps, showing the memory locality and
                binding policy as well as mem usage (in pages) of each mapping.
 ..............................................................................
 
@@ -366,7 +368,7 @@ Table 1-4: Contents of the stat files (as of 2.6.30-rc7)
   exit_code     the thread's exit_code in the form reported by the waitpid system call
 ..............................................................................
 
-The /proc/PID/maps file containing the currently mapped memory regions and
+The /proc/PID/maps file contains the currently mapped memory regions and
 their access permissions.
 
 The format is:
@@ -417,11 +419,14 @@ is not associated with a file:
  or if empty, the mapping is anonymous.
 
 The /proc/PID/smaps is an extension based on maps, showing the memory
-consumption for each of the process's mappings. For each of mappings there
-is a series of lines such as the following:
+consumption for each of the process's mappings. For each mapping (aka Virtual
+Memory Area, or VMA) there is a series of lines such as the following:
 
 08048000-080bc000 r-xp 00000000 03:02 13130      /bin/bash
+
 Size:               1084 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
 Rss:                 892 kB
 Pss:                 374 kB
 Shared_Clean:        892 kB
@@ -443,11 +448,14 @@ Locked:                0 kB
 THPeligible:           0
 VmFlags: rd ex mr mw me dw
 
-the first of these lines shows the same information as is displayed for the
-mapping in /proc/PID/maps.  The remaining lines show the size of the mapping
-(size), the amount of the mapping that is currently resident in RAM (RSS), the
-process' proportional share of this mapping (PSS), the number of clean and
-dirty private pages in the mapping.
+The first of these lines shows the same information as is displayed for the
+mapping in /proc/PID/maps.  Following lines show the size of the mapping
+(size); the size of each page allocated when backing a VMA (KernelPageSize),
+which is usually the same as the size in the page table entries; the page size
+used by the MMU when backing a VMA (in most cases, the same as KernelPageSize);
+the amount of the mapping that is currently resident in RAM (RSS); the
+process' proportional share of this mapping (PSS); and the number of clean and
+dirty shared and private pages in the mapping.
 
 The "proportional set size" (PSS) of a process is the count of pages it has
 in memory, where each page is divided by the number of processes sharing it.
@@ -532,6 +540,19 @@ guarantees:
 2) If there is something at a given vaddr during the entirety of the
    life of the smaps/maps walk, there will be some output for it.
 
+The /proc/PID/smaps_rollup file includes the same fields as /proc/PID/smaps,
+but their values are the sums of the corresponding values for all mappings of
+the process.  Additionally, it contains these fields:
+
+Pss_Anon
+Pss_File
+Pss_Shmem
+
+They represent the proportional shares of anonymous, file, and shmem pages, as
+described for smaps above.  These fields are omitted in smaps since each
+mapping identifies the type (anon, file, or shmem) of all pages it contains.
+Thus all information in smaps_rollup can be derived from smaps, but at a
+significantly higher cost.
 
 The /proc/PID/clear_refs is used to reset the PG_Referenced and ACCESSED/YOUNG
 bits on both physical and virtual pages associated with a process, and the
index 68604e6..8db0121 100644 (file)
@@ -222,7 +222,7 @@ static void
 xfs_foo_read_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount *mp = bp->b_target->bt_mount;
+       struct xfs_mount *mp = bp->b_mount;
 
         if ((xfs_sb_version_hascrc(&mp->m_sb) &&
              !xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
@@ -245,7 +245,7 @@ static bool
 xfs_foo_verify(
        struct xfs_buf          *bp)
 {
-        struct xfs_mount       *mp = bp->b_target->bt_mount;
+        struct xfs_mount       *mp = bp->b_mount;
         struct xfs_ondisk_hdr  *hdr = bp->b_addr;
 
         if (hdr->magic != cpu_to_be32(XFS_FOO_MAGIC))
@@ -272,7 +272,7 @@ static bool
 xfs_foo_verify(
        struct xfs_buf          *bp)
 {
-        struct xfs_mount       *mp = bp->b_target->bt_mount;
+        struct xfs_mount       *mp = bp->b_mount;
         struct xfs_ondisk_hdr  *hdr = bp->b_addr;
 
         if (hdr->magic == cpu_to_be32(XFS_FOO_CRC_MAGIC)) {
@@ -297,7 +297,7 @@ static void
 xfs_foo_write_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_buf_log_item *bip = bp->b_fspriv;
 
        if (!xfs_foo_verify(bp)) {
diff --git a/Documentation/hid/hid-alps.rst b/Documentation/hid/hid-alps.rst
new file mode 100644 (file)
index 0000000..e2f4c4c
--- /dev/null
@@ -0,0 +1,180 @@
+==========================
+ALPS HID Touchpad Protocol
+==========================
+
+Introduction
+------------
+Currently ALPS HID driver supports U1 Touchpad device.
+
+U1 device basic information.
+
+==========     ======
+Vender ID      0x044E
+Product ID     0x120B
+Version ID     0x0121
+==========     ======
+
+
+HID Descriptor
+--------------
+
+=======        ====================    =====   =======================================
+Byte   Field                   Value   Notes
+=======        ====================    =====   =======================================
+0      wHIDDescLength          001E    Length of HID Descriptor : 30 bytes
+2      bcdVersion              0100    Compliant with Version 1.00
+4      wReportDescLength       00B2    Report Descriptor is 178 Bytes (0x00B2)
+6      wReportDescRegister     0002    Identifier to read Report Descriptor
+8      wInputRegister          0003    Identifier to read Input Report
+10     wMaxInputLength         0053    Input Report is 80 Bytes + 2
+12     wOutputRegister         0000    Identifier to read Output Report
+14     wMaxOutputLength        0000    No Output Reports
+16     wCommandRegister        0005    Identifier for Command Register
+18     wDataRegister           0006    Identifier for Data Register
+20     wVendorID               044E    Vendor ID 0x044E
+22     wProductID              120B    Product ID 0x120B
+24     wVersionID              0121    Version 01.21
+26     RESERVED                0000    RESERVED
+=======        ====================    =====   =======================================
+
+
+Report ID
+---------
+
+==========     =================  =========================================
+ReportID-1     (Input Reports)    (HIDUsage-Mouse) for TP&SP
+ReportID-2     (Input Reports)    (HIDUsage-keyboard) for TP
+ReportID-3     (Input Reports)    (Vendor Usage: Max 10 finger data) for TP
+ReportID-4     (Input Reports)    (Vendor Usage: ON bit data) for GP
+ReportID-5     (Feature Reports)  Feature Reports
+ReportID-6     (Input Reports)    (Vendor Usage: StickPointer data) for SP
+ReportID-7     (Feature Reports)  Flash update (Bootloader)
+==========     =================  =========================================
+
+
+Data pattern
+------------
+
+=====  ==========      =====   =================
+Case1  ReportID_1      TP/SP   Relative/Relative
+Case2  ReportID_3      TP      Absolute
+       ReportID_6      SP      Absolute
+=====  ==========      =====   =================
+
+
+Command Read/Write
+------------------
+To read/write to RAM, need to send a commands to the device.
+
+The command format is as below.
+
+DataByte(SET_REPORT)
+
+=====  ======================
+Byte1  Command Byte
+Byte2  Address - Byte 0 (LSB)
+Byte3  Address - Byte 1
+Byte4  Address - Byte 2
+Byte5  Address - Byte 3 (MSB)
+Byte6  Value Byte
+Byte7  Checksum
+=====  ======================
+
+Command Byte is read=0xD1/write=0xD2 .
+
+Address is read/write RAM address.
+
+Value Byte is writing data when you send the write commands.
+
+When you read RAM, there is no meaning.
+
+DataByte(GET_REPORT)
+
+=====  ======================
+Byte1  Response Byte
+Byte2  Address - Byte 0 (LSB)
+Byte3  Address - Byte 1
+Byte4  Address - Byte 2
+Byte5  Address - Byte 3 (MSB)
+Byte6  Value Byte
+Byte7  Checksum
+=====  ======================
+
+Read value is stored in Value Byte.
+
+
+Packet Format
+Touchpad data byte
+------------------
+
+
+======= ======= ======= ======= ======= ======= ======= ======= =====
+-      b7      b6      b5      b4      b3      b2      b1      b0
+======= ======= ======= ======= ======= ======= ======= ======= =====
+1      0       0       SW6     SW5     SW4     SW3     SW2     SW1
+2      0       0       0       Fcv     Fn3     Fn2     Fn1     Fn0
+3      Xa0_7   Xa0_6   Xa0_5   Xa0_4   Xa0_3   Xa0_2   Xa0_1   Xa0_0
+4      Xa0_15  Xa0_14  Xa0_13  Xa0_12  Xa0_11  Xa0_10  Xa0_9   Xa0_8
+5      Ya0_7   Ya0_6   Ya0_5   Ya0_4   Ya0_3   Ya0_2   Ya0_1   Ya0_0
+6      Ya0_15  Ya0_14  Ya0_13  Ya0_12  Ya0_11  Ya0_10  Ya0_9   Ya0_8
+7      LFB0    Zs0_6   Zs0_5   Zs0_4   Zs0_3   Zs0_2   Zs0_1   Zs0_0
+
+8      Xa1_7   Xa1_6   Xa1_5   Xa1_4   Xa1_3   Xa1_2   Xa1_1   Xa1_0
+9      Xa1_15  Xa1_14  Xa1_13  Xa1_12  Xa1_11  Xa1_10  Xa1_9   Xa1_8
+10     Ya1_7   Ya1_6   Ya1_5   Ya1_4   Ya1_3   Ya1_2   Ya1_1   Ya1_0
+11     Ya1_15  Ya1_14  Ya1_13  Ya1_12  Ya1_11  Ya1_10  Ya1_9   Ya1_8
+12     LFB1    Zs1_6   Zs1_5   Zs1_4   Zs1_3   Zs1_2   Zs1_1   Zs1_0
+
+13     Xa2_7   Xa2_6   Xa2_5   Xa2_4   Xa2_3   Xa2_2   Xa2_1   Xa2_0
+14     Xa2_15  Xa2_14  Xa2_13  Xa2_12  Xa2_11  Xa2_10  Xa2_9   Xa2_8
+15     Ya2_7   Ya2_6   Ya2_5   Ya2_4   Ya2_3   Ya2_2   Ya2_1   Ya2_0
+16     Ya2_15  Ya2_14  Ya2_13  Ya2_12  Ya2_11  Ya2_10  Ya2_9   Ya2_8
+17     LFB2    Zs2_6   Zs2_5   Zs2_4   Zs2_3   Zs2_2   Zs2_1   Zs2_0
+
+18     Xa3_7   Xa3_6   Xa3_5   Xa3_4   Xa3_3   Xa3_2   Xa3_1   Xa3_0
+19     Xa3_15  Xa3_14  Xa3_13  Xa3_12  Xa3_11  Xa3_10  Xa3_9   Xa3_8
+20     Ya3_7   Ya3_6   Ya3_5   Ya3_4   Ya3_3   Ya3_2   Ya3_1   Ya3_0
+21     Ya3_15  Ya3_14  Ya3_13  Ya3_12  Ya3_11  Ya3_10  Ya3_9   Ya3_8
+22     LFB3    Zs3_6   Zs3_5   Zs3_4   Zs3_3   Zs3_2   Zs3_1   Zs3_0
+
+23     Xa4_7   Xa4_6   Xa4_5   Xa4_4   Xa4_3   Xa4_2   Xa4_1   Xa4_0
+24     Xa4_15  Xa4_14  Xa4_13  Xa4_12  Xa4_11  Xa4_10  Xa4_9   Xa4_8
+25     Ya4_7   Ya4_6   Ya4_5   Ya4_4   Ya4_3   Ya4_2   Ya4_1   Ya4_0
+26     Ya4_15  Ya4_14  Ya4_13  Ya4_12  Ya4_11  Ya4_10  Ya4_9   Ya4_8
+27     LFB4    Zs4_6   Zs4_5   Zs4_4   Zs4_3   Zs4_2   Zs4_1   Zs4_0
+======= ======= ======= ======= ======= ======= ======= ======= =====
+
+
+SW1-SW6:
+       SW ON/OFF status
+Xan_15-0(16bit):
+       X Absolute data of the "n"th finger
+Yan_15-0(16bit):
+       Y Absolute data of the "n"th finger
+Zsn_6-0(7bit):
+       Operation area of the "n"th finger
+
+
+StickPointer data byte
+----------------------
+
+======= ======= ======= ======= ======= ======= ======= ======= =====
+-      b7      b6      b5      b4      b3      b2      b1      b0
+======= ======= ======= ======= ======= ======= ======= ======= =====
+Byte1  1       1       1       0       1       SW3     SW2     SW1
+Byte2  X7      X6      X5      X4      X3      X2      X1      X0
+Byte3  X15     X14     X13     X12     X11     X10     X9      X8
+Byte4  Y7      Y6      Y5      Y4      Y3      Y2      Y1      Y0
+Byte5  Y15     Y14     Y13     Y12     Y11     Y10     Y9      Y8
+Byte6  Z7      Z6      Z5      Z4      Z3      Z2      Z1      Z0
+Byte7  T&P     Z14     Z13     Z12     Z11     Z10     Z9      Z8
+======= ======= ======= ======= ======= ======= ======= ======= =====
+
+SW1-SW3:
+       SW ON/OFF status
+Xn_15-0(16bit):
+       X Absolute data
+Yn_15-0(16bit):
+       Y Absolute data
+Zn_14-0(15bit):
+       Z
diff --git a/Documentation/hid/hid-alps.txt b/Documentation/hid/hid-alps.txt
deleted file mode 100644 (file)
index 6b02a24..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-ALPS HID Touchpad Protocol
-----------------------
-
-Introduction
-------------
-Currently ALPS HID driver supports U1 Touchpad device.
-
-U1 devuce basic information.
-Vender ID      0x044E
-Product ID     0x120B
-Version ID     0x0121
-
-
-HID Descriptor
-------------
-Byte   Field                   Value   Notes
-0      wHIDDescLength          001E    Length of HID Descriptor : 30 bytes
-2      bcdVersion              0100    Compliant with Version 1.00
-4      wReportDescLength       00B2    Report Descriptor is 178 Bytes (0x00B2)
-6      wReportDescRegister     0002    Identifier to read Report Descriptor
-8      wInputRegister          0003    Identifier to read Input Report
-10     wMaxInputLength         0053    Input Report is 80 Bytes + 2
-12     wOutputRegister         0000    Identifier to read Output Report
-14     wMaxOutputLength        0000    No Output Reports
-16     wCommandRegister        0005    Identifier for Command Register
-18     wDataRegister           0006    Identifier for Data Register
-20     wVendorID               044E    Vendor ID 0x044E
-22     wProductID              120B    Product ID 0x120B
-24     wVersionID              0121    Version 01.21
-26     RESERVED                0000    RESERVED
-
-
-Report ID
-------------
-ReportID-1     (Input Reports) (HIDUsage-Mouse) for TP&SP
-ReportID-2     (Input Reports) (HIDUsage-keyboard) for TP
-ReportID-3     (Input Reports) (Vendor Usage: Max 10 finger data) for TP
-ReportID-4     (Input Reports) (Vendor Usage: ON bit data) for GP
-ReportID-5     (Feature Reports)       Feature Reports
-ReportID-6     (Input Reports) (Vendor Usage: StickPointer data) for SP
-ReportID-7     (Feature Reports)       Flash update (Bootloader)
-
-
-Data pattern
-------------
-Case1  ReportID_1      TP/SP   Relative/Relative
-Case2  ReportID_3      TP      Absolute
-       ReportID_6      SP      Absolute
-
-
-Command Read/Write
-------------------
-To read/write to RAM, need to send a commands to the device.
-The command format is as below.
-
-DataByte(SET_REPORT)
-Byte1  Command Byte
-Byte2  Address - Byte 0 (LSB)
-Byte3  Address - Byte 1
-Byte4  Address - Byte 2
-Byte5  Address - Byte 3 (MSB)
-Byte6  Value Byte
-Byte7  Checksum
-
-Command Byte is read=0xD1/write=0xD2 .
-Address is read/write RAM address.
-Value Byte is writing data when you send the write commands.
-When you read RAM, there is no meaning.
-
-DataByte(GET_REPORT)
-Byte1  Response Byte
-Byte2  Address - Byte 0 (LSB)
-Byte3  Address - Byte 1
-Byte4  Address - Byte 2
-Byte5  Address - Byte 3 (MSB)
-Byte6  Value Byte
-Byte7  Checksum
-
-Read value is stored in Value Byte.
-
-
-Packet Format
-Touchpad data byte
-------------------
-       b7      b6      b5      b4      b3      b2      b1      b0
-1      0       0       SW6     SW5     SW4     SW3     SW2     SW1
-2      0       0       0       Fcv     Fn3     Fn2     Fn1     Fn0
-3      Xa0_7   Xa0_6   Xa0_5   Xa0_4   Xa0_3   Xa0_2   Xa0_1   Xa0_0
-4      Xa0_15  Xa0_14  Xa0_13  Xa0_12  Xa0_11  Xa0_10  Xa0_9   Xa0_8
-5      Ya0_7   Ya0_6   Ya0_5   Ya0_4   Ya0_3   Ya0_2   Ya0_1   Ya0_0
-6      Ya0_15  Ya0_14  Ya0_13  Ya0_12  Ya0_11  Ya0_10  Ya0_9   Ya0_8
-7      LFB0    Zs0_6   Zs0_5   Zs0_4   Zs0_3   Zs0_2   Zs0_1   Zs0_0
-
-8      Xa1_7   Xa1_6   Xa1_5   Xa1_4   Xa1_3   Xa1_2   Xa1_1   Xa1_0
-9      Xa1_15  Xa1_14  Xa1_13  Xa1_12  Xa1_11  Xa1_10  Xa1_9   Xa1_8
-10     Ya1_7   Ya1_6   Ya1_5   Ya1_4   Ya1_3   Ya1_2   Ya1_1   Ya1_0
-11     Ya1_15  Ya1_14  Ya1_13  Ya1_12  Ya1_11  Ya1_10  Ya1_9   Ya1_8
-12     LFB1    Zs1_6   Zs1_5   Zs1_4   Zs1_3   Zs1_2   Zs1_1   Zs1_0
-
-13     Xa2_7   Xa2_6   Xa2_5   Xa2_4   Xa2_3   Xa2_2   Xa2_1   Xa2_0
-14     Xa2_15  Xa2_14  Xa2_13  Xa2_12  Xa2_11  Xa2_10  Xa2_9   Xa2_8
-15     Ya2_7   Ya2_6   Ya2_5   Ya2_4   Ya2_3   Ya2_2   Ya2_1   Ya2_0
-16     Ya2_15  Ya2_14  Ya2_13  Ya2_12  Ya2_11  Ya2_10  Ya2_9   Ya2_8
-17     LFB2    Zs2_6   Zs2_5   Zs2_4   Zs2_3   Zs2_2   Zs2_1   Zs2_0
-
-18     Xa3_7   Xa3_6   Xa3_5   Xa3_4   Xa3_3   Xa3_2   Xa3_1   Xa3_0
-19     Xa3_15  Xa3_14  Xa3_13  Xa3_12  Xa3_11  Xa3_10  Xa3_9   Xa3_8
-20     Ya3_7   Ya3_6   Ya3_5   Ya3_4   Ya3_3   Ya3_2   Ya3_1   Ya3_0
-21     Ya3_15  Ya3_14  Ya3_13  Ya3_12  Ya3_11  Ya3_10  Ya3_9   Ya3_8
-22     LFB3    Zs3_6   Zs3_5   Zs3_4   Zs3_3   Zs3_2   Zs3_1   Zs3_0
-
-23     Xa4_7   Xa4_6   Xa4_5   Xa4_4   Xa4_3   Xa4_2   Xa4_1   Xa4_0
-24     Xa4_15  Xa4_14  Xa4_13  Xa4_12  Xa4_11  Xa4_10  Xa4_9   Xa4_8
-25     Ya4_7   Ya4_6   Ya4_5   Ya4_4   Ya4_3   Ya4_2   Ya4_1   Ya4_0
-26     Ya4_15  Ya4_14  Ya4_13  Ya4_12  Ya4_11  Ya4_10  Ya4_9   Ya4_8
-27     LFB4    Zs4_6   Zs4_5   Zs4_4   Zs4_3   Zs4_2   Zs4_1   Zs4_0
-
-
-SW1-SW6:       SW ON/OFF status
-Xan_15-0(16bit):X Absolute data of the "n"th finger
-Yan_15-0(16bit):Y Absolute data of the "n"th finger
-Zsn_6-0(7bit): Operation area of the "n"th finger
-
-
-StickPointer data byte
-------------------
-       b7      b6      b5      b4      b3      b2      b1      b0
-Byte1  1       1       1       0       1       SW3     SW2     SW1
-Byte2  X7      X6      X5      X4      X3      X2      X1      X0
-Byte3  X15     X14     X13     X12     X11     X10     X9      X8
-Byte4  Y7      Y6      Y5      Y4      Y3      Y2      Y1      Y0
-Byte5  Y15     Y14     Y13     Y12     Y11     Y10     Y9      Y8
-Byte6  Z7      Z6      Z5      Z4      Z3      Z2      Z1      Z0
-Byte7  T&P     Z14     Z13     Z12     Z11     Z10     Z9      Z8
-
-SW1-SW3:       SW ON/OFF status
-Xn_15-0(16bit):X Absolute data
-Yn_15-0(16bit):Y Absolute data
-Zn_14-0(15bit):Z
diff --git a/Documentation/hid/hid-sensor.rst b/Documentation/hid/hid-sensor.rst
new file mode 100644 (file)
index 0000000..758972e
--- /dev/null
@@ -0,0 +1,242 @@
+=====================
+HID Sensors Framework
+=====================
+HID sensor framework provides necessary interfaces to implement sensor drivers,
+which are connected to a sensor hub. The sensor hub is a HID device and it provides
+a report descriptor conforming to HID 1.12 sensor usage tables.
+
+Description from the HID 1.12 "HID Sensor Usages" specification:
+"Standardization of HID usages for sensors would allow (but not require) sensor
+hardware vendors to provide a consistent Plug And Play interface at the USB boundary,
+thereby enabling some operating systems to incorporate common device drivers that
+could be reused between vendors, alleviating any need for the vendors to provide
+the drivers themselves."
+
+This specification describes many usage IDs, which describe the type of sensor
+and also the individual data fields. Each sensor can have variable number of
+data fields. The length and order is specified in the report descriptor. For
+example a part of report descriptor can look like::
+
+     INPUT(1)[INPUT]
+   ..
+      Field(2)
+        Physical(0020.0073)
+        Usage(1)
+          0020.045f
+        Logical Minimum(-32767)
+        Logical Maximum(32767)
+        Report Size(8)
+        Report Count(1)
+        Report Offset(16)
+        Flags(Variable Absolute)
+  ..
+  ..
+
+The report is indicating "sensor page (0x20)" contains an accelerometer-3D (0x73).
+This accelerometer-3D has some fields. Here for example field 2 is motion intensity
+(0x045f) with a logical minimum value of -32767 and logical maximum of 32767. The
+order of fields and length of each field is important as the input event raw
+data will use this format.
+
+
+Implementation
+==============
+
+This specification defines many different types of sensors with different sets of
+data fields. It is difficult to have a common input event to user space applications,
+for different sensors. For example an accelerometer can send X,Y and Z data, whereas
+an ambient light sensor can send illumination data.
+So the implementation has two parts:
+
+- Core hid driver
+- Individual sensor processing part (sensor drivers)
+
+Core driver
+-----------
+The core driver registers (hid-sensor-hub) registers as a HID driver. It parses
+report descriptors and identifies all the sensors present. It adds an MFD device
+with name HID-SENSOR-xxxx (where xxxx is usage id from the specification).
+
+For example:
+
+HID-SENSOR-200073 is registered for an Accelerometer 3D driver.
+
+So if any driver with this name is inserted, then the probe routine for that
+function will be called. So an accelerometer processing driver can register
+with this name and will be probed if there is an accelerometer-3D detected.
+
+The core driver provides a set of APIs which can be used by the processing
+drivers to register and get events for that usage id. Also it provides parsing
+functions, which get and set each input/feature/output report.
+
+Individual sensor processing part (sensor drivers)
+--------------------------------------------------
+
+The processing driver will use an interface provided by the core driver to parse
+the report and get the indexes of the fields and also can get events. This driver
+can use IIO interface to use the standard ABI defined for a type of sensor.
+
+
+Core driver Interface
+=====================
+
+Callback structure::
+
+  Each processing driver can use this structure to set some callbacks.
+       int (*suspend)(..): Callback when HID suspend is received
+       int (*resume)(..): Callback when HID resume is received
+       int (*capture_sample)(..): Capture a sample for one of its data fields
+       int (*send_event)(..): One complete event is received which can have
+                               multiple data fields.
+
+Registration functions::
+
+  int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
+                       u32 usage_id,
+                       struct hid_sensor_hub_callbacks *usage_callback):
+
+Registers callbacks for an usage id. The callback functions are not allowed
+to sleep::
+
+
+  int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
+                       u32 usage_id):
+
+Removes callbacks for an usage id.
+
+
+Parsing function::
+
+  int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
+                       u8 type,
+                       u32 usage_id, u32 attr_usage_id,
+                       struct hid_sensor_hub_attribute_info *info);
+
+A processing driver can look for some field of interest and check if it exists
+in a report descriptor. If it exists it will store necessary information
+so that fields can be set or get individually.
+These indexes avoid searching every time and getting field index to get or set.
+
+
+Set Feature report::
+
+  int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
+                       u32 field_index, s32 value);
+
+This interface is used to set a value for a field in feature report. For example
+if there is a field report_interval, which is parsed by a call to
+sensor_hub_input_get_attribute_info before, then it can directly set that
+individual field::
+
+
+  int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
+                       u32 field_index, s32 *value);
+
+This interface is used to get a value for a field in input report. For example
+if there is a field report_interval, which is parsed by a call to
+sensor_hub_input_get_attribute_info before, then it can directly get that
+individual field value::
+
+
+  int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
+                       u32 usage_id,
+                       u32 attr_usage_id, u32 report_id);
+
+This is used to get a particular field value through input reports. For example
+accelerometer wants to poll X axis value, then it can call this function with
+the usage id of X axis. HID sensors can provide events, so this is not necessary
+to poll for any field. If there is some new sample, the core driver will call
+registered callback function to process the sample.
+
+
+----------
+
+HID Custom and generic Sensors
+------------------------------
+
+
+HID Sensor specification defines two special sensor usage types. Since they
+don't represent a standard sensor, it is not possible to define using Linux IIO
+type interfaces.
+The purpose of these sensors is to extend the functionality or provide a
+way to obfuscate the data being communicated by a sensor. Without knowing the
+mapping between the data and its encapsulated form, it is difficult for
+an application/driver to determine what data is being communicated by the sensor.
+This allows some differentiating use cases, where vendor can provide applications.
+Some common use cases are debug other sensors or to provide some events like
+keyboard attached/detached or lid open/close.
+
+To allow application to utilize these sensors, here they are exported uses sysfs
+attribute groups, attributes and misc device interface.
+
+An example of this representation on sysfs::
+
+  /sys/devices/pci0000:00/INT33C2:00/i2c-0/i2c-INT33D1:00/0018:8086:09FA.0001/HID-SENSOR-2000e1.6.auto$ tree -R
+  .
+  │   ├──  enable_sensor
+  │   │   ├── feature-0-200316
+  │   │   │   ├── feature-0-200316-maximum
+  │   │   │   ├── feature-0-200316-minimum
+  │   │   │   ├── feature-0-200316-name
+  │   │   │   ├── feature-0-200316-size
+  │   │   │   ├── feature-0-200316-unit-expo
+  │   │   │   ├── feature-0-200316-units
+  │   │   │   ├── feature-0-200316-value
+  │   │   ├── feature-1-200201
+  │   │   │   ├── feature-1-200201-maximum
+  │   │   │   ├── feature-1-200201-minimum
+  │   │   │   ├── feature-1-200201-name
+  │   │   │   ├── feature-1-200201-size
+  │   │   │   ├── feature-1-200201-unit-expo
+  │   │   │   ├── feature-1-200201-units
+  │   │   │   ├── feature-1-200201-value
+  │   │   ├── input-0-200201
+  │   │   │   ├── input-0-200201-maximum
+  │   │   │   ├── input-0-200201-minimum
+  │   │   │   ├── input-0-200201-name
+  │   │   │   ├── input-0-200201-size
+  │   │   │   ├── input-0-200201-unit-expo
+  │   │   │   ├── input-0-200201-units
+  │   │   │   ├── input-0-200201-value
+  │   │   ├── input-1-200202
+  │   │   │   ├── input-1-200202-maximum
+  │   │   │   ├── input-1-200202-minimum
+  │   │   │   ├── input-1-200202-name
+  │   │   │   ├── input-1-200202-size
+  │   │   │   ├── input-1-200202-unit-expo
+  │   │   │   ├── input-1-200202-units
+  │   │   │   ├── input-1-200202-value
+
+Here there is a custom sensors with four fields, two feature and two inputs.
+Each field is represented by a set of attributes. All fields except the "value"
+are read only. The value field is a RW field.
+
+Example::
+
+  /sys/bus/platform/devices/HID-SENSOR-2000e1.6.auto/feature-0-200316$ grep -r . *
+  feature-0-200316-maximum:6
+  feature-0-200316-minimum:0
+  feature-0-200316-name:property-reporting-state
+  feature-0-200316-size:1
+  feature-0-200316-unit-expo:0
+  feature-0-200316-units:25
+  feature-0-200316-value:1
+
+How to enable such sensor?
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+By default sensor can be power gated. To enable sysfs attribute "enable" can be
+used::
+
+       $ echo 1 > enable_sensor
+
+Once enabled and powered on, sensor can report value using HID reports.
+These reports are pushed using misc device interface in a FIFO order::
+
+       /dev$ tree | grep HID-SENSOR-2000e1.6.auto
+       │   │   │   ├── 10:53 -> ../HID-SENSOR-2000e1.6.auto
+       │   ├──  HID-SENSOR-2000e1.6.auto
+
+Each reports can be of variable length preceded by a header. This header
+consist of a 32 bit usage id, 64 bit time stamp and 32 bit length field of raw
+data.
diff --git a/Documentation/hid/hid-sensor.txt b/Documentation/hid/hid-sensor.txt
deleted file mode 100644 (file)
index b287752..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-
-HID Sensors Framework
-======================
-HID sensor framework provides necessary interfaces to implement sensor drivers,
-which are connected to a sensor hub. The sensor hub is a HID device and it provides
-a report descriptor conforming to HID 1.12 sensor usage tables.
-
-Description from the HID 1.12 "HID Sensor Usages" specification:
-"Standardization of HID usages for sensors would allow (but not require) sensor
-hardware vendors to provide a consistent Plug And Play interface at the USB boundary,
-thereby enabling some operating systems to incorporate common device drivers that
-could be reused between vendors, alleviating any need for the vendors to provide
-the drivers themselves."
-
-This specification describes many usage IDs, which describe the type of sensor
-and also the individual data fields. Each sensor can have variable number of
-data fields. The length and order is specified in the report descriptor. For
-example a part of report descriptor can look like:
-
-   INPUT(1)[INPUT]
- ..
-    Field(2)
-      Physical(0020.0073)
-      Usage(1)
-        0020.045f
-      Logical Minimum(-32767)
-      Logical Maximum(32767)
-      Report Size(8)
-      Report Count(1)
-      Report Offset(16)
-      Flags(Variable Absolute)
-..
-..
-
-The report is indicating "sensor page (0x20)" contains an accelerometer-3D (0x73).
-This accelerometer-3D has some fields. Here for example field 2 is motion intensity
-(0x045f) with a logical minimum value of -32767 and logical maximum of 32767. The
-order of fields and length of each field is important as the input event raw
-data will use this format.
-
-
-Implementation
-=================
-
-This specification defines many different types of sensors with different sets of
-data fields. It is difficult to have a common input event to user space applications,
-for different sensors. For example an accelerometer can send X,Y and Z data, whereas
-an ambient light sensor can send illumination data.
-So the implementation has two parts:
-- Core hid driver
-- Individual sensor processing part (sensor drivers)
-
-Core driver
------------
-The core driver registers (hid-sensor-hub) registers as a HID driver. It parses
-report descriptors and identifies all the sensors present. It adds an MFD device
-with name HID-SENSOR-xxxx (where xxxx is usage id from the specification).
-For example
-HID-SENSOR-200073 is registered for an Accelerometer 3D driver.
-So if any driver with this name is inserted, then the probe routine for that
-function will be called. So an accelerometer processing driver can register
-with this name and will be probed if there is an accelerometer-3D detected.
-
-The core driver provides a set of APIs which can be used by the processing
-drivers to register and get events for that usage id. Also it provides parsing
-functions, which get and set each input/feature/output report.
-
-Individual sensor processing part (sensor drivers)
------------
-The processing driver will use an interface provided by the core driver to parse
-the report and get the indexes of the fields and also can get events. This driver
-can use IIO interface to use the standard ABI defined for a type of sensor.
-
-
-Core driver Interface
-=====================
-
-Callback structure:
-Each processing driver can use this structure to set some callbacks.
-       int (*suspend)(..): Callback when HID suspend is received
-       int (*resume)(..): Callback when HID resume is received
-       int (*capture_sample)(..): Capture a sample for one of its data fields
-       int (*send_event)(..): One complete event is received which can have
-                               multiple data fields.
-
-Registration functions:
-int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
-                       u32 usage_id,
-                       struct hid_sensor_hub_callbacks *usage_callback):
-
-Registers callbacks for an usage id. The callback functions are not allowed
-to sleep.
-
-
-int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
-                       u32 usage_id):
-
-Removes callbacks for an usage id.
-
-
-Parsing function:
-int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
-                       u8 type,
-                       u32 usage_id, u32 attr_usage_id,
-                       struct hid_sensor_hub_attribute_info *info);
-
-A processing driver can look for some field of interest and check if it exists
-in a report descriptor. If it exists it will store necessary information
-so that fields can be set or get individually.
-These indexes avoid searching every time and getting field index to get or set.
-
-
-Set Feature report
-int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
-                       u32 field_index, s32 value);
-
-This interface is used to set a value for a field in feature report. For example
-if there is a field report_interval, which is parsed by a call to
-sensor_hub_input_get_attribute_info before, then it can directly set that individual
-field.
-
-
-int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
-                       u32 field_index, s32 *value);
-
-This interface is used to get a value for a field in input report. For example
-if there is a field report_interval, which is parsed by a call to
-sensor_hub_input_get_attribute_info before, then it can directly get that individual
-field value.
-
-
-int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
-                       u32 usage_id,
-                       u32 attr_usage_id, u32 report_id);
-
-This is used to get a particular field value through input reports. For example
-accelerometer wants to poll X axis value, then it can call this function with
-the usage id of X axis. HID sensors can provide events, so this is not necessary
-to poll for any field. If there is some new sample, the core driver will call
-registered callback function to process the sample.
-
-
-----------
-
-HID Custom and generic Sensors
-
-HID Sensor specification defines two special sensor usage types. Since they
-don't represent a standard sensor, it is not possible to define using Linux IIO
-type interfaces.
-The purpose of these sensors is to extend the functionality or provide a
-way to obfuscate the data being communicated by a sensor. Without knowing the
-mapping between the data and its encapsulated form, it is difficult for
-an application/driver to determine what data is being communicated by the sensor.
-This allows some differentiating use cases, where vendor can provide applications.
-Some common use cases are debug other sensors or to provide some events like
-keyboard attached/detached or lid open/close.
-
-To allow application to utilize these sensors, here they are exported uses sysfs
-attribute groups, attributes and misc device interface.
-
-An example of this representation on sysfs:
-/sys/devices/pci0000:00/INT33C2:00/i2c-0/i2c-INT33D1:00/0018:8086:09FA.0001/HID-SENSOR-2000e1.6.auto$ tree -R
-.
-????????? enable_sensor
-????????? feature-0-200316
-??????? ????????? feature-0-200316-maximum
-??????? ????????? feature-0-200316-minimum
-??????? ????????? feature-0-200316-name
-??????? ????????? feature-0-200316-size
-??????? ????????? feature-0-200316-unit-expo
-??????? ????????? feature-0-200316-units
-??????? ????????? feature-0-200316-value
-????????? feature-1-200201
-??????? ????????? feature-1-200201-maximum
-??????? ????????? feature-1-200201-minimum
-??????? ????????? feature-1-200201-name
-??????? ????????? feature-1-200201-size
-??????? ????????? feature-1-200201-unit-expo
-??????? ????????? feature-1-200201-units
-??????? ????????? feature-1-200201-value
-????????? input-0-200201
-??????? ????????? input-0-200201-maximum
-??????? ????????? input-0-200201-minimum
-??????? ????????? input-0-200201-name
-??????? ????????? input-0-200201-size
-??????? ????????? input-0-200201-unit-expo
-??????? ????????? input-0-200201-units
-??????? ????????? input-0-200201-value
-????????? input-1-200202
-??????? ????????? input-1-200202-maximum
-??????? ????????? input-1-200202-minimum
-??????? ????????? input-1-200202-name
-??????? ????????? input-1-200202-size
-??????? ????????? input-1-200202-unit-expo
-??????? ????????? input-1-200202-units
-??????? ????????? input-1-200202-value
-
-Here there is a custom sensors with four fields, two feature and two inputs.
-Each field is represented by a set of attributes. All fields except the "value"
-are read only. The value field is a RW field.
-Example
-/sys/bus/platform/devices/HID-SENSOR-2000e1.6.auto/feature-0-200316$ grep -r . *
-feature-0-200316-maximum:6
-feature-0-200316-minimum:0
-feature-0-200316-name:property-reporting-state
-feature-0-200316-size:1
-feature-0-200316-unit-expo:0
-feature-0-200316-units:25
-feature-0-200316-value:1
-
-How to enable such sensor?
-By default sensor can be power gated. To enable sysfs attribute "enable" can be
-used.
-$ echo 1 > enable_sensor
-
-Once enabled and powered on, sensor can report value using HID reports.
-These reports are pushed using misc device interface in a FIFO order.
-/dev$ tree | grep HID-SENSOR-2000e1.6.auto
-??????? ????????? 10:53 -> ../HID-SENSOR-2000e1.6.auto
-????????? HID-SENSOR-2000e1.6.auto
-
-Each reports can be of variable length preceded by a header. This header
-consist of a 32 bit usage id, 64 bit time stamp and 32 bit length field of raw
-data.
diff --git a/Documentation/hid/hid-transport.rst b/Documentation/hid/hid-transport.rst
new file mode 100644 (file)
index 0000000..0fe526f
--- /dev/null
@@ -0,0 +1,359 @@
+=========================
+HID I/O Transport Drivers
+=========================
+
+The HID subsystem is independent of the underlying transport driver. Initially,
+only USB was supported, but other specifications adopted the HID design and
+provided new transport drivers. The kernel includes at least support for USB,
+Bluetooth, I2C and user-space I/O drivers.
+
+1) HID Bus
+==========
+
+The HID subsystem is designed as a bus. Any I/O subsystem may provide HID
+devices and register them with the HID bus. HID core then loads generic device
+drivers on top of it. The transport drivers are responsible of raw data
+transport and device setup/management. HID core is responsible of
+report-parsing, report interpretation and the user-space API. Device specifics
+and quirks are handled by all layers depending on the quirk.
+
+::
+
+ +-----------+  +-----------+            +-----------+  +-----------+
+ | Device #1 |  | Device #i |            | Device #j |  | Device #k |
+ +-----------+  +-----------+            +-----------+  +-----------+
+          \\      //                              \\      //
+        +------------+                          +------------+
+        | I/O Driver |                          | I/O Driver |
+        +------------+                          +------------+
+              ||                                      ||
+     +------------------+                    +------------------+
+     | Transport Driver |                    | Transport Driver |
+     +------------------+                    +------------------+
+                       \___                ___/
+                           \              /
+                          +----------------+
+                          |    HID Core    |
+                          +----------------+
+                           /  |        |  \
+                          /   |        |   \
+             ____________/    |        |    \_________________
+            /                 |        |                      \
+           /                  |        |                       \
+ +----------------+  +-----------+  +------------------+  +------------------+
+ | Generic Driver |  | MT Driver |  | Custom Driver #1 |  | Custom Driver #2 |
+ +----------------+  +-----------+  +------------------+  +------------------+
+
+Example Drivers:
+
+  - I/O: USB, I2C, Bluetooth-l2cap
+  - Transport: USB-HID, I2C-HID, BT-HIDP
+
+Everything below "HID Core" is simplified in this graph as it is only of
+interest to HID device drivers. Transport drivers do not need to know the
+specifics.
+
+1.1) Device Setup
+-----------------
+
+I/O drivers normally provide hotplug detection or device enumeration APIs to the
+transport drivers. Transport drivers use this to find any suitable HID device.
+They allocate HID device objects and register them with HID core. Transport
+drivers are not required to register themselves with HID core. HID core is never
+aware of which transport drivers are available and is not interested in it. It
+is only interested in devices.
+
+Transport drivers attach a constant "struct hid_ll_driver" object with each
+device. Once a device is registered with HID core, the callbacks provided via
+this struct are used by HID core to communicate with the device.
+
+Transport drivers are responsible of detecting device failures and unplugging.
+HID core will operate a device as long as it is registered regardless of any
+device failures. Once transport drivers detect unplug or failure events, they
+must unregister the device from HID core and HID core will stop using the
+provided callbacks.
+
+1.2) Transport Driver Requirements
+----------------------------------
+
+The terms "asynchronous" and "synchronous" in this document describe the
+transmission behavior regarding acknowledgements. An asynchronous channel must
+not perform any synchronous operations like waiting for acknowledgements or
+verifications. Generally, HID calls operating on asynchronous channels must be
+running in atomic-context just fine.
+On the other hand, synchronous channels can be implemented by the transport
+driver in whatever way they like. They might just be the same as asynchronous
+channels, but they can also provide acknowledgement reports, automatic
+retransmission on failure, etc. in a blocking manner. If such functionality is
+required on asynchronous channels, a transport-driver must implement that via
+its own worker threads.
+
+HID core requires transport drivers to follow a given design. A Transport
+driver must provide two bi-directional I/O channels to each HID device. These
+channels must not necessarily be bi-directional in the hardware itself. A
+transport driver might just provide 4 uni-directional channels. Or it might
+multiplex all four on a single physical channel. However, in this document we
+will describe them as two bi-directional channels as they have several
+properties in common.
+
+ - Interrupt Channel (intr): The intr channel is used for asynchronous data
+   reports. No management commands or data acknowledgements are sent on this
+   channel. Any unrequested incoming or outgoing data report must be sent on
+   this channel and is never acknowledged by the remote side. Devices usually
+   send their input events on this channel. Outgoing events are normally
+   not send via intr, except if high throughput is required.
+ - Control Channel (ctrl): The ctrl channel is used for synchronous requests and
+   device management. Unrequested data input events must not be sent on this
+   channel and are normally ignored. Instead, devices only send management
+   events or answers to host requests on this channel.
+   The control-channel is used for direct blocking queries to the device
+   independent of any events on the intr-channel.
+   Outgoing reports are usually sent on the ctrl channel via synchronous
+   SET_REPORT requests.
+
+Communication between devices and HID core is mostly done via HID reports. A
+report can be of one of three types:
+
+ - INPUT Report: Input reports provide data from device to host. This
+   data may include button events, axis events, battery status or more. This
+   data is generated by the device and sent to the host with or without
+   requiring explicit requests. Devices can choose to send data continuously or
+   only on change.
+ - OUTPUT Report: Output reports change device states. They are sent from host
+   to device and may include LED requests, rumble requests or more. Output
+   reports are never sent from device to host, but a host can retrieve their
+   current state.
+   Hosts may choose to send output reports either continuously or only on
+   change.
+ - FEATURE Report: Feature reports are used for specific static device features
+   and never reported spontaneously. A host can read and/or write them to access
+   data like battery-state or device-settings.
+   Feature reports are never sent without requests. A host must explicitly set
+   or retrieve a feature report. This also means, feature reports are never sent
+   on the intr channel as this channel is asynchronous.
+
+INPUT and OUTPUT reports can be sent as pure data reports on the intr channel.
+For INPUT reports this is the usual operational mode. But for OUTPUT reports,
+this is rarely done as OUTPUT reports are normally quite scarce. But devices are
+free to make excessive use of asynchronous OUTPUT reports (for instance, custom
+HID audio speakers make great use of it).
+
+Plain reports must not be sent on the ctrl channel, though. Instead, the ctrl
+channel provides synchronous GET/SET_REPORT requests. Plain reports are only
+allowed on the intr channel and are the only means of data there.
+
+ - GET_REPORT: A GET_REPORT request has a report ID as payload and is sent
+   from host to device. The device must answer with a data report for the
+   requested report ID on the ctrl channel as a synchronous acknowledgement.
+   Only one GET_REPORT request can be pending for each device. This restriction
+   is enforced by HID core as several transport drivers don't allow multiple
+   simultaneous GET_REPORT requests.
+   Note that data reports which are sent as answer to a GET_REPORT request are
+   not handled as generic device events. That is, if a device does not operate
+   in continuous data reporting mode, an answer to GET_REPORT does not replace
+   the raw data report on the intr channel on state change.
+   GET_REPORT is only used by custom HID device drivers to query device state.
+   Normally, HID core caches any device state so this request is not necessary
+   on devices that follow the HID specs except during device initialization to
+   retrieve the current state.
+   GET_REPORT requests can be sent for any of the 3 report types and shall
+   return the current report state of the device. However, OUTPUT reports as
+   payload may be blocked by the underlying transport driver if the
+   specification does not allow them.
+ - SET_REPORT: A SET_REPORT request has a report ID plus data as payload. It is
+   sent from host to device and a device must update it's current report state
+   according to the given data. Any of the 3 report types can be used. However,
+   INPUT reports as payload might be blocked by the underlying transport driver
+   if the specification does not allow them.
+   A device must answer with a synchronous acknowledgement. However, HID core
+   does not require transport drivers to forward this acknowledgement to HID
+   core.
+   Same as for GET_REPORT, only one SET_REPORT can be pending at a time. This
+   restriction is enforced by HID core as some transport drivers do not support
+   multiple synchronous SET_REPORT requests.
+
+Other ctrl-channel requests are supported by USB-HID but are not available
+(or deprecated) in most other transport level specifications:
+
+ - GET/SET_IDLE: Only used by USB-HID and I2C-HID.
+ - GET/SET_PROTOCOL: Not used by HID core.
+ - RESET: Used by I2C-HID, not hooked up in HID core.
+ - SET_POWER: Used by I2C-HID, not hooked up in HID core.
+
+2) HID API
+==========
+
+2.1) Initialization
+-------------------
+
+Transport drivers normally use the following procedure to register a new device
+with HID core::
+
+       struct hid_device *hid;
+       int ret;
+
+       hid = hid_allocate_device();
+       if (IS_ERR(hid)) {
+               ret = PTR_ERR(hid);
+               goto err_<...>;
+       }
+
+       strscpy(hid->name, <device-name-src>, sizeof(hid->name));
+       strscpy(hid->phys, <device-phys-src>, sizeof(hid->phys));
+       strscpy(hid->uniq, <device-uniq-src>, sizeof(hid->uniq));
+
+       hid->ll_driver = &custom_ll_driver;
+       hid->bus = <device-bus>;
+       hid->vendor = <device-vendor>;
+       hid->product = <device-product>;
+       hid->version = <device-version>;
+       hid->country = <device-country>;
+       hid->dev.parent = <pointer-to-parent-device>;
+       hid->driver_data = <transport-driver-data-field>;
+
+       ret = hid_add_device(hid);
+       if (ret)
+               goto err_<...>;
+
+Once hid_add_device() is entered, HID core might use the callbacks provided in
+"custom_ll_driver". Note that fields like "country" can be ignored by underlying
+transport-drivers if not supported.
+
+To unregister a device, use::
+
+       hid_destroy_device(hid);
+
+Once hid_destroy_device() returns, HID core will no longer make use of any
+driver callbacks.
+
+2.2) hid_ll_driver operations
+-----------------------------
+
+The available HID callbacks are:
+
+   ::
+
+      int (*start) (struct hid_device *hdev)
+
+   Called from HID device drivers once they want to use the device. Transport
+   drivers can choose to setup their device in this callback. However, normally
+   devices are already set up before transport drivers register them to HID core
+   so this is mostly only used by USB-HID.
+
+   ::
+
+      void (*stop) (struct hid_device *hdev)
+
+   Called from HID device drivers once they are done with a device. Transport
+   drivers can free any buffers and deinitialize the device. But note that
+   ->start() might be called again if another HID device driver is loaded on the
+   device.
+
+   Transport drivers are free to ignore it and deinitialize devices after they
+   destroyed them via hid_destroy_device().
+
+   ::
+
+      int (*open) (struct hid_device *hdev)
+
+   Called from HID device drivers once they are interested in data reports.
+   Usually, while user-space didn't open any input API/etc., device drivers are
+   not interested in device data and transport drivers can put devices asleep.
+   However, once ->open() is called, transport drivers must be ready for I/O.
+   ->open() calls are nested for each client that opens the HID device.
+
+   ::
+
+      void (*close) (struct hid_device *hdev)
+
+   Called from HID device drivers after ->open() was called but they are no
+   longer interested in device reports. (Usually if user-space closed any input
+   devices of the driver).
+
+   Transport drivers can put devices asleep and terminate any I/O of all
+   ->open() calls have been followed by a ->close() call. However, ->start() may
+   be called again if the device driver is interested in input reports again.
+
+   ::
+
+      int (*parse) (struct hid_device *hdev)
+
+   Called once during device setup after ->start() has been called. Transport
+   drivers must read the HID report-descriptor from the device and tell HID core
+   about it via hid_parse_report().
+
+   ::
+
+      int (*power) (struct hid_device *hdev, int level)
+
+   Called by HID core to give PM hints to transport drivers. Usually this is
+   analogical to the ->open() and ->close() hints and redundant.
+
+   ::
+
+      void (*request) (struct hid_device *hdev, struct hid_report *report,
+                      int reqtype)
+
+   Send an HID request on the ctrl channel. "report" contains the report that
+   should be sent and "reqtype" the request type. Request-type can be
+   HID_REQ_SET_REPORT or HID_REQ_GET_REPORT.
+
+   This callback is optional. If not provided, HID core will assemble a raw
+   report following the HID specs and send it via the ->raw_request() callback.
+   The transport driver is free to implement this asynchronously.
+
+   ::
+
+      int (*wait) (struct hid_device *hdev)
+
+   Used by HID core before calling ->request() again. A transport driver can use
+   it to wait for any pending requests to complete if only one request is
+   allowed at a time.
+
+   ::
+
+      int (*raw_request) (struct hid_device *hdev, unsigned char reportnum,
+                          __u8 *buf, size_t count, unsigned char rtype,
+                          int reqtype)
+
+   Same as ->request() but provides the report as raw buffer. This request shall
+   be synchronous. A transport driver must not use ->wait() to complete such
+   requests. This request is mandatory and hid core will reject the device if
+   it is missing.
+
+   ::
+
+      int (*output_report) (struct hid_device *hdev, __u8 *buf, size_t len)
+
+   Send raw output report via intr channel. Used by some HID device drivers
+   which require high throughput for outgoing requests on the intr channel. This
+   must not cause SET_REPORT calls! This must be implemented as asynchronous
+   output report on the intr channel!
+
+   ::
+
+      int (*idle) (struct hid_device *hdev, int report, int idle, int reqtype)
+
+   Perform SET/GET_IDLE request. Only used by USB-HID, do not implement!
+
+2.3) Data Path
+--------------
+
+Transport drivers are responsible of reading data from I/O devices. They must
+handle any I/O-related state-tracking themselves. HID core does not implement
+protocol handshakes or other management commands which can be required by the
+given HID transport specification.
+
+Every raw data packet read from a device must be fed into HID core via
+hid_input_report(). You must specify the channel-type (intr or ctrl) and report
+type (input/output/feature). Under normal conditions, only input reports are
+provided via this API.
+
+Responses to GET_REPORT requests via ->request() must also be provided via this
+API. Responses to ->raw_request() are synchronous and must be intercepted by the
+transport driver and not passed to hid_input_report().
+Acknowledgements to SET_REPORT requests are not of interest to HID core.
+
+----------------------------------------------------
+
+Written 2013, David Herrmann <dh.herrmann@gmail.com>
diff --git a/Documentation/hid/hid-transport.txt b/Documentation/hid/hid-transport.txt
deleted file mode 100644 (file)
index 4f41d67..0000000
+++ /dev/null
@@ -1,317 +0,0 @@
-                          HID I/O Transport Drivers
-                         ===========================
-
-The HID subsystem is independent of the underlying transport driver. Initially,
-only USB was supported, but other specifications adopted the HID design and
-provided new transport drivers. The kernel includes at least support for USB,
-Bluetooth, I2C and user-space I/O drivers.
-
-1) HID Bus
-==========
-
-The HID subsystem is designed as a bus. Any I/O subsystem may provide HID
-devices and register them with the HID bus. HID core then loads generic device
-drivers on top of it. The transport drivers are responsible of raw data
-transport and device setup/management. HID core is responsible of
-report-parsing, report interpretation and the user-space API. Device specifics
-and quirks are handled by all layers depending on the quirk.
-
- +-----------+  +-----------+            +-----------+  +-----------+
- | Device #1 |  | Device #i |            | Device #j |  | Device #k |
- +-----------+  +-----------+            +-----------+  +-----------+
-          \\      //                              \\      //
-        +------------+                          +------------+
-        | I/O Driver |                          | I/O Driver |
-        +------------+                          +------------+
-              ||                                      ||
-     +------------------+                    +------------------+
-     | Transport Driver |                    | Transport Driver |
-     +------------------+                    +------------------+
-                       \___                ___/
-                           \              /
-                          +----------------+
-                          |    HID Core    |
-                          +----------------+
-                           /  |        |  \
-                          /   |        |   \
-             ____________/    |        |    \_________________
-            /                 |        |                      \
-           /                  |        |                       \
- +----------------+  +-----------+  +------------------+  +------------------+
- | Generic Driver |  | MT Driver |  | Custom Driver #1 |  | Custom Driver #2 |
- +----------------+  +-----------+  +------------------+  +------------------+
-
-Example Drivers:
-  I/O: USB, I2C, Bluetooth-l2cap
-  Transport: USB-HID, I2C-HID, BT-HIDP
-
-Everything below "HID Core" is simplified in this graph as it is only of
-interest to HID device drivers. Transport drivers do not need to know the
-specifics.
-
-1.1) Device Setup
------------------
-
-I/O drivers normally provide hotplug detection or device enumeration APIs to the
-transport drivers. Transport drivers use this to find any suitable HID device.
-They allocate HID device objects and register them with HID core. Transport
-drivers are not required to register themselves with HID core. HID core is never
-aware of which transport drivers are available and is not interested in it. It
-is only interested in devices.
-
-Transport drivers attach a constant "struct hid_ll_driver" object with each
-device. Once a device is registered with HID core, the callbacks provided via
-this struct are used by HID core to communicate with the device.
-
-Transport drivers are responsible of detecting device failures and unplugging.
-HID core will operate a device as long as it is registered regardless of any
-device failures. Once transport drivers detect unplug or failure events, they
-must unregister the device from HID core and HID core will stop using the
-provided callbacks.
-
-1.2) Transport Driver Requirements
-----------------------------------
-
-The terms "asynchronous" and "synchronous" in this document describe the
-transmission behavior regarding acknowledgements. An asynchronous channel must
-not perform any synchronous operations like waiting for acknowledgements or
-verifications. Generally, HID calls operating on asynchronous channels must be
-running in atomic-context just fine.
-On the other hand, synchronous channels can be implemented by the transport
-driver in whatever way they like. They might just be the same as asynchronous
-channels, but they can also provide acknowledgement reports, automatic
-retransmission on failure, etc. in a blocking manner. If such functionality is
-required on asynchronous channels, a transport-driver must implement that via
-its own worker threads.
-
-HID core requires transport drivers to follow a given design. A Transport
-driver must provide two bi-directional I/O channels to each HID device. These
-channels must not necessarily be bi-directional in the hardware itself. A
-transport driver might just provide 4 uni-directional channels. Or it might
-multiplex all four on a single physical channel. However, in this document we
-will describe them as two bi-directional channels as they have several
-properties in common.
-
- - Interrupt Channel (intr): The intr channel is used for asynchronous data
-   reports. No management commands or data acknowledgements are sent on this
-   channel. Any unrequested incoming or outgoing data report must be sent on
-   this channel and is never acknowledged by the remote side. Devices usually
-   send their input events on this channel. Outgoing events are normally
-   not send via intr, except if high throughput is required.
- - Control Channel (ctrl): The ctrl channel is used for synchronous requests and
-   device management. Unrequested data input events must not be sent on this
-   channel and are normally ignored. Instead, devices only send management
-   events or answers to host requests on this channel.
-   The control-channel is used for direct blocking queries to the device
-   independent of any events on the intr-channel.
-   Outgoing reports are usually sent on the ctrl channel via synchronous
-   SET_REPORT requests.
-
-Communication between devices and HID core is mostly done via HID reports. A
-report can be of one of three types:
-
- - INPUT Report: Input reports provide data from device to host. This
-   data may include button events, axis events, battery status or more. This
-   data is generated by the device and sent to the host with or without
-   requiring explicit requests. Devices can choose to send data continuously or
-   only on change.
- - OUTPUT Report: Output reports change device states. They are sent from host
-   to device and may include LED requests, rumble requests or more. Output
-   reports are never sent from device to host, but a host can retrieve their
-   current state.
-   Hosts may choose to send output reports either continuously or only on
-   change.
- - FEATURE Report: Feature reports are used for specific static device features
-   and never reported spontaneously. A host can read and/or write them to access
-   data like battery-state or device-settings.
-   Feature reports are never sent without requests. A host must explicitly set
-   or retrieve a feature report. This also means, feature reports are never sent
-   on the intr channel as this channel is asynchronous.
-
-INPUT and OUTPUT reports can be sent as pure data reports on the intr channel.
-For INPUT reports this is the usual operational mode. But for OUTPUT reports,
-this is rarely done as OUTPUT reports are normally quite scarce. But devices are
-free to make excessive use of asynchronous OUTPUT reports (for instance, custom
-HID audio speakers make great use of it).
-
-Plain reports must not be sent on the ctrl channel, though. Instead, the ctrl
-channel provides synchronous GET/SET_REPORT requests. Plain reports are only
-allowed on the intr channel and are the only means of data there.
-
- - GET_REPORT: A GET_REPORT request has a report ID as payload and is sent
-   from host to device. The device must answer with a data report for the
-   requested report ID on the ctrl channel as a synchronous acknowledgement.
-   Only one GET_REPORT request can be pending for each device. This restriction
-   is enforced by HID core as several transport drivers don't allow multiple
-   simultaneous GET_REPORT requests.
-   Note that data reports which are sent as answer to a GET_REPORT request are
-   not handled as generic device events. That is, if a device does not operate
-   in continuous data reporting mode, an answer to GET_REPORT does not replace
-   the raw data report on the intr channel on state change.
-   GET_REPORT is only used by custom HID device drivers to query device state.
-   Normally, HID core caches any device state so this request is not necessary
-   on devices that follow the HID specs except during device initialization to
-   retrieve the current state.
-   GET_REPORT requests can be sent for any of the 3 report types and shall
-   return the current report state of the device. However, OUTPUT reports as
-   payload may be blocked by the underlying transport driver if the
-   specification does not allow them.
- - SET_REPORT: A SET_REPORT request has a report ID plus data as payload. It is
-   sent from host to device and a device must update it's current report state
-   according to the given data. Any of the 3 report types can be used. However,
-   INPUT reports as payload might be blocked by the underlying transport driver
-   if the specification does not allow them.
-   A device must answer with a synchronous acknowledgement. However, HID core
-   does not require transport drivers to forward this acknowledgement to HID
-   core.
-   Same as for GET_REPORT, only one SET_REPORT can be pending at a time. This
-   restriction is enforced by HID core as some transport drivers do not support
-   multiple synchronous SET_REPORT requests.
-
-Other ctrl-channel requests are supported by USB-HID but are not available
-(or deprecated) in most other transport level specifications:
-
- - GET/SET_IDLE: Only used by USB-HID and I2C-HID.
- - GET/SET_PROTOCOL: Not used by HID core.
- - RESET: Used by I2C-HID, not hooked up in HID core.
- - SET_POWER: Used by I2C-HID, not hooked up in HID core.
-
-2) HID API
-==========
-
-2.1) Initialization
--------------------
-
-Transport drivers normally use the following procedure to register a new device
-with HID core:
-
-       struct hid_device *hid;
-       int ret;
-
-       hid = hid_allocate_device();
-       if (IS_ERR(hid)) {
-               ret = PTR_ERR(hid);
-               goto err_<...>;
-       }
-
-       strscpy(hid->name, <device-name-src>, sizeof(hid->name));
-       strscpy(hid->phys, <device-phys-src>, sizeof(hid->phys));
-       strscpy(hid->uniq, <device-uniq-src>, sizeof(hid->uniq));
-
-       hid->ll_driver = &custom_ll_driver;
-       hid->bus = <device-bus>;
-       hid->vendor = <device-vendor>;
-       hid->product = <device-product>;
-       hid->version = <device-version>;
-       hid->country = <device-country>;
-       hid->dev.parent = <pointer-to-parent-device>;
-       hid->driver_data = <transport-driver-data-field>;
-
-       ret = hid_add_device(hid);
-       if (ret)
-               goto err_<...>;
-
-Once hid_add_device() is entered, HID core might use the callbacks provided in
-"custom_ll_driver". Note that fields like "country" can be ignored by underlying
-transport-drivers if not supported.
-
-To unregister a device, use:
-
-       hid_destroy_device(hid);
-
-Once hid_destroy_device() returns, HID core will no longer make use of any
-driver callbacks.
-
-2.2) hid_ll_driver operations
------------------------------
-
-The available HID callbacks are:
- - int (*start) (struct hid_device *hdev)
-   Called from HID device drivers once they want to use the device. Transport
-   drivers can choose to setup their device in this callback. However, normally
-   devices are already set up before transport drivers register them to HID core
-   so this is mostly only used by USB-HID.
-
- - void (*stop) (struct hid_device *hdev)
-   Called from HID device drivers once they are done with a device. Transport
-   drivers can free any buffers and deinitialize the device. But note that
-   ->start() might be called again if another HID device driver is loaded on the
-   device.
-   Transport drivers are free to ignore it and deinitialize devices after they
-   destroyed them via hid_destroy_device().
-
- - int (*open) (struct hid_device *hdev)
-   Called from HID device drivers once they are interested in data reports.
-   Usually, while user-space didn't open any input API/etc., device drivers are
-   not interested in device data and transport drivers can put devices asleep.
-   However, once ->open() is called, transport drivers must be ready for I/O.
-   ->open() calls are nested for each client that opens the HID device.
-
- - void (*close) (struct hid_device *hdev)
-   Called from HID device drivers after ->open() was called but they are no
-   longer interested in device reports. (Usually if user-space closed any input
-   devices of the driver).
-   Transport drivers can put devices asleep and terminate any I/O of all
-   ->open() calls have been followed by a ->close() call. However, ->start() may
-   be called again if the device driver is interested in input reports again.
-
- - int (*parse) (struct hid_device *hdev)
-   Called once during device setup after ->start() has been called. Transport
-   drivers must read the HID report-descriptor from the device and tell HID core
-   about it via hid_parse_report().
-
- - int (*power) (struct hid_device *hdev, int level)
-   Called by HID core to give PM hints to transport drivers. Usually this is
-   analogical to the ->open() and ->close() hints and redundant.
-
- - void (*request) (struct hid_device *hdev, struct hid_report *report,
-                    int reqtype)
-   Send an HID request on the ctrl channel. "report" contains the report that
-   should be sent and "reqtype" the request type. Request-type can be
-   HID_REQ_SET_REPORT or HID_REQ_GET_REPORT.
-   This callback is optional. If not provided, HID core will assemble a raw
-   report following the HID specs and send it via the ->raw_request() callback.
-   The transport driver is free to implement this asynchronously.
-
- - int (*wait) (struct hid_device *hdev)
-   Used by HID core before calling ->request() again. A transport driver can use
-   it to wait for any pending requests to complete if only one request is
-   allowed at a time.
-
- - int (*raw_request) (struct hid_device *hdev, unsigned char reportnum,
-                       __u8 *buf, size_t count, unsigned char rtype,
-                       int reqtype)
-   Same as ->request() but provides the report as raw buffer. This request shall
-   be synchronous. A transport driver must not use ->wait() to complete such
-   requests. This request is mandatory and hid core will reject the device if
-   it is missing.
-
- - int (*output_report) (struct hid_device *hdev, __u8 *buf, size_t len)
-   Send raw output report via intr channel. Used by some HID device drivers
-   which require high throughput for outgoing requests on the intr channel. This
-   must not cause SET_REPORT calls! This must be implemented as asynchronous
-   output report on the intr channel!
-
- - int (*idle) (struct hid_device *hdev, int report, int idle, int reqtype)
-   Perform SET/GET_IDLE request. Only used by USB-HID, do not implement!
-
-2.3) Data Path
---------------
-
-Transport drivers are responsible of reading data from I/O devices. They must
-handle any I/O-related state-tracking themselves. HID core does not implement
-protocol handshakes or other management commands which can be required by the
-given HID transport specification.
-
-Every raw data packet read from a device must be fed into HID core via
-hid_input_report(). You must specify the channel-type (intr or ctrl) and report
-type (input/output/feature). Under normal conditions, only input reports are
-provided via this API.
-
-Responses to GET_REPORT requests via ->request() must also be provided via this
-API. Responses to ->raw_request() are synchronous and must be intercepted by the
-transport driver and not passed to hid_input_report().
-Acknowledgements to SET_REPORT requests are not of interest to HID core.
-
-----------------------------------------------------
-Written 2013, David Herrmann <dh.herrmann@gmail.com>
diff --git a/Documentation/hid/hiddev.rst b/Documentation/hid/hiddev.rst
new file mode 100644 (file)
index 0000000..209e6ba
--- /dev/null
@@ -0,0 +1,251 @@
+================================================
+Care and feeding of your Human Interface Devices
+================================================
+
+Introduction
+============
+
+In addition to the normal input type HID devices, USB also uses the
+human interface device protocols for things that are not really human
+interfaces, but have similar sorts of communication needs. The two big
+examples for this are power devices (especially uninterruptable power
+supplies) and monitor control on higher end monitors.
+
+To support these disparate requirements, the Linux USB system provides
+HID events to two separate interfaces:
+* the input subsystem, which converts HID events into normal input
+device interfaces (such as keyboard, mouse and joystick) and a
+normalised event interface - see Documentation/input/input.rst
+* the hiddev interface, which provides fairly raw HID events
+
+The data flow for a HID event produced by a device is something like
+the following::
+
+ usb.c ---> hid-core.c  ----> hid-input.c ----> [keyboard/mouse/joystick/event]
+                         |
+                         |
+                          --> hiddev.c ----> POWER / MONITOR CONTROL
+
+In addition, other subsystems (apart from USB) can potentially feed
+events into the input subsystem, but these have no effect on the hid
+device interface.
+
+Using the HID Device Interface
+==============================
+
+The hiddev interface is a char interface using the normal USB major,
+with the minor numbers starting at 96 and finishing at 111. Therefore,
+you need the following commands::
+
+       mknod /dev/usb/hiddev0 c 180 96
+       mknod /dev/usb/hiddev1 c 180 97
+       mknod /dev/usb/hiddev2 c 180 98
+       mknod /dev/usb/hiddev3 c 180 99
+       mknod /dev/usb/hiddev4 c 180 100
+       mknod /dev/usb/hiddev5 c 180 101
+       mknod /dev/usb/hiddev6 c 180 102
+       mknod /dev/usb/hiddev7 c 180 103
+       mknod /dev/usb/hiddev8 c 180 104
+       mknod /dev/usb/hiddev9 c 180 105
+       mknod /dev/usb/hiddev10 c 180 106
+       mknod /dev/usb/hiddev11 c 180 107
+       mknod /dev/usb/hiddev12 c 180 108
+       mknod /dev/usb/hiddev13 c 180 109
+       mknod /dev/usb/hiddev14 c 180 110
+       mknod /dev/usb/hiddev15 c 180 111
+
+So you point your hiddev compliant user-space program at the correct
+interface for your device, and it all just works.
+
+Assuming that you have a hiddev compliant user-space program, of
+course. If you need to write one, read on.
+
+
+The HIDDEV API
+==============
+
+This description should be read in conjunction with the HID
+specification, freely available from http://www.usb.org, and
+conveniently linked of http://www.linux-usb.org.
+
+The hiddev API uses a read() interface, and a set of ioctl() calls.
+
+HID devices exchange data with the host computer using data
+bundles called "reports".  Each report is divided into "fields",
+each of which can have one or more "usages".  In the hid-core,
+each one of these usages has a single signed 32 bit value.
+
+read():
+-------
+
+This is the event interface.  When the HID device's state changes,
+it performs an interrupt transfer containing a report which contains
+the changed value.  The hid-core.c module parses the report, and
+returns to hiddev.c the individual usages that have changed within
+the report.  In its basic mode, the hiddev will make these individual
+usage changes available to the reader using a struct hiddev_event::
+
+       struct hiddev_event {
+           unsigned hid;
+           signed int value;
+       };
+
+containing the HID usage identifier for the status that changed, and
+the value that it was changed to. Note that the structure is defined
+within <linux/hiddev.h>, along with some other useful #defines and
+structures.  The HID usage identifier is a composite of the HID usage
+page shifted to the 16 high order bits ORed with the usage code.  The
+behavior of the read() function can be modified using the HIDIOCSFLAG
+ioctl() described below.
+
+
+ioctl():
+--------
+
+This is the control interface. There are a number of controls:
+
+HIDIOCGVERSION
+  - int (read)
+
+ Gets the version code out of the hiddev driver.
+
+HIDIOCAPPLICATION
+  - (none)
+
+This ioctl call returns the HID application usage associated with the
+hid device. The third argument to ioctl() specifies which application
+index to get. This is useful when the device has more than one
+application collection. If the index is invalid (greater or equal to
+the number of application collections this device has) the ioctl
+returns -1. You can find out beforehand how many application
+collections the device has from the num_applications field from the
+hiddev_devinfo structure.
+
+HIDIOCGCOLLECTIONINFO
+  - struct hiddev_collection_info (read/write)
+
+This returns a superset of the information above, providing not only
+application collections, but all the collections the device has.  It
+also returns the level the collection lives in the hierarchy.
+The user passes in a hiddev_collection_info struct with the index
+field set to the index that should be returned.  The ioctl fills in
+the other fields.  If the index is larger than the last collection
+index, the ioctl returns -1 and sets errno to -EINVAL.
+
+HIDIOCGDEVINFO
+  - struct hiddev_devinfo (read)
+
+Gets a hiddev_devinfo structure which describes the device.
+
+HIDIOCGSTRING
+  - struct hiddev_string_descriptor (read/write)
+
+Gets a string descriptor from the device. The caller must fill in the
+"index" field to indicate which descriptor should be returned.
+
+HIDIOCINITREPORT
+  - (none)
+
+Instructs the kernel to retrieve all input and feature report values
+from the device. At this point, all the usage structures will contain
+current values for the device, and will maintain it as the device
+changes.  Note that the use of this ioctl is unnecessary in general,
+since later kernels automatically initialize the reports from the
+device at attach time.
+
+HIDIOCGNAME
+  - string (variable length)
+
+Gets the device name
+
+HIDIOCGREPORT
+  - struct hiddev_report_info (write)
+
+Instructs the kernel to get a feature or input report from the device,
+in order to selectively update the usage structures (in contrast to
+INITREPORT).
+
+HIDIOCSREPORT
+  - struct hiddev_report_info (write)
+
+Instructs the kernel to send a report to the device. This report can
+be filled in by the user through HIDIOCSUSAGE calls (below) to fill in
+individual usage values in the report before sending the report in full
+to the device.
+
+HIDIOCGREPORTINFO
+  - struct hiddev_report_info (read/write)
+
+Fills in a hiddev_report_info structure for the user. The report is
+looked up by type (input, output or feature) and id, so these fields
+must be filled in by the user. The ID can be absolute -- the actual
+report id as reported by the device -- or relative --
+HID_REPORT_ID_FIRST for the first report, and (HID_REPORT_ID_NEXT |
+report_id) for the next report after report_id. Without a-priori
+information about report ids, the right way to use this ioctl is to
+use the relative IDs above to enumerate the valid IDs. The ioctl
+returns non-zero when there is no more next ID. The real report ID is
+filled into the returned hiddev_report_info structure.
+
+HIDIOCGFIELDINFO
+  - struct hiddev_field_info (read/write)
+
+Returns the field information associated with a report in a
+hiddev_field_info structure. The user must fill in report_id and
+report_type in this structure, as above. The field_index should also
+be filled in, which should be a number from 0 and maxfield-1, as
+returned from a previous HIDIOCGREPORTINFO call.
+
+HIDIOCGUCODE
+  - struct hiddev_usage_ref (read/write)
+
+Returns the usage_code in a hiddev_usage_ref structure, given that
+given its report type, report id, field index, and index within the
+field have already been filled into the structure.
+
+HIDIOCGUSAGE
+  - struct hiddev_usage_ref (read/write)
+
+Returns the value of a usage in a hiddev_usage_ref structure. The
+usage to be retrieved can be specified as above, or the user can
+choose to fill in the report_type field and specify the report_id as
+HID_REPORT_ID_UNKNOWN. In this case, the hiddev_usage_ref will be
+filled in with the report and field information associated with this
+usage if it is found.
+
+HIDIOCSUSAGE
+  - struct hiddev_usage_ref (write)
+
+Sets the value of a usage in an output report.  The user fills in
+the hiddev_usage_ref structure as above, but additionally fills in
+the value field.
+
+HIDIOGCOLLECTIONINDEX
+  - struct hiddev_usage_ref (write)
+
+Returns the collection index associated with this usage.  This
+indicates where in the collection hierarchy this usage sits.
+
+HIDIOCGFLAG
+  - int (read)
+HIDIOCSFLAG
+  - int (write)
+
+These operations respectively inspect and replace the mode flags
+that influence the read() call above.  The flags are as follows:
+
+    HIDDEV_FLAG_UREF
+      - read() calls will now return
+        struct hiddev_usage_ref instead of struct hiddev_event.
+        This is a larger structure, but in situations where the
+        device has more than one usage in its reports with the
+        same usage code, this mode serves to resolve such
+        ambiguity.
+
+    HIDDEV_FLAG_REPORT
+      - This flag can only be used in conjunction
+        with HIDDEV_FLAG_UREF.  With this flag set, when the device
+        sends a report, a struct hiddev_usage_ref will be returned
+        to read() filled in with the report_type and report_id, but
+        with field_index set to FIELD_INDEX_NONE.  This serves as
+        additional notification when the device has sent a report.
diff --git a/Documentation/hid/hiddev.txt b/Documentation/hid/hiddev.txt
deleted file mode 100644 (file)
index 6384487..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-Care and feeding of your Human Interface Devices
-
-INTRODUCTION
-
-In addition to the normal input type HID devices, USB also uses the
-human interface device protocols for things that are not really human
-interfaces, but have similar sorts of communication needs. The two big
-examples for this are power devices (especially uninterruptable power
-supplies) and monitor control on higher end monitors.
-
-To support these disparate requirements, the Linux USB system provides
-HID events to two separate interfaces:
-* the input subsystem, which converts HID events into normal input
-device interfaces (such as keyboard, mouse and joystick) and a
-normalised event interface - see Documentation/input/input.rst
-* the hiddev interface, which provides fairly raw HID events
-
-The data flow for a HID event produced by a device is something like
-the following :
-
- usb.c ---> hid-core.c  ----> hid-input.c ----> [keyboard/mouse/joystick/event]
-                         |
-                         |
-                          --> hiddev.c ----> POWER / MONITOR CONTROL 
-
-In addition, other subsystems (apart from USB) can potentially feed
-events into the input subsystem, but these have no effect on the hid
-device interface.
-
-USING THE HID DEVICE INTERFACE
-
-The hiddev interface is a char interface using the normal USB major,
-with the minor numbers starting at 96 and finishing at 111. Therefore,
-you need the following commands:
-mknod /dev/usb/hiddev0 c 180 96
-mknod /dev/usb/hiddev1 c 180 97
-mknod /dev/usb/hiddev2 c 180 98
-mknod /dev/usb/hiddev3 c 180 99
-mknod /dev/usb/hiddev4 c 180 100
-mknod /dev/usb/hiddev5 c 180 101
-mknod /dev/usb/hiddev6 c 180 102
-mknod /dev/usb/hiddev7 c 180 103
-mknod /dev/usb/hiddev8 c 180 104
-mknod /dev/usb/hiddev9 c 180 105
-mknod /dev/usb/hiddev10 c 180 106
-mknod /dev/usb/hiddev11 c 180 107
-mknod /dev/usb/hiddev12 c 180 108
-mknod /dev/usb/hiddev13 c 180 109
-mknod /dev/usb/hiddev14 c 180 110
-mknod /dev/usb/hiddev15 c 180 111
-
-So you point your hiddev compliant user-space program at the correct
-interface for your device, and it all just works.
-
-Assuming that you have a hiddev compliant user-space program, of
-course. If you need to write one, read on.
-
-
-THE HIDDEV API
-This description should be read in conjunction with the HID
-specification, freely available from http://www.usb.org, and
-conveniently linked of http://www.linux-usb.org.
-
-The hiddev API uses a read() interface, and a set of ioctl() calls.
-
-HID devices exchange data with the host computer using data
-bundles called "reports".  Each report is divided into "fields",
-each of which can have one or more "usages".  In the hid-core,
-each one of these usages has a single signed 32 bit value.
-
-read():
-This is the event interface.  When the HID device's state changes,
-it performs an interrupt transfer containing a report which contains
-the changed value.  The hid-core.c module parses the report, and
-returns to hiddev.c the individual usages that have changed within
-the report.  In its basic mode, the hiddev will make these individual
-usage changes available to the reader using a struct hiddev_event:
-
-       struct hiddev_event {
-           unsigned hid;
-           signed int value;
-       };
-
-containing the HID usage identifier for the status that changed, and
-the value that it was changed to. Note that the structure is defined
-within <linux/hiddev.h>, along with some other useful #defines and
-structures.  The HID usage identifier is a composite of the HID usage
-page shifted to the 16 high order bits ORed with the usage code.  The
-behavior of the read() function can be modified using the HIDIOCSFLAG
-ioctl() described below.
-
-
-ioctl(): 
-This is the control interface. There are a number of controls: 
-
-HIDIOCGVERSION - int (read)
-Gets the version code out of the hiddev driver.
-
-HIDIOCAPPLICATION - (none)
-This ioctl call returns the HID application usage associated with the
-hid device. The third argument to ioctl() specifies which application
-index to get. This is useful when the device has more than one
-application collection. If the index is invalid (greater or equal to
-the number of application collections this device has) the ioctl
-returns -1. You can find out beforehand how many application
-collections the device has from the num_applications field from the
-hiddev_devinfo structure. 
-
-HIDIOCGCOLLECTIONINFO - struct hiddev_collection_info (read/write)
-This returns a superset of the information above, providing not only
-application collections, but all the collections the device has.  It
-also returns the level the collection lives in the hierarchy.
-The user passes in a hiddev_collection_info struct with the index 
-field set to the index that should be returned.  The ioctl fills in 
-the other fields.  If the index is larger than the last collection 
-index, the ioctl returns -1 and sets errno to -EINVAL.
-
-HIDIOCGDEVINFO - struct hiddev_devinfo (read)
-Gets a hiddev_devinfo structure which describes the device.
-
-HIDIOCGSTRING - struct hiddev_string_descriptor (read/write)
-Gets a string descriptor from the device. The caller must fill in the
-"index" field to indicate which descriptor should be returned.
-
-HIDIOCINITREPORT - (none)
-Instructs the kernel to retrieve all input and feature report values
-from the device. At this point, all the usage structures will contain
-current values for the device, and will maintain it as the device
-changes.  Note that the use of this ioctl is unnecessary in general,
-since later kernels automatically initialize the reports from the
-device at attach time.
-
-HIDIOCGNAME - string (variable length)
-Gets the device name
-
-HIDIOCGREPORT - struct hiddev_report_info (write)
-Instructs the kernel to get a feature or input report from the device,
-in order to selectively update the usage structures (in contrast to
-INITREPORT).
-
-HIDIOCSREPORT - struct hiddev_report_info (write)
-Instructs the kernel to send a report to the device. This report can
-be filled in by the user through HIDIOCSUSAGE calls (below) to fill in
-individual usage values in the report before sending the report in full
-to the device. 
-
-HIDIOCGREPORTINFO - struct hiddev_report_info (read/write)
-Fills in a hiddev_report_info structure for the user. The report is
-looked up by type (input, output or feature) and id, so these fields
-must be filled in by the user. The ID can be absolute -- the actual
-report id as reported by the device -- or relative --
-HID_REPORT_ID_FIRST for the first report, and (HID_REPORT_ID_NEXT |
-report_id) for the next report after report_id. Without a-priori
-information about report ids, the right way to use this ioctl is to
-use the relative IDs above to enumerate the valid IDs. The ioctl
-returns non-zero when there is no more next ID. The real report ID is
-filled into the returned hiddev_report_info structure. 
-
-HIDIOCGFIELDINFO - struct hiddev_field_info (read/write)
-Returns the field information associated with a report in a
-hiddev_field_info structure. The user must fill in report_id and
-report_type in this structure, as above. The field_index should also
-be filled in, which should be a number from 0 and maxfield-1, as
-returned from a previous HIDIOCGREPORTINFO call. 
-
-HIDIOCGUCODE - struct hiddev_usage_ref (read/write)
-Returns the usage_code in a hiddev_usage_ref structure, given that
-given its report type, report id, field index, and index within the
-field have already been filled into the structure.
-
-HIDIOCGUSAGE - struct hiddev_usage_ref (read/write)
-Returns the value of a usage in a hiddev_usage_ref structure. The
-usage to be retrieved can be specified as above, or the user can
-choose to fill in the report_type field and specify the report_id as
-HID_REPORT_ID_UNKNOWN. In this case, the hiddev_usage_ref will be
-filled in with the report and field information associated with this
-usage if it is found. 
-
-HIDIOCSUSAGE - struct hiddev_usage_ref (write)
-Sets the value of a usage in an output report.  The user fills in
-the hiddev_usage_ref structure as above, but additionally fills in
-the value field.
-
-HIDIOGCOLLECTIONINDEX - struct hiddev_usage_ref (write)
-Returns the collection index associated with this usage.  This
-indicates where in the collection hierarchy this usage sits.
-
-HIDIOCGFLAG - int (read)
-HIDIOCSFLAG - int (write)
-These operations respectively inspect and replace the mode flags
-that influence the read() call above.  The flags are as follows:
-
-    HIDDEV_FLAG_UREF - read() calls will now return 
-        struct hiddev_usage_ref instead of struct hiddev_event.
-        This is a larger structure, but in situations where the
-        device has more than one usage in its reports with the
-        same usage code, this mode serves to resolve such
-        ambiguity.
-
-    HIDDEV_FLAG_REPORT - This flag can only be used in conjunction
-        with HIDDEV_FLAG_UREF.  With this flag set, when the device
-        sends a report, a struct hiddev_usage_ref will be returned
-        to read() filled in with the report_type and report_id, but 
-        with field_index set to FIELD_INDEX_NONE.  This serves as
-        additional notification when the device has sent a report.
diff --git a/Documentation/hid/hidraw.rst b/Documentation/hid/hidraw.rst
new file mode 100644 (file)
index 0000000..4a4a0ba
--- /dev/null
@@ -0,0 +1,138 @@
+================================================================
+HIDRAW - Raw Access to USB and Bluetooth Human Interface Devices
+================================================================
+
+The hidraw driver provides a raw interface to USB and Bluetooth Human
+Interface Devices (HIDs).  It differs from hiddev in that reports sent and
+received are not parsed by the HID parser, but are sent to and received from
+the device unmodified.
+
+Hidraw should be used if the userspace application knows exactly how to
+communicate with the hardware device, and is able to construct the HID
+reports manually.  This is often the case when making userspace drivers for
+custom HID devices.
+
+Hidraw is also useful for communicating with non-conformant HID devices
+which send and receive data in a way that is inconsistent with their report
+descriptors.  Because hiddev parses reports which are sent and received
+through it, checking them against the device's report descriptor, such
+communication with these non-conformant devices is impossible using hiddev.
+Hidraw is the only alternative, short of writing a custom kernel driver, for
+these non-conformant devices.
+
+A benefit of hidraw is that its use by userspace applications is independent
+of the underlying hardware type.  Currently, Hidraw is implemented for USB
+and Bluetooth.  In the future, as new hardware bus types are developed which
+use the HID specification, hidraw will be expanded to add support for these
+new bus types.
+
+Hidraw uses a dynamic major number, meaning that udev should be relied on to
+create hidraw device nodes.  Udev will typically create the device nodes
+directly under /dev (eg: /dev/hidraw0).  As this location is distribution-
+and udev rule-dependent, applications should use libudev to locate hidraw
+devices attached to the system.  There is a tutorial on libudev with a
+working example at:
+
+       http://www.signal11.us/oss/udev/
+
+The HIDRAW API
+---------------
+
+read()
+-------
+read() will read a queued report received from the HID device. On USB
+devices, the reports read using read() are the reports sent from the device
+on the INTERRUPT IN endpoint.  By default, read() will block until there is
+a report available to be read.  read() can be made non-blocking, by passing
+the O_NONBLOCK flag to open(), or by setting the O_NONBLOCK flag using
+fcntl().
+
+On a device which uses numbered reports, the first byte of the returned data
+will be the report number; the report data follows, beginning in the second
+byte.  For devices which do not use numbered reports, the report data
+will begin at the first byte.
+
+write()
+-------
+The write() function will write a report to the device. For USB devices, if
+the device has an INTERRUPT OUT endpoint, the report will be sent on that
+endpoint. If it does not, the report will be sent over the control endpoint,
+using a SET_REPORT transfer.
+
+The first byte of the buffer passed to write() should be set to the report
+number.  If the device does not use numbered reports, the first byte should
+be set to 0. The report data itself should begin at the second byte.
+
+ioctl()
+-------
+Hidraw supports the following ioctls:
+
+HIDIOCGRDESCSIZE:
+       Get Report Descriptor Size
+
+This ioctl will get the size of the device's report descriptor.
+
+HIDIOCGRDESC:
+       Get Report Descriptor
+
+This ioctl returns the device's report descriptor using a
+hidraw_report_descriptor struct.  Make sure to set the size field of the
+hidraw_report_descriptor struct to the size returned from HIDIOCGRDESCSIZE.
+
+HIDIOCGRAWINFO:
+       Get Raw Info
+
+This ioctl will return a hidraw_devinfo struct containing the bus type, the
+vendor ID (VID), and product ID (PID) of the device. The bus type can be one
+of::
+
+       - BUS_USB
+       - BUS_HIL
+       - BUS_BLUETOOTH
+       - BUS_VIRTUAL
+
+which are defined in uapi/linux/input.h.
+
+HIDIOCGRAWNAME(len):
+       Get Raw Name
+
+This ioctl returns a string containing the vendor and product strings of
+the device.  The returned string is Unicode, UTF-8 encoded.
+
+HIDIOCGRAWPHYS(len):
+       Get Physical Address
+
+This ioctl returns a string representing the physical address of the device.
+For USB devices, the string contains the physical path to the device (the
+USB controller, hubs, ports, etc).  For Bluetooth devices, the string
+contains the hardware (MAC) address of the device.
+
+HIDIOCSFEATURE(len):
+       Send a Feature Report
+
+This ioctl will send a feature report to the device.  Per the HID
+specification, feature reports are always sent using the control endpoint.
+Set the first byte of the supplied buffer to the report number.  For devices
+which do not use numbered reports, set the first byte to 0. The report data
+begins in the second byte. Make sure to set len accordingly, to one more
+than the length of the report (to account for the report number).
+
+HIDIOCGFEATURE(len):
+       Get a Feature Report
+
+This ioctl will request a feature report from the device using the control
+endpoint.  The first byte of the supplied buffer should be set to the report
+number of the requested report.  For devices which do not use numbered
+reports, set the first byte to 0.  The report will be returned starting at
+the first byte of the buffer (ie: the report number is not returned).
+
+Example
+-------
+In samples/, find hid-example.c, which shows examples of read(), write(),
+and all the ioctls for hidraw.  The code may be used by anyone for any
+purpose, and can serve as a starting point for developing applications using
+hidraw.
+
+Document by:
+
+       Alan Ott <alan@signal11.us>, Signal 11 Software
diff --git a/Documentation/hid/hidraw.txt b/Documentation/hid/hidraw.txt
deleted file mode 100644 (file)
index c8436e3..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-      HIDRAW - Raw Access to USB and Bluetooth Human Interface Devices
-     ==================================================================
-
-The hidraw driver provides a raw interface to USB and Bluetooth Human
-Interface Devices (HIDs).  It differs from hiddev in that reports sent and
-received are not parsed by the HID parser, but are sent to and received from
-the device unmodified.
-
-Hidraw should be used if the userspace application knows exactly how to
-communicate with the hardware device, and is able to construct the HID
-reports manually.  This is often the case when making userspace drivers for
-custom HID devices.
-
-Hidraw is also useful for communicating with non-conformant HID devices
-which send and receive data in a way that is inconsistent with their report
-descriptors.  Because hiddev parses reports which are sent and received
-through it, checking them against the device's report descriptor, such
-communication with these non-conformant devices is impossible using hiddev.
-Hidraw is the only alternative, short of writing a custom kernel driver, for
-these non-conformant devices.
-
-A benefit of hidraw is that its use by userspace applications is independent
-of the underlying hardware type.  Currently, Hidraw is implemented for USB
-and Bluetooth.  In the future, as new hardware bus types are developed which
-use the HID specification, hidraw will be expanded to add support for these
-new bus types.
-
-Hidraw uses a dynamic major number, meaning that udev should be relied on to
-create hidraw device nodes.  Udev will typically create the device nodes
-directly under /dev (eg: /dev/hidraw0).  As this location is distribution-
-and udev rule-dependent, applications should use libudev to locate hidraw
-devices attached to the system.  There is a tutorial on libudev with a
-working example at:
-       http://www.signal11.us/oss/udev/
-
-The HIDRAW API
----------------
-
-read()
--------
-read() will read a queued report received from the HID device. On USB
-devices, the reports read using read() are the reports sent from the device
-on the INTERRUPT IN endpoint.  By default, read() will block until there is
-a report available to be read.  read() can be made non-blocking, by passing
-the O_NONBLOCK flag to open(), or by setting the O_NONBLOCK flag using
-fcntl().
-
-On a device which uses numbered reports, the first byte of the returned data
-will be the report number; the report data follows, beginning in the second
-byte.  For devices which do not use numbered reports, the report data
-will begin at the first byte.
-
-write()
---------
-The write() function will write a report to the device. For USB devices, if
-the device has an INTERRUPT OUT endpoint, the report will be sent on that
-endpoint. If it does not, the report will be sent over the control endpoint,
-using a SET_REPORT transfer.
-
-The first byte of the buffer passed to write() should be set to the report
-number.  If the device does not use numbered reports, the first byte should
-be set to 0. The report data itself should begin at the second byte.
-
-ioctl()
---------
-Hidraw supports the following ioctls:
-
-HIDIOCGRDESCSIZE: Get Report Descriptor Size
-This ioctl will get the size of the device's report descriptor.
-
-HIDIOCGRDESC: Get Report Descriptor
-This ioctl returns the device's report descriptor using a
-hidraw_report_descriptor struct.  Make sure to set the size field of the
-hidraw_report_descriptor struct to the size returned from HIDIOCGRDESCSIZE.
-
-HIDIOCGRAWINFO: Get Raw Info
-This ioctl will return a hidraw_devinfo struct containing the bus type, the
-vendor ID (VID), and product ID (PID) of the device. The bus type can be one
-of:
-       BUS_USB
-       BUS_HIL
-       BUS_BLUETOOTH
-       BUS_VIRTUAL
-which are defined in uapi/linux/input.h.
-
-HIDIOCGRAWNAME(len): Get Raw Name
-This ioctl returns a string containing the vendor and product strings of
-the device.  The returned string is Unicode, UTF-8 encoded.
-
-HIDIOCGRAWPHYS(len): Get Physical Address
-This ioctl returns a string representing the physical address of the device.
-For USB devices, the string contains the physical path to the device (the
-USB controller, hubs, ports, etc).  For Bluetooth devices, the string
-contains the hardware (MAC) address of the device.
-
-HIDIOCSFEATURE(len): Send a Feature Report
-This ioctl will send a feature report to the device.  Per the HID
-specification, feature reports are always sent using the control endpoint.
-Set the first byte of the supplied buffer to the report number.  For devices
-which do not use numbered reports, set the first byte to 0. The report data
-begins in the second byte. Make sure to set len accordingly, to one more
-than the length of the report (to account for the report number).
-
-HIDIOCGFEATURE(len): Get a Feature Report
-This ioctl will request a feature report from the device using the control
-endpoint.  The first byte of the supplied buffer should be set to the report
-number of the requested report.  For devices which do not use numbered
-reports, set the first byte to 0.  The report will be returned starting at
-the first byte of the buffer (ie: the report number is not returned).
-
-Example
----------
-In samples/, find hid-example.c, which shows examples of read(), write(),
-and all the ioctls for hidraw.  The code may be used by anyone for any
-purpose, and can serve as a starting point for developing applications using
-hidraw.
-
-Document by:
-       Alan Ott <alan@signal11.us>, Signal 11 Software
diff --git a/Documentation/hid/index.rst b/Documentation/hid/index.rst
new file mode 100644 (file)
index 0000000..af43249
--- /dev/null
@@ -0,0 +1,18 @@
+:orphan:
+
+=============================
+Human Interface Devices (HID)
+=============================
+
+.. toctree::
+   :maxdepth: 1
+
+   hiddev
+   hidraw
+   hid-sensor
+   hid-transport
+
+   uhid
+
+   hid-alps
+   intel-ish-hid
diff --git a/Documentation/hid/intel-ish-hid.rst b/Documentation/hid/intel-ish-hid.rst
new file mode 100644 (file)
index 0000000..cccbf4b
--- /dev/null
@@ -0,0 +1,485 @@
+=================================
+Intel Integrated Sensor Hub (ISH)
+=================================
+
+A sensor hub enables the ability to offload sensor polling and algorithm
+processing to a dedicated low power co-processor. This allows the core
+processor to go into low power modes more often, resulting in the increased
+battery life.
+
+There are many vendors providing external sensor hubs confirming to HID
+Sensor usage tables, and used in several tablets, 2 in 1 convertible laptops
+and embedded products. Linux had this support since Linux 3.9.
+
+Intel® introduced integrated sensor hubs as a part of the SoC starting from
+Cherry Trail and now supported on multiple generations of CPU packages. There
+are many commercial devices already shipped with Integrated Sensor Hubs (ISH).
+These ISH also comply to HID sensor specification, but the  difference is the
+transport protocol used for communication. The current external sensor hubs
+mainly use HID over i2C or USB. But ISH doesn't use either i2c or USB.
+
+1. Overview
+===========
+
+Using a analogy with a usbhid implementation, the ISH follows a similar model
+for a very high speed communication::
+
+       -----------------               ----------------------
+       |    USB HID    |       -->     |    ISH HID         |
+       -----------------               ----------------------
+       -----------------               ----------------------
+       |  USB protocol |       -->     |    ISH Transport   |
+       -----------------               ----------------------
+       -----------------               ----------------------
+       |  EHCI/XHCI    |       -->     |    ISH IPC         |
+       -----------------               ----------------------
+             PCI                                PCI
+       -----------------               ----------------------
+        |Host controller|      -->     |    ISH processor   |
+       -----------------               ----------------------
+            USB Link
+       -----------------               ----------------------
+       | USB End points|       -->     |    ISH Clients     |
+       -----------------               ----------------------
+
+Like USB protocol provides a method for device enumeration, link management
+and user data encapsulation, the ISH also provides similar services. But it is
+very light weight tailored to manage and communicate with ISH client
+applications implemented in the firmware.
+
+The ISH allows multiple sensor management applications executing in the
+firmware. Like USB endpoints the messaging can be to/from a client. As part of
+enumeration process, these clients are identified. These clients can be simple
+HID sensor applications, sensor calibration application or senor firmware
+update application.
+
+The implementation model is similar, like USB bus, ISH transport is also
+implemented as a bus. Each client application executing in the ISH processor
+is registered as a device on this bus. The driver, which binds each device
+(ISH HID driver) identifies the device type and registers with the hid core.
+
+2. ISH Implementation: Block Diagram
+====================================
+
+::
+
+        ---------------------------
+       |  User Space Applications  |
+        ---------------------------
+
+  ----------------IIO ABI----------------
+        --------------------------
+       |  IIO Sensor Drivers     |
+        --------------------------
+        --------------------------
+       |        IIO core         |
+        --------------------------
+        --------------------------
+       |   HID Sensor Hub MFD    |
+        --------------------------
+        --------------------------
+       |       HID Core          |
+        --------------------------
+        --------------------------
+       |   HID over ISH Client   |
+        --------------------------
+        --------------------------
+       |   ISH Transport (ISHTP) |
+        --------------------------
+        --------------------------
+       |      IPC Drivers        |
+        --------------------------
+  OS
+  ---------------- PCI -----------------
+  Hardware + Firmware
+        ----------------------------
+       | ISH Hardware/Firmware(FW) |
+        ----------------------------
+
+3. High level processing in above blocks
+========================================
+
+3.1 Hardware Interface
+----------------------
+
+The ISH is exposed as "Non-VGA unclassified PCI device" to the host. The PCI
+product and vendor IDs are changed from different generations of processors. So
+the source code which enumerate drivers needs to update from generation to
+generation.
+
+3.2 Inter Processor Communication (IPC) driver
+----------------------------------------------
+
+Location: drivers/hid/intel-ish-hid/ipc
+
+The IPC message used memory mapped I/O. The registers are defined in
+hw-ish-regs.h.
+
+3.2.1 IPC/FW message types
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+There are two types of messages, one for management of link and other messages
+are to and from transport layers.
+
+TX and RX of Transport messages
+...............................
+
+A set of memory mapped register offers support of multi byte messages TX and
+RX (E.g.IPC_REG_ISH2HOST_MSG, IPC_REG_HOST2ISH_MSG). The IPC layer maintains
+internal queues to sequence messages and send them in order to the FW.
+Optionally the caller can register handler to get notification of completion.
+A door bell mechanism is used in messaging to trigger processing in host and
+client firmware side. When ISH interrupt handler is called, the ISH2HOST
+doorbell register is used by host drivers to determine that the interrupt
+is for ISH.
+
+Each side has 32 32-bit message registers and a 32-bit doorbell. Doorbell
+register has the following format:
+Bits 0..6: fragment length (7 bits are used)
+Bits 10..13: encapsulated protocol
+Bits 16..19: management command (for IPC management protocol)
+Bit 31: doorbell trigger (signal H/W interrupt to the other side)
+Other bits are reserved, should be 0.
+
+3.2.2 Transport layer interface
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To abstract HW level IPC communication, a set of callbacks are registered.
+The transport layer uses them to send and receive messages.
+Refer to  struct ishtp_hw_ops for callbacks.
+
+3.3 ISH Transport layer
+-----------------------
+
+Location: drivers/hid/intel-ish-hid/ishtp/
+
+3.3.1 A Generic Transport Layer
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The transport layer is a bi-directional protocol, which defines:
+- Set of commands to start, stop, connect, disconnect and flow control
+(ishtp/hbm.h) for details
+- A flow control mechanism to avoid buffer overflows
+
+This protocol resembles bus messages described in the following document:
+http://www.intel.com/content/dam/www/public/us/en/documents/technical-\
+specifications/dcmi-hi-1-0-spec.pdf "Chapter 7: Bus Message Layer"
+
+3.3.2 Connection and Flow Control Mechanism
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Each FW client and a protocol is identified by an UUID. In order to communicate
+to a FW client, a connection must be established using connect request and
+response bus messages. If successful, a pair (host_client_id and fw_client_id)
+will identify the connection.
+
+Once connection is established, peers send each other flow control bus messages
+independently. Every peer may send a message only if it has received a
+flow-control credit before. Once it sent a message, it may not send another one
+before receiving the next flow control credit.
+Either side can send disconnect request bus message to end communication. Also
+the link will be dropped if major FW reset occurs.
+
+3.3.3 Peer to Peer data transfer
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Peer to Peer data transfer can happen with or without using DMA. Depending on
+the sensor bandwidth requirement DMA can be enabled by using module parameter
+ishtp_use_dma under intel_ishtp.
+
+Each side (host and FW) manages its DMA transfer memory independently. When an
+ISHTP client from either host or FW side wants to send something, it decides
+whether to send over IPC or over DMA; for each transfer the decision is
+independent. The sending side sends DMA_XFER message when the message is in
+the respective host buffer (TX when host client sends, RX when FW client
+sends). The recipient of DMA message responds with DMA_XFER_ACK, indicating
+the sender that the memory region for that message may be reused.
+
+DMA initialization is started with host sending DMA_ALLOC_NOTIFY bus message
+(that includes RX buffer) and FW responds with DMA_ALLOC_NOTIFY_ACK.
+Additionally to DMA address communication, this sequence checks capabilities:
+if thw host doesn't support DMA, then it won't send DMA allocation, so FW can't
+send DMA; if FW doesn't support DMA then it won't respond with
+DMA_ALLOC_NOTIFY_ACK, in which case host will not use DMA transfers.
+Here ISH acts as busmaster DMA controller. Hence when host sends DMA_XFER,
+it's request to do host->ISH DMA transfer; when FW sends DMA_XFER, it means
+that it already did DMA and the message resides at host. Thus, DMA_XFER
+and DMA_XFER_ACK act as ownership indicators.
+
+At initial state all outgoing memory belongs to the sender (TX to host, RX to
+FW), DMA_XFER transfers ownership on the region that contains ISHTP message to
+the receiving side, DMA_XFER_ACK returns ownership to the sender. A sender
+needs not wait for previous DMA_XFER to be ack'ed, and may send another message
+as long as remaining continuous memory in its ownership is enough.
+In principle, multiple DMA_XFER and DMA_XFER_ACK messages may be sent at once
+(up to IPC MTU), thus allowing for interrupt throttling.
+Currently, ISH FW decides to send over DMA if ISHTP message is more than 3 IPC
+fragments and via IPC otherwise.
+
+3.3.4 Ring Buffers
+^^^^^^^^^^^^^^^^^^
+
+When a client initiate a connection, a ring or RX and TX buffers are allocated.
+The size of ring can be specified by the client. HID client set 16 and 32 for
+TX and RX buffers respectively. On send request from client, the data to be
+sent is copied to one of the send ring buffer and scheduled to be sent using
+bus message protocol. These buffers are required because the FW may have not
+have processed the last message and may not have enough flow control credits
+to send. Same thing holds true on receive side and flow control is required.
+
+3.3.5 Host Enumeration
+^^^^^^^^^^^^^^^^^^^^^^
+
+The host enumeration bus command allow discovery of clients present in the FW.
+There can be multiple sensor clients and clients for calibration function.
+
+To ease in implantation and allow independent driver handle each client
+this transport layer takes advantage of Linux Bus driver model. Each
+client is registered as device on the the transport bus (ishtp bus).
+
+Enumeration sequence of messages:
+
+- Host sends HOST_START_REQ_CMD, indicating that host ISHTP layer is up.
+- FW responds with HOST_START_RES_CMD
+- Host sends HOST_ENUM_REQ_CMD (enumerate FW clients)
+- FW responds with HOST_ENUM_RES_CMD that includes bitmap of available FW
+  client IDs
+- For each FW ID found in that bitmap host sends
+  HOST_CLIENT_PROPERTIES_REQ_CMD
+- FW responds with HOST_CLIENT_PROPERTIES_RES_CMD. Properties include UUID,
+  max ISHTP message size, etc.
+- Once host received properties for that last discovered client, it considers
+  ISHTP device fully functional (and allocates DMA buffers)
+
+3.4 HID over ISH Client
+-----------------------
+
+Location: drivers/hid/intel-ish-hid
+
+The ISHTP client driver is responsible for:
+
+- enumerate HID devices under FW ISH client
+- Get Report descriptor
+- Register with HID core as a LL driver
+- Process Get/Set feature request
+- Get input reports
+
+3.5 HID Sensor Hub MFD and IIO sensor drivers
+---------------------------------------------
+
+The functionality in these drivers is the same as an external sensor hub.
+Refer to
+Documentation/hid/hid-sensor.rst for HID sensor
+Documentation/ABI/testing/sysfs-bus-iio for IIO ABIs to user space
+
+3.6 End to End HID transport Sequence Diagram
+---------------------------------------------
+
+::
+
+  HID-ISH-CLN                    ISHTP                    IPC                             HW
+          |                        |                       |                               |
+          |                        |                       |-----WAKE UP------------------>|
+          |                        |                       |                               |
+          |                        |                       |-----HOST READY--------------->|
+          |                        |                       |                               |
+          |                        |                       |<----MNG_RESET_NOTIFY_ACK----- |
+          |                        |                       |                               |
+          |                        |<----ISHTP_START------ |                               |
+          |                        |                       |                               |
+          |                        |<-----------------HOST_START_RES_CMD-------------------|
+          |                        |                       |                               |
+          |                        |------------------QUERY_SUBSCRIBER-------------------->|
+          |                        |                       |                               |
+          |                        |------------------HOST_ENUM_REQ_CMD------------------->|
+          |                        |                       |                               |
+          |                        |<-----------------HOST_ENUM_RES_CMD--------------------|
+          |                        |                       |                               |
+          |                        |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
+          |                        |                       |                               |
+          |                        |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
+          |       Create new device on in ishtp bus        |                               |
+          |                        |                       |                               |
+          |                        |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
+          |                        |                       |                               |
+          |                        |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
+          |       Create new device on in ishtp bus        |                               |
+          |                        |                       |                               |
+          |                        |--Repeat HOST_CLIENT_PROPERTIES_REQ_CMD-till last one--|
+          |                        |                       |                               |
+       probed()
+          |----ishtp_cl_connect--->|----------------- CLIENT_CONNECT_REQ_CMD-------------->|
+          |                        |                       |                               |
+          |                        |<----------------CLIENT_CONNECT_RES_CMD----------------|
+          |                        |                       |                               |
+          |register event callback |                       |                               |
+          |                        |                       |                               |
+          |ishtp_cl_send(
+          HOSTIF_DM_ENUM_DEVICES)  |----------fill ishtp_msg_hdr struct write to HW-----  >|
+          |                        |                       |                               |
+          |                        |                       |<-----IRQ(IPC_PROTOCOL_ISHTP---|
+          |                        |                       |                               |
+          |<--ENUM_DEVICE RSP------|                       |                               |
+          |                        |                       |                               |
+  for each enumerated device
+          |ishtp_cl_send(
+          HOSTIF_GET_HID_DESCRIPTOR|----------fill ishtp_msg_hdr struct write to HW-----  >|
+          |                        |                       |                               |
+          ...Response
+          |                        |                       |                               |
+  for each enumerated device
+          |ishtp_cl_send(
+       HOSTIF_GET_REPORT_DESCRIPTOR|--------------fill ishtp_msg_hdr struct write to HW-- >|
+          |                        |                       |                               |
+          |                        |                       |                               |
+   hid_allocate_device
+          |                        |                       |                               |
+   hid_add_device                  |                       |                               |
+          |                        |                       |                               |
+
+
+3.7 ISH Debugging
+-----------------
+
+To debug ISH, event tracing mechanism is used. To enable debug logs
+echo 1 > /sys/kernel/debug/tracing/events/intel_ish/enable
+cat sys/kernel/debug/tracing/trace
+
+3.8 ISH IIO sysfs Example on Lenovo thinkpad Yoga 260
+-----------------------------------------------------
+
+::
+
+  root@otcpl-ThinkPad-Yoga-260:~# tree -l /sys/bus/iio/devices/
+  /sys/bus/iio/devices/
+  ├── iio:device0 -> ../../../devices/0044:8086:22D8.0001/HID-SENSOR-200073.9.auto/iio:device0
+  │   ├── buffer
+  │   │   ├── enable
+  │   │   ├── length
+  │   │   └── watermark
+  ...
+  │   ├── in_accel_hysteresis
+  │   ├── in_accel_offset
+  │   ├── in_accel_sampling_frequency
+  │   ├── in_accel_scale
+  │   ├── in_accel_x_raw
+  │   ├── in_accel_y_raw
+  │   ├── in_accel_z_raw
+  │   ├── name
+  │   ├── scan_elements
+  │   │   ├── in_accel_x_en
+  │   │   ├── in_accel_x_index
+  │   │   ├── in_accel_x_type
+  │   │   ├── in_accel_y_en
+  │   │   ├── in_accel_y_index
+  │   │   ├── in_accel_y_type
+  │   │   ├── in_accel_z_en
+  │   │   ├── in_accel_z_index
+  │   │   └── in_accel_z_type
+  ...
+  │   │   ├── devices
+  │   │   │   │   ├── buffer
+  │   │   │   │   │   ├── enable
+  │   │   │   │   │   ├── length
+  │   │   │   │   │   └── watermark
+  │   │   │   │   ├── dev
+  │   │   │   │   ├── in_intensity_both_raw
+  │   │   │   │   ├── in_intensity_hysteresis
+  │   │   │   │   ├── in_intensity_offset
+  │   │   │   │   ├── in_intensity_sampling_frequency
+  │   │   │   │   ├── in_intensity_scale
+  │   │   │   │   ├── name
+  │   │   │   │   ├── scan_elements
+  │   │   │   │   │   ├── in_intensity_both_en
+  │   │   │   │   │   ├── in_intensity_both_index
+  │   │   │   │   │   └── in_intensity_both_type
+  │   │   │   │   ├── trigger
+  │   │   │   │   │   └── current_trigger
+  ...
+  │   │   │   │   ├── buffer
+  │   │   │   │   │   ├── enable
+  │   │   │   │   │   ├── length
+  │   │   │   │   │   └── watermark
+  │   │   │   │   ├── dev
+  │   │   │   │   ├── in_magn_hysteresis
+  │   │   │   │   ├── in_magn_offset
+  │   │   │   │   ├── in_magn_sampling_frequency
+  │   │   │   │   ├── in_magn_scale
+  │   │   │   │   ├── in_magn_x_raw
+  │   │   │   │   ├── in_magn_y_raw
+  │   │   │   │   ├── in_magn_z_raw
+  │   │   │   │   ├── in_rot_from_north_magnetic_tilt_comp_raw
+  │   │   │   │   ├── in_rot_hysteresis
+  │   │   │   │   ├── in_rot_offset
+  │   │   │   │   ├── in_rot_sampling_frequency
+  │   │   │   │   ├── in_rot_scale
+  │   │   │   │   ├── name
+  ...
+  │   │   │   │   ├── scan_elements
+  │   │   │   │   │   ├── in_magn_x_en
+  │   │   │   │   │   ├── in_magn_x_index
+  │   │   │   │   │   ├── in_magn_x_type
+  │   │   │   │   │   ├── in_magn_y_en
+  │   │   │   │   │   ├── in_magn_y_index
+  │   │   │   │   │   ├── in_magn_y_type
+  │   │   │   │   │   ├── in_magn_z_en
+  │   │   │   │   │   ├── in_magn_z_index
+  │   │   │   │   │   ├── in_magn_z_type
+  │   │   │   │   │   ├── in_rot_from_north_magnetic_tilt_comp_en
+  │   │   │   │   │   ├── in_rot_from_north_magnetic_tilt_comp_index
+  │   │   │   │   │   └── in_rot_from_north_magnetic_tilt_comp_type
+  │   │   │   │   ├── trigger
+  │   │   │   │   │   └── current_trigger
+  ...
+  │   │   │   │   ├── buffer
+  │   │   │   │   │   ├── enable
+  │   │   │   │   │   ├── length
+  │   │   │   │   │   └── watermark
+  │   │   │   │   ├── dev
+  │   │   │   │   ├── in_anglvel_hysteresis
+  │   │   │   │   ├── in_anglvel_offset
+  │   │   │   │   ├── in_anglvel_sampling_frequency
+  │   │   │   │   ├── in_anglvel_scale
+  │   │   │   │   ├── in_anglvel_x_raw
+  │   │   │   │   ├── in_anglvel_y_raw
+  │   │   │   │   ├── in_anglvel_z_raw
+  │   │   │   │   ├── name
+  │   │   │   │   ├── scan_elements
+  │   │   │   │   │   ├── in_anglvel_x_en
+  │   │   │   │   │   ├── in_anglvel_x_index
+  │   │   │   │   │   ├── in_anglvel_x_type
+  │   │   │   │   │   ├── in_anglvel_y_en
+  │   │   │   │   │   ├── in_anglvel_y_index
+  │   │   │   │   │   ├── in_anglvel_y_type
+  │   │   │   │   │   ├── in_anglvel_z_en
+  │   │   │   │   │   ├── in_anglvel_z_index
+  │   │   │   │   │   └── in_anglvel_z_type
+  │   │   │   │   ├── trigger
+  │   │   │   │   │   └── current_trigger
+  ...
+  │   │   │   │   ├── buffer
+  │   │   │   │   │   ├── enable
+  │   │   │   │   │   ├── length
+  │   │   │   │   │   └── watermark
+  │   │   │   │   ├── dev
+  │   │   │   │   ├── in_anglvel_hysteresis
+  │   │   │   │   ├── in_anglvel_offset
+  │   │   │   │   ├── in_anglvel_sampling_frequency
+  │   │   │   │   ├── in_anglvel_scale
+  │   │   │   │   ├── in_anglvel_x_raw
+  │   │   │   │   ├── in_anglvel_y_raw
+  │   │   │   │   ├── in_anglvel_z_raw
+  │   │   │   │   ├── name
+  │   │   │   │   ├── scan_elements
+  │   │   │   │   │   ├── in_anglvel_x_en
+  │   │   │   │   │   ├── in_anglvel_x_index
+  │   │   │   │   │   ├── in_anglvel_x_type
+  │   │   │   │   │   ├── in_anglvel_y_en
+  │   │   │   │   │   ├── in_anglvel_y_index
+  │   │   │   │   │   ├── in_anglvel_y_type
+  │   │   │   │   │   ├── in_anglvel_z_en
+  │   │   │   │   │   ├── in_anglvel_z_index
+  │   │   │   │   │   └── in_anglvel_z_type
+  │   │   │   │   ├── trigger
+  │   │   │   │   │   └── current_trigger
+  ...
diff --git a/Documentation/hid/intel-ish-hid.txt b/Documentation/hid/intel-ish-hid.txt
deleted file mode 100644 (file)
index d48b21c..0000000
+++ /dev/null
@@ -1,454 +0,0 @@
-Intel Integrated Sensor Hub (ISH)
-===============================
-
-A sensor hub enables the ability to offload sensor polling and algorithm
-processing to a dedicated low power co-processor. This allows the core
-processor to go into low power modes more often, resulting in the increased
-battery life.
-
-There are many vendors providing external sensor hubs confirming to HID
-Sensor usage tables, and used in several tablets, 2 in 1 convertible laptops
-and embedded products. Linux had this support since Linux 3.9.
-
-Intel® introduced integrated sensor hubs as a part of the SoC starting from
-Cherry Trail and now supported on multiple generations of CPU packages. There
-are many commercial devices already shipped with Integrated Sensor Hubs (ISH).
-These ISH also comply to HID sensor specification, but the  difference is the
-transport protocol used for communication. The current external sensor hubs
-mainly use HID over i2C or USB. But ISH doesn't use either i2c or USB.
-
-1. Overview
-
-Using a analogy with a usbhid implementation, the ISH follows a similar model
-for a very high speed communication:
-
-       -----------------               ----------------------
-       |    USB HID    |       -->     |    ISH HID         |
-       -----------------               ----------------------
-       -----------------               ----------------------
-       |  USB protocol |       -->     |    ISH Transport   |
-       -----------------               ----------------------
-       -----------------               ----------------------
-       |  EHCI/XHCI    |       -->     |    ISH IPC         |
-       -----------------               ----------------------
-             PCI                                PCI
-       -----------------               ----------------------
-        |Host controller|      -->     |    ISH processor   |
-       -----------------               ----------------------
-            USB Link
-       -----------------               ----------------------
-       | USB End points|       -->     |    ISH Clients     |
-       -----------------               ----------------------
-
-Like USB protocol provides a method for device enumeration, link management
-and user data encapsulation, the ISH also provides similar services. But it is
-very light weight tailored to manage and communicate with ISH client
-applications implemented in the firmware.
-
-The ISH allows multiple sensor management applications executing in the
-firmware. Like USB endpoints the messaging can be to/from a client. As part of
-enumeration process, these clients are identified. These clients can be simple
-HID sensor applications, sensor calibration application or senor firmware
-update application.
-
-The implementation model is similar, like USB bus, ISH transport is also
-implemented as a bus. Each client application executing in the ISH processor
-is registered as a device on this bus. The driver, which binds each device
-(ISH HID driver) identifies the device type and registers with the hid core.
-
-2. ISH Implementation: Block Diagram
-
-        ---------------------------
-       |  User Space Applications  |
-        ---------------------------
-
-----------------IIO ABI----------------
-        --------------------------
-       |  IIO Sensor Drivers     |
-        --------------------------
-        --------------------------
-       |        IIO core         |
-        --------------------------
-        --------------------------
-       |   HID Sensor Hub MFD    |
-        --------------------------
-        --------------------------
-       |       HID Core          |
-        --------------------------
-        --------------------------
-       |   HID over ISH Client   |
-        --------------------------
-        --------------------------
-       |   ISH Transport (ISHTP) |
-        --------------------------
-        --------------------------
-       |      IPC Drivers        |
-        --------------------------
-OS
-----------------   PCI -----------------
-Hardware + Firmware
-        ----------------------------
-       | ISH Hardware/Firmware(FW) |
-        ----------------------------
-
-3. High level processing in above blocks
-
-3.1 Hardware Interface
-
-The ISH is exposed as "Non-VGA unclassified PCI device" to the host. The PCI
-product and vendor IDs are changed from different generations of processors. So
-the source code which enumerate drivers needs to update from generation to
-generation.
-
-3.2 Inter Processor Communication (IPC) driver
-Location: drivers/hid/intel-ish-hid/ipc
-
-The IPC message used memory mapped I/O. The registers are defined in
-hw-ish-regs.h.
-
-3.2.1 IPC/FW message types
-
-There are two types of messages, one for management of link and other messages
-are to and from transport layers.
-
-TX and RX of Transport messages
-
-A set of memory mapped register offers support of multi byte messages TX and
-RX (E.g.IPC_REG_ISH2HOST_MSG, IPC_REG_HOST2ISH_MSG). The IPC layer maintains
-internal queues to sequence messages and send them in order to the FW.
-Optionally the caller can register handler to get notification of completion.
-A door bell mechanism is used in messaging to trigger processing in host and
-client firmware side. When ISH interrupt handler is called, the ISH2HOST
-doorbell register is used by host drivers to determine that the interrupt
-is for ISH.
-
-Each side has 32 32-bit message registers and a 32-bit doorbell. Doorbell
-register has the following format:
-Bits 0..6: fragment length (7 bits are used)
-Bits 10..13: encapsulated protocol
-Bits 16..19: management command (for IPC management protocol)
-Bit 31: doorbell trigger (signal H/W interrupt to the other side)
-Other bits are reserved, should be 0.
-
-3.2.2 Transport layer interface
-
-To abstract HW level IPC communication, a set of callbacks are registered.
-The transport layer uses them to send and receive messages.
-Refer to  struct ishtp_hw_ops for callbacks.
-
-3.3 ISH Transport layer
-Location: drivers/hid/intel-ish-hid/ishtp/
-
-3.3.1 A Generic Transport Layer
-
-The transport layer is a bi-directional protocol, which defines:
-- Set of commands to start, stop, connect, disconnect and flow control
-(ishtp/hbm.h) for details
-- A flow control mechanism to avoid buffer overflows
-
-This protocol resembles bus messages described in the following document:
-http://www.intel.com/content/dam/www/public/us/en/documents/technical-\
-specifications/dcmi-hi-1-0-spec.pdf "Chapter 7: Bus Message Layer"
-
-3.3.2 Connection and Flow Control Mechanism
-
-Each FW client and a protocol is identified by an UUID. In order to communicate
-to a FW client, a connection must be established using connect request and
-response bus messages. If successful, a pair (host_client_id and fw_client_id)
-will identify the connection.
-
-Once connection is established, peers send each other flow control bus messages
-independently. Every peer may send a message only if it has received a
-flow-control credit before. Once it sent a message, it may not send another one
-before receiving the next flow control credit.
-Either side can send disconnect request bus message to end communication. Also
-the link will be dropped if major FW reset occurs.
-
-3.3.3 Peer to Peer data transfer
-
-Peer to Peer data transfer can happen with or without using DMA. Depending on
-the sensor bandwidth requirement DMA can be enabled by using module parameter
-ishtp_use_dma under intel_ishtp.
-
-Each side (host and FW) manages its DMA transfer memory independently. When an
-ISHTP client from either host or FW side wants to send something, it decides
-whether to send over IPC or over DMA; for each transfer the decision is
-independent. The sending side sends DMA_XFER message when the message is in
-the respective host buffer (TX when host client sends, RX when FW client
-sends). The recipient of DMA message responds with DMA_XFER_ACK, indicating
-the sender that the memory region for that message may be reused.
-
-DMA initialization is started with host sending DMA_ALLOC_NOTIFY bus message
-(that includes RX buffer) and FW responds with DMA_ALLOC_NOTIFY_ACK.
-Additionally to DMA address communication, this sequence checks capabilities:
-if thw host doesn't support DMA, then it won't send DMA allocation, so FW can't
-send DMA; if FW doesn't support DMA then it won't respond with
-DMA_ALLOC_NOTIFY_ACK, in which case host will not use DMA transfers.
-Here ISH acts as busmaster DMA controller. Hence when host sends DMA_XFER,
-it's request to do host->ISH DMA transfer; when FW sends DMA_XFER, it means
-that it already did DMA and the message resides at host. Thus, DMA_XFER
-and DMA_XFER_ACK act as ownership indicators.
-
-At initial state all outgoing memory belongs to the sender (TX to host, RX to
-FW), DMA_XFER transfers ownership on the region that contains ISHTP message to
-the receiving side, DMA_XFER_ACK returns ownership to the sender. A sender
-needs not wait for previous DMA_XFER to be ack'ed, and may send another message
-as long as remaining continuous memory in its ownership is enough.
-In principle, multiple DMA_XFER and DMA_XFER_ACK messages may be sent at once
-(up to IPC MTU), thus allowing for interrupt throttling.
-Currently, ISH FW decides to send over DMA if ISHTP message is more than 3 IPC
-fragments and via IPC otherwise.
-
-3.3.4 Ring Buffers
-
-When a client initiate a connection, a ring or RX and TX buffers are allocated.
-The size of ring can be specified by the client. HID client set 16 and 32 for
-TX and RX buffers respectively. On send request from client, the data to be
-sent is copied to one of the send ring buffer and scheduled to be sent using
-bus message protocol. These buffers are required because the FW may have not
-have processed the last message and may not have enough flow control credits
-to send. Same thing holds true on receive side and flow control is required.
-
-3.3.5 Host Enumeration
-
-The host enumeration bus command allow discovery of clients present in the FW.
-There can be multiple sensor clients and clients for calibration function.
-
-To ease in implantation and allow independent driver handle each client
-this transport layer takes advantage of Linux Bus driver model. Each
-client is registered as device on the the transport bus (ishtp bus).
-
-Enumeration sequence of messages:
-- Host sends HOST_START_REQ_CMD, indicating that host ISHTP layer is up.
-- FW responds with HOST_START_RES_CMD
-- Host sends HOST_ENUM_REQ_CMD (enumerate FW clients)
-- FW responds with HOST_ENUM_RES_CMD that includes bitmap of available FW
-client IDs
-- For each FW ID found in that bitmap host sends
-HOST_CLIENT_PROPERTIES_REQ_CMD
-- FW responds with HOST_CLIENT_PROPERTIES_RES_CMD. Properties include UUID,
-max ISHTP message size, etc.
-- Once host received properties for that last discovered client, it considers
-ISHTP device fully functional (and allocates DMA buffers)
-
-3.4 HID over ISH Client
-Location: drivers/hid/intel-ish-hid
-
-The ISHTP client driver is responsible for:
-- enumerate HID devices under FW ISH client
-- Get Report descriptor
-- Register with HID core as a LL driver
-- Process Get/Set feature request
-- Get input reports
-
-3.5 HID Sensor Hub MFD and IIO sensor drivers
-
-The functionality in these drivers is the same as an external sensor hub.
-Refer to
-Documentation/hid/hid-sensor.txt for HID sensor
-Documentation/ABI/testing/sysfs-bus-iio for IIO ABIs to user space
-
-3.6 End to End HID transport Sequence Diagram
-
-HID-ISH-CLN                    ISHTP                   IPC                             HW
-       |                       |                       |                               |
-       |                       |                       |-----WAKE UP------------------>|
-       |                       |                       |                               |
-       |                       |                       |-----HOST READY--------------->|
-       |                       |                       |                               |
-       |                       |                       |<----MNG_RESET_NOTIFY_ACK----- |
-       |                       |                       |                               |
-       |                       |<----ISHTP_START------ |                               |
-       |                       |                       |                               |
-       |                       |<-----------------HOST_START_RES_CMD-------------------|
-       |                       |                       |                               |
-       |                       |------------------QUERY_SUBSCRIBER-------------------->|
-       |                       |                       |                               |
-       |                       |------------------HOST_ENUM_REQ_CMD------------------->|
-       |                       |                       |                               |
-       |                       |<-----------------HOST_ENUM_RES_CMD--------------------|
-       |                       |                       |                               |
-       |                       |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
-       |                       |                       |                               |
-       |                       |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
-       |       Create new device on in ishtp bus       |                               |
-       |                       |                       |                               |
-       |                       |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
-       |                       |                       |                               |
-       |                       |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
-       |       Create new device on in ishtp bus       |                               |
-       |                       |                       |                               |
-       |                       |--Repeat HOST_CLIENT_PROPERTIES_REQ_CMD-till last one--|
-       |                       |                       |                               |
-     probed()
-       |----ishtp_cl_connect-->|----------------- CLIENT_CONNECT_REQ_CMD-------------->|
-       |                       |                       |                               |
-       |                       |<----------------CLIENT_CONNECT_RES_CMD----------------|
-       |                       |                       |                               |
-       |register event callback|                       |                               |
-       |                       |                       |                               |
-       |ishtp_cl_send(
-       HOSTIF_DM_ENUM_DEVICES) |----------fill ishtp_msg_hdr struct write to HW-----  >|
-       |                       |                       |                               |
-       |                       |                       |<-----IRQ(IPC_PROTOCOL_ISHTP---|
-       |                       |                       |                               |
-       |<--ENUM_DEVICE RSP-----|                       |                               |
-       |                       |                       |                               |
-for each enumerated device
-       |ishtp_cl_send(
-       HOSTIF_GET_HID_DESCRIPTOR |----------fill ishtp_msg_hdr struct write to HW---  >|
-       |                       |                       |                               |
-       ...Response
-       |                       |                       |                               |
-for each enumerated device
-       |ishtp_cl_send(
-       HOSTIF_GET_REPORT_DESCRIPTOR |----------fill ishtp_msg_hdr struct write to HW- >|
-       |                       |                       |                               |
-       |                       |                       |                               |
- hid_allocate_device
-       |                       |                       |                               |
- hid_add_device                        |                       |                               |
-       |                       |                       |                               |
-
-
-3.7 ISH Debugging
-
-To debug ISH, event tracing mechanism is used. To enable debug logs
-echo 1 > /sys/kernel/debug/tracing/events/intel_ish/enable
-cat sys/kernel/debug/tracing/trace
-
-3.8 ISH IIO sysfs Example on Lenovo thinkpad Yoga 260
-
-root@otcpl-ThinkPad-Yoga-260:~# tree -l /sys/bus/iio/devices/
-/sys/bus/iio/devices/
-├── iio:device0 -> ../../../devices/0044:8086:22D8.0001/HID-SENSOR-200073.9.auto/iio:device0
-│   ├── buffer
-│   │   ├── enable
-│   │   ├── length
-│   │   └── watermark
-...
-│   ├── in_accel_hysteresis
-│   ├── in_accel_offset
-│   ├── in_accel_sampling_frequency
-│   ├── in_accel_scale
-│   ├── in_accel_x_raw
-│   ├── in_accel_y_raw
-│   ├── in_accel_z_raw
-│   ├── name
-│   ├── scan_elements
-│   │   ├── in_accel_x_en
-│   │   ├── in_accel_x_index
-│   │   ├── in_accel_x_type
-│   │   ├── in_accel_y_en
-│   │   ├── in_accel_y_index
-│   │   ├── in_accel_y_type
-│   │   ├── in_accel_z_en
-│   │   ├── in_accel_z_index
-│   │   └── in_accel_z_type
-...
-│   │   ├── devices
-│   │   │   │   ├── buffer
-│   │   │   │   │   ├── enable
-│   │   │   │   │   ├── length
-│   │   │   │   │   └── watermark
-│   │   │   │   ├── dev
-│   │   │   │   ├── in_intensity_both_raw
-│   │   │   │   ├── in_intensity_hysteresis
-│   │   │   │   ├── in_intensity_offset
-│   │   │   │   ├── in_intensity_sampling_frequency
-│   │   │   │   ├── in_intensity_scale
-│   │   │   │   ├── name
-│   │   │   │   ├── scan_elements
-│   │   │   │   │   ├── in_intensity_both_en
-│   │   │   │   │   ├── in_intensity_both_index
-│   │   │   │   │   └── in_intensity_both_type
-│   │   │   │   ├── trigger
-│   │   │   │   │   └── current_trigger
-...
-│   │   │   │   ├── buffer
-│   │   │   │   │   ├── enable
-│   │   │   │   │   ├── length
-│   │   │   │   │   └── watermark
-│   │   │   │   ├── dev
-│   │   │   │   ├── in_magn_hysteresis
-│   │   │   │   ├── in_magn_offset
-│   │   │   │   ├── in_magn_sampling_frequency
-│   │   │   │   ├── in_magn_scale
-│   │   │   │   ├── in_magn_x_raw
-│   │   │   │   ├── in_magn_y_raw
-│   │   │   │   ├── in_magn_z_raw
-│   │   │   │   ├── in_rot_from_north_magnetic_tilt_comp_raw
-│   │   │   │   ├── in_rot_hysteresis
-│   │   │   │   ├── in_rot_offset
-│   │   │   │   ├── in_rot_sampling_frequency
-│   │   │   │   ├── in_rot_scale
-│   │   │   │   ├── name
-...
-│   │   │   │   ├── scan_elements
-│   │   │   │   │   ├── in_magn_x_en
-│   │   │   │   │   ├── in_magn_x_index
-│   │   │   │   │   ├── in_magn_x_type
-│   │   │   │   │   ├── in_magn_y_en
-│   │   │   │   │   ├── in_magn_y_index
-│   │   │   │   │   ├── in_magn_y_type
-│   │   │   │   │   ├── in_magn_z_en
-│   │   │   │   │   ├── in_magn_z_index
-│   │   │   │   │   ├── in_magn_z_type
-│   │   │   │   │   ├── in_rot_from_north_magnetic_tilt_comp_en
-│   │   │   │   │   ├── in_rot_from_north_magnetic_tilt_comp_index
-│   │   │   │   │   └── in_rot_from_north_magnetic_tilt_comp_type
-│   │   │   │   ├── trigger
-│   │   │   │   │   └── current_trigger
-...
-│   │   │   │   ├── buffer
-│   │   │   │   │   ├── enable
-│   │   │   │   │   ├── length
-│   │   │   │   │   └── watermark
-│   │   │   │   ├── dev
-│   │   │   │   ├── in_anglvel_hysteresis
-│   │   │   │   ├── in_anglvel_offset
-│   │   │   │   ├── in_anglvel_sampling_frequency
-│   │   │   │   ├── in_anglvel_scale
-│   │   │   │   ├── in_anglvel_x_raw
-│   │   │   │   ├── in_anglvel_y_raw
-│   │   │   │   ├── in_anglvel_z_raw
-│   │   │   │   ├── name
-│   │   │   │   ├── scan_elements
-│   │   │   │   │   ├── in_anglvel_x_en
-│   │   │   │   │   ├── in_anglvel_x_index
-│   │   │   │   │   ├── in_anglvel_x_type
-│   │   │   │   │   ├── in_anglvel_y_en
-│   │   │   │   │   ├── in_anglvel_y_index
-│   │   │   │   │   ├── in_anglvel_y_type
-│   │   │   │   │   ├── in_anglvel_z_en
-│   │   │   │   │   ├── in_anglvel_z_index
-│   │   │   │   │   └── in_anglvel_z_type
-│   │   │   │   ├── trigger
-│   │   │   │   │   └── current_trigger
-...
-│   │   │   │   ├── buffer
-│   │   │   │   │   ├── enable
-│   │   │   │   │   ├── length
-│   │   │   │   │   └── watermark
-│   │   │   │   ├── dev
-│   │   │   │   ├── in_anglvel_hysteresis
-│   │   │   │   ├── in_anglvel_offset
-│   │   │   │   ├── in_anglvel_sampling_frequency
-│   │   │   │   ├── in_anglvel_scale
-│   │   │   │   ├── in_anglvel_x_raw
-│   │   │   │   ├── in_anglvel_y_raw
-│   │   │   │   ├── in_anglvel_z_raw
-│   │   │   │   ├── name
-│   │   │   │   ├── scan_elements
-│   │   │   │   │   ├── in_anglvel_x_en
-│   │   │   │   │   ├── in_anglvel_x_index
-│   │   │   │   │   ├── in_anglvel_x_type
-│   │   │   │   │   ├── in_anglvel_y_en
-│   │   │   │   │   ├── in_anglvel_y_index
-│   │   │   │   │   ├── in_anglvel_y_type
-│   │   │   │   │   ├── in_anglvel_z_en
-│   │   │   │   │   ├── in_anglvel_z_index
-│   │   │   │   │   └── in_anglvel_z_type
-│   │   │   │   ├── trigger
-│   │   │   │   │   └── current_trigger
-...
diff --git a/Documentation/hid/uhid.rst b/Documentation/hid/uhid.rst
new file mode 100644 (file)
index 0000000..b18cb96
--- /dev/null
@@ -0,0 +1,193 @@
+======================================================
+UHID - User-space I/O driver support for HID subsystem
+======================================================
+
+UHID allows user-space to implement HID transport drivers. Please see
+hid-transport.txt for an introduction into HID transport drivers. This document
+relies heavily on the definitions declared there.
+
+With UHID, a user-space transport driver can create kernel hid-devices for each
+device connected to the user-space controlled bus. The UHID API defines the I/O
+events provided from the kernel to user-space and vice versa.
+
+There is an example user-space application in ./samples/uhid/uhid-example.c
+
+The UHID API
+------------
+
+UHID is accessed through a character misc-device. The minor-number is allocated
+dynamically so you need to rely on udev (or similar) to create the device node.
+This is /dev/uhid by default.
+
+If a new device is detected by your HID I/O Driver and you want to register this
+device with the HID subsystem, then you need to open /dev/uhid once for each
+device you want to register. All further communication is done by read()'ing or
+write()'ing "struct uhid_event" objects. Non-blocking operations are supported
+by setting O_NONBLOCK::
+
+  struct uhid_event {
+        __u32 type;
+        union {
+                struct uhid_create2_req create2;
+                struct uhid_output_req output;
+                struct uhid_input2_req input2;
+                ...
+        } u;
+  };
+
+The "type" field contains the ID of the event. Depending on the ID different
+payloads are sent. You must not split a single event across multiple read()'s or
+multiple write()'s. A single event must always be sent as a whole. Furthermore,
+only a single event can be sent per read() or write(). Pending data is ignored.
+If you want to handle multiple events in a single syscall, then use vectored
+I/O with readv()/writev().
+The "type" field defines the payload. For each type, there is a
+payload-structure available in the union "u" (except for empty payloads). This
+payload contains management and/or device data.
+
+The first thing you should do is sending an UHID_CREATE2 event. This will
+register the device. UHID will respond with an UHID_START event. You can now
+start sending data to and reading data from UHID. However, unless UHID sends the
+UHID_OPEN event, the internally attached HID Device Driver has no user attached.
+That is, you might put your device asleep unless you receive the UHID_OPEN
+event. If you receive the UHID_OPEN event, you should start I/O. If the last
+user closes the HID device, you will receive an UHID_CLOSE event. This may be
+followed by an UHID_OPEN event again and so on. There is no need to perform
+reference-counting in user-space. That is, you will never receive multiple
+UHID_OPEN events without an UHID_CLOSE event. The HID subsystem performs
+ref-counting for you.
+You may decide to ignore UHID_OPEN/UHID_CLOSE, though. I/O is allowed even
+though the device may have no users.
+
+If you want to send data on the interrupt channel to the HID subsystem, you send
+an HID_INPUT2 event with your raw data payload. If the kernel wants to send data
+on the interrupt channel to the device, you will read an UHID_OUTPUT event.
+Data requests on the control channel are currently limited to GET_REPORT and
+SET_REPORT (no other data reports on the control channel are defined so far).
+Those requests are always synchronous. That means, the kernel sends
+UHID_GET_REPORT and UHID_SET_REPORT events and requires you to forward them to
+the device on the control channel. Once the device responds, you must forward
+the response via UHID_GET_REPORT_REPLY and UHID_SET_REPORT_REPLY to the kernel.
+The kernel blocks internal driver-execution during such round-trips (times out
+after a hard-coded period).
+
+If your device disconnects, you should send an UHID_DESTROY event. This will
+unregister the device. You can now send UHID_CREATE2 again to register a new
+device.
+If you close() the fd, the device is automatically unregistered and destroyed
+internally.
+
+write()
+-------
+write() allows you to modify the state of the device and feed input data into
+the kernel. The kernel will parse the event immediately and if the event ID is
+not supported, it will return -EOPNOTSUPP. If the payload is invalid, then
+-EINVAL is returned, otherwise, the amount of data that was read is returned and
+the request was handled successfully. O_NONBLOCK does not affect write() as
+writes are always handled immediately in a non-blocking fashion. Future requests
+might make use of O_NONBLOCK, though.
+
+UHID_CREATE2:
+  This creates the internal HID device. No I/O is possible until you send this
+  event to the kernel. The payload is of type struct uhid_create2_req and
+  contains information about your device. You can start I/O now.
+
+UHID_DESTROY:
+  This destroys the internal HID device. No further I/O will be accepted. There
+  may still be pending messages that you can receive with read() but no further
+  UHID_INPUT events can be sent to the kernel.
+  You can create a new device by sending UHID_CREATE2 again. There is no need to
+  reopen the character device.
+
+UHID_INPUT2:
+  You must send UHID_CREATE2 before sending input to the kernel! This event
+  contains a data-payload. This is the raw data that you read from your device
+  on the interrupt channel. The kernel will parse the HID reports.
+
+UHID_GET_REPORT_REPLY:
+  If you receive a UHID_GET_REPORT request you must answer with this request.
+  You  must copy the "id" field from the request into the answer. Set the "err"
+  field to 0 if no error occurred or to EIO if an I/O error occurred.
+  If "err" is 0 then you should fill the buffer of the answer with the results
+  of the GET_REPORT request and set "size" correspondingly.
+
+UHID_SET_REPORT_REPLY:
+  This is the SET_REPORT equivalent of UHID_GET_REPORT_REPLY. Unlike GET_REPORT,
+  SET_REPORT never returns a data buffer, therefore, it's sufficient to set the
+  "id" and "err" fields correctly.
+
+read()
+------
+read() will return a queued output report. No reaction is required to any of
+them but you should handle them according to your needs.
+
+UHID_START:
+  This is sent when the HID device is started. Consider this as an answer to
+  UHID_CREATE2. This is always the first event that is sent. Note that this
+  event might not be available immediately after write(UHID_CREATE2) returns.
+  Device drivers might required delayed setups.
+  This event contains a payload of type uhid_start_req. The "dev_flags" field
+  describes special behaviors of a device. The following flags are defined:
+
+      - UHID_DEV_NUMBERED_FEATURE_REPORTS
+      - UHID_DEV_NUMBERED_OUTPUT_REPORTS
+      - UHID_DEV_NUMBERED_INPUT_REPORTS
+
+          Each of these flags defines whether a given report-type uses numbered
+          reports. If numbered reports are used for a type, all messages from
+          the kernel already have the report-number as prefix. Otherwise, no
+          prefix is added by the kernel.
+          For messages sent by user-space to the kernel, you must adjust the
+          prefixes according to these flags.
+
+UHID_STOP:
+  This is sent when the HID device is stopped. Consider this as an answer to
+  UHID_DESTROY.
+
+  If you didn't destroy your device via UHID_DESTROY, but the kernel sends an
+  UHID_STOP event, this should usually be ignored. It means that the kernel
+  reloaded/changed the device driver loaded on your HID device (or some other
+  maintenance actions happened).
+
+  You can usually ignored any UHID_STOP events safely.
+
+UHID_OPEN:
+  This is sent when the HID device is opened. That is, the data that the HID
+  device provides is read by some other process. You may ignore this event but
+  it is useful for power-management. As long as you haven't received this event
+  there is actually no other process that reads your data so there is no need to
+  send UHID_INPUT2 events to the kernel.
+
+UHID_CLOSE:
+  This is sent when there are no more processes which read the HID data. It is
+  the counterpart of UHID_OPEN and you may as well ignore this event.
+
+UHID_OUTPUT:
+  This is sent if the HID device driver wants to send raw data to the I/O
+  device on the interrupt channel. You should read the payload and forward it to
+  the device. The payload is of type "struct uhid_output_req".
+  This may be received even though you haven't received UHID_OPEN, yet.
+
+UHID_GET_REPORT:
+  This event is sent if the kernel driver wants to perform a GET_REPORT request
+  on the control channeld as described in the HID specs. The report-type and
+  report-number are available in the payload.
+  The kernel serializes GET_REPORT requests so there will never be two in
+  parallel. However, if you fail to respond with a UHID_GET_REPORT_REPLY, the
+  request might silently time out.
+  Once you read a GET_REPORT request, you shall forward it to the hid device and
+  remember the "id" field in the payload. Once your hid device responds to the
+  GET_REPORT (or if it fails), you must send a UHID_GET_REPORT_REPLY to the
+  kernel with the exact same "id" as in the request. If the request already
+  timed out, the kernel will ignore the response silently. The "id" field is
+  never re-used, so conflicts cannot happen.
+
+UHID_SET_REPORT:
+  This is the SET_REPORT equivalent of UHID_GET_REPORT. On receipt, you shall
+  send a SET_REPORT request to your hid device. Once it replies, you must tell
+  the kernel about it via UHID_SET_REPORT_REPLY.
+  The same restrictions as for UHID_GET_REPORT apply.
+
+----------------------------------------------------
+
+Written 2012, David Herrmann <dh.herrmann@gmail.com>
diff --git a/Documentation/hid/uhid.txt b/Documentation/hid/uhid.txt
deleted file mode 100644 (file)
index 958fff9..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-      UHID - User-space I/O driver support for HID subsystem
-     ========================================================
-
-UHID allows user-space to implement HID transport drivers. Please see
-hid-transport.txt for an introduction into HID transport drivers. This document
-relies heavily on the definitions declared there.
-
-With UHID, a user-space transport driver can create kernel hid-devices for each
-device connected to the user-space controlled bus. The UHID API defines the I/O
-events provided from the kernel to user-space and vice versa.
-
-There is an example user-space application in ./samples/uhid/uhid-example.c
-
-The UHID API
-------------
-
-UHID is accessed through a character misc-device. The minor-number is allocated
-dynamically so you need to rely on udev (or similar) to create the device node.
-This is /dev/uhid by default.
-
-If a new device is detected by your HID I/O Driver and you want to register this
-device with the HID subsystem, then you need to open /dev/uhid once for each
-device you want to register. All further communication is done by read()'ing or
-write()'ing "struct uhid_event" objects. Non-blocking operations are supported
-by setting O_NONBLOCK.
-
-struct uhid_event {
-        __u32 type;
-        union {
-                struct uhid_create2_req create2;
-                struct uhid_output_req output;
-                struct uhid_input2_req input2;
-                ...
-        } u;
-};
-
-The "type" field contains the ID of the event. Depending on the ID different
-payloads are sent. You must not split a single event across multiple read()'s or
-multiple write()'s. A single event must always be sent as a whole. Furthermore,
-only a single event can be sent per read() or write(). Pending data is ignored.
-If you want to handle multiple events in a single syscall, then use vectored
-I/O with readv()/writev().
-The "type" field defines the payload. For each type, there is a
-payload-structure available in the union "u" (except for empty payloads). This
-payload contains management and/or device data.
-
-The first thing you should do is sending an UHID_CREATE2 event. This will
-register the device. UHID will respond with an UHID_START event. You can now
-start sending data to and reading data from UHID. However, unless UHID sends the
-UHID_OPEN event, the internally attached HID Device Driver has no user attached.
-That is, you might put your device asleep unless you receive the UHID_OPEN
-event. If you receive the UHID_OPEN event, you should start I/O. If the last
-user closes the HID device, you will receive an UHID_CLOSE event. This may be
-followed by an UHID_OPEN event again and so on. There is no need to perform
-reference-counting in user-space. That is, you will never receive multiple
-UHID_OPEN events without an UHID_CLOSE event. The HID subsystem performs
-ref-counting for you.
-You may decide to ignore UHID_OPEN/UHID_CLOSE, though. I/O is allowed even
-though the device may have no users.
-
-If you want to send data on the interrupt channel to the HID subsystem, you send
-an HID_INPUT2 event with your raw data payload. If the kernel wants to send data
-on the interrupt channel to the device, you will read an UHID_OUTPUT event.
-Data requests on the control channel are currently limited to GET_REPORT and
-SET_REPORT (no other data reports on the control channel are defined so far).
-Those requests are always synchronous. That means, the kernel sends
-UHID_GET_REPORT and UHID_SET_REPORT events and requires you to forward them to
-the device on the control channel. Once the device responds, you must forward
-the response via UHID_GET_REPORT_REPLY and UHID_SET_REPORT_REPLY to the kernel.
-The kernel blocks internal driver-execution during such round-trips (times out
-after a hard-coded period).
-
-If your device disconnects, you should send an UHID_DESTROY event. This will
-unregister the device. You can now send UHID_CREATE2 again to register a new
-device.
-If you close() the fd, the device is automatically unregistered and destroyed
-internally.
-
-write()
--------
-write() allows you to modify the state of the device and feed input data into
-the kernel. The kernel will parse the event immediately and if the event ID is
-not supported, it will return -EOPNOTSUPP. If the payload is invalid, then
--EINVAL is returned, otherwise, the amount of data that was read is returned and
-the request was handled successfully. O_NONBLOCK does not affect write() as
-writes are always handled immediately in a non-blocking fashion. Future requests
-might make use of O_NONBLOCK, though.
-
-  UHID_CREATE2:
-  This creates the internal HID device. No I/O is possible until you send this
-  event to the kernel. The payload is of type struct uhid_create2_req and
-  contains information about your device. You can start I/O now.
-
-  UHID_DESTROY:
-  This destroys the internal HID device. No further I/O will be accepted. There
-  may still be pending messages that you can receive with read() but no further
-  UHID_INPUT events can be sent to the kernel.
-  You can create a new device by sending UHID_CREATE2 again. There is no need to
-  reopen the character device.
-
-  UHID_INPUT2:
-  You must send UHID_CREATE2 before sending input to the kernel! This event
-  contains a data-payload. This is the raw data that you read from your device
-  on the interrupt channel. The kernel will parse the HID reports.
-
-  UHID_GET_REPORT_REPLY:
-  If you receive a UHID_GET_REPORT request you must answer with this request.
-  You  must copy the "id" field from the request into the answer. Set the "err"
-  field to 0 if no error occurred or to EIO if an I/O error occurred.
-  If "err" is 0 then you should fill the buffer of the answer with the results
-  of the GET_REPORT request and set "size" correspondingly.
-
-  UHID_SET_REPORT_REPLY:
-  This is the SET_REPORT equivalent of UHID_GET_REPORT_REPLY. Unlike GET_REPORT,
-  SET_REPORT never returns a data buffer, therefore, it's sufficient to set the
-  "id" and "err" fields correctly.
-
-read()
-------
-read() will return a queued output report. No reaction is required to any of
-them but you should handle them according to your needs.
-
-  UHID_START:
-  This is sent when the HID device is started. Consider this as an answer to
-  UHID_CREATE2. This is always the first event that is sent. Note that this
-  event might not be available immediately after write(UHID_CREATE2) returns.
-  Device drivers might required delayed setups.
-  This event contains a payload of type uhid_start_req. The "dev_flags" field
-  describes special behaviors of a device. The following flags are defined:
-      UHID_DEV_NUMBERED_FEATURE_REPORTS:
-      UHID_DEV_NUMBERED_OUTPUT_REPORTS:
-      UHID_DEV_NUMBERED_INPUT_REPORTS:
-          Each of these flags defines whether a given report-type uses numbered
-          reports. If numbered reports are used for a type, all messages from
-          the kernel already have the report-number as prefix. Otherwise, no
-          prefix is added by the kernel.
-          For messages sent by user-space to the kernel, you must adjust the
-          prefixes according to these flags.
-
-  UHID_STOP:
-  This is sent when the HID device is stopped. Consider this as an answer to
-  UHID_DESTROY.
-  If you didn't destroy your device via UHID_DESTROY, but the kernel sends an
-  UHID_STOP event, this should usually be ignored. It means that the kernel
-  reloaded/changed the device driver loaded on your HID device (or some other
-  maintenance actions happened).
-  You can usually ignored any UHID_STOP events safely.
-
-  UHID_OPEN:
-  This is sent when the HID device is opened. That is, the data that the HID
-  device provides is read by some other process. You may ignore this event but
-  it is useful for power-management. As long as you haven't received this event
-  there is actually no other process that reads your data so there is no need to
-  send UHID_INPUT2 events to the kernel.
-
-  UHID_CLOSE:
-  This is sent when there are no more processes which read the HID data. It is
-  the counterpart of UHID_OPEN and you may as well ignore this event.
-
-  UHID_OUTPUT:
-  This is sent if the HID device driver wants to send raw data to the I/O
-  device on the interrupt channel. You should read the payload and forward it to
-  the device. The payload is of type "struct uhid_output_req".
-  This may be received even though you haven't received UHID_OPEN, yet.
-
-  UHID_GET_REPORT:
-  This event is sent if the kernel driver wants to perform a GET_REPORT request
-  on the control channeld as described in the HID specs. The report-type and
-  report-number are available in the payload.
-  The kernel serializes GET_REPORT requests so there will never be two in
-  parallel. However, if you fail to respond with a UHID_GET_REPORT_REPLY, the
-  request might silently time out.
-  Once you read a GET_REPORT request, you shall forward it to the hid device and
-  remember the "id" field in the payload. Once your hid device responds to the
-  GET_REPORT (or if it fails), you must send a UHID_GET_REPORT_REPLY to the
-  kernel with the exact same "id" as in the request. If the request already
-  timed out, the kernel will ignore the response silently. The "id" field is
-  never re-used, so conflicts cannot happen.
-
-  UHID_SET_REPORT:
-  This is the SET_REPORT equivalent of UHID_GET_REPORT. On receipt, you shall
-  send a SET_REPORT request to your hid device. Once it replies, you must tell
-  the kernel about it via UHID_SET_REPORT_REPLY.
-  The same restrictions as for UHID_GET_REPORT apply.
-
-----------------------------------------------------
-Written 2012, David Herrmann <dh.herrmann@gmail.com>
diff --git a/Documentation/hwmon/pxe1610 b/Documentation/hwmon/pxe1610
new file mode 100644 (file)
index 0000000..211cede
--- /dev/null
@@ -0,0 +1,90 @@
+Kernel driver pxe1610
+=====================
+
+Supported chips:
+  * Infineon PXE1610
+    Prefix: 'pxe1610'
+    Addresses scanned: -
+    Datasheet: Datasheet is not publicly available.
+
+  * Infineon PXE1110
+    Prefix: 'pxe1110'
+    Addresses scanned: -
+    Datasheet: Datasheet is not publicly available.
+
+  * Infineon PXM1310
+    Prefix: 'pxm1310'
+    Addresses scanned: -
+    Datasheet: Datasheet is not publicly available.
+
+Author: Vijay Khemka <vijaykhemka@fb.com>
+
+
+Description
+-----------
+
+PXE1610/PXE1110 are Multi-rail/Multiphase Digital Controllers
+and compliant to
+       -- Intel VR13 DC-DC converter specifications.
+       -- Intel SVID protocol.
+Used for Vcore power regulation for Intel VR13 based microprocessors
+       -- Servers, Workstations, and High-end desktops
+
+PXM1310 is a Multi-rail Controller and it is compliant to
+       -- Intel VR13 DC-DC converter specifications.
+       -- Intel SVID protocol.
+Used for DDR3/DDR4 Memory power regulation for Intel VR13 and
+IMVP8 based systems
+
+
+Usage Notes
+-----------
+
+This driver does not probe for PMBus devices. You will have
+to instantiate devices explicitly.
+
+Example: the following commands will load the driver for an PXE1610
+at address 0x70 on I2C bus #4:
+
+# modprobe pxe1610
+# echo pxe1610 0x70 > /sys/bus/i2c/devices/i2c-4/new_device
+
+It can also be instantiated by declaring in device tree
+
+
+Sysfs attributes
+----------------
+
+curr1_label            "iin"
+curr1_input            Measured input current
+curr1_alarm            Current high alarm
+
+curr[2-4]_label                "iout[1-3]"
+curr[2-4]_input                Measured output current
+curr[2-4]_crit         Critical maximum current
+curr[2-4]_crit_alarm   Current critical high alarm
+
+in1_label              "vin"
+in1_input              Measured input voltage
+in1_crit               Critical maximum input voltage
+in1_crit_alarm         Input voltage critical high alarm
+
+in[2-4]_label          "vout[1-3]"
+in[2-4]_input          Measured output voltage
+in[2-4]_lcrit          Critical minimum output voltage
+in[2-4]_lcrit_alarm    Output voltage critical low alarm
+in[2-4]_crit           Critical maximum output voltage
+in[2-4]_crit_alarm     Output voltage critical high alarm
+
+power1_label           "pin"
+power1_input           Measured input power
+power1_alarm           Input power high alarm
+
+power[2-4]_label       "pout[1-3]"
+power[2-4]_input       Measured output power
+
+temp[1-3]_input                Measured temperature
+temp[1-3]_crit         Critical high temperature
+temp[1-3]_crit_alarm   Chip temperature critical high alarm
+temp[1-3]_max          Maximum temperature
+temp[1-3]_max_alarm    Chip temperature high alarm
index f9796b9..d5b05d3 100644 (file)
@@ -89,7 +89,7 @@ increase the chances of your change being accepted.
   console. Excessive logging can seriously affect system performance.
 
 * Use devres functions whenever possible to allocate resources. For rationale
-  and supported functions, please see Documentation/driver-model/devres.txt.
+  and supported functions, please see Documentation/driver-model/devres.rst.
   If a function is not supported by devres, consider using devm_add_action().
 
 * If the driver has a detect function, make sure it is silent. Debug messages
diff --git a/Documentation/iio/ep93xx_adc.rst b/Documentation/iio/ep93xx_adc.rst
new file mode 100644 (file)
index 0000000..4fd8dea
--- /dev/null
@@ -0,0 +1,40 @@
+==============================
+Cirrus Logic EP93xx ADC driver
+==============================
+
+1. Overview
+===========
+
+The driver is intended to work on both low-end (EP9301, EP9302) devices with
+5-channel ADC and high-end (EP9307, EP9312, EP9315) devices with 10-channel
+touchscreen/ADC module.
+
+2. Channel numbering
+====================
+
+Numbering scheme for channels 0..4 is defined in EP9301 and EP9302 datasheets.
+EP9307, EP9312 and EP9312 have 3 channels more (total 8), but the numbering is
+not defined. So the last three are numbered randomly, let's say.
+
+Assuming ep93xx_adc is IIO device0, you'd find the following entries under
+/sys/bus/iio/devices/iio:device0/:
+
+  +-----------------+---------------+
+  | sysfs entry     | ball/pin name |
+  +=================+===============+
+  | in_voltage0_raw | YM            |
+  +-----------------+---------------+
+  | in_voltage1_raw | SXP           |
+  +-----------------+---------------+
+  | in_voltage2_raw | SXM           |
+  +-----------------+---------------+
+  | in_voltage3_raw | SYP           |
+  +-----------------+---------------+
+  | in_voltage4_raw | SYM           |
+  +-----------------+---------------+
+  | in_voltage5_raw | XP            |
+  +-----------------+---------------+
+  | in_voltage6_raw | XM            |
+  +-----------------+---------------+
+  | in_voltage7_raw | YP            |
+  +-----------------+---------------+
diff --git a/Documentation/iio/ep93xx_adc.txt b/Documentation/iio/ep93xx_adc.txt
deleted file mode 100644 (file)
index 23053e7..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-Cirrus Logic EP93xx ADC driver.
-
-1. Overview
-
-The driver is intended to work on both low-end (EP9301, EP9302) devices with
-5-channel ADC and high-end (EP9307, EP9312, EP9315) devices with 10-channel
-touchscreen/ADC module.
-
-2. Channel numbering
-
-Numbering scheme for channels 0..4 is defined in EP9301 and EP9302 datasheets.
-EP9307, EP9312 and EP9312 have 3 channels more (total 8), but the numbering is
-not defined. So the last three are numbered randomly, let's say.
-
-Assuming ep93xx_adc is IIO device0, you'd find the following entries under
-/sys/bus/iio/devices/iio:device0/:
-
-  +-----------------+---------------+
-  | sysfs entry     | ball/pin name |
-  +-----------------+---------------+
-  | in_voltage0_raw | YM            |
-  | in_voltage1_raw | SXP           |
-  | in_voltage2_raw | SXM           |
-  | in_voltage3_raw | SYP           |
-  | in_voltage4_raw | SYM           |
-  | in_voltage5_raw | XP            |
-  | in_voltage6_raw | XM            |
-  | in_voltage7_raw | YP            |
-  +-----------------+---------------+
diff --git a/Documentation/iio/iio_configfs.rst b/Documentation/iio/iio_configfs.rst
new file mode 100644 (file)
index 0000000..ecbfdb3
--- /dev/null
@@ -0,0 +1,101 @@
+===============================
+Industrial IIO configfs support
+===============================
+
+1. Overview
+===========
+
+Configfs is a filesystem-based manager of kernel objects. IIO uses some
+objects that could be easily configured using configfs (e.g.: devices,
+triggers).
+
+See Documentation/filesystems/configfs/configfs.txt for more information
+about how configfs works.
+
+2. Usage
+========
+
+In order to use configfs support in IIO we need to select it at compile
+time via CONFIG_IIO_CONFIGFS config option.
+
+Then, mount the configfs filesystem (usually under /config directory)::
+
+  $ mkdir /config
+  $ mount -t configfs none /config
+
+At this point, all default IIO groups will be created and can be accessed
+under /config/iio. Next chapters will describe available IIO configuration
+objects.
+
+3. Software triggers
+====================
+
+One of the IIO default configfs groups is the "triggers" group. It is
+automagically accessible when the configfs is mounted and can be found
+under /config/iio/triggers.
+
+IIO software triggers implementation offers support for creating multiple
+trigger types. A new trigger type is usually implemented as a separate
+kernel module following the interface in include/linux/iio/sw_trigger.h::
+
+  /*
+   * drivers/iio/trigger/iio-trig-sample.c
+   * sample kernel module implementing a new trigger type
+   */
+  #include <linux/iio/sw_trigger.h>
+
+
+  static struct iio_sw_trigger *iio_trig_sample_probe(const char *name)
+  {
+       /*
+        * This allocates and registers an IIO trigger plus other
+        * trigger type specific initialization.
+        */
+  }
+
+  static int iio_trig_hrtimer_remove(struct iio_sw_trigger *swt)
+  {
+       /*
+        * This undoes the actions in iio_trig_sample_probe
+        */
+  }
+
+  static const struct iio_sw_trigger_ops iio_trig_sample_ops = {
+       .probe          = iio_trig_sample_probe,
+       .remove         = iio_trig_sample_remove,
+  };
+
+  static struct iio_sw_trigger_type iio_trig_sample = {
+       .name = "trig-sample",
+       .owner = THIS_MODULE,
+       .ops = &iio_trig_sample_ops,
+  };
+
+module_iio_sw_trigger_driver(iio_trig_sample);
+
+Each trigger type has its own directory under /config/iio/triggers. Loading
+iio-trig-sample module will create 'trig-sample' trigger type directory
+/config/iio/triggers/trig-sample.
+
+We support the following interrupt sources (trigger types):
+
+       * hrtimer, uses high resolution timers as interrupt source
+
+3.1 Hrtimer triggers creation and destruction
+---------------------------------------------
+
+Loading iio-trig-hrtimer module will register hrtimer trigger types allowing
+users to create hrtimer triggers under /config/iio/triggers/hrtimer.
+
+e.g::
+
+  $ mkdir /config/iio/triggers/hrtimer/instance1
+  $ rmdir /config/iio/triggers/hrtimer/instance1
+
+Each trigger can have one or more attributes specific to the trigger type.
+
+3.2 "hrtimer" trigger types attributes
+--------------------------------------
+
+"hrtimer" trigger type doesn't have any configurable attribute from /config dir.
+It does introduce the sampling_frequency attribute to trigger directory.
diff --git a/Documentation/iio/iio_configfs.txt b/Documentation/iio/iio_configfs.txt
deleted file mode 100644 (file)
index 4e5f101..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-Industrial IIO configfs support
-
-1. Overview
-
-Configfs is a filesystem-based manager of kernel objects. IIO uses some
-objects that could be easily configured using configfs (e.g.: devices,
-triggers).
-
-See Documentation/filesystems/configfs/configfs.txt for more information
-about how configfs works.
-
-2. Usage
-
-In order to use configfs support in IIO we need to select it at compile
-time via CONFIG_IIO_CONFIGFS config option.
-
-Then, mount the configfs filesystem (usually under /config directory):
-
-$ mkdir /config
-$ mount -t configfs none /config
-
-At this point, all default IIO groups will be created and can be accessed
-under /config/iio. Next chapters will describe available IIO configuration
-objects.
-
-3. Software triggers
-
-One of the IIO default configfs groups is the "triggers" group. It is
-automagically accessible when the configfs is mounted and can be found
-under /config/iio/triggers.
-
-IIO software triggers implementation offers support for creating multiple
-trigger types. A new trigger type is usually implemented as a separate
-kernel module following the interface in include/linux/iio/sw_trigger.h:
-
-/*
- * drivers/iio/trigger/iio-trig-sample.c
- * sample kernel module implementing a new trigger type
- */
-#include <linux/iio/sw_trigger.h>
-
-
-static struct iio_sw_trigger *iio_trig_sample_probe(const char *name)
-{
-       /*
-        * This allocates and registers an IIO trigger plus other
-        * trigger type specific initialization.
-        */
-}
-
-static int iio_trig_hrtimer_remove(struct iio_sw_trigger *swt)
-{
-       /*
-        * This undoes the actions in iio_trig_sample_probe
-        */
-}
-
-static const struct iio_sw_trigger_ops iio_trig_sample_ops = {
-       .probe          = iio_trig_sample_probe,
-       .remove         = iio_trig_sample_remove,
-};
-
-static struct iio_sw_trigger_type iio_trig_sample = {
-       .name = "trig-sample",
-       .owner = THIS_MODULE,
-       .ops = &iio_trig_sample_ops,
-};
-
-module_iio_sw_trigger_driver(iio_trig_sample);
-
-Each trigger type has its own directory under /config/iio/triggers. Loading
-iio-trig-sample module will create 'trig-sample' trigger type directory
-/config/iio/triggers/trig-sample.
-
-We support the following interrupt sources (trigger types):
-       * hrtimer, uses high resolution timers as interrupt source
-
-3.1 Hrtimer triggers creation and destruction
-
-Loading iio-trig-hrtimer module will register hrtimer trigger types allowing
-users to create hrtimer triggers under /config/iio/triggers/hrtimer.
-
-e.g:
-
-$ mkdir /config/iio/triggers/hrtimer/instance1
-$ rmdir /config/iio/triggers/hrtimer/instance1
-
-Each trigger can have one or more attributes specific to the trigger type.
-
-3.2 "hrtimer" trigger types attributes
-
-"hrtimer" trigger type doesn't have any configurable attribute from /config dir.
-It does introduce the sampling_frequency attribute to trigger directory.
diff --git a/Documentation/iio/index.rst b/Documentation/iio/index.rst
new file mode 100644 (file)
index 0000000..0593dca
--- /dev/null
@@ -0,0 +1,12 @@
+:orphan:
+
+==============
+Industrial I/O
+==============
+
+.. toctree::
+   :maxdepth: 1
+
+   iio_configfs
+
+   ep93xx_adc
index 781042b..216dc0e 100644 (file)
@@ -101,6 +101,7 @@ needed).
    filesystems/index
    vm/index
    bpf/index
+   usb/index
    misc-devices/index
 
 Architecture-specific documentation
index 47f86a4..0eb61e6 100644 (file)
@@ -188,7 +188,7 @@ LCDs and many other purposes.
 
 The monitor and speaker controls should be easy to add to the hid/input
 interface, but for the UPSs and LCDs it doesn't make much sense. For this,
-the hiddev interface was designed. See Documentation/hid/hiddev.txt
+the hiddev interface was designed. See Documentation/hid/hiddev.rst
 for more information about it.
 
 The usage of the usbhid module is very simple, it takes no parameters,
index 1ab7294..f6c6b74 100644 (file)
@@ -40,12 +40,5 @@ INSTALL_HDR_PATH indicates where to install the headers. It defaults to
 An 'include' directory is automatically created inside INSTALL_HDR_PATH and
 headers are installed in 'INSTALL_HDR_PATH/include'.
 
-The command "make headers_install_all" exports headers for all architectures
-simultaneously.  (This is mostly of interest to distribution maintainers,
-who create an architecture-independent tarball from the resulting include
-directory.)  You also can use HDR_ARCH_LIST to specify list of architectures.
-Remember to provide the appropriate linux/asm directory via "mv" or "ln -s"
-before building a C library with headers exported this way.
-
 The kernel header export infrastructure is maintained by David Woodhouse
 <dwmw2@infradead.org>.
index e774e76..b255489 100644 (file)
@@ -200,6 +200,15 @@ The output directory is often set using "O=..." on the commandline.
 
 The value can be overridden in which case the default value is ignored.
 
+KBUILD_ABS_SRCTREE
+--------------------------------------------------
+Kbuild uses a relative path to point to the tree when possible. For instance,
+when building in the source tree, the source tree path is '.'
+
+Setting this flag requests Kbuild to use absolute path to the source tree.
+There are some useful cases to do so, like when generating tag files with
+absolute path entries etc.
+
 KBUILD_SIGN_PIN
 ---------------
 This variable allows a passphrase or PIN to be passed to the sign-file
index 9274cdc..093f2d7 100644 (file)
@@ -999,11 +999,7 @@ When kbuild executes, the following steps are followed (roughly):
 ------------------------------------
 
        The archheaders: rule is used to generate header files that
-       may be installed into user space by "make header_install" or
-       "make headers_install_all".  In order to support
-       "make headers_install_all", this target has to be able to run
-       on an unconfigured tree, or a tree configured for another
-       architecture.
+       may be installed into user space by "make header_install".
 
        It is run before "make archprepare" when run on the
        architecture itself.
@@ -1140,6 +1136,22 @@ When kbuild executes, the following steps are followed (roughly):
        In this example, extra-y is used to list object files that
        shall be built, but shall not be linked as part of built-in.a.
 
+    header-test-y
+
+       header-test-y specifies headers (*.h) in the current directory that
+       should be compile tested to ensure they are self-contained,
+       i.e. compilable as standalone units. If CONFIG_HEADER_TEST is enabled,
+       this builds them as part of extra-y.
+
+    header-test-pattern-y
+
+       This works as a weaker version of header-test-y, and accepts wildcard
+       patterns. The typical usage is:
+
+                 header-test-pattern-y += *.h
+
+       This specifies all the files that matches to '*.h' in the current
+       directory, but the files in 'header-test-' are excluded.
 
 6.7 Commands useful for building a boot image
 ---------------------------------------------
diff --git a/Documentation/misc-devices/eeprom b/Documentation/misc-devices/eeprom
deleted file mode 100644 (file)
index ba69201..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-Kernel driver eeprom
-====================
-
-Supported chips:
-  * Any EEPROM chip in the designated address range
-    Prefix: 'eeprom'
-    Addresses scanned: I2C 0x50 - 0x57
-    Datasheets: Publicly available from:
-                Atmel (www.atmel.com),
-                Catalyst (www.catsemi.com),
-                Fairchild (www.fairchildsemi.com),
-                Microchip (www.microchip.com),
-                Philips (www.semiconductor.philips.com),
-                Rohm (www.rohm.com),
-                ST (www.st.com),
-                Xicor (www.xicor.com),
-                and others.
-
-        Chip     Size (bits)    Address
-        24C01     1K            0x50 (shadows at 0x51 - 0x57)
-        24C01A    1K            0x50 - 0x57 (Typical device on DIMMs)
-        24C02     2K            0x50 - 0x57
-        24C04     4K            0x50, 0x52, 0x54, 0x56
-                                (additional data at 0x51, 0x53, 0x55, 0x57)
-        24C08     8K            0x50, 0x54 (additional data at 0x51, 0x52,
-                                0x53, 0x55, 0x56, 0x57)
-        24C16    16K            0x50 (additional data at 0x51 - 0x57)
-        Sony      2K            0x57
-
-        Atmel     34C02B  2K    0x50 - 0x57, SW write protect at 0x30-37
-        Catalyst  34FC02  2K    0x50 - 0x57, SW write protect at 0x30-37
-        Catalyst  34RC02  2K    0x50 - 0x57, SW write protect at 0x30-37
-        Fairchild 34W02   2K    0x50 - 0x57, SW write protect at 0x30-37
-        Microchip 24AA52  2K    0x50 - 0x57, SW write protect at 0x30-37
-        ST        M34C02  2K    0x50 - 0x57, SW write protect at 0x30-37
-
-
-Authors:
-        Frodo Looijaard <frodol@dds.nl>,
-        Philip Edelbrock <phil@netroedge.com>,
-        Jean Delvare <jdelvare@suse.de>,
-        Greg Kroah-Hartman <greg@kroah.com>,
-        IBM Corp.
-
-Description
------------
-
-This is a simple EEPROM module meant to enable reading the first 256 bytes
-of an EEPROM (on a SDRAM DIMM for example). However, it will access serial
-EEPROMs on any I2C adapter. The supported devices are generically called
-24Cxx, and are listed above; however the numbering for these
-industry-standard devices may vary by manufacturer.
-
-This module was a programming exercise to get used to the new project
-organization laid out by Frodo, but it should be at least completely
-effective for decoding the contents of EEPROMs on DIMMs.
-
-DIMMS will typically contain a 24C01A or 24C02, or the 34C02 variants.
-The other devices will not be found on a DIMM because they respond to more
-than one address.
-
-DDC Monitors may contain any device. Often a 24C01, which responds to all 8
-addresses, is found.
-
-Recent Sony Vaio laptops have an EEPROM at 0x57. We couldn't get the
-specification, so it is guess work and far from being complete.
-
-The Microchip 24AA52/24LCS52, ST M34C02, and others support an additional
-software write protect register at 0x30 - 0x37 (0x20 less than the memory
-location). The chip responds to "write quick" detection at this address but
-does not respond to byte reads. If this register is present, the lower 128
-bytes of the memory array are not write protected. Any byte data write to
-this address will write protect the memory array permanently, and the
-device will no longer respond at the 0x30-37 address. The eeprom driver
-does not support this register.
-
-Lacking functionality:
-
-* Full support for larger devices (24C04, 24C08, 24C16). These are not
-typically found on a PC. These devices will appear as separate devices at
-multiple addresses.
-
-* Support for really large devices (24C32, 24C64, 24C128, 24C256, 24C512).
-These devices require two-byte address fields and are not supported.
-
-* Enable Writing. Again, no technical reason why not, but making it easy
-to change the contents of the EEPROMs (on DIMMs anyway) also makes it easy
-to disable the DIMMs (potentially preventing the computer from booting)
-until the values are restored somehow.
-
-Use:
-
-After inserting the module (and any other required SMBus/i2c modules), you
-should have some EEPROM directories in /sys/bus/i2c/devices/* of names such
-as "0-0050". Inside each of these is a series of files, the eeprom file
-contains the binary data from EEPROM.
diff --git a/Documentation/misc-devices/eeprom.rst b/Documentation/misc-devices/eeprom.rst
new file mode 100644 (file)
index 0000000..0082496
--- /dev/null
@@ -0,0 +1,107 @@
+====================
+Kernel driver eeprom
+====================
+
+Supported chips:
+
+  * Any EEPROM chip in the designated address range
+
+    Prefix: 'eeprom'
+
+    Addresses scanned: I2C 0x50 - 0x57
+
+    Datasheets: Publicly available from:
+
+                Atmel (www.atmel.com),
+                Catalyst (www.catsemi.com),
+                Fairchild (www.fairchildsemi.com),
+                Microchip (www.microchip.com),
+                Philips (www.semiconductor.philips.com),
+                Rohm (www.rohm.com),
+                ST (www.st.com),
+                Xicor (www.xicor.com),
+                and others.
+
+        ========= ============= ============================================
+        Chip      Size (bits)   Address
+        ========= ============= ============================================
+        24C01     1K            0x50 (shadows at 0x51 - 0x57)
+        24C01A    1K            0x50 - 0x57 (Typical device on DIMMs)
+        24C02     2K            0x50 - 0x57
+        24C04     4K            0x50, 0x52, 0x54, 0x56
+                                (additional data at 0x51, 0x53, 0x55, 0x57)
+        24C08     8K            0x50, 0x54 (additional data at 0x51, 0x52,
+                                0x53, 0x55, 0x56, 0x57)
+        24C16     16K           0x50 (additional data at 0x51 - 0x57)
+        Sony      2K            0x57
+
+        Atmel     34C02B  2K    0x50 - 0x57, SW write protect at 0x30-37
+        Catalyst  34FC02  2K    0x50 - 0x57, SW write protect at 0x30-37
+        Catalyst  34RC02  2K    0x50 - 0x57, SW write protect at 0x30-37
+        Fairchild 34W02   2K    0x50 - 0x57, SW write protect at 0x30-37
+        Microchip 24AA52  2K    0x50 - 0x57, SW write protect at 0x30-37
+        ST        M34C02  2K    0x50 - 0x57, SW write protect at 0x30-37
+        ========= ============= ============================================
+
+
+Authors:
+        - Frodo Looijaard <frodol@dds.nl>,
+        - Philip Edelbrock <phil@netroedge.com>,
+        - Jean Delvare <jdelvare@suse.de>,
+        - Greg Kroah-Hartman <greg@kroah.com>,
+        - IBM Corp.
+
+Description
+-----------
+
+This is a simple EEPROM module meant to enable reading the first 256 bytes
+of an EEPROM (on a SDRAM DIMM for example). However, it will access serial
+EEPROMs on any I2C adapter. The supported devices are generically called
+24Cxx, and are listed above; however the numbering for these
+industry-standard devices may vary by manufacturer.
+
+This module was a programming exercise to get used to the new project
+organization laid out by Frodo, but it should be at least completely
+effective for decoding the contents of EEPROMs on DIMMs.
+
+DIMMS will typically contain a 24C01A or 24C02, or the 34C02 variants.
+The other devices will not be found on a DIMM because they respond to more
+than one address.
+
+DDC Monitors may contain any device. Often a 24C01, which responds to all 8
+addresses, is found.
+
+Recent Sony Vaio laptops have an EEPROM at 0x57. We couldn't get the
+specification, so it is guess work and far from being complete.
+
+The Microchip 24AA52/24LCS52, ST M34C02, and others support an additional
+software write protect register at 0x30 - 0x37 (0x20 less than the memory
+location). The chip responds to "write quick" detection at this address but
+does not respond to byte reads. If this register is present, the lower 128
+bytes of the memory array are not write protected. Any byte data write to
+this address will write protect the memory array permanently, and the
+device will no longer respond at the 0x30-37 address. The eeprom driver
+does not support this register.
+
+Lacking functionality
+---------------------
+
+* Full support for larger devices (24C04, 24C08, 24C16). These are not
+  typically found on a PC. These devices will appear as separate devices at
+  multiple addresses.
+
+* Support for really large devices (24C32, 24C64, 24C128, 24C256, 24C512).
+  These devices require two-byte address fields and are not supported.
+
+* Enable Writing. Again, no technical reason why not, but making it easy
+  to change the contents of the EEPROMs (on DIMMs anyway) also makes it easy
+  to disable the DIMMs (potentially preventing the computer from booting)
+  until the values are restored somehow.
+
+Use
+---
+
+After inserting the module (and any other required SMBus/i2c modules), you
+should have some EEPROM directories in ``/sys/bus/i2c/devices/*`` of names such
+as "0-0050". Inside each of these is a series of files, the eeprom file
+contains the binary data from EEPROM.
diff --git a/Documentation/misc-devices/ics932s401 b/Documentation/misc-devices/ics932s401
deleted file mode 100644 (file)
index bdac67f..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-Kernel driver ics932s401
-======================
-
-Supported chips:
-  * IDT ICS932S401
-    Prefix: 'ics932s401'
-    Addresses scanned: I2C 0x69
-    Datasheet: Publicly available at the IDT website
-
-Author: Darrick J. Wong
-
-Description
------------
-
-This driver implements support for the IDT ICS932S401 chip family.
-
-This chip has 4 clock outputs--a base clock for the CPU (which is likely
-multiplied to get the real CPU clock), a system clock, a PCI clock, a USB
-clock, and a reference clock.  The driver reports selected and actual
-frequency.  If spread spectrum mode is enabled, the driver also reports by what
-percent the clock signal is being spread, which should be between 0 and -0.5%.
-All frequencies are reported in KHz.
-
-The ICS932S401 monitors all inputs continuously. The driver will not read
-the registers more often than once every other second.
-
-Special Features
-----------------
-
-The clocks could be reprogrammed to increase system speed.  I will not help you
-do this, as you risk damaging your system!
diff --git a/Documentation/misc-devices/ics932s401.rst b/Documentation/misc-devices/ics932s401.rst
new file mode 100644 (file)
index 0000000..613ee54
--- /dev/null
@@ -0,0 +1,36 @@
+========================
+Kernel driver ics932s401
+========================
+
+Supported chips:
+
+  * IDT ICS932S401
+
+    Prefix: 'ics932s401'
+
+    Addresses scanned: I2C 0x69
+
+    Datasheet: Publicly available at the IDT website
+
+Author: Darrick J. Wong
+
+Description
+-----------
+
+This driver implements support for the IDT ICS932S401 chip family.
+
+This chip has 4 clock outputs--a base clock for the CPU (which is likely
+multiplied to get the real CPU clock), a system clock, a PCI clock, a USB
+clock, and a reference clock.  The driver reports selected and actual
+frequency.  If spread spectrum mode is enabled, the driver also reports by what
+percent the clock signal is being spread, which should be between 0 and -0.5%.
+All frequencies are reported in KHz.
+
+The ICS932S401 monitors all inputs continuously. The driver will not read
+the registers more often than once every other second.
+
+Special Features
+----------------
+
+The clocks could be reprogrammed to increase system speed.  I will not help you
+do this, as you risk damaging your system!
index dfd1f45..a57f92d 100644 (file)
@@ -14,4 +14,9 @@ fit into other categories.
 .. toctree::
    :maxdepth: 2
 
+   eeprom
    ibmvmc
+   ics932s401
+   isl29003
+   lis3lv02d
+   max6875
diff --git a/Documentation/misc-devices/isl29003 b/Documentation/misc-devices/isl29003
deleted file mode 100644 (file)
index 80b952f..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-Kernel driver isl29003
-=====================
-
-Supported chips:
-* Intersil ISL29003
-Prefix: 'isl29003'
-Addresses scanned: none
-Datasheet:
-http://www.intersil.com/data/fn/fn7464.pdf
-
-Author: Daniel Mack <daniel@caiaq.de>
-
-
-Description
------------
-The ISL29003 is an integrated light sensor with a 16-bit integrating type
-ADC, I2C user programmable lux range select for optimized counts/lux, and
-I2C multi-function control and monitoring capabilities. The internal ADC
-provides 16-bit resolution while rejecting 50Hz and 60Hz flicker caused by
-artificial light sources.
-
-The driver allows to set the lux range, the bit resolution, the operational
-mode (see below) and the power state of device and can read the current lux
-value, of course.
-
-
-Detection
----------
-
-The ISL29003 does not have an ID register which could be used to identify
-it, so the detection routine will just try to read from the configured I2C
-address and consider the device to be present as soon as it ACKs the
-transfer.
-
-
-Sysfs entries
--------------
-
-range:
-       0: 0 lux to 1000 lux (default)
-       1: 0 lux to 4000 lux
-       2: 0 lux to 16,000 lux
-       3: 0 lux to 64,000 lux
-
-resolution:
-       0: 2^16 cycles (default)
-       1: 2^12 cycles
-       2: 2^8 cycles
-       3: 2^4 cycles
-
-mode:
-       0: diode1's current (unsigned 16bit) (default)
-       1: diode1's current (unsigned 16bit)
-       2: difference between diodes (l1 - l2, signed 15bit)
-
-power_state:
-       0: device is disabled (default)
-       1: device is enabled
-
-lux (read only):
-       returns the value from the last sensor reading
-
diff --git a/Documentation/misc-devices/isl29003.rst b/Documentation/misc-devices/isl29003.rst
new file mode 100644 (file)
index 0000000..0cc38ae
--- /dev/null
@@ -0,0 +1,75 @@
+======================
+Kernel driver isl29003
+======================
+
+Supported chips:
+
+* Intersil ISL29003
+
+Prefix: 'isl29003'
+
+Addresses scanned: none
+
+Datasheet:
+http://www.intersil.com/data/fn/fn7464.pdf
+
+Author: Daniel Mack <daniel@caiaq.de>
+
+
+Description
+-----------
+The ISL29003 is an integrated light sensor with a 16-bit integrating type
+ADC, I2C user programmable lux range select for optimized counts/lux, and
+I2C multi-function control and monitoring capabilities. The internal ADC
+provides 16-bit resolution while rejecting 50Hz and 60Hz flicker caused by
+artificial light sources.
+
+The driver allows to set the lux range, the bit resolution, the operational
+mode (see below) and the power state of device and can read the current lux
+value, of course.
+
+
+Detection
+---------
+
+The ISL29003 does not have an ID register which could be used to identify
+it, so the detection routine will just try to read from the configured I2C
+address and consider the device to be present as soon as it ACKs the
+transfer.
+
+
+Sysfs entries
+-------------
+
+range:
+        == ===========================
+       0: 0 lux to 1000 lux (default)
+       1: 0 lux to 4000 lux
+       2: 0 lux to 16,000 lux
+       3: 0 lux to 64,000 lux
+        == ===========================
+
+resolution:
+        == =====================
+       0: 2^16 cycles (default)
+       1: 2^12 cycles
+       2: 2^8 cycles
+       3: 2^4 cycles
+        == =====================
+
+mode:
+        == =================================================
+       0: diode1's current (unsigned 16bit) (default)
+       1: diode1's current (unsigned 16bit)
+       2: difference between diodes (l1 - l2, signed 15bit)
+        == =================================================
+
+power_state:
+        == =================================================
+       0: device is disabled (default)
+       1: device is enabled
+        == =================================================
+
+lux (read only):
+       returns the value from the last sensor reading
+
diff --git a/Documentation/misc-devices/lis3lv02d b/Documentation/misc-devices/lis3lv02d
deleted file mode 100644 (file)
index f89960a..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-Kernel driver lis3lv02d
-=======================
-
-Supported chips:
-
-  * STMicroelectronics LIS3LV02DL, LIS3LV02DQ (12 bits precision)
-  * STMicroelectronics LIS302DL, LIS3L02DQ, LIS331DL (8 bits) and
-    LIS331DLH (16 bits)
-
-Authors:
-        Yan Burman <burman.yan@gmail.com>
-       Eric Piel <eric.piel@tremplin-utc.net>
-
-
-Description
------------
-
-This driver provides support for the accelerometer found in various HP laptops
-sporting the feature officially called "HP Mobile Data Protection System 3D" or
-"HP 3D DriveGuard". It detects automatically laptops with this sensor. Known
-models (full list can be found in drivers/platform/x86/hp_accel.c) will have
-their axis automatically oriented on standard way (eg: you can directly play
-neverball). The accelerometer data is readable via
-/sys/devices/platform/lis3lv02d. Reported values are scaled
-to mg values (1/1000th of earth gravity).
-
-Sysfs attributes under /sys/devices/platform/lis3lv02d/:
-position - 3D position that the accelerometer reports. Format: "(x,y,z)"
-rate - read reports the sampling rate of the accelerometer device in HZ.
-       write changes sampling rate of the accelerometer device.
-       Only values which are supported by HW are accepted.
-selftest - performs selftest for the chip as specified by chip manufacturer.
-
-This driver also provides an absolute input class device, allowing
-the laptop to act as a pinball machine-esque joystick. Joystick device can be
-calibrated. Joystick device can be in two different modes.
-By default output values are scaled between -32768 .. 32767. In joystick raw
-mode, joystick and sysfs position entry have the same scale. There can be
-small difference due to input system fuzziness feature.
-Events are also available as input event device.
-
-Selftest is meant only for hardware diagnostic purposes. It is not meant to be
-used during normal operations. Position data is not corrupted during selftest
-but interrupt behaviour is not guaranteed to work reliably. In test mode, the
-sensing element is internally moved little bit. Selftest measures difference
-between normal mode and test mode. Chip specifications tell the acceptance
-limit for each type of the chip. Limits are provided via platform data
-to allow adjustment of the limits without a change to the actual driver.
-Seltest returns either "OK x y z" or "FAIL x y z" where x, y and z are
-measured difference between modes. Axes are not remapped in selftest mode.
-Measurement values are provided to help HW diagnostic applications to make
-final decision.
-
-On HP laptops, if the led infrastructure is activated, support for a led
-indicating disk protection will be provided as /sys/class/leds/hp::hddprotect.
-
-Another feature of the driver is misc device called "freefall" that
-acts similar to /dev/rtc and reacts on free-fall interrupts received
-from the device. It supports blocking operations, poll/select and
-fasync operation modes. You must read 1 bytes from the device.  The
-result is number of free-fall interrupts since the last successful
-read (or 255 if number of interrupts would not fit). See the freefall.c
-file for an example on using the device.
-
-
-Axes orientation
-----------------
-
-For better compatibility between the various laptops. The values reported by
-the accelerometer are converted into a "standard" organisation of the axes
-(aka "can play neverball out of the box"):
- * When the laptop is horizontal the position reported is about 0 for X and Y
-       and a positive value for Z
- * If the left side is elevated, X increases (becomes positive)
- * If the front side (where the touchpad is) is elevated, Y decreases
-       (becomes negative)
- * If the laptop is put upside-down, Z becomes negative
-
-If your laptop model is not recognized (cf "dmesg"), you can send an
-email to the maintainer to add it to the database.  When reporting a new
-laptop, please include the output of "dmidecode" plus the value of
-/sys/devices/platform/lis3lv02d/position in these four cases.
-
-Q&A
----
-
-Q: How do I safely simulate freefall? I have an HP "portable
-workstation" which has about 3.5kg and a plastic case, so letting it
-fall to the ground is out of question...
-
-A: The sensor is pretty sensitive, so your hands can do it. Lift it
-into free space, follow the fall with your hands for like 10
-centimeters. That should be enough to trigger the detection.
diff --git a/Documentation/misc-devices/lis3lv02d.rst b/Documentation/misc-devices/lis3lv02d.rst
new file mode 100644 (file)
index 0000000..959bd2b
--- /dev/null
@@ -0,0 +1,99 @@
+=======================
+Kernel driver lis3lv02d
+=======================
+
+Supported chips:
+
+  * STMicroelectronics LIS3LV02DL, LIS3LV02DQ (12 bits precision)
+  * STMicroelectronics LIS302DL, LIS3L02DQ, LIS331DL (8 bits) and
+    LIS331DLH (16 bits)
+
+Authors:
+        - Yan Burman <burman.yan@gmail.com>
+       - Eric Piel <eric.piel@tremplin-utc.net>
+
+
+Description
+-----------
+
+This driver provides support for the accelerometer found in various HP laptops
+sporting the feature officially called "HP Mobile Data Protection System 3D" or
+"HP 3D DriveGuard". It detects automatically laptops with this sensor. Known
+models (full list can be found in drivers/platform/x86/hp_accel.c) will have
+their axis automatically oriented on standard way (eg: you can directly play
+neverball). The accelerometer data is readable via
+/sys/devices/platform/lis3lv02d. Reported values are scaled
+to mg values (1/1000th of earth gravity).
+
+Sysfs attributes under /sys/devices/platform/lis3lv02d/:
+
+position
+      - 3D position that the accelerometer reports. Format: "(x,y,z)"
+rate
+      - read reports the sampling rate of the accelerometer device in HZ.
+       write changes sampling rate of the accelerometer device.
+       Only values which are supported by HW are accepted.
+selftest
+      - performs selftest for the chip as specified by chip manufacturer.
+
+This driver also provides an absolute input class device, allowing
+the laptop to act as a pinball machine-esque joystick. Joystick device can be
+calibrated. Joystick device can be in two different modes.
+By default output values are scaled between -32768 .. 32767. In joystick raw
+mode, joystick and sysfs position entry have the same scale. There can be
+small difference due to input system fuzziness feature.
+Events are also available as input event device.
+
+Selftest is meant only for hardware diagnostic purposes. It is not meant to be
+used during normal operations. Position data is not corrupted during selftest
+but interrupt behaviour is not guaranteed to work reliably. In test mode, the
+sensing element is internally moved little bit. Selftest measures difference
+between normal mode and test mode. Chip specifications tell the acceptance
+limit for each type of the chip. Limits are provided via platform data
+to allow adjustment of the limits without a change to the actual driver.
+Seltest returns either "OK x y z" or "FAIL x y z" where x, y and z are
+measured difference between modes. Axes are not remapped in selftest mode.
+Measurement values are provided to help HW diagnostic applications to make
+final decision.
+
+On HP laptops, if the led infrastructure is activated, support for a led
+indicating disk protection will be provided as /sys/class/leds/hp::hddprotect.
+
+Another feature of the driver is misc device called "freefall" that
+acts similar to /dev/rtc and reacts on free-fall interrupts received
+from the device. It supports blocking operations, poll/select and
+fasync operation modes. You must read 1 bytes from the device.  The
+result is number of free-fall interrupts since the last successful
+read (or 255 if number of interrupts would not fit). See the freefall.c
+file for an example on using the device.
+
+
+Axes orientation
+----------------
+
+For better compatibility between the various laptops. The values reported by
+the accelerometer are converted into a "standard" organisation of the axes
+(aka "can play neverball out of the box"):
+
+ * When the laptop is horizontal the position reported is about 0 for X and Y
+   and a positive value for Z
+ * If the left side is elevated, X increases (becomes positive)
+ * If the front side (where the touchpad is) is elevated, Y decreases
+   (becomes negative)
+ * If the laptop is put upside-down, Z becomes negative
+
+If your laptop model is not recognized (cf "dmesg"), you can send an
+email to the maintainer to add it to the database.  When reporting a new
+laptop, please include the output of "dmidecode" plus the value of
+/sys/devices/platform/lis3lv02d/position in these four cases.
+
+Q&A
+---
+
+Q: How do I safely simulate freefall? I have an HP "portable
+workstation" which has about 3.5kg and a plastic case, so letting it
+fall to the ground is out of question...
+
+A: The sensor is pretty sensitive, so your hands can do it. Lift it
+into free space, follow the fall with your hands for like 10
+centimeters. That should be enough to trigger the detection.
diff --git a/Documentation/misc-devices/max6875 b/Documentation/misc-devices/max6875
deleted file mode 100644 (file)
index 2f2bd0b..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-Kernel driver max6875
-=====================
-
-Supported chips:
-  * Maxim MAX6874, MAX6875
-    Prefix: 'max6875'
-    Addresses scanned: None (see below)
-    Datasheet:
-        http://pdfserv.maxim-ic.com/en/ds/MAX6874-MAX6875.pdf
-
-Author: Ben Gardner <bgardner@wabtec.com>
-
-
-Description
------------
-
-The Maxim MAX6875 is an EEPROM-programmable power-supply sequencer/supervisor.
-It provides timed outputs that can be used as a watchdog, if properly wired.
-It also provides 512 bytes of user EEPROM.
-
-At reset, the MAX6875 reads the configuration EEPROM into its configuration
-registers.  The chip then begins to operate according to the values in the
-registers.
-
-The Maxim MAX6874 is a similar, mostly compatible device, with more inputs
-and outputs:
-             vin     gpi    vout
-MAX6874        6       4       8
-MAX6875        4       3       5
-
-See the datasheet for more information.
-
-
-Sysfs entries
--------------
-
-eeprom        - 512 bytes of user-defined EEPROM space.
-
-
-General Remarks
----------------
-
-Valid addresses for the MAX6875 are 0x50 and 0x52.
-Valid addresses for the MAX6874 are 0x50, 0x52, 0x54 and 0x56.
-The driver does not probe any address, so you explicitly instantiate the
-devices.
-
-Example:
-$ modprobe max6875
-$ echo max6875 0x50 > /sys/bus/i2c/devices/i2c-0/new_device
-
-The MAX6874/MAX6875 ignores address bit 0, so this driver attaches to multiple
-addresses.  For example, for address 0x50, it also reserves 0x51.
-The even-address instance is called 'max6875', the odd one is 'dummy'.
-
-
-Programming the chip using i2c-dev
-----------------------------------
-
-Use the i2c-dev interface to access and program the chips.
-Reads and writes are performed differently depending on the address range.
-
-The configuration registers are at addresses 0x00 - 0x45.
-Use i2c_smbus_write_byte_data() to write a register and
-i2c_smbus_read_byte_data() to read a register.
-The command is the register number.
-
-Examples:
-To write a 1 to register 0x45:
-  i2c_smbus_write_byte_data(fd, 0x45, 1);
-
-To read register 0x45:
-  value = i2c_smbus_read_byte_data(fd, 0x45);
-
-
-The configuration EEPROM is at addresses 0x8000 - 0x8045.
-The user EEPROM is at addresses 0x8100 - 0x82ff.
-
-Use i2c_smbus_write_word_data() to write a byte to EEPROM.
-
-The command is the upper byte of the address: 0x80, 0x81, or 0x82.
-The data word is the lower part of the address or'd with data << 8.
-  cmd = address >> 8;
-  val = (address & 0xff) | (data << 8);
-
-Example:
-To write 0x5a to address 0x8003:
-  i2c_smbus_write_word_data(fd, 0x80, 0x5a03);
-
-
-Reading data from the EEPROM is a little more complicated.
-Use i2c_smbus_write_byte_data() to set the read address and then
-i2c_smbus_read_byte() or i2c_smbus_read_i2c_block_data() to read the data.
-
-Example:
-To read data starting at offset 0x8100, first set the address:
-  i2c_smbus_write_byte_data(fd, 0x81, 0x00);
-
-And then read the data
-  value = i2c_smbus_read_byte(fd);
-
-  or
-
-  count = i2c_smbus_read_i2c_block_data(fd, 0x84, 16, buffer);
-
-The block read should read 16 bytes.
-0x84 is the block read command.
-
-See the datasheet for more details.
-
diff --git a/Documentation/misc-devices/max6875.rst b/Documentation/misc-devices/max6875.rst
new file mode 100644 (file)
index 0000000..ad419ac
--- /dev/null
@@ -0,0 +1,136 @@
+=====================
+Kernel driver max6875
+=====================
+
+Supported chips:
+
+  * Maxim MAX6874, MAX6875
+
+    Prefix: 'max6875'
+
+    Addresses scanned: None (see below)
+
+    Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6874-MAX6875.pdf
+
+Author: Ben Gardner <bgardner@wabtec.com>
+
+
+Description
+-----------
+
+The Maxim MAX6875 is an EEPROM-programmable power-supply sequencer/supervisor.
+It provides timed outputs that can be used as a watchdog, if properly wired.
+It also provides 512 bytes of user EEPROM.
+
+At reset, the MAX6875 reads the configuration EEPROM into its configuration
+registers.  The chip then begins to operate according to the values in the
+registers.
+
+The Maxim MAX6874 is a similar, mostly compatible device, with more inputs
+and outputs:
+
+===========  ===     ===    ====
+-            vin     gpi    vout
+===========  ===     ===    ====
+MAX6874        6       4       8
+MAX6875        4       3       5
+===========  ===     ===    ====
+
+See the datasheet for more information.
+
+
+Sysfs entries
+-------------
+
+eeprom        - 512 bytes of user-defined EEPROM space.
+
+
+General Remarks
+---------------
+
+Valid addresses for the MAX6875 are 0x50 and 0x52.
+
+Valid addresses for the MAX6874 are 0x50, 0x52, 0x54 and 0x56.
+
+The driver does not probe any address, so you explicitly instantiate the
+devices.
+
+Example::
+
+  $ modprobe max6875
+  $ echo max6875 0x50 > /sys/bus/i2c/devices/i2c-0/new_device
+
+The MAX6874/MAX6875 ignores address bit 0, so this driver attaches to multiple
+addresses.  For example, for address 0x50, it also reserves 0x51.
+The even-address instance is called 'max6875', the odd one is 'dummy'.
+
+
+Programming the chip using i2c-dev
+----------------------------------
+
+Use the i2c-dev interface to access and program the chips.
+
+Reads and writes are performed differently depending on the address range.
+
+The configuration registers are at addresses 0x00 - 0x45.
+
+Use i2c_smbus_write_byte_data() to write a register and
+i2c_smbus_read_byte_data() to read a register.
+
+The command is the register number.
+
+Examples:
+
+To write a 1 to register 0x45::
+
+  i2c_smbus_write_byte_data(fd, 0x45, 1);
+
+To read register 0x45::
+
+  value = i2c_smbus_read_byte_data(fd, 0x45);
+
+
+The configuration EEPROM is at addresses 0x8000 - 0x8045.
+
+The user EEPROM is at addresses 0x8100 - 0x82ff.
+
+Use i2c_smbus_write_word_data() to write a byte to EEPROM.
+
+The command is the upper byte of the address: 0x80, 0x81, or 0x82.
+The data word is the lower part of the address or'd with data << 8::
+
+  cmd = address >> 8;
+  val = (address & 0xff) | (data << 8);
+
+Example:
+
+To write 0x5a to address 0x8003::
+
+  i2c_smbus_write_word_data(fd, 0x80, 0x5a03);
+
+
+Reading data from the EEPROM is a little more complicated.
+
+Use i2c_smbus_write_byte_data() to set the read address and then
+i2c_smbus_read_byte() or i2c_smbus_read_i2c_block_data() to read the data.
+
+Example:
+
+To read data starting at offset 0x8100, first set the address::
+
+  i2c_smbus_write_byte_data(fd, 0x81, 0x00);
+
+And then read the data::
+
+  value = i2c_smbus_read_byte(fd);
+
+or::
+
+  count = i2c_smbus_read_i2c_block_data(fd, 0x84, 16, buffer);
+
+The block read should read 16 bytes.
+
+0x84 is the block read command.
+
+See the datasheet for more details.
+
diff --git a/Documentation/misc-devices/mei/mei-client-bus.txt b/Documentation/misc-devices/mei/mei-client-bus.txt
deleted file mode 100644 (file)
index 743be4e..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-Intel(R) Management Engine (ME) Client bus API
-==============================================
-
-
-Rationale
-=========
-
-MEI misc character device is useful for dedicated applications to send and receive
-data to the many FW appliance found in Intel's ME from the user space.
-However for some of the ME functionalities it make sense to leverage existing software
-stack and expose them through existing kernel subsystems.
-
-In order to plug seamlessly into the kernel device driver model we add kernel virtual
-bus abstraction on top of the MEI driver. This allows implementing linux kernel drivers
-for the various MEI features as a stand alone entities found in their respective subsystem.
-Existing device drivers can even potentially be re-used by adding an MEI CL bus layer to
-the existing code.
-
-
-MEI CL bus API
-==============
-
-A driver implementation for an MEI Client is very similar to existing bus
-based device drivers. The driver registers itself as an MEI CL bus driver through
-the mei_cl_driver structure:
-
-struct mei_cl_driver {
-       struct device_driver driver;
-       const char *name;
-
-       const struct mei_cl_device_id *id_table;
-
-       int (*probe)(struct mei_cl_device *dev, const struct mei_cl_id *id);
-       int (*remove)(struct mei_cl_device *dev);
-};
-
-struct mei_cl_id {
-       char name[MEI_NAME_SIZE];
-       kernel_ulong_t driver_info;
-};
-
-The mei_cl_id structure allows the driver to bind itself against a device name.
-
-To actually register a driver on the ME Client bus one must call the mei_cl_add_driver()
-API. This is typically called at module init time.
-
-Once registered on the ME Client bus, a driver will typically try to do some I/O on
-this bus and this should be done through the mei_cl_send() and mei_cl_recv()
-routines. The latter is synchronous (blocks and sleeps until data shows up).
-In order for drivers to be notified of pending events waiting for them (e.g.
-an Rx event) they can register an event handler through the
-mei_cl_register_event_cb() routine. Currently only the MEI_EVENT_RX event
-will trigger an event handler call and the driver implementation is supposed
-to call mei_recv() from the event handler in order to fetch the pending
-received buffers.
-
-
-Example
-=======
-
-As a theoretical example let's pretend the ME comes with a "contact" NFC IP.
-The driver init and exit routines for this device would look like:
-
-#define CONTACT_DRIVER_NAME "contact"
-
-static struct mei_cl_device_id contact_mei_cl_tbl[] = {
-       { CONTACT_DRIVER_NAME, },
-
-       /* required last entry */
-       { }
-};
-MODULE_DEVICE_TABLE(mei_cl, contact_mei_cl_tbl);
-
-static struct mei_cl_driver contact_driver = {
-       .id_table = contact_mei_tbl,
-       .name = CONTACT_DRIVER_NAME,
-
-       .probe = contact_probe,
-       .remove = contact_remove,
-};
-
-static int contact_init(void)
-{
-       int r;
-
-       r = mei_cl_driver_register(&contact_driver);
-       if (r) {
-               pr_err(CONTACT_DRIVER_NAME ": driver registration failed\n");
-               return r;
-       }
-
-       return 0;
-}
-
-static void __exit contact_exit(void)
-{
-       mei_cl_driver_unregister(&contact_driver);
-}
-
-module_init(contact_init);
-module_exit(contact_exit);
-
-And the driver's simplified probe routine would look like that:
-
-int contact_probe(struct mei_cl_device *dev, struct mei_cl_device_id *id)
-{
-       struct contact_driver *contact;
-
-       [...]
-       mei_cl_enable_device(dev);
-
-       mei_cl_register_event_cb(dev, contact_event_cb, contact);
-
-       return 0;
-}
-
-In the probe routine the driver first enable the MEI device and then registers
-an ME bus event handler which is as close as it can get to registering a
-threaded IRQ handler.
-The handler implementation will typically call some I/O routine depending on
-the pending events:
-
-#define MAX_NFC_PAYLOAD 128
-
-static void contact_event_cb(struct mei_cl_device *dev, u32 events,
-                            void *context)
-{
-       struct contact_driver *contact = context;
-
-       if (events & BIT(MEI_EVENT_RX)) {
-               u8 payload[MAX_NFC_PAYLOAD];
-               int payload_size;
-
-               payload_size = mei_recv(dev, payload, MAX_NFC_PAYLOAD);
-               if (payload_size <= 0)
-                       return;
-
-               /* Hook to the NFC subsystem */
-               nfc_hci_recv_frame(contact->hdev, payload, payload_size);
-       }
-}
diff --git a/Documentation/misc-devices/mei/mei.txt b/Documentation/misc-devices/mei/mei.txt
deleted file mode 100644 (file)
index 2b80a0c..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-Intel(R) Management Engine Interface (Intel(R) MEI)
-===================================================
-
-Introduction
-============
-
-The Intel Management Engine (Intel ME) is an isolated and protected computing
-resource (Co-processor) residing inside certain Intel chipsets. The Intel ME
-provides support for computer/IT management features. The feature set
-depends on the Intel chipset SKU.
-
-The Intel Management Engine Interface (Intel MEI, previously known as HECI)
-is the interface between the Host and Intel ME. This interface is exposed
-to the host as a PCI device. The Intel MEI Driver is in charge of the
-communication channel between a host application and the Intel ME feature.
-
-Each Intel ME feature (Intel ME Client) is addressed by a GUID/UUID and
-each client has its own protocol. The protocol is message-based with a
-header and payload up to 512 bytes.
-
-Prominent usage of the Intel ME Interface is to communicate with Intel(R)
-Active Management Technology (Intel AMT) implemented in firmware running on
-the Intel ME.
-
-Intel AMT provides the ability to manage a host remotely out-of-band (OOB)
-even when the operating system running on the host processor has crashed or
-is in a sleep state.
-
-Some examples of Intel AMT usage are:
-   - Monitoring hardware state and platform components
-   - Remote power off/on (useful for green computing or overnight IT
-     maintenance)
-   - OS updates
-   - Storage of useful platform information such as software assets
-   - Built-in hardware KVM
-   - Selective network isolation of Ethernet and IP protocol flows based
-     on policies set by a remote management console
-   - IDE device redirection from remote management console
-
-Intel AMT (OOB) communication is based on SOAP (deprecated
-starting with Release 6.0) over HTTP/S or WS-Management protocol over
-HTTP/S that are received from a remote management console application.
-
-For more information about Intel AMT:
-http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide
-
-
-Intel MEI Driver
-================
-
-The driver exposes a misc device called /dev/mei.
-
-An application maintains communication with an Intel ME feature while
-/dev/mei is open. The binding to a specific feature is performed by calling
-MEI_CONNECT_CLIENT_IOCTL, which passes the desired UUID.
-The number of instances of an Intel ME feature that can be opened
-at the same time depends on the Intel ME feature, but most of the
-features allow only a single instance.
-
-The Intel AMT Host Interface (Intel AMTHI) feature supports multiple
-simultaneous user connected applications. The Intel MEI driver
-handles this internally by maintaining request queues for the applications.
-
-The driver is transparent to data that are passed between firmware feature
-and host application.
-
-Because some of the Intel ME features can change the system
-configuration, the driver by default allows only a privileged
-user to access it.
-
-A code snippet for an application communicating with Intel AMTHI client:
-
-       struct mei_connect_client_data data;
-       fd = open(MEI_DEVICE);
-
-       data.d.in_client_uuid = AMTHI_UUID;
-
-       ioctl(fd, IOCTL_MEI_CONNECT_CLIENT, &data);
-
-       printf("Ver=%d, MaxLen=%ld\n",
-                       data.d.in_client_uuid.protocol_version,
-                       data.d.in_client_uuid.max_msg_length);
-
-       [...]
-
-       write(fd, amthi_req_data, amthi_req_data_len);
-
-       [...]
-
-       read(fd, &amthi_res_data, amthi_res_data_len);
-
-       [...]
-       close(fd);
-
-
-IOCTL
-=====
-
-The Intel MEI Driver supports the following IOCTL commands:
-       IOCTL_MEI_CONNECT_CLIENT        Connect to firmware Feature (client).
-
-       usage:
-               struct mei_connect_client_data clientData;
-               ioctl(fd, IOCTL_MEI_CONNECT_CLIENT, &clientData);
-
-       inputs:
-               mei_connect_client_data struct contain the following
-               input field:
-
-               in_client_uuid -        UUID of the FW Feature that needs
-                                       to connect to.
-       outputs:
-               out_client_properties - Client Properties: MTU and Protocol Version.
-
-       error returns:
-               EINVAL  Wrong IOCTL Number
-               ENODEV  Device or Connection is not initialized or ready.
-                       (e.g. Wrong UUID)
-               ENOMEM  Unable to allocate memory to client internal data.
-               EFAULT  Fatal Error (e.g. Unable to access user input data)
-               EBUSY   Connection Already Open
-
-       Notes:
-        max_msg_length (MTU) in client properties describes the maximum
-        data that can be sent or received. (e.g. if MTU=2K, can send
-        requests up to bytes 2k and received responses up to 2k bytes).
-
-       IOCTL_MEI_NOTIFY_SET: enable or disable event notifications
-
-       Usage:
-               uint32_t enable;
-               ioctl(fd, IOCTL_MEI_NOTIFY_SET, &enable);
-
-       Inputs:
-               uint32_t enable = 1;
-               or
-               uint32_t enable[disable] = 0;
-
-       Error returns:
-               EINVAL  Wrong IOCTL Number
-               ENODEV  Device  is not initialized or the client not connected
-               ENOMEM  Unable to allocate memory to client internal data.
-               EFAULT  Fatal Error (e.g. Unable to access user input data)
-               EOPNOTSUPP if the device doesn't support the feature
-
-       Notes:
-       The client must be connected in order to enable notification events
-
-
-       IOCTL_MEI_NOTIFY_GET : retrieve event
-
-       Usage:
-               uint32_t event;
-               ioctl(fd, IOCTL_MEI_NOTIFY_GET, &event);
-
-       Outputs:
-               1 - if an event is pending
-               0 - if there is no even pending
-
-       Error returns:
-               EINVAL  Wrong IOCTL Number
-               ENODEV  Device is not initialized or the client not connected
-               ENOMEM  Unable to allocate memory to client internal data.
-               EFAULT  Fatal Error (e.g. Unable to access user input data)
-               EOPNOTSUPP if the device doesn't support the feature
-
-       Notes:
-       The client must be connected and event notification has to be enabled
-       in order to receive an event
-
-
-Intel ME Applications
-=====================
-
-       1) Intel Local Management Service (Intel LMS)
-
-          Applications running locally on the platform communicate with Intel AMT Release
-          2.0 and later releases in the same way that network applications do via SOAP
-          over HTTP (deprecated starting with Release 6.0) or with WS-Management over
-          SOAP over HTTP. This means that some Intel AMT features can be accessed from a
-          local application using the same network interface as a remote application
-          communicating with Intel AMT over the network.
-
-          When a local application sends a message addressed to the local Intel AMT host
-          name, the Intel LMS, which listens for traffic directed to the host name,
-          intercepts the message and routes it to the Intel MEI.
-          For more information:
-          http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide
-          Under "About Intel AMT" => "Local Access"
-
-          For downloading Intel LMS:
-          http://software.intel.com/en-us/articles/download-the-latest-intel-amt-open-source-drivers/
-
-          The Intel LMS opens a connection using the Intel MEI driver to the Intel LMS
-          firmware feature using a defined UUID and then communicates with the feature
-          using a protocol called Intel AMT Port Forwarding Protocol (Intel APF protocol).
-          The protocol is used to maintain multiple sessions with Intel AMT from a
-          single application.
-
-          See the protocol specification in the Intel AMT Software Development Kit (SDK)
-          http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide
-          Under "SDK Resources" => "Intel(R) vPro(TM) Gateway (MPS)"
-          => "Information for Intel(R) vPro(TM) Gateway Developers"
-          => "Description of the Intel AMT Port Forwarding (APF) Protocol"
-
-       2) Intel AMT Remote configuration using a Local Agent
-
-          A Local Agent enables IT personnel to configure Intel AMT out-of-the-box
-          without requiring installing additional data to enable setup. The remote
-          configuration process may involve an ISV-developed remote configuration
-          agent that runs on the host.
-          For more information:
-          http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide
-          Under "Setup and Configuration of Intel AMT" =>
-          "SDK Tools Supporting Setup and Configuration" =>
-          "Using the Local Agent Sample"
-
-          An open source Intel AMT configuration utility,      implementing a local agent
-          that accesses the Intel MEI driver, can be found here:
-          http://software.intel.com/en-us/articles/download-the-latest-intel-amt-open-source-drivers/
-
-
-Intel AMT OS Health Watchdog
-============================
-
-The Intel AMT Watchdog is an OS Health (Hang/Crash) watchdog.
-Whenever the OS hangs or crashes, Intel AMT will send an event
-to any subscriber to this event. This mechanism means that
-IT knows when a platform crashes even when there is a hard failure on the host.
-
-The Intel AMT Watchdog is composed of two parts:
-       1) Firmware feature - receives the heartbeats
-          and sends an event when the heartbeats stop.
-       2) Intel MEI iAMT watchdog driver - connects to the watchdog feature,
-          configures the watchdog and sends the heartbeats.
-
-The Intel iAMT watchdog MEI driver uses the kernel watchdog API to configure
-the Intel AMT Watchdog and to send heartbeats to it. The default timeout of the
-watchdog is 120 seconds.
-
-If the Intel AMT is not enabled in the firmware then the watchdog client won't enumerate
-on the me client bus and watchdog devices won't be exposed.
-
-
-Supported Chipsets
-==================
-
-7 Series Chipset Family
-6 Series Chipset Family
-5 Series Chipset Family
-4 Series Chipset Family
-Mobile 4 Series Chipset Family
-ICH9
-82946GZ/GL
-82G35 Express
-82Q963/Q965
-82P965/G965
-Mobile PM965/GM965
-Mobile GME965/GLE960
-82Q35 Express
-82G33/G31/P35/P31 Express
-82Q33 Express
-82X38/X48 Express
-
----
-linux-mei@linux.intel.com
diff --git a/Documentation/scsi/osst.txt b/Documentation/scsi/osst.txt
deleted file mode 100644 (file)
index 00c8ebb..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-README file for the osst driver
-===============================
-(w) Kurt Garloff <garloff@suse.de> 12/2000
-
-This file describes the osst driver as of version 0.8.x/0.9.x, the released
-version of the osst driver.
-It is intended to help advanced users to understand the role of osst and to
-get them started using (and maybe debugging) it.
-It won't address issues like "How do I compile a kernel?" or "How do I load
-a module?", as these are too basic.
-Once the OnStream got merged into the official kernel, the distro makers
-will provide the OnStream support for those who are not familiar with
-hacking their kernels.
-
-
-Purpose
--------
-The osst driver was developed, because the standard SCSI tape driver in
-Linux, st, does not support the OnStream SC-x0 SCSI tape. The st is not to
-blame for that, as the OnStream tape drives do not support the standard SCSI
-command set for Serial Access Storage Devices (SASDs), which basically
-corresponds to the QIC-157 spec.
-Nevertheless, the OnStream tapes are nice pieces of hardware and therefore
-the osst driver has been written to make these tape devs supported by Linux.
-The driver is free software. It's released under the GNU GPL and planned to
-be integrated into the mainstream kernel.
-
-
-Implementation
---------------
-The osst is a new high-level SCSI driver, just like st, sr, sd and sg. It
-can be compiled into the kernel or loaded as a module.
-As it represents a new device, it got assigned a new device node: /dev/osstX
-are character devices with major no 206 and minor numbers like the /dev/stX
-devices. If those are not present, you may create them by calling
-Makedevs.sh as root (see below).
-The driver started being a copy of st and as such, the osst devices'
-behavior looks very much the same as st to the userspace applications.
-
-
-History
--------
-In the first place, osst shared its identity very much with st. That meant
-that it used the same kernel structures and the same device node as st.
-So you could only have either of them being present in the kernel. This has
-been fixed by registering an own device, now.
-st and osst can coexist, each only accessing the devices it can support by
-themselves.
-
-
-Installation
-------------
-osst got integrated into the linux kernel. Select it during kernel
-configuration as module or compile statically into the kernel.
-Compile your kernel and install the modules.
-
-Now, your osst driver is inside the kernel or available as a module,
-depending on your choice during kernel config. You may still need to create
-the device nodes by calling the Makedevs.sh script (see below) manually.
-
-To load your module, you may use the command 
-modprobe osst
-as root. dmesg should show you, whether your OnStream tapes have been
-recognized.
-
-If you want to have the module autoloaded on access to /dev/osst, you may
-add something like
-alias char-major-206 osst
-to a file under /etc/modprobe.d/ directory.
-
-You may find it convenient to create a symbolic link 
-ln -s nosst0 /dev/tape
-to make programs assuming a default name of /dev/tape more convenient to
-use.
-
-The device nodes for osst have to be created. Use the Makedevs.sh script
-attached to this file.
-
-
-Using it
---------
-You may use the OnStream tape driver with your standard backup software,
-which may be tar, cpio, amanda, arkeia, BRU, Lone Tar, ...
-by specifying /dev/(n)osst0 as the tape device to use or using the above
-symlink trick. The IOCTLs to control tape operation are also mostly
-supported and you may try the mt (or mt_st) program to jump between
-filemarks, eject the tape, ...
-
-There's one limitation: You need to use a block size of 32kB.
-
-(This limitation is worked on and will be fixed in version 0.8.8 of
- this driver.)
-
-If you just want to get started with standard software, here is an example
-for creating and restoring a full backup:
-# Backup
-tar cvf - / --exclude /proc | buffer -s 32k -m 24M -B -t -o /dev/nosst0
-# Restore
-buffer -s 32k -m 8M -B -t -i /dev/osst0 | tar xvf - -C /
-
-The buffer command has been used to buffer the data before it goes to the
-tape (or the file system) in order to smooth out the data stream and prevent
-the tape from needing to stop and rewind. The OnStream does have an internal
-buffer and a variable speed which help this, but especially on writing, the
-buffering still proves useful in most cases. It also pads the data to
-guarantees the block size of 32k. (Otherwise you may pass the -b64 option to
-tar.)
-Expect something like 1.8MB/s for the SC-x0 drives and 0.9MB/s for the DI-30.
-The USB drive will give you about 0.7MB/s.
-On a fast machine, you may profit from software data compression (z flag for
-tar).
-
-
-USB and IDE
------------
-Via the SCSI emulation layers usb-storage and ide-scsi, you can also use the
-osst driver to drive the USB-30 and the DI-30 drives. (Unfortunately, there
-is no such layer for the parallel port, otherwise the DP-30 would work as
-well.) For the USB support, you need the latest 2.4.0-test kernels and the 
-latest usb-storage driver from 
-http://www.linux-usb.org/
-http://sourceforge.net/cvs/?group_id=3581
-
-Note that the ide-tape driver as of 1.16f uses a slightly outdated on-tape
-format and therefore is not completely interoperable with osst tapes.
-
-The ADR-x0 line is fully SCSI-2 compliant and is supported by st, not osst.
-The on-tape format is supposed to be compatible with the one used by osst.
-
-
-Feedback and updates
---------------------
-The driver development is coordinated through a mailing list
-<osst@linux1.onstream.nl>
-a CVS repository and some web pages. 
-The tester's pages which contain recent news and updated drivers to download
-can be found on
-http://sourceforge.net/projects/osst/
-
-If you find any problems, please have a look at the tester's page in order
-to see whether the problem is already known and solved. Otherwise, please
-report it to the mailing list. Your feedback is welcome. (This holds also
-for reports of successful usage, of course.) 
-In case of trouble, please do always provide the following info:
-* driver and kernel version used (see syslog)
-* driver messages (syslog)
-* SCSI config and OnStream Firmware (/proc/scsi/scsi)
-* description of error. Is it reproducible?
-* software and commands used
-
-You may subscribe to the mailing list, BTW, it's a majordomo list.
-
-
-Status
-------
-0.8.0 was the first widespread BETA release. Since then a lot of reports
-have been sent, but mostly reported success or only minor trouble.
-All the issues have been addressed.
-Check the web pages for more info about the current developments.
-0.9.x is the tree for the 2.3/2.4 kernel.
-
-
-Acknowledgments
-----------------
-The driver has been started by making a copy of Kai Makisara's st driver.
-Most of the development has been done by Willem Riede. The presence of the
-userspace program osg (onstreamsg) from Terry Hardie has been rather
-helpful. The same holds for Gadi Oxman's ide-tape support for the DI-30.
-I did add some patches to those drivers as well and coordinated things a
-little bit. 
-Note that most of them did mostly spend their spare time for the creation of
-this driver.
-The people from OnStream, especially Jack Bombeeck did support this project
-and always tried to answer HW or FW related questions. Furthermore, he
-pushed the FW developers to do the right things.
-SuSE did support this project by allowing me to work on it during my working
-time for them and by integrating the driver into their distro.
-
-More people did help by sending useful comments. Sorry to those who have
-been forgotten. Thanks to all the GNU/FSF and Linux developers who made this
-platform such an interesting, nice and stable platform.
-Thanks go to those who tested the drivers and did send useful reports. Your
-help is needed!
-
-
-Makedevs.sh
------------
-#!/bin/sh
-# Script to create OnStream SC-x0 device nodes (major 206)
-# Usage: Makedevs.sh [nos [path to dev]]
-# $Id: README.osst.kernel,v 1.4 2000/12/20 14:13:15 garloff Exp $
-major=206
-nrs=4
-dir=/dev
-test -z "$1" || nrs=$1
-test -z "$2" || dir=$2
-declare -i nr
-nr=0
-test -d $dir || mkdir -p $dir
-while test $nr -lt $nrs; do
-  mknod $dir/osst$nr c $major $nr
-  chown 0.disk $dir/osst$nr; chmod 660 $dir/osst$nr;
-  mknod $dir/nosst$nr c $major $[nr+128]
-  chown 0.disk $dir/nosst$nr; chmod 660 $dir/nosst$nr;
-  mknod $dir/osst${nr}l c $major $[nr+32]
-  chown 0.disk $dir/osst${nr}l; chmod 660 $dir/osst${nr}l;
-  mknod $dir/nosst${nr}l c $major $[nr+160]
-  chown 0.disk $dir/nosst${nr}l; chmod 660 $dir/nosst${nr}l;
-  mknod $dir/osst${nr}m c $major $[nr+64]
-  chown 0.disk $dir/osst${nr}m; chmod 660 $dir/osst${nr}m;
-  mknod $dir/nosst${nr}m c $major $[nr+192]
-  chown 0.disk $dir/nosst${nr}m; chmod 660 $dir/nosst${nr}m;
-  mknod $dir/osst${nr}a c $major $[nr+96]
-  chown 0.disk $dir/osst${nr}a; chmod 660 $dir/osst${nr}a;
-  mknod $dir/nosst${nr}a c $major $[nr+224]
-  chown 0.disk $dir/nosst${nr}a; chmod 660 $dir/nosst${nr}a;
-  let nr+=1
-done
index 1769f71..81842ec 100644 (file)
@@ -158,6 +158,13 @@ send SG_IO with the applicable sg_io_v4:
 If you wish to read or write a descriptor, use the appropriate xferp of
 sg_io_v4.
 
+The userspace tool that interacts with the ufs-bsg endpoint and uses its
+upiu-based protocol is available at:
+
+       https://github.com/westerndigitalcorporation/ufs-tool
+
+For more detailed information about the tool and its supported
+features, please see the tool's README.
 
 UFS Specifications can be found at,
 UFS - http://www.jedec.org/sites/default/files/docs/JESD220.pdf
index 3bfbf66..4e373d1 100644 (file)
@@ -236,7 +236,7 @@ AArch64 内核当前没有提供自解压代码,因此如果使用了压缩内
   *译者注: ARM DEN 0022A 已更新到 ARM DEN 0022C。
 
   设备树必须包含一个 ‘psci’ 节点,请参考以下文档:
-  Documentation/devicetree/bindings/arm/psci.txt
+  Documentation/devicetree/bindings/arm/psci.yaml
 
 
 - 辅助 CPU 通用寄存器设置
diff --git a/Documentation/usb/WUSB-Design-overview.txt b/Documentation/usb/WUSB-Design-overview.txt
deleted file mode 100644 (file)
index dc5e216..0000000
+++ /dev/null
@@ -1,457 +0,0 @@
-================================
-Linux UWB + Wireless USB + WiNET
-================================
-
-   Copyright (C) 2005-2006 Intel Corporation
-
-   Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.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 Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-
-Please visit http://bughost.org/thewiki/Design-overview.txt-1.8 for
-updated content.
-
-    * Design-overview.txt-1.8
-
-This code implements a Ultra Wide Band stack for Linux, as well as
-drivers for the USB based UWB radio controllers defined in the
-Wireless USB 1.0 specification (including Wireless USB host controller
-and an Intel WiNET controller).
-
-.. Contents
-   1. Introduction
-         1. HWA: Host Wire adapters, your Wireless USB dongle
-
-         2. DWA: Device Wired Adaptor, a Wireless USB hub for wired
-            devices
-         3. WHCI: Wireless Host Controller Interface, the PCI WUSB host
-            adapter
-   2. The UWB stack
-         1. Devices and hosts: the basic structure
-
-         2. Host Controller life cycle
-
-         3. On the air: beacons and enumerating the radio neighborhood
-
-         4. Device lists
-         5. Bandwidth allocation
-
-   3. Wireless USB Host Controller drivers
-
-   4. Glossary
-
-
-Introduction
-============
-
-UWB is a wide-band communication protocol that is to serve also as the
-low-level protocol for others (much like TCP sits on IP). Currently
-these others are Wireless USB and TCP/IP, but seems Bluetooth and
-Firewire/1394 are coming along.
-
-UWB uses a band from roughly 3 to 10 GHz, transmitting at a max of
-~-41dB (or 0.074 uW/MHz--geography specific data is still being
-negotiated w/ regulators, so watch for changes). That band is divided in
-a bunch of ~1.5 GHz wide channels (or band groups) composed of three
-subbands/subchannels (528 MHz each). Each channel is independent of each
-other, so you could consider them different "busses". Initially this
-driver considers them all a single one.
-
-Radio time is divided in 65536 us long /superframes/, each one divided
-in 256 256us long /MASs/ (Media Allocation Slots), which are the basic
-time/media allocation units for transferring data. At the beginning of
-each superframe there is a Beacon Period (BP), where every device
-transmit its beacon on a single MAS. The length of the BP depends on how
-many devices are present and the length of their beacons.
-
-Devices have a MAC (fixed, 48 bit address) and a device (changeable, 16
-bit address) and send periodic beacons to advertise themselves and pass
-info on what they are and do. They advertise their capabilities and a
-bunch of other stuff.
-
-The different logical parts of this driver are:
-
-    *
-
-      *UWB*: the Ultra-Wide-Band stack -- manages the radio and
-      associated spectrum to allow for devices sharing it. Allows to
-      control bandwidth assignment, beaconing, scanning, etc
-
-    *
-
-      *WUSB*: the layer that sits on top of UWB to provide Wireless USB.
-      The Wireless USB spec defines means to control a UWB radio and to
-      do the actual WUSB.
-
-
-HWA: Host Wire adapters, your Wireless USB dongle
--------------------------------------------------
-
-WUSB also defines a device called a Host Wire Adaptor (HWA), which in
-mere terms is a USB dongle that enables your PC to have UWB and Wireless
-USB. The Wireless USB Host Controller in a HWA looks to the host like a
-[Wireless] USB controller connected via USB (!)
-
-The HWA itself is broken in two or three main interfaces:
-
-    *
-
-      *RC*: Radio control -- this implements an interface to the
-      Ultra-Wide-Band radio controller. The driver for this implements a
-      USB-based UWB Radio Controller to the UWB stack.
-
-    *
-
-      *HC*: the wireless USB host controller. It looks like a USB host
-      whose root port is the radio and the WUSB devices connect to it.
-      To the system it looks like a separate USB host. The driver (will)
-      implement a USB host controller (similar to UHCI, OHCI or EHCI)
-      for which the root hub is the radio...To reiterate: it is a USB
-      controller that is connected via USB instead of PCI.
-
-    *
-
-      *WINET*: some HW provide a WiNET interface (IP over UWB). This
-      package provides a driver for it (it looks like a network
-      interface, winetX). The driver detects when there is a link up for
-      their type and kick into gear.
-
-
-DWA: Device Wired Adaptor, a Wireless USB hub for wired devices
----------------------------------------------------------------
-
-These are the complement to HWAs. They are a USB host for connecting
-wired devices, but it is connected to your PC connected via Wireless
-USB. To the system it looks like yet another USB host. To the untrained
-eye, it looks like a hub that connects upstream wirelessly.
-
-We still offer no support for this; however, it should share a lot of
-code with the HWA-RC driver; there is a bunch of factorization work that
-has been done to support that in upcoming releases.
-
-
-WHCI: Wireless Host Controller Interface, the PCI WUSB host adapter
--------------------------------------------------------------------
-
-This is your usual PCI device that implements WHCI. Similar in concept
-to EHCI, it allows your wireless USB devices (including DWAs) to connect
-to your host via a PCI interface. As in the case of the HWA, it has a
-Radio Control interface and the WUSB Host Controller interface per se.
-
-There is still no driver support for this, but will be in upcoming
-releases.
-
-
-The UWB stack
-=============
-
-The main mission of the UWB stack is to keep a tally of which devices
-are in radio proximity to allow drivers to connect to them. As well, it
-provides an API for controlling the local radio controllers (RCs from
-now on), such as to start/stop beaconing, scan, allocate bandwidth, etc.
-
-
-Devices and hosts: the basic structure
---------------------------------------
-
-The main building block here is the UWB device (struct uwb_dev). For
-each device that pops up in radio presence (ie: the UWB host receives a
-beacon from it) you get a struct uwb_dev that will show up in
-/sys/bus/uwb/devices.
-
-For each RC that is detected, a new struct uwb_rc and struct uwb_dev are
-created. An entry is also created in /sys/class/uwb_rc for each RC.
-
-Each RC driver is implemented by a separate driver that plugs into the
-interface that the UWB stack provides through a struct uwb_rc_ops. The
-spec creators have been nice enough to make the message format the same
-for HWA and WHCI RCs, so the driver is really a very thin transport that
-moves the requests from the UWB API to the device [/uwb_rc_ops->cmd()/]
-and sends the replies and notifications back to the API
-[/uwb_rc_neh_grok()/]. Notifications are handled to the UWB daemon, that
-is chartered, among other things, to keep the tab of how the UWB radio
-neighborhood looks, creating and destroying devices as they show up or
-disappear.
-
-Command execution is very simple: a command block is sent and a event
-block or reply is expected back. For sending/receiving command/events, a
-handle called /neh/ (Notification/Event Handle) is opened with
-/uwb_rc_neh_open()/.
-
-The HWA-RC (USB dongle) driver (drivers/uwb/hwa-rc.c) does this job for
-the USB connected HWA. Eventually, drivers/whci-rc.c will do the same
-for the PCI connected WHCI controller.
-
-
-Host Controller life cycle
---------------------------
-
-So let's say we connect a dongle to the system: it is detected and
-firmware uploaded if needed [for Intel's i1480
-/drivers/uwb/ptc/usb.c:ptc_usb_probe()/] and then it is reenumerated.
-Now we have a real HWA device connected and
-/drivers/uwb/hwa-rc.c:hwarc_probe()/ picks it up, that will set up the
-Wire-Adaptor environment and then suck it into the UWB stack's vision of
-the world [/drivers/uwb/lc-rc.c:uwb_rc_add()/].
-
-    *
-
-      [*] The stack should put a new RC to scan for devices
-      [/uwb_rc_scan()/] so it finds what's available around and tries to
-      connect to them, but this is policy stuff and should be driven
-      from user space. As of now, the operator is expected to do it
-      manually; see the release notes for documentation on the procedure.
-
-When a dongle is disconnected, /drivers/uwb/hwa-rc.c:hwarc_disconnect()/
-takes time of tearing everything down safely (or not...).
-
-
-On the air: beacons and enumerating the radio neighborhood
-----------------------------------------------------------
-
-So assuming we have devices and we have agreed for a channel to connect
-on (let's say 9), we put the new RC to beacon:
-
-    *
-
-            $ echo 9 0 > /sys/class/uwb_rc/uwb0/beacon
-
-Now it is visible. If there were other devices in the same radio channel
-and beacon group (that's what the zero is for), the dongle's radio
-control interface will send beacon notifications on its
-notification/event endpoint (NEEP). The beacon notifications are part of
-the event stream that is funneled into the API with
-/drivers/uwb/neh.c:uwb_rc_neh_grok()/ and delivered to the UWBD, the UWB
-daemon through a notification list.
-
-UWBD wakes up and scans the event list; finds a beacon and adds it to
-the BEACON CACHE (/uwb_beca/). If he receives a number of beacons from
-the same device, he considers it to be 'onair' and creates a new device
-[/drivers/uwb/lc-dev.c:uwbd_dev_onair()/]. Similarly, when no beacons
-are received in some time, the device is considered gone and wiped out
-[uwbd calls periodically /uwb/beacon.c:uwb_beca_purge()/ that will purge
-the beacon cache of dead devices].
-
-
-Device lists
-------------
-
-All UWB devices are kept in the list of the struct bus_type uwb_bus_type.
-
-
-Bandwidth allocation
---------------------
-
-The UWB stack maintains a local copy of DRP availability through
-processing of incoming *DRP Availability Change* notifications. This
-local copy is currently used to present the current bandwidth
-availability to the user through the sysfs file
-/sys/class/uwb_rc/uwbx/bw_avail. In the future the bandwidth
-availability information will be used by the bandwidth reservation
-routines.
-
-The bandwidth reservation routines are in progress and are thus not
-present in the current release. When completed they will enable a user
-to initiate DRP reservation requests through interaction with sysfs. DRP
-reservation requests from remote UWB devices will also be handled. The
-bandwidth management done by the UWB stack will include callbacks to the
-higher layers will enable the higher layers to use the reservations upon
-completion. [Note: The bandwidth reservation work is in progress and
-subject to change.]
-
-
-Wireless USB Host Controller drivers
-====================================
-
-*WARNING* This section needs a lot of work!
-
-As explained above, there are three different types of HCs in the WUSB
-world: HWA-HC, DWA-HC and WHCI-HC.
-
-HWA-HC and DWA-HC share that they are Wire-Adapters (USB or WUSB
-connected controllers), and their transfer management system is almost
-identical. So is their notification delivery system.
-
-HWA-HC and WHCI-HC share that they are both WUSB host controllers, so
-they have to deal with WUSB device life cycle and maintenance, wireless
-root-hub
-
-HWA exposes a Host Controller interface (HWA-HC 0xe0/02/02). This has
-three endpoints (Notifications, Data Transfer In and Data Transfer
-Out--known as NEP, DTI and DTO in the code).
-
-We reserve UWB bandwidth for our Wireless USB Cluster, create a Cluster
-ID and tell the HC to use all that. Then we start it. This means the HC
-starts sending MMCs.
-
-    *
-
-      The MMCs are blocks of data defined somewhere in the WUSB1.0 spec
-      that define a stream in the UWB channel time allocated for sending
-      WUSB IEs (host to device commands/notifications) and Device
-      Notifications (device initiated to host). Each host defines a
-      unique Wireless USB cluster through MMCs. Devices can connect to a
-      single cluster at the time. The IEs are Information Elements, and
-      among them are the bandwidth allocations that tell each device
-      when can they transmit or receive.
-
-Now it all depends on external stimuli.
-
-New device connection
----------------------
-
-A new device pops up, it scans the radio looking for MMCs that give out
-the existence of Wireless USB channels. Once one (or more) are found,
-selects which one to connect to. Sends a /DN_Connect/ (device
-notification connect) during the DNTS (Device Notification Time
-Slot--announced in the MMCs
-
-HC picks the /DN_Connect/ out (nep module sends to notif.c for delivery
-into /devconnect/). This process starts the authentication process for
-the device. First we allocate a /fake port/ and assign an
-unauthenticated address (128 to 255--what we really do is
-0x80 | fake_port_idx). We fiddle with the fake port status and /hub_wq/
-sees a new connection, so he moves on to enable the fake port with a reset.
-
-So now we are in the reset path -- we know we have a non-yet enumerated
-device with an unauthorized address; we ask user space to authenticate
-(FIXME: not yet done, similar to bluetooth pairing), then we do the key
-exchange (FIXME: not yet done) and issue a /set address 0/ to bring the
-device to the default state. Device is authenticated.
-
-From here, the USB stack takes control through the usb_hcd ops. hub_wq
-has seen the port status changes, as we have been toggling them. It will
-start enumerating and doing transfers through usb_hcd->urb_enqueue() to
-read descriptors and move our data.
-
-Device life cycle and keep alives
----------------------------------
-
-Every time there is a successful transfer to/from a device, we update a
-per-device activity timestamp. If not, every now and then we check and
-if the activity timestamp gets old, we ping the device by sending it a
-Keep Alive IE; it responds with a /DN_Alive/ pong during the DNTS (this
-arrives to us as a notification through
-devconnect.c:wusb_handle_dn_alive(). If a device times out, we
-disconnect it from the system (cleaning up internal information and
-toggling the bits in the fake hub port, which kicks hub_wq into removing
-the rest of the stuff).
-
-This is done through devconnect:__wusb_check_devs(), which will scan the
-device list looking for whom needs refreshing.
-
-If the device wants to disconnect, it will either die (ugly) or send a
-/DN_Disconnect/ that will prompt a disconnection from the system.
-
-Sending and receiving data
---------------------------
-
-Data is sent and received through /Remote Pipes/ (rpipes). An rpipe is
-/aimed/ at an endpoint in a WUSB device. This is the same for HWAs and
-DWAs.
-
-Each HC has a number of rpipes and buffers that can be assigned to them;
-when doing a data transfer (xfer), first the rpipe has to be aimed and
-prepared (buffers assigned), then we can start queueing requests for
-data in or out.
-
-Data buffers have to be segmented out before sending--so we send first a
-header (segment request) and then if there is any data, a data buffer
-immediately after to the DTI interface (yep, even the request). If our
-buffer is bigger than the max segment size, then we just do multiple
-requests.
-
-[This sucks, because doing USB scatter gatter in Linux is resource
-intensive, if any...not that the current approach is not. It just has to
-be cleaned up a lot :)].
-
-If reading, we don't send data buffers, just the segment headers saying
-we want to read segments.
-
-When the xfer is executed, we receive a notification that says data is
-ready in the DTI endpoint (handled through
-xfer.c:wa_handle_notif_xfer()). In there we read from the DTI endpoint a
-descriptor that gives us the status of the transfer, its identification
-(given when we issued it) and the segment number. If it was a data read,
-we issue another URB to read into the destination buffer the chunk of
-data coming out of the remote endpoint. Done, wait for the next guy. The
-callbacks for the URBs issued from here are the ones that will declare
-the xfer complete at some point and call its callback.
-
-Seems simple, but the implementation is not trivial.
-
-    *
-
-      *WARNING* Old!!
-
-The main xfer descriptor, wa_xfer (equivalent to a URB) contains an
-array of segments, tallys on segments and buffers and callback
-information. Buried in there is a lot of URBs for executing the segments
-and buffer transfers.
-
-For OUT xfers, there is an array of segments, one URB for each, another
-one of buffer URB. When submitting, we submit URBs for segment request
-1, buffer 1, segment 2, buffer 2...etc. Then we wait on the DTI for xfer
-result data; when all the segments are complete, we call the callback to
-finalize the transfer.
-
-For IN xfers, we only issue URBs for the segments we want to read and
-then wait for the xfer result data.
-
-URB mapping into xfers
-^^^^^^^^^^^^^^^^^^^^^^
-
-This is done by hwahc_op_urb_[en|de]queue(). In enqueue() we aim an
-rpipe to the endpoint where we have to transmit, create a transfer
-context (wa_xfer) and submit it. When the xfer is done, our callback is
-called and we assign the status bits and release the xfer resources.
-
-In dequeue() we are basically cancelling/aborting the transfer. We issue
-a xfer abort request to the HC, cancel all the URBs we had submitted
-and not yet done and when all that is done, the xfer callback will be
-called--this will call the URB callback.
-
-
-Glossary
-========
-
-*DWA* -- Device Wire Adapter
-
-USB host, wired for downstream devices, upstream connects wirelessly
-with Wireless USB.
-
-*EVENT* -- Response to a command on the NEEP
-
-*HWA* -- Host Wire Adapter / USB dongle for UWB and Wireless USB
-
-*NEH* -- Notification/Event Handle
-
-Handle/file descriptor for receiving notifications or events. The WA
-code requires you to get one of this to listen for notifications or
-events on the NEEP.
-
-*NEEP* -- Notification/Event EndPoint
-
-Stuff related to the management of the first endpoint of a HWA USB
-dongle that is used to deliver an stream of events and notifications to
-the host.
-
-*NOTIFICATION* -- Message coming in the NEEP as response to something.
-
-*RC* -- Radio Control
-
-Design-overview.txt-1.8 (last edited 2006-11-04 12:22:24 by
-InakyPerezGonzalez)
diff --git a/Documentation/usb/acm.rst b/Documentation/usb/acm.rst
new file mode 100644 (file)
index 0000000..e8bda98
--- /dev/null
@@ -0,0 +1,132 @@
+======================
+Linux ACM driver v0.16
+======================
+
+Copyright (c) 1999 Vojtech Pavlik <vojtech@suse.cz>
+
+Sponsored by SuSE
+
+0. Disclaimer
+~~~~~~~~~~~~~
+This program is free software; you can redistribute it and/or modify it
+under the terms of the 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
+
+Should you need to contact me, the author, you can do so either by e-mail -
+mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
+Ucitelska 1576, Prague 8, 182 00 Czech Republic
+
+For your convenience, the GNU General Public License version 2 is included
+in the package: See the file COPYING.
+
+1. Usage
+~~~~~~~~
+The drivers/usb/class/cdc-acm.c drivers works with USB modems and USB ISDN terminal
+adapters that conform to the Universal Serial Bus Communication Device Class
+Abstract Control Model (USB CDC ACM) specification.
+
+Many modems do, here is a list of those I know of:
+
+       - 3Com OfficeConnect 56k
+       - 3Com Voice FaxModem Pro
+       - 3Com Sportster
+       - MultiTech MultiModem 56k
+       - Zoom 2986L FaxModem
+       - Compaq 56k FaxModem
+       - ELSA Microlink 56k
+
+I know of one ISDN TA that does work with the acm driver:
+
+       - 3Com USR ISDN Pro TA
+
+Some cell phones also connect via USB. I know the following phones work:
+
+       - SonyEricsson K800i
+
+Unfortunately many modems and most ISDN TAs use proprietary interfaces and
+thus won't work with this drivers. Check for ACM compliance before buying.
+
+To use the modems you need these modules loaded::
+
+       usbcore.ko
+       uhci-hcd.ko ohci-hcd.ko or ehci-hcd.ko
+       cdc-acm.ko
+
+After that, the modem[s] should be accessible. You should be able to use
+minicom, ppp and mgetty with them.
+
+2. Verifying that it works
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The first step would be to check /sys/kernel/debug/usb/devices, it should look
+like this::
+
+  T:  Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12  MxCh= 2
+  B:  Alloc=  0/900 us ( 0%), #Int=  0, #Iso=  0
+  D:  Ver= 1.00 Cls=09(hub  ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
+  P:  Vendor=0000 ProdID=0000 Rev= 0.00
+  S:  Product=USB UHCI Root Hub
+  S:  SerialNumber=6800
+  C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=  0mA
+  I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
+  E:  Ad=81(I) Atr=03(Int.) MxPS=   8 Ivl=255ms
+  T:  Bus=01 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#=  2 Spd=12  MxCh= 0
+  D:  Ver= 1.00 Cls=02(comm.) Sub=00 Prot=00 MxPS= 8 #Cfgs=  2
+  P:  Vendor=04c1 ProdID=008f Rev= 2.07
+  S:  Manufacturer=3Com Inc.
+  S:  Product=3Com U.S. Robotics Pro ISDN TA
+  S:  SerialNumber=UFT53A49BVT7
+  C:  #Ifs= 1 Cfg#= 1 Atr=60 MxPwr=  0mA
+  I:  If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=acm
+  E:  Ad=85(I) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
+  E:  Ad=04(O) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
+  E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=128ms
+  C:* #Ifs= 2 Cfg#= 2 Atr=60 MxPwr=  0mA
+  I:  If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm
+  E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=128ms
+  I:  If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm
+  E:  Ad=85(I) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
+  E:  Ad=04(O) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
+
+The presence of these three lines (and the Cls= 'comm' and 'data' classes)
+is important, it means it's an ACM device. The Driver=acm means the acm
+driver is used for the device. If you see only Cls=ff(vend.) then you're out
+of luck, you have a device with vendor specific-interface::
+
+  D:  Ver= 1.00 Cls=02(comm.) Sub=00 Prot=00 MxPS= 8 #Cfgs=  2
+  I:  If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm
+  I:  If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm
+
+In the system log you should see::
+
+  usb.c: USB new device connect, assigned device number 2
+  usb.c: kmalloc IF c7691fa0, numif 1
+  usb.c: kmalloc IF c7b5f3e0, numif 2
+  usb.c: skipped 4 class/vendor specific interface descriptors
+  usb.c: new device strings: Mfr=1, Product=2, SerialNumber=3
+  usb.c: USB device number 2 default language ID 0x409
+  Manufacturer: 3Com Inc.
+  Product: 3Com U.S. Robotics Pro ISDN TA
+  SerialNumber: UFT53A49BVT7
+  acm.c: probing config 1
+  acm.c: probing config 2
+  ttyACM0: USB ACM device
+  acm.c: acm_control_msg: rq: 0x22 val: 0x0 len: 0x0 result: 0
+  acm.c: acm_control_msg: rq: 0x20 val: 0x0 len: 0x7 result: 7
+  usb.c: acm driver claimed interface c7b5f3e0
+  usb.c: acm driver claimed interface c7b5f3f8
+  usb.c: acm driver claimed interface c7691fa0
+
+If all this seems to be OK, fire up minicom and set it to talk to the ttyACM
+device and try typing 'at'. If it responds with 'OK', then everything is
+working.
diff --git a/Documentation/usb/acm.txt b/Documentation/usb/acm.txt
deleted file mode 100644 (file)
index e8bda98..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-======================
-Linux ACM driver v0.16
-======================
-
-Copyright (c) 1999 Vojtech Pavlik <vojtech@suse.cz>
-
-Sponsored by SuSE
-
-0. Disclaimer
-~~~~~~~~~~~~~
-This program is free software; you can redistribute it and/or modify it
-under the terms of the 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
-
-Should you need to contact me, the author, you can do so either by e-mail -
-mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
-Ucitelska 1576, Prague 8, 182 00 Czech Republic
-
-For your convenience, the GNU General Public License version 2 is included
-in the package: See the file COPYING.
-
-1. Usage
-~~~~~~~~
-The drivers/usb/class/cdc-acm.c drivers works with USB modems and USB ISDN terminal
-adapters that conform to the Universal Serial Bus Communication Device Class
-Abstract Control Model (USB CDC ACM) specification.
-
-Many modems do, here is a list of those I know of:
-
-       - 3Com OfficeConnect 56k
-       - 3Com Voice FaxModem Pro
-       - 3Com Sportster
-       - MultiTech MultiModem 56k
-       - Zoom 2986L FaxModem
-       - Compaq 56k FaxModem
-       - ELSA Microlink 56k
-
-I know of one ISDN TA that does work with the acm driver:
-
-       - 3Com USR ISDN Pro TA
-
-Some cell phones also connect via USB. I know the following phones work:
-
-       - SonyEricsson K800i
-
-Unfortunately many modems and most ISDN TAs use proprietary interfaces and
-thus won't work with this drivers. Check for ACM compliance before buying.
-
-To use the modems you need these modules loaded::
-
-       usbcore.ko
-       uhci-hcd.ko ohci-hcd.ko or ehci-hcd.ko
-       cdc-acm.ko
-
-After that, the modem[s] should be accessible. You should be able to use
-minicom, ppp and mgetty with them.
-
-2. Verifying that it works
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The first step would be to check /sys/kernel/debug/usb/devices, it should look
-like this::
-
-  T:  Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12  MxCh= 2
-  B:  Alloc=  0/900 us ( 0%), #Int=  0, #Iso=  0
-  D:  Ver= 1.00 Cls=09(hub  ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
-  P:  Vendor=0000 ProdID=0000 Rev= 0.00
-  S:  Product=USB UHCI Root Hub
-  S:  SerialNumber=6800
-  C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=  0mA
-  I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
-  E:  Ad=81(I) Atr=03(Int.) MxPS=   8 Ivl=255ms
-  T:  Bus=01 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#=  2 Spd=12  MxCh= 0
-  D:  Ver= 1.00 Cls=02(comm.) Sub=00 Prot=00 MxPS= 8 #Cfgs=  2
-  P:  Vendor=04c1 ProdID=008f Rev= 2.07
-  S:  Manufacturer=3Com Inc.
-  S:  Product=3Com U.S. Robotics Pro ISDN TA
-  S:  SerialNumber=UFT53A49BVT7
-  C:  #Ifs= 1 Cfg#= 1 Atr=60 MxPwr=  0mA
-  I:  If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=acm
-  E:  Ad=85(I) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
-  E:  Ad=04(O) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
-  E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=128ms
-  C:* #Ifs= 2 Cfg#= 2 Atr=60 MxPwr=  0mA
-  I:  If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm
-  E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=128ms
-  I:  If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm
-  E:  Ad=85(I) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
-  E:  Ad=04(O) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
-
-The presence of these three lines (and the Cls= 'comm' and 'data' classes)
-is important, it means it's an ACM device. The Driver=acm means the acm
-driver is used for the device. If you see only Cls=ff(vend.) then you're out
-of luck, you have a device with vendor specific-interface::
-
-  D:  Ver= 1.00 Cls=02(comm.) Sub=00 Prot=00 MxPS= 8 #Cfgs=  2
-  I:  If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm
-  I:  If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm
-
-In the system log you should see::
-
-  usb.c: USB new device connect, assigned device number 2
-  usb.c: kmalloc IF c7691fa0, numif 1
-  usb.c: kmalloc IF c7b5f3e0, numif 2
-  usb.c: skipped 4 class/vendor specific interface descriptors
-  usb.c: new device strings: Mfr=1, Product=2, SerialNumber=3
-  usb.c: USB device number 2 default language ID 0x409
-  Manufacturer: 3Com Inc.
-  Product: 3Com U.S. Robotics Pro ISDN TA
-  SerialNumber: UFT53A49BVT7
-  acm.c: probing config 1
-  acm.c: probing config 2
-  ttyACM0: USB ACM device
-  acm.c: acm_control_msg: rq: 0x22 val: 0x0 len: 0x0 result: 0
-  acm.c: acm_control_msg: rq: 0x20 val: 0x0 len: 0x7 result: 7
-  usb.c: acm driver claimed interface c7b5f3e0
-  usb.c: acm driver claimed interface c7b5f3f8
-  usb.c: acm driver claimed interface c7691fa0
-
-If all this seems to be OK, fire up minicom and set it to talk to the ttyACM
-device and try typing 'at'. If it responds with 'OK', then everything is
-working.
diff --git a/Documentation/usb/authorization.rst b/Documentation/usb/authorization.rst
new file mode 100644 (file)
index 0000000..9e53909
--- /dev/null
@@ -0,0 +1,132 @@
+==============================================================
+Authorizing (or not) your USB devices to connect to the system
+==============================================================
+
+Copyright (C) 2007 Inaky Perez-Gonzalez <inaky@linux.intel.com> Intel Corporation
+
+This feature allows you to control if a USB device can be used (or
+not) in a system. This feature will allow you to implement a lock-down
+of USB devices, fully controlled by user space.
+
+As of now, when a USB device is connected it is configured and
+its interfaces are immediately made available to the users.  With this
+modification, only if root authorizes the device to be configured will
+then it be possible to use it.
+
+Usage
+=====
+
+Authorize a device to connect::
+
+       $ echo 1 > /sys/bus/usb/devices/DEVICE/authorized
+
+De-authorize a device::
+
+       $ echo 0 > /sys/bus/usb/devices/DEVICE/authorized
+
+Set new devices connected to hostX to be deauthorized by default (ie:
+lock down)::
+
+       $ echo 0 > /sys/bus/usb/devices/usbX/authorized_default
+
+Remove the lock down::
+
+       $ echo 1 > /sys/bus/usb/devices/usbX/authorized_default
+
+By default, Wired USB devices are authorized by default to
+connect. Wireless USB hosts deauthorize by default all new connected
+devices (this is so because we need to do an authentication phase
+before authorizing). Writing "2" to the authorized_default attribute
+causes kernel to only authorize by default devices connected to internal
+USB ports.
+
+
+Example system lockdown (lame)
+------------------------------
+
+Imagine you want to implement a lockdown so only devices of type XYZ
+can be connected (for example, it is a kiosk machine with a visible
+USB port)::
+
+  boot up
+  rc.local ->
+
+   for host in /sys/bus/usb/devices/usb*
+   do
+      echo 0 > $host/authorized_default
+   done
+
+Hookup an script to udev, for new USB devices::
+
+ if device_is_my_type $DEV
+ then
+   echo 1 > $device_path/authorized
+ done
+
+
+Now, device_is_my_type() is where the juice for a lockdown is. Just
+checking if the class, type and protocol match something is the worse
+security verification you can make (or the best, for someone willing
+to break it). If you need something secure, use crypto and Certificate
+Authentication or stuff like that. Something simple for an storage key
+could be::
+
+ function device_is_my_type()
+ {
+   echo 1 > authorized         # temporarily authorize it
+                                # FIXME: make sure none can mount it
+   mount DEVICENODE /mntpoint
+   sum=$(md5sum /mntpoint/.signature)
+   if [ $sum = $(cat /etc/lockdown/keysum) ]
+   then
+        echo "We are good, connected"
+        umount /mntpoint
+        # Other stuff so others can use it
+   else
+        echo 0 > authorized
+   fi
+ }
+
+
+Of course, this is lame, you'd want to do a real certificate
+verification stuff with PKI, so you don't depend on a shared secret,
+etc, but you get the idea. Anybody with access to a device gadget kit
+can fake descriptors and device info. Don't trust that. You are
+welcome.
+
+
+Interface authorization
+-----------------------
+
+There is a similar approach to allow or deny specific USB interfaces.
+That allows to block only a subset of an USB device.
+
+Authorize an interface::
+
+       $ echo 1 > /sys/bus/usb/devices/INTERFACE/authorized
+
+Deauthorize an interface::
+
+       $ echo 0 > /sys/bus/usb/devices/INTERFACE/authorized
+
+The default value for new interfaces
+on a particular USB bus can be changed, too.
+
+Allow interfaces per default::
+
+       $ echo 1 > /sys/bus/usb/devices/usbX/interface_authorized_default
+
+Deny interfaces per default::
+
+       $ echo 0 > /sys/bus/usb/devices/usbX/interface_authorized_default
+
+Per default the interface_authorized_default bit is 1.
+So all interfaces would authorized per default.
+
+Note:
+  If a deauthorized interface will be authorized so the driver probing must
+  be triggered manually by writing INTERFACE to /sys/bus/usb/drivers_probe
+
+For drivers that need multiple interfaces all needed interfaces should be
+authorized first. After that the drivers should be probed.
+This avoids side effects.
diff --git a/Documentation/usb/authorization.txt b/Documentation/usb/authorization.txt
deleted file mode 100644 (file)
index 9e53909..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-==============================================================
-Authorizing (or not) your USB devices to connect to the system
-==============================================================
-
-Copyright (C) 2007 Inaky Perez-Gonzalez <inaky@linux.intel.com> Intel Corporation
-
-This feature allows you to control if a USB device can be used (or
-not) in a system. This feature will allow you to implement a lock-down
-of USB devices, fully controlled by user space.
-
-As of now, when a USB device is connected it is configured and
-its interfaces are immediately made available to the users.  With this
-modification, only if root authorizes the device to be configured will
-then it be possible to use it.
-
-Usage
-=====
-
-Authorize a device to connect::
-
-       $ echo 1 > /sys/bus/usb/devices/DEVICE/authorized
-
-De-authorize a device::
-
-       $ echo 0 > /sys/bus/usb/devices/DEVICE/authorized
-
-Set new devices connected to hostX to be deauthorized by default (ie:
-lock down)::
-
-       $ echo 0 > /sys/bus/usb/devices/usbX/authorized_default
-
-Remove the lock down::
-
-       $ echo 1 > /sys/bus/usb/devices/usbX/authorized_default
-
-By default, Wired USB devices are authorized by default to
-connect. Wireless USB hosts deauthorize by default all new connected
-devices (this is so because we need to do an authentication phase
-before authorizing). Writing "2" to the authorized_default attribute
-causes kernel to only authorize by default devices connected to internal
-USB ports.
-
-
-Example system lockdown (lame)
-------------------------------
-
-Imagine you want to implement a lockdown so only devices of type XYZ
-can be connected (for example, it is a kiosk machine with a visible
-USB port)::
-
-  boot up
-  rc.local ->
-
-   for host in /sys/bus/usb/devices/usb*
-   do
-      echo 0 > $host/authorized_default
-   done
-
-Hookup an script to udev, for new USB devices::
-
- if device_is_my_type $DEV
- then
-   echo 1 > $device_path/authorized
- done
-
-
-Now, device_is_my_type() is where the juice for a lockdown is. Just
-checking if the class, type and protocol match something is the worse
-security verification you can make (or the best, for someone willing
-to break it). If you need something secure, use crypto and Certificate
-Authentication or stuff like that. Something simple for an storage key
-could be::
-
- function device_is_my_type()
- {
-   echo 1 > authorized         # temporarily authorize it
-                                # FIXME: make sure none can mount it
-   mount DEVICENODE /mntpoint
-   sum=$(md5sum /mntpoint/.signature)
-   if [ $sum = $(cat /etc/lockdown/keysum) ]
-   then
-        echo "We are good, connected"
-        umount /mntpoint
-        # Other stuff so others can use it
-   else
-        echo 0 > authorized
-   fi
- }
-
-
-Of course, this is lame, you'd want to do a real certificate
-verification stuff with PKI, so you don't depend on a shared secret,
-etc, but you get the idea. Anybody with access to a device gadget kit
-can fake descriptors and device info. Don't trust that. You are
-welcome.
-
-
-Interface authorization
------------------------
-
-There is a similar approach to allow or deny specific USB interfaces.
-That allows to block only a subset of an USB device.
-
-Authorize an interface::
-
-       $ echo 1 > /sys/bus/usb/devices/INTERFACE/authorized
-
-Deauthorize an interface::
-
-       $ echo 0 > /sys/bus/usb/devices/INTERFACE/authorized
-
-The default value for new interfaces
-on a particular USB bus can be changed, too.
-
-Allow interfaces per default::
-
-       $ echo 1 > /sys/bus/usb/devices/usbX/interface_authorized_default
-
-Deny interfaces per default::
-
-       $ echo 0 > /sys/bus/usb/devices/usbX/interface_authorized_default
-
-Per default the interface_authorized_default bit is 1.
-So all interfaces would authorized per default.
-
-Note:
-  If a deauthorized interface will be authorized so the driver probing must
-  be triggered manually by writing INTERFACE to /sys/bus/usb/drivers_probe
-
-For drivers that need multiple interfaces all needed interfaces should be
-authorized first. After that the drivers should be probed.
-This avoids side effects.
diff --git a/Documentation/usb/chipidea.rst b/Documentation/usb/chipidea.rst
new file mode 100644 (file)
index 0000000..68473ab
--- /dev/null
@@ -0,0 +1,133 @@
+==============================================
+ChipIdea Highspeed Dual Role Controller Driver
+==============================================
+
+1. How to test OTG FSM(HNP and SRP)
+-----------------------------------
+
+To show how to demo OTG HNP and SRP functions via sys input files
+with 2 Freescale i.MX6Q sabre SD boards.
+
+1.1 How to enable OTG FSM
+-------------------------
+
+1.1.1 Select CONFIG_USB_OTG_FSM in menuconfig, rebuild kernel
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Image and modules. If you want to check some internal
+variables for otg fsm, mount debugfs, there are 2 files
+which can show otg fsm variables and some controller registers value::
+
+       cat /sys/kernel/debug/ci_hdrc.0/otg
+       cat /sys/kernel/debug/ci_hdrc.0/registers
+
+1.1.2 Add below entries in your dts file for your controller node
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+::
+
+       otg-rev = <0x0200>;
+       adp-disable;
+
+1.2 Test operations
+-------------------
+
+1) Power up 2 Freescale i.MX6Q sabre SD boards with gadget class driver loaded
+   (e.g. g_mass_storage).
+
+2) Connect 2 boards with usb cable with one end is micro A plug, the other end
+   is micro B plug.
+
+   The A-device(with micro A plug inserted) should enumerate B-device.
+
+3) Role switch
+
+   On B-device::
+
+       echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req
+
+   B-device should take host role and enumerate A-device.
+
+4) A-device switch back to host.
+
+   On B-device::
+
+       echo 0 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req
+
+   or, by introducing HNP polling, B-Host can know when A-peripheral wish
+   to be host role, so this role switch also can be trigged in A-peripheral
+   side by answering the polling from B-Host, this can be done on A-device::
+
+       echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req
+
+   A-device should switch back to host and enumerate B-device.
+
+5) Remove B-device(unplug micro B plug) and insert again in 10 seconds,
+   A-device should enumerate B-device again.
+
+6) Remove B-device(unplug micro B plug) and insert again after 10 seconds,
+   A-device should NOT enumerate B-device.
+
+   if A-device wants to use bus:
+
+   On A-device::
+
+       echo 0 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_drop
+       echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req
+
+   if B-device wants to use bus:
+
+   On B-device::
+
+       echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req
+
+7) A-device power down the bus.
+
+   On A-device::
+
+       echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_drop
+
+   A-device should disconnect with B-device and power down the bus.
+
+8) B-device does data pulse for SRP.
+
+   On B-device::
+
+       echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req
+
+   A-device should resume usb bus and enumerate B-device.
+
+1.3 Reference document
+----------------------
+"On-The-Go and Embedded Host Supplement to the USB Revision 2.0 Specification
+July 27, 2012 Revision 2.0 version 1.1a"
+
+2. How to enable USB as system wakeup source
+--------------------------------------------
+Below is the example for how to enable USB as system wakeup source
+at imx6 platform.
+
+2.1 Enable core's wakeup::
+
+       echo enabled > /sys/bus/platform/devices/ci_hdrc.0/power/wakeup
+
+2.2 Enable glue layer's wakeup::
+
+       echo enabled > /sys/bus/platform/devices/2184000.usb/power/wakeup
+
+2.3 Enable PHY's wakeup (optional)::
+
+       echo enabled > /sys/bus/platform/devices/20c9000.usbphy/power/wakeup
+
+2.4 Enable roothub's wakeup::
+
+       echo enabled > /sys/bus/usb/devices/usb1/power/wakeup
+
+2.5 Enable related device's wakeup::
+
+       echo enabled > /sys/bus/usb/devices/1-1/power/wakeup
+
+If the system has only one usb port, and you want usb wakeup at this port, you
+can use below script to enable usb wakeup::
+
+       for i in $(find /sys -name wakeup | grep usb);do echo enabled > $i;done;
diff --git a/Documentation/usb/chipidea.txt b/Documentation/usb/chipidea.txt
deleted file mode 100644 (file)
index 68473ab..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-==============================================
-ChipIdea Highspeed Dual Role Controller Driver
-==============================================
-
-1. How to test OTG FSM(HNP and SRP)
------------------------------------
-
-To show how to demo OTG HNP and SRP functions via sys input files
-with 2 Freescale i.MX6Q sabre SD boards.
-
-1.1 How to enable OTG FSM
--------------------------
-
-1.1.1 Select CONFIG_USB_OTG_FSM in menuconfig, rebuild kernel
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Image and modules. If you want to check some internal
-variables for otg fsm, mount debugfs, there are 2 files
-which can show otg fsm variables and some controller registers value::
-
-       cat /sys/kernel/debug/ci_hdrc.0/otg
-       cat /sys/kernel/debug/ci_hdrc.0/registers
-
-1.1.2 Add below entries in your dts file for your controller node
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-::
-
-       otg-rev = <0x0200>;
-       adp-disable;
-
-1.2 Test operations
--------------------
-
-1) Power up 2 Freescale i.MX6Q sabre SD boards with gadget class driver loaded
-   (e.g. g_mass_storage).
-
-2) Connect 2 boards with usb cable with one end is micro A plug, the other end
-   is micro B plug.
-
-   The A-device(with micro A plug inserted) should enumerate B-device.
-
-3) Role switch
-
-   On B-device::
-
-       echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req
-
-   B-device should take host role and enumerate A-device.
-
-4) A-device switch back to host.
-
-   On B-device::
-
-       echo 0 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req
-
-   or, by introducing HNP polling, B-Host can know when A-peripheral wish
-   to be host role, so this role switch also can be trigged in A-peripheral
-   side by answering the polling from B-Host, this can be done on A-device::
-
-       echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req
-
-   A-device should switch back to host and enumerate B-device.
-
-5) Remove B-device(unplug micro B plug) and insert again in 10 seconds,
-   A-device should enumerate B-device again.
-
-6) Remove B-device(unplug micro B plug) and insert again after 10 seconds,
-   A-device should NOT enumerate B-device.
-
-   if A-device wants to use bus:
-
-   On A-device::
-
-       echo 0 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_drop
-       echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req
-
-   if B-device wants to use bus:
-
-   On B-device::
-
-       echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req
-
-7) A-device power down the bus.
-
-   On A-device::
-
-       echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_drop
-
-   A-device should disconnect with B-device and power down the bus.
-
-8) B-device does data pulse for SRP.
-
-   On B-device::
-
-       echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req
-
-   A-device should resume usb bus and enumerate B-device.
-
-1.3 Reference document
-----------------------
-"On-The-Go and Embedded Host Supplement to the USB Revision 2.0 Specification
-July 27, 2012 Revision 2.0 version 1.1a"
-
-2. How to enable USB as system wakeup source
---------------------------------------------
-Below is the example for how to enable USB as system wakeup source
-at imx6 platform.
-
-2.1 Enable core's wakeup::
-
-       echo enabled > /sys/bus/platform/devices/ci_hdrc.0/power/wakeup
-
-2.2 Enable glue layer's wakeup::
-
-       echo enabled > /sys/bus/platform/devices/2184000.usb/power/wakeup
-
-2.3 Enable PHY's wakeup (optional)::
-
-       echo enabled > /sys/bus/platform/devices/20c9000.usbphy/power/wakeup
-
-2.4 Enable roothub's wakeup::
-
-       echo enabled > /sys/bus/usb/devices/usb1/power/wakeup
-
-2.5 Enable related device's wakeup::
-
-       echo enabled > /sys/bus/usb/devices/1-1/power/wakeup
-
-If the system has only one usb port, and you want usb wakeup at this port, you
-can use below script to enable usb wakeup::
-
-       for i in $(find /sys -name wakeup | grep usb);do echo enabled > $i;done;
diff --git a/Documentation/usb/dwc3.rst b/Documentation/usb/dwc3.rst
new file mode 100644 (file)
index 0000000..f94a7ba
--- /dev/null
@@ -0,0 +1,53 @@
+===========
+DWC3 driver
+===========
+
+
+TODO
+~~~~
+
+Please pick something while reading :)
+
+- Convert interrupt handler to per-ep-thread-irq
+
+  As it turns out some DWC3-commands ~1ms to complete. Currently we spin
+  until the command completes which is bad.
+
+  Implementation idea:
+
+  - dwc core implements a demultiplexing irq chip for interrupts per
+    endpoint. The interrupt numbers are allocated during probe and belong
+    to the device. If MSI provides per-endpoint interrupt this dummy
+    interrupt chip can be replaced with "real" interrupts.
+  - interrupts are requested / allocated on usb_ep_enable() and removed on
+    usb_ep_disable(). Worst case are 32 interrupts, the lower limit is two
+    for ep0/1.
+  - dwc3_send_gadget_ep_cmd() will sleep in wait_for_completion_timeout()
+    until the command completes.
+  - the interrupt handler is split into the following pieces:
+
+    - primary handler of the device
+      goes through every event and calls generic_handle_irq() for event
+      it. On return from generic_handle_irq() in acknowledges the event
+      counter so interrupt goes away (eventually).
+
+    - threaded handler of the device
+      none
+
+    - primary handler of the EP-interrupt
+      reads the event and tries to process it. Everything that requires
+      sleeping is handed over to the Thread. The event is saved in an
+      per-endpoint data-structure.
+      We probably have to pay attention not to process events once we
+      handed something to thread so we don't process event X prio Y
+      where X > Y.
+
+    - threaded handler of the EP-interrupt
+      handles the remaining EP work which might sleep such as waiting
+      for command completion.
+
+  Latency:
+
+   There should be no increase in latency since the interrupt-thread has a
+   high priority and will be run before an average task in user land
+   (except the user changed priorities).
diff --git a/Documentation/usb/dwc3.txt b/Documentation/usb/dwc3.txt
deleted file mode 100644 (file)
index f94a7ba..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-===========
-DWC3 driver
-===========
-
-
-TODO
-~~~~
-
-Please pick something while reading :)
-
-- Convert interrupt handler to per-ep-thread-irq
-
-  As it turns out some DWC3-commands ~1ms to complete. Currently we spin
-  until the command completes which is bad.
-
-  Implementation idea:
-
-  - dwc core implements a demultiplexing irq chip for interrupts per
-    endpoint. The interrupt numbers are allocated during probe and belong
-    to the device. If MSI provides per-endpoint interrupt this dummy
-    interrupt chip can be replaced with "real" interrupts.
-  - interrupts are requested / allocated on usb_ep_enable() and removed on
-    usb_ep_disable(). Worst case are 32 interrupts, the lower limit is two
-    for ep0/1.
-  - dwc3_send_gadget_ep_cmd() will sleep in wait_for_completion_timeout()
-    until the command completes.
-  - the interrupt handler is split into the following pieces:
-
-    - primary handler of the device
-      goes through every event and calls generic_handle_irq() for event
-      it. On return from generic_handle_irq() in acknowledges the event
-      counter so interrupt goes away (eventually).
-
-    - threaded handler of the device
-      none
-
-    - primary handler of the EP-interrupt
-      reads the event and tries to process it. Everything that requires
-      sleeping is handed over to the Thread. The event is saved in an
-      per-endpoint data-structure.
-      We probably have to pay attention not to process events once we
-      handed something to thread so we don't process event X prio Y
-      where X > Y.
-
-    - threaded handler of the EP-interrupt
-      handles the remaining EP work which might sleep such as waiting
-      for command completion.
-
-  Latency:
-
-   There should be no increase in latency since the interrupt-thread has a
-   high priority and will be run before an average task in user land
-   (except the user changed priorities).
diff --git a/Documentation/usb/ehci.rst b/Documentation/usb/ehci.rst
new file mode 100644 (file)
index 0000000..31f650e
--- /dev/null
@@ -0,0 +1,230 @@
+===========
+EHCI driver
+===========
+
+27-Dec-2002
+
+The EHCI driver is used to talk to high speed USB 2.0 devices using
+USB 2.0-capable host controller hardware.  The USB 2.0 standard is
+compatible with the USB 1.1 standard. It defines three transfer speeds:
+
+    - "High Speed" 480 Mbit/sec (60 MByte/sec)
+    - "Full Speed" 12 Mbit/sec (1.5 MByte/sec)
+    - "Low Speed" 1.5 Mbit/sec
+
+USB 1.1 only addressed full speed and low speed.  High speed devices
+can be used on USB 1.1 systems, but they slow down to USB 1.1 speeds.
+
+USB 1.1 devices may also be used on USB 2.0 systems.  When plugged
+into an EHCI controller, they are given to a USB 1.1 "companion"
+controller, which is a OHCI or UHCI controller as normally used with
+such devices.  When USB 1.1 devices plug into USB 2.0 hubs, they
+interact with the EHCI controller through a "Transaction Translator"
+(TT) in the hub, which turns low or full speed transactions into
+high speed "split transactions" that don't waste transfer bandwidth.
+
+At this writing, this driver has been seen to work with implementations
+of EHCI from (in alphabetical order):  Intel, NEC, Philips, and VIA.
+Other EHCI implementations are becoming available from other vendors;
+you should expect this driver to work with them too.
+
+While usb-storage devices have been available since mid-2001 (working
+quite speedily on the 2.4 version of this driver), hubs have only
+been available since late 2001, and other kinds of high speed devices
+appear to be on hold until more systems come with USB 2.0 built-in.
+Such new systems have been available since early 2002, and became much
+more typical in the second half of 2002.
+
+Note that USB 2.0 support involves more than just EHCI.  It requires
+other changes to the Linux-USB core APIs, including the hub driver,
+but those changes haven't needed to really change the basic "usbcore"
+APIs exposed to USB device drivers.
+
+- David Brownell
+  <dbrownell@users.sourceforge.net>
+
+
+Functionality
+=============
+
+This driver is regularly tested on x86 hardware, and has also been
+used on PPC hardware so big/little endianness issues should be gone.
+It's believed to do all the right PCI magic so that I/O works even on
+systems with interesting DMA mapping issues.
+
+Transfer Types
+--------------
+
+At this writing the driver should comfortably handle all control, bulk,
+and interrupt transfers, including requests to USB 1.1 devices through
+transaction translators (TTs) in USB 2.0 hubs.  But you may find bugs.
+
+High Speed Isochronous (ISO) transfer support is also functional, but
+at this writing no Linux drivers have been using that support.
+
+Full Speed Isochronous transfer support, through transaction translators,
+is not yet available.  Note that split transaction support for ISO
+transfers can't share much code with the code for high speed ISO transfers,
+since EHCI represents these with a different data structure.  So for now,
+most USB audio and video devices can't be connected to high speed buses.
+
+Driver Behavior
+---------------
+
+Transfers of all types can be queued.  This means that control transfers
+from a driver on one interface (or through usbfs) won't interfere with
+ones from another driver, and that interrupt transfers can use periods
+of one frame without risking data loss due to interrupt processing costs.
+
+The EHCI root hub code hands off USB 1.1 devices to its companion
+controller.  This driver doesn't need to know anything about those
+drivers; a OHCI or UHCI driver that works already doesn't need to change
+just because the EHCI driver is also present.
+
+There are some issues with power management; suspend/resume doesn't
+behave quite right at the moment.
+
+Also, some shortcuts have been taken with the scheduling periodic
+transactions (interrupt and isochronous transfers).  These place some
+limits on the number of periodic transactions that can be scheduled,
+and prevent use of polling intervals of less than one frame.
+
+
+Use by
+======
+
+Assuming you have an EHCI controller (on a PCI card or motherboard)
+and have compiled this driver as a module, load this like::
+
+    # modprobe ehci-hcd
+
+and remove it by::
+
+    # rmmod ehci-hcd
+
+You should also have a driver for a "companion controller", such as
+"ohci-hcd"  or "uhci-hcd".  In case of any trouble with the EHCI driver,
+remove its module and then the driver for that companion controller will
+take over (at lower speed) all the devices that were previously handled
+by the EHCI driver.
+
+Module parameters (pass to "modprobe") include:
+
+    log2_irq_thresh (default 0):
+       Log2 of default interrupt delay, in microframes.  The default
+       value is 0, indicating 1 microframe (125 usec).  Maximum value
+       is 6, indicating 2^6 = 64 microframes.  This controls how often
+       the EHCI controller can issue interrupts.
+
+If you're using this driver on a 2.5 kernel, and you've enabled USB
+debugging support, you'll see three files in the "sysfs" directory for
+any EHCI controller:
+
+       "async"
+               dumps the asynchronous schedule, used for control
+               and bulk transfers.  Shows each active qh and the qtds
+               pending, usually one qtd per urb.  (Look at it with
+               usb-storage doing disk I/O; watch the request queues!)
+       "periodic"
+               dumps the periodic schedule, used for interrupt
+               and isochronous transfers.  Doesn't show qtds.
+       "registers"
+               show controller register state, and
+
+The contents of those files can help identify driver problems.
+
+
+Device drivers shouldn't care whether they're running over EHCI or not,
+but they may want to check for "usb_device->speed == USB_SPEED_HIGH".
+High speed devices can do things that full speed (or low speed) ones
+can't, such as "high bandwidth" periodic (interrupt or ISO) transfers.
+Also, some values in device descriptors (such as polling intervals for
+periodic transfers) use different encodings when operating at high speed.
+
+However, do make a point of testing device drivers through USB 2.0 hubs.
+Those hubs report some failures, such as disconnections, differently when
+transaction translators are in use; some drivers have been seen to behave
+badly when they see different faults than OHCI or UHCI report.
+
+
+Performance
+===========
+
+USB 2.0 throughput is gated by two main factors:  how fast the host
+controller can process requests, and how fast devices can respond to
+them.  The 480 Mbit/sec "raw transfer rate" is obeyed by all devices,
+but aggregate throughput is also affected by issues like delays between
+individual high speed packets, driver intelligence, and of course the
+overall system load.  Latency is also a performance concern.
+
+Bulk transfers are most often used where throughput is an issue.  It's
+good to keep in mind that bulk transfers are always in 512 byte packets,
+and at most 13 of those fit into one USB 2.0 microframe.  Eight USB 2.0
+microframes fit in a USB 1.1 frame; a microframe is 1 msec/8 = 125 usec.
+
+So more than 50 MByte/sec is available for bulk transfers, when both
+hardware and device driver software allow it.  Periodic transfer modes
+(isochronous and interrupt) allow the larger packet sizes which let you
+approach the quoted 480 MBit/sec transfer rate.
+
+Hardware Performance
+--------------------
+
+At this writing, individual USB 2.0 devices tend to max out at around
+20 MByte/sec transfer rates.  This is of course subject to change;
+and some devices now go faster, while others go slower.
+
+The first NEC implementation of EHCI seems to have a hardware bottleneck
+at around 28 MByte/sec aggregate transfer rate.  While this is clearly
+enough for a single device at 20 MByte/sec, putting three such devices
+onto one bus does not get you 60 MByte/sec.  The issue appears to be
+that the controller hardware won't do concurrent USB and PCI access,
+so that it's only trying six (or maybe seven) USB transactions each
+microframe rather than thirteen.  (Seems like a reasonable trade off
+for a product that beat all the others to market by over a year!)
+
+It's expected that newer implementations will better this, throwing
+more silicon real estate at the problem so that new motherboard chip
+sets will get closer to that 60 MByte/sec target.  That includes an
+updated implementation from NEC, as well as other vendors' silicon.
+
+There's a minimum latency of one microframe (125 usec) for the host
+to receive interrupts from the EHCI controller indicating completion
+of requests.  That latency is tunable; there's a module option.  By
+default ehci-hcd driver uses the minimum latency, which means that if
+you issue a control or bulk request you can often expect to learn that
+it completed in less than 250 usec (depending on transfer size).
+
+Software Performance
+--------------------
+
+To get even 20 MByte/sec transfer rates, Linux-USB device drivers will
+need to keep the EHCI queue full.  That means issuing large requests,
+or using bulk queuing if a series of small requests needs to be issued.
+When drivers don't do that, their performance results will show it.
+
+In typical situations, a usb_bulk_msg() loop writing out 4 KB chunks is
+going to waste more than half the USB 2.0 bandwidth.  Delays between the
+I/O completion and the driver issuing the next request will take longer
+than the I/O.  If that same loop used 16 KB chunks, it'd be better; a
+sequence of 128 KB chunks would waste a lot less.
+
+But rather than depending on such large I/O buffers to make synchronous
+I/O be efficient, it's better to just queue up several (bulk) requests
+to the HC, and wait for them all to complete (or be canceled on error).
+Such URB queuing should work with all the USB 1.1 HC drivers too.
+
+In the Linux 2.5 kernels, new usb_sg_*() api calls have been defined; they
+queue all the buffers from a scatterlist.  They also use scatterlist DMA
+mapping (which might apply an IOMMU) and IRQ reduction, all of which will
+help make high speed transfers run as fast as they can.
+
+
+TBD:
+   Interrupt and ISO transfer performance issues.  Those periodic
+   transfers are fully scheduled, so the main issue is likely to be how
+   to trigger "high bandwidth" modes.
+
+TBD:
+   More than standard 80% periodic bandwidth allocation is possible
+   through sysfs uframe_periodic_max parameter. Describe that.
diff --git a/Documentation/usb/ehci.txt b/Documentation/usb/ehci.txt
deleted file mode 100644 (file)
index 31f650e..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-===========
-EHCI driver
-===========
-
-27-Dec-2002
-
-The EHCI driver is used to talk to high speed USB 2.0 devices using
-USB 2.0-capable host controller hardware.  The USB 2.0 standard is
-compatible with the USB 1.1 standard. It defines three transfer speeds:
-
-    - "High Speed" 480 Mbit/sec (60 MByte/sec)
-    - "Full Speed" 12 Mbit/sec (1.5 MByte/sec)
-    - "Low Speed" 1.5 Mbit/sec
-
-USB 1.1 only addressed full speed and low speed.  High speed devices
-can be used on USB 1.1 systems, but they slow down to USB 1.1 speeds.
-
-USB 1.1 devices may also be used on USB 2.0 systems.  When plugged
-into an EHCI controller, they are given to a USB 1.1 "companion"
-controller, which is a OHCI or UHCI controller as normally used with
-such devices.  When USB 1.1 devices plug into USB 2.0 hubs, they
-interact with the EHCI controller through a "Transaction Translator"
-(TT) in the hub, which turns low or full speed transactions into
-high speed "split transactions" that don't waste transfer bandwidth.
-
-At this writing, this driver has been seen to work with implementations
-of EHCI from (in alphabetical order):  Intel, NEC, Philips, and VIA.
-Other EHCI implementations are becoming available from other vendors;
-you should expect this driver to work with them too.
-
-While usb-storage devices have been available since mid-2001 (working
-quite speedily on the 2.4 version of this driver), hubs have only
-been available since late 2001, and other kinds of high speed devices
-appear to be on hold until more systems come with USB 2.0 built-in.
-Such new systems have been available since early 2002, and became much
-more typical in the second half of 2002.
-
-Note that USB 2.0 support involves more than just EHCI.  It requires
-other changes to the Linux-USB core APIs, including the hub driver,
-but those changes haven't needed to really change the basic "usbcore"
-APIs exposed to USB device drivers.
-
-- David Brownell
-  <dbrownell@users.sourceforge.net>
-
-
-Functionality
-=============
-
-This driver is regularly tested on x86 hardware, and has also been
-used on PPC hardware so big/little endianness issues should be gone.
-It's believed to do all the right PCI magic so that I/O works even on
-systems with interesting DMA mapping issues.
-
-Transfer Types
---------------
-
-At this writing the driver should comfortably handle all control, bulk,
-and interrupt transfers, including requests to USB 1.1 devices through
-transaction translators (TTs) in USB 2.0 hubs.  But you may find bugs.
-
-High Speed Isochronous (ISO) transfer support is also functional, but
-at this writing no Linux drivers have been using that support.
-
-Full Speed Isochronous transfer support, through transaction translators,
-is not yet available.  Note that split transaction support for ISO
-transfers can't share much code with the code for high speed ISO transfers,
-since EHCI represents these with a different data structure.  So for now,
-most USB audio and video devices can't be connected to high speed buses.
-
-Driver Behavior
----------------
-
-Transfers of all types can be queued.  This means that control transfers
-from a driver on one interface (or through usbfs) won't interfere with
-ones from another driver, and that interrupt transfers can use periods
-of one frame without risking data loss due to interrupt processing costs.
-
-The EHCI root hub code hands off USB 1.1 devices to its companion
-controller.  This driver doesn't need to know anything about those
-drivers; a OHCI or UHCI driver that works already doesn't need to change
-just because the EHCI driver is also present.
-
-There are some issues with power management; suspend/resume doesn't
-behave quite right at the moment.
-
-Also, some shortcuts have been taken with the scheduling periodic
-transactions (interrupt and isochronous transfers).  These place some
-limits on the number of periodic transactions that can be scheduled,
-and prevent use of polling intervals of less than one frame.
-
-
-Use by
-======
-
-Assuming you have an EHCI controller (on a PCI card or motherboard)
-and have compiled this driver as a module, load this like::
-
-    # modprobe ehci-hcd
-
-and remove it by::
-
-    # rmmod ehci-hcd
-
-You should also have a driver for a "companion controller", such as
-"ohci-hcd"  or "uhci-hcd".  In case of any trouble with the EHCI driver,
-remove its module and then the driver for that companion controller will
-take over (at lower speed) all the devices that were previously handled
-by the EHCI driver.
-
-Module parameters (pass to "modprobe") include:
-
-    log2_irq_thresh (default 0):
-       Log2 of default interrupt delay, in microframes.  The default
-       value is 0, indicating 1 microframe (125 usec).  Maximum value
-       is 6, indicating 2^6 = 64 microframes.  This controls how often
-       the EHCI controller can issue interrupts.
-
-If you're using this driver on a 2.5 kernel, and you've enabled USB
-debugging support, you'll see three files in the "sysfs" directory for
-any EHCI controller:
-
-       "async"
-               dumps the asynchronous schedule, used for control
-               and bulk transfers.  Shows each active qh and the qtds
-               pending, usually one qtd per urb.  (Look at it with
-               usb-storage doing disk I/O; watch the request queues!)
-       "periodic"
-               dumps the periodic schedule, used for interrupt
-               and isochronous transfers.  Doesn't show qtds.
-       "registers"
-               show controller register state, and
-
-The contents of those files can help identify driver problems.
-
-
-Device drivers shouldn't care whether they're running over EHCI or not,
-but they may want to check for "usb_device->speed == USB_SPEED_HIGH".
-High speed devices can do things that full speed (or low speed) ones
-can't, such as "high bandwidth" periodic (interrupt or ISO) transfers.
-Also, some values in device descriptors (such as polling intervals for
-periodic transfers) use different encodings when operating at high speed.
-
-However, do make a point of testing device drivers through USB 2.0 hubs.
-Those hubs report some failures, such as disconnections, differently when
-transaction translators are in use; some drivers have been seen to behave
-badly when they see different faults than OHCI or UHCI report.
-
-
-Performance
-===========
-
-USB 2.0 throughput is gated by two main factors:  how fast the host
-controller can process requests, and how fast devices can respond to
-them.  The 480 Mbit/sec "raw transfer rate" is obeyed by all devices,
-but aggregate throughput is also affected by issues like delays between
-individual high speed packets, driver intelligence, and of course the
-overall system load.  Latency is also a performance concern.
-
-Bulk transfers are most often used where throughput is an issue.  It's
-good to keep in mind that bulk transfers are always in 512 byte packets,
-and at most 13 of those fit into one USB 2.0 microframe.  Eight USB 2.0
-microframes fit in a USB 1.1 frame; a microframe is 1 msec/8 = 125 usec.
-
-So more than 50 MByte/sec is available for bulk transfers, when both
-hardware and device driver software allow it.  Periodic transfer modes
-(isochronous and interrupt) allow the larger packet sizes which let you
-approach the quoted 480 MBit/sec transfer rate.
-
-Hardware Performance
---------------------
-
-At this writing, individual USB 2.0 devices tend to max out at around
-20 MByte/sec transfer rates.  This is of course subject to change;
-and some devices now go faster, while others go slower.
-
-The first NEC implementation of EHCI seems to have a hardware bottleneck
-at around 28 MByte/sec aggregate transfer rate.  While this is clearly
-enough for a single device at 20 MByte/sec, putting three such devices
-onto one bus does not get you 60 MByte/sec.  The issue appears to be
-that the controller hardware won't do concurrent USB and PCI access,
-so that it's only trying six (or maybe seven) USB transactions each
-microframe rather than thirteen.  (Seems like a reasonable trade off
-for a product that beat all the others to market by over a year!)
-
-It's expected that newer implementations will better this, throwing
-more silicon real estate at the problem so that new motherboard chip
-sets will get closer to that 60 MByte/sec target.  That includes an
-updated implementation from NEC, as well as other vendors' silicon.
-
-There's a minimum latency of one microframe (125 usec) for the host
-to receive interrupts from the EHCI controller indicating completion
-of requests.  That latency is tunable; there's a module option.  By
-default ehci-hcd driver uses the minimum latency, which means that if
-you issue a control or bulk request you can often expect to learn that
-it completed in less than 250 usec (depending on transfer size).
-
-Software Performance
---------------------
-
-To get even 20 MByte/sec transfer rates, Linux-USB device drivers will
-need to keep the EHCI queue full.  That means issuing large requests,
-or using bulk queuing if a series of small requests needs to be issued.
-When drivers don't do that, their performance results will show it.
-
-In typical situations, a usb_bulk_msg() loop writing out 4 KB chunks is
-going to waste more than half the USB 2.0 bandwidth.  Delays between the
-I/O completion and the driver issuing the next request will take longer
-than the I/O.  If that same loop used 16 KB chunks, it'd be better; a
-sequence of 128 KB chunks would waste a lot less.
-
-But rather than depending on such large I/O buffers to make synchronous
-I/O be efficient, it's better to just queue up several (bulk) requests
-to the HC, and wait for them all to complete (or be canceled on error).
-Such URB queuing should work with all the USB 1.1 HC drivers too.
-
-In the Linux 2.5 kernels, new usb_sg_*() api calls have been defined; they
-queue all the buffers from a scatterlist.  They also use scatterlist DMA
-mapping (which might apply an IOMMU) and IRQ reduction, all of which will
-help make high speed transfers run as fast as they can.
-
-
-TBD:
-   Interrupt and ISO transfer performance issues.  Those periodic
-   transfers are fully scheduled, so the main issue is likely to be how
-   to trigger "high bandwidth" modes.
-
-TBD:
-   More than standard 80% periodic bandwidth allocation is possible
-   through sysfs uframe_periodic_max parameter. Describe that.
diff --git a/Documentation/usb/functionfs.rst b/Documentation/usb/functionfs.rst
new file mode 100644 (file)
index 0000000..7fdc6d8
--- /dev/null
@@ -0,0 +1,68 @@
+====================
+How FunctionFS works
+====================
+
+From kernel point of view it is just a composite function with some
+unique behaviour.  It may be added to an USB configuration only after
+the user space driver has registered by writing descriptors and
+strings (the user space program has to provide the same information
+that kernel level composite functions provide when they are added to
+the configuration).
+
+This in particular means that the composite initialisation functions
+may not be in init section (ie. may not use the __init tag).
+
+From user space point of view it is a file system which when
+mounted provides an "ep0" file.  User space driver need to
+write descriptors and strings to that file.  It does not need
+to worry about endpoints, interfaces or strings numbers but
+simply provide descriptors such as if the function was the
+only one (endpoints and strings numbers starting from one and
+interface numbers starting from zero).  The FunctionFS changes
+them as needed also handling situation when numbers differ in
+different configurations.
+
+When descriptors and strings are written "ep#" files appear
+(one for each declared endpoint) which handle communication on
+a single endpoint.  Again, FunctionFS takes care of the real
+numbers and changing of the configuration (which means that
+"ep1" file may be really mapped to (say) endpoint 3 (and when
+configuration changes to (say) endpoint 2)).  "ep0" is used
+for receiving events and handling setup requests.
+
+When all files are closed the function disables itself.
+
+What I also want to mention is that the FunctionFS is designed in such
+a way that it is possible to mount it several times so in the end
+a gadget could use several FunctionFS functions. The idea is that
+each FunctionFS instance is identified by the device name used
+when mounting.
+
+One can imagine a gadget that has an Ethernet, MTP and HID interfaces
+where the last two are implemented via FunctionFS.  On user space
+level it would look like this::
+
+  $ insmod g_ffs.ko idVendor=<ID> iSerialNumber=<string> functions=mtp,hid
+  $ mkdir /dev/ffs-mtp && mount -t functionfs mtp /dev/ffs-mtp
+  $ ( cd /dev/ffs-mtp && mtp-daemon ) &
+  $ mkdir /dev/ffs-hid && mount -t functionfs hid /dev/ffs-hid
+  $ ( cd /dev/ffs-hid && hid-daemon ) &
+
+On kernel level the gadget checks ffs_data->dev_name to identify
+whether it's FunctionFS designed for MTP ("mtp") or HID ("hid").
+
+If no "functions" module parameters is supplied, the driver accepts
+just one function with any name.
+
+When "functions" module parameter is supplied, only functions
+with listed names are accepted. In particular, if the "functions"
+parameter's value is just a one-element list, then the behaviour
+is similar to when there is no "functions" at all; however,
+only a function with the specified name is accepted.
+
+The gadget is registered only after all the declared function
+filesystems have been mounted and USB descriptors of all functions
+have been written to their ep0's.
+
+Conversely, the gadget is unregistered after the first USB function
+closes its endpoints.
diff --git a/Documentation/usb/functionfs.txt b/Documentation/usb/functionfs.txt
deleted file mode 100644 (file)
index 7fdc6d8..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-====================
-How FunctionFS works
-====================
-
-From kernel point of view it is just a composite function with some
-unique behaviour.  It may be added to an USB configuration only after
-the user space driver has registered by writing descriptors and
-strings (the user space program has to provide the same information
-that kernel level composite functions provide when they are added to
-the configuration).
-
-This in particular means that the composite initialisation functions
-may not be in init section (ie. may not use the __init tag).
-
-From user space point of view it is a file system which when
-mounted provides an "ep0" file.  User space driver need to
-write descriptors and strings to that file.  It does not need
-to worry about endpoints, interfaces or strings numbers but
-simply provide descriptors such as if the function was the
-only one (endpoints and strings numbers starting from one and
-interface numbers starting from zero).  The FunctionFS changes
-them as needed also handling situation when numbers differ in
-different configurations.
-
-When descriptors and strings are written "ep#" files appear
-(one for each declared endpoint) which handle communication on
-a single endpoint.  Again, FunctionFS takes care of the real
-numbers and changing of the configuration (which means that
-"ep1" file may be really mapped to (say) endpoint 3 (and when
-configuration changes to (say) endpoint 2)).  "ep0" is used
-for receiving events and handling setup requests.
-
-When all files are closed the function disables itself.
-
-What I also want to mention is that the FunctionFS is designed in such
-a way that it is possible to mount it several times so in the end
-a gadget could use several FunctionFS functions. The idea is that
-each FunctionFS instance is identified by the device name used
-when mounting.
-
-One can imagine a gadget that has an Ethernet, MTP and HID interfaces
-where the last two are implemented via FunctionFS.  On user space
-level it would look like this::
-
-  $ insmod g_ffs.ko idVendor=<ID> iSerialNumber=<string> functions=mtp,hid
-  $ mkdir /dev/ffs-mtp && mount -t functionfs mtp /dev/ffs-mtp
-  $ ( cd /dev/ffs-mtp && mtp-daemon ) &
-  $ mkdir /dev/ffs-hid && mount -t functionfs hid /dev/ffs-hid
-  $ ( cd /dev/ffs-hid && hid-daemon ) &
-
-On kernel level the gadget checks ffs_data->dev_name to identify
-whether it's FunctionFS designed for MTP ("mtp") or HID ("hid").
-
-If no "functions" module parameters is supplied, the driver accepts
-just one function with any name.
-
-When "functions" module parameter is supplied, only functions
-with listed names are accepted. In particular, if the "functions"
-parameter's value is just a one-element list, then the behaviour
-is similar to when there is no "functions" at all; however,
-only a function with the specified name is accepted.
-
-The gadget is registered only after all the declared function
-filesystems have been mounted and USB descriptors of all functions
-have been written to their ep0's.
-
-Conversely, the gadget is unregistered after the first USB function
-closes its endpoints.
diff --git a/Documentation/usb/gadget-testing.rst b/Documentation/usb/gadget-testing.rst
new file mode 100644 (file)
index 0000000..2eeb3e9
--- /dev/null
@@ -0,0 +1,934 @@
+==============
+Gadget Testing
+==============
+
+This file summarizes information on basic testing of USB functions
+provided by gadgets.
+
+.. contents
+
+   1. ACM function
+   2. ECM function
+   3. ECM subset function
+   4. EEM function
+   5. FFS function
+   6. HID function
+   7. LOOPBACK function
+   8. MASS STORAGE function
+   9. MIDI function
+   10. NCM function
+   11. OBEX function
+   12. PHONET function
+   13. RNDIS function
+   14. SERIAL function
+   15. SOURCESINK function
+   16. UAC1 function (legacy implementation)
+   17. UAC2 function
+   18. UVC function
+   19. PRINTER function
+   20. UAC1 function (new API)
+
+
+1. ACM function
+===============
+
+The function is provided by usb_f_acm.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "acm".
+The ACM function provides just one attribute in its function directory:
+
+       port_num
+
+The attribute is read-only.
+
+There can be at most 4 ACM/generic serial/OBEX ports in the system.
+
+
+Testing the ACM function
+------------------------
+
+On the host::
+
+       cat > /dev/ttyACM<X>
+
+On the device::
+
+       cat /dev/ttyGS<Y>
+
+then the other way round
+
+On the device::
+
+       cat > /dev/ttyGS<Y>
+
+On the host::
+
+       cat /dev/ttyACM<X>
+
+2. ECM function
+===============
+
+The function is provided by usb_f_ecm.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "ecm".
+The ECM function provides these attributes in its function directory:
+
+       =============== ==================================================
+       ifname          network device interface name associated with this
+                       function instance
+       qmult           queue length multiplier for high and super speed
+       host_addr       MAC address of host's end of this
+                       Ethernet over USB link
+       dev_addr        MAC address of device's end of this
+                       Ethernet over USB link
+       =============== ==================================================
+
+and after creating the functions/ecm.<instance name> they contain default
+values: qmult is 5, dev_addr and host_addr are randomly selected.
+Except for ifname they can be written to until the function is linked to a
+configuration. The ifname is read-only and contains the name of the interface
+which was assigned by the net core, e. g. usb0.
+
+Testing the ECM function
+------------------------
+
+Configure IP addresses of the device and the host. Then:
+
+On the device::
+
+       ping <host's IP>
+
+On the host::
+
+       ping <device's IP>
+
+3. ECM subset function
+======================
+
+The function is provided by usb_f_ecm_subset.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "geth".
+The ECM subset function provides these attributes in its function directory:
+
+       =============== ==================================================
+       ifname          network device interface name associated with this
+                       function instance
+       qmult           queue length multiplier for high and super speed
+       host_addr       MAC address of host's end of this
+                       Ethernet over USB link
+       dev_addr        MAC address of device's end of this
+                       Ethernet over USB link
+       =============== ==================================================
+
+and after creating the functions/ecm.<instance name> they contain default
+values: qmult is 5, dev_addr and host_addr are randomly selected.
+Except for ifname they can be written to until the function is linked to a
+configuration. The ifname is read-only and contains the name of the interface
+which was assigned by the net core, e. g. usb0.
+
+Testing the ECM subset function
+-------------------------------
+
+Configure IP addresses of the device and the host. Then:
+
+On the device::
+
+       ping <host's IP>
+
+On the host::
+
+       ping <device's IP>
+
+4. EEM function
+===============
+
+The function is provided by usb_f_eem.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "eem".
+The EEM function provides these attributes in its function directory:
+
+       =============== ==================================================
+       ifname          network device interface name associated with this
+                       function instance
+       qmult           queue length multiplier for high and super speed
+       host_addr       MAC address of host's end of this
+                       Ethernet over USB link
+       dev_addr        MAC address of device's end of this
+                       Ethernet over USB link
+       =============== ==================================================
+
+and after creating the functions/eem.<instance name> they contain default
+values: qmult is 5, dev_addr and host_addr are randomly selected.
+Except for ifname they can be written to until the function is linked to a
+configuration. The ifname is read-only and contains the name of the interface
+which was assigned by the net core, e. g. usb0.
+
+Testing the EEM function
+------------------------
+
+Configure IP addresses of the device and the host. Then:
+
+On the device::
+
+       ping <host's IP>
+
+On the host::
+
+       ping <device's IP>
+
+5. FFS function
+===============
+
+The function is provided by usb_f_fs.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "ffs".
+The function directory is intentionally empty and not modifiable.
+
+After creating the directory there is a new instance (a "device") of FunctionFS
+available in the system. Once a "device" is available, the user should follow
+the standard procedure for using FunctionFS (mount it, run the userspace
+process which implements the function proper). The gadget should be enabled
+by writing a suitable string to usb_gadget/<gadget>/UDC.
+
+Testing the FFS function
+------------------------
+
+On the device: start the function's userspace daemon, enable the gadget
+
+On the host: use the USB function provided by the device
+
+6. HID function
+===============
+
+The function is provided by usb_f_hid.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "hid".
+The HID function provides these attributes in its function directory:
+
+       =============== ===========================================
+       protocol        HID protocol to use
+       report_desc     data to be used in HID reports, except data
+                       passed with /dev/hidg<X>
+       report_length   HID report length
+       subclass        HID subclass to use
+       =============== ===========================================
+
+For a keyboard the protocol and the subclass are 1, the report_length is 8,
+while the report_desc is::
+
+  $ hd my_report_desc
+  00000000  05 01 09 06 a1 01 05 07  19 e0 29 e7 15 00 25 01  |..........)...%.|
+  00000010  75 01 95 08 81 02 95 01  75 08 81 03 95 05 75 01  |u.......u.....u.|
+  00000020  05 08 19 01 29 05 91 02  95 01 75 03 91 03 95 06  |....).....u.....|
+  00000030  75 08 15 00 25 65 05 07  19 00 29 65 81 00 c0     |u...%e....)e...|
+  0000003f
+
+Such a sequence of bytes can be stored to the attribute with echo::
+
+  $ echo -ne \\x05\\x01\\x09\\x06\\xa1.....
+
+Testing the HID function
+------------------------
+
+Device:
+
+- create the gadget
+- connect the gadget to a host, preferably not the one used
+  to control the gadget
+- run a program which writes to /dev/hidg<N>, e.g.
+  a userspace program found in Documentation/usb/gadget_hid.rst::
+
+       $ ./hid_gadget_test /dev/hidg0 keyboard
+
+Host:
+
+- observe the keystrokes from the gadget
+
+7. LOOPBACK function
+====================
+
+The function is provided by usb_f_ss_lb.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "Loopback".
+The LOOPBACK function provides these attributes in its function directory:
+
+       =============== =======================
+       qlen            depth of loopback queue
+       bulk_buflen     buffer length
+       =============== =======================
+
+Testing the LOOPBACK function
+-----------------------------
+
+device: run the gadget
+
+host: test-usb (tools/usb/testusb.c)
+
+8. MASS STORAGE function
+========================
+
+The function is provided by usb_f_mass_storage.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "mass_storage".
+The MASS STORAGE function provides these attributes in its directory:
+files:
+
+       =============== ==============================================
+       stall           Set to permit function to halt bulk endpoints.
+                       Disabled on some USB devices known not to work
+                       correctly. You should set it to true.
+       num_buffers     Number of pipeline buffers. Valid numbers
+                       are 2..4. Available only if
+                       CONFIG_USB_GADGET_DEBUG_FILES is set.
+       =============== ==============================================
+
+and a default lun.0 directory corresponding to SCSI LUN #0.
+
+A new lun can be added with mkdir::
+
+       $ mkdir functions/mass_storage.0/partition.5
+
+Lun numbering does not have to be continuous, except for lun #0 which is
+created by default. A maximum of 8 luns can be specified and they all must be
+named following the <name>.<number> scheme. The numbers can be 0..8.
+Probably a good convention is to name the luns "lun.<number>",
+although it is not mandatory.
+
+In each lun directory there are the following attribute files:
+
+       =============== ==============================================
+       file            The path to the backing file for the LUN.
+                       Required if LUN is not marked as removable.
+       ro              Flag specifying access to the LUN shall be
+                       read-only. This is implied if CD-ROM emulation
+                       is enabled as well as when it was impossible
+                       to open "filename" in R/W mode.
+       removable       Flag specifying that LUN shall be indicated as
+                       being removable.
+       cdrom           Flag specifying that LUN shall be reported as
+                       being a CD-ROM.
+       nofua           Flag specifying that FUA flag
+                       in SCSI WRITE(10,12)
+       =============== ==============================================
+
+Testing the MASS STORAGE function
+---------------------------------
+
+device: connect the gadget, enable it
+host: dmesg, see the USB drives appear (if system configured to automatically
+mount)
+
+9. MIDI function
+================
+
+The function is provided by usb_f_midi.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "midi".
+The MIDI function provides these attributes in its function directory:
+
+       =============== ====================================
+       buflen          MIDI buffer length
+       id              ID string for the USB MIDI adapter
+       in_ports        number of MIDI input ports
+       index           index value for the USB MIDI adapter
+       out_ports       number of MIDI output ports
+       qlen            USB read request queue length
+       =============== ====================================
+
+Testing the MIDI function
+-------------------------
+
+There are two cases: playing a mid from the gadget to
+the host and playing a mid from the host to the gadget.
+
+1) Playing a mid from the gadget to the host:
+
+host::
+
+  $ arecordmidi -l
+   Port    Client name                      Port name
+   14:0    Midi Through                     Midi Through Port-0
+   24:0    MIDI Gadget                      MIDI Gadget MIDI 1
+  $ arecordmidi -p 24:0 from_gadget.mid
+
+gadget::
+
+  $ aplaymidi -l
+   Port    Client name                      Port name
+   20:0    f_midi                           f_midi
+
+  $ aplaymidi -p 20:0 to_host.mid
+
+2) Playing a mid from the host to the gadget
+
+gadget::
+
+  $ arecordmidi -l
+   Port    Client name                      Port name
+   20:0    f_midi                           f_midi
+
+  $ arecordmidi -p 20:0 from_host.mid
+
+host::
+
+  $ aplaymidi -l
+   Port    Client name                      Port name
+   14:0    Midi Through                     Midi Through Port-0
+   24:0    MIDI Gadget                      MIDI Gadget MIDI 1
+
+  $ aplaymidi -p24:0 to_gadget.mid
+
+The from_gadget.mid should sound identical to the to_host.mid.
+
+The from_host.id should sound identical to the to_gadget.mid.
+
+MIDI files can be played to speakers/headphones with e.g. timidity installed::
+
+  $ aplaymidi -l
+   Port    Client name                      Port name
+   14:0    Midi Through                     Midi Through Port-0
+   24:0    MIDI Gadget                      MIDI Gadget MIDI 1
+  128:0    TiMidity                         TiMidity port 0
+  128:1    TiMidity                         TiMidity port 1
+  128:2    TiMidity                         TiMidity port 2
+  128:3    TiMidity                         TiMidity port 3
+
+  $ aplaymidi -p 128:0 file.mid
+
+MIDI ports can be logically connected using the aconnect utility, e.g.::
+
+  $ aconnect 24:0 128:0 # try it on the host
+
+After the gadget's MIDI port is connected to timidity's MIDI port,
+whatever is played at the gadget side with aplaymidi -l is audible
+in host's speakers/headphones.
+
+10. NCM function
+================
+
+The function is provided by usb_f_ncm.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "ncm".
+The NCM function provides these attributes in its function directory:
+
+       =============== ==================================================
+       ifname          network device interface name associated with this
+                       function instance
+       qmult           queue length multiplier for high and super speed
+       host_addr       MAC address of host's end of this
+                       Ethernet over USB link
+       dev_addr        MAC address of device's end of this
+                       Ethernet over USB link
+       =============== ==================================================
+
+and after creating the functions/ncm.<instance name> they contain default
+values: qmult is 5, dev_addr and host_addr are randomly selected.
+Except for ifname they can be written to until the function is linked to a
+configuration. The ifname is read-only and contains the name of the interface
+which was assigned by the net core, e. g. usb0.
+
+Testing the NCM function
+------------------------
+
+Configure IP addresses of the device and the host. Then:
+
+On the device::
+
+       ping <host's IP>
+
+On the host::
+
+       ping <device's IP>
+
+11. OBEX function
+=================
+
+The function is provided by usb_f_obex.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "obex".
+The OBEX function provides just one attribute in its function directory:
+
+       port_num
+
+The attribute is read-only.
+
+There can be at most 4 ACM/generic serial/OBEX ports in the system.
+
+Testing the OBEX function
+-------------------------
+
+On device::
+
+       seriald -f /dev/ttyGS<Y> -s 1024
+
+On host::
+
+       serialc -v <vendorID> -p <productID> -i<interface#> -a1 -s1024 \
+                -t<out endpoint addr> -r<in endpoint addr>
+
+where seriald and serialc are Felipe's utilities found here:
+
+       https://github.com/felipebalbi/usb-tools.git master
+
+12. PHONET function
+===================
+
+The function is provided by usb_f_phonet.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "phonet".
+The PHONET function provides just one attribute in its function directory:
+
+       =============== ==================================================
+       ifname          network device interface name associated with this
+                       function instance
+       =============== ==================================================
+
+Testing the PHONET function
+---------------------------
+
+It is not possible to test the SOCK_STREAM protocol without a specific piece
+of hardware, so only SOCK_DGRAM has been tested. For the latter to work,
+in the past I had to apply the patch mentioned here:
+
+http://www.spinics.net/lists/linux-usb/msg85689.html
+
+These tools are required:
+
+git://git.gitorious.org/meego-cellular/phonet-utils.git
+
+On the host::
+
+       $ ./phonet -a 0x10 -i usbpn0
+       $ ./pnroute add 0x6c usbpn0
+       $./pnroute add 0x10 usbpn0
+       $ ifconfig usbpn0 up
+
+On the device::
+
+       $ ./phonet -a 0x6c -i upnlink0
+       $ ./pnroute add 0x10 upnlink0
+       $ ifconfig upnlink0 up
+
+Then a test program can be used::
+
+       http://www.spinics.net/lists/linux-usb/msg85690.html
+
+On the device::
+
+       $ ./pnxmit -a 0x6c -r
+
+On the host::
+
+       $ ./pnxmit -a 0x10 -s 0x6c
+
+As a result some data should be sent from host to device.
+Then the other way round:
+
+On the host::
+
+       $ ./pnxmit -a 0x10 -r
+
+On the device::
+
+       $ ./pnxmit -a 0x6c -s 0x10
+
+13. RNDIS function
+==================
+
+The function is provided by usb_f_rndis.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "rndis".
+The RNDIS function provides these attributes in its function directory:
+
+       =============== ==================================================
+       ifname          network device interface name associated with this
+                       function instance
+       qmult           queue length multiplier for high and super speed
+       host_addr       MAC address of host's end of this
+                       Ethernet over USB link
+       dev_addr        MAC address of device's end of this
+                       Ethernet over USB link
+       =============== ==================================================
+
+and after creating the functions/rndis.<instance name> they contain default
+values: qmult is 5, dev_addr and host_addr are randomly selected.
+Except for ifname they can be written to until the function is linked to a
+configuration. The ifname is read-only and contains the name of the interface
+which was assigned by the net core, e. g. usb0.
+
+Testing the RNDIS function
+--------------------------
+
+Configure IP addresses of the device and the host. Then:
+
+On the device::
+
+       ping <host's IP>
+
+On the host::
+
+       ping <device's IP>
+
+14. SERIAL function
+===================
+
+The function is provided by usb_f_gser.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "gser".
+The SERIAL function provides just one attribute in its function directory:
+
+       port_num
+
+The attribute is read-only.
+
+There can be at most 4 ACM/generic serial/OBEX ports in the system.
+
+Testing the SERIAL function
+---------------------------
+
+On host::
+
+       insmod usbserial
+       echo VID PID >/sys/bus/usb-serial/drivers/generic/new_id
+
+On host::
+
+       cat > /dev/ttyUSB<X>
+
+On target::
+
+       cat /dev/ttyGS<Y>
+
+then the other way round
+
+On target::
+
+       cat > /dev/ttyGS<Y>
+
+On host::
+
+       cat /dev/ttyUSB<X>
+
+15. SOURCESINK function
+=======================
+
+The function is provided by usb_f_ss_lb.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "SourceSink".
+The SOURCESINK function provides these attributes in its function directory:
+
+       =============== ==================================
+       pattern         0 (all zeros), 1 (mod63), 2 (none)
+       isoc_interval   1..16
+       isoc_maxpacket  0 - 1023 (fs), 0 - 1024 (hs/ss)
+       isoc_mult       0..2 (hs/ss only)
+       isoc_maxburst   0..15 (ss only)
+       bulk_buflen     buffer length
+       bulk_qlen       depth of queue for bulk
+       iso_qlen        depth of queue for iso
+       =============== ==================================
+
+Testing the SOURCESINK function
+-------------------------------
+
+device: run the gadget
+
+host: test-usb (tools/usb/testusb.c)
+
+
+16. UAC1 function (legacy implementation)
+=========================================
+
+The function is provided by usb_f_uac1_legacy.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory
+is "uac1_legacy".
+The uac1 function provides these attributes in its function directory:
+
+       =============== ====================================
+       audio_buf_size  audio buffer size
+       fn_cap          capture pcm device file name
+       fn_cntl         control device file name
+       fn_play         playback pcm device file name
+       req_buf_size    ISO OUT endpoint request buffer size
+       req_count       ISO OUT endpoint request count
+       =============== ====================================
+
+The attributes have sane default values.
+
+Testing the UAC1 function
+-------------------------
+
+device: run the gadget
+
+host::
+
+       aplay -l # should list our USB Audio Gadget
+
+17. UAC2 function
+=================
+
+The function is provided by usb_f_uac2.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "uac2".
+The uac2 function provides these attributes in its function directory:
+
+       =============== ====================================================
+       c_chmask        capture channel mask
+       c_srate         capture sampling rate
+       c_ssize         capture sample size (bytes)
+       p_chmask        playback channel mask
+       p_srate         playback sampling rate
+       p_ssize         playback sample size (bytes)
+       req_number      the number of pre-allocated request for both capture
+                       and playback
+       =============== ====================================================
+
+The attributes have sane default values.
+
+Testing the UAC2 function
+-------------------------
+
+device: run the gadget
+host: aplay -l # should list our USB Audio Gadget
+
+This function does not require real hardware support, it just
+sends a stream of audio data to/from the host. In order to
+actually hear something at the device side, a command similar
+to this must be used at the device side::
+
+       $ arecord -f dat -t wav -D hw:2,0 | aplay -D hw:0,0 &
+
+e.g.::
+
+       $ arecord -f dat -t wav -D hw:CARD=UAC2Gadget,DEV=0 | \
+         aplay -D default:CARD=OdroidU3
+
+18. UVC function
+================
+
+The function is provided by usb_f_uvc.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "uvc".
+The uvc function provides these attributes in its function directory:
+
+       =================== ================================================
+       streaming_interval  interval for polling endpoint for data transfers
+       streaming_maxburst  bMaxBurst for super speed companion descriptor
+       streaming_maxpacket maximum packet size this endpoint is capable of
+                           sending or receiving when this configuration is
+                           selected
+       =================== ================================================
+
+There are also "control" and "streaming" subdirectories, each of which contain
+a number of their subdirectories. There are some sane defaults provided, but
+the user must provide the following:
+
+       ================== ====================================================
+       control header     create in control/header, link from control/class/fs
+                          and/or control/class/ss
+       streaming header   create in streaming/header, link from
+                          streaming/class/fs and/or streaming/class/hs and/or
+                          streaming/class/ss
+       format description create in streaming/mjpeg and/or
+                          streaming/uncompressed
+       frame description  create in streaming/mjpeg/<format> and/or in
+                          streaming/uncompressed/<format>
+       ================== ====================================================
+
+Each frame description contains frame interval specification, and each
+such specification consists of a number of lines with an inverval value
+in each line. The rules stated above are best illustrated with an example::
+
+  # mkdir functions/uvc.usb0/control/header/h
+  # cd functions/uvc.usb0/control/
+  # ln -s header/h class/fs
+  # ln -s header/h class/ss
+  # mkdir -p functions/uvc.usb0/streaming/uncompressed/u/360p
+  # cat <<EOF > functions/uvc.usb0/streaming/uncompressed/u/360p/dwFrameInterval
+  666666
+  1000000
+  5000000
+  EOF
+  # cd $GADGET_CONFIGFS_ROOT
+  # mkdir functions/uvc.usb0/streaming/header/h
+  # cd functions/uvc.usb0/streaming/header/h
+  # ln -s ../../uncompressed/u
+  # cd ../../class/fs
+  # ln -s ../../header/h
+  # cd ../../class/hs
+  # ln -s ../../header/h
+  # cd ../../class/ss
+  # ln -s ../../header/h
+
+
+Testing the UVC function
+------------------------
+
+device: run the gadget, modprobe vivid::
+
+  # uvc-gadget -u /dev/video<uvc video node #> -v /dev/video<vivid video node #>
+
+where uvc-gadget is this program:
+       http://git.ideasonboard.org/uvc-gadget.git
+
+with these patches:
+
+       http://www.spinics.net/lists/linux-usb/msg99220.html
+
+host::
+
+       luvcview -f yuv
+
+19. PRINTER function
+====================
+
+The function is provided by usb_f_printer.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "printer".
+The printer function provides these attributes in its function directory:
+
+       ==========      ===========================================
+       pnp_string      Data to be passed to the host in pnp string
+       q_len           Number of requests per endpoint
+       ==========      ===========================================
+
+Testing the PRINTER function
+----------------------------
+
+The most basic testing:
+
+device: run the gadget::
+
+       # ls -l /devices/virtual/usb_printer_gadget/
+
+should show g_printer<number>.
+
+If udev is active, then /dev/g_printer<number> should appear automatically.
+
+host:
+
+If udev is active, then e.g. /dev/usb/lp0 should appear.
+
+host->device transmission:
+
+device::
+
+       # cat /dev/g_printer<number>
+
+host::
+
+       # cat > /dev/usb/lp0
+
+device->host transmission::
+
+       # cat > /dev/g_printer<number>
+
+host::
+
+       # cat /dev/usb/lp0
+
+More advanced testing can be done with the prn_example
+described in Documentation/usb/gadget_printer.rst.
+
+
+20. UAC1 function (virtual ALSA card, using u_audio API)
+========================================================
+
+The function is provided by usb_f_uac1.ko module.
+It will create a virtual ALSA card and the audio streams are simply
+sinked to and sourced from it.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "uac1".
+The uac1 function provides these attributes in its function directory:
+
+       ========== ====================================================
+       c_chmask   capture channel mask
+       c_srate    capture sampling rate
+       c_ssize    capture sample size (bytes)
+       p_chmask   playback channel mask
+       p_srate    playback sampling rate
+       p_ssize    playback sample size (bytes)
+       req_number the number of pre-allocated request for both capture
+                  and playback
+       ========== ====================================================
+
+The attributes have sane default values.
+
+Testing the UAC1 function
+-------------------------
+
+device: run the gadget
+host: aplay -l # should list our USB Audio Gadget
+
+This function does not require real hardware support, it just
+sends a stream of audio data to/from the host. In order to
+actually hear something at the device side, a command similar
+to this must be used at the device side::
+
+       $ arecord -f dat -t wav -D hw:2,0 | aplay -D hw:0,0 &
+
+e.g.::
+
+       $ arecord -f dat -t wav -D hw:CARD=UAC1Gadget,DEV=0 | \
+         aplay -D default:CARD=OdroidU3
diff --git a/Documentation/usb/gadget-testing.txt b/Documentation/usb/gadget-testing.txt
deleted file mode 100644 (file)
index 7d7f234..0000000
+++ /dev/null
@@ -1,934 +0,0 @@
-==============
-Gadget Testing
-==============
-
-This file summarizes information on basic testing of USB functions
-provided by gadgets.
-
-.. contents
-
-   1. ACM function
-   2. ECM function
-   3. ECM subset function
-   4. EEM function
-   5. FFS function
-   6. HID function
-   7. LOOPBACK function
-   8. MASS STORAGE function
-   9. MIDI function
-   10. NCM function
-   11. OBEX function
-   12. PHONET function
-   13. RNDIS function
-   14. SERIAL function
-   15. SOURCESINK function
-   16. UAC1 function (legacy implementation)
-   17. UAC2 function
-   18. UVC function
-   19. PRINTER function
-   20. UAC1 function (new API)
-
-
-1. ACM function
-===============
-
-The function is provided by usb_f_acm.ko module.
-
-Function-specific configfs interface
-------------------------------------
-
-The function name to use when creating the function directory is "acm".
-The ACM function provides just one attribute in its function directory:
-
-       port_num
-
-The attribute is read-only.
-
-There can be at most 4 ACM/generic serial/OBEX ports in the system.
-
-
-Testing the ACM function
-------------------------
-
-On the host::
-
-       cat > /dev/ttyACM<X>
-
-On the device::
-
-       cat /dev/ttyGS<Y>
-
-then the other way round
-
-On the device::
-
-       cat > /dev/ttyGS<Y>
-
-On the host::
-
-       cat /dev/ttyACM<X>
-
-2. ECM function
-===============
-
-The function is provided by usb_f_ecm.ko module.
-
-Function-specific configfs interface
-------------------------------------
-
-The function name to use when creating the function directory is "ecm".
-The ECM function provides these attributes in its function directory:
-
-       =============== ==================================================
-       ifname          network device interface name associated with this
-                       function instance
-       qmult           queue length multiplier for high and super speed
-       host_addr       MAC address of host's end of this
-                       Ethernet over USB link
-       dev_addr        MAC address of device's end of this
-                       Ethernet over USB link
-       =============== ==================================================
-
-and after creating the functions/ecm.<instance name> they contain default
-values: qmult is 5, dev_addr and host_addr are randomly selected.
-Except for ifname they can be written to until the function is linked to a
-configuration. The ifname is read-only and contains the name of the interface
-which was assigned by the net core, e. g. usb0.
-
-Testing the ECM function
-------------------------
-
-Configure IP addresses of the device and the host. Then:
-
-On the device::
-
-       ping <host's IP>
-
-On the host::
-
-       ping <device's IP>
-
-3. ECM subset function
-======================
-
-The function is provided by usb_f_ecm_subset.ko module.
-
-Function-specific configfs interface
-------------------------------------
-
-The function name to use when creating the function directory is "geth".
-The ECM subset function provides these attributes in its function directory:
-
-       =============== ==================================================
-       ifname          network device interface name associated with this
-                       function instance
-       qmult           queue length multiplier for high and super speed
-       host_addr       MAC address of host's end of this
-                       Ethernet over USB link
-       dev_addr        MAC address of device's end of this
-                       Ethernet over USB link
-       =============== ==================================================
-
-and after creating the functions/ecm.<instance name> they contain default
-values: qmult is 5, dev_addr and host_addr are randomly selected.
-Except for ifname they can be written to until the function is linked to a
-configuration. The ifname is read-only and contains the name of the interface
-which was assigned by the net core, e. g. usb0.
-
-Testing the ECM subset function
--------------------------------
-
-Configure IP addresses of the device and the host. Then:
-
-On the device::
-
-       ping <host's IP>
-
-On the host::
-
-       ping <device's IP>
-
-4. EEM function
-===============
-
-The function is provided by usb_f_eem.ko module.
-
-Function-specific configfs interface
-------------------------------------
-
-The function name to use when creating the function directory is "eem".
-The EEM function provides these attributes in its function directory:
-
-       =============== ==================================================
-       ifname          network device interface name associated with this
-                       function instance
-       qmult           queue length multiplier for high and super speed
-       host_addr       MAC address of host's end of this
-                       Ethernet over USB link
-       dev_addr        MAC address of device's end of this
-                       Ethernet over USB link
-       =============== ==================================================
-
-and after creating the functions/eem.<instance name> they contain default
-values: qmult is 5, dev_addr and host_addr are randomly selected.
-Except for ifname they can be written to until the function is linked to a
-configuration. The ifname is read-only and contains the name of the interface
-which was assigned by the net core, e. g. usb0.
-
-Testing the EEM function
-------------------------
-
-Configure IP addresses of the device and the host. Then:
-
-On the device::
-
-       ping <host's IP>
-
-On the host::
-
-       ping <device's IP>
-
-5. FFS function
-===============
-
-The function is provided by usb_f_fs.ko module.
-
-Function-specific configfs interface
-------------------------------------
-
-The function name to use when creating the function directory is "ffs".
-The function directory is intentionally empty and not modifiable.
-
-After creating the directory there is a new instance (a "device") of FunctionFS
-available in the system. Once a "device" is available, the user should follow
-the standard procedure for using FunctionFS (mount it, run the userspace
-process which implements the function proper). The gadget should be enabled
-by writing a suitable string to usb_gadget/<gadget>/UDC.
-
-Testing the FFS function
-------------------------
-
-On the device: start the function's userspace daemon, enable the gadget
-
-On the host: use the USB function provided by the device
-
-6. HID function
-===============
-
-The function is provided by usb_f_hid.ko module.
-
-Function-specific configfs interface
-------------------------------------
-
-The function name to use when creating the function directory is "hid".
-The HID function provides these attributes in its function directory:
-
-       =============== ===========================================
-       protocol        HID protocol to use
-       report_desc     data to be used in HID reports, except data
-                       passed with /dev/hidg<X>
-       report_length   HID report length
-       subclass        HID subclass to use
-       =============== ===========================================
-
-For a keyboard the protocol and the subclass are 1, the report_length is 8,
-while the report_desc is::
-
-  $ hd my_report_desc
-  00000000  05 01 09 06 a1 01 05 07  19 e0 29 e7 15 00 25 01  |..........)...%.|
-  00000010  75 01 95 08 81 02 95 01  75 08 81 03 95 05 75 01  |u.......u.....u.|
-  00000020  05 08 19 01 29 05 91 02  95 01 75 03 91 03 95 06  |....).....u.....|
-  00000030  75 08 15 00 25 65 05 07  19 00 29 65 81 00 c0     |u...%e....)e...|
-  0000003f
-
-Such a sequence of bytes can be stored to the attribute with echo::
-
-  $ echo -ne \\x05\\x01\\x09\\x06\\xa1.....
-
-Testing the HID function
-------------------------
-
-Device:
-
-- create the gadget
-- connect the gadget to a host, preferably not the one used
-  to control the gadget
-- run a program which writes to /dev/hidg<N>, e.g.
-  a userspace program found in Documentation/usb/gadget_hid.txt::
-
-       $ ./hid_gadget_test /dev/hidg0 keyboard
-
-Host:
-
-- observe the keystrokes from the gadget
-
-7. LOOPBACK function
-====================
-
-The function is provided by usb_f_ss_lb.ko module.
-
-Function-specific configfs interface
-------------------------------------
-
-The function name to use when creating the function directory is "Loopback".
-The LOOPBACK function provides these attributes in its function directory:
-
-       =============== =======================
-       qlen            depth of loopback queue
-       bulk_buflen     buffer length
-       =============== =======================
-
-Testing the LOOPBACK function
------------------------------
-
-device: run the gadget
-
-host: test-usb (tools/usb/testusb.c)
-
-8. MASS STORAGE function
-========================
-
-The function is provided by usb_f_mass_storage.ko module.
-
-Function-specific configfs interface
-------------------------------------
-
-The function name to use when creating the function directory is "mass_storage".
-The MASS STORAGE function provides these attributes in its directory:
-files:
-
-       =============== ==============================================
-       stall           Set to permit function to halt bulk endpoints.
-                       Disabled on some USB devices known not to work
-                       correctly. You should set it to true.
-       num_buffers     Number of pipeline buffers. Valid numbers
-                       are 2..4. Available only if
-                       CONFIG_USB_GADGET_DEBUG_FILES is set.
-       =============== ==============================================
-
-and a default lun.0 directory corresponding to SCSI LUN #0.
-
-A new lun can be added with mkdir::
-
-       $ mkdir functions/mass_storage.0/partition.5
-
-Lun numbering does not have to be continuous, except for lun #0 which is
-created by default. A maximum of 8 luns can be specified and they all must be
-named following the <name>.<number> scheme. The numbers can be 0..8.
-Probably a good convention is to name the luns "lun.<number>",
-although it is not mandatory.
-
-In each lun directory there are the following attribute files:
-
-       =============== ==============================================
-       file            The path to the backing file for the LUN.
-                       Required if LUN is not marked as removable.
-       ro              Flag specifying access to the LUN shall be
-                       read-only. This is implied if CD-ROM emulation
-                       is enabled as well as when it was impossible
-                       to open "filename" in R/W mode.
-       removable       Flag specifying that LUN shall be indicated as
-                       being removable.
-       cdrom           Flag specifying that LUN shall be reported as
-                       being a CD-ROM.
-       nofua           Flag specifying that FUA flag
-                       in SCSI WRITE(10,12)
-       =============== ==============================================
-
-Testing the MASS STORAGE function
----------------------------------
-
-device: connect the gadget, enable it
-host: dmesg, see the USB drives appear (if system configured to automatically
-mount)
-
-9. MIDI function
-================
-
-The function is provided by usb_f_midi.ko module.
-
-Function-specific configfs interface
-------------------------------------
-
-The function name to use when creating the function directory is "midi".
-The MIDI function provides these attributes in its function directory:
-
-       =============== ====================================
-       buflen          MIDI buffer length
-       id              ID string for the USB MIDI adapter
-       in_ports        number of MIDI input ports
-       index           index value for the USB MIDI adapter
-       out_ports       number of MIDI output ports
-       qlen            USB read request queue length
-       =============== ====================================
-
-Testing the MIDI function
--------------------------
-
-There are two cases: playing a mid from the gadget to
-the host and playing a mid from the host to the gadget.
-
-1) Playing a mid from the gadget to the host:
-
-host::
-
-  $ arecordmidi -l
-   Port    Client name                      Port name
-   14:0    Midi Through                     Midi Through Port-0
-   24:0    MIDI Gadget                      MIDI Gadget MIDI 1
-  $ arecordmidi -p 24:0 from_gadget.mid
-
-gadget::
-
-  $ aplaymidi -l
-   Port    Client name                      Port name
-   20:0    f_midi                           f_midi
-
-  $ aplaymidi -p 20:0 to_host.mid
-
-2) Playing a mid from the host to the gadget
-
-gadget::
-
-  $ arecordmidi -l
-   Port    Client name                      Port name
-   20:0    f_midi                           f_midi
-
-  $ arecordmidi -p 20:0 from_host.mid
-
-host::
-
-  $ aplaymidi -l
-   Port    Client name                      Port name
-   14:0    Midi Through                     Midi Through Port-0
-   24:0    MIDI Gadget                      MIDI Gadget MIDI 1
-
-  $ aplaymidi -p24:0 to_gadget.mid
-
-The from_gadget.mid should sound identical to the to_host.mid.
-
-The from_host.id should sound identical to the to_gadget.mid.
-
-MIDI files can be played to speakers/headphones with e.g. timidity installed::
-
-  $ aplaymidi -l
-   Port    Client name                      Port name
-   14:0    Midi Through                     Midi Through Port-0
-   24:0    MIDI Gadget                      MIDI Gadget MIDI 1
-  128:0    TiMidity                         TiMidity port 0
-  128:1    TiMidity                         TiMidity port 1
-  128:2    TiMidity                         TiMidity port 2
-  128:3    TiMidity                         TiMidity port 3
-
-  $ aplaymidi -p 128:0 file.mid
-
-MIDI ports can be logically connected using the aconnect utility, e.g.::
-
-  $ aconnect 24:0 128:0 # try it on the host
-
-After the gadget's MIDI port is connected to timidity's MIDI port,
-whatever is played at the gadget side with aplaymidi -l is audible
-in host's speakers/headphones.
-
-10. NCM function
-================
-
-The function is provided by usb_f_ncm.ko module.
-
-Function-specific configfs interface
-------------------------------------
-
-The function name to use when creating the function directory is "ncm".
-The NCM function provides these attributes in its function directory:
-
-       =============== ==================================================
-       ifname          network device interface name associated with this
-                       function instance
-       qmult           queue length multiplier for high and super speed
-       host_addr       MAC address of host's end of this
-                       Ethernet over USB link
-       dev_addr        MAC address of device's end of this
-                       Ethernet over USB link
-       =============== ==================================================
-
-and after creating the functions/ncm.<instance name> they contain default
-values: qmult is 5, dev_addr and host_addr are randomly selected.
-Except for ifname they can be written to until the function is linked to a
-configuration. The ifname is read-only and contains the name of the interface
-which was assigned by the net core, e. g. usb0.
-
-Testing the NCM function
-------------------------
-
-Configure IP addresses of the device and the host. Then:
-
-On the device::
-
-       ping <host's IP>
-
-On the host::
-
-       ping <device's IP>
-
-11. OBEX function
-=================
-
-The function is provided by usb_f_obex.ko module.
-
-Function-specific configfs interface
-------------------------------------
-
-The function name to use when creating the function directory is "obex".
-The OBEX function provides just one attribute in its function directory:
-
-       port_num
-
-The attribute is read-only.
-
-There can be at most 4 ACM/generic serial/OBEX ports in the system.
-
-Testing the OBEX function
--------------------------
-
-On device::
-
-       seriald -f /dev/ttyGS<Y> -s 1024
-
-On host::
-
-       serialc -v <vendorID> -p <productID> -i<interface#> -a1 -s1024 \
-                -t<out endpoint addr> -r<in endpoint addr>
-
-where seriald and serialc are Felipe's utilities found here:
-
-       https://github.com/felipebalbi/usb-tools.git master
-
-12. PHONET function
-===================
-
-The function is provided by usb_f_phonet.ko module.
-
-Function-specific configfs interface
-------------------------------------
-
-The function name to use when creating the function directory is "phonet".
-The PHONET function provides just one attribute in its function directory:
-
-       =============== ==================================================
-       ifname          network device interface name associated with this
-                       function instance
-       =============== ==================================================
-
-Testing the PHONET function
----------------------------
-
-It is not possible to test the SOCK_STREAM protocol without a specific piece
-of hardware, so only SOCK_DGRAM has been tested. For the latter to work,
-in the past I had to apply the patch mentioned here:
-
-http://www.spinics.net/lists/linux-usb/msg85689.html
-
-These tools are required:
-
-git://git.gitorious.org/meego-cellular/phonet-utils.git
-
-On the host::
-
-       $ ./phonet -a 0x10 -i usbpn0
-       $ ./pnroute add 0x6c usbpn0
-       $./pnroute add 0x10 usbpn0
-       $ ifconfig usbpn0 up
-
-On the device::
-
-       $ ./phonet -a 0x6c -i upnlink0
-       $ ./pnroute add 0x10 upnlink0
-       $ ifconfig upnlink0 up
-
-Then a test program can be used::
-
-       http://www.spinics.net/lists/linux-usb/msg85690.html
-
-On the device::
-
-       $ ./pnxmit -a 0x6c -r
-
-On the host::
-
-       $ ./pnxmit -a 0x10 -s 0x6c
-
-As a result some data should be sent from host to device.
-Then the other way round:
-
-On the host::
-
-       $ ./pnxmit -a 0x10 -r
-
-On the device::
-
-       $ ./pnxmit -a 0x6c -s 0x10
-
-13. RNDIS function
-==================
-
-The function is provided by usb_f_rndis.ko module.
-
-Function-specific configfs interface
-------------------------------------
-
-The function name to use when creating the function directory is "rndis".
-The RNDIS function provides these attributes in its function directory:
-
-       =============== ==================================================
-       ifname          network device interface name associated with this
-                       function instance
-       qmult           queue length multiplier for high and super speed
-       host_addr       MAC address of host's end of this
-                       Ethernet over USB link
-       dev_addr        MAC address of device's end of this
-                       Ethernet over USB link
-       =============== ==================================================
-
-and after creating the functions/rndis.<instance name> they contain default
-values: qmult is 5, dev_addr and host_addr are randomly selected.
-Except for ifname they can be written to until the function is linked to a
-configuration. The ifname is read-only and contains the name of the interface
-which was assigned by the net core, e. g. usb0.
-
-Testing the RNDIS function
---------------------------
-
-Configure IP addresses of the device and the host. Then:
-
-On the device::
-
-       ping <host's IP>
-
-On the host::
-
-       ping <device's IP>
-
-14. SERIAL function
-===================
-
-The function is provided by usb_f_gser.ko module.
-
-Function-specific configfs interface
-------------------------------------
-
-The function name to use when creating the function directory is "gser".
-The SERIAL function provides just one attribute in its function directory:
-
-       port_num
-
-The attribute is read-only.
-
-There can be at most 4 ACM/generic serial/OBEX ports in the system.
-
-Testing the SERIAL function
----------------------------
-
-On host::
-
-       insmod usbserial
-       echo VID PID >/sys/bus/usb-serial/drivers/generic/new_id
-
-On host::
-
-       cat > /dev/ttyUSB<X>
-
-On target::
-
-       cat /dev/ttyGS<Y>
-
-then the other way round
-
-On target::
-
-       cat > /dev/ttyGS<Y>
-
-On host::
-
-       cat /dev/ttyUSB<X>
-
-15. SOURCESINK function
-=======================
-
-The function is provided by usb_f_ss_lb.ko module.
-
-Function-specific configfs interface
-------------------------------------
-
-The function name to use when creating the function directory is "SourceSink".
-The SOURCESINK function provides these attributes in its function directory:
-
-       =============== ==================================
-       pattern         0 (all zeros), 1 (mod63), 2 (none)
-       isoc_interval   1..16
-       isoc_maxpacket  0 - 1023 (fs), 0 - 1024 (hs/ss)
-       isoc_mult       0..2 (hs/ss only)
-       isoc_maxburst   0..15 (ss only)
-       bulk_buflen     buffer length
-       bulk_qlen       depth of queue for bulk
-       iso_qlen        depth of queue for iso
-       =============== ==================================
-
-Testing the SOURCESINK function
--------------------------------
-
-device: run the gadget
-
-host: test-usb (tools/usb/testusb.c)
-
-
-16. UAC1 function (legacy implementation)
-=========================================
-
-The function is provided by usb_f_uac1_legacy.ko module.
-
-Function-specific configfs interface
-------------------------------------
-
-The function name to use when creating the function directory
-is "uac1_legacy".
-The uac1 function provides these attributes in its function directory:
-
-       =============== ====================================
-       audio_buf_size  audio buffer size
-       fn_cap          capture pcm device file name
-       fn_cntl         control device file name
-       fn_play         playback pcm device file name
-       req_buf_size    ISO OUT endpoint request buffer size
-       req_count       ISO OUT endpoint request count
-       =============== ====================================
-
-The attributes have sane default values.
-
-Testing the UAC1 function
--------------------------
-
-device: run the gadget
-
-host::
-
-       aplay -l # should list our USB Audio Gadget
-
-17. UAC2 function
-=================
-
-The function is provided by usb_f_uac2.ko module.
-
-Function-specific configfs interface
-------------------------------------
-
-The function name to use when creating the function directory is "uac2".
-The uac2 function provides these attributes in its function directory:
-
-       =============== ====================================================
-       c_chmask        capture channel mask
-       c_srate         capture sampling rate
-       c_ssize         capture sample size (bytes)
-       p_chmask        playback channel mask
-       p_srate         playback sampling rate
-       p_ssize         playback sample size (bytes)
-       req_number      the number of pre-allocated request for both capture
-                       and playback
-       =============== ====================================================
-
-The attributes have sane default values.
-
-Testing the UAC2 function
--------------------------
-
-device: run the gadget
-host: aplay -l # should list our USB Audio Gadget
-
-This function does not require real hardware support, it just
-sends a stream of audio data to/from the host. In order to
-actually hear something at the device side, a command similar
-to this must be used at the device side::
-
-       $ arecord -f dat -t wav -D hw:2,0 | aplay -D hw:0,0 &
-
-e.g.::
-
-       $ arecord -f dat -t wav -D hw:CARD=UAC2Gadget,DEV=0 | \
-         aplay -D default:CARD=OdroidU3
-
-18. UVC function
-================
-
-The function is provided by usb_f_uvc.ko module.
-
-Function-specific configfs interface
-------------------------------------
-
-The function name to use when creating the function directory is "uvc".
-The uvc function provides these attributes in its function directory:
-
-       =================== ================================================
-       streaming_interval  interval for polling endpoint for data transfers
-       streaming_maxburst  bMaxBurst for super speed companion descriptor
-       streaming_maxpacket maximum packet size this endpoint is capable of
-                           sending or receiving when this configuration is
-                           selected
-       =================== ================================================
-
-There are also "control" and "streaming" subdirectories, each of which contain
-a number of their subdirectories. There are some sane defaults provided, but
-the user must provide the following:
-
-       ================== ====================================================
-       control header     create in control/header, link from control/class/fs
-                          and/or control/class/ss
-       streaming header   create in streaming/header, link from
-                          streaming/class/fs and/or streaming/class/hs and/or
-                          streaming/class/ss
-       format description create in streaming/mjpeg and/or
-                          streaming/uncompressed
-       frame description  create in streaming/mjpeg/<format> and/or in
-                          streaming/uncompressed/<format>
-       ================== ====================================================
-
-Each frame description contains frame interval specification, and each
-such specification consists of a number of lines with an inverval value
-in each line. The rules stated above are best illustrated with an example::
-
-  # mkdir functions/uvc.usb0/control/header/h
-  # cd functions/uvc.usb0/control/
-  # ln -s header/h class/fs
-  # ln -s header/h class/ss
-  # mkdir -p functions/uvc.usb0/streaming/uncompressed/u/360p
-  # cat <<EOF > functions/uvc.usb0/streaming/uncompressed/u/360p/dwFrameInterval
-  666666
-  1000000
-  5000000
-  EOF
-  # cd $GADGET_CONFIGFS_ROOT
-  # mkdir functions/uvc.usb0/streaming/header/h
-  # cd functions/uvc.usb0/streaming/header/h
-  # ln -s ../../uncompressed/u
-  # cd ../../class/fs
-  # ln -s ../../header/h
-  # cd ../../class/hs
-  # ln -s ../../header/h
-  # cd ../../class/ss
-  # ln -s ../../header/h
-
-
-Testing the UVC function
-------------------------
-
-device: run the gadget, modprobe vivid::
-
-  # uvc-gadget -u /dev/video<uvc video node #> -v /dev/video<vivid video node #>
-
-where uvc-gadget is this program:
-       http://git.ideasonboard.org/uvc-gadget.git
-
-with these patches:
-
-       http://www.spinics.net/lists/linux-usb/msg99220.html
-
-host::
-
-       luvcview -f yuv
-
-19. PRINTER function
-====================
-
-The function is provided by usb_f_printer.ko module.
-
-Function-specific configfs interface
-------------------------------------
-
-The function name to use when creating the function directory is "printer".
-The printer function provides these attributes in its function directory:
-
-       ==========      ===========================================
-       pnp_string      Data to be passed to the host in pnp string
-       q_len           Number of requests per endpoint
-       ==========      ===========================================
-
-Testing the PRINTER function
-----------------------------
-
-The most basic testing:
-
-device: run the gadget::
-
-       # ls -l /devices/virtual/usb_printer_gadget/
-
-should show g_printer<number>.
-
-If udev is active, then /dev/g_printer<number> should appear automatically.
-
-host:
-
-If udev is active, then e.g. /dev/usb/lp0 should appear.
-
-host->device transmission:
-
-device::
-
-       # cat /dev/g_printer<number>
-
-host::
-
-       # cat > /dev/usb/lp0
-
-device->host transmission::
-
-       # cat > /dev/g_printer<number>
-
-host::
-
-       # cat /dev/usb/lp0
-
-More advanced testing can be done with the prn_example
-described in Documentation/usb/gadget_printer.txt.
-
-
-20. UAC1 function (virtual ALSA card, using u_audio API)
-========================================================
-
-The function is provided by usb_f_uac1.ko module.
-It will create a virtual ALSA card and the audio streams are simply
-sinked to and sourced from it.
-
-Function-specific configfs interface
-------------------------------------
-
-The function name to use when creating the function directory is "uac1".
-The uac1 function provides these attributes in its function directory:
-
-       ========== ====================================================
-       c_chmask   capture channel mask
-       c_srate    capture sampling rate
-       c_ssize    capture sample size (bytes)
-       p_chmask   playback channel mask
-       p_srate    playback sampling rate
-       p_ssize    playback sample size (bytes)
-       req_number the number of pre-allocated request for both capture
-                  and playback
-       ========== ====================================================
-
-The attributes have sane default values.
-
-Testing the UAC1 function
--------------------------
-
-device: run the gadget
-host: aplay -l # should list our USB Audio Gadget
-
-This function does not require real hardware support, it just
-sends a stream of audio data to/from the host. In order to
-actually hear something at the device side, a command similar
-to this must be used at the device side::
-
-       $ arecord -f dat -t wav -D hw:2,0 | aplay -D hw:0,0 &
-
-e.g.::
-
-       $ arecord -f dat -t wav -D hw:CARD=UAC1Gadget,DEV=0 | \
-         aplay -D default:CARD=OdroidU3
diff --git a/Documentation/usb/gadget_configfs.rst b/Documentation/usb/gadget_configfs.rst
new file mode 100644 (file)
index 0000000..54fb08b
--- /dev/null
@@ -0,0 +1,390 @@
+============================================
+Linux USB gadget configured through configfs
+============================================
+
+
+25th April 2013
+
+
+
+
+Overview
+========
+
+A USB Linux Gadget is a device which has a UDC (USB Device Controller) and can
+be connected to a USB Host to extend it with additional functions like a serial
+port or a mass storage capability.
+
+A gadget is seen by its host as a set of configurations, each of which contains
+a number of interfaces which, from the gadget's perspective, are known as
+functions, each function representing e.g. a serial connection or a SCSI disk.
+
+Linux provides a number of functions for gadgets to use.
+
+Creating a gadget means deciding what configurations there will be
+and which functions each configuration will provide.
+
+Configfs (please see `Documentation/filesystems/configfs/*`) lends itself nicely
+for the purpose of telling the kernel about the above mentioned decision.
+This document is about how to do it.
+
+It also describes how configfs integration into gadget is designed.
+
+
+
+
+Requirements
+============
+
+In order for this to work configfs must be available, so CONFIGFS_FS must be
+'y' or 'm' in .config. As of this writing USB_LIBCOMPOSITE selects CONFIGFS_FS.
+
+
+
+
+Usage
+=====
+
+(The original post describing the first function
+made available through configfs can be seen here:
+http://www.spinics.net/lists/linux-usb/msg76388.html)
+
+::
+
+       $ modprobe libcomposite
+       $ mount none $CONFIGFS_HOME -t configfs
+
+where CONFIGFS_HOME is the mount point for configfs
+
+1. Creating the gadgets
+-----------------------
+
+For each gadget to be created its corresponding directory must be created::
+
+       $ mkdir $CONFIGFS_HOME/usb_gadget/<gadget name>
+
+e.g.::
+
+       $ mkdir $CONFIGFS_HOME/usb_gadget/g1
+
+       ...
+       ...
+       ...
+
+       $ cd $CONFIGFS_HOME/usb_gadget/g1
+
+Each gadget needs to have its vendor id <VID> and product id <PID> specified::
+
+       $ echo <VID> > idVendor
+       $ echo <PID> > idProduct
+
+A gadget also needs its serial number, manufacturer and product strings.
+In order to have a place to store them, a strings subdirectory must be created
+for each language, e.g.::
+
+       $ mkdir strings/0x409
+
+Then the strings can be specified::
+
+       $ echo <serial number> > strings/0x409/serialnumber
+       $ echo <manufacturer> > strings/0x409/manufacturer
+       $ echo <product> > strings/0x409/product
+
+2. Creating the configurations
+------------------------------
+
+Each gadget will consist of a number of configurations, their corresponding
+directories must be created:
+
+$ mkdir configs/<name>.<number>
+
+where <name> can be any string which is legal in a filesystem and the
+<number> is the configuration's number, e.g.::
+
+       $ mkdir configs/c.1
+
+       ...
+       ...
+       ...
+
+Each configuration also needs its strings, so a subdirectory must be created
+for each language, e.g.::
+
+       $ mkdir configs/c.1/strings/0x409
+
+Then the configuration string can be specified::
+
+       $ echo <configuration> > configs/c.1/strings/0x409/configuration
+
+Some attributes can also be set for a configuration, e.g.::
+
+       $ echo 120 > configs/c.1/MaxPower
+
+3. Creating the functions
+-------------------------
+
+The gadget will provide some functions, for each function its corresponding
+directory must be created::
+
+       $ mkdir functions/<name>.<instance name>
+
+where <name> corresponds to one of allowed function names and instance name
+is an arbitrary string allowed in a filesystem, e.g.::
+
+  $ mkdir functions/ncm.usb0 # usb_f_ncm.ko gets loaded with request_module()
+
+  ...
+  ...
+  ...
+
+Each function provides its specific set of attributes, with either read-only
+or read-write access. Where applicable they need to be written to as
+appropriate.
+Please refer to Documentation/ABI/*/configfs-usb-gadget* for more information.
+
+4. Associating the functions with their configurations
+------------------------------------------------------
+
+At this moment a number of gadgets is created, each of which has a number of
+configurations specified and a number of functions available. What remains
+is specifying which function is available in which configuration (the same
+function can be used in multiple configurations). This is achieved with
+creating symbolic links::
+
+       $ ln -s functions/<name>.<instance name> configs/<name>.<number>
+
+e.g.::
+
+       $ ln -s functions/ncm.usb0 configs/c.1
+
+       ...
+       ...
+       ...
+
+5. Enabling the gadget
+----------------------
+
+All the above steps serve the purpose of composing the gadget of
+configurations and functions.
+
+An example directory structure might look like this::
+
+  .
+  ./strings
+  ./strings/0x409
+  ./strings/0x409/serialnumber
+  ./strings/0x409/product
+  ./strings/0x409/manufacturer
+  ./configs
+  ./configs/c.1
+  ./configs/c.1/ncm.usb0 -> ../../../../usb_gadget/g1/functions/ncm.usb0
+  ./configs/c.1/strings
+  ./configs/c.1/strings/0x409
+  ./configs/c.1/strings/0x409/configuration
+  ./configs/c.1/bmAttributes
+  ./configs/c.1/MaxPower
+  ./functions
+  ./functions/ncm.usb0
+  ./functions/ncm.usb0/ifname
+  ./functions/ncm.usb0/qmult
+  ./functions/ncm.usb0/host_addr
+  ./functions/ncm.usb0/dev_addr
+  ./UDC
+  ./bcdUSB
+  ./bcdDevice
+  ./idProduct
+  ./idVendor
+  ./bMaxPacketSize0
+  ./bDeviceProtocol
+  ./bDeviceSubClass
+  ./bDeviceClass
+
+
+Such a gadget must be finally enabled so that the USB host can enumerate it.
+
+In order to enable the gadget it must be bound to a UDC (USB Device
+Controller)::
+
+       $ echo <udc name> > UDC
+
+where <udc name> is one of those found in /sys/class/udc/*
+e.g.::
+
+       $ echo s3c-hsotg > UDC
+
+
+6. Disabling the gadget
+-----------------------
+
+::
+
+       $ echo "" > UDC
+
+7. Cleaning up
+--------------
+
+Remove functions from configurations::
+
+       $ rm configs/<config name>.<number>/<function>
+
+where <config name>.<number> specify the configuration and <function> is
+a symlink to a function being removed from the configuration, e.g.::
+
+       $ rm configs/c.1/ncm.usb0
+
+       ...
+       ...
+       ...
+
+Remove strings directories in configurations:
+
+       $ rmdir configs/<config name>.<number>/strings/<lang>
+
+e.g.::
+
+       $ rmdir configs/c.1/strings/0x409
+
+       ...
+       ...
+       ...
+
+and remove the configurations::
+
+       $ rmdir configs/<config name>.<number>
+
+e.g.::
+
+       rmdir configs/c.1
+
+       ...
+       ...
+       ...
+
+Remove functions (function modules are not unloaded, though):
+
+       $ rmdir functions/<name>.<instance name>
+
+e.g.::
+
+       $ rmdir functions/ncm.usb0
+
+       ...
+       ...
+       ...
+
+Remove strings directories in the gadget::
+
+       $ rmdir strings/<lang>
+
+e.g.::
+
+       $ rmdir strings/0x409
+
+and finally remove the gadget::
+
+       $ cd ..
+       $ rmdir <gadget name>
+
+e.g.::
+
+       $ rmdir g1
+
+
+
+
+Implementation design
+=====================
+
+Below the idea of how configfs works is presented.
+In configfs there are items and groups, both represented as directories.
+The difference between an item and a group is that a group can contain
+other groups. In the picture below only an item is shown.
+Both items and groups can have attributes, which are represented as files.
+The user can create and remove directories, but cannot remove files,
+which can be read-only or read-write, depending on what they represent.
+
+The filesystem part of configfs operates on config_items/groups and
+configfs_attributes which are generic and of the same type for all
+configured elements. However, they are embedded in usage-specific
+larger structures. In the picture below there is a "cs" which contains
+a config_item and an "sa" which contains a configfs_attribute.
+
+The filesystem view would be like this::
+
+  ./
+  ./cs        (directory)
+     |
+     +--sa    (file)
+     |
+     .
+     .
+     .
+
+Whenever a user reads/writes the "sa" file, a function is called
+which accepts a struct config_item and a struct configfs_attribute.
+In the said function the "cs" and "sa" are retrieved using the well
+known container_of technique and an appropriate sa's function (show or
+store) is called and passed the "cs" and a character buffer. The "show"
+is for displaying the file's contents (copy data from the cs to the
+buffer), while the "store" is for modifying the file's contents (copy data
+from the buffer to the cs), but it is up to the implementer of the
+two functions to decide what they actually do.
+
+::
+
+  typedef struct configured_structure cs;
+  typedef struct specific_attribute sa;
+
+                                         sa
+                         +----------------------------------+
+          cs             |  (*show)(cs *, buffer);          |
+  +-----------------+    |  (*store)(cs *, buffer, length); |
+  |                 |    |                                  |
+  | +-------------+ |    |       +------------------+       |
+  | | struct      |-|----|------>|struct            |       |
+  | | config_item | |    |       |configfs_attribute|       |
+  | +-------------+ |    |       +------------------+       |
+  |                 |    +----------------------------------+
+  | data to be set  |                .
+  |                 |                .
+  +-----------------+                .
+
+The file names are decided by the config item/group designer, while
+the directories in general can be named at will. A group can have
+a number of its default sub-groups created automatically.
+
+For more information on configfs please see
+`Documentation/filesystems/configfs/*`.
+
+The concepts described above translate to USB gadgets like this:
+
+1. A gadget has its config group, which has some attributes (idVendor,
+idProduct etc) and default sub-groups (configs, functions, strings).
+Writing to the attributes causes the information to be stored in
+appropriate locations. In the configs, functions and strings sub-groups
+a user can create their sub-groups to represent configurations, functions,
+and groups of strings in a given language.
+
+2. The user creates configurations and functions, in the configurations
+creates symbolic links to functions. This information is used when the
+gadget's UDC attribute is written to, which means binding the gadget
+to the UDC. The code in drivers/usb/gadget/configfs.c iterates over
+all configurations, and in each configuration it iterates over all
+functions and binds them. This way the whole gadget is bound.
+
+3. The file drivers/usb/gadget/configfs.c contains code for
+
+       - gadget's config_group
+       - gadget's default groups (configs, functions, strings)
+       - associating functions with configurations (symlinks)
+
+4. Each USB function naturally has its own view of what it wants
+configured, so config_groups for particular functions are defined
+in the functions implementation files drivers/usb/gadget/f_*.c.
+
+5. Function's code is written in such a way that it uses
+
+usb_get_function_instance(), which, in turn, calls request_module.
+So, provided that modprobe works, modules for particular functions
+are loaded automatically. Please note that the converse is not true:
+after a gadget is disabled and torn down, the modules remain loaded.
diff --git a/Documentation/usb/gadget_configfs.txt b/Documentation/usb/gadget_configfs.txt
deleted file mode 100644 (file)
index 54fb08b..0000000
+++ /dev/null
@@ -1,390 +0,0 @@
-============================================
-Linux USB gadget configured through configfs
-============================================
-
-
-25th April 2013
-
-
-
-
-Overview
-========
-
-A USB Linux Gadget is a device which has a UDC (USB Device Controller) and can
-be connected to a USB Host to extend it with additional functions like a serial
-port or a mass storage capability.
-
-A gadget is seen by its host as a set of configurations, each of which contains
-a number of interfaces which, from the gadget's perspective, are known as
-functions, each function representing e.g. a serial connection or a SCSI disk.
-
-Linux provides a number of functions for gadgets to use.
-
-Creating a gadget means deciding what configurations there will be
-and which functions each configuration will provide.
-
-Configfs (please see `Documentation/filesystems/configfs/*`) lends itself nicely
-for the purpose of telling the kernel about the above mentioned decision.
-This document is about how to do it.
-
-It also describes how configfs integration into gadget is designed.
-
-
-
-
-Requirements
-============
-
-In order for this to work configfs must be available, so CONFIGFS_FS must be
-'y' or 'm' in .config. As of this writing USB_LIBCOMPOSITE selects CONFIGFS_FS.
-
-
-
-
-Usage
-=====
-
-(The original post describing the first function
-made available through configfs can be seen here:
-http://www.spinics.net/lists/linux-usb/msg76388.html)
-
-::
-
-       $ modprobe libcomposite
-       $ mount none $CONFIGFS_HOME -t configfs
-
-where CONFIGFS_HOME is the mount point for configfs
-
-1. Creating the gadgets
------------------------
-
-For each gadget to be created its corresponding directory must be created::
-
-       $ mkdir $CONFIGFS_HOME/usb_gadget/<gadget name>
-
-e.g.::
-
-       $ mkdir $CONFIGFS_HOME/usb_gadget/g1
-
-       ...
-       ...
-       ...
-
-       $ cd $CONFIGFS_HOME/usb_gadget/g1
-
-Each gadget needs to have its vendor id <VID> and product id <PID> specified::
-
-       $ echo <VID> > idVendor
-       $ echo <PID> > idProduct
-
-A gadget also needs its serial number, manufacturer and product strings.
-In order to have a place to store them, a strings subdirectory must be created
-for each language, e.g.::
-
-       $ mkdir strings/0x409
-
-Then the strings can be specified::
-
-       $ echo <serial number> > strings/0x409/serialnumber
-       $ echo <manufacturer> > strings/0x409/manufacturer
-       $ echo <product> > strings/0x409/product
-
-2. Creating the configurations
-------------------------------
-
-Each gadget will consist of a number of configurations, their corresponding
-directories must be created:
-
-$ mkdir configs/<name>.<number>
-
-where <name> can be any string which is legal in a filesystem and the
-<number> is the configuration's number, e.g.::
-
-       $ mkdir configs/c.1
-
-       ...
-       ...
-       ...
-
-Each configuration also needs its strings, so a subdirectory must be created
-for each language, e.g.::
-
-       $ mkdir configs/c.1/strings/0x409
-
-Then the configuration string can be specified::
-
-       $ echo <configuration> > configs/c.1/strings/0x409/configuration
-
-Some attributes can also be set for a configuration, e.g.::
-
-       $ echo 120 > configs/c.1/MaxPower
-
-3. Creating the functions
--------------------------
-
-The gadget will provide some functions, for each function its corresponding
-directory must be created::
-
-       $ mkdir functions/<name>.<instance name>
-
-where <name> corresponds to one of allowed function names and instance name
-is an arbitrary string allowed in a filesystem, e.g.::
-
-  $ mkdir functions/ncm.usb0 # usb_f_ncm.ko gets loaded with request_module()
-
-  ...
-  ...
-  ...
-
-Each function provides its specific set of attributes, with either read-only
-or read-write access. Where applicable they need to be written to as
-appropriate.
-Please refer to Documentation/ABI/*/configfs-usb-gadget* for more information.
-
-4. Associating the functions with their configurations
-------------------------------------------------------
-
-At this moment a number of gadgets is created, each of which has a number of
-configurations specified and a number of functions available. What remains
-is specifying which function is available in which configuration (the same
-function can be used in multiple configurations). This is achieved with
-creating symbolic links::
-
-       $ ln -s functions/<name>.<instance name> configs/<name>.<number>
-
-e.g.::
-
-       $ ln -s functions/ncm.usb0 configs/c.1
-
-       ...
-       ...
-       ...
-
-5. Enabling the gadget
-----------------------
-
-All the above steps serve the purpose of composing the gadget of
-configurations and functions.
-
-An example directory structure might look like this::
-
-  .
-  ./strings
-  ./strings/0x409
-  ./strings/0x409/serialnumber
-  ./strings/0x409/product
-  ./strings/0x409/manufacturer
-  ./configs
-  ./configs/c.1
-  ./configs/c.1/ncm.usb0 -> ../../../../usb_gadget/g1/functions/ncm.usb0
-  ./configs/c.1/strings
-  ./configs/c.1/strings/0x409
-  ./configs/c.1/strings/0x409/configuration
-  ./configs/c.1/bmAttributes
-  ./configs/c.1/MaxPower
-  ./functions
-  ./functions/ncm.usb0
-  ./functions/ncm.usb0/ifname
-  ./functions/ncm.usb0/qmult
-  ./functions/ncm.usb0/host_addr
-  ./functions/ncm.usb0/dev_addr
-  ./UDC
-  ./bcdUSB
-  ./bcdDevice
-  ./idProduct
-  ./idVendor
-  ./bMaxPacketSize0
-  ./bDeviceProtocol
-  ./bDeviceSubClass
-  ./bDeviceClass
-
-
-Such a gadget must be finally enabled so that the USB host can enumerate it.
-
-In order to enable the gadget it must be bound to a UDC (USB Device
-Controller)::
-
-       $ echo <udc name> > UDC
-
-where <udc name> is one of those found in /sys/class/udc/*
-e.g.::
-
-       $ echo s3c-hsotg > UDC
-
-
-6. Disabling the gadget
------------------------
-
-::
-
-       $ echo "" > UDC
-
-7. Cleaning up
---------------
-
-Remove functions from configurations::
-
-       $ rm configs/<config name>.<number>/<function>
-
-where <config name>.<number> specify the configuration and <function> is
-a symlink to a function being removed from the configuration, e.g.::
-
-       $ rm configs/c.1/ncm.usb0
-
-       ...
-       ...
-       ...
-
-Remove strings directories in configurations:
-
-       $ rmdir configs/<config name>.<number>/strings/<lang>
-
-e.g.::
-
-       $ rmdir configs/c.1/strings/0x409
-
-       ...
-       ...
-       ...
-
-and remove the configurations::
-
-       $ rmdir configs/<config name>.<number>
-
-e.g.::
-
-       rmdir configs/c.1
-
-       ...
-       ...
-       ...
-
-Remove functions (function modules are not unloaded, though):
-
-       $ rmdir functions/<name>.<instance name>
-
-e.g.::
-
-       $ rmdir functions/ncm.usb0
-
-       ...
-       ...
-       ...
-
-Remove strings directories in the gadget::
-
-       $ rmdir strings/<lang>
-
-e.g.::
-
-       $ rmdir strings/0x409
-
-and finally remove the gadget::
-
-       $ cd ..
-       $ rmdir <gadget name>
-
-e.g.::
-
-       $ rmdir g1
-
-
-
-
-Implementation design
-=====================
-
-Below the idea of how configfs works is presented.
-In configfs there are items and groups, both represented as directories.
-The difference between an item and a group is that a group can contain
-other groups. In the picture below only an item is shown.
-Both items and groups can have attributes, which are represented as files.
-The user can create and remove directories, but cannot remove files,
-which can be read-only or read-write, depending on what they represent.
-
-The filesystem part of configfs operates on config_items/groups and
-configfs_attributes which are generic and of the same type for all
-configured elements. However, they are embedded in usage-specific
-larger structures. In the picture below there is a "cs" which contains
-a config_item and an "sa" which contains a configfs_attribute.
-
-The filesystem view would be like this::
-
-  ./
-  ./cs        (directory)
-     |
-     +--sa    (file)
-     |
-     .
-     .
-     .
-
-Whenever a user reads/writes the "sa" file, a function is called
-which accepts a struct config_item and a struct configfs_attribute.
-In the said function the "cs" and "sa" are retrieved using the well
-known container_of technique and an appropriate sa's function (show or
-store) is called and passed the "cs" and a character buffer. The "show"
-is for displaying the file's contents (copy data from the cs to the
-buffer), while the "store" is for modifying the file's contents (copy data
-from the buffer to the cs), but it is up to the implementer of the
-two functions to decide what they actually do.
-
-::
-
-  typedef struct configured_structure cs;
-  typedef struct specific_attribute sa;
-
-                                         sa
-                         +----------------------------------+
-          cs             |  (*show)(cs *, buffer);          |
-  +-----------------+    |  (*store)(cs *, buffer, length); |
-  |                 |    |                                  |
-  | +-------------+ |    |       +------------------+       |
-  | | struct      |-|----|------>|struct            |       |
-  | | config_item | |    |       |configfs_attribute|       |
-  | +-------------+ |    |       +------------------+       |
-  |                 |    +----------------------------------+
-  | data to be set  |                .
-  |                 |                .
-  +-----------------+                .
-
-The file names are decided by the config item/group designer, while
-the directories in general can be named at will. A group can have
-a number of its default sub-groups created automatically.
-
-For more information on configfs please see
-`Documentation/filesystems/configfs/*`.
-
-The concepts described above translate to USB gadgets like this:
-
-1. A gadget has its config group, which has some attributes (idVendor,
-idProduct etc) and default sub-groups (configs, functions, strings).
-Writing to the attributes causes the information to be stored in
-appropriate locations. In the configs, functions and strings sub-groups
-a user can create their sub-groups to represent configurations, functions,
-and groups of strings in a given language.
-
-2. The user creates configurations and functions, in the configurations
-creates symbolic links to functions. This information is used when the
-gadget's UDC attribute is written to, which means binding the gadget
-to the UDC. The code in drivers/usb/gadget/configfs.c iterates over
-all configurations, and in each configuration it iterates over all
-functions and binds them. This way the whole gadget is bound.
-
-3. The file drivers/usb/gadget/configfs.c contains code for
-
-       - gadget's config_group
-       - gadget's default groups (configs, functions, strings)
-       - associating functions with configurations (symlinks)
-
-4. Each USB function naturally has its own view of what it wants
-configured, so config_groups for particular functions are defined
-in the functions implementation files drivers/usb/gadget/f_*.c.
-
-5. Function's code is written in such a way that it uses
-
-usb_get_function_instance(), which, in turn, calls request_module.
-So, provided that modprobe works, modules for particular functions
-are loaded automatically. Please note that the converse is not true:
-after a gadget is disabled and torn down, the modules remain loaded.
diff --git a/Documentation/usb/gadget_hid.rst b/Documentation/usb/gadget_hid.rst
new file mode 100644 (file)
index 0000000..098d563
--- /dev/null
@@ -0,0 +1,457 @@
+===========================
+Linux USB HID gadget driver
+===========================
+
+Introduction
+============
+
+The HID Gadget driver provides emulation of USB Human Interface
+Devices (HID). The basic HID handling is done in the kernel,
+and HID reports can be sent/received through I/O on the
+/dev/hidgX character devices.
+
+For more details about HID, see the developer page on
+http://www.usb.org/developers/hidpage/
+
+Configuration
+=============
+
+g_hid is a platform driver, so to use it you need to add
+struct platform_device(s) to your platform code defining the
+HID function descriptors you want to use - E.G. something
+like::
+
+  #include <linux/platform_device.h>
+  #include <linux/usb/g_hid.h>
+
+  /* hid descriptor for a keyboard */
+  static struct hidg_func_descriptor my_hid_data = {
+       .subclass               = 0, /* No subclass */
+       .protocol               = 1, /* Keyboard */
+       .report_length          = 8,
+       .report_desc_length     = 63,
+       .report_desc            = {
+               0x05, 0x01,     /* USAGE_PAGE (Generic Desktop)           */
+               0x09, 0x06,     /* USAGE (Keyboard)                       */
+               0xa1, 0x01,     /* COLLECTION (Application)               */
+               0x05, 0x07,     /*   USAGE_PAGE (Keyboard)                */
+               0x19, 0xe0,     /*   USAGE_MINIMUM (Keyboard LeftControl) */
+               0x29, 0xe7,     /*   USAGE_MAXIMUM (Keyboard Right GUI)   */
+               0x15, 0x00,     /*   LOGICAL_MINIMUM (0)                  */
+               0x25, 0x01,     /*   LOGICAL_MAXIMUM (1)                  */
+               0x75, 0x01,     /*   REPORT_SIZE (1)                      */
+               0x95, 0x08,     /*   REPORT_COUNT (8)                     */
+               0x81, 0x02,     /*   INPUT (Data,Var,Abs)                 */
+               0x95, 0x01,     /*   REPORT_COUNT (1)                     */
+               0x75, 0x08,     /*   REPORT_SIZE (8)                      */
+               0x81, 0x03,     /*   INPUT (Cnst,Var,Abs)                 */
+               0x95, 0x05,     /*   REPORT_COUNT (5)                     */
+               0x75, 0x01,     /*   REPORT_SIZE (1)                      */
+               0x05, 0x08,     /*   USAGE_PAGE (LEDs)                    */
+               0x19, 0x01,     /*   USAGE_MINIMUM (Num Lock)             */
+               0x29, 0x05,     /*   USAGE_MAXIMUM (Kana)                 */
+               0x91, 0x02,     /*   OUTPUT (Data,Var,Abs)                */
+               0x95, 0x01,     /*   REPORT_COUNT (1)                     */
+               0x75, 0x03,     /*   REPORT_SIZE (3)                      */
+               0x91, 0x03,     /*   OUTPUT (Cnst,Var,Abs)                */
+               0x95, 0x06,     /*   REPORT_COUNT (6)                     */
+               0x75, 0x08,     /*   REPORT_SIZE (8)                      */
+               0x15, 0x00,     /*   LOGICAL_MINIMUM (0)                  */
+               0x25, 0x65,     /*   LOGICAL_MAXIMUM (101)                */
+               0x05, 0x07,     /*   USAGE_PAGE (Keyboard)                */
+               0x19, 0x00,     /*   USAGE_MINIMUM (Reserved)             */
+               0x29, 0x65,     /*   USAGE_MAXIMUM (Keyboard Application) */
+               0x81, 0x00,     /*   INPUT (Data,Ary,Abs)                 */
+               0xc0            /* END_COLLECTION                         */
+       }
+  };
+
+  static struct platform_device my_hid = {
+       .name                   = "hidg",
+       .id                     = 0,
+       .num_resources          = 0,
+       .resource               = 0,
+       .dev.platform_data      = &my_hid_data,
+  };
+
+You can add as many HID functions as you want, only limited by
+the amount of interrupt endpoints your gadget driver supports.
+
+Configuration with configfs
+===========================
+
+Instead of adding fake platform devices and drivers in order to pass
+some data to the kernel, if HID is a part of a gadget composed with
+configfs the hidg_func_descriptor.report_desc is passed to the kernel
+by writing the appropriate stream of bytes to a configfs attribute.
+
+Send and receive HID reports
+============================
+
+HID reports can be sent/received using read/write on the
+/dev/hidgX character devices. See below for an example program
+to do this.
+
+hid_gadget_test is a small interactive program to test the HID
+gadget driver. To use, point it at a hidg device and set the
+device type (keyboard / mouse / joystick) - E.G.::
+
+       # hid_gadget_test /dev/hidg0 keyboard
+
+You are now in the prompt of hid_gadget_test. You can type any
+combination of options and values. Available options and
+values are listed at program start. In keyboard mode you can
+send up to six values.
+
+For example type: g i s t r --left-shift
+
+Hit return and the corresponding report will be sent by the
+HID gadget.
+
+Another interesting example is the caps lock test. Type
+--caps-lock and hit return. A report is then sent by the
+gadget and you should receive the host answer, corresponding
+to the caps lock LED status::
+
+       --caps-lock
+       recv report:2
+
+With this command::
+
+       # hid_gadget_test /dev/hidg1 mouse
+
+You can test the mouse emulation. Values are two signed numbers.
+
+
+Sample code::
+
+    /* hid_gadget_test */
+
+    #include <pthread.h>
+    #include <string.h>
+    #include <stdio.h>
+    #include <ctype.h>
+    #include <fcntl.h>
+    #include <errno.h>
+    #include <stdio.h>
+    #include <stdlib.h>
+    #include <unistd.h>
+
+    #define BUF_LEN 512
+
+    struct options {
+       const char    *opt;
+       unsigned char val;
+  };
+
+  static struct options kmod[] = {
+       {.opt = "--left-ctrl",          .val = 0x01},
+       {.opt = "--right-ctrl",         .val = 0x10},
+       {.opt = "--left-shift",         .val = 0x02},
+       {.opt = "--right-shift",        .val = 0x20},
+       {.opt = "--left-alt",           .val = 0x04},
+       {.opt = "--right-alt",          .val = 0x40},
+       {.opt = "--left-meta",          .val = 0x08},
+       {.opt = "--right-meta",         .val = 0x80},
+       {.opt = NULL}
+  };
+
+  static struct options kval[] = {
+       {.opt = "--return",     .val = 0x28},
+       {.opt = "--esc",        .val = 0x29},
+       {.opt = "--bckspc",     .val = 0x2a},
+       {.opt = "--tab",        .val = 0x2b},
+       {.opt = "--spacebar",   .val = 0x2c},
+       {.opt = "--caps-lock",  .val = 0x39},
+       {.opt = "--f1",         .val = 0x3a},
+       {.opt = "--f2",         .val = 0x3b},
+       {.opt = "--f3",         .val = 0x3c},
+       {.opt = "--f4",         .val = 0x3d},
+       {.opt = "--f5",         .val = 0x3e},
+       {.opt = "--f6",         .val = 0x3f},
+       {.opt = "--f7",         .val = 0x40},
+       {.opt = "--f8",         .val = 0x41},
+       {.opt = "--f9",         .val = 0x42},
+       {.opt = "--f10",        .val = 0x43},
+       {.opt = "--f11",        .val = 0x44},
+       {.opt = "--f12",        .val = 0x45},
+       {.opt = "--insert",     .val = 0x49},
+       {.opt = "--home",       .val = 0x4a},
+       {.opt = "--pageup",     .val = 0x4b},
+       {.opt = "--del",        .val = 0x4c},
+       {.opt = "--end",        .val = 0x4d},
+       {.opt = "--pagedown",   .val = 0x4e},
+       {.opt = "--right",      .val = 0x4f},
+       {.opt = "--left",       .val = 0x50},
+       {.opt = "--down",       .val = 0x51},
+       {.opt = "--kp-enter",   .val = 0x58},
+       {.opt = "--up",         .val = 0x52},
+       {.opt = "--num-lock",   .val = 0x53},
+       {.opt = NULL}
+  };
+
+  int keyboard_fill_report(char report[8], char buf[BUF_LEN], int *hold)
+  {
+       char *tok = strtok(buf, " ");
+       int key = 0;
+       int i = 0;
+
+       for (; tok != NULL; tok = strtok(NULL, " ")) {
+
+               if (strcmp(tok, "--quit") == 0)
+                       return -1;
+
+               if (strcmp(tok, "--hold") == 0) {
+                       *hold = 1;
+                       continue;
+               }
+
+               if (key < 6) {
+                       for (i = 0; kval[i].opt != NULL; i++)
+                               if (strcmp(tok, kval[i].opt) == 0) {
+                                       report[2 + key++] = kval[i].val;
+                                       break;
+                               }
+                       if (kval[i].opt != NULL)
+                               continue;
+               }
+
+               if (key < 6)
+                       if (islower(tok[0])) {
+                               report[2 + key++] = (tok[0] - ('a' - 0x04));
+                               continue;
+                       }
+
+               for (i = 0; kmod[i].opt != NULL; i++)
+                       if (strcmp(tok, kmod[i].opt) == 0) {
+                               report[0] = report[0] | kmod[i].val;
+                               break;
+                       }
+               if (kmod[i].opt != NULL)
+                       continue;
+
+               if (key < 6)
+                       fprintf(stderr, "unknown option: %s\n", tok);
+       }
+       return 8;
+  }
+
+  static struct options mmod[] = {
+       {.opt = "--b1", .val = 0x01},
+       {.opt = "--b2", .val = 0x02},
+       {.opt = "--b3", .val = 0x04},
+       {.opt = NULL}
+  };
+
+  int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold)
+  {
+       char *tok = strtok(buf, " ");
+       int mvt = 0;
+       int i = 0;
+       for (; tok != NULL; tok = strtok(NULL, " ")) {
+
+               if (strcmp(tok, "--quit") == 0)
+                       return -1;
+
+               if (strcmp(tok, "--hold") == 0) {
+                       *hold = 1;
+                       continue;
+               }
+
+               for (i = 0; mmod[i].opt != NULL; i++)
+                       if (strcmp(tok, mmod[i].opt) == 0) {
+                               report[0] = report[0] | mmod[i].val;
+                               break;
+                       }
+               if (mmod[i].opt != NULL)
+                       continue;
+
+               if (!(tok[0] == '-' && tok[1] == '-') && mvt < 2) {
+                       errno = 0;
+                       report[1 + mvt++] = (char)strtol(tok, NULL, 0);
+                       if (errno != 0) {
+                               fprintf(stderr, "Bad value:'%s'\n", tok);
+                               report[1 + mvt--] = 0;
+                       }
+                       continue;
+               }
+
+               fprintf(stderr, "unknown option: %s\n", tok);
+       }
+       return 3;
+  }
+
+  static struct options jmod[] = {
+       {.opt = "--b1",         .val = 0x10},
+       {.opt = "--b2",         .val = 0x20},
+       {.opt = "--b3",         .val = 0x40},
+       {.opt = "--b4",         .val = 0x80},
+       {.opt = "--hat1",       .val = 0x00},
+       {.opt = "--hat2",       .val = 0x01},
+       {.opt = "--hat3",       .val = 0x02},
+       {.opt = "--hat4",       .val = 0x03},
+       {.opt = "--hatneutral", .val = 0x04},
+       {.opt = NULL}
+  };
+
+  int joystick_fill_report(char report[8], char buf[BUF_LEN], int *hold)
+  {
+       char *tok = strtok(buf, " ");
+       int mvt = 0;
+       int i = 0;
+
+       *hold = 1;
+
+       /* set default hat position: neutral */
+       report[3] = 0x04;
+
+       for (; tok != NULL; tok = strtok(NULL, " ")) {
+
+               if (strcmp(tok, "--quit") == 0)
+                       return -1;
+
+               for (i = 0; jmod[i].opt != NULL; i++)
+                       if (strcmp(tok, jmod[i].opt) == 0) {
+                               report[3] = (report[3] & 0xF0) | jmod[i].val;
+                               break;
+                       }
+               if (jmod[i].opt != NULL)
+                       continue;
+
+               if (!(tok[0] == '-' && tok[1] == '-') && mvt < 3) {
+                       errno = 0;
+                       report[mvt++] = (char)strtol(tok, NULL, 0);
+                       if (errno != 0) {
+                               fprintf(stderr, "Bad value:'%s'\n", tok);
+                               report[mvt--] = 0;
+                       }
+                       continue;
+               }
+
+               fprintf(stderr, "unknown option: %s\n", tok);
+       }
+       return 4;
+  }
+
+  void print_options(char c)
+  {
+       int i = 0;
+
+       if (c == 'k') {
+               printf("        keyboard options:\n"
+                      "                --hold\n");
+               for (i = 0; kmod[i].opt != NULL; i++)
+                       printf("\t\t%s\n", kmod[i].opt);
+               printf("\n      keyboard values:\n"
+                      "                [a-z] or\n");
+               for (i = 0; kval[i].opt != NULL; i++)
+                       printf("\t\t%-8s%s", kval[i].opt, i % 2 ? "\n" : "");
+               printf("\n");
+       } else if (c == 'm') {
+               printf("        mouse options:\n"
+                      "                --hold\n");
+               for (i = 0; mmod[i].opt != NULL; i++)
+                       printf("\t\t%s\n", mmod[i].opt);
+               printf("\n      mouse values:\n"
+                      "                Two signed numbers\n"
+                      "--quit to close\n");
+       } else {
+               printf("        joystick options:\n");
+               for (i = 0; jmod[i].opt != NULL; i++)
+                       printf("\t\t%s\n", jmod[i].opt);
+               printf("\n      joystick values:\n"
+                      "                three signed numbers\n"
+                      "--quit to close\n");
+       }
+  }
+
+  int main(int argc, const char *argv[])
+  {
+       const char *filename = NULL;
+       int fd = 0;
+       char buf[BUF_LEN];
+       int cmd_len;
+       char report[8];
+       int to_send = 8;
+       int hold = 0;
+       fd_set rfds;
+       int retval, i;
+
+       if (argc < 3) {
+               fprintf(stderr, "Usage: %s devname mouse|keyboard|joystick\n",
+                       argv[0]);
+               return 1;
+       }
+
+       if (argv[2][0] != 'k' && argv[2][0] != 'm' && argv[2][0] != 'j')
+         return 2;
+
+       filename = argv[1];
+
+       if ((fd = open(filename, O_RDWR, 0666)) == -1) {
+               perror(filename);
+               return 3;
+       }
+
+       print_options(argv[2][0]);
+
+       while (42) {
+
+               FD_ZERO(&rfds);
+               FD_SET(STDIN_FILENO, &rfds);
+               FD_SET(fd, &rfds);
+
+               retval = select(fd + 1, &rfds, NULL, NULL, NULL);
+               if (retval == -1 && errno == EINTR)
+                       continue;
+               if (retval < 0) {
+                       perror("select()");
+                       return 4;
+               }
+
+               if (FD_ISSET(fd, &rfds)) {
+                       cmd_len = read(fd, buf, BUF_LEN - 1);
+                       printf("recv report:");
+                       for (i = 0; i < cmd_len; i++)
+                               printf(" %02x", buf[i]);
+                       printf("\n");
+               }
+
+               if (FD_ISSET(STDIN_FILENO, &rfds)) {
+                       memset(report, 0x0, sizeof(report));
+                       cmd_len = read(STDIN_FILENO, buf, BUF_LEN - 1);
+
+                       if (cmd_len == 0)
+                               break;
+
+                       buf[cmd_len - 1] = '\0';
+                       hold = 0;
+
+                       memset(report, 0x0, sizeof(report));
+                       if (argv[2][0] == 'k')
+                               to_send = keyboard_fill_report(report, buf, &hold);
+                       else if (argv[2][0] == 'm')
+                               to_send = mouse_fill_report(report, buf, &hold);
+                       else
+                               to_send = joystick_fill_report(report, buf, &hold);
+
+                       if (to_send == -1)
+                               break;
+
+                       if (write(fd, report, to_send) != to_send) {
+                               perror(filename);
+                               return 5;
+                       }
+                       if (!hold) {
+                               memset(report, 0x0, sizeof(report));
+                               if (write(fd, report, to_send) != to_send) {
+                                       perror(filename);
+                                       return 6;
+                               }
+                       }
+               }
+       }
+
+       close(fd);
+       return 0;
+  }
diff --git a/Documentation/usb/gadget_hid.txt b/Documentation/usb/gadget_hid.txt
deleted file mode 100644 (file)
index 098d563..0000000
+++ /dev/null
@@ -1,457 +0,0 @@
-===========================
-Linux USB HID gadget driver
-===========================
-
-Introduction
-============
-
-The HID Gadget driver provides emulation of USB Human Interface
-Devices (HID). The basic HID handling is done in the kernel,
-and HID reports can be sent/received through I/O on the
-/dev/hidgX character devices.
-
-For more details about HID, see the developer page on
-http://www.usb.org/developers/hidpage/
-
-Configuration
-=============
-
-g_hid is a platform driver, so to use it you need to add
-struct platform_device(s) to your platform code defining the
-HID function descriptors you want to use - E.G. something
-like::
-
-  #include <linux/platform_device.h>
-  #include <linux/usb/g_hid.h>
-
-  /* hid descriptor for a keyboard */
-  static struct hidg_func_descriptor my_hid_data = {
-       .subclass               = 0, /* No subclass */
-       .protocol               = 1, /* Keyboard */
-       .report_length          = 8,
-       .report_desc_length     = 63,
-       .report_desc            = {
-               0x05, 0x01,     /* USAGE_PAGE (Generic Desktop)           */
-               0x09, 0x06,     /* USAGE (Keyboard)                       */
-               0xa1, 0x01,     /* COLLECTION (Application)               */
-               0x05, 0x07,     /*   USAGE_PAGE (Keyboard)                */
-               0x19, 0xe0,     /*   USAGE_MINIMUM (Keyboard LeftControl) */
-               0x29, 0xe7,     /*   USAGE_MAXIMUM (Keyboard Right GUI)   */
-               0x15, 0x00,     /*   LOGICAL_MINIMUM (0)                  */
-               0x25, 0x01,     /*   LOGICAL_MAXIMUM (1)                  */
-               0x75, 0x01,     /*   REPORT_SIZE (1)                      */
-               0x95, 0x08,     /*   REPORT_COUNT (8)                     */
-               0x81, 0x02,     /*   INPUT (Data,Var,Abs)                 */
-               0x95, 0x01,     /*   REPORT_COUNT (1)                     */
-               0x75, 0x08,     /*   REPORT_SIZE (8)                      */
-               0x81, 0x03,     /*   INPUT (Cnst,Var,Abs)                 */
-               0x95, 0x05,     /*   REPORT_COUNT (5)                     */
-               0x75, 0x01,     /*   REPORT_SIZE (1)                      */
-               0x05, 0x08,     /*   USAGE_PAGE (LEDs)                    */
-               0x19, 0x01,     /*   USAGE_MINIMUM (Num Lock)             */
-               0x29, 0x05,     /*   USAGE_MAXIMUM (Kana)                 */
-               0x91, 0x02,     /*   OUTPUT (Data,Var,Abs)                */
-               0x95, 0x01,     /*   REPORT_COUNT (1)                     */
-               0x75, 0x03,     /*   REPORT_SIZE (3)                      */
-               0x91, 0x03,     /*   OUTPUT (Cnst,Var,Abs)                */
-               0x95, 0x06,     /*   REPORT_COUNT (6)                     */
-               0x75, 0x08,     /*   REPORT_SIZE (8)                      */
-               0x15, 0x00,     /*   LOGICAL_MINIMUM (0)                  */
-               0x25, 0x65,     /*   LOGICAL_MAXIMUM (101)                */
-               0x05, 0x07,     /*   USAGE_PAGE (Keyboard)                */
-               0x19, 0x00,     /*   USAGE_MINIMUM (Reserved)             */
-               0x29, 0x65,     /*   USAGE_MAXIMUM (Keyboard Application) */
-               0x81, 0x00,     /*   INPUT (Data,Ary,Abs)                 */
-               0xc0            /* END_COLLECTION                         */
-       }
-  };
-
-  static struct platform_device my_hid = {
-       .name                   = "hidg",
-       .id                     = 0,
-       .num_resources          = 0,
-       .resource               = 0,
-       .dev.platform_data      = &my_hid_data,
-  };
-
-You can add as many HID functions as you want, only limited by
-the amount of interrupt endpoints your gadget driver supports.
-
-Configuration with configfs
-===========================
-
-Instead of adding fake platform devices and drivers in order to pass
-some data to the kernel, if HID is a part of a gadget composed with
-configfs the hidg_func_descriptor.report_desc is passed to the kernel
-by writing the appropriate stream of bytes to a configfs attribute.
-
-Send and receive HID reports
-============================
-
-HID reports can be sent/received using read/write on the
-/dev/hidgX character devices. See below for an example program
-to do this.
-
-hid_gadget_test is a small interactive program to test the HID
-gadget driver. To use, point it at a hidg device and set the
-device type (keyboard / mouse / joystick) - E.G.::
-
-       # hid_gadget_test /dev/hidg0 keyboard
-
-You are now in the prompt of hid_gadget_test. You can type any
-combination of options and values. Available options and
-values are listed at program start. In keyboard mode you can
-send up to six values.
-
-For example type: g i s t r --left-shift
-
-Hit return and the corresponding report will be sent by the
-HID gadget.
-
-Another interesting example is the caps lock test. Type
---caps-lock and hit return. A report is then sent by the
-gadget and you should receive the host answer, corresponding
-to the caps lock LED status::
-
-       --caps-lock
-       recv report:2
-
-With this command::
-
-       # hid_gadget_test /dev/hidg1 mouse
-
-You can test the mouse emulation. Values are two signed numbers.
-
-
-Sample code::
-
-    /* hid_gadget_test */
-
-    #include <pthread.h>
-    #include <string.h>
-    #include <stdio.h>
-    #include <ctype.h>
-    #include <fcntl.h>
-    #include <errno.h>
-    #include <stdio.h>
-    #include <stdlib.h>
-    #include <unistd.h>
-
-    #define BUF_LEN 512
-
-    struct options {
-       const char    *opt;
-       unsigned char val;
-  };
-
-  static struct options kmod[] = {
-       {.opt = "--left-ctrl",          .val = 0x01},
-       {.opt = "--right-ctrl",         .val = 0x10},
-       {.opt = "--left-shift",         .val = 0x02},
-       {.opt = "--right-shift",        .val = 0x20},
-       {.opt = "--left-alt",           .val = 0x04},
-       {.opt = "--right-alt",          .val = 0x40},
-       {.opt = "--left-meta",          .val = 0x08},
-       {.opt = "--right-meta",         .val = 0x80},
-       {.opt = NULL}
-  };
-
-  static struct options kval[] = {
-       {.opt = "--return",     .val = 0x28},
-       {.opt = "--esc",        .val = 0x29},
-       {.opt = "--bckspc",     .val = 0x2a},
-       {.opt = "--tab",        .val = 0x2b},
-       {.opt = "--spacebar",   .val = 0x2c},
-       {.opt = "--caps-lock",  .val = 0x39},
-       {.opt = "--f1",         .val = 0x3a},
-       {.opt = "--f2",         .val = 0x3b},
-       {.opt = "--f3",         .val = 0x3c},
-       {.opt = "--f4",         .val = 0x3d},
-       {.opt = "--f5",         .val = 0x3e},
-       {.opt = "--f6",         .val = 0x3f},
-       {.opt = "--f7",         .val = 0x40},
-       {.opt = "--f8",         .val = 0x41},
-       {.opt = "--f9",         .val = 0x42},
-       {.opt = "--f10",        .val = 0x43},
-       {.opt = "--f11",        .val = 0x44},
-       {.opt = "--f12",        .val = 0x45},
-       {.opt = "--insert",     .val = 0x49},
-       {.opt = "--home",       .val = 0x4a},
-       {.opt = "--pageup",     .val = 0x4b},
-       {.opt = "--del",        .val = 0x4c},
-       {.opt = "--end",        .val = 0x4d},
-       {.opt = "--pagedown",   .val = 0x4e},
-       {.opt = "--right",      .val = 0x4f},
-       {.opt = "--left",       .val = 0x50},
-       {.opt = "--down",       .val = 0x51},
-       {.opt = "--kp-enter",   .val = 0x58},
-       {.opt = "--up",         .val = 0x52},
-       {.opt = "--num-lock",   .val = 0x53},
-       {.opt = NULL}
-  };
-
-  int keyboard_fill_report(char report[8], char buf[BUF_LEN], int *hold)
-  {
-       char *tok = strtok(buf, " ");
-       int key = 0;
-       int i = 0;
-
-       for (; tok != NULL; tok = strtok(NULL, " ")) {
-
-               if (strcmp(tok, "--quit") == 0)
-                       return -1;
-
-               if (strcmp(tok, "--hold") == 0) {
-                       *hold = 1;
-                       continue;
-               }
-
-               if (key < 6) {
-                       for (i = 0; kval[i].opt != NULL; i++)
-                               if (strcmp(tok, kval[i].opt) == 0) {
-                                       report[2 + key++] = kval[i].val;
-                                       break;
-                               }
-                       if (kval[i].opt != NULL)
-                               continue;
-               }
-
-               if (key < 6)
-                       if (islower(tok[0])) {
-                               report[2 + key++] = (tok[0] - ('a' - 0x04));
-                               continue;
-                       }
-
-               for (i = 0; kmod[i].opt != NULL; i++)
-                       if (strcmp(tok, kmod[i].opt) == 0) {
-                               report[0] = report[0] | kmod[i].val;
-                               break;
-                       }
-               if (kmod[i].opt != NULL)
-                       continue;
-
-               if (key < 6)
-                       fprintf(stderr, "unknown option: %s\n", tok);
-       }
-       return 8;
-  }
-
-  static struct options mmod[] = {
-       {.opt = "--b1", .val = 0x01},
-       {.opt = "--b2", .val = 0x02},
-       {.opt = "--b3", .val = 0x04},
-       {.opt = NULL}
-  };
-
-  int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold)
-  {
-       char *tok = strtok(buf, " ");
-       int mvt = 0;
-       int i = 0;
-       for (; tok != NULL; tok = strtok(NULL, " ")) {
-
-               if (strcmp(tok, "--quit") == 0)
-                       return -1;
-
-               if (strcmp(tok, "--hold") == 0) {
-                       *hold = 1;
-                       continue;
-               }
-
-               for (i = 0; mmod[i].opt != NULL; i++)
-                       if (strcmp(tok, mmod[i].opt) == 0) {
-                               report[0] = report[0] | mmod[i].val;
-                               break;
-                       }
-               if (mmod[i].opt != NULL)
-                       continue;
-
-               if (!(tok[0] == '-' && tok[1] == '-') && mvt < 2) {
-                       errno = 0;
-                       report[1 + mvt++] = (char)strtol(tok, NULL, 0);
-                       if (errno != 0) {
-                               fprintf(stderr, "Bad value:'%s'\n", tok);
-                               report[1 + mvt--] = 0;
-                       }
-                       continue;
-               }
-
-               fprintf(stderr, "unknown option: %s\n", tok);
-       }
-       return 3;
-  }
-
-  static struct options jmod[] = {
-       {.opt = "--b1",         .val = 0x10},
-       {.opt = "--b2",         .val = 0x20},
-       {.opt = "--b3",         .val = 0x40},
-       {.opt = "--b4",         .val = 0x80},
-       {.opt = "--hat1",       .val = 0x00},
-       {.opt = "--hat2",       .val = 0x01},
-       {.opt = "--hat3",       .val = 0x02},
-       {.opt = "--hat4",       .val = 0x03},
-       {.opt = "--hatneutral", .val = 0x04},
-       {.opt = NULL}
-  };
-
-  int joystick_fill_report(char report[8], char buf[BUF_LEN], int *hold)
-  {
-       char *tok = strtok(buf, " ");
-       int mvt = 0;
-       int i = 0;
-
-       *hold = 1;
-
-       /* set default hat position: neutral */
-       report[3] = 0x04;
-
-       for (; tok != NULL; tok = strtok(NULL, " ")) {
-
-               if (strcmp(tok, "--quit") == 0)
-                       return -1;
-
-               for (i = 0; jmod[i].opt != NULL; i++)
-                       if (strcmp(tok, jmod[i].opt) == 0) {
-                               report[3] = (report[3] & 0xF0) | jmod[i].val;
-                               break;
-                       }
-               if (jmod[i].opt != NULL)
-                       continue;
-
-               if (!(tok[0] == '-' && tok[1] == '-') && mvt < 3) {
-                       errno = 0;
-                       report[mvt++] = (char)strtol(tok, NULL, 0);
-                       if (errno != 0) {
-                               fprintf(stderr, "Bad value:'%s'\n", tok);
-                               report[mvt--] = 0;
-                       }
-                       continue;
-               }
-
-               fprintf(stderr, "unknown option: %s\n", tok);
-       }
-       return 4;
-  }
-
-  void print_options(char c)
-  {
-       int i = 0;
-
-       if (c == 'k') {
-               printf("        keyboard options:\n"
-                      "                --hold\n");
-               for (i = 0; kmod[i].opt != NULL; i++)
-                       printf("\t\t%s\n", kmod[i].opt);
-               printf("\n      keyboard values:\n"
-                      "                [a-z] or\n");
-               for (i = 0; kval[i].opt != NULL; i++)
-                       printf("\t\t%-8s%s", kval[i].opt, i % 2 ? "\n" : "");
-               printf("\n");
-       } else if (c == 'm') {
-               printf("        mouse options:\n"
-                      "                --hold\n");
-               for (i = 0; mmod[i].opt != NULL; i++)
-                       printf("\t\t%s\n", mmod[i].opt);
-               printf("\n      mouse values:\n"
-                      "                Two signed numbers\n"
-                      "--quit to close\n");
-       } else {
-               printf("        joystick options:\n");
-               for (i = 0; jmod[i].opt != NULL; i++)
-                       printf("\t\t%s\n", jmod[i].opt);
-               printf("\n      joystick values:\n"
-                      "                three signed numbers\n"
-                      "--quit to close\n");
-       }
-  }
-
-  int main(int argc, const char *argv[])
-  {
-       const char *filename = NULL;
-       int fd = 0;
-       char buf[BUF_LEN];
-       int cmd_len;
-       char report[8];
-       int to_send = 8;
-       int hold = 0;
-       fd_set rfds;
-       int retval, i;
-
-       if (argc < 3) {
-               fprintf(stderr, "Usage: %s devname mouse|keyboard|joystick\n",
-                       argv[0]);
-               return 1;
-       }
-
-       if (argv[2][0] != 'k' && argv[2][0] != 'm' && argv[2][0] != 'j')
-         return 2;
-
-       filename = argv[1];
-
-       if ((fd = open(filename, O_RDWR, 0666)) == -1) {
-               perror(filename);
-               return 3;
-       }
-
-       print_options(argv[2][0]);
-
-       while (42) {
-
-               FD_ZERO(&rfds);
-               FD_SET(STDIN_FILENO, &rfds);
-               FD_SET(fd, &rfds);
-
-               retval = select(fd + 1, &rfds, NULL, NULL, NULL);
-               if (retval == -1 && errno == EINTR)
-                       continue;
-               if (retval < 0) {
-                       perror("select()");
-                       return 4;
-               }
-
-               if (FD_ISSET(fd, &rfds)) {
-                       cmd_len = read(fd, buf, BUF_LEN - 1);
-                       printf("recv report:");
-                       for (i = 0; i < cmd_len; i++)
-                               printf(" %02x", buf[i]);
-                       printf("\n");
-               }
-
-               if (FD_ISSET(STDIN_FILENO, &rfds)) {
-                       memset(report, 0x0, sizeof(report));
-                       cmd_len = read(STDIN_FILENO, buf, BUF_LEN - 1);
-
-                       if (cmd_len == 0)
-                               break;
-
-                       buf[cmd_len - 1] = '\0';
-                       hold = 0;
-
-                       memset(report, 0x0, sizeof(report));
-                       if (argv[2][0] == 'k')
-                               to_send = keyboard_fill_report(report, buf, &hold);
-                       else if (argv[2][0] == 'm')
-                               to_send = mouse_fill_report(report, buf, &hold);
-                       else
-                               to_send = joystick_fill_report(report, buf, &hold);
-
-                       if (to_send == -1)
-                               break;
-
-                       if (write(fd, report, to_send) != to_send) {
-                               perror(filename);
-                               return 5;
-                       }
-                       if (!hold) {
-                               memset(report, 0x0, sizeof(report));
-                               if (write(fd, report, to_send) != to_send) {
-                                       perror(filename);
-                                       return 6;
-                               }
-                       }
-               }
-       }
-
-       close(fd);
-       return 0;
-  }
diff --git a/Documentation/usb/gadget_multi.rst b/Documentation/usb/gadget_multi.rst
new file mode 100644 (file)
index 0000000..9806b55
--- /dev/null
@@ -0,0 +1,165 @@
+==============================
+Multifunction Composite Gadget
+==============================
+
+Overview
+========
+
+The Multifunction Composite Gadget (or g_multi) is a composite gadget
+that makes extensive use of the composite framework to provide
+a... multifunction gadget.
+
+In it's standard configuration it provides a single USB configuration
+with RNDIS[1] (that is Ethernet), USB CDC[2] ACM (that is serial) and
+USB Mass Storage functions.
+
+A CDC ECM (Ethernet) function may be turned on via a Kconfig option
+and RNDIS can be turned off.  If they are both enabled the gadget will
+have two configurations -- one with RNDIS and another with CDC ECM[3].
+
+Please note that if you use non-standard configuration (that is enable
+CDC ECM) you may need to change vendor and/or product ID.
+
+Host drivers
+============
+
+To make use of the gadget one needs to make it work on host side --
+without that there's no hope of achieving anything with the gadget.
+As one might expect, things one need to do very from system to system.
+
+Linux host drivers
+------------------
+
+Since the gadget uses standard composite framework and appears as such
+to Linux host it does not need any additional drivers on Linux host
+side.  All the functions are handled by respective drivers developed
+for them.
+
+This is also true for two configuration set-up with RNDIS
+configuration being the first one.  Linux host will use the second
+configuration with CDC ECM which should work better under Linux.
+
+Windows host drivers
+--------------------
+
+For the gadget to work under Windows two conditions have to be met:
+
+Detecting as composite gadget
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+First of all, Windows need to detect the gadget as an USB composite
+gadget which on its own have some conditions[4].  If they are met,
+Windows lets USB Generic Parent Driver[5] handle the device which then
+tries to match drivers for each individual interface (sort of, don't
+get into too many details).
+
+The good news is: you do not have to worry about most of the
+conditions!
+
+The only thing to worry is that the gadget has to have a single
+configuration so a dual RNDIS and CDC ECM gadget won't work unless you
+create a proper INF -- and of course, if you do submit it!
+
+Installing drivers for each function
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The other, trickier thing is making Windows install drivers for each
+individual function.
+
+For mass storage it is trivial since Windows detect it's an interface
+implementing USB Mass Storage class and selects appropriate driver.
+
+Things are harder with RDNIS and CDC ACM.
+
+RNDIS
+.....
+
+To make Windows select RNDIS drivers for the first function in the
+gadget, one needs to use the [[file:linux.inf]] file provided with this
+document.  It "attaches" Window's RNDIS driver to the first interface
+of the gadget.
+
+Please note, that while testing we encountered some issues[6] when
+RNDIS was not the first interface.  You do not need to worry abut it
+unless you are trying to develop your own gadget in which case watch
+out for this bug.
+
+CDC ACM
+.......
+
+Similarly, [[file:linux-cdc-acm.inf]] is provided for CDC ACM.
+
+Customising the gadget
+......................
+
+If you intend to hack the g_multi gadget be advised that rearranging
+functions will obviously change interface numbers for each of the
+functionality.  As an effect provided INFs won't work since they have
+interface numbers hard-coded in them (it's not hard to change those
+though[7]).
+
+This also means, that after experimenting with g_multi and changing
+provided functions one should change gadget's vendor and/or product ID
+so there will be no collision with other customised gadgets or the
+original gadget.
+
+Failing to comply may cause brain damage after wondering for hours why
+things don't work as intended before realising Windows have cached
+some drivers information (changing USB port may sometimes help plus
+you might try using USBDeview[8] to remove the phantom device).
+
+INF testing
+...........
+
+Provided INF files have been tested on Windows XP SP3, Windows Vista
+and Windows 7, all 32-bit versions.  It should work on 64-bit versions
+as well.  It most likely won't work on Windows prior to Windows XP
+SP2.
+
+Other systems
+-------------
+
+At this moment, drivers for any other systems have not been tested.
+Knowing how MacOS is based on BSD and BSD is an Open Source it is
+believed that it should (read: "I have no idea whether it will") work
+out-of-the-box.
+
+For more exotic systems I have even less to say...
+
+Any testing and drivers *are* *welcome*!
+
+Authors
+=======
+
+This document has been written by Michal Nazarewicz
+([[mailto:mina86@mina86.com]]).  INF files have been hacked with
+support of Marek Szyprowski ([[mailto:m.szyprowski@samsung.com]]) and
+Xiaofan Chen ([[mailto:xiaofanc@gmail.com]]) basing on the MS RNDIS
+template[9], Microchip's CDC ACM INF file and David Brownell's
+([[mailto:dbrownell@users.sourceforge.net]]) original INF files.
+
+Footnotes
+=========
+
+[1] Remote Network Driver Interface Specification,
+[[http://msdn.microsoft.com/en-us/library/ee484414.aspx]].
+
+[2] Communications Device Class Abstract Control Model, spec for this
+and other USB classes can be found at
+[[http://www.usb.org/developers/devclass_docs/]].
+
+[3] CDC Ethernet Control Model.
+
+[4] [[http://msdn.microsoft.com/en-us/library/ff537109(v=VS.85).aspx]]
+
+[5] [[http://msdn.microsoft.com/en-us/library/ff539234(v=VS.85).aspx]]
+
+[6] To put it in some other nice words, Windows failed to respond to
+any user input.
+
+[7] You may find [[http://www.cygnal.org/ubb/Forum9/HTML/001050.html]]
+useful.
+
+[8] http://www.nirsoft.net/utils/usb_devices_view.html
+
+[9] [[http://msdn.microsoft.com/en-us/library/ff570620.aspx]]
diff --git a/Documentation/usb/gadget_multi.txt b/Documentation/usb/gadget_multi.txt
deleted file mode 100644 (file)
index 9806b55..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-==============================
-Multifunction Composite Gadget
-==============================
-
-Overview
-========
-
-The Multifunction Composite Gadget (or g_multi) is a composite gadget
-that makes extensive use of the composite framework to provide
-a... multifunction gadget.
-
-In it's standard configuration it provides a single USB configuration
-with RNDIS[1] (that is Ethernet), USB CDC[2] ACM (that is serial) and
-USB Mass Storage functions.
-
-A CDC ECM (Ethernet) function may be turned on via a Kconfig option
-and RNDIS can be turned off.  If they are both enabled the gadget will
-have two configurations -- one with RNDIS and another with CDC ECM[3].
-
-Please note that if you use non-standard configuration (that is enable
-CDC ECM) you may need to change vendor and/or product ID.
-
-Host drivers
-============
-
-To make use of the gadget one needs to make it work on host side --
-without that there's no hope of achieving anything with the gadget.
-As one might expect, things one need to do very from system to system.
-
-Linux host drivers
-------------------
-
-Since the gadget uses standard composite framework and appears as such
-to Linux host it does not need any additional drivers on Linux host
-side.  All the functions are handled by respective drivers developed
-for them.
-
-This is also true for two configuration set-up with RNDIS
-configuration being the first one.  Linux host will use the second
-configuration with CDC ECM which should work better under Linux.
-
-Windows host drivers
---------------------
-
-For the gadget to work under Windows two conditions have to be met:
-
-Detecting as composite gadget
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-First of all, Windows need to detect the gadget as an USB composite
-gadget which on its own have some conditions[4].  If they are met,
-Windows lets USB Generic Parent Driver[5] handle the device which then
-tries to match drivers for each individual interface (sort of, don't
-get into too many details).
-
-The good news is: you do not have to worry about most of the
-conditions!
-
-The only thing to worry is that the gadget has to have a single
-configuration so a dual RNDIS and CDC ECM gadget won't work unless you
-create a proper INF -- and of course, if you do submit it!
-
-Installing drivers for each function
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The other, trickier thing is making Windows install drivers for each
-individual function.
-
-For mass storage it is trivial since Windows detect it's an interface
-implementing USB Mass Storage class and selects appropriate driver.
-
-Things are harder with RDNIS and CDC ACM.
-
-RNDIS
-.....
-
-To make Windows select RNDIS drivers for the first function in the
-gadget, one needs to use the [[file:linux.inf]] file provided with this
-document.  It "attaches" Window's RNDIS driver to the first interface
-of the gadget.
-
-Please note, that while testing we encountered some issues[6] when
-RNDIS was not the first interface.  You do not need to worry abut it
-unless you are trying to develop your own gadget in which case watch
-out for this bug.
-
-CDC ACM
-.......
-
-Similarly, [[file:linux-cdc-acm.inf]] is provided for CDC ACM.
-
-Customising the gadget
-......................
-
-If you intend to hack the g_multi gadget be advised that rearranging
-functions will obviously change interface numbers for each of the
-functionality.  As an effect provided INFs won't work since they have
-interface numbers hard-coded in them (it's not hard to change those
-though[7]).
-
-This also means, that after experimenting with g_multi and changing
-provided functions one should change gadget's vendor and/or product ID
-so there will be no collision with other customised gadgets or the
-original gadget.
-
-Failing to comply may cause brain damage after wondering for hours why
-things don't work as intended before realising Windows have cached
-some drivers information (changing USB port may sometimes help plus
-you might try using USBDeview[8] to remove the phantom device).
-
-INF testing
-...........
-
-Provided INF files have been tested on Windows XP SP3, Windows Vista
-and Windows 7, all 32-bit versions.  It should work on 64-bit versions
-as well.  It most likely won't work on Windows prior to Windows XP
-SP2.
-
-Other systems
--------------
-
-At this moment, drivers for any other systems have not been tested.
-Knowing how MacOS is based on BSD and BSD is an Open Source it is
-believed that it should (read: "I have no idea whether it will") work
-out-of-the-box.
-
-For more exotic systems I have even less to say...
-
-Any testing and drivers *are* *welcome*!
-
-Authors
-=======
-
-This document has been written by Michal Nazarewicz
-([[mailto:mina86@mina86.com]]).  INF files have been hacked with
-support of Marek Szyprowski ([[mailto:m.szyprowski@samsung.com]]) and
-Xiaofan Chen ([[mailto:xiaofanc@gmail.com]]) basing on the MS RNDIS
-template[9], Microchip's CDC ACM INF file and David Brownell's
-([[mailto:dbrownell@users.sourceforge.net]]) original INF files.
-
-Footnotes
-=========
-
-[1] Remote Network Driver Interface Specification,
-[[http://msdn.microsoft.com/en-us/library/ee484414.aspx]].
-
-[2] Communications Device Class Abstract Control Model, spec for this
-and other USB classes can be found at
-[[http://www.usb.org/developers/devclass_docs/]].
-
-[3] CDC Ethernet Control Model.
-
-[4] [[http://msdn.microsoft.com/en-us/library/ff537109(v=VS.85).aspx]]
-
-[5] [[http://msdn.microsoft.com/en-us/library/ff539234(v=VS.85).aspx]]
-
-[6] To put it in some other nice words, Windows failed to respond to
-any user input.
-
-[7] You may find [[http://www.cygnal.org/ubb/Forum9/HTML/001050.html]]
-useful.
-
-[8] http://www.nirsoft.net/utils/usb_devices_view.html
-
-[9] [[http://msdn.microsoft.com/en-us/library/ff570620.aspx]]
diff --git a/Documentation/usb/gadget_printer.rst b/Documentation/usb/gadget_printer.rst
new file mode 100644 (file)
index 0000000..5e5516c
--- /dev/null
@@ -0,0 +1,523 @@
+===============================
+Linux USB Printer Gadget Driver
+===============================
+
+06/04/2007
+
+Copyright (C) 2007 Craig W. Nadler <craig@nadler.us>
+
+
+
+General
+=======
+
+This driver may be used if you are writing printer firmware using Linux as
+the embedded OS. This driver has nothing to do with using a printer with
+your Linux host system.
+
+You will need a USB device controller and a Linux driver for it that accepts
+a gadget / "device class" driver using the Linux USB Gadget API. After the
+USB device controller driver is loaded then load the printer gadget driver.
+This will present a printer interface to the USB Host that your USB Device
+port is connected to.
+
+This driver is structured for printer firmware that runs in user mode. The
+user mode printer firmware will read and write data from the kernel mode
+printer gadget driver using a device file. The printer returns a printer status
+byte when the USB HOST sends a device request to get the printer status.  The
+user space firmware can read or write this status byte using a device file
+/dev/g_printer . Both blocking and non-blocking read/write calls are supported.
+
+
+
+
+Howto Use This Driver
+=====================
+
+To load the USB device controller driver and the printer gadget driver. The
+following example uses the Netchip 2280 USB device controller driver::
+
+       modprobe net2280
+       modprobe g_printer
+
+
+The follow command line parameter can be used when loading the printer gadget
+(ex: modprobe g_printer idVendor=0x0525 idProduct=0xa4a8 ):
+
+idVendor
+       This is the Vendor ID used in the device descriptor. The default is
+       the Netchip vendor id 0x0525. YOU MUST CHANGE TO YOUR OWN VENDOR ID
+       BEFORE RELEASING A PRODUCT. If you plan to release a product and don't
+       already have a Vendor ID please see www.usb.org for details on how to
+       get one.
+
+idProduct
+       This is the Product ID used in the device descriptor. The default
+       is 0xa4a8, you should change this to an ID that's not used by any of
+       your other USB products if you have any. It would be a good idea to
+       start numbering your products starting with say 0x0001.
+
+bcdDevice
+       This is the version number of your product. It would be a good idea
+       to put your firmware version here.
+
+iManufacturer
+       A string containing the name of the Vendor.
+
+iProduct
+       A string containing the Product Name.
+
+iSerialNum
+       A string containing the Serial Number. This should be changed for
+       each unit of your product.
+
+iPNPstring
+       The PNP ID string used for this printer. You will want to set
+       either on the command line or hard code the PNP ID string used for
+       your printer product.
+
+qlen
+       The number of 8k buffers to use per endpoint. The default is 10, you
+       should tune this for your product. You may also want to tune the
+       size of each buffer for your product.
+
+
+
+
+Using The Example Code
+======================
+
+This example code talks to stdout, instead of a print engine.
+
+To compile the test code below:
+
+1) save it to a file called prn_example.c
+2) compile the code with the follow command::
+
+        gcc prn_example.c -o prn_example
+
+
+
+To read printer data from the host to stdout::
+
+       # prn_example -read_data
+
+
+To write printer data from a file (data_file) to the host::
+
+       # cat data_file | prn_example -write_data
+
+
+To get the current printer status for the gadget driver:::
+
+       # prn_example -get_status
+
+       Printer status is:
+            Printer is NOT Selected
+            Paper is Out
+            Printer OK
+
+
+To set printer to Selected/On-line::
+
+       # prn_example -selected
+
+
+To set printer to Not Selected/Off-line::
+
+       # prn_example -not_selected
+
+
+To set paper status to paper out::
+
+       # prn_example -paper_out
+
+
+To set paper status to paper loaded::
+
+       # prn_example -paper_loaded
+
+
+To set error status to printer OK::
+
+       # prn_example -no_error
+
+
+To set error status to ERROR::
+
+       # prn_example -error
+
+
+
+
+Example Code
+============
+
+::
+
+
+  #include <stdio.h>
+  #include <stdlib.h>
+  #include <fcntl.h>
+  #include <linux/poll.h>
+  #include <sys/ioctl.h>
+  #include <linux/usb/g_printer.h>
+
+  #define PRINTER_FILE                 "/dev/g_printer"
+  #define BUF_SIZE                     512
+
+
+  /*
+   * 'usage()' - Show program usage.
+   */
+
+  static void
+  usage(const char *option)            /* I - Option string or NULL */
+  {
+       if (option) {
+               fprintf(stderr,"prn_example: Unknown option \"%s\"!\n",
+                               option);
+       }
+
+       fputs("\n", stderr);
+       fputs("Usage: prn_example -[options]\n", stderr);
+       fputs("Options:\n", stderr);
+       fputs("\n", stderr);
+       fputs("-get_status    Get the current printer status.\n", stderr);
+       fputs("-selected      Set the selected status to selected.\n", stderr);
+       fputs("-not_selected  Set the selected status to NOT selected.\n",
+                       stderr);
+       fputs("-error         Set the error status to error.\n", stderr);
+       fputs("-no_error      Set the error status to NO error.\n", stderr);
+       fputs("-paper_out     Set the paper status to paper out.\n", stderr);
+       fputs("-paper_loaded  Set the paper status to paper loaded.\n",
+                       stderr);
+       fputs("-read_data     Read printer data from driver.\n", stderr);
+       fputs("-write_data    Write printer sata to driver.\n", stderr);
+       fputs("-NB_read_data  (Non-Blocking) Read printer data from driver.\n",
+                       stderr);
+       fputs("\n\n", stderr);
+
+       exit(1);
+  }
+
+
+  static int
+  read_printer_data()
+  {
+       struct pollfd   fd[1];
+
+       /* Open device file for printer gadget. */
+       fd[0].fd = open(PRINTER_FILE, O_RDWR);
+       if (fd[0].fd < 0) {
+               printf("Error %d opening %s\n", fd[0].fd, PRINTER_FILE);
+               close(fd[0].fd);
+               return(-1);
+       }
+
+       fd[0].events = POLLIN | POLLRDNORM;
+
+       while (1) {
+               static char buf[BUF_SIZE];
+               int bytes_read;
+               int retval;
+
+               /* Wait for up to 1 second for data. */
+               retval = poll(fd, 1, 1000);
+
+               if (retval && (fd[0].revents & POLLRDNORM)) {
+
+                       /* Read data from printer gadget driver. */
+                       bytes_read = read(fd[0].fd, buf, BUF_SIZE);
+
+                       if (bytes_read < 0) {
+                               printf("Error %d reading from %s\n",
+                                               fd[0].fd, PRINTER_FILE);
+                               close(fd[0].fd);
+                               return(-1);
+                       } else if (bytes_read > 0) {
+                               /* Write data to standard OUTPUT (stdout). */
+                               fwrite(buf, 1, bytes_read, stdout);
+                               fflush(stdout);
+                       }
+
+               }
+
+       }
+
+       /* Close the device file. */
+       close(fd[0].fd);
+
+       return 0;
+  }
+
+
+  static int
+  write_printer_data()
+  {
+       struct pollfd   fd[1];
+
+       /* Open device file for printer gadget. */
+       fd[0].fd = open (PRINTER_FILE, O_RDWR);
+       if (fd[0].fd < 0) {
+               printf("Error %d opening %s\n", fd[0].fd, PRINTER_FILE);
+               close(fd[0].fd);
+               return(-1);
+       }
+
+       fd[0].events = POLLOUT | POLLWRNORM;
+
+       while (1) {
+               int retval;
+               static char buf[BUF_SIZE];
+               /* Read data from standard INPUT (stdin). */
+               int bytes_read = fread(buf, 1, BUF_SIZE, stdin);
+
+               if (!bytes_read) {
+                       break;
+               }
+
+               while (bytes_read) {
+
+                       /* Wait for up to 1 second to sent data. */
+                       retval = poll(fd, 1, 1000);
+
+                       /* Write data to printer gadget driver. */
+                       if (retval && (fd[0].revents & POLLWRNORM)) {
+                               retval = write(fd[0].fd, buf, bytes_read);
+                               if (retval < 0) {
+                                       printf("Error %d writing to %s\n",
+                                                       fd[0].fd,
+                                                       PRINTER_FILE);
+                                       close(fd[0].fd);
+                                       return(-1);
+                               } else {
+                                       bytes_read -= retval;
+                               }
+
+                       }
+
+               }
+
+       }
+
+       /* Wait until the data has been sent. */
+       fsync(fd[0].fd);
+
+       /* Close the device file. */
+       close(fd[0].fd);
+
+       return 0;
+  }
+
+
+  static int
+  read_NB_printer_data()
+  {
+       int             fd;
+       static char     buf[BUF_SIZE];
+       int             bytes_read;
+
+       /* Open device file for printer gadget. */
+       fd = open(PRINTER_FILE, O_RDWR|O_NONBLOCK);
+       if (fd < 0) {
+               printf("Error %d opening %s\n", fd, PRINTER_FILE);
+               close(fd);
+               return(-1);
+       }
+
+       while (1) {
+               /* Read data from printer gadget driver. */
+               bytes_read = read(fd, buf, BUF_SIZE);
+               if (bytes_read <= 0) {
+                       break;
+               }
+
+               /* Write data to standard OUTPUT (stdout). */
+               fwrite(buf, 1, bytes_read, stdout);
+               fflush(stdout);
+       }
+
+       /* Close the device file. */
+       close(fd);
+
+       return 0;
+  }
+
+
+  static int
+  get_printer_status()
+  {
+       int     retval;
+       int     fd;
+
+       /* Open device file for printer gadget. */
+       fd = open(PRINTER_FILE, O_RDWR);
+       if (fd < 0) {
+               printf("Error %d opening %s\n", fd, PRINTER_FILE);
+               close(fd);
+               return(-1);
+       }
+
+       /* Make the IOCTL call. */
+       retval = ioctl(fd, GADGET_GET_PRINTER_STATUS);
+       if (retval < 0) {
+               fprintf(stderr, "ERROR: Failed to set printer status\n");
+               return(-1);
+       }
+
+       /* Close the device file. */
+       close(fd);
+
+       return(retval);
+  }
+
+
+  static int
+  set_printer_status(unsigned char buf, int clear_printer_status_bit)
+  {
+       int     retval;
+       int     fd;
+
+       retval = get_printer_status();
+       if (retval < 0) {
+               fprintf(stderr, "ERROR: Failed to get printer status\n");
+               return(-1);
+       }
+
+       /* Open device file for printer gadget. */
+       fd = open(PRINTER_FILE, O_RDWR);
+
+       if (fd < 0) {
+               printf("Error %d opening %s\n", fd, PRINTER_FILE);
+               close(fd);
+               return(-1);
+       }
+
+       if (clear_printer_status_bit) {
+               retval &= ~buf;
+       } else {
+               retval |= buf;
+       }
+
+       /* Make the IOCTL call. */
+       if (ioctl(fd, GADGET_SET_PRINTER_STATUS, (unsigned char)retval)) {
+               fprintf(stderr, "ERROR: Failed to set printer status\n");
+               return(-1);
+       }
+
+       /* Close the device file. */
+       close(fd);
+
+       return 0;
+  }
+
+
+  static int
+  display_printer_status()
+  {
+       char    printer_status;
+
+       printer_status = get_printer_status();
+       if (printer_status < 0) {
+               fprintf(stderr, "ERROR: Failed to get printer status\n");
+               return(-1);
+       }
+
+       printf("Printer status is:\n");
+       if (printer_status & PRINTER_SELECTED) {
+               printf("     Printer is Selected\n");
+       } else {
+               printf("     Printer is NOT Selected\n");
+       }
+       if (printer_status & PRINTER_PAPER_EMPTY) {
+               printf("     Paper is Out\n");
+       } else {
+               printf("     Paper is Loaded\n");
+       }
+       if (printer_status & PRINTER_NOT_ERROR) {
+               printf("     Printer OK\n");
+       } else {
+               printf("     Printer ERROR\n");
+       }
+
+       return(0);
+  }
+
+
+  int
+  main(int  argc, char *argv[])
+  {
+       int     i;              /* Looping var */
+       int     retval = 0;
+
+       /* No Args */
+       if (argc == 1) {
+               usage(0);
+               exit(0);
+       }
+
+       for (i = 1; i < argc && !retval; i ++) {
+
+               if (argv[i][0] != '-') {
+                       continue;
+               }
+
+               if (!strcmp(argv[i], "-get_status")) {
+                       if (display_printer_status()) {
+                               retval = 1;
+                       }
+
+               } else if (!strcmp(argv[i], "-paper_loaded")) {
+                       if (set_printer_status(PRINTER_PAPER_EMPTY, 1)) {
+                               retval = 1;
+                       }
+
+               } else if (!strcmp(argv[i], "-paper_out")) {
+                       if (set_printer_status(PRINTER_PAPER_EMPTY, 0)) {
+                               retval = 1;
+                       }
+
+               } else if (!strcmp(argv[i], "-selected")) {
+                       if (set_printer_status(PRINTER_SELECTED, 0)) {
+                               retval = 1;
+                       }
+
+               } else if (!strcmp(argv[i], "-not_selected")) {
+                       if (set_printer_status(PRINTER_SELECTED, 1)) {
+                               retval = 1;
+                       }
+
+               } else if (!strcmp(argv[i], "-error")) {
+                       if (set_printer_status(PRINTER_NOT_ERROR, 1)) {
+                               retval = 1;
+                       }
+
+               } else if (!strcmp(argv[i], "-no_error")) {
+                       if (set_printer_status(PRINTER_NOT_ERROR, 0)) {
+                               retval = 1;
+                       }
+
+               } else if (!strcmp(argv[i], "-read_data")) {
+                       if (read_printer_data()) {
+                               retval = 1;
+                       }
+
+               } else if (!strcmp(argv[i], "-write_data")) {
+                       if (write_printer_data()) {
+                               retval = 1;
+                       }
+
+               } else if (!strcmp(argv[i], "-NB_read_data")) {
+                       if (read_NB_printer_data()) {
+                               retval = 1;
+                       }
+
+               } else {
+                       usage(argv[i]);
+                       retval = 1;
+               }
+       }
+
+       exit(retval);
+  }
diff --git a/Documentation/usb/gadget_printer.txt b/Documentation/usb/gadget_printer.txt
deleted file mode 100644 (file)
index 5e5516c..0000000
+++ /dev/null
@@ -1,523 +0,0 @@
-===============================
-Linux USB Printer Gadget Driver
-===============================
-
-06/04/2007
-
-Copyright (C) 2007 Craig W. Nadler <craig@nadler.us>
-
-
-
-General
-=======
-
-This driver may be used if you are writing printer firmware using Linux as
-the embedded OS. This driver has nothing to do with using a printer with
-your Linux host system.
-
-You will need a USB device controller and a Linux driver for it that accepts
-a gadget / "device class" driver using the Linux USB Gadget API. After the
-USB device controller driver is loaded then load the printer gadget driver.
-This will present a printer interface to the USB Host that your USB Device
-port is connected to.
-
-This driver is structured for printer firmware that runs in user mode. The
-user mode printer firmware will read and write data from the kernel mode
-printer gadget driver using a device file. The printer returns a printer status
-byte when the USB HOST sends a device request to get the printer status.  The
-user space firmware can read or write this status byte using a device file
-/dev/g_printer . Both blocking and non-blocking read/write calls are supported.
-
-
-
-
-Howto Use This Driver
-=====================
-
-To load the USB device controller driver and the printer gadget driver. The
-following example uses the Netchip 2280 USB device controller driver::
-
-       modprobe net2280
-       modprobe g_printer
-
-
-The follow command line parameter can be used when loading the printer gadget
-(ex: modprobe g_printer idVendor=0x0525 idProduct=0xa4a8 ):
-
-idVendor
-       This is the Vendor ID used in the device descriptor. The default is
-       the Netchip vendor id 0x0525. YOU MUST CHANGE TO YOUR OWN VENDOR ID
-       BEFORE RELEASING A PRODUCT. If you plan to release a product and don't
-       already have a Vendor ID please see www.usb.org for details on how to
-       get one.
-
-idProduct
-       This is the Product ID used in the device descriptor. The default
-       is 0xa4a8, you should change this to an ID that's not used by any of
-       your other USB products if you have any. It would be a good idea to
-       start numbering your products starting with say 0x0001.
-
-bcdDevice
-       This is the version number of your product. It would be a good idea
-       to put your firmware version here.
-
-iManufacturer
-       A string containing the name of the Vendor.
-
-iProduct
-       A string containing the Product Name.
-
-iSerialNum
-       A string containing the Serial Number. This should be changed for
-       each unit of your product.
-
-iPNPstring
-       The PNP ID string used for this printer. You will want to set
-       either on the command line or hard code the PNP ID string used for
-       your printer product.
-
-qlen
-       The number of 8k buffers to use per endpoint. The default is 10, you
-       should tune this for your product. You may also want to tune the
-       size of each buffer for your product.
-
-
-
-
-Using The Example Code
-======================
-
-This example code talks to stdout, instead of a print engine.
-
-To compile the test code below:
-
-1) save it to a file called prn_example.c
-2) compile the code with the follow command::
-
-        gcc prn_example.c -o prn_example
-
-
-
-To read printer data from the host to stdout::
-
-       # prn_example -read_data
-
-
-To write printer data from a file (data_file) to the host::
-
-       # cat data_file | prn_example -write_data
-
-
-To get the current printer status for the gadget driver:::
-
-       # prn_example -get_status
-
-       Printer status is:
-            Printer is NOT Selected
-            Paper is Out
-            Printer OK
-
-
-To set printer to Selected/On-line::
-
-       # prn_example -selected
-
-
-To set printer to Not Selected/Off-line::
-
-       # prn_example -not_selected
-
-
-To set paper status to paper out::
-
-       # prn_example -paper_out
-
-
-To set paper status to paper loaded::
-
-       # prn_example -paper_loaded
-
-
-To set error status to printer OK::
-
-       # prn_example -no_error
-
-
-To set error status to ERROR::
-
-       # prn_example -error
-
-
-
-
-Example Code
-============
-
-::
-
-
-  #include <stdio.h>
-  #include <stdlib.h>
-  #include <fcntl.h>
-  #include <linux/poll.h>
-  #include <sys/ioctl.h>
-  #include <linux/usb/g_printer.h>
-
-  #define PRINTER_FILE                 "/dev/g_printer"
-  #define BUF_SIZE                     512
-
-
-  /*
-   * 'usage()' - Show program usage.
-   */
-
-  static void
-  usage(const char *option)            /* I - Option string or NULL */
-  {
-       if (option) {
-               fprintf(stderr,"prn_example: Unknown option \"%s\"!\n",
-                               option);
-       }
-
-       fputs("\n", stderr);
-       fputs("Usage: prn_example -[options]\n", stderr);
-       fputs("Options:\n", stderr);
-       fputs("\n", stderr);
-       fputs("-get_status    Get the current printer status.\n", stderr);
-       fputs("-selected      Set the selected status to selected.\n", stderr);
-       fputs("-not_selected  Set the selected status to NOT selected.\n",
-                       stderr);
-       fputs("-error         Set the error status to error.\n", stderr);
-       fputs("-no_error      Set the error status to NO error.\n", stderr);
-       fputs("-paper_out     Set the paper status to paper out.\n", stderr);
-       fputs("-paper_loaded  Set the paper status to paper loaded.\n",
-                       stderr);
-       fputs("-read_data     Read printer data from driver.\n", stderr);
-       fputs("-write_data    Write printer sata to driver.\n", stderr);
-       fputs("-NB_read_data  (Non-Blocking) Read printer data from driver.\n",
-                       stderr);
-       fputs("\n\n", stderr);
-
-       exit(1);
-  }
-
-
-  static int
-  read_printer_data()
-  {
-       struct pollfd   fd[1];
-
-       /* Open device file for printer gadget. */
-       fd[0].fd = open(PRINTER_FILE, O_RDWR);
-       if (fd[0].fd < 0) {
-               printf("Error %d opening %s\n", fd[0].fd, PRINTER_FILE);
-               close(fd[0].fd);
-               return(-1);
-       }
-
-       fd[0].events = POLLIN | POLLRDNORM;
-
-       while (1) {
-               static char buf[BUF_SIZE];
-               int bytes_read;
-               int retval;
-
-               /* Wait for up to 1 second for data. */
-               retval = poll(fd, 1, 1000);
-
-               if (retval && (fd[0].revents & POLLRDNORM)) {
-
-                       /* Read data from printer gadget driver. */
-                       bytes_read = read(fd[0].fd, buf, BUF_SIZE);
-
-                       if (bytes_read < 0) {
-                               printf("Error %d reading from %s\n",
-                                               fd[0].fd, PRINTER_FILE);
-                               close(fd[0].fd);
-                               return(-1);
-                       } else if (bytes_read > 0) {
-                               /* Write data to standard OUTPUT (stdout). */
-                               fwrite(buf, 1, bytes_read, stdout);
-                               fflush(stdout);
-                       }
-
-               }
-
-       }
-
-       /* Close the device file. */
-       close(fd[0].fd);
-
-       return 0;
-  }
-
-
-  static int
-  write_printer_data()
-  {
-       struct pollfd   fd[1];
-
-       /* Open device file for printer gadget. */
-       fd[0].fd = open (PRINTER_FILE, O_RDWR);
-       if (fd[0].fd < 0) {
-               printf("Error %d opening %s\n", fd[0].fd, PRINTER_FILE);
-               close(fd[0].fd);
-               return(-1);
-       }
-
-       fd[0].events = POLLOUT | POLLWRNORM;
-
-       while (1) {
-               int retval;
-               static char buf[BUF_SIZE];
-               /* Read data from standard INPUT (stdin). */
-               int bytes_read = fread(buf, 1, BUF_SIZE, stdin);
-
-               if (!bytes_read) {
-                       break;
-               }
-
-               while (bytes_read) {
-
-                       /* Wait for up to 1 second to sent data. */
-                       retval = poll(fd, 1, 1000);
-
-                       /* Write data to printer gadget driver. */
-                       if (retval && (fd[0].revents & POLLWRNORM)) {
-                               retval = write(fd[0].fd, buf, bytes_read);
-                               if (retval < 0) {
-                                       printf("Error %d writing to %s\n",
-                                                       fd[0].fd,
-                                                       PRINTER_FILE);
-                                       close(fd[0].fd);
-                                       return(-1);
-                               } else {
-                                       bytes_read -= retval;
-                               }
-
-                       }
-
-               }
-
-       }
-
-       /* Wait until the data has been sent. */
-       fsync(fd[0].fd);
-
-       /* Close the device file. */
-       close(fd[0].fd);
-
-       return 0;
-  }
-
-
-  static int
-  read_NB_printer_data()
-  {
-       int             fd;
-       static char     buf[BUF_SIZE];
-       int             bytes_read;
-
-       /* Open device file for printer gadget. */
-       fd = open(PRINTER_FILE, O_RDWR|O_NONBLOCK);
-       if (fd < 0) {
-               printf("Error %d opening %s\n", fd, PRINTER_FILE);
-               close(fd);
-               return(-1);
-       }
-
-       while (1) {
-               /* Read data from printer gadget driver. */
-               bytes_read = read(fd, buf, BUF_SIZE);
-               if (bytes_read <= 0) {
-                       break;
-               }
-
-               /* Write data to standard OUTPUT (stdout). */
-               fwrite(buf, 1, bytes_read, stdout);
-               fflush(stdout);
-       }
-
-       /* Close the device file. */
-       close(fd);
-
-       return 0;
-  }
-
-
-  static int
-  get_printer_status()
-  {
-       int     retval;
-       int     fd;
-
-       /* Open device file for printer gadget. */
-       fd = open(PRINTER_FILE, O_RDWR);
-       if (fd < 0) {
-               printf("Error %d opening %s\n", fd, PRINTER_FILE);
-               close(fd);
-               return(-1);
-       }
-
-       /* Make the IOCTL call. */
-       retval = ioctl(fd, GADGET_GET_PRINTER_STATUS);
-       if (retval < 0) {
-               fprintf(stderr, "ERROR: Failed to set printer status\n");
-               return(-1);
-       }
-
-       /* Close the device file. */
-       close(fd);
-
-       return(retval);
-  }
-
-
-  static int
-  set_printer_status(unsigned char buf, int clear_printer_status_bit)
-  {
-       int     retval;
-       int     fd;
-
-       retval = get_printer_status();
-       if (retval < 0) {
-               fprintf(stderr, "ERROR: Failed to get printer status\n");
-               return(-1);
-       }
-
-       /* Open device file for printer gadget. */
-       fd = open(PRINTER_FILE, O_RDWR);
-
-       if (fd < 0) {
-               printf("Error %d opening %s\n", fd, PRINTER_FILE);
-               close(fd);
-               return(-1);
-       }
-
-       if (clear_printer_status_bit) {
-               retval &= ~buf;
-       } else {
-               retval |= buf;
-       }
-
-       /* Make the IOCTL call. */
-       if (ioctl(fd, GADGET_SET_PRINTER_STATUS, (unsigned char)retval)) {
-               fprintf(stderr, "ERROR: Failed to set printer status\n");
-               return(-1);
-       }
-
-       /* Close the device file. */
-       close(fd);
-
-       return 0;
-  }
-
-
-  static int
-  display_printer_status()
-  {
-       char    printer_status;
-
-       printer_status = get_printer_status();
-       if (printer_status < 0) {
-               fprintf(stderr, "ERROR: Failed to get printer status\n");
-               return(-1);
-       }
-
-       printf("Printer status is:\n");
-       if (printer_status & PRINTER_SELECTED) {
-               printf("     Printer is Selected\n");
-       } else {
-               printf("     Printer is NOT Selected\n");
-       }
-       if (printer_status & PRINTER_PAPER_EMPTY) {
-               printf("     Paper is Out\n");
-       } else {
-               printf("     Paper is Loaded\n");
-       }
-       if (printer_status & PRINTER_NOT_ERROR) {
-               printf("     Printer OK\n");
-       } else {
-               printf("     Printer ERROR\n");
-       }
-
-       return(0);
-  }
-
-
-  int
-  main(int  argc, char *argv[])
-  {
-       int     i;              /* Looping var */
-       int     retval = 0;
-
-       /* No Args */
-       if (argc == 1) {
-               usage(0);
-               exit(0);
-       }
-
-       for (i = 1; i < argc && !retval; i ++) {
-
-               if (argv[i][0] != '-') {
-                       continue;
-               }
-
-               if (!strcmp(argv[i], "-get_status")) {
-                       if (display_printer_status()) {
-                               retval = 1;
-                       }
-
-               } else if (!strcmp(argv[i], "-paper_loaded")) {
-                       if (set_printer_status(PRINTER_PAPER_EMPTY, 1)) {
-                               retval = 1;
-                       }
-
-               } else if (!strcmp(argv[i], "-paper_out")) {
-                       if (set_printer_status(PRINTER_PAPER_EMPTY, 0)) {
-                               retval = 1;
-                       }
-
-               } else if (!strcmp(argv[i], "-selected")) {
-                       if (set_printer_status(PRINTER_SELECTED, 0)) {
-                               retval = 1;
-                       }
-
-               } else if (!strcmp(argv[i], "-not_selected")) {
-                       if (set_printer_status(PRINTER_SELECTED, 1)) {
-                               retval = 1;
-                       }
-
-               } else if (!strcmp(argv[i], "-error")) {
-                       if (set_printer_status(PRINTER_NOT_ERROR, 1)) {
-                               retval = 1;
-                       }
-
-               } else if (!strcmp(argv[i], "-no_error")) {
-                       if (set_printer_status(PRINTER_NOT_ERROR, 0)) {
-                               retval = 1;
-                       }
-
-               } else if (!strcmp(argv[i], "-read_data")) {
-                       if (read_printer_data()) {
-                               retval = 1;
-                       }
-
-               } else if (!strcmp(argv[i], "-write_data")) {
-                       if (write_printer_data()) {
-                               retval = 1;
-                       }
-
-               } else if (!strcmp(argv[i], "-NB_read_data")) {
-                       if (read_NB_printer_data()) {
-                               retval = 1;
-                       }
-
-               } else {
-                       usage(argv[i]);
-                       retval = 1;
-               }
-       }
-
-       exit(retval);
-  }
diff --git a/Documentation/usb/gadget_serial.rst b/Documentation/usb/gadget_serial.rst
new file mode 100644 (file)
index 0000000..dce8bc1
--- /dev/null
@@ -0,0 +1,289 @@
+===============================
+Linux Gadget Serial Driver v2.0
+===============================
+
+11/20/2004
+
+(updated 8-May-2008 for v2.3)
+
+
+License and Disclaimer
+----------------------
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of
+the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public
+License along with this program; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+MA 02111-1307 USA.
+
+This document and the gadget serial driver itself are
+Copyright (C) 2004 by Al Borchers (alborchers@steinerpoint.com).
+
+If you have questions, problems, or suggestions for this driver
+please contact Al Borchers at alborchers@steinerpoint.com.
+
+
+Prerequisites
+-------------
+Versions of the gadget serial driver are available for the
+2.4 Linux kernels, but this document assumes you are using
+version 2.3 or later of the gadget serial driver in a 2.6
+Linux kernel.
+
+This document assumes that you are familiar with Linux and
+Windows and know how to configure and build Linux kernels, run
+standard utilities, use minicom and HyperTerminal, and work with
+USB and serial devices.  It also assumes you configure the Linux
+gadget and usb drivers as modules.
+
+With version 2.3 of the driver, major and minor device nodes are
+no longer statically defined.  Your Linux based system should mount
+sysfs in /sys, and use "mdev" (in Busybox) or "udev" to make the
+/dev nodes matching the sysfs /sys/class/tty files.
+
+
+
+Overview
+--------
+The gadget serial driver is a Linux USB gadget driver, a USB device
+side driver.  It runs on a Linux system that has USB device side
+hardware; for example, a PDA, an embedded Linux system, or a PC
+with a USB development card.
+
+The gadget serial driver talks over USB to either a CDC ACM driver
+or a generic USB serial driver running on a host PC::
+
+   Host
+   --------------------------------------
+  | Host-Side   CDC ACM       USB Host   |
+  | Operating |   or        | Controller |   USB
+  | System    | Generic USB | Driver     |--------
+  | (Linux or | Serial      | and        |        |
+  | Windows)    Driver        USB Stack  |        |
+   --------------------------------------         |
+                                                  |
+                                                  |
+                                                  |
+   Gadget                                         |
+   --------------------------------------         |
+  | Gadget                   USB Periph. |        |
+  | Device-Side |  Gadget  | Controller  |        |
+  | Linux       |  Serial  | Driver      |--------
+  | Operating   |  Driver  | and         |
+  | System                   USB Stack   |
+   --------------------------------------
+
+On the device-side Linux system, the gadget serial driver looks
+like a serial device.
+
+On the host-side system, the gadget serial device looks like a
+CDC ACM compliant class device or a simple vendor specific device
+with bulk in and bulk out endpoints, and it is treated similarly
+to other serial devices.
+
+The host side driver can potentially be any ACM compliant driver
+or any driver that can talk to a device with a simple bulk in/out
+interface.  Gadget serial has been tested with the Linux ACM driver,
+the Windows usbser.sys ACM driver, and the Linux USB generic serial
+driver.
+
+With the gadget serial driver and the host side ACM or generic
+serial driver running, you should be able to communicate between
+the host and the gadget side systems as if they were connected by a
+serial cable.
+
+The gadget serial driver only provides simple unreliable data
+communication.  It does not yet handle flow control or many other
+features of normal serial devices.
+
+
+Installing the Gadget Serial Driver
+-----------------------------------
+To use the gadget serial driver you must configure the Linux gadget
+side kernel for "Support for USB Gadgets", for a "USB Peripheral
+Controller" (for example, net2280), and for the "Serial Gadget"
+driver.  All this are listed under "USB Gadget Support" when
+configuring the kernel.  Then rebuild and install the kernel or
+modules.
+
+Then you must load the gadget serial driver.  To load it as an
+ACM device (recommended for interoperability), do this::
+
+  modprobe g_serial
+
+To load it as a vendor specific bulk in/out device, do this::
+
+  modprobe g_serial use_acm=0
+
+This will also automatically load the underlying gadget peripheral
+controller driver.  This must be done each time you reboot the gadget
+side Linux system.  You can add this to the start up scripts, if
+desired.
+
+Your system should use mdev (from busybox) or udev to make the
+device nodes.  After this gadget driver has been set up you should
+then see a /dev/ttyGS0 node::
+
+  # ls -l /dev/ttyGS0 | cat
+  crw-rw----    1 root     root     253,   0 May  8 14:10 /dev/ttyGS0
+  #
+
+Note that the major number (253, above) is system-specific.  If
+you need to create /dev nodes by hand, the right numbers to use
+will be in the /sys/class/tty/ttyGS0/dev file.
+
+When you link this gadget driver early, perhaps even statically,
+you may want to set up an /etc/inittab entry to run "getty" on it.
+The /dev/ttyGS0 line should work like most any other serial port.
+
+
+If gadget serial is loaded as an ACM device you will want to use
+either the Windows or Linux ACM driver on the host side.  If gadget
+serial is loaded as a bulk in/out device, you will want to use the
+Linux generic serial driver on the host side.  Follow the appropriate
+instructions below to install the host side driver.
+
+
+Installing the Windows Host ACM Driver
+--------------------------------------
+To use the Windows ACM driver you must have the "linux-cdc-acm.inf"
+file (provided along this document) which supports all recent versions
+of Windows.
+
+When the gadget serial driver is loaded and the USB device connected
+to the Windows host with a USB cable, Windows should recognize the
+gadget serial device and ask for a driver.  Tell Windows to find the
+driver in the folder that contains the "linux-cdc-acm.inf" file.
+
+For example, on Windows XP, when the gadget serial device is first
+plugged in, the "Found New Hardware Wizard" starts up.  Select
+"Install from a list or specific location (Advanced)", then on the
+next screen select "Include this location in the search" and enter the
+path or browse to the folder containing the "linux-cdc-acm.inf" file.
+Windows will complain that the Gadget Serial driver has not passed
+Windows Logo testing, but select "Continue anyway" and finish the
+driver installation.
+
+On Windows XP, in the "Device Manager" (under "Control Panel",
+"System", "Hardware") expand the "Ports (COM & LPT)" entry and you
+should see "Gadget Serial" listed as the driver for one of the COM
+ports.
+
+To uninstall the Windows XP driver for "Gadget Serial", right click
+on the "Gadget Serial" entry in the "Device Manager" and select
+"Uninstall".
+
+
+Installing the Linux Host ACM Driver
+------------------------------------
+To use the Linux ACM driver you must configure the Linux host side
+kernel for "Support for Host-side USB" and for "USB Modem (CDC ACM)
+support".
+
+Once the gadget serial driver is loaded and the USB device connected
+to the Linux host with a USB cable, the host system should recognize
+the gadget serial device.  For example, the command::
+
+  cat /sys/kernel/debug/usb/devices
+
+should show something like this:::
+
+  T:  Bus=01 Lev=01 Prnt=01 Port=01 Cnt=02 Dev#=  5 Spd=480 MxCh= 0
+  D:  Ver= 2.00 Cls=02(comm.) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
+  P:  Vendor=0525 ProdID=a4a7 Rev= 2.01
+  S:  Manufacturer=Linux 2.6.8.1 with net2280
+  S:  Product=Gadget Serial
+  S:  SerialNumber=0
+  C:* #Ifs= 2 Cfg#= 2 Atr=c0 MxPwr=  2mA
+  I:  If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm
+  E:  Ad=83(I) Atr=03(Int.) MxPS=   8 Ivl=32ms
+  I:  If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm
+  E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+  E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+
+If the host side Linux system is configured properly, the ACM driver
+should be loaded automatically.  The command "lsmod" should show the
+"acm" module is loaded.
+
+
+Installing the Linux Host Generic USB Serial Driver
+---------------------------------------------------
+To use the Linux generic USB serial driver you must configure the
+Linux host side kernel for "Support for Host-side USB", for "USB
+Serial Converter support", and for the "USB Generic Serial Driver".
+
+Once the gadget serial driver is loaded and the USB device connected
+to the Linux host with a USB cable, the host system should recognize
+the gadget serial device.  For example, the command::
+
+  cat /sys/kernel/debug/usb/devices
+
+should show something like this:::
+
+  T:  Bus=01 Lev=01 Prnt=01 Port=01 Cnt=02 Dev#=  6 Spd=480 MxCh= 0
+  D:  Ver= 2.00 Cls=ff(vend.) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
+  P:  Vendor=0525 ProdID=a4a6 Rev= 2.01
+  S:  Manufacturer=Linux 2.6.8.1 with net2280
+  S:  Product=Gadget Serial
+  S:  SerialNumber=0
+  C:* #Ifs= 1 Cfg#= 1 Atr=c0 MxPwr=  2mA
+  I:  If#= 0 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=serial
+  E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+  E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+
+You must load the usbserial driver and explicitly set its parameters
+to configure it to recognize the gadget serial device, like this::
+
+  echo 0x0525 0xA4A6 >/sys/bus/usb-serial/drivers/generic/new_id
+
+The legacy way is to use module parameters::
+
+  modprobe usbserial vendor=0x0525 product=0xA4A6
+
+If everything is working, usbserial will print a message in the
+system log saying something like "Gadget Serial converter now
+attached to ttyUSB0".
+
+
+Testing with Minicom or HyperTerminal
+-------------------------------------
+Once the gadget serial driver and the host driver are both installed,
+and a USB cable connects the gadget device to the host, you should
+be able to communicate over USB between the gadget and host systems.
+You can use minicom or HyperTerminal to try this out.
+
+On the gadget side run "minicom -s" to configure a new minicom
+session.  Under "Serial port setup" set "/dev/ttygserial" as the
+"Serial Device".  Set baud rate, data bits, parity, and stop bits,
+to 9600, 8, none, and 1--these settings mostly do not matter.
+Under "Modem and dialing" erase all the modem and dialing strings.
+
+On a Linux host running the ACM driver, configure minicom similarly
+but use "/dev/ttyACM0" as the "Serial Device".  (If you have other
+ACM devices connected, change the device name appropriately.)
+
+On a Linux host running the USB generic serial driver, configure
+minicom similarly, but use "/dev/ttyUSB0" as the "Serial Device".
+(If you have other USB serial devices connected, change the device
+name appropriately.)
+
+On a Windows host configure a new HyperTerminal session to use the
+COM port assigned to Gadget Serial.  The "Port Settings" will be
+set automatically when HyperTerminal connects to the gadget serial
+device, so you can leave them set to the default values--these
+settings mostly do not matter.
+
+With minicom configured and running on the gadget side and with
+minicom or HyperTerminal configured and running on the host side,
+you should be able to send data back and forth between the gadget
+side and host side systems.  Anything you type on the terminal
+window on the gadget side should appear in the terminal window on
+the host side and vice versa.
diff --git a/Documentation/usb/gadget_serial.txt b/Documentation/usb/gadget_serial.txt
deleted file mode 100644 (file)
index dce8bc1..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-===============================
-Linux Gadget Serial Driver v2.0
-===============================
-
-11/20/2004
-
-(updated 8-May-2008 for v2.3)
-
-
-License and Disclaimer
-----------------------
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of
-the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public
-License along with this program; if not, write to the Free
-Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
-MA 02111-1307 USA.
-
-This document and the gadget serial driver itself are
-Copyright (C) 2004 by Al Borchers (alborchers@steinerpoint.com).
-
-If you have questions, problems, or suggestions for this driver
-please contact Al Borchers at alborchers@steinerpoint.com.
-
-
-Prerequisites
--------------
-Versions of the gadget serial driver are available for the
-2.4 Linux kernels, but this document assumes you are using
-version 2.3 or later of the gadget serial driver in a 2.6
-Linux kernel.
-
-This document assumes that you are familiar with Linux and
-Windows and know how to configure and build Linux kernels, run
-standard utilities, use minicom and HyperTerminal, and work with
-USB and serial devices.  It also assumes you configure the Linux
-gadget and usb drivers as modules.
-
-With version 2.3 of the driver, major and minor device nodes are
-no longer statically defined.  Your Linux based system should mount
-sysfs in /sys, and use "mdev" (in Busybox) or "udev" to make the
-/dev nodes matching the sysfs /sys/class/tty files.
-
-
-
-Overview
---------
-The gadget serial driver is a Linux USB gadget driver, a USB device
-side driver.  It runs on a Linux system that has USB device side
-hardware; for example, a PDA, an embedded Linux system, or a PC
-with a USB development card.
-
-The gadget serial driver talks over USB to either a CDC ACM driver
-or a generic USB serial driver running on a host PC::
-
-   Host
-   --------------------------------------
-  | Host-Side   CDC ACM       USB Host   |
-  | Operating |   or        | Controller |   USB
-  | System    | Generic USB | Driver     |--------
-  | (Linux or | Serial      | and        |        |
-  | Windows)    Driver        USB Stack  |        |
-   --------------------------------------         |
-                                                  |
-                                                  |
-                                                  |
-   Gadget                                         |
-   --------------------------------------         |
-  | Gadget                   USB Periph. |        |
-  | Device-Side |  Gadget  | Controller  |        |
-  | Linux       |  Serial  | Driver      |--------
-  | Operating   |  Driver  | and         |
-  | System                   USB Stack   |
-   --------------------------------------
-
-On the device-side Linux system, the gadget serial driver looks
-like a serial device.
-
-On the host-side system, the gadget serial device looks like a
-CDC ACM compliant class device or a simple vendor specific device
-with bulk in and bulk out endpoints, and it is treated similarly
-to other serial devices.
-
-The host side driver can potentially be any ACM compliant driver
-or any driver that can talk to a device with a simple bulk in/out
-interface.  Gadget serial has been tested with the Linux ACM driver,
-the Windows usbser.sys ACM driver, and the Linux USB generic serial
-driver.
-
-With the gadget serial driver and the host side ACM or generic
-serial driver running, you should be able to communicate between
-the host and the gadget side systems as if they were connected by a
-serial cable.
-
-The gadget serial driver only provides simple unreliable data
-communication.  It does not yet handle flow control or many other
-features of normal serial devices.
-
-
-Installing the Gadget Serial Driver
------------------------------------
-To use the gadget serial driver you must configure the Linux gadget
-side kernel for "Support for USB Gadgets", for a "USB Peripheral
-Controller" (for example, net2280), and for the "Serial Gadget"
-driver.  All this are listed under "USB Gadget Support" when
-configuring the kernel.  Then rebuild and install the kernel or
-modules.
-
-Then you must load the gadget serial driver.  To load it as an
-ACM device (recommended for interoperability), do this::
-
-  modprobe g_serial
-
-To load it as a vendor specific bulk in/out device, do this::
-
-  modprobe g_serial use_acm=0
-
-This will also automatically load the underlying gadget peripheral
-controller driver.  This must be done each time you reboot the gadget
-side Linux system.  You can add this to the start up scripts, if
-desired.
-
-Your system should use mdev (from busybox) or udev to make the
-device nodes.  After this gadget driver has been set up you should
-then see a /dev/ttyGS0 node::
-
-  # ls -l /dev/ttyGS0 | cat
-  crw-rw----    1 root     root     253,   0 May  8 14:10 /dev/ttyGS0
-  #
-
-Note that the major number (253, above) is system-specific.  If
-you need to create /dev nodes by hand, the right numbers to use
-will be in the /sys/class/tty/ttyGS0/dev file.
-
-When you link this gadget driver early, perhaps even statically,
-you may want to set up an /etc/inittab entry to run "getty" on it.
-The /dev/ttyGS0 line should work like most any other serial port.
-
-
-If gadget serial is loaded as an ACM device you will want to use
-either the Windows or Linux ACM driver on the host side.  If gadget
-serial is loaded as a bulk in/out device, you will want to use the
-Linux generic serial driver on the host side.  Follow the appropriate
-instructions below to install the host side driver.
-
-
-Installing the Windows Host ACM Driver
---------------------------------------
-To use the Windows ACM driver you must have the "linux-cdc-acm.inf"
-file (provided along this document) which supports all recent versions
-of Windows.
-
-When the gadget serial driver is loaded and the USB device connected
-to the Windows host with a USB cable, Windows should recognize the
-gadget serial device and ask for a driver.  Tell Windows to find the
-driver in the folder that contains the "linux-cdc-acm.inf" file.
-
-For example, on Windows XP, when the gadget serial device is first
-plugged in, the "Found New Hardware Wizard" starts up.  Select
-"Install from a list or specific location (Advanced)", then on the
-next screen select "Include this location in the search" and enter the
-path or browse to the folder containing the "linux-cdc-acm.inf" file.
-Windows will complain that the Gadget Serial driver has not passed
-Windows Logo testing, but select "Continue anyway" and finish the
-driver installation.
-
-On Windows XP, in the "Device Manager" (under "Control Panel",
-"System", "Hardware") expand the "Ports (COM & LPT)" entry and you
-should see "Gadget Serial" listed as the driver for one of the COM
-ports.
-
-To uninstall the Windows XP driver for "Gadget Serial", right click
-on the "Gadget Serial" entry in the "Device Manager" and select
-"Uninstall".
-
-
-Installing the Linux Host ACM Driver
-------------------------------------
-To use the Linux ACM driver you must configure the Linux host side
-kernel for "Support for Host-side USB" and for "USB Modem (CDC ACM)
-support".
-
-Once the gadget serial driver is loaded and the USB device connected
-to the Linux host with a USB cable, the host system should recognize
-the gadget serial device.  For example, the command::
-
-  cat /sys/kernel/debug/usb/devices
-
-should show something like this:::
-
-  T:  Bus=01 Lev=01 Prnt=01 Port=01 Cnt=02 Dev#=  5 Spd=480 MxCh= 0
-  D:  Ver= 2.00 Cls=02(comm.) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
-  P:  Vendor=0525 ProdID=a4a7 Rev= 2.01
-  S:  Manufacturer=Linux 2.6.8.1 with net2280
-  S:  Product=Gadget Serial
-  S:  SerialNumber=0
-  C:* #Ifs= 2 Cfg#= 2 Atr=c0 MxPwr=  2mA
-  I:  If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm
-  E:  Ad=83(I) Atr=03(Int.) MxPS=   8 Ivl=32ms
-  I:  If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm
-  E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
-  E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
-
-If the host side Linux system is configured properly, the ACM driver
-should be loaded automatically.  The command "lsmod" should show the
-"acm" module is loaded.
-
-
-Installing the Linux Host Generic USB Serial Driver
----------------------------------------------------
-To use the Linux generic USB serial driver you must configure the
-Linux host side kernel for "Support for Host-side USB", for "USB
-Serial Converter support", and for the "USB Generic Serial Driver".
-
-Once the gadget serial driver is loaded and the USB device connected
-to the Linux host with a USB cable, the host system should recognize
-the gadget serial device.  For example, the command::
-
-  cat /sys/kernel/debug/usb/devices
-
-should show something like this:::
-
-  T:  Bus=01 Lev=01 Prnt=01 Port=01 Cnt=02 Dev#=  6 Spd=480 MxCh= 0
-  D:  Ver= 2.00 Cls=ff(vend.) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
-  P:  Vendor=0525 ProdID=a4a6 Rev= 2.01
-  S:  Manufacturer=Linux 2.6.8.1 with net2280
-  S:  Product=Gadget Serial
-  S:  SerialNumber=0
-  C:* #Ifs= 1 Cfg#= 1 Atr=c0 MxPwr=  2mA
-  I:  If#= 0 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=serial
-  E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
-  E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
-
-You must load the usbserial driver and explicitly set its parameters
-to configure it to recognize the gadget serial device, like this::
-
-  echo 0x0525 0xA4A6 >/sys/bus/usb-serial/drivers/generic/new_id
-
-The legacy way is to use module parameters::
-
-  modprobe usbserial vendor=0x0525 product=0xA4A6
-
-If everything is working, usbserial will print a message in the
-system log saying something like "Gadget Serial converter now
-attached to ttyUSB0".
-
-
-Testing with Minicom or HyperTerminal
--------------------------------------
-Once the gadget serial driver and the host driver are both installed,
-and a USB cable connects the gadget device to the host, you should
-be able to communicate over USB between the gadget and host systems.
-You can use minicom or HyperTerminal to try this out.
-
-On the gadget side run "minicom -s" to configure a new minicom
-session.  Under "Serial port setup" set "/dev/ttygserial" as the
-"Serial Device".  Set baud rate, data bits, parity, and stop bits,
-to 9600, 8, none, and 1--these settings mostly do not matter.
-Under "Modem and dialing" erase all the modem and dialing strings.
-
-On a Linux host running the ACM driver, configure minicom similarly
-but use "/dev/ttyACM0" as the "Serial Device".  (If you have other
-ACM devices connected, change the device name appropriately.)
-
-On a Linux host running the USB generic serial driver, configure
-minicom similarly, but use "/dev/ttyUSB0" as the "Serial Device".
-(If you have other USB serial devices connected, change the device
-name appropriately.)
-
-On a Windows host configure a new HyperTerminal session to use the
-COM port assigned to Gadget Serial.  The "Port Settings" will be
-set automatically when HyperTerminal connects to the gadget serial
-device, so you can leave them set to the default values--these
-settings mostly do not matter.
-
-With minicom configured and running on the gadget side and with
-minicom or HyperTerminal configured and running on the host side,
-you should be able to send data back and forth between the gadget
-side and host side systems.  Anything you type on the terminal
-window on the gadget side should appear in the terminal window on
-the host side and vice versa.
diff --git a/Documentation/usb/index.rst b/Documentation/usb/index.rst
new file mode 100644 (file)
index 0000000..e55386a
--- /dev/null
@@ -0,0 +1,39 @@
+===========
+USB support
+===========
+
+.. toctree::
+    :maxdepth: 1
+
+    acm
+    authorization
+    chipidea
+    dwc3
+    ehci
+    functionfs
+    gadget_configfs
+    gadget_hid
+    gadget_multi
+    gadget_printer
+    gadget_serial
+    gadget-testing
+    iuu_phoenix
+    mass-storage
+    misc_usbsevseg
+    mtouchusb
+    ohci
+    rio
+    usbip_protocol
+    usbmon
+    usb-serial
+    wusb-design-overview
+
+    usb-help
+    text_files
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
diff --git a/Documentation/usb/iuu_phoenix.rst b/Documentation/usb/iuu_phoenix.rst
new file mode 100644 (file)
index 0000000..b762687
--- /dev/null
@@ -0,0 +1,94 @@
+=============================
+Infinity Usb Unlimited Readme
+=============================
+
+Hi all,
+
+
+This module provide a serial interface to use your
+IUU unit in phoenix mode. Loading this module will
+bring a ttyUSB[0-x] interface. This driver must be
+used by your favorite application to pilot the IUU
+
+This driver is still in beta stage, so bugs can
+occur and your system may freeze. As far I now,
+I never had any problem with it, but I'm not a real
+guru, so don't blame me if your system is unstable
+
+You can plug more than one IUU. Every unit will
+have his own device file(/dev/ttyUSB0,/dev/ttyUSB1,...)
+
+
+
+How to tune the reader speed?
+=============================
+
+ A few parameters can be used at load time
+ To use parameters, just unload the module if it is
+ already loaded and use modprobe iuu_phoenix param=value.
+ In case of prebuilt module, use the command
+ insmod iuu_phoenix param=value.
+
+ Example::
+
+       modprobe iuu_phoenix clockmode=3
+
+ The parameters are:
+
+clockmode:
+       1=3Mhz579,2=3Mhz680,3=6Mhz (int)
+boost:
+       overclock boost percent 100 to 500 (int)
+cdmode:
+       Card detect mode
+       0=none, 1=CD, 2=!CD, 3=DSR, 4=!DSR, 5=CTS, 6=!CTS, 7=RING, 8=!RING (int)
+xmas:
+       xmas color enabled or not (bool)
+debug:
+       Debug enabled or not (bool)
+
+-  clockmode will provide 3 different base settings commonly adopted by
+   different software:
+
+       1. 3Mhz579
+       2. 3Mhz680
+       3. 6Mhz
+
+-  boost provide a way to overclock the reader ( my favorite :-)  )
+   For example to have best performance than a simple clockmode=3, try this::
+
+      modprobe boost=195
+
+   This will put the reader in a base of 3Mhz579 but boosted a 195 % !
+   the real clock will be now : 6979050 Hz ( 6Mhz979 ) and will increase
+   the speed to a score 10 to 20% better than the simple clockmode=3 !!!
+
+
+-  cdmode permit to setup the signal used to inform the userland ( ioctl answer )
+   if the card is present or not. Eight signals are possible.
+
+-  xmas is completely useless except for your eyes. This is one of my friend who was
+   so sad to have a nice device like the iuu without seeing all color range available.
+   So I have added this option to permit him to see a lot of color ( each activity change the color
+   and the frequency randomly )
+
+-  debug will produce a lot of debugging messages...
+
+
+Last notes
+==========
+
+ Don't worry about the serial settings, the serial emulation
+ is an abstraction, so use any speed or parity setting will
+ work. ( This will not change anything ).Later I will perhaps
+ use this settings to deduce de boost but is that feature
+ really necessary ?
+ The autodetect feature used is the serial CD. If that doesn't
+ work for your software, disable detection mechanism in it.
+
+
+ Have fun !
+
+ Alain Degreffe
+
+ eczema(at)ecze.com
diff --git a/Documentation/usb/iuu_phoenix.txt b/Documentation/usb/iuu_phoenix.txt
deleted file mode 100644 (file)
index b762687..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-=============================
-Infinity Usb Unlimited Readme
-=============================
-
-Hi all,
-
-
-This module provide a serial interface to use your
-IUU unit in phoenix mode. Loading this module will
-bring a ttyUSB[0-x] interface. This driver must be
-used by your favorite application to pilot the IUU
-
-This driver is still in beta stage, so bugs can
-occur and your system may freeze. As far I now,
-I never had any problem with it, but I'm not a real
-guru, so don't blame me if your system is unstable
-
-You can plug more than one IUU. Every unit will
-have his own device file(/dev/ttyUSB0,/dev/ttyUSB1,...)
-
-
-
-How to tune the reader speed?
-=============================
-
- A few parameters can be used at load time
- To use parameters, just unload the module if it is
- already loaded and use modprobe iuu_phoenix param=value.
- In case of prebuilt module, use the command
- insmod iuu_phoenix param=value.
-
- Example::
-
-       modprobe iuu_phoenix clockmode=3
-
- The parameters are:
-
-clockmode:
-       1=3Mhz579,2=3Mhz680,3=6Mhz (int)
-boost:
-       overclock boost percent 100 to 500 (int)
-cdmode:
-       Card detect mode
-       0=none, 1=CD, 2=!CD, 3=DSR, 4=!DSR, 5=CTS, 6=!CTS, 7=RING, 8=!RING (int)
-xmas:
-       xmas color enabled or not (bool)
-debug:
-       Debug enabled or not (bool)
-
--  clockmode will provide 3 different base settings commonly adopted by
-   different software:
-
-       1. 3Mhz579
-       2. 3Mhz680
-       3. 6Mhz
-
--  boost provide a way to overclock the reader ( my favorite :-)  )
-   For example to have best performance than a simple clockmode=3, try this::
-
-      modprobe boost=195
-
-   This will put the reader in a base of 3Mhz579 but boosted a 195 % !
-   the real clock will be now : 6979050 Hz ( 6Mhz979 ) and will increase
-   the speed to a score 10 to 20% better than the simple clockmode=3 !!!
-
-
--  cdmode permit to setup the signal used to inform the userland ( ioctl answer )
-   if the card is present or not. Eight signals are possible.
-
--  xmas is completely useless except for your eyes. This is one of my friend who was
-   so sad to have a nice device like the iuu without seeing all color range available.
-   So I have added this option to permit him to see a lot of color ( each activity change the color
-   and the frequency randomly )
-
--  debug will produce a lot of debugging messages...
-
-
-Last notes
-==========
-
- Don't worry about the serial settings, the serial emulation
- is an abstraction, so use any speed or parity setting will
- work. ( This will not change anything ).Later I will perhaps
- use this settings to deduce de boost but is that feature
- really necessary ?
- The autodetect feature used is the serial CD. If that doesn't
- work for your software, disable detection mechanism in it.
-
-
- Have fun !
-
- Alain Degreffe
-
- eczema(at)ecze.com
diff --git a/Documentation/usb/mass-storage.rst b/Documentation/usb/mass-storage.rst
new file mode 100644 (file)
index 0000000..d181b47
--- /dev/null
@@ -0,0 +1,234 @@
+=========================
+Mass Storage Gadget (MSG)
+=========================
+
+Overview
+========
+
+  Mass Storage Gadget (or MSG) acts as a USB Mass Storage device,
+  appearing to the host as a disk or a CD-ROM drive.  It supports
+  multiple logical units (LUNs).  Backing storage for each LUN is
+  provided by a regular file or a block device, access can be limited
+  to read-only, and gadget can indicate that it is removable and/or
+  CD-ROM (the latter implies read-only access).
+
+  Its requirements are modest; only a bulk-in and a bulk-out endpoint
+  are needed.  The memory requirement amounts to two 16K buffers.
+  Support is included for full-speed, high-speed and SuperSpeed
+  operation.
+
+  Note that the driver is slightly non-portable in that it assumes
+  a single memory/DMA buffer will be usable for bulk-in and bulk-out
+  endpoints.  With most device controllers this is not an issue, but
+  there may be some with hardware restrictions that prevent a buffer
+  from being used by more than one endpoint.
+
+  This document describes how to use the gadget from user space, its
+  relation to mass storage function (or MSF) and different gadgets
+  using it, and how it differs from File Storage Gadget (or FSG)
+  (which is no longer included in Linux).  It will talk only briefly
+  about how to use MSF within composite gadgets.
+
+Module parameters
+=================
+
+  The mass storage gadget accepts the following mass storage specific
+  module parameters:
+
+  - file=filename[,filename...]
+
+    This parameter lists paths to files or block devices used for
+    backing storage for each logical unit.  There may be at most
+    FSG_MAX_LUNS (8) LUNs set.  If more files are specified, they will
+    be silently ignored.  See also “luns” parameter.
+
+    *BEWARE* that if a file is used as a backing storage, it may not
+    be modified by any other process.  This is because the host
+    assumes the data does not change without its knowledge.  It may be
+    read, but (if the logical unit is writable) due to buffering on
+    the host side, the contents are not well defined.
+
+    The size of the logical unit will be rounded down to a full
+    logical block.  The logical block size is 2048 bytes for LUNs
+    simulating CD-ROM, block size of the device if the backing file is
+    a block device, or 512 bytes otherwise.
+
+  - removable=b[,b...]
+
+    This parameter specifies whether each logical unit should be
+    removable.  “b” here is either “y”, “Y” or “1” for true or “n”,
+    “N” or “0” for false.
+
+    If this option is set for a logical unit, gadget will accept an
+    “eject” SCSI request (Start/Stop Unit).  When it is sent, the
+    backing file will be closed to simulate ejection and the logical
+    unit will not be mountable by the host until a new backing file is
+    specified by userspace on the device (see “sysfs entries”
+    section).
+
+    If a logical unit is not removable (the default), a backing file
+    must be specified for it with the “file” parameter as the module
+    is loaded.  The same applies if the module is built in, no
+    exceptions.
+
+    The default value of the flag is false, *HOWEVER* it used to be
+    true.  This has been changed to better match File Storage Gadget
+    and because it seems like a saner default after all.  Thus to
+    maintain compatibility with older kernels, it's best to specify
+    the default values.  Also, if one relied on old default, explicit
+    “n” needs to be specified now.
+
+    Note that “removable” means the logical unit's media can be
+    ejected or removed (as is true for a CD-ROM drive or a card
+    reader).  It does *not* mean that the entire gadget can be
+    unplugged from the host; the proper term for that is
+    “hot-unpluggable”.
+
+  - cdrom=b[,b...]
+
+    This parameter specifies whether each logical unit should simulate
+    CD-ROM.  The default is false.
+
+  - ro=b[,b...]
+
+    This parameter specifies whether each logical unit should be
+    reported as read only.  This will prevent host from modifying the
+    backing files.
+
+    Note that if this flag for given logical unit is false but the
+    backing file could not be opened in read/write mode, the gadget
+    will fall back to read only mode anyway.
+
+    The default value for non-CD-ROM logical units is false; for
+    logical units simulating CD-ROM it is forced to true.
+
+  - nofua=b[,b...]
+
+    This parameter specifies whether FUA flag should be ignored in SCSI
+    Write10 and Write12 commands sent to given logical units.
+
+    MS Windows mounts removable storage in “Removal optimised mode” by
+    default.  All the writes to the media are synchronous, which is
+    achieved by setting the FUA (Force Unit Access) bit in SCSI
+    Write(10,12) commands.  This forces each write to wait until the
+    data has actually been written out and prevents I/O requests
+    aggregation in block layer dramatically decreasing performance.
+
+    Note that this may mean that if the device is powered from USB and
+    the user unplugs the device without unmounting it first (which at
+    least some Windows users do), the data may be lost.
+
+    The default value is false.
+
+  - luns=N
+
+    This parameter specifies number of logical units the gadget will
+    have.  It is limited by FSG_MAX_LUNS (8) and higher value will be
+    capped.
+
+    If this parameter is provided, and the number of files specified
+    in “file” argument is greater then the value of “luns”, all excess
+    files will be ignored.
+
+    If this parameter is not present, the number of logical units will
+    be deduced from the number of files specified in the “file”
+    parameter.  If the file parameter is missing as well, one is
+    assumed.
+
+  - stall=b
+
+    Specifies whether the gadget is allowed to halt bulk endpoints.
+    The default is determined according to the type of USB device
+    controller, but usually true.
+
+  In addition to the above, the gadget also accepts the following
+  parameters defined by the composite framework (they are common to
+  all composite gadgets so just a quick listing):
+
+  - idVendor      -- USB Vendor ID (16 bit integer)
+  - idProduct     -- USB Product ID (16 bit integer)
+  - bcdDevice     -- USB Device version (BCD) (16 bit integer)
+  - iManufacturer -- USB Manufacturer string (string)
+  - iProduct      -- USB Product string (string)
+  - iSerialNumber -- SerialNumber string (sting)
+
+sysfs entries
+=============
+
+  For each logical unit, the gadget creates a directory in the sysfs
+  hierarchy.  Inside of it the following three files are created:
+
+  - file
+
+    When read it returns the path to the backing file for the given
+    logical unit.  If there is no backing file (possible only if the
+    logical unit is removable), the content is empty.
+
+    When written into, it changes the backing file for given logical
+    unit.  This change can be performed even if given logical unit is
+    not specified as removable (but that may look strange to the
+    host).  It may fail, however, if host disallowed medium removal
+    with the Prevent-Allow Medium Removal SCSI command.
+
+  - ro
+
+    Reflects the state of ro flag for the given logical unit.  It can
+    be read any time, and written to when there is no backing file
+    open for given logical unit.
+
+  - nofua
+
+    Reflects the state of nofua flag for given logical unit.  It can
+    be read and written.
+
+  Other then those, as usual, the values of module parameters can be
+  read from /sys/module/g_mass_storage/parameters/* files.
+
+Other gadgets using mass storage function
+=========================================
+
+  The Mass Storage Gadget uses the Mass Storage Function to handle
+  mass storage protocol.  As a composite function, MSF may be used by
+  other gadgets as well (eg. g_multi and acm_ms).
+
+  All of the information in previous sections are valid for other
+  gadgets using MSF, except that support for mass storage related
+  module parameters may be missing, or the parameters may have
+  a prefix.  To figure out whether any of this is true one needs to
+  consult the gadget's documentation or its source code.
+
+  For examples of how to include mass storage function in gadgets, one
+  may take a look at mass_storage.c, acm_ms.c and multi.c (sorted by
+  complexity).
+
+Relation to file storage gadget
+===============================
+
+  The Mass Storage Function and thus the Mass Storage Gadget has been
+  based on the File Storage Gadget.  The difference between the two is
+  that MSG is a composite gadget (ie. uses the composite framework)
+  while file storage gadget was a traditional gadget.  From userspace
+  point of view this distinction does not really matter, but from
+  kernel hacker's point of view, this means that (i) MSG does not
+  duplicate code needed for handling basic USB protocol commands and
+  (ii) MSF can be used in any other composite gadget.
+
+  Because of that, File Storage Gadget has been removed in Linux 3.8.
+  All users need to transition to the Mass Storage Gadget.  The two
+  gadgets behave mostly the same from the outside except:
+
+  1. In FSG the “removable” and “cdrom” module parameters set the flag
+     for all logical units whereas in MSG they accept a list of y/n
+     values for each logical unit.  If one uses only a single logical
+     unit this does not matter, but if there are more, the y/n value
+     needs to be repeated for each logical unit.
+
+  2. FSG's “serial”, “vendor”, “product” and “release” module
+     parameters are handled in MSG by the composite layer's parameters
+     named respectively: “iSerialnumber”, “idVendor”, “idProduct” and
+     “bcdDevice”.
+
+  3. MSG does not support FSG's test mode, thus “transport”,
+     “protocol” and “buflen” FSG's module parameters are not
+     supported.  MSG always uses SCSI protocol with bulk only
+     transport mode and 16 KiB buffers.
diff --git a/Documentation/usb/mass-storage.txt b/Documentation/usb/mass-storage.txt
deleted file mode 100644 (file)
index d181b47..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-=========================
-Mass Storage Gadget (MSG)
-=========================
-
-Overview
-========
-
-  Mass Storage Gadget (or MSG) acts as a USB Mass Storage device,
-  appearing to the host as a disk or a CD-ROM drive.  It supports
-  multiple logical units (LUNs).  Backing storage for each LUN is
-  provided by a regular file or a block device, access can be limited
-  to read-only, and gadget can indicate that it is removable and/or
-  CD-ROM (the latter implies read-only access).
-
-  Its requirements are modest; only a bulk-in and a bulk-out endpoint
-  are needed.  The memory requirement amounts to two 16K buffers.
-  Support is included for full-speed, high-speed and SuperSpeed
-  operation.
-
-  Note that the driver is slightly non-portable in that it assumes
-  a single memory/DMA buffer will be usable for bulk-in and bulk-out
-  endpoints.  With most device controllers this is not an issue, but
-  there may be some with hardware restrictions that prevent a buffer
-  from being used by more than one endpoint.
-
-  This document describes how to use the gadget from user space, its
-  relation to mass storage function (or MSF) and different gadgets
-  using it, and how it differs from File Storage Gadget (or FSG)
-  (which is no longer included in Linux).  It will talk only briefly
-  about how to use MSF within composite gadgets.
-
-Module parameters
-=================
-
-  The mass storage gadget accepts the following mass storage specific
-  module parameters:
-
-  - file=filename[,filename...]
-
-    This parameter lists paths to files or block devices used for
-    backing storage for each logical unit.  There may be at most
-    FSG_MAX_LUNS (8) LUNs set.  If more files are specified, they will
-    be silently ignored.  See also “luns” parameter.
-
-    *BEWARE* that if a file is used as a backing storage, it may not
-    be modified by any other process.  This is because the host
-    assumes the data does not change without its knowledge.  It may be
-    read, but (if the logical unit is writable) due to buffering on
-    the host side, the contents are not well defined.
-
-    The size of the logical unit will be rounded down to a full
-    logical block.  The logical block size is 2048 bytes for LUNs
-    simulating CD-ROM, block size of the device if the backing file is
-    a block device, or 512 bytes otherwise.
-
-  - removable=b[,b...]
-
-    This parameter specifies whether each logical unit should be
-    removable.  “b” here is either “y”, “Y” or “1” for true or “n”,
-    “N” or “0” for false.
-
-    If this option is set for a logical unit, gadget will accept an
-    “eject” SCSI request (Start/Stop Unit).  When it is sent, the
-    backing file will be closed to simulate ejection and the logical
-    unit will not be mountable by the host until a new backing file is
-    specified by userspace on the device (see “sysfs entries”
-    section).
-
-    If a logical unit is not removable (the default), a backing file
-    must be specified for it with the “file” parameter as the module
-    is loaded.  The same applies if the module is built in, no
-    exceptions.
-
-    The default value of the flag is false, *HOWEVER* it used to be
-    true.  This has been changed to better match File Storage Gadget
-    and because it seems like a saner default after all.  Thus to
-    maintain compatibility with older kernels, it's best to specify
-    the default values.  Also, if one relied on old default, explicit
-    “n” needs to be specified now.
-
-    Note that “removable” means the logical unit's media can be
-    ejected or removed (as is true for a CD-ROM drive or a card
-    reader).  It does *not* mean that the entire gadget can be
-    unplugged from the host; the proper term for that is
-    “hot-unpluggable”.
-
-  - cdrom=b[,b...]
-
-    This parameter specifies whether each logical unit should simulate
-    CD-ROM.  The default is false.
-
-  - ro=b[,b...]
-
-    This parameter specifies whether each logical unit should be
-    reported as read only.  This will prevent host from modifying the
-    backing files.
-
-    Note that if this flag for given logical unit is false but the
-    backing file could not be opened in read/write mode, the gadget
-    will fall back to read only mode anyway.
-
-    The default value for non-CD-ROM logical units is false; for
-    logical units simulating CD-ROM it is forced to true.
-
-  - nofua=b[,b...]
-
-    This parameter specifies whether FUA flag should be ignored in SCSI
-    Write10 and Write12 commands sent to given logical units.
-
-    MS Windows mounts removable storage in “Removal optimised mode” by
-    default.  All the writes to the media are synchronous, which is
-    achieved by setting the FUA (Force Unit Access) bit in SCSI
-    Write(10,12) commands.  This forces each write to wait until the
-    data has actually been written out and prevents I/O requests
-    aggregation in block layer dramatically decreasing performance.
-
-    Note that this may mean that if the device is powered from USB and
-    the user unplugs the device without unmounting it first (which at
-    least some Windows users do), the data may be lost.
-
-    The default value is false.
-
-  - luns=N
-
-    This parameter specifies number of logical units the gadget will
-    have.  It is limited by FSG_MAX_LUNS (8) and higher value will be
-    capped.
-
-    If this parameter is provided, and the number of files specified
-    in “file” argument is greater then the value of “luns”, all excess
-    files will be ignored.
-
-    If this parameter is not present, the number of logical units will
-    be deduced from the number of files specified in the “file”
-    parameter.  If the file parameter is missing as well, one is
-    assumed.
-
-  - stall=b
-
-    Specifies whether the gadget is allowed to halt bulk endpoints.
-    The default is determined according to the type of USB device
-    controller, but usually true.
-
-  In addition to the above, the gadget also accepts the following
-  parameters defined by the composite framework (they are common to
-  all composite gadgets so just a quick listing):
-
-  - idVendor      -- USB Vendor ID (16 bit integer)
-  - idProduct     -- USB Product ID (16 bit integer)
-  - bcdDevice     -- USB Device version (BCD) (16 bit integer)
-  - iManufacturer -- USB Manufacturer string (string)
-  - iProduct      -- USB Product string (string)
-  - iSerialNumber -- SerialNumber string (sting)
-
-sysfs entries
-=============
-
-  For each logical unit, the gadget creates a directory in the sysfs
-  hierarchy.  Inside of it the following three files are created:
-
-  - file
-
-    When read it returns the path to the backing file for the given
-    logical unit.  If there is no backing file (possible only if the
-    logical unit is removable), the content is empty.
-
-    When written into, it changes the backing file for given logical
-    unit.  This change can be performed even if given logical unit is
-    not specified as removable (but that may look strange to the
-    host).  It may fail, however, if host disallowed medium removal
-    with the Prevent-Allow Medium Removal SCSI command.
-
-  - ro
-
-    Reflects the state of ro flag for the given logical unit.  It can
-    be read any time, and written to when there is no backing file
-    open for given logical unit.
-
-  - nofua
-
-    Reflects the state of nofua flag for given logical unit.  It can
-    be read and written.
-
-  Other then those, as usual, the values of module parameters can be
-  read from /sys/module/g_mass_storage/parameters/* files.
-
-Other gadgets using mass storage function
-=========================================
-
-  The Mass Storage Gadget uses the Mass Storage Function to handle
-  mass storage protocol.  As a composite function, MSF may be used by
-  other gadgets as well (eg. g_multi and acm_ms).
-
-  All of the information in previous sections are valid for other
-  gadgets using MSF, except that support for mass storage related
-  module parameters may be missing, or the parameters may have
-  a prefix.  To figure out whether any of this is true one needs to
-  consult the gadget's documentation or its source code.
-
-  For examples of how to include mass storage function in gadgets, one
-  may take a look at mass_storage.c, acm_ms.c and multi.c (sorted by
-  complexity).
-
-Relation to file storage gadget
-===============================
-
-  The Mass Storage Function and thus the Mass Storage Gadget has been
-  based on the File Storage Gadget.  The difference between the two is
-  that MSG is a composite gadget (ie. uses the composite framework)
-  while file storage gadget was a traditional gadget.  From userspace
-  point of view this distinction does not really matter, but from
-  kernel hacker's point of view, this means that (i) MSG does not
-  duplicate code needed for handling basic USB protocol commands and
-  (ii) MSF can be used in any other composite gadget.
-
-  Because of that, File Storage Gadget has been removed in Linux 3.8.
-  All users need to transition to the Mass Storage Gadget.  The two
-  gadgets behave mostly the same from the outside except:
-
-  1. In FSG the “removable” and “cdrom” module parameters set the flag
-     for all logical units whereas in MSG they accept a list of y/n
-     values for each logical unit.  If one uses only a single logical
-     unit this does not matter, but if there are more, the y/n value
-     needs to be repeated for each logical unit.
-
-  2. FSG's “serial”, “vendor”, “product” and “release” module
-     parameters are handled in MSG by the composite layer's parameters
-     named respectively: “iSerialnumber”, “idVendor”, “idProduct” and
-     “bcdDevice”.
-
-  3. MSG does not support FSG's test mode, thus “transport”,
-     “protocol” and “buflen” FSG's module parameters are not
-     supported.  MSG always uses SCSI protocol with bulk only
-     transport mode and 16 KiB buffers.
diff --git a/Documentation/usb/misc_usbsevseg.rst b/Documentation/usb/misc_usbsevseg.rst
new file mode 100644 (file)
index 0000000..6274aee
--- /dev/null
@@ -0,0 +1,51 @@
+=============================
+USB 7-Segment Numeric Display
+=============================
+
+Manufactured by Delcom Engineering
+
+Device Information
+------------------
+USB VENDOR_ID  0x0fc5
+USB PRODUCT_ID 0x1227
+Both the 6 character and 8 character displays have PRODUCT_ID,
+and according to Delcom Engineering no queryable information
+can be obtained from the device to tell them apart.
+
+Device Modes
+------------
+By default, the driver assumes the display is only 6 characters
+The mode for 6 characters is:
+
+       MSB 0x06; LSB 0x3f
+
+For the 8 character display:
+
+       MSB 0x08; LSB 0xff
+
+The device can accept "text" either in raw, hex, or ascii textmode.
+raw controls each segment manually,
+hex expects a value between 0-15 per character,
+ascii expects a value between '0'-'9' and 'A'-'F'.
+The default is ascii.
+
+Device Operation
+----------------
+1.     Turn on the device:
+       echo 1 > /sys/bus/usb/.../powered
+2.     Set the device's mode:
+       echo $mode_msb > /sys/bus/usb/.../mode_msb
+       echo $mode_lsb > /sys/bus/usb/.../mode_lsb
+3.     Set the textmode:
+       echo $textmode > /sys/bus/usb/.../textmode
+4.     set the text (for example):
+       echo "123ABC" > /sys/bus/usb/.../text (ascii)
+       echo "A1B2" > /sys/bus/usb/.../text (ascii)
+       echo -ne "\x01\x02\x03" > /sys/bus/usb/.../text (hex)
+5.     Set the decimal places.
+       The device has either 6 or 8 decimal points.
+       to set the nth decimal place calculate 10 ** n
+       and echo it in to /sys/bus/usb/.../decimals
+       To set multiple decimals points sum up each power.
+       For example, to set the 0th and 3rd decimal place
+       echo 1001 > /sys/bus/usb/.../decimals
diff --git a/Documentation/usb/misc_usbsevseg.txt b/Documentation/usb/misc_usbsevseg.txt
deleted file mode 100644 (file)
index 6274aee..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-=============================
-USB 7-Segment Numeric Display
-=============================
-
-Manufactured by Delcom Engineering
-
-Device Information
-------------------
-USB VENDOR_ID  0x0fc5
-USB PRODUCT_ID 0x1227
-Both the 6 character and 8 character displays have PRODUCT_ID,
-and according to Delcom Engineering no queryable information
-can be obtained from the device to tell them apart.
-
-Device Modes
-------------
-By default, the driver assumes the display is only 6 characters
-The mode for 6 characters is:
-
-       MSB 0x06; LSB 0x3f
-
-For the 8 character display:
-
-       MSB 0x08; LSB 0xff
-
-The device can accept "text" either in raw, hex, or ascii textmode.
-raw controls each segment manually,
-hex expects a value between 0-15 per character,
-ascii expects a value between '0'-'9' and 'A'-'F'.
-The default is ascii.
-
-Device Operation
-----------------
-1.     Turn on the device:
-       echo 1 > /sys/bus/usb/.../powered
-2.     Set the device's mode:
-       echo $mode_msb > /sys/bus/usb/.../mode_msb
-       echo $mode_lsb > /sys/bus/usb/.../mode_lsb
-3.     Set the textmode:
-       echo $textmode > /sys/bus/usb/.../textmode
-4.     set the text (for example):
-       echo "123ABC" > /sys/bus/usb/.../text (ascii)
-       echo "A1B2" > /sys/bus/usb/.../text (ascii)
-       echo -ne "\x01\x02\x03" > /sys/bus/usb/.../text (hex)
-5.     Set the decimal places.
-       The device has either 6 or 8 decimal points.
-       to set the nth decimal place calculate 10 ** n
-       and echo it in to /sys/bus/usb/.../decimals
-       To set multiple decimals points sum up each power.
-       For example, to set the 0th and 3rd decimal place
-       echo 1001 > /sys/bus/usb/.../decimals
diff --git a/Documentation/usb/mtouchusb.rst b/Documentation/usb/mtouchusb.rst
new file mode 100644 (file)
index 0000000..d1111b7
--- /dev/null
@@ -0,0 +1,84 @@
+================
+mtouchusb driver
+================
+
+Changes
+=======
+
+- 0.3 - Created based off of scanner & INSTALL from the original touchscreen
+  driver on freecode (http://freecode.com/projects/3mtouchscreendriver)
+- Amended for linux-2.4.18, then 2.4.19
+
+- 0.5 - Complete rewrite using Linux Input in 2.6.3
+  Unfortunately no calibration support at this time
+
+- 1.4 - Multiple changes to support the EXII 5000UC and house cleaning
+  Changed reset from standard USB dev reset to vendor reset
+  Changed data sent to host from compensated to raw coordinates
+  Eliminated vendor/product module params
+  Performed multiple successful tests with an EXII-5010UC
+
+Supported Hardware
+==================
+
+::
+
+        All controllers have the Vendor: 0x0596 & Product: 0x0001
+
+
+        Controller Description          Part Number
+        ------------------------------------------------------
+
+        USB Capacitive - Pearl Case     14-205  (Discontinued)
+        USB Capacitive - Black Case     14-124  (Discontinued)
+        USB Capacitive - No Case        14-206  (Discontinued)
+
+        USB Capacitive - Pearl Case     EXII-5010UC
+        USB Capacitive - Black Case     EXII-5030UC
+        USB Capacitive - No Case        EXII-5050UC
+
+Driver Notes
+============
+
+Installation is simple, you only need to add Linux Input, Linux USB, and the
+driver to the kernel.  The driver can also be optionally built as a module.
+
+This driver appears to be one of possible 2 Linux USB Input Touchscreen
+drivers.  Although 3M produces a binary only driver available for
+download, I persist in updating this driver since I would like to use the
+touchscreen for embedded apps using QTEmbedded, DirectFB, etc. So I feel the
+logical choice is to use Linux Input.
+
+Currently there is no way to calibrate the device via this driver.  Even if
+the device could be calibrated, the driver pulls to raw coordinate data from
+the controller.  This means calibration must be performed within the
+userspace.
+
+The controller screen resolution is now 0 to 16384 for both X and Y reporting
+the raw touch data.  This is the same for the old and new capacitive USB
+controllers.
+
+Perhaps at some point an abstract function will be placed into evdev so
+generic functions like calibrations, resets, and vendor information can be
+requested from the userspace (And the drivers would handle the vendor specific
+tasks).
+
+TODO
+====
+
+Implement a control urb again to handle requests to and from the device
+such as calibration, etc once/if it becomes available.
+
+Disclaimer
+==========
+
+I am not a MicroTouch/3M employee, nor have I ever been.  3M does not support
+this driver!  If you want touch drivers only supported within X, please go to:
+
+http://www.3m.com/3MTouchSystems/
+
+Thanks
+======
+
+A huge thank you to 3M Touch Systems for the EXII-5010UC controllers for
+testing!
diff --git a/Documentation/usb/mtouchusb.txt b/Documentation/usb/mtouchusb.txt
deleted file mode 100644 (file)
index d1111b7..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-================
-mtouchusb driver
-================
-
-Changes
-=======
-
-- 0.3 - Created based off of scanner & INSTALL from the original touchscreen
-  driver on freecode (http://freecode.com/projects/3mtouchscreendriver)
-- Amended for linux-2.4.18, then 2.4.19
-
-- 0.5 - Complete rewrite using Linux Input in 2.6.3
-  Unfortunately no calibration support at this time
-
-- 1.4 - Multiple changes to support the EXII 5000UC and house cleaning
-  Changed reset from standard USB dev reset to vendor reset
-  Changed data sent to host from compensated to raw coordinates
-  Eliminated vendor/product module params
-  Performed multiple successful tests with an EXII-5010UC
-
-Supported Hardware
-==================
-
-::
-
-        All controllers have the Vendor: 0x0596 & Product: 0x0001
-
-
-        Controller Description          Part Number
-        ------------------------------------------------------
-
-        USB Capacitive - Pearl Case     14-205  (Discontinued)
-        USB Capacitive - Black Case     14-124  (Discontinued)
-        USB Capacitive - No Case        14-206  (Discontinued)
-
-        USB Capacitive - Pearl Case     EXII-5010UC
-        USB Capacitive - Black Case     EXII-5030UC
-        USB Capacitive - No Case        EXII-5050UC
-
-Driver Notes
-============
-
-Installation is simple, you only need to add Linux Input, Linux USB, and the
-driver to the kernel.  The driver can also be optionally built as a module.
-
-This driver appears to be one of possible 2 Linux USB Input Touchscreen
-drivers.  Although 3M produces a binary only driver available for
-download, I persist in updating this driver since I would like to use the
-touchscreen for embedded apps using QTEmbedded, DirectFB, etc. So I feel the
-logical choice is to use Linux Input.
-
-Currently there is no way to calibrate the device via this driver.  Even if
-the device could be calibrated, the driver pulls to raw coordinate data from
-the controller.  This means calibration must be performed within the
-userspace.
-
-The controller screen resolution is now 0 to 16384 for both X and Y reporting
-the raw touch data.  This is the same for the old and new capacitive USB
-controllers.
-
-Perhaps at some point an abstract function will be placed into evdev so
-generic functions like calibrations, resets, and vendor information can be
-requested from the userspace (And the drivers would handle the vendor specific
-tasks).
-
-TODO
-====
-
-Implement a control urb again to handle requests to and from the device
-such as calibration, etc once/if it becomes available.
-
-Disclaimer
-==========
-
-I am not a MicroTouch/3M employee, nor have I ever been.  3M does not support
-this driver!  If you want touch drivers only supported within X, please go to:
-
-http://www.3m.com/3MTouchSystems/
-
-Thanks
-======
-
-A huge thank you to 3M Touch Systems for the EXII-5010UC controllers for
-testing!
diff --git a/Documentation/usb/ohci.rst b/Documentation/usb/ohci.rst
new file mode 100644 (file)
index 0000000..bb3c497
--- /dev/null
@@ -0,0 +1,35 @@
+====
+OHCI
+====
+
+23-Aug-2002
+
+The "ohci-hcd" driver is a USB Host Controller Driver (HCD) that is derived
+from the "usb-ohci" driver from the 2.4 kernel series.  The "usb-ohci" code
+was written primarily by Roman Weissgaerber <weissg@vienna.at> but with
+contributions from many others (read its copyright/licencing header).
+
+It supports the "Open Host Controller Interface" (OHCI), which standardizes
+hardware register protocols used to talk to USB 1.1 host controllers.  As
+compared to the earlier "Universal Host Controller Interface" (UHCI) from
+Intel, it pushes more intelligence into the hardware.  USB 1.1 controllers
+from vendors other than Intel and VIA generally use OHCI.
+
+Changes since the 2.4 kernel include
+
+       - improved robustness; bugfixes; and less overhead
+       - supports the updated and simplified usbcore APIs
+       - interrupt transfers can be larger, and can be queued
+       - less code, by using the upper level "hcd" framework
+       - supports some non-PCI implementations of OHCI
+       - ... more
+
+The "ohci-hcd" driver handles all USB 1.1 transfer types.  Transfers of all
+types can be queued.  That was also true in "usb-ohci", except for interrupt
+transfers.  Previously, using periods of one frame would risk data loss due
+to overhead in IRQ processing.  When interrupt transfers are queued, those
+risks can be minimized by making sure the hardware always has transfers to
+work on while the OS is getting around to the relevant IRQ processing.
+
+- David Brownell
+  <dbrownell@users.sourceforge.net>
diff --git a/Documentation/usb/ohci.txt b/Documentation/usb/ohci.txt
deleted file mode 100644 (file)
index bb3c497..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-====
-OHCI
-====
-
-23-Aug-2002
-
-The "ohci-hcd" driver is a USB Host Controller Driver (HCD) that is derived
-from the "usb-ohci" driver from the 2.4 kernel series.  The "usb-ohci" code
-was written primarily by Roman Weissgaerber <weissg@vienna.at> but with
-contributions from many others (read its copyright/licencing header).
-
-It supports the "Open Host Controller Interface" (OHCI), which standardizes
-hardware register protocols used to talk to USB 1.1 host controllers.  As
-compared to the earlier "Universal Host Controller Interface" (UHCI) from
-Intel, it pushes more intelligence into the hardware.  USB 1.1 controllers
-from vendors other than Intel and VIA generally use OHCI.
-
-Changes since the 2.4 kernel include
-
-       - improved robustness; bugfixes; and less overhead
-       - supports the updated and simplified usbcore APIs
-       - interrupt transfers can be larger, and can be queued
-       - less code, by using the upper level "hcd" framework
-       - supports some non-PCI implementations of OHCI
-       - ... more
-
-The "ohci-hcd" driver handles all USB 1.1 transfer types.  Transfers of all
-types can be queued.  That was also true in "usb-ohci", except for interrupt
-transfers.  Previously, using periods of one frame would risk data loss due
-to overhead in IRQ processing.  When interrupt transfers are queued, those
-risks can be minimized by making sure the hardware always has transfers to
-work on while the OS is getting around to the relevant IRQ processing.
-
-- David Brownell
-  <dbrownell@users.sourceforge.net>
diff --git a/Documentation/usb/rio.rst b/Documentation/usb/rio.rst
new file mode 100644 (file)
index 0000000..ea73475
--- /dev/null
@@ -0,0 +1,109 @@
+============
+Diamonds Rio
+============
+
+Copyright (C) 1999, 2000 Bruce Tenison
+
+Portions Copyright (C) 1999, 2000 David Nelson
+
+Thanks to David Nelson for guidance and the usage of the scanner.txt
+and scanner.c files to model our driver and this informative file.
+
+Mar. 2, 2000
+
+Changes
+=======
+
+- Initial Revision
+
+
+Overview
+========
+
+This README will address issues regarding how to configure the kernel
+to access a RIO 500 mp3 player.
+Before I explain how to use this to access the Rio500 please be warned:
+
+.. warning::
+
+   Please note that this software is still under development.  The authors
+   are in no way responsible for any damage that may occur, no matter how
+   inconsequential.
+
+It seems that the Rio has a problem when sending .mp3 with low batteries.
+I suggest when the batteries are low and you want to transfer stuff that you
+replace it with a fresh one. In my case, what happened is I lost two 16kb
+blocks (they are no longer usable to store information to it). But I don't
+know if that's normal or not; it could simply be a problem with the flash
+memory.
+
+In an extreme case, I left my Rio playing overnight and the batteries wore
+down to nothing and appear to have corrupted the flash memory. My RIO
+needed to be replaced as a result.  Diamond tech support is aware of the
+problem.  Do NOT allow your batteries to wear down to nothing before
+changing them.  It appears RIO 500 firmware does not handle low battery
+power well at all.
+
+On systems with OHCI controllers, the kernel OHCI code appears to have
+power on problems with some chipsets.  If you are having problems
+connecting to your RIO 500, try turning it on first and then plugging it
+into the USB cable.
+
+Contact Information
+-------------------
+
+   The main page for the project is hosted at sourceforge.net in the following
+   URL: <http://rio500.sourceforge.net>. You can also go to the project's
+   sourceforge home page at: <http://sourceforge.net/projects/rio500/>.
+   There is also a mailing list: rio500-users@lists.sourceforge.net
+
+Authors
+-------
+
+Most of the code was written by Cesar Miquel <miquel@df.uba.ar>. Keith
+Clayton <kclayton@jps.net> is incharge of the PPC port and making sure
+things work there. Bruce Tenison <btenison@dibbs.net> is adding support
+for .fon files and also does testing. The program will mostly sure be
+re-written and Pete Ikusz along with the rest will re-design it. I would
+also like to thank Tri Nguyen <tmn_3022000@hotmail.com> who provided use
+with some important information regarding the communication with the Rio.
+
+Additional Information and userspace tools
+
+       http://rio500.sourceforge.net/
+
+
+Requirements
+============
+
+A host with a USB port running a Linux kernel with RIO 500 support enabled.
+
+The driver is a module called rio500, which should be automatically loaded
+as you plug in your device. If that fails you can manually load it with
+
+  modprobe rio500
+
+Udev should automatically create a device node as soon as plug in your device.
+If that fails, you can manually add a device for the USB rio500::
+
+  mknod /dev/usb/rio500 c 180 64
+
+In that case, set appropriate permissions for /dev/usb/rio500 (don't forget
+about group and world permissions).  Both read and write permissions are
+required for proper operation.
+
+That's it.  The Rio500 Utils at: http://rio500.sourceforge.net should
+be able to access the rio500.
+
+Limits
+======
+
+You can use only a single rio500 device at a time with your computer.
+
+Bugs
+====
+
+If you encounter any problems feel free to drop me an email.
+
+Bruce Tenison
+btenison@dibbs.net
diff --git a/Documentation/usb/rio.txt b/Documentation/usb/rio.txt
deleted file mode 100644 (file)
index ea73475..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-============
-Diamonds Rio
-============
-
-Copyright (C) 1999, 2000 Bruce Tenison
-
-Portions Copyright (C) 1999, 2000 David Nelson
-
-Thanks to David Nelson for guidance and the usage of the scanner.txt
-and scanner.c files to model our driver and this informative file.
-
-Mar. 2, 2000
-
-Changes
-=======
-
-- Initial Revision
-
-
-Overview
-========
-
-This README will address issues regarding how to configure the kernel
-to access a RIO 500 mp3 player.
-Before I explain how to use this to access the Rio500 please be warned:
-
-.. warning::
-
-   Please note that this software is still under development.  The authors
-   are in no way responsible for any damage that may occur, no matter how
-   inconsequential.
-
-It seems that the Rio has a problem when sending .mp3 with low batteries.
-I suggest when the batteries are low and you want to transfer stuff that you
-replace it with a fresh one. In my case, what happened is I lost two 16kb
-blocks (they are no longer usable to store information to it). But I don't
-know if that's normal or not; it could simply be a problem with the flash
-memory.
-
-In an extreme case, I left my Rio playing overnight and the batteries wore
-down to nothing and appear to have corrupted the flash memory. My RIO
-needed to be replaced as a result.  Diamond tech support is aware of the
-problem.  Do NOT allow your batteries to wear down to nothing before
-changing them.  It appears RIO 500 firmware does not handle low battery
-power well at all.
-
-On systems with OHCI controllers, the kernel OHCI code appears to have
-power on problems with some chipsets.  If you are having problems
-connecting to your RIO 500, try turning it on first and then plugging it
-into the USB cable.
-
-Contact Information
--------------------
-
-   The main page for the project is hosted at sourceforge.net in the following
-   URL: <http://rio500.sourceforge.net>. You can also go to the project's
-   sourceforge home page at: <http://sourceforge.net/projects/rio500/>.
-   There is also a mailing list: rio500-users@lists.sourceforge.net
-
-Authors
--------
-
-Most of the code was written by Cesar Miquel <miquel@df.uba.ar>. Keith
-Clayton <kclayton@jps.net> is incharge of the PPC port and making sure
-things work there. Bruce Tenison <btenison@dibbs.net> is adding support
-for .fon files and also does testing. The program will mostly sure be
-re-written and Pete Ikusz along with the rest will re-design it. I would
-also like to thank Tri Nguyen <tmn_3022000@hotmail.com> who provided use
-with some important information regarding the communication with the Rio.
-
-Additional Information and userspace tools
-
-       http://rio500.sourceforge.net/
-
-
-Requirements
-============
-
-A host with a USB port running a Linux kernel with RIO 500 support enabled.
-
-The driver is a module called rio500, which should be automatically loaded
-as you plug in your device. If that fails you can manually load it with
-
-  modprobe rio500
-
-Udev should automatically create a device node as soon as plug in your device.
-If that fails, you can manually add a device for the USB rio500::
-
-  mknod /dev/usb/rio500 c 180 64
-
-In that case, set appropriate permissions for /dev/usb/rio500 (don't forget
-about group and world permissions).  Both read and write permissions are
-required for proper operation.
-
-That's it.  The Rio500 Utils at: http://rio500.sourceforge.net should
-be able to access the rio500.
-
-Limits
-======
-
-You can use only a single rio500 device at a time with your computer.
-
-Bugs
-====
-
-If you encounter any problems feel free to drop me an email.
-
-Bruce Tenison
-btenison@dibbs.net
diff --git a/Documentation/usb/text_files.rst b/Documentation/usb/text_files.rst
new file mode 100644 (file)
index 0000000..6a8d3fc
--- /dev/null
@@ -0,0 +1,29 @@
+Linux CDC ACM inf
+-----------------
+
+.. include:: linux-cdc-acm.inf
+    :literal:
+
+Linux inf
+---------
+
+.. include:: linux.inf
+    :literal:
+
+USB devfs drop permissions source
+---------------------------------
+
+.. literalinclude:: usbdevfs-drop-permissions.c
+    :language: c
+
+WUSB command line script to manipulate auth credentials
+-------------------------------------------------------
+
+.. literalinclude:: wusb-cbaf
+   :language: shell
+
+Credits
+-------
+
+.. include:: CREDITS
+    :literal:
diff --git a/Documentation/usb/usb-help.rst b/Documentation/usb/usb-help.rst
new file mode 100644 (file)
index 0000000..dc23ecd
--- /dev/null
@@ -0,0 +1,17 @@
+==============
+USB references
+==============
+
+2008-Mar-7
+
+For USB help other than the readme files that are located in
+`Documentation/usb/*`, see the following:
+
+- Linux-USB project:  http://www.linux-usb.org
+  mirrors at          http://usb.in.tum.de/linux-usb/
+  and                 http://it.linux-usb.org
+- Linux USB Guide:    http://linux-usb.sourceforge.net
+- Linux-USB device overview (working devices and drivers):
+  http://www.qbik.ch/usb/devices/
+
+The Linux-USB mailing list is at linux-usb@vger.kernel.org
diff --git a/Documentation/usb/usb-help.txt b/Documentation/usb/usb-help.txt
deleted file mode 100644 (file)
index dc23ecd..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-==============
-USB references
-==============
-
-2008-Mar-7
-
-For USB help other than the readme files that are located in
-`Documentation/usb/*`, see the following:
-
-- Linux-USB project:  http://www.linux-usb.org
-  mirrors at          http://usb.in.tum.de/linux-usb/
-  and                 http://it.linux-usb.org
-- Linux USB Guide:    http://linux-usb.sourceforge.net
-- Linux-USB device overview (working devices and drivers):
-  http://www.qbik.ch/usb/devices/
-
-The Linux-USB mailing list is at linux-usb@vger.kernel.org
diff --git a/Documentation/usb/usb-serial.rst b/Documentation/usb/usb-serial.rst
new file mode 100644 (file)
index 0000000..8fa7dbd
--- /dev/null
@@ -0,0 +1,537 @@
+==========
+USB serial
+==========
+
+Introduction
+============
+
+  The USB serial driver currently supports a number of different USB to
+  serial converter products, as well as some devices that use a serial
+  interface from userspace to talk to the device.
+
+  See the individual product section below for specific information about
+  the different devices.
+
+
+Configuration
+=============
+
+  Currently the driver can handle up to 256 different serial interfaces at
+  one time.
+
+    The major number that the driver uses is 188 so to use the driver,
+    create the following nodes::
+
+       mknod /dev/ttyUSB0 c 188 0
+       mknod /dev/ttyUSB1 c 188 1
+       mknod /dev/ttyUSB2 c 188 2
+       mknod /dev/ttyUSB3 c 188 3
+               .
+               .
+               .
+       mknod /dev/ttyUSB254 c 188 254
+       mknod /dev/ttyUSB255 c 188 255
+
+  When the device is connected and recognized by the driver, the driver
+  will print to the system log, which node(s) the device has been bound
+  to.
+
+
+Specific Devices Supported
+==========================
+
+
+ConnectTech WhiteHEAT 4 port converter
+--------------------------------------
+
+  ConnectTech has been very forthcoming with information about their
+  device, including providing a unit to test with.
+
+  The driver is officially supported by Connect Tech Inc.
+  http://www.connecttech.com
+
+  For any questions or problems with this driver, please contact
+  Connect Tech's Support Department at support@connecttech.com
+
+
+HandSpring Visor, Palm USB, and Clié USB driver
+-----------------------------------------------
+
+  This driver works with all HandSpring USB, Palm USB, and Sony Clié USB
+  devices.
+
+  Only when the device tries to connect to the host, will the device show
+  up to the host as a valid USB device. When this happens, the device is
+  properly enumerated, assigned a port, and then communication _should_ be
+  possible. The driver cleans up properly when the device is removed, or
+  the connection is canceled on the device.
+
+  NOTE:
+    This means that in order to talk to the device, the sync button must be
+    pressed BEFORE trying to get any program to communicate to the device.
+    This goes against the current documentation for pilot-xfer and other
+    packages, but is the only way that it will work due to the hardware
+    in the device.
+
+  When the device is connected, try talking to it on the second port
+  (this is usually /dev/ttyUSB1 if you do not have any other usb-serial
+  devices in the system.) The system log should tell you which port is
+  the port to use for the HotSync transfer. The "Generic" port can be used
+  for other device communication, such as a PPP link.
+
+  For some Sony Clié devices, /dev/ttyUSB0 must be used to talk to the
+  device.  This is true for all OS version 3.5 devices, and most devices
+  that have had a flash upgrade to a newer version of the OS.  See the
+  kernel system log for information on which is the correct port to use.
+
+  If after pressing the sync button, nothing shows up in the system log,
+  try resetting the device, first a hot reset, and then a cold reset if
+  necessary.  Some devices need this before they can talk to the USB port
+  properly.
+
+  Devices that are not compiled into the kernel can be specified with module
+  parameters.  e.g. modprobe visor vendor=0x54c product=0x66
+
+  There is a webpage and mailing lists for this portion of the driver at:
+  http://sourceforge.net/projects/usbvisor/
+
+  For any questions or problems with this driver, please contact Greg
+  Kroah-Hartman at greg@kroah.com
+
+
+PocketPC PDA Driver
+-------------------
+
+  This driver can be used to connect to Compaq iPAQ, HP Jornada, Casio EM500
+  and other PDAs running Windows CE 3.0 or PocketPC 2002 using a USB
+  cable/cradle.
+  Most devices supported by ActiveSync are supported out of the box.
+  For others, please use module parameters to specify the product and vendor
+  id. e.g. modprobe ipaq vendor=0x3f0 product=0x1125
+
+  The driver presents a serial interface (usually on /dev/ttyUSB0) over
+  which one may run ppp and establish a TCP/IP link to the PDA. Once this
+  is done, you can transfer files, backup, download email etc. The most
+  significant advantage of using USB is speed - I can get 73 to 113
+  kbytes/sec for download/upload to my iPAQ.
+
+  This driver is only one of a set of components required to utilize
+  the USB connection. Please visit http://synce.sourceforge.net which
+  contains the necessary packages and a simple step-by-step howto.
+
+  Once connected, you can use Win CE programs like ftpView, Pocket Outlook
+  from the PDA and xcerdisp, synce utilities from the Linux side.
+
+  To use Pocket IE, follow the instructions given at
+  http://www.tekguru.co.uk/EM500/usbtonet.htm to achieve the same thing
+  on Win98. Omit the proxy server part; Linux is quite capable of forwarding
+  packets unlike Win98. Another modification is required at least for the
+  iPAQ - disable autosync by going to the Start/Settings/Connections menu
+  and unchecking the "Automatically synchronize ..." box. Go to
+  Start/Programs/Connections, connect the cable and select "usbdial" (or
+  whatever you named your new USB connection). You should finally wind
+  up with a "Connected to usbdial" window with status shown as connected.
+  Now start up PIE and browse away.
+
+  If it doesn't work for some reason, load both the usbserial and ipaq module
+  with the module parameter "debug" set to 1 and examine the system log.
+  You can also try soft-resetting your PDA before attempting a connection.
+
+  Other functionality may be possible depending on your PDA. According to
+  Wes Cilldhaire <billybobjoehenrybob@hotmail.com>, with the Toshiba E570,
+  ...if you boot into the bootloader (hold down the power when hitting the
+  reset button, continuing to hold onto the power until the bootloader screen
+  is displayed), then put it in the cradle with the ipaq driver loaded, open
+  a terminal on /dev/ttyUSB0, it gives you a "USB Reflash" terminal, which can
+  be used to flash the ROM, as well as the microP code..  so much for needing
+  Toshiba's $350 serial cable for flashing!! :D
+  NOTE: This has NOT been tested. Use at your own risk.
+
+  For any questions or problems with the driver, please contact Ganesh
+  Varadarajan <ganesh@veritas.com>
+
+
+Keyspan PDA Serial Adapter
+--------------------------
+
+  Single port DB-9 serial adapter, pushed as a PDA adapter for iMacs (mostly
+  sold in Macintosh catalogs, comes in a translucent white/green dongle).
+  Fairly simple device. Firmware is homebrew.
+  This driver also works for the Xircom/Entrega single port serial adapter.
+
+  Current status:
+
+   Things that work:
+     - basic input/output (tested with 'cu')
+     - blocking write when serial line can't keep up
+     - changing baud rates (up to 115200)
+     - getting/setting modem control pins (TIOCM{GET,SET,BIS,BIC})
+     - sending break (although duration looks suspect)
+
+   Things that don't:
+     - device strings (as logged by kernel) have trailing binary garbage
+     - device ID isn't right, might collide with other Keyspan products
+     - changing baud rates ought to flush tx/rx to avoid mangled half characters
+
+   Big Things on the todo list:
+     - parity, 7 vs 8 bits per char, 1 or 2 stop bits
+     - HW flow control
+     - not all of the standard USB descriptors are handled:
+       Get_Status, Set_Feature, O_NONBLOCK, select()
+
+  For any questions or problems with this driver, please contact Brian
+  Warner at warner@lothar.com
+
+
+Keyspan USA-series Serial Adapters
+----------------------------------
+
+  Single, Dual and Quad port adapters - driver uses Keyspan supplied
+  firmware and is being developed with their support.
+
+  Current status:
+
+    The USA-18X, USA-28X, USA-19, USA-19W and USA-49W are supported and
+    have been pretty thoroughly tested at various baud rates with 8-N-1
+    character settings.  Other character lengths and parity setups are
+    presently untested.
+
+    The USA-28 isn't yet supported though doing so should be pretty
+    straightforward.  Contact the maintainer if you require this
+    functionality.
+
+  More information is available at:
+
+        http://www.carnationsoftware.com/carnation/Keyspan.html
+
+  For any questions or problems with this driver, please contact Hugh
+  Blemings at hugh@misc.nu
+
+
+FTDI Single Port Serial Driver
+------------------------------
+
+  This is a single port DB-25 serial adapter.
+
+  Devices supported include:
+
+                - TripNav TN-200 USB GPS
+                - Navis Engineering Bureau CH-4711 USB GPS
+
+  For any questions or problems with this driver, please contact Bill Ryder.
+
+
+ZyXEL omni.net lcd plus ISDN TA
+-------------------------------
+
+  This is an ISDN TA. Please report both successes and troubles to
+  azummo@towertech.it
+
+
+Cypress M8 CY4601 Family Serial Driver
+--------------------------------------
+
+  This driver was in most part developed by Neil "koyama" Whelchel.  It
+  has been improved since that previous form to support dynamic serial
+  line settings and improved line handling.  The driver is for the most
+  part stable and has been tested on an smp machine. (dual p2)
+
+    Chipsets supported under CY4601 family:
+
+               CY7C63723, CY7C63742, CY7C63743, CY7C64013
+
+    Devices supported:
+
+               - DeLorme's USB Earthmate GPS (SiRF Star II lp arch)
+               - Cypress HID->COM RS232 adapter
+
+               Note:
+                       Cypress Semiconductor claims no affiliation with the
+                       hid->com device.
+
+     Most devices using chipsets under the CY4601 family should
+     work with the driver.  As long as they stay true to the CY4601
+     usbserial specification.
+
+    Technical notes:
+
+        The Earthmate starts out at 4800 8N1 by default... the driver will
+       upon start init to this setting.  usbserial core provides the rest
+       of the termios settings, along with some custom termios so that the
+       output is in proper format and parsable.
+
+       The device can be put into sirf mode by issuing NMEA command::
+
+               $PSRF100,<protocol>,<baud>,<databits>,<stopbits>,<parity>*CHECKSUM
+               $PSRF100,0,9600,8,1,0*0C
+
+               It should then be sufficient to change the port termios to match this
+               to begin communicating.
+
+       As far as I can tell it supports pretty much every sirf command as
+       documented online available with firmware 2.31, with some unknown
+       message ids.
+
+       The hid->com adapter can run at a maximum baud of 115200bps.  Please note
+       that the device has trouble or is incapable of raising line voltage properly.
+       It will be fine with null modem links, as long as you do not try to link two
+       together without hacking the adapter to set the line high.
+
+       The driver is smp safe.  Performance with the driver is rather low when using
+       it for transferring files.  This is being worked on, but I would be willing to
+       accept patches.  An urb queue or packet buffer would likely fit the bill here.
+
+       If you have any questions, problems, patches, feature requests, etc. you can
+       contact me here via email:
+
+                                       dignome@gmail.com
+
+               (your problems/patches can alternately be submitted to usb-devel)
+
+
+Digi AccelePort Driver
+----------------------
+
+  This driver supports the Digi AccelePort USB 2 and 4 devices, 2 port
+  (plus a parallel port) and 4 port USB serial converters.  The driver
+  does NOT yet support the Digi AccelePort USB 8.
+
+  This driver works under SMP with the usb-uhci driver.  It does not
+  work under SMP with the uhci driver.
+
+  The driver is generally working, though we still have a few more ioctls
+  to implement and final testing and debugging to do.  The parallel port
+  on the USB 2 is supported as a serial to parallel converter; in other
+  words, it appears as another USB serial port on Linux, even though
+  physically it is really a parallel port.  The Digi Acceleport USB 8
+  is not yet supported.
+
+  Please contact Peter Berger (pberger@brimson.com) or Al Borchers
+  (alborchers@steinerpoint.com) for questions or problems with this
+  driver.
+
+
+Belkin USB Serial Adapter F5U103
+--------------------------------
+
+  Single port DB-9/PS-2 serial adapter from Belkin with firmware by eTEK Labs.
+  The Peracom single port serial adapter also works with this driver, as
+  well as the GoHubs adapter.
+
+  Current status:
+
+    The following have been tested and work:
+
+      - Baud rate    300-230400
+      - Data bits    5-8
+      - Stop bits    1-2
+      - Parity       N,E,O,M,S
+      - Handshake    None, Software (XON/XOFF), Hardware (CTSRTS,CTSDTR) [1]_
+      - Break        Set and clear
+      - Line control Input/Output query and control [2]_
+
+  .. [1]
+         Hardware input flow control is only enabled for firmware
+         levels above 2.06.  Read source code comments describing Belkin
+         firmware errata.  Hardware output flow control is working for all
+         firmware versions.
+
+  .. [2]
+         Queries of inputs (CTS,DSR,CD,RI) show the last
+         reported state.  Queries of outputs (DTR,RTS) show the last
+         requested state and may not reflect current state as set by
+         automatic hardware flow control.
+
+  TO DO List:
+    - Add true modem control line query capability.  Currently tracks the
+      states reported by the interrupt and the states requested.
+    - Add error reporting back to application for UART error conditions.
+    - Add support for flush ioctls.
+    - Add everything else that is missing :)
+
+  For any questions or problems with this driver, please contact William
+  Greathouse at wgreathouse@smva.com
+
+
+Empeg empeg-car Mark I/II Driver
+--------------------------------
+
+  This is an experimental driver to provide connectivity support for the
+  client synchronization tools for an Empeg empeg-car mp3 player.
+
+  Tips:
+    * Don't forget to create the device nodes for ttyUSB{0,1,2,...}
+    * modprobe empeg (modprobe is your friend)
+    * emptool --usb /dev/ttyUSB0 (or whatever you named your device node)
+
+  For any questions or problems with this driver, please contact Gary
+  Brubaker at xavyer@ix.netcom.com
+
+
+MCT USB Single Port Serial Adapter U232
+---------------------------------------
+
+  This driver is for the MCT USB-RS232 Converter (25 pin, Model No.
+  U232-P25) from Magic Control Technology Corp. (there is also a 9 pin
+  Model No. U232-P9). More information about this device can be found at
+  the manufacturer's web-site: http://www.mct.com.tw.
+
+  The driver is generally working, though it still needs some more testing.
+  It is derived from the Belkin USB Serial Adapter F5U103 driver and its
+  TODO list is valid for this driver as well.
+
+  This driver has also been found to work for other products, which have
+  the same Vendor ID but different Product IDs. Sitecom's U232-P25 serial
+  converter uses Product ID 0x230 and Vendor ID 0x711 and works with this
+  driver. Also, D-Link's DU-H3SP USB BAY also works with this driver.
+
+  For any questions or problems with this driver, please contact Wolfgang
+  Grandegger at wolfgang@ces.ch
+
+
+Inside Out Networks Edgeport Driver
+-----------------------------------
+
+  This driver supports all devices made by Inside Out Networks, specifically
+  the following models:
+
+       - Edgeport/4
+       - Rapidport/4
+       - Edgeport/4t
+       - Edgeport/2
+       - Edgeport/4i
+       - Edgeport/2i
+       - Edgeport/421
+       - Edgeport/21
+       - Edgeport/8
+       - Edgeport/8 Dual
+       - Edgeport/2D8
+       - Edgeport/4D8
+       - Edgeport/8i
+       - Edgeport/2 DIN
+       - Edgeport/4 DIN
+       - Edgeport/16 Dual
+
+  For any questions or problems with this driver, please contact Greg
+  Kroah-Hartman at greg@kroah.com
+
+
+REINER SCT cyberJack pinpad/e-com USB chipcard reader
+-----------------------------------------------------
+
+  Interface to ISO 7816 compatible contactbased chipcards, e.g. GSM SIMs.
+
+  Current status:
+
+    This is the kernel part of the driver for this USB card reader.
+    There is also a user part for a CT-API driver available. A site
+    for downloading is TBA. For now, you can request it from the
+    maintainer (linux-usb@sii.li).
+
+  For any questions or problems with this driver, please contact
+  linux-usb@sii.li
+
+
+Prolific PL2303 Driver
+----------------------
+
+  This driver supports any device that has the PL2303 chip from Prolific
+  in it.  This includes a number of single port USB to serial converters,
+  more than 70% of USB GPS devices (in 2010), and some USB UPSes. Devices
+  from Aten (the UC-232) and IO-Data work with this driver, as does
+  the DCU-11 mobile-phone cable.
+
+  For any questions or problems with this driver, please contact Greg
+  Kroah-Hartman at greg@kroah.com
+
+
+KL5KUSB105 chipset / PalmConnect USB single-port adapter
+--------------------------------------------------------
+
+Current status:
+
+  The driver was put together by looking at the usb bus transactions
+  done by Palm's driver under Windows, so a lot of functionality is
+  still missing.  Notably, serial ioctls are sometimes faked or not yet
+  implemented.  Support for finding out about DSR and CTS line status is
+  however implemented (though not nicely), so your favorite autopilot(1)
+  and pilot-manager -daemon calls will work.  Baud rates up to 115200
+  are supported, but handshaking (software or hardware) is not, which is
+  why it is wise to cut down on the rate used is wise for large
+  transfers until this is settled.
+
+  See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
+  information on this driver.
+
+Winchiphead CH341 Driver
+------------------------
+
+  This driver is for the Winchiphead CH341 USB-RS232 Converter. This chip
+  also implements an IEEE 1284 parallel port, I2C and SPI, but that is not
+  supported by the driver. The protocol was analyzed from the behaviour
+  of the Windows driver, no datasheet is available at present.
+
+  The manufacturer's website: http://www.winchiphead.com/.
+
+  For any questions or problems with this driver, please contact
+  frank@kingswood-consulting.co.uk.
+
+Moschip MCS7720, MCS7715 driver
+-------------------------------
+
+  These chips are present in devices sold by various manufacturers, such as Syba
+  and Cables Unlimited.  There may be others.  The 7720 provides two serial
+  ports, and the 7715 provides one serial and one standard PC parallel port.
+  Support for the 7715's parallel port is enabled by a separate option, which
+  will not appear unless parallel port support is first enabled at the top-level
+  of the Device Drivers config menu.  Currently only compatibility mode is
+  supported on the parallel port (no ECP/EPP).
+
+  TODO:
+    - Implement ECP/EPP modes for the parallel port.
+    - Baud rates higher than 115200 are currently broken.
+    - Devices with a single serial port based on the Moschip MCS7703 may work
+      with this driver with a simple addition to the usb_device_id table.  I
+      don't have one of these devices, so I can't say for sure.
+
+Generic Serial driver
+---------------------
+
+  If your device is not one of the above listed devices, compatible with
+  the above models, you can try out the "generic" interface. This
+  interface does not provide any type of control messages sent to the
+  device, and does not support any kind of device flow control. All that
+  is required of your device is that it has at least one bulk in endpoint,
+  or one bulk out endpoint.
+
+  To enable the generic driver to recognize your device, provide::
+
+       echo <vid> <pid> >/sys/bus/usb-serial/drivers/generic/new_id
+
+  where the <vid> and <pid> is replaced with the hex representation of your
+  device's vendor id and product id.
+  If the driver is compiled as a module you can also provide one id when
+  loading the module::
+
+       insmod usbserial vendor=0x#### product=0x####
+
+  This driver has been successfully used to connect to the NetChip USB
+  development board, providing a way to develop USB firmware without
+  having to write a custom driver.
+
+  For any questions or problems with this driver, please contact Greg
+  Kroah-Hartman at greg@kroah.com
+
+
+Contact
+=======
+
+  If anyone has any problems using these drivers, with any of the above
+  specified products, please contact the specific driver's author listed
+  above, or join the Linux-USB mailing list (information on joining the
+  mailing list, as well as a link to its searchable archive is at
+  http://www.linux-usb.org/ )
+
+
+Greg Kroah-Hartman
+greg@kroah.com
diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt
deleted file mode 100644 (file)
index 8fa7dbd..0000000
+++ /dev/null
@@ -1,537 +0,0 @@
-==========
-USB serial
-==========
-
-Introduction
-============
-
-  The USB serial driver currently supports a number of different USB to
-  serial converter products, as well as some devices that use a serial
-  interface from userspace to talk to the device.
-
-  See the individual product section below for specific information about
-  the different devices.
-
-
-Configuration
-=============
-
-  Currently the driver can handle up to 256 different serial interfaces at
-  one time.
-
-    The major number that the driver uses is 188 so to use the driver,
-    create the following nodes::
-
-       mknod /dev/ttyUSB0 c 188 0
-       mknod /dev/ttyUSB1 c 188 1
-       mknod /dev/ttyUSB2 c 188 2
-       mknod /dev/ttyUSB3 c 188 3
-               .
-               .
-               .
-       mknod /dev/ttyUSB254 c 188 254
-       mknod /dev/ttyUSB255 c 188 255
-
-  When the device is connected and recognized by the driver, the driver
-  will print to the system log, which node(s) the device has been bound
-  to.
-
-
-Specific Devices Supported
-==========================
-
-
-ConnectTech WhiteHEAT 4 port converter
---------------------------------------
-
-  ConnectTech has been very forthcoming with information about their
-  device, including providing a unit to test with.
-
-  The driver is officially supported by Connect Tech Inc.
-  http://www.connecttech.com
-
-  For any questions or problems with this driver, please contact
-  Connect Tech's Support Department at support@connecttech.com
-
-
-HandSpring Visor, Palm USB, and Clié USB driver
------------------------------------------------
-
-  This driver works with all HandSpring USB, Palm USB, and Sony Clié USB
-  devices.
-
-  Only when the device tries to connect to the host, will the device show
-  up to the host as a valid USB device. When this happens, the device is
-  properly enumerated, assigned a port, and then communication _should_ be
-  possible. The driver cleans up properly when the device is removed, or
-  the connection is canceled on the device.
-
-  NOTE:
-    This means that in order to talk to the device, the sync button must be
-    pressed BEFORE trying to get any program to communicate to the device.
-    This goes against the current documentation for pilot-xfer and other
-    packages, but is the only way that it will work due to the hardware
-    in the device.
-
-  When the device is connected, try talking to it on the second port
-  (this is usually /dev/ttyUSB1 if you do not have any other usb-serial
-  devices in the system.) The system log should tell you which port is
-  the port to use for the HotSync transfer. The "Generic" port can be used
-  for other device communication, such as a PPP link.
-
-  For some Sony Clié devices, /dev/ttyUSB0 must be used to talk to the
-  device.  This is true for all OS version 3.5 devices, and most devices
-  that have had a flash upgrade to a newer version of the OS.  See the
-  kernel system log for information on which is the correct port to use.
-
-  If after pressing the sync button, nothing shows up in the system log,
-  try resetting the device, first a hot reset, and then a cold reset if
-  necessary.  Some devices need this before they can talk to the USB port
-  properly.
-
-  Devices that are not compiled into the kernel can be specified with module
-  parameters.  e.g. modprobe visor vendor=0x54c product=0x66
-
-  There is a webpage and mailing lists for this portion of the driver at:
-  http://sourceforge.net/projects/usbvisor/
-
-  For any questions or problems with this driver, please contact Greg
-  Kroah-Hartman at greg@kroah.com
-
-
-PocketPC PDA Driver
--------------------
-
-  This driver can be used to connect to Compaq iPAQ, HP Jornada, Casio EM500
-  and other PDAs running Windows CE 3.0 or PocketPC 2002 using a USB
-  cable/cradle.
-  Most devices supported by ActiveSync are supported out of the box.
-  For others, please use module parameters to specify the product and vendor
-  id. e.g. modprobe ipaq vendor=0x3f0 product=0x1125
-
-  The driver presents a serial interface (usually on /dev/ttyUSB0) over
-  which one may run ppp and establish a TCP/IP link to the PDA. Once this
-  is done, you can transfer files, backup, download email etc. The most
-  significant advantage of using USB is speed - I can get 73 to 113
-  kbytes/sec for download/upload to my iPAQ.
-
-  This driver is only one of a set of components required to utilize
-  the USB connection. Please visit http://synce.sourceforge.net which
-  contains the necessary packages and a simple step-by-step howto.
-
-  Once connected, you can use Win CE programs like ftpView, Pocket Outlook
-  from the PDA and xcerdisp, synce utilities from the Linux side.
-
-  To use Pocket IE, follow the instructions given at
-  http://www.tekguru.co.uk/EM500/usbtonet.htm to achieve the same thing
-  on Win98. Omit the proxy server part; Linux is quite capable of forwarding
-  packets unlike Win98. Another modification is required at least for the
-  iPAQ - disable autosync by going to the Start/Settings/Connections menu
-  and unchecking the "Automatically synchronize ..." box. Go to
-  Start/Programs/Connections, connect the cable and select "usbdial" (or
-  whatever you named your new USB connection). You should finally wind
-  up with a "Connected to usbdial" window with status shown as connected.
-  Now start up PIE and browse away.
-
-  If it doesn't work for some reason, load both the usbserial and ipaq module
-  with the module parameter "debug" set to 1 and examine the system log.
-  You can also try soft-resetting your PDA before attempting a connection.
-
-  Other functionality may be possible depending on your PDA. According to
-  Wes Cilldhaire <billybobjoehenrybob@hotmail.com>, with the Toshiba E570,
-  ...if you boot into the bootloader (hold down the power when hitting the
-  reset button, continuing to hold onto the power until the bootloader screen
-  is displayed), then put it in the cradle with the ipaq driver loaded, open
-  a terminal on /dev/ttyUSB0, it gives you a "USB Reflash" terminal, which can
-  be used to flash the ROM, as well as the microP code..  so much for needing
-  Toshiba's $350 serial cable for flashing!! :D
-  NOTE: This has NOT been tested. Use at your own risk.
-
-  For any questions or problems with the driver, please contact Ganesh
-  Varadarajan <ganesh@veritas.com>
-
-
-Keyspan PDA Serial Adapter
---------------------------
-
-  Single port DB-9 serial adapter, pushed as a PDA adapter for iMacs (mostly
-  sold in Macintosh catalogs, comes in a translucent white/green dongle).
-  Fairly simple device. Firmware is homebrew.
-  This driver also works for the Xircom/Entrega single port serial adapter.
-
-  Current status:
-
-   Things that work:
-     - basic input/output (tested with 'cu')
-     - blocking write when serial line can't keep up
-     - changing baud rates (up to 115200)
-     - getting/setting modem control pins (TIOCM{GET,SET,BIS,BIC})
-     - sending break (although duration looks suspect)
-
-   Things that don't:
-     - device strings (as logged by kernel) have trailing binary garbage
-     - device ID isn't right, might collide with other Keyspan products
-     - changing baud rates ought to flush tx/rx to avoid mangled half characters
-
-   Big Things on the todo list:
-     - parity, 7 vs 8 bits per char, 1 or 2 stop bits
-     - HW flow control
-     - not all of the standard USB descriptors are handled:
-       Get_Status, Set_Feature, O_NONBLOCK, select()
-
-  For any questions or problems with this driver, please contact Brian
-  Warner at warner@lothar.com
-
-
-Keyspan USA-series Serial Adapters
-----------------------------------
-
-  Single, Dual and Quad port adapters - driver uses Keyspan supplied
-  firmware and is being developed with their support.
-
-  Current status:
-
-    The USA-18X, USA-28X, USA-19, USA-19W and USA-49W are supported and
-    have been pretty thoroughly tested at various baud rates with 8-N-1
-    character settings.  Other character lengths and parity setups are
-    presently untested.
-
-    The USA-28 isn't yet supported though doing so should be pretty
-    straightforward.  Contact the maintainer if you require this
-    functionality.
-
-  More information is available at:
-
-        http://www.carnationsoftware.com/carnation/Keyspan.html
-
-  For any questions or problems with this driver, please contact Hugh
-  Blemings at hugh@misc.nu
-
-
-FTDI Single Port Serial Driver
-------------------------------
-
-  This is a single port DB-25 serial adapter.
-
-  Devices supported include:
-
-                - TripNav TN-200 USB GPS
-                - Navis Engineering Bureau CH-4711 USB GPS
-
-  For any questions or problems with this driver, please contact Bill Ryder.
-
-
-ZyXEL omni.net lcd plus ISDN TA
--------------------------------
-
-  This is an ISDN TA. Please report both successes and troubles to
-  azummo@towertech.it
-
-
-Cypress M8 CY4601 Family Serial Driver
---------------------------------------
-
-  This driver was in most part developed by Neil "koyama" Whelchel.  It
-  has been improved since that previous form to support dynamic serial
-  line settings and improved line handling.  The driver is for the most
-  part stable and has been tested on an smp machine. (dual p2)
-
-    Chipsets supported under CY4601 family:
-
-               CY7C63723, CY7C63742, CY7C63743, CY7C64013
-
-    Devices supported:
-
-               - DeLorme's USB Earthmate GPS (SiRF Star II lp arch)
-               - Cypress HID->COM RS232 adapter
-
-               Note:
-                       Cypress Semiconductor claims no affiliation with the
-                       hid->com device.
-
-     Most devices using chipsets under the CY4601 family should
-     work with the driver.  As long as they stay true to the CY4601
-     usbserial specification.
-
-    Technical notes:
-
-        The Earthmate starts out at 4800 8N1 by default... the driver will
-       upon start init to this setting.  usbserial core provides the rest
-       of the termios settings, along with some custom termios so that the
-       output is in proper format and parsable.
-
-       The device can be put into sirf mode by issuing NMEA command::
-
-               $PSRF100,<protocol>,<baud>,<databits>,<stopbits>,<parity>*CHECKSUM
-               $PSRF100,0,9600,8,1,0*0C
-
-               It should then be sufficient to change the port termios to match this
-               to begin communicating.
-
-       As far as I can tell it supports pretty much every sirf command as
-       documented online available with firmware 2.31, with some unknown
-       message ids.
-
-       The hid->com adapter can run at a maximum baud of 115200bps.  Please note
-       that the device has trouble or is incapable of raising line voltage properly.
-       It will be fine with null modem links, as long as you do not try to link two
-       together without hacking the adapter to set the line high.
-
-       The driver is smp safe.  Performance with the driver is rather low when using
-       it for transferring files.  This is being worked on, but I would be willing to
-       accept patches.  An urb queue or packet buffer would likely fit the bill here.
-
-       If you have any questions, problems, patches, feature requests, etc. you can
-       contact me here via email:
-
-                                       dignome@gmail.com
-
-               (your problems/patches can alternately be submitted to usb-devel)
-
-
-Digi AccelePort Driver
-----------------------
-
-  This driver supports the Digi AccelePort USB 2 and 4 devices, 2 port
-  (plus a parallel port) and 4 port USB serial converters.  The driver
-  does NOT yet support the Digi AccelePort USB 8.
-
-  This driver works under SMP with the usb-uhci driver.  It does not
-  work under SMP with the uhci driver.
-
-  The driver is generally working, though we still have a few more ioctls
-  to implement and final testing and debugging to do.  The parallel port
-  on the USB 2 is supported as a serial to parallel converter; in other
-  words, it appears as another USB serial port on Linux, even though
-  physically it is really a parallel port.  The Digi Acceleport USB 8
-  is not yet supported.
-
-  Please contact Peter Berger (pberger@brimson.com) or Al Borchers
-  (alborchers@steinerpoint.com) for questions or problems with this
-  driver.
-
-
-Belkin USB Serial Adapter F5U103
---------------------------------
-
-  Single port DB-9/PS-2 serial adapter from Belkin with firmware by eTEK Labs.
-  The Peracom single port serial adapter also works with this driver, as
-  well as the GoHubs adapter.
-
-  Current status:
-
-    The following have been tested and work:
-
-      - Baud rate    300-230400
-      - Data bits    5-8
-      - Stop bits    1-2
-      - Parity       N,E,O,M,S
-      - Handshake    None, Software (XON/XOFF), Hardware (CTSRTS,CTSDTR) [1]_
-      - Break        Set and clear
-      - Line control Input/Output query and control [2]_
-
-  .. [1]
-         Hardware input flow control is only enabled for firmware
-         levels above 2.06.  Read source code comments describing Belkin
-         firmware errata.  Hardware output flow control is working for all
-         firmware versions.
-
-  .. [2]
-         Queries of inputs (CTS,DSR,CD,RI) show the last
-         reported state.  Queries of outputs (DTR,RTS) show the last
-         requested state and may not reflect current state as set by
-         automatic hardware flow control.
-
-  TO DO List:
-    - Add true modem control line query capability.  Currently tracks the
-      states reported by the interrupt and the states requested.
-    - Add error reporting back to application for UART error conditions.
-    - Add support for flush ioctls.
-    - Add everything else that is missing :)
-
-  For any questions or problems with this driver, please contact William
-  Greathouse at wgreathouse@smva.com
-
-
-Empeg empeg-car Mark I/II Driver
---------------------------------
-
-  This is an experimental driver to provide connectivity support for the
-  client synchronization tools for an Empeg empeg-car mp3 player.
-
-  Tips:
-    * Don't forget to create the device nodes for ttyUSB{0,1,2,...}
-    * modprobe empeg (modprobe is your friend)
-    * emptool --usb /dev/ttyUSB0 (or whatever you named your device node)
-
-  For any questions or problems with this driver, please contact Gary
-  Brubaker at xavyer@ix.netcom.com
-
-
-MCT USB Single Port Serial Adapter U232
----------------------------------------
-
-  This driver is for the MCT USB-RS232 Converter (25 pin, Model No.
-  U232-P25) from Magic Control Technology Corp. (there is also a 9 pin
-  Model No. U232-P9). More information about this device can be found at
-  the manufacturer's web-site: http://www.mct.com.tw.
-
-  The driver is generally working, though it still needs some more testing.
-  It is derived from the Belkin USB Serial Adapter F5U103 driver and its
-  TODO list is valid for this driver as well.
-
-  This driver has also been found to work for other products, which have
-  the same Vendor ID but different Product IDs. Sitecom's U232-P25 serial
-  converter uses Product ID 0x230 and Vendor ID 0x711 and works with this
-  driver. Also, D-Link's DU-H3SP USB BAY also works with this driver.
-
-  For any questions or problems with this driver, please contact Wolfgang
-  Grandegger at wolfgang@ces.ch
-
-
-Inside Out Networks Edgeport Driver
------------------------------------
-
-  This driver supports all devices made by Inside Out Networks, specifically
-  the following models:
-
-       - Edgeport/4
-       - Rapidport/4
-       - Edgeport/4t
-       - Edgeport/2
-       - Edgeport/4i
-       - Edgeport/2i
-       - Edgeport/421
-       - Edgeport/21
-       - Edgeport/8
-       - Edgeport/8 Dual
-       - Edgeport/2D8
-       - Edgeport/4D8
-       - Edgeport/8i
-       - Edgeport/2 DIN
-       - Edgeport/4 DIN
-       - Edgeport/16 Dual
-
-  For any questions or problems with this driver, please contact Greg
-  Kroah-Hartman at greg@kroah.com
-
-
-REINER SCT cyberJack pinpad/e-com USB chipcard reader
------------------------------------------------------
-
-  Interface to ISO 7816 compatible contactbased chipcards, e.g. GSM SIMs.
-
-  Current status:
-
-    This is the kernel part of the driver for this USB card reader.
-    There is also a user part for a CT-API driver available. A site
-    for downloading is TBA. For now, you can request it from the
-    maintainer (linux-usb@sii.li).
-
-  For any questions or problems with this driver, please contact
-  linux-usb@sii.li
-
-
-Prolific PL2303 Driver
-----------------------
-
-  This driver supports any device that has the PL2303 chip from Prolific
-  in it.  This includes a number of single port USB to serial converters,
-  more than 70% of USB GPS devices (in 2010), and some USB UPSes. Devices
-  from Aten (the UC-232) and IO-Data work with this driver, as does
-  the DCU-11 mobile-phone cable.
-
-  For any questions or problems with this driver, please contact Greg
-  Kroah-Hartman at greg@kroah.com
-
-
-KL5KUSB105 chipset / PalmConnect USB single-port adapter
---------------------------------------------------------
-
-Current status:
-
-  The driver was put together by looking at the usb bus transactions
-  done by Palm's driver under Windows, so a lot of functionality is
-  still missing.  Notably, serial ioctls are sometimes faked or not yet
-  implemented.  Support for finding out about DSR and CTS line status is
-  however implemented (though not nicely), so your favorite autopilot(1)
-  and pilot-manager -daemon calls will work.  Baud rates up to 115200
-  are supported, but handshaking (software or hardware) is not, which is
-  why it is wise to cut down on the rate used is wise for large
-  transfers until this is settled.
-
-  See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
-  information on this driver.
-
-Winchiphead CH341 Driver
-------------------------
-
-  This driver is for the Winchiphead CH341 USB-RS232 Converter. This chip
-  also implements an IEEE 1284 parallel port, I2C and SPI, but that is not
-  supported by the driver. The protocol was analyzed from the behaviour
-  of the Windows driver, no datasheet is available at present.
-
-  The manufacturer's website: http://www.winchiphead.com/.
-
-  For any questions or problems with this driver, please contact
-  frank@kingswood-consulting.co.uk.
-
-Moschip MCS7720, MCS7715 driver
--------------------------------
-
-  These chips are present in devices sold by various manufacturers, such as Syba
-  and Cables Unlimited.  There may be others.  The 7720 provides two serial
-  ports, and the 7715 provides one serial and one standard PC parallel port.
-  Support for the 7715's parallel port is enabled by a separate option, which
-  will not appear unless parallel port support is first enabled at the top-level
-  of the Device Drivers config menu.  Currently only compatibility mode is
-  supported on the parallel port (no ECP/EPP).
-
-  TODO:
-    - Implement ECP/EPP modes for the parallel port.
-    - Baud rates higher than 115200 are currently broken.
-    - Devices with a single serial port based on the Moschip MCS7703 may work
-      with this driver with a simple addition to the usb_device_id table.  I
-      don't have one of these devices, so I can't say for sure.
-
-Generic Serial driver
----------------------
-
-  If your device is not one of the above listed devices, compatible with
-  the above models, you can try out the "generic" interface. This
-  interface does not provide any type of control messages sent to the
-  device, and does not support any kind of device flow control. All that
-  is required of your device is that it has at least one bulk in endpoint,
-  or one bulk out endpoint.
-
-  To enable the generic driver to recognize your device, provide::
-
-       echo <vid> <pid> >/sys/bus/usb-serial/drivers/generic/new_id
-
-  where the <vid> and <pid> is replaced with the hex representation of your
-  device's vendor id and product id.
-  If the driver is compiled as a module you can also provide one id when
-  loading the module::
-
-       insmod usbserial vendor=0x#### product=0x####
-
-  This driver has been successfully used to connect to the NetChip USB
-  development board, providing a way to develop USB firmware without
-  having to write a custom driver.
-
-  For any questions or problems with this driver, please contact Greg
-  Kroah-Hartman at greg@kroah.com
-
-
-Contact
-=======
-
-  If anyone has any problems using these drivers, with any of the above
-  specified products, please contact the specific driver's author listed
-  above, or join the Linux-USB mailing list (information on joining the
-  mailing list, as well as a link to its searchable archive is at
-  http://www.linux-usb.org/ )
-
-
-Greg Kroah-Hartman
-greg@kroah.com
diff --git a/Documentation/usb/usbip_protocol.rst b/Documentation/usb/usbip_protocol.rst
new file mode 100644 (file)
index 0000000..988c832
--- /dev/null
@@ -0,0 +1,411 @@
+===============
+USB/IP protocol
+===============
+
+PRELIMINARY DRAFT, MAY CONTAIN MISTAKES!
+28 Jun 2011
+
+The USB/IP protocol follows a server/client architecture. The server exports the
+USB devices and the clients imports them. The device driver for the exported
+USB device runs on the client machine.
+
+The client may ask for the list of the exported USB devices. To get the list the
+client opens a TCP/IP connection towards the server, and sends an OP_REQ_DEVLIST
+packet on top of the TCP/IP connection (so the actual OP_REQ_DEVLIST may be sent
+in one or more pieces at the low level transport layer). The server sends back
+the OP_REP_DEVLIST packet which lists the exported USB devices. Finally the
+TCP/IP connection is closed.
+
+::
+
+ virtual host controller                                 usb host
+      "client"                                           "server"
+  (imports USB devices)                             (exports USB devices)
+          |                                                 |
+          |                  OP_REQ_DEVLIST                 |
+          | ----------------------------------------------> |
+          |                                                 |
+          |                  OP_REP_DEVLIST                 |
+          | <---------------------------------------------- |
+          |                                                 |
+
+Once the client knows the list of exported USB devices it may decide to use one
+of them. First the client opens a TCP/IP connection towards the server and
+sends an OP_REQ_IMPORT packet. The server replies with OP_REP_IMPORT. If the
+import was successful the TCP/IP connection remains open and will be used
+to transfer the URB traffic between the client and the server. The client may
+send two types of packets: the USBIP_CMD_SUBMIT to submit an URB, and
+USBIP_CMD_UNLINK to unlink a previously submitted URB. The answers of the
+server may be USBIP_RET_SUBMIT and USBIP_RET_UNLINK respectively.
+
+::
+
+ virtual host controller                                 usb host
+      "client"                                           "server"
+  (imports USB devices)                             (exports USB devices)
+          |                                                 |
+          |                  OP_REQ_IMPORT                  |
+          | ----------------------------------------------> |
+          |                                                 |
+          |                  OP_REP_IMPORT                  |
+          | <---------------------------------------------- |
+          |                                                 |
+          |                                                 |
+          |            USBIP_CMD_SUBMIT(seqnum = n)         |
+          | ----------------------------------------------> |
+          |                                                 |
+          |            USBIP_RET_SUBMIT(seqnum = n)         |
+          | <---------------------------------------------- |
+          |                        .                        |
+          |                        :                        |
+          |                                                 |
+          |            USBIP_CMD_SUBMIT(seqnum = m)         |
+          | ----------------------------------------------> |
+          |                                                 |
+          |            USBIP_CMD_SUBMIT(seqnum = m+1)       |
+          | ----------------------------------------------> |
+          |                                                 |
+          |            USBIP_CMD_SUBMIT(seqnum = m+2)       |
+          | ----------------------------------------------> |
+          |                                                 |
+          |            USBIP_RET_SUBMIT(seqnum = m)         |
+          | <---------------------------------------------- |
+          |                                                 |
+          |            USBIP_CMD_SUBMIT(seqnum = m+3)       |
+          | ----------------------------------------------> |
+          |                                                 |
+          |            USBIP_RET_SUBMIT(seqnum = m+1)       |
+          | <---------------------------------------------- |
+          |                                                 |
+          |            USBIP_CMD_SUBMIT(seqnum = m+4)       |
+          | ----------------------------------------------> |
+          |                                                 |
+          |            USBIP_RET_SUBMIT(seqnum = m+2)       |
+          | <---------------------------------------------- |
+          |                        .                        |
+          |                        :                        |
+          |                                                 |
+          |               USBIP_CMD_UNLINK                  |
+          | ----------------------------------------------> |
+          |                                                 |
+          |               USBIP_RET_UNLINK                  |
+          | <---------------------------------------------- |
+          |                                                 |
+
+The fields are in network (big endian) byte order meaning that the most significant
+byte (MSB) is stored at the lowest address.
+
+
+OP_REQ_DEVLIST:
+       Retrieve the list of exported USB devices.
+
++-----------+--------+------------+---------------------------------------------------+
+| Offset    | Length | Value      | Description                                       |
++===========+========+============+===================================================+
+| 0         | 2      | 0x0100     | Binary-coded decimal USBIP version number: v1.0.0 |
++-----------+--------+------------+---------------------------------------------------+
+| 2         | 2      | 0x8005     | Command code: Retrieve the list of exported USB   |
+|           |        |            | devices.                                          |
++-----------+--------+------------+---------------------------------------------------+
+| 4         | 4      | 0x00000000 | Status: unused, shall be set to 0                 |
++-----------+--------+------------+---------------------------------------------------+
+
+OP_REP_DEVLIST:
+       Reply with the list of exported USB devices.
+
++-----------+--------+------------+---------------------------------------------------+
+| Offset    | Length | Value      | Description                                       |
++===========+========+============+===================================================+
+| 0         | 2      | 0x0100     | Binary-coded decimal USBIP version number: v1.0.0.|
++-----------+--------+------------+---------------------------------------------------+
+| 2         | 2      | 0x0005     | Reply code: The list of exported USB devices.     |
++-----------+--------+------------+---------------------------------------------------+
+| 4         | 4      | 0x00000000 | Status: 0 for OK                                  |
++-----------+--------+------------+---------------------------------------------------+
+| 8         | 4      | n          | Number of exported devices: 0 means no exported   |
+|           |        |            | devices.                                          |
++-----------+--------+------------+---------------------------------------------------+
+| 0x0C      |        |            | From now on the exported n devices are described, |
+|           |        |            | if any. If no devices are exported the message    |
+|           |        |            | ends with the previous "number of exported        |
+|           |        |            | devices" field.                                   |
++-----------+--------+------------+---------------------------------------------------+
+|           | 256    |            | path: Path of the device on the host exporting the|
+|           |        |            | USB device, string closed with zero byte, e.g.    |
+|           |        |            | "/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-2"   |
+|           |        |            | The unused bytes shall be filled with zero        |
+|           |        |            | bytes.                                            |
++-----------+--------+------------+---------------------------------------------------+
+| 0x10C     | 32     |            | busid: Bus ID of the exported device, string      |
+|           |        |            | closed with zero byte, e.g. "3-2". The unused     |
+|           |        |            | bytes shall be filled with zero bytes.            |
++-----------+--------+------------+---------------------------------------------------+
+| 0x12C     | 4      |            | busnum                                            |
++-----------+--------+------------+---------------------------------------------------+
+| 0x130     | 4      |            | devnum                                            |
++-----------+--------+------------+---------------------------------------------------+
+| 0x134     | 4      |            | speed                                             |
++-----------+--------+------------+---------------------------------------------------+
+| 0x138     | 2      |            | idVendor                                          |
++-----------+--------+------------+---------------------------------------------------+
+| 0x13A     | 2      |            | idProduct                                         |
++-----------+--------+------------+---------------------------------------------------+
+| 0x13C     | 2      |            | bcdDevice                                         |
++-----------+--------+------------+---------------------------------------------------+
+| 0x13E     | 1      |            | bDeviceClass                                      |
++-----------+--------+------------+---------------------------------------------------+
+| 0x13F     | 1      |            | bDeviceSubClass                                   |
++-----------+--------+------------+---------------------------------------------------+
+| 0x140     | 1      |            | bDeviceProtocol                                   |
++-----------+--------+------------+---------------------------------------------------+
+| 0x141     | 1      |            | bConfigurationValue                               |
++-----------+--------+------------+---------------------------------------------------+
+| 0x142     | 1      |            | bNumConfigurations                                |
++-----------+--------+------------+---------------------------------------------------+
+| 0x143     | 1      |            | bNumInterfaces                                    |
++-----------+--------+------------+---------------------------------------------------+
+| 0x144     |        | m_0        | From now on each interface is described, all      |
+|           |        |            | together bNumInterfaces times, with the           |
+|           |        |            | the following 4 fields:                           |
++-----------+--------+------------+---------------------------------------------------+
+|           | 1      |            | bInterfaceClass                                   |
++-----------+--------+------------+---------------------------------------------------+
+| 0x145     | 1      |            | bInterfaceSubClass                                |
++-----------+--------+------------+---------------------------------------------------+
+| 0x146     | 1      |            | bInterfaceProtocol                                |
++-----------+--------+------------+---------------------------------------------------+
+| 0x147     | 1      |            | padding byte for alignment, shall be set to zero  |
++-----------+--------+------------+---------------------------------------------------+
+| 0xC +     |        |            | The second exported USB device starts at i=1      |
+| i*0x138 + |        |            | with the busid field.                             |
+| m_(i-1)*4 |        |            |                                                   |
++-----------+--------+------------+---------------------------------------------------+
+
+OP_REQ_IMPORT:
+       Request to import (attach) a remote USB device.
+
++-----------+--------+------------+---------------------------------------------------+
+| Offset    | Length | Value      | Description                                       |
++===========+========+============+===================================================+
+| 0         | 2      | 0x0100     | Binary-coded decimal USBIP version number: v1.0.0 |
++-----------+--------+------------+---------------------------------------------------+
+| 2         | 2      | 0x8003     | Command code: import a remote USB device.         |
++-----------+--------+------------+---------------------------------------------------+
+| 4         | 4      | 0x00000000 | Status: unused, shall be set to 0                 |
++-----------+--------+------------+---------------------------------------------------+
+| 8         | 32     |            | busid: the busid of the exported device on the    |
+|           |        |            | remote host. The possible values are taken        |
+|           |        |            | from the message field OP_REP_DEVLIST.busid.      |
+|           |        |            | A string closed with zero, the unused bytes       |
+|           |        |            | shall be filled with zeros.                       |
++-----------+--------+------------+---------------------------------------------------+
+
+OP_REP_IMPORT:
+       Reply to import (attach) a remote USB device.
+
++-----------+--------+------------+---------------------------------------------------+
+| Offset    | Length | Value      | Description                                       |
++===========+========+============+===================================================+
+| 0         | 2      | 0x0100     | Binary-coded decimal USBIP version number: v1.0.0 |
++-----------+--------+------------+---------------------------------------------------+
+| 2         | 2      | 0x0003     | Reply code: Reply to import.                      |
++-----------+--------+------------+---------------------------------------------------+
+| 4         | 4      | 0x00000000 | Status:                                           |
+|           |        |            |                                                   |
+|           |        |            |   - 0 for OK                                      |
+|           |        |            |   - 1 for error                                   |
++-----------+--------+------------+---------------------------------------------------+
+| 8         |        |            | From now on comes the details of the imported     |
+|           |        |            | device, if the previous status field was OK (0),  |
+|           |        |            | otherwise the reply ends with the status field.   |
++-----------+--------+------------+---------------------------------------------------+
+|           | 256    |            | path: Path of the device on the host exporting the|
+|           |        |            | USB device, string closed with zero byte, e.g.    |
+|           |        |            | "/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-2"   |
+|           |        |            | The unused bytes shall be filled with zero        |
+|           |        |            | bytes.                                            |
++-----------+--------+------------+---------------------------------------------------+
+| 0x108     | 32     |            | busid: Bus ID of the exported device, string      |
+|           |        |            | closed with zero byte, e.g. "3-2". The unused     |
+|           |        |            | bytes shall be filled with zero bytes.            |
++-----------+--------+------------+---------------------------------------------------+
+| 0x128     | 4      |            | busnum                                            |
++-----------+--------+------------+---------------------------------------------------+
+| 0x12C     | 4      |            | devnum                                            |
++-----------+--------+------------+---------------------------------------------------+
+| 0x130     | 4      |            | speed                                             |
++-----------+--------+------------+---------------------------------------------------+
+| 0x134     | 2      |            | idVendor                                          |
++-----------+--------+------------+---------------------------------------------------+
+| 0x136     | 2      |            | idProduct                                         |
++-----------+--------+------------+---------------------------------------------------+
+| 0x138     | 2      |            | bcdDevice                                         |
++-----------+--------+------------+---------------------------------------------------+
+| 0x139     | 1      |            | bDeviceClass                                      |
++-----------+--------+------------+---------------------------------------------------+
+| 0x13A     | 1      |            | bDeviceSubClass                                   |
++-----------+--------+------------+---------------------------------------------------+
+| 0x13B     | 1      |            | bDeviceProtocol                                   |
++-----------+--------+------------+---------------------------------------------------+
+| 0x13C     | 1      |            | bConfigurationValue                               |
++-----------+--------+------------+---------------------------------------------------+
+| 0x13D     | 1      |            | bNumConfigurations                                |
++-----------+--------+------------+---------------------------------------------------+
+| 0x13E     | 1      |            | bNumInterfaces                                    |
++-----------+--------+------------+---------------------------------------------------+
+
+USBIP_CMD_SUBMIT:
+       Submit an URB
+
++-----------+--------+------------+---------------------------------------------------+
+| Offset    | Length | Value      | Description                                       |
++===========+========+============+===================================================+
+| 0         | 4      | 0x00000001 | command: Submit an URB                            |
++-----------+--------+------------+---------------------------------------------------+
+| 4         | 4      |            | seqnum: the sequence number of the URB to submit  |
++-----------+--------+------------+---------------------------------------------------+
+| 8         | 4      |            | devid                                             |
++-----------+--------+------------+---------------------------------------------------+
+| 0xC       | 4      |            | direction:                                        |
+|           |        |            |                                                   |
+|           |        |            |    - 0: USBIP_DIR_OUT                             |
+|           |        |            |    - 1: USBIP_DIR_IN                              |
++-----------+--------+------------+---------------------------------------------------+
+| 0x10      | 4      |            | ep: endpoint number, possible values are: 0...15  |
++-----------+--------+------------+---------------------------------------------------+
+| 0x14      | 4      |            | transfer_flags: possible values depend on the     |
+|           |        |            | URB transfer type, see below                      |
++-----------+--------+------------+---------------------------------------------------+
+| 0x18      | 4      |            | transfer_buffer_length                            |
++-----------+--------+------------+---------------------------------------------------+
+| 0x1C      | 4      |            | start_frame: specify the selected frame to        |
+|           |        |            | transmit an ISO frame, ignored if URB_ISO_ASAP    |
+|           |        |            | is specified at transfer_flags                    |
++-----------+--------+------------+---------------------------------------------------+
+| 0x20      | 4      |            | number_of_packets: number of ISO packets          |
++-----------+--------+------------+---------------------------------------------------+
+| 0x24      | 4      |            | interval: maximum time for the request on the     |
+|           |        |            | server-side host controller                       |
++-----------+--------+------------+---------------------------------------------------+
+| 0x28      | 8      |            | setup: data bytes for USB setup, filled with      |
+|           |        |            | zeros if not used                                 |
++-----------+--------+------------+---------------------------------------------------+
+| 0x30      |        |            | URB data. For ISO transfers the padding between   |
+|           |        |            | each ISO packets is not transmitted.              |
++-----------+--------+------------+---------------------------------------------------+
+
+
+ +-------------------------+------------+---------+-----------+----------+-------------+
+ | Allowed transfer_flags  | value      | control | interrupt | bulk     | isochronous |
+ +=========================+============+=========+===========+==========+=============+
+ | URB_SHORT_NOT_OK        | 0x00000001 | only in | only in   | only in  | no          |
+ +-------------------------+------------+---------+-----------+----------+-------------+
+ | URB_ISO_ASAP            | 0x00000002 | no      | no        | no       | yes         |
+ +-------------------------+------------+---------+-----------+----------+-------------+
+ | URB_NO_TRANSFER_DMA_MAP | 0x00000004 | yes     | yes       | yes      | yes         |
+ +-------------------------+------------+---------+-----------+----------+-------------+
+ | URB_ZERO_PACKET         | 0x00000040 | no      | no        | only out | no          |
+ +-------------------------+------------+---------+-----------+----------+-------------+
+ | URB_NO_INTERRUPT        | 0x00000080 | yes     | yes       | yes      | yes         |
+ +-------------------------+------------+---------+-----------+----------+-------------+
+ | URB_FREE_BUFFER         | 0x00000100 | yes     | yes       | yes      | yes         |
+ +-------------------------+------------+---------+-----------+----------+-------------+
+ | URB_DIR_MASK            | 0x00000200 | yes     | yes       | yes      | yes         |
+ +-------------------------+------------+---------+-----------+----------+-------------+
+
+
+USBIP_RET_SUBMIT:
+       Reply for submitting an URB
+
++-----------+--------+------------+---------------------------------------------------+
+| Offset    | Length | Value      | Description                                       |
++===========+========+============+===================================================+
+| 0         | 4      | 0x00000003 | command                                           |
++-----------+--------+------------+---------------------------------------------------+
+| 4         | 4      |            | seqnum: URB sequence number                       |
++-----------+--------+------------+---------------------------------------------------+
+| 8         | 4      |            | devid                                             |
++-----------+--------+------------+---------------------------------------------------+
+| 0xC       | 4      |            | direction:                                        |
+|           |        |            |                                                   |
+|           |        |            |    - 0: USBIP_DIR_OUT                             |
+|           |        |            |    - 1: USBIP_DIR_IN                              |
++-----------+--------+------------+---------------------------------------------------+
+| 0x10      | 4      |            | ep: endpoint number                               |
++-----------+--------+------------+---------------------------------------------------+
+| 0x14      | 4      |            | status: zero for successful URB transaction,      |
+|           |        |            | otherwise some kind of error happened.            |
++-----------+--------+------------+---------------------------------------------------+
+| 0x18      | 4      | n          | actual_length: number of URB data bytes           |
++-----------+--------+------------+---------------------------------------------------+
+| 0x1C      | 4      |            | start_frame: for an ISO frame the actually        |
+|           |        |            | selected frame for transmit.                      |
++-----------+--------+------------+---------------------------------------------------+
+| 0x20      | 4      |            | number_of_packets                                 |
++-----------+--------+------------+---------------------------------------------------+
+| 0x24      | 4      |            | error_count                                       |
++-----------+--------+------------+---------------------------------------------------+
+| 0x28      | 8      |            | setup: data bytes for USB setup, filled with      |
+|           |        |            | zeros if not used                                 |
++-----------+--------+------------+---------------------------------------------------+
+| 0x30      | n      |            | URB data bytes. For ISO transfers the padding     |
+|           |        |            | between each ISO packets is not transmitted.      |
++-----------+--------+------------+---------------------------------------------------+
+
+USBIP_CMD_UNLINK:
+       Unlink an URB
+
++-----------+--------+------------+---------------------------------------------------+
+| Offset    | Length | Value      | Description                                       |
++===========+========+============+===================================================+
+| 0         | 4      | 0x00000002 | command: URB unlink command                       |
++-----------+--------+------------+---------------------------------------------------+
+| 4         | 4      |            | seqnum: URB sequence number to unlink:            |
+|           |        |            |                                                   |
+|           |        |            | FIXME:                                            |
+|           |        |            |    is this so?                                    |
++-----------+--------+------------+---------------------------------------------------+
+| 8         | 4      |            | devid                                             |
++-----------+--------+------------+---------------------------------------------------+
+| 0xC       | 4      |            | direction:                                        |
+|           |        |            |                                                   |
+|           |        |            |    - 0: USBIP_DIR_OUT                             |
+|           |        |            |    - 1: USBIP_DIR_IN                              |
++-----------+--------+------------+---------------------------------------------------+
+| 0x10      | 4      |            | ep: endpoint number: zero                         |
++-----------+--------+------------+---------------------------------------------------+
+| 0x14      | 4      |            | seqnum: the URB sequence number given previously  |
+|           |        |            | at USBIP_CMD_SUBMIT.seqnum field                  |
++-----------+--------+------------+---------------------------------------------------+
+| 0x30      | n      |            | URB data bytes. For ISO transfers the padding     |
+|           |        |            | between each ISO packets is not transmitted.      |
++-----------+--------+------------+---------------------------------------------------+
+
+USBIP_RET_UNLINK:
+       Reply for URB unlink
+
++-----------+--------+------------+---------------------------------------------------+
+| Offset    | Length | Value      | Description                                       |
++===========+========+============+===================================================+
+| 0         | 4      | 0x00000004 | command: reply for the URB unlink command         |
++-----------+--------+------------+---------------------------------------------------+
+| 4         | 4      |            | seqnum: the unlinked URB sequence number          |
++-----------+--------+------------+---------------------------------------------------+
+| 8         | 4      |            | devid                                             |
++-----------+--------+------------+---------------------------------------------------+
+| 0xC       | 4      |            | direction:                                        |
+|           |        |            |                                                   |
+|           |        |            |    - 0: USBIP_DIR_OUT                             |
+|           |        |            |    - 1: USBIP_DIR_IN                              |
++-----------+--------+------------+---------------------------------------------------+
+| 0x10      | 4      |            | ep: endpoint number                               |
++-----------+--------+------------+---------------------------------------------------+
+| 0x14      | 4      |            | status: This is the value contained in the        |
+|           |        |            | urb->status in the URB completition handler.      |
+|           |        |            |                                                   |
+|           |        |            | FIXME:                                            |
+|           |        |            |      a better explanation needed.                 |
++-----------+--------+------------+---------------------------------------------------+
+| 0x30      | n      |            | URB data bytes. For ISO transfers the padding     |
+|           |        |            | between each ISO packets is not transmitted.      |
++-----------+--------+------------+---------------------------------------------------+
diff --git a/Documentation/usb/usbip_protocol.txt b/Documentation/usb/usbip_protocol.txt
deleted file mode 100644 (file)
index 988c832..0000000
+++ /dev/null
@@ -1,411 +0,0 @@
-===============
-USB/IP protocol
-===============
-
-PRELIMINARY DRAFT, MAY CONTAIN MISTAKES!
-28 Jun 2011
-
-The USB/IP protocol follows a server/client architecture. The server exports the
-USB devices and the clients imports them. The device driver for the exported
-USB device runs on the client machine.
-
-The client may ask for the list of the exported USB devices. To get the list the
-client opens a TCP/IP connection towards the server, and sends an OP_REQ_DEVLIST
-packet on top of the TCP/IP connection (so the actual OP_REQ_DEVLIST may be sent
-in one or more pieces at the low level transport layer). The server sends back
-the OP_REP_DEVLIST packet which lists the exported USB devices. Finally the
-TCP/IP connection is closed.
-
-::
-
- virtual host controller                                 usb host
-      "client"                                           "server"
-  (imports USB devices)                             (exports USB devices)
-          |                                                 |
-          |                  OP_REQ_DEVLIST                 |
-          | ----------------------------------------------> |
-          |                                                 |
-          |                  OP_REP_DEVLIST                 |
-          | <---------------------------------------------- |
-          |                                                 |
-
-Once the client knows the list of exported USB devices it may decide to use one
-of them. First the client opens a TCP/IP connection towards the server and
-sends an OP_REQ_IMPORT packet. The server replies with OP_REP_IMPORT. If the
-import was successful the TCP/IP connection remains open and will be used
-to transfer the URB traffic between the client and the server. The client may
-send two types of packets: the USBIP_CMD_SUBMIT to submit an URB, and
-USBIP_CMD_UNLINK to unlink a previously submitted URB. The answers of the
-server may be USBIP_RET_SUBMIT and USBIP_RET_UNLINK respectively.
-
-::
-
- virtual host controller                                 usb host
-      "client"                                           "server"
-  (imports USB devices)                             (exports USB devices)
-          |                                                 |
-          |                  OP_REQ_IMPORT                  |
-          | ----------------------------------------------> |
-          |                                                 |
-          |                  OP_REP_IMPORT                  |
-          | <---------------------------------------------- |
-          |                                                 |
-          |                                                 |
-          |            USBIP_CMD_SUBMIT(seqnum = n)         |
-          | ----------------------------------------------> |
-          |                                                 |
-          |            USBIP_RET_SUBMIT(seqnum = n)         |
-          | <---------------------------------------------- |
-          |                        .                        |
-          |                        :                        |
-          |                                                 |
-          |            USBIP_CMD_SUBMIT(seqnum = m)         |
-          | ----------------------------------------------> |
-          |                                                 |
-          |            USBIP_CMD_SUBMIT(seqnum = m+1)       |
-          | ----------------------------------------------> |
-          |                                                 |
-          |            USBIP_CMD_SUBMIT(seqnum = m+2)       |
-          | ----------------------------------------------> |
-          |                                                 |
-          |            USBIP_RET_SUBMIT(seqnum = m)         |
-          | <---------------------------------------------- |
-          |                                                 |
-          |            USBIP_CMD_SUBMIT(seqnum = m+3)       |
-          | ----------------------------------------------> |
-          |                                                 |
-          |            USBIP_RET_SUBMIT(seqnum = m+1)       |
-          | <---------------------------------------------- |
-          |                                                 |
-          |            USBIP_CMD_SUBMIT(seqnum = m+4)       |
-          | ----------------------------------------------> |
-          |                                                 |
-          |            USBIP_RET_SUBMIT(seqnum = m+2)       |
-          | <---------------------------------------------- |
-          |                        .                        |
-          |                        :                        |
-          |                                                 |
-          |               USBIP_CMD_UNLINK                  |
-          | ----------------------------------------------> |
-          |                                                 |
-          |               USBIP_RET_UNLINK                  |
-          | <---------------------------------------------- |
-          |                                                 |
-
-The fields are in network (big endian) byte order meaning that the most significant
-byte (MSB) is stored at the lowest address.
-
-
-OP_REQ_DEVLIST:
-       Retrieve the list of exported USB devices.
-
-+-----------+--------+------------+---------------------------------------------------+
-| Offset    | Length | Value      | Description                                       |
-+===========+========+============+===================================================+
-| 0         | 2      | 0x0100     | Binary-coded decimal USBIP version number: v1.0.0 |
-+-----------+--------+------------+---------------------------------------------------+
-| 2         | 2      | 0x8005     | Command code: Retrieve the list of exported USB   |
-|           |        |            | devices.                                          |
-+-----------+--------+------------+---------------------------------------------------+
-| 4         | 4      | 0x00000000 | Status: unused, shall be set to 0                 |
-+-----------+--------+------------+---------------------------------------------------+
-
-OP_REP_DEVLIST:
-       Reply with the list of exported USB devices.
-
-+-----------+--------+------------+---------------------------------------------------+
-| Offset    | Length | Value      | Description                                       |
-+===========+========+============+===================================================+
-| 0         | 2      | 0x0100     | Binary-coded decimal USBIP version number: v1.0.0.|
-+-----------+--------+------------+---------------------------------------------------+
-| 2         | 2      | 0x0005     | Reply code: The list of exported USB devices.     |
-+-----------+--------+------------+---------------------------------------------------+
-| 4         | 4      | 0x00000000 | Status: 0 for OK                                  |
-+-----------+--------+------------+---------------------------------------------------+
-| 8         | 4      | n          | Number of exported devices: 0 means no exported   |
-|           |        |            | devices.                                          |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x0C      |        |            | From now on the exported n devices are described, |
-|           |        |            | if any. If no devices are exported the message    |
-|           |        |            | ends with the previous "number of exported        |
-|           |        |            | devices" field.                                   |
-+-----------+--------+------------+---------------------------------------------------+
-|           | 256    |            | path: Path of the device on the host exporting the|
-|           |        |            | USB device, string closed with zero byte, e.g.    |
-|           |        |            | "/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-2"   |
-|           |        |            | The unused bytes shall be filled with zero        |
-|           |        |            | bytes.                                            |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x10C     | 32     |            | busid: Bus ID of the exported device, string      |
-|           |        |            | closed with zero byte, e.g. "3-2". The unused     |
-|           |        |            | bytes shall be filled with zero bytes.            |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x12C     | 4      |            | busnum                                            |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x130     | 4      |            | devnum                                            |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x134     | 4      |            | speed                                             |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x138     | 2      |            | idVendor                                          |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x13A     | 2      |            | idProduct                                         |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x13C     | 2      |            | bcdDevice                                         |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x13E     | 1      |            | bDeviceClass                                      |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x13F     | 1      |            | bDeviceSubClass                                   |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x140     | 1      |            | bDeviceProtocol                                   |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x141     | 1      |            | bConfigurationValue                               |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x142     | 1      |            | bNumConfigurations                                |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x143     | 1      |            | bNumInterfaces                                    |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x144     |        | m_0        | From now on each interface is described, all      |
-|           |        |            | together bNumInterfaces times, with the           |
-|           |        |            | the following 4 fields:                           |
-+-----------+--------+------------+---------------------------------------------------+
-|           | 1      |            | bInterfaceClass                                   |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x145     | 1      |            | bInterfaceSubClass                                |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x146     | 1      |            | bInterfaceProtocol                                |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x147     | 1      |            | padding byte for alignment, shall be set to zero  |
-+-----------+--------+------------+---------------------------------------------------+
-| 0xC +     |        |            | The second exported USB device starts at i=1      |
-| i*0x138 + |        |            | with the busid field.                             |
-| m_(i-1)*4 |        |            |                                                   |
-+-----------+--------+------------+---------------------------------------------------+
-
-OP_REQ_IMPORT:
-       Request to import (attach) a remote USB device.
-
-+-----------+--------+------------+---------------------------------------------------+
-| Offset    | Length | Value      | Description                                       |
-+===========+========+============+===================================================+
-| 0         | 2      | 0x0100     | Binary-coded decimal USBIP version number: v1.0.0 |
-+-----------+--------+------------+---------------------------------------------------+
-| 2         | 2      | 0x8003     | Command code: import a remote USB device.         |
-+-----------+--------+------------+---------------------------------------------------+
-| 4         | 4      | 0x00000000 | Status: unused, shall be set to 0                 |
-+-----------+--------+------------+---------------------------------------------------+
-| 8         | 32     |            | busid: the busid of the exported device on the    |
-|           |        |            | remote host. The possible values are taken        |
-|           |        |            | from the message field OP_REP_DEVLIST.busid.      |
-|           |        |            | A string closed with zero, the unused bytes       |
-|           |        |            | shall be filled with zeros.                       |
-+-----------+--------+------------+---------------------------------------------------+
-
-OP_REP_IMPORT:
-       Reply to import (attach) a remote USB device.
-
-+-----------+--------+------------+---------------------------------------------------+
-| Offset    | Length | Value      | Description                                       |
-+===========+========+============+===================================================+
-| 0         | 2      | 0x0100     | Binary-coded decimal USBIP version number: v1.0.0 |
-+-----------+--------+------------+---------------------------------------------------+
-| 2         | 2      | 0x0003     | Reply code: Reply to import.                      |
-+-----------+--------+------------+---------------------------------------------------+
-| 4         | 4      | 0x00000000 | Status:                                           |
-|           |        |            |                                                   |
-|           |        |            |   - 0 for OK                                      |
-|           |        |            |   - 1 for error                                   |
-+-----------+--------+------------+---------------------------------------------------+
-| 8         |        |            | From now on comes the details of the imported     |
-|           |        |            | device, if the previous status field was OK (0),  |
-|           |        |            | otherwise the reply ends with the status field.   |
-+-----------+--------+------------+---------------------------------------------------+
-|           | 256    |            | path: Path of the device on the host exporting the|
-|           |        |            | USB device, string closed with zero byte, e.g.    |
-|           |        |            | "/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-2"   |
-|           |        |            | The unused bytes shall be filled with zero        |
-|           |        |            | bytes.                                            |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x108     | 32     |            | busid: Bus ID of the exported device, string      |
-|           |        |            | closed with zero byte, e.g. "3-2". The unused     |
-|           |        |            | bytes shall be filled with zero bytes.            |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x128     | 4      |            | busnum                                            |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x12C     | 4      |            | devnum                                            |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x130     | 4      |            | speed                                             |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x134     | 2      |            | idVendor                                          |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x136     | 2      |            | idProduct                                         |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x138     | 2      |            | bcdDevice                                         |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x139     | 1      |            | bDeviceClass                                      |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x13A     | 1      |            | bDeviceSubClass                                   |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x13B     | 1      |            | bDeviceProtocol                                   |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x13C     | 1      |            | bConfigurationValue                               |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x13D     | 1      |            | bNumConfigurations                                |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x13E     | 1      |            | bNumInterfaces                                    |
-+-----------+--------+------------+---------------------------------------------------+
-
-USBIP_CMD_SUBMIT:
-       Submit an URB
-
-+-----------+--------+------------+---------------------------------------------------+
-| Offset    | Length | Value      | Description                                       |
-+===========+========+============+===================================================+
-| 0         | 4      | 0x00000001 | command: Submit an URB                            |
-+-----------+--------+------------+---------------------------------------------------+
-| 4         | 4      |            | seqnum: the sequence number of the URB to submit  |
-+-----------+--------+------------+---------------------------------------------------+
-| 8         | 4      |            | devid                                             |
-+-----------+--------+------------+---------------------------------------------------+
-| 0xC       | 4      |            | direction:                                        |
-|           |        |            |                                                   |
-|           |        |            |    - 0: USBIP_DIR_OUT                             |
-|           |        |            |    - 1: USBIP_DIR_IN                              |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x10      | 4      |            | ep: endpoint number, possible values are: 0...15  |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x14      | 4      |            | transfer_flags: possible values depend on the     |
-|           |        |            | URB transfer type, see below                      |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x18      | 4      |            | transfer_buffer_length                            |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x1C      | 4      |            | start_frame: specify the selected frame to        |
-|           |        |            | transmit an ISO frame, ignored if URB_ISO_ASAP    |
-|           |        |            | is specified at transfer_flags                    |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x20      | 4      |            | number_of_packets: number of ISO packets          |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x24      | 4      |            | interval: maximum time for the request on the     |
-|           |        |            | server-side host controller                       |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x28      | 8      |            | setup: data bytes for USB setup, filled with      |
-|           |        |            | zeros if not used                                 |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x30      |        |            | URB data. For ISO transfers the padding between   |
-|           |        |            | each ISO packets is not transmitted.              |
-+-----------+--------+------------+---------------------------------------------------+
-
-
- +-------------------------+------------+---------+-----------+----------+-------------+
- | Allowed transfer_flags  | value      | control | interrupt | bulk     | isochronous |
- +=========================+============+=========+===========+==========+=============+
- | URB_SHORT_NOT_OK        | 0x00000001 | only in | only in   | only in  | no          |
- +-------------------------+------------+---------+-----------+----------+-------------+
- | URB_ISO_ASAP            | 0x00000002 | no      | no        | no       | yes         |
- +-------------------------+------------+---------+-----------+----------+-------------+
- | URB_NO_TRANSFER_DMA_MAP | 0x00000004 | yes     | yes       | yes      | yes         |
- +-------------------------+------------+---------+-----------+----------+-------------+
- | URB_ZERO_PACKET         | 0x00000040 | no      | no        | only out | no          |
- +-------------------------+------------+---------+-----------+----------+-------------+
- | URB_NO_INTERRUPT        | 0x00000080 | yes     | yes       | yes      | yes         |
- +-------------------------+------------+---------+-----------+----------+-------------+
- | URB_FREE_BUFFER         | 0x00000100 | yes     | yes       | yes      | yes         |
- +-------------------------+------------+---------+-----------+----------+-------------+
- | URB_DIR_MASK            | 0x00000200 | yes     | yes       | yes      | yes         |
- +-------------------------+------------+---------+-----------+----------+-------------+
-
-
-USBIP_RET_SUBMIT:
-       Reply for submitting an URB
-
-+-----------+--------+------------+---------------------------------------------------+
-| Offset    | Length | Value      | Description                                       |
-+===========+========+============+===================================================+
-| 0         | 4      | 0x00000003 | command                                           |
-+-----------+--------+------------+---------------------------------------------------+
-| 4         | 4      |            | seqnum: URB sequence number                       |
-+-----------+--------+------------+---------------------------------------------------+
-| 8         | 4      |            | devid                                             |
-+-----------+--------+------------+---------------------------------------------------+
-| 0xC       | 4      |            | direction:                                        |
-|           |        |            |                                                   |
-|           |        |            |    - 0: USBIP_DIR_OUT                             |
-|           |        |            |    - 1: USBIP_DIR_IN                              |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x10      | 4      |            | ep: endpoint number                               |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x14      | 4      |            | status: zero for successful URB transaction,      |
-|           |        |            | otherwise some kind of error happened.            |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x18      | 4      | n          | actual_length: number of URB data bytes           |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x1C      | 4      |            | start_frame: for an ISO frame the actually        |
-|           |        |            | selected frame for transmit.                      |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x20      | 4      |            | number_of_packets                                 |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x24      | 4      |            | error_count                                       |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x28      | 8      |            | setup: data bytes for USB setup, filled with      |
-|           |        |            | zeros if not used                                 |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x30      | n      |            | URB data bytes. For ISO transfers the padding     |
-|           |        |            | between each ISO packets is not transmitted.      |
-+-----------+--------+------------+---------------------------------------------------+
-
-USBIP_CMD_UNLINK:
-       Unlink an URB
-
-+-----------+--------+------------+---------------------------------------------------+
-| Offset    | Length | Value      | Description                                       |
-+===========+========+============+===================================================+
-| 0         | 4      | 0x00000002 | command: URB unlink command                       |
-+-----------+--------+------------+---------------------------------------------------+
-| 4         | 4      |            | seqnum: URB sequence number to unlink:            |
-|           |        |            |                                                   |
-|           |        |            | FIXME:                                            |
-|           |        |            |    is this so?                                    |
-+-----------+--------+------------+---------------------------------------------------+
-| 8         | 4      |            | devid                                             |
-+-----------+--------+------------+---------------------------------------------------+
-| 0xC       | 4      |            | direction:                                        |
-|           |        |            |                                                   |
-|           |        |            |    - 0: USBIP_DIR_OUT                             |
-|           |        |            |    - 1: USBIP_DIR_IN                              |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x10      | 4      |            | ep: endpoint number: zero                         |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x14      | 4      |            | seqnum: the URB sequence number given previously  |
-|           |        |            | at USBIP_CMD_SUBMIT.seqnum field                  |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x30      | n      |            | URB data bytes. For ISO transfers the padding     |
-|           |        |            | between each ISO packets is not transmitted.      |
-+-----------+--------+------------+---------------------------------------------------+
-
-USBIP_RET_UNLINK:
-       Reply for URB unlink
-
-+-----------+--------+------------+---------------------------------------------------+
-| Offset    | Length | Value      | Description                                       |
-+===========+========+============+===================================================+
-| 0         | 4      | 0x00000004 | command: reply for the URB unlink command         |
-+-----------+--------+------------+---------------------------------------------------+
-| 4         | 4      |            | seqnum: the unlinked URB sequence number          |
-+-----------+--------+------------+---------------------------------------------------+
-| 8         | 4      |            | devid                                             |
-+-----------+--------+------------+---------------------------------------------------+
-| 0xC       | 4      |            | direction:                                        |
-|           |        |            |                                                   |
-|           |        |            |    - 0: USBIP_DIR_OUT                             |
-|           |        |            |    - 1: USBIP_DIR_IN                              |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x10      | 4      |            | ep: endpoint number                               |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x14      | 4      |            | status: This is the value contained in the        |
-|           |        |            | urb->status in the URB completition handler.      |
-|           |        |            |                                                   |
-|           |        |            | FIXME:                                            |
-|           |        |            |      a better explanation needed.                 |
-+-----------+--------+------------+---------------------------------------------------+
-| 0x30      | n      |            | URB data bytes. For ISO transfers the padding     |
-|           |        |            | between each ISO packets is not transmitted.      |
-+-----------+--------+------------+---------------------------------------------------+
diff --git a/Documentation/usb/usbmon.rst b/Documentation/usb/usbmon.rst
new file mode 100644 (file)
index 0000000..b0bd510
--- /dev/null
@@ -0,0 +1,375 @@
+======
+usbmon
+======
+
+Introduction
+============
+
+The name "usbmon" in lowercase refers to a facility in kernel which is
+used to collect traces of I/O on the USB bus. This function is analogous
+to a packet socket used by network monitoring tools such as tcpdump(1)
+or Ethereal. Similarly, it is expected that a tool such as usbdump or
+USBMon (with uppercase letters) is used to examine raw traces produced
+by usbmon.
+
+The usbmon reports requests made by peripheral-specific drivers to Host
+Controller Drivers (HCD). So, if HCD is buggy, the traces reported by
+usbmon may not correspond to bus transactions precisely. This is the same
+situation as with tcpdump.
+
+Two APIs are currently implemented: "text" and "binary". The binary API
+is available through a character device in /dev namespace and is an ABI.
+The text API is deprecated since 2.6.35, but available for convenience.
+
+How to use usbmon to collect raw text traces
+============================================
+
+Unlike the packet socket, usbmon has an interface which provides traces
+in a text format. This is used for two purposes. First, it serves as a
+common trace exchange format for tools while more sophisticated formats
+are finalized. Second, humans can read it in case tools are not available.
+
+To collect a raw text trace, execute following steps.
+
+1. Prepare
+----------
+
+Mount debugfs (it has to be enabled in your kernel configuration), and
+load the usbmon module (if built as module). The second step is skipped
+if usbmon is built into the kernel::
+
+       # mount -t debugfs none_debugs /sys/kernel/debug
+       # modprobe usbmon
+       #
+
+Verify that bus sockets are present:
+
+       # ls /sys/kernel/debug/usb/usbmon
+       0s  0u  1s  1t  1u  2s  2t  2u  3s  3t  3u  4s  4t  4u
+       #
+
+Now you can choose to either use the socket '0u' (to capture packets on all
+buses), and skip to step #3, or find the bus used by your device with step #2.
+This allows to filter away annoying devices that talk continuously.
+
+2. Find which bus connects to the desired device
+------------------------------------------------
+
+Run "cat /sys/kernel/debug/usb/devices", and find the T-line which corresponds
+to the device. Usually you do it by looking for the vendor string. If you have
+many similar devices, unplug one and compare the two
+/sys/kernel/debug/usb/devices outputs. The T-line will have a bus number.
+
+Example::
+
+  T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 0
+  D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
+  P:  Vendor=0557 ProdID=2004 Rev= 1.00
+  S:  Manufacturer=ATEN
+  S:  Product=UC100KM V2.00
+
+"Bus=03" means it's bus 3. Alternatively, you can look at the output from
+"lsusb" and get the bus number from the appropriate line. Example:
+
+Bus 003 Device 002: ID 0557:2004 ATEN UC100KM V2.00
+
+3. Start 'cat'
+--------------
+
+::
+
+       # cat /sys/kernel/debug/usb/usbmon/3u > /tmp/1.mon.out
+
+to listen on a single bus, otherwise, to listen on all buses, type::
+
+       # cat /sys/kernel/debug/usb/usbmon/0u > /tmp/1.mon.out
+
+This process will read until it is killed. Naturally, the output can be
+redirected to a desirable location. This is preferred, because it is going
+to be quite long.
+
+4. Perform the desired operation on the USB bus
+-----------------------------------------------
+
+This is where you do something that creates the traffic: plug in a flash key,
+copy files, control a webcam, etc.
+
+5. Kill cat
+-----------
+
+Usually it's done with a keyboard interrupt (Control-C).
+
+At this point the output file (/tmp/1.mon.out in this example) can be saved,
+sent by e-mail, or inspected with a text editor. In the last case make sure
+that the file size is not excessive for your favourite editor.
+
+Raw text data format
+====================
+
+Two formats are supported currently: the original, or '1t' format, and
+the '1u' format. The '1t' format is deprecated in kernel 2.6.21. The '1u'
+format adds a few fields, such as ISO frame descriptors, interval, etc.
+It produces slightly longer lines, but otherwise is a perfect superset
+of '1t' format.
+
+If it is desired to recognize one from the other in a program, look at the
+"address" word (see below), where '1u' format adds a bus number. If 2 colons
+are present, it's the '1t' format, otherwise '1u'.
+
+Any text format data consists of a stream of events, such as URB submission,
+URB callback, submission error. Every event is a text line, which consists
+of whitespace separated words. The number or position of words may depend
+on the event type, but there is a set of words, common for all types.
+
+Here is the list of words, from left to right:
+
+- URB Tag. This is used to identify URBs, and is normally an in-kernel address
+  of the URB structure in hexadecimal, but can be a sequence number or any
+  other unique string, within reason.
+
+- Timestamp in microseconds, a decimal number. The timestamp's resolution
+  depends on available clock, and so it can be much worse than a microsecond
+  (if the implementation uses jiffies, for example).
+
+- Event Type. This type refers to the format of the event, not URB type.
+  Available types are: S - submission, C - callback, E - submission error.
+
+- "Address" word (formerly a "pipe"). It consists of four fields, separated by
+  colons: URB type and direction, Bus number, Device address, Endpoint number.
+  Type and direction are encoded with two bytes in the following manner:
+
+    == ==   =============================
+    Ci Co   Control input and output
+    Zi Zo   Isochronous input and output
+    Ii Io   Interrupt input and output
+    Bi Bo   Bulk input and output
+    == ==   =============================
+
+  Bus number, Device address, and Endpoint are decimal numbers, but they may
+  have leading zeros, for the sake of human readers.
+
+- URB Status word. This is either a letter, or several numbers separated
+  by colons: URB status, interval, start frame, and error count. Unlike the
+  "address" word, all fields save the status are optional. Interval is printed
+  only for interrupt and isochronous URBs. Start frame is printed only for
+  isochronous URBs. Error count is printed only for isochronous callback
+  events.
+
+  The status field is a decimal number, sometimes negative, which represents
+  a "status" field of the URB. This field makes no sense for submissions, but
+  is present anyway to help scripts with parsing. When an error occurs, the
+  field contains the error code.
+
+  In case of a submission of a Control packet, this field contains a Setup Tag
+  instead of an group of numbers. It is easy to tell whether the Setup Tag is
+  present because it is never a number. Thus if scripts find a set of numbers
+  in this word, they proceed to read Data Length (except for isochronous URBs).
+  If they find something else, like a letter, they read the setup packet before
+  reading the Data Length or isochronous descriptors.
+
+- Setup packet, if present, consists of 5 words: one of each for bmRequestType,
+  bRequest, wValue, wIndex, wLength, as specified by the USB Specification 2.0.
+  These words are safe to decode if Setup Tag was 's'. Otherwise, the setup
+  packet was present, but not captured, and the fields contain filler.
+
+- Number of isochronous frame descriptors and descriptors themselves.
+  If an Isochronous transfer event has a set of descriptors, a total number
+  of them in an URB is printed first, then a word per descriptor, up to a
+  total of 5. The word consists of 3 colon-separated decimal numbers for
+  status, offset, and length respectively. For submissions, initial length
+  is reported. For callbacks, actual length is reported.
+
+- Data Length. For submissions, this is the requested length. For callbacks,
+  this is the actual length.
+
+- Data tag. The usbmon may not always capture data, even if length is nonzero.
+  The data words are present only if this tag is '='.
+
+- Data words follow, in big endian hexadecimal format. Notice that they are
+  not machine words, but really just a byte stream split into words to make
+  it easier to read. Thus, the last word may contain from one to four bytes.
+  The length of collected data is limited and can be less than the data length
+  reported in the Data Length word. In the case of an Isochronous input (Zi)
+  completion where the received data is sparse in the buffer, the length of
+  the collected data can be greater than the Data Length value (because Data
+  Length counts only the bytes that were received whereas the Data words
+  contain the entire transfer buffer).
+
+Examples:
+
+An input control transfer to get a port status::
+
+  d5ea89a0 3575914555 S Ci:1:001:0 s a3 00 0000 0003 0004 4 <
+  d5ea89a0 3575914560 C Ci:1:001:0 0 4 = 01050000
+
+An output bulk transfer to send a SCSI command 0x28 (READ_10) in a 31-byte
+Bulk wrapper to a storage device at address 5::
+
+  dd65f0e8 4128379752 S Bo:1:005:2 -115 31 = 55534243 ad000000 00800000 80010a28 20000000 20000040 00000000 000000
+  dd65f0e8 4128379808 C Bo:1:005:2 0 31 >
+
+Raw binary format and API
+=========================
+
+The overall architecture of the API is about the same as the one above,
+only the events are delivered in binary format. Each event is sent in
+the following structure (its name is made up, so that we can refer to it)::
+
+  struct usbmon_packet {
+       u64 id;                 /*  0: URB ID - from submission to callback */
+       unsigned char type;     /*  8: Same as text; extensible. */
+       unsigned char xfer_type; /*    ISO (0), Intr, Control, Bulk (3) */
+       unsigned char epnum;    /*     Endpoint number and transfer direction */
+       unsigned char devnum;   /*     Device address */
+       u16 busnum;             /* 12: Bus number */
+       char flag_setup;        /* 14: Same as text */
+       char flag_data;         /* 15: Same as text; Binary zero is OK. */
+       s64 ts_sec;             /* 16: gettimeofday */
+       s32 ts_usec;            /* 24: gettimeofday */
+       int status;             /* 28: */
+       unsigned int length;    /* 32: Length of data (submitted or actual) */
+       unsigned int len_cap;   /* 36: Delivered length */
+       union {                 /* 40: */
+               unsigned char setup[SETUP_LEN]; /* Only for Control S-type */
+               struct iso_rec {                /* Only for ISO */
+                       int error_count;
+                       int numdesc;
+               } iso;
+       } s;
+       int interval;           /* 48: Only for Interrupt and ISO */
+       int start_frame;        /* 52: For ISO */
+       unsigned int xfer_flags; /* 56: copy of URB's transfer_flags */
+       unsigned int ndesc;     /* 60: Actual number of ISO descriptors */
+  };                           /* 64 total length */
+
+These events can be received from a character device by reading with read(2),
+with an ioctl(2), or by accessing the buffer with mmap. However, read(2)
+only returns first 48 bytes for compatibility reasons.
+
+The character device is usually called /dev/usbmonN, where N is the USB bus
+number. Number zero (/dev/usbmon0) is special and means "all buses".
+Note that specific naming policy is set by your Linux distribution.
+
+If you create /dev/usbmon0 by hand, make sure that it is owned by root
+and has mode 0600. Otherwise, unprivileged users will be able to snoop
+keyboard traffic.
+
+The following ioctl calls are available, with MON_IOC_MAGIC 0x92:
+
+ MON_IOCQ_URB_LEN, defined as _IO(MON_IOC_MAGIC, 1)
+
+This call returns the length of data in the next event. Note that majority of
+events contain no data, so if this call returns zero, it does not mean that
+no events are available.
+
+ MON_IOCG_STATS, defined as _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)
+
+The argument is a pointer to the following structure::
+
+  struct mon_bin_stats {
+       u32 queued;
+       u32 dropped;
+  };
+
+The member "queued" refers to the number of events currently queued in the
+buffer (and not to the number of events processed since the last reset).
+
+The member "dropped" is the number of events lost since the last call
+to MON_IOCG_STATS.
+
+ MON_IOCT_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 4)
+
+This call sets the buffer size. The argument is the size in bytes.
+The size may be rounded down to the next chunk (or page). If the requested
+size is out of [unspecified] bounds for this kernel, the call fails with
+-EINVAL.
+
+ MON_IOCQ_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 5)
+
+This call returns the current size of the buffer in bytes.
+
+ MON_IOCX_GET, defined as _IOW(MON_IOC_MAGIC, 6, struct mon_get_arg)
+ MON_IOCX_GETX, defined as _IOW(MON_IOC_MAGIC, 10, struct mon_get_arg)
+
+These calls wait for events to arrive if none were in the kernel buffer,
+then return the first event. The argument is a pointer to the following
+structure::
+
+  struct mon_get_arg {
+       struct usbmon_packet *hdr;
+       void *data;
+       size_t alloc;           /* Length of data (can be zero) */
+  };
+
+Before the call, hdr, data, and alloc should be filled. Upon return, the area
+pointed by hdr contains the next event structure, and the data buffer contains
+the data, if any. The event is removed from the kernel buffer.
+
+The MON_IOCX_GET copies 48 bytes to hdr area, MON_IOCX_GETX copies 64 bytes.
+
+ MON_IOCX_MFETCH, defined as _IOWR(MON_IOC_MAGIC, 7, struct mon_mfetch_arg)
+
+This ioctl is primarily used when the application accesses the buffer
+with mmap(2). Its argument is a pointer to the following structure::
+
+  struct mon_mfetch_arg {
+       uint32_t *offvec;       /* Vector of events fetched */
+       uint32_t nfetch;        /* Number of events to fetch (out: fetched) */
+       uint32_t nflush;        /* Number of events to flush */
+  };
+
+The ioctl operates in 3 stages.
+
+First, it removes and discards up to nflush events from the kernel buffer.
+The actual number of events discarded is returned in nflush.
+
+Second, it waits for an event to be present in the buffer, unless the pseudo-
+device is open with O_NONBLOCK.
+
+Third, it extracts up to nfetch offsets into the mmap buffer, and stores
+them into the offvec. The actual number of event offsets is stored into
+the nfetch.
+
+ MON_IOCH_MFLUSH, defined as _IO(MON_IOC_MAGIC, 8)
+
+This call removes a number of events from the kernel buffer. Its argument
+is the number of events to remove. If the buffer contains fewer events
+than requested, all events present are removed, and no error is reported.
+This works when no events are available too.
+
+ FIONBIO
+
+The ioctl FIONBIO may be implemented in the future, if there's a need.
+
+In addition to ioctl(2) and read(2), the special file of binary API can
+be polled with select(2) and poll(2). But lseek(2) does not work.
+
+* Memory-mapped access of the kernel buffer for the binary API
+
+The basic idea is simple:
+
+To prepare, map the buffer by getting the current size, then using mmap(2).
+Then, execute a loop similar to the one written in pseudo-code below::
+
+   struct mon_mfetch_arg fetch;
+   struct usbmon_packet *hdr;
+   int nflush = 0;
+   for (;;) {
+      fetch.offvec = vec; // Has N 32-bit words
+      fetch.nfetch = N;   // Or less than N
+      fetch.nflush = nflush;
+      ioctl(fd, MON_IOCX_MFETCH, &fetch);   // Process errors, too
+      nflush = fetch.nfetch;       // This many packets to flush when done
+      for (i = 0; i < nflush; i++) {
+         hdr = (struct ubsmon_packet *) &mmap_area[vec[i]];
+         if (hdr->type == '@')     // Filler packet
+            continue;
+         caddr_t data = &mmap_area[vec[i]] + 64;
+         process_packet(hdr, data);
+      }
+   }
+
+Thus, the main idea is to execute only one ioctl per N events.
+
+Although the buffer is circular, the returned headers and data do not cross
+the end of the buffer, so the above pseudo-code does not need any gathering.
diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt
deleted file mode 100644 (file)
index b0bd510..0000000
+++ /dev/null
@@ -1,375 +0,0 @@
-======
-usbmon
-======
-
-Introduction
-============
-
-The name "usbmon" in lowercase refers to a facility in kernel which is
-used to collect traces of I/O on the USB bus. This function is analogous
-to a packet socket used by network monitoring tools such as tcpdump(1)
-or Ethereal. Similarly, it is expected that a tool such as usbdump or
-USBMon (with uppercase letters) is used to examine raw traces produced
-by usbmon.
-
-The usbmon reports requests made by peripheral-specific drivers to Host
-Controller Drivers (HCD). So, if HCD is buggy, the traces reported by
-usbmon may not correspond to bus transactions precisely. This is the same
-situation as with tcpdump.
-
-Two APIs are currently implemented: "text" and "binary". The binary API
-is available through a character device in /dev namespace and is an ABI.
-The text API is deprecated since 2.6.35, but available for convenience.
-
-How to use usbmon to collect raw text traces
-============================================
-
-Unlike the packet socket, usbmon has an interface which provides traces
-in a text format. This is used for two purposes. First, it serves as a
-common trace exchange format for tools while more sophisticated formats
-are finalized. Second, humans can read it in case tools are not available.
-
-To collect a raw text trace, execute following steps.
-
-1. Prepare
-----------
-
-Mount debugfs (it has to be enabled in your kernel configuration), and
-load the usbmon module (if built as module). The second step is skipped
-if usbmon is built into the kernel::
-
-       # mount -t debugfs none_debugs /sys/kernel/debug
-       # modprobe usbmon
-       #
-
-Verify that bus sockets are present:
-
-       # ls /sys/kernel/debug/usb/usbmon
-       0s  0u  1s  1t  1u  2s  2t  2u  3s  3t  3u  4s  4t  4u
-       #
-
-Now you can choose to either use the socket '0u' (to capture packets on all
-buses), and skip to step #3, or find the bus used by your device with step #2.
-This allows to filter away annoying devices that talk continuously.
-
-2. Find which bus connects to the desired device
-------------------------------------------------
-
-Run "cat /sys/kernel/debug/usb/devices", and find the T-line which corresponds
-to the device. Usually you do it by looking for the vendor string. If you have
-many similar devices, unplug one and compare the two
-/sys/kernel/debug/usb/devices outputs. The T-line will have a bus number.
-
-Example::
-
-  T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 0
-  D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
-  P:  Vendor=0557 ProdID=2004 Rev= 1.00
-  S:  Manufacturer=ATEN
-  S:  Product=UC100KM V2.00
-
-"Bus=03" means it's bus 3. Alternatively, you can look at the output from
-"lsusb" and get the bus number from the appropriate line. Example:
-
-Bus 003 Device 002: ID 0557:2004 ATEN UC100KM V2.00
-
-3. Start 'cat'
---------------
-
-::
-
-       # cat /sys/kernel/debug/usb/usbmon/3u > /tmp/1.mon.out
-
-to listen on a single bus, otherwise, to listen on all buses, type::
-
-       # cat /sys/kernel/debug/usb/usbmon/0u > /tmp/1.mon.out
-
-This process will read until it is killed. Naturally, the output can be
-redirected to a desirable location. This is preferred, because it is going
-to be quite long.
-
-4. Perform the desired operation on the USB bus
------------------------------------------------
-
-This is where you do something that creates the traffic: plug in a flash key,
-copy files, control a webcam, etc.
-
-5. Kill cat
------------
-
-Usually it's done with a keyboard interrupt (Control-C).
-
-At this point the output file (/tmp/1.mon.out in this example) can be saved,
-sent by e-mail, or inspected with a text editor. In the last case make sure
-that the file size is not excessive for your favourite editor.
-
-Raw text data format
-====================
-
-Two formats are supported currently: the original, or '1t' format, and
-the '1u' format. The '1t' format is deprecated in kernel 2.6.21. The '1u'
-format adds a few fields, such as ISO frame descriptors, interval, etc.
-It produces slightly longer lines, but otherwise is a perfect superset
-of '1t' format.
-
-If it is desired to recognize one from the other in a program, look at the
-"address" word (see below), where '1u' format adds a bus number. If 2 colons
-are present, it's the '1t' format, otherwise '1u'.
-
-Any text format data consists of a stream of events, such as URB submission,
-URB callback, submission error. Every event is a text line, which consists
-of whitespace separated words. The number or position of words may depend
-on the event type, but there is a set of words, common for all types.
-
-Here is the list of words, from left to right:
-
-- URB Tag. This is used to identify URBs, and is normally an in-kernel address
-  of the URB structure in hexadecimal, but can be a sequence number or any
-  other unique string, within reason.
-
-- Timestamp in microseconds, a decimal number. The timestamp's resolution
-  depends on available clock, and so it can be much worse than a microsecond
-  (if the implementation uses jiffies, for example).
-
-- Event Type. This type refers to the format of the event, not URB type.
-  Available types are: S - submission, C - callback, E - submission error.
-
-- "Address" word (formerly a "pipe"). It consists of four fields, separated by
-  colons: URB type and direction, Bus number, Device address, Endpoint number.
-  Type and direction are encoded with two bytes in the following manner:
-
-    == ==   =============================
-    Ci Co   Control input and output
-    Zi Zo   Isochronous input and output
-    Ii Io   Interrupt input and output
-    Bi Bo   Bulk input and output
-    == ==   =============================
-
-  Bus number, Device address, and Endpoint are decimal numbers, but they may
-  have leading zeros, for the sake of human readers.
-
-- URB Status word. This is either a letter, or several numbers separated
-  by colons: URB status, interval, start frame, and error count. Unlike the
-  "address" word, all fields save the status are optional. Interval is printed
-  only for interrupt and isochronous URBs. Start frame is printed only for
-  isochronous URBs. Error count is printed only for isochronous callback
-  events.
-
-  The status field is a decimal number, sometimes negative, which represents
-  a "status" field of the URB. This field makes no sense for submissions, but
-  is present anyway to help scripts with parsing. When an error occurs, the
-  field contains the error code.
-
-  In case of a submission of a Control packet, this field contains a Setup Tag
-  instead of an group of numbers. It is easy to tell whether the Setup Tag is
-  present because it is never a number. Thus if scripts find a set of numbers
-  in this word, they proceed to read Data Length (except for isochronous URBs).
-  If they find something else, like a letter, they read the setup packet before
-  reading the Data Length or isochronous descriptors.
-
-- Setup packet, if present, consists of 5 words: one of each for bmRequestType,
-  bRequest, wValue, wIndex, wLength, as specified by the USB Specification 2.0.
-  These words are safe to decode if Setup Tag was 's'. Otherwise, the setup
-  packet was present, but not captured, and the fields contain filler.
-
-- Number of isochronous frame descriptors and descriptors themselves.
-  If an Isochronous transfer event has a set of descriptors, a total number
-  of them in an URB is printed first, then a word per descriptor, up to a
-  total of 5. The word consists of 3 colon-separated decimal numbers for
-  status, offset, and length respectively. For submissions, initial length
-  is reported. For callbacks, actual length is reported.
-
-- Data Length. For submissions, this is the requested length. For callbacks,
-  this is the actual length.
-
-- Data tag. The usbmon may not always capture data, even if length is nonzero.
-  The data words are present only if this tag is '='.
-
-- Data words follow, in big endian hexadecimal format. Notice that they are
-  not machine words, but really just a byte stream split into words to make
-  it easier to read. Thus, the last word may contain from one to four bytes.
-  The length of collected data is limited and can be less than the data length
-  reported in the Data Length word. In the case of an Isochronous input (Zi)
-  completion where the received data is sparse in the buffer, the length of
-  the collected data can be greater than the Data Length value (because Data
-  Length counts only the bytes that were received whereas the Data words
-  contain the entire transfer buffer).
-
-Examples:
-
-An input control transfer to get a port status::
-
-  d5ea89a0 3575914555 S Ci:1:001:0 s a3 00 0000 0003 0004 4 <
-  d5ea89a0 3575914560 C Ci:1:001:0 0 4 = 01050000
-
-An output bulk transfer to send a SCSI command 0x28 (READ_10) in a 31-byte
-Bulk wrapper to a storage device at address 5::
-
-  dd65f0e8 4128379752 S Bo:1:005:2 -115 31 = 55534243 ad000000 00800000 80010a28 20000000 20000040 00000000 000000
-  dd65f0e8 4128379808 C Bo:1:005:2 0 31 >
-
-Raw binary format and API
-=========================
-
-The overall architecture of the API is about the same as the one above,
-only the events are delivered in binary format. Each event is sent in
-the following structure (its name is made up, so that we can refer to it)::
-
-  struct usbmon_packet {
-       u64 id;                 /*  0: URB ID - from submission to callback */
-       unsigned char type;     /*  8: Same as text; extensible. */
-       unsigned char xfer_type; /*    ISO (0), Intr, Control, Bulk (3) */
-       unsigned char epnum;    /*     Endpoint number and transfer direction */
-       unsigned char devnum;   /*     Device address */
-       u16 busnum;             /* 12: Bus number */
-       char flag_setup;        /* 14: Same as text */
-       char flag_data;         /* 15: Same as text; Binary zero is OK. */
-       s64 ts_sec;             /* 16: gettimeofday */
-       s32 ts_usec;            /* 24: gettimeofday */
-       int status;             /* 28: */
-       unsigned int length;    /* 32: Length of data (submitted or actual) */
-       unsigned int len_cap;   /* 36: Delivered length */
-       union {                 /* 40: */
-               unsigned char setup[SETUP_LEN]; /* Only for Control S-type */
-               struct iso_rec {                /* Only for ISO */
-                       int error_count;
-                       int numdesc;
-               } iso;
-       } s;
-       int interval;           /* 48: Only for Interrupt and ISO */
-       int start_frame;        /* 52: For ISO */
-       unsigned int xfer_flags; /* 56: copy of URB's transfer_flags */
-       unsigned int ndesc;     /* 60: Actual number of ISO descriptors */
-  };                           /* 64 total length */
-
-These events can be received from a character device by reading with read(2),
-with an ioctl(2), or by accessing the buffer with mmap. However, read(2)
-only returns first 48 bytes for compatibility reasons.
-
-The character device is usually called /dev/usbmonN, where N is the USB bus
-number. Number zero (/dev/usbmon0) is special and means "all buses".
-Note that specific naming policy is set by your Linux distribution.
-
-If you create /dev/usbmon0 by hand, make sure that it is owned by root
-and has mode 0600. Otherwise, unprivileged users will be able to snoop
-keyboard traffic.
-
-The following ioctl calls are available, with MON_IOC_MAGIC 0x92:
-
- MON_IOCQ_URB_LEN, defined as _IO(MON_IOC_MAGIC, 1)
-
-This call returns the length of data in the next event. Note that majority of
-events contain no data, so if this call returns zero, it does not mean that
-no events are available.
-
- MON_IOCG_STATS, defined as _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)
-
-The argument is a pointer to the following structure::
-
-  struct mon_bin_stats {
-       u32 queued;
-       u32 dropped;
-  };
-
-The member "queued" refers to the number of events currently queued in the
-buffer (and not to the number of events processed since the last reset).
-
-The member "dropped" is the number of events lost since the last call
-to MON_IOCG_STATS.
-
- MON_IOCT_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 4)
-
-This call sets the buffer size. The argument is the size in bytes.
-The size may be rounded down to the next chunk (or page). If the requested
-size is out of [unspecified] bounds for this kernel, the call fails with
--EINVAL.
-
- MON_IOCQ_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 5)
-
-This call returns the current size of the buffer in bytes.
-
- MON_IOCX_GET, defined as _IOW(MON_IOC_MAGIC, 6, struct mon_get_arg)
- MON_IOCX_GETX, defined as _IOW(MON_IOC_MAGIC, 10, struct mon_get_arg)
-
-These calls wait for events to arrive if none were in the kernel buffer,
-then return the first event. The argument is a pointer to the following
-structure::
-
-  struct mon_get_arg {
-       struct usbmon_packet *hdr;
-       void *data;
-       size_t alloc;           /* Length of data (can be zero) */
-  };
-
-Before the call, hdr, data, and alloc should be filled. Upon return, the area
-pointed by hdr contains the next event structure, and the data buffer contains
-the data, if any. The event is removed from the kernel buffer.
-
-The MON_IOCX_GET copies 48 bytes to hdr area, MON_IOCX_GETX copies 64 bytes.
-
- MON_IOCX_MFETCH, defined as _IOWR(MON_IOC_MAGIC, 7, struct mon_mfetch_arg)
-
-This ioctl is primarily used when the application accesses the buffer
-with mmap(2). Its argument is a pointer to the following structure::
-
-  struct mon_mfetch_arg {
-       uint32_t *offvec;       /* Vector of events fetched */
-       uint32_t nfetch;        /* Number of events to fetch (out: fetched) */
-       uint32_t nflush;        /* Number of events to flush */
-  };
-
-The ioctl operates in 3 stages.
-
-First, it removes and discards up to nflush events from the kernel buffer.
-The actual number of events discarded is returned in nflush.
-
-Second, it waits for an event to be present in the buffer, unless the pseudo-
-device is open with O_NONBLOCK.
-
-Third, it extracts up to nfetch offsets into the mmap buffer, and stores
-them into the offvec. The actual number of event offsets is stored into
-the nfetch.
-
- MON_IOCH_MFLUSH, defined as _IO(MON_IOC_MAGIC, 8)
-
-This call removes a number of events from the kernel buffer. Its argument
-is the number of events to remove. If the buffer contains fewer events
-than requested, all events present are removed, and no error is reported.
-This works when no events are available too.
-
- FIONBIO
-
-The ioctl FIONBIO may be implemented in the future, if there's a need.
-
-In addition to ioctl(2) and read(2), the special file of binary API can
-be polled with select(2) and poll(2). But lseek(2) does not work.
-
-* Memory-mapped access of the kernel buffer for the binary API
-
-The basic idea is simple:
-
-To prepare, map the buffer by getting the current size, then using mmap(2).
-Then, execute a loop similar to the one written in pseudo-code below::
-
-   struct mon_mfetch_arg fetch;
-   struct usbmon_packet *hdr;
-   int nflush = 0;
-   for (;;) {
-      fetch.offvec = vec; // Has N 32-bit words
-      fetch.nfetch = N;   // Or less than N
-      fetch.nflush = nflush;
-      ioctl(fd, MON_IOCX_MFETCH, &fetch);   // Process errors, too
-      nflush = fetch.nfetch;       // This many packets to flush when done
-      for (i = 0; i < nflush; i++) {
-         hdr = (struct ubsmon_packet *) &mmap_area[vec[i]];
-         if (hdr->type == '@')     // Filler packet
-            continue;
-         caddr_t data = &mmap_area[vec[i]] + 64;
-         process_packet(hdr, data);
-      }
-   }
-
-Thus, the main idea is to execute only one ioctl per N events.
-
-Although the buffer is circular, the returned headers and data do not cross
-the end of the buffer, so the above pseudo-code does not need any gathering.
diff --git a/Documentation/usb/wusb-design-overview.rst b/Documentation/usb/wusb-design-overview.rst
new file mode 100644 (file)
index 0000000..dc5e216
--- /dev/null
@@ -0,0 +1,457 @@
+================================
+Linux UWB + Wireless USB + WiNET
+================================
+
+   Copyright (C) 2005-2006 Intel Corporation
+
+   Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.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 Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+
+Please visit http://bughost.org/thewiki/Design-overview.txt-1.8 for
+updated content.
+
+    * Design-overview.txt-1.8
+
+This code implements a Ultra Wide Band stack for Linux, as well as
+drivers for the USB based UWB radio controllers defined in the
+Wireless USB 1.0 specification (including Wireless USB host controller
+and an Intel WiNET controller).
+
+.. Contents
+   1. Introduction
+         1. HWA: Host Wire adapters, your Wireless USB dongle
+
+         2. DWA: Device Wired Adaptor, a Wireless USB hub for wired
+            devices
+         3. WHCI: Wireless Host Controller Interface, the PCI WUSB host
+            adapter
+   2. The UWB stack
+         1. Devices and hosts: the basic structure
+
+         2. Host Controller life cycle
+
+         3. On the air: beacons and enumerating the radio neighborhood
+
+         4. Device lists
+         5. Bandwidth allocation
+
+   3. Wireless USB Host Controller drivers
+
+   4. Glossary
+
+
+Introduction
+============
+
+UWB is a wide-band communication protocol that is to serve also as the
+low-level protocol for others (much like TCP sits on IP). Currently
+these others are Wireless USB and TCP/IP, but seems Bluetooth and
+Firewire/1394 are coming along.
+
+UWB uses a band from roughly 3 to 10 GHz, transmitting at a max of
+~-41dB (or 0.074 uW/MHz--geography specific data is still being
+negotiated w/ regulators, so watch for changes). That band is divided in
+a bunch of ~1.5 GHz wide channels (or band groups) composed of three
+subbands/subchannels (528 MHz each). Each channel is independent of each
+other, so you could consider them different "busses". Initially this
+driver considers them all a single one.
+
+Radio time is divided in 65536 us long /superframes/, each one divided
+in 256 256us long /MASs/ (Media Allocation Slots), which are the basic
+time/media allocation units for transferring data. At the beginning of
+each superframe there is a Beacon Period (BP), where every device
+transmit its beacon on a single MAS. The length of the BP depends on how
+many devices are present and the length of their beacons.
+
+Devices have a MAC (fixed, 48 bit address) and a device (changeable, 16
+bit address) and send periodic beacons to advertise themselves and pass
+info on what they are and do. They advertise their capabilities and a
+bunch of other stuff.
+
+The different logical parts of this driver are:
+
+    *
+
+      *UWB*: the Ultra-Wide-Band stack -- manages the radio and
+      associated spectrum to allow for devices sharing it. Allows to
+      control bandwidth assignment, beaconing, scanning, etc
+
+    *
+
+      *WUSB*: the layer that sits on top of UWB to provide Wireless USB.
+      The Wireless USB spec defines means to control a UWB radio and to
+      do the actual WUSB.
+
+
+HWA: Host Wire adapters, your Wireless USB dongle
+-------------------------------------------------
+
+WUSB also defines a device called a Host Wire Adaptor (HWA), which in
+mere terms is a USB dongle that enables your PC to have UWB and Wireless
+USB. The Wireless USB Host Controller in a HWA looks to the host like a
+[Wireless] USB controller connected via USB (!)
+
+The HWA itself is broken in two or three main interfaces:
+
+    *
+
+      *RC*: Radio control -- this implements an interface to the
+      Ultra-Wide-Band radio controller. The driver for this implements a
+      USB-based UWB Radio Controller to the UWB stack.
+
+    *
+
+      *HC*: the wireless USB host controller. It looks like a USB host
+      whose root port is the radio and the WUSB devices connect to it.
+      To the system it looks like a separate USB host. The driver (will)
+      implement a USB host controller (similar to UHCI, OHCI or EHCI)
+      for which the root hub is the radio...To reiterate: it is a USB
+      controller that is connected via USB instead of PCI.
+
+    *
+
+      *WINET*: some HW provide a WiNET interface (IP over UWB). This
+      package provides a driver for it (it looks like a network
+      interface, winetX). The driver detects when there is a link up for
+      their type and kick into gear.
+
+
+DWA: Device Wired Adaptor, a Wireless USB hub for wired devices
+---------------------------------------------------------------
+
+These are the complement to HWAs. They are a USB host for connecting
+wired devices, but it is connected to your PC connected via Wireless
+USB. To the system it looks like yet another USB host. To the untrained
+eye, it looks like a hub that connects upstream wirelessly.
+
+We still offer no support for this; however, it should share a lot of
+code with the HWA-RC driver; there is a bunch of factorization work that
+has been done to support that in upcoming releases.
+
+
+WHCI: Wireless Host Controller Interface, the PCI WUSB host adapter
+-------------------------------------------------------------------
+
+This is your usual PCI device that implements WHCI. Similar in concept
+to EHCI, it allows your wireless USB devices (including DWAs) to connect
+to your host via a PCI interface. As in the case of the HWA, it has a
+Radio Control interface and the WUSB Host Controller interface per se.
+
+There is still no driver support for this, but will be in upcoming
+releases.
+
+
+The UWB stack
+=============
+
+The main mission of the UWB stack is to keep a tally of which devices
+are in radio proximity to allow drivers to connect to them. As well, it
+provides an API for controlling the local radio controllers (RCs from
+now on), such as to start/stop beaconing, scan, allocate bandwidth, etc.
+
+
+Devices and hosts: the basic structure
+--------------------------------------
+
+The main building block here is the UWB device (struct uwb_dev). For
+each device that pops up in radio presence (ie: the UWB host receives a
+beacon from it) you get a struct uwb_dev that will show up in
+/sys/bus/uwb/devices.
+
+For each RC that is detected, a new struct uwb_rc and struct uwb_dev are
+created. An entry is also created in /sys/class/uwb_rc for each RC.
+
+Each RC driver is implemented by a separate driver that plugs into the
+interface that the UWB stack provides through a struct uwb_rc_ops. The
+spec creators have been nice enough to make the message format the same
+for HWA and WHCI RCs, so the driver is really a very thin transport that
+moves the requests from the UWB API to the device [/uwb_rc_ops->cmd()/]
+and sends the replies and notifications back to the API
+[/uwb_rc_neh_grok()/]. Notifications are handled to the UWB daemon, that
+is chartered, among other things, to keep the tab of how the UWB radio
+neighborhood looks, creating and destroying devices as they show up or
+disappear.
+
+Command execution is very simple: a command block is sent and a event
+block or reply is expected back. For sending/receiving command/events, a
+handle called /neh/ (Notification/Event Handle) is opened with
+/uwb_rc_neh_open()/.
+
+The HWA-RC (USB dongle) driver (drivers/uwb/hwa-rc.c) does this job for
+the USB connected HWA. Eventually, drivers/whci-rc.c will do the same
+for the PCI connected WHCI controller.
+
+
+Host Controller life cycle
+--------------------------
+
+So let's say we connect a dongle to the system: it is detected and
+firmware uploaded if needed [for Intel's i1480
+/drivers/uwb/ptc/usb.c:ptc_usb_probe()/] and then it is reenumerated.
+Now we have a real HWA device connected and
+/drivers/uwb/hwa-rc.c:hwarc_probe()/ picks it up, that will set up the
+Wire-Adaptor environment and then suck it into the UWB stack's vision of
+the world [/drivers/uwb/lc-rc.c:uwb_rc_add()/].
+
+    *
+
+      [*] The stack should put a new RC to scan for devices
+      [/uwb_rc_scan()/] so it finds what's available around and tries to
+      connect to them, but this is policy stuff and should be driven
+      from user space. As of now, the operator is expected to do it
+      manually; see the release notes for documentation on the procedure.
+
+When a dongle is disconnected, /drivers/uwb/hwa-rc.c:hwarc_disconnect()/
+takes time of tearing everything down safely (or not...).
+
+
+On the air: beacons and enumerating the radio neighborhood
+----------------------------------------------------------
+
+So assuming we have devices and we have agreed for a channel to connect
+on (let's say 9), we put the new RC to beacon:
+
+    *
+
+            $ echo 9 0 > /sys/class/uwb_rc/uwb0/beacon
+
+Now it is visible. If there were other devices in the same radio channel
+and beacon group (that's what the zero is for), the dongle's radio
+control interface will send beacon notifications on its
+notification/event endpoint (NEEP). The beacon notifications are part of
+the event stream that is funneled into the API with
+/drivers/uwb/neh.c:uwb_rc_neh_grok()/ and delivered to the UWBD, the UWB
+daemon through a notification list.
+
+UWBD wakes up and scans the event list; finds a beacon and adds it to
+the BEACON CACHE (/uwb_beca/). If he receives a number of beacons from
+the same device, he considers it to be 'onair' and creates a new device
+[/drivers/uwb/lc-dev.c:uwbd_dev_onair()/]. Similarly, when no beacons
+are received in some time, the device is considered gone and wiped out
+[uwbd calls periodically /uwb/beacon.c:uwb_beca_purge()/ that will purge
+the beacon cache of dead devices].
+
+
+Device lists
+------------
+
+All UWB devices are kept in the list of the struct bus_type uwb_bus_type.
+
+
+Bandwidth allocation
+--------------------
+
+The UWB stack maintains a local copy of DRP availability through
+processing of incoming *DRP Availability Change* notifications. This
+local copy is currently used to present the current bandwidth
+availability to the user through the sysfs file
+/sys/class/uwb_rc/uwbx/bw_avail. In the future the bandwidth
+availability information will be used by the bandwidth reservation
+routines.
+
+The bandwidth reservation routines are in progress and are thus not
+present in the current release. When completed they will enable a user
+to initiate DRP reservation requests through interaction with sysfs. DRP
+reservation requests from remote UWB devices will also be handled. The
+bandwidth management done by the UWB stack will include callbacks to the
+higher layers will enable the higher layers to use the reservations upon
+completion. [Note: The bandwidth reservation work is in progress and
+subject to change.]
+
+
+Wireless USB Host Controller drivers
+====================================
+
+*WARNING* This section needs a lot of work!
+
+As explained above, there are three different types of HCs in the WUSB
+world: HWA-HC, DWA-HC and WHCI-HC.
+
+HWA-HC and DWA-HC share that they are Wire-Adapters (USB or WUSB
+connected controllers), and their transfer management system is almost
+identical. So is their notification delivery system.
+
+HWA-HC and WHCI-HC share that they are both WUSB host controllers, so
+they have to deal with WUSB device life cycle and maintenance, wireless
+root-hub
+
+HWA exposes a Host Controller interface (HWA-HC 0xe0/02/02). This has
+three endpoints (Notifications, Data Transfer In and Data Transfer
+Out--known as NEP, DTI and DTO in the code).
+
+We reserve UWB bandwidth for our Wireless USB Cluster, create a Cluster
+ID and tell the HC to use all that. Then we start it. This means the HC
+starts sending MMCs.
+
+    *
+
+      The MMCs are blocks of data defined somewhere in the WUSB1.0 spec
+      that define a stream in the UWB channel time allocated for sending
+      WUSB IEs (host to device commands/notifications) and Device
+      Notifications (device initiated to host). Each host defines a
+      unique Wireless USB cluster through MMCs. Devices can connect to a
+      single cluster at the time. The IEs are Information Elements, and
+      among them are the bandwidth allocations that tell each device
+      when can they transmit or receive.
+
+Now it all depends on external stimuli.
+
+New device connection
+---------------------
+
+A new device pops up, it scans the radio looking for MMCs that give out
+the existence of Wireless USB channels. Once one (or more) are found,
+selects which one to connect to. Sends a /DN_Connect/ (device
+notification connect) during the DNTS (Device Notification Time
+Slot--announced in the MMCs
+
+HC picks the /DN_Connect/ out (nep module sends to notif.c for delivery
+into /devconnect/). This process starts the authentication process for
+the device. First we allocate a /fake port/ and assign an
+unauthenticated address (128 to 255--what we really do is
+0x80 | fake_port_idx). We fiddle with the fake port status and /hub_wq/
+sees a new connection, so he moves on to enable the fake port with a reset.
+
+So now we are in the reset path -- we know we have a non-yet enumerated
+device with an unauthorized address; we ask user space to authenticate
+(FIXME: not yet done, similar to bluetooth pairing), then we do the key
+exchange (FIXME: not yet done) and issue a /set address 0/ to bring the
+device to the default state. Device is authenticated.
+
+From here, the USB stack takes control through the usb_hcd ops. hub_wq
+has seen the port status changes, as we have been toggling them. It will
+start enumerating and doing transfers through usb_hcd->urb_enqueue() to
+read descriptors and move our data.
+
+Device life cycle and keep alives
+---------------------------------
+
+Every time there is a successful transfer to/from a device, we update a
+per-device activity timestamp. If not, every now and then we check and
+if the activity timestamp gets old, we ping the device by sending it a
+Keep Alive IE; it responds with a /DN_Alive/ pong during the DNTS (this
+arrives to us as a notification through
+devconnect.c:wusb_handle_dn_alive(). If a device times out, we
+disconnect it from the system (cleaning up internal information and
+toggling the bits in the fake hub port, which kicks hub_wq into removing
+the rest of the stuff).
+
+This is done through devconnect:__wusb_check_devs(), which will scan the
+device list looking for whom needs refreshing.
+
+If the device wants to disconnect, it will either die (ugly) or send a
+/DN_Disconnect/ that will prompt a disconnection from the system.
+
+Sending and receiving data
+--------------------------
+
+Data is sent and received through /Remote Pipes/ (rpipes). An rpipe is
+/aimed/ at an endpoint in a WUSB device. This is the same for HWAs and
+DWAs.
+
+Each HC has a number of rpipes and buffers that can be assigned to them;
+when doing a data transfer (xfer), first the rpipe has to be aimed and
+prepared (buffers assigned), then we can start queueing requests for
+data in or out.
+
+Data buffers have to be segmented out before sending--so we send first a
+header (segment request) and then if there is any data, a data buffer
+immediately after to the DTI interface (yep, even the request). If our
+buffer is bigger than the max segment size, then we just do multiple
+requests.
+
+[This sucks, because doing USB scatter gatter in Linux is resource
+intensive, if any...not that the current approach is not. It just has to
+be cleaned up a lot :)].
+
+If reading, we don't send data buffers, just the segment headers saying
+we want to read segments.
+
+When the xfer is executed, we receive a notification that says data is
+ready in the DTI endpoint (handled through
+xfer.c:wa_handle_notif_xfer()). In there we read from the DTI endpoint a
+descriptor that gives us the status of the transfer, its identification
+(given when we issued it) and the segment number. If it was a data read,
+we issue another URB to read into the destination buffer the chunk of
+data coming out of the remote endpoint. Done, wait for the next guy. The
+callbacks for the URBs issued from here are the ones that will declare
+the xfer complete at some point and call its callback.
+
+Seems simple, but the implementation is not trivial.
+
+    *
+
+      *WARNING* Old!!
+
+The main xfer descriptor, wa_xfer (equivalent to a URB) contains an
+array of segments, tallys on segments and buffers and callback
+information. Buried in there is a lot of URBs for executing the segments
+and buffer transfers.
+
+For OUT xfers, there is an array of segments, one URB for each, another
+one of buffer URB. When submitting, we submit URBs for segment request
+1, buffer 1, segment 2, buffer 2...etc. Then we wait on the DTI for xfer
+result data; when all the segments are complete, we call the callback to
+finalize the transfer.
+
+For IN xfers, we only issue URBs for the segments we want to read and
+then wait for the xfer result data.
+
+URB mapping into xfers
+^^^^^^^^^^^^^^^^^^^^^^
+
+This is done by hwahc_op_urb_[en|de]queue(). In enqueue() we aim an
+rpipe to the endpoint where we have to transmit, create a transfer
+context (wa_xfer) and submit it. When the xfer is done, our callback is
+called and we assign the status bits and release the xfer resources.
+
+In dequeue() we are basically cancelling/aborting the transfer. We issue
+a xfer abort request to the HC, cancel all the URBs we had submitted
+and not yet done and when all that is done, the xfer callback will be
+called--this will call the URB callback.
+
+
+Glossary
+========
+
+*DWA* -- Device Wire Adapter
+
+USB host, wired for downstream devices, upstream connects wirelessly
+with Wireless USB.
+
+*EVENT* -- Response to a command on the NEEP
+
+*HWA* -- Host Wire Adapter / USB dongle for UWB and Wireless USB
+
+*NEH* -- Notification/Event Handle
+
+Handle/file descriptor for receiving notifications or events. The WA
+code requires you to get one of this to listen for notifications or
+events on the NEEP.
+
+*NEEP* -- Notification/Event EndPoint
+
+Stuff related to the management of the first endpoint of a HWA USB
+dongle that is used to deliver an stream of events and notifications to
+the host.
+
+*NOTIFICATION* -- Message coming in the NEEP as response to something.
+
+*RC* -- Radio Control
+
+Design-overview.txt-1.8 (last edited 2006-11-04 12:22:24 by
+InakyPerezGonzalez)
diff --git a/Documentation/virtual/index.rst b/Documentation/virtual/index.rst
new file mode 100644 (file)
index 0000000..062ffb5
--- /dev/null
@@ -0,0 +1,18 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+============================
+Linux Virtualization Support
+============================
+
+.. toctree::
+   :maxdepth: 2
+
+   kvm/index
+   paravirt_ops
+
+.. only:: html and subproject
+
+   Indices
+   =======
+
+   * :ref:`genindex`
index 383b292..2cd6250 100644 (file)
@@ -4081,6 +4081,32 @@ KVM_ARM_VCPU_FINALIZE call.
 See KVM_ARM_VCPU_INIT for details of vcpu features that require finalization
 using this ioctl.
 
+4.120 KVM_SET_PMU_EVENT_FILTER
+
+Capability: KVM_CAP_PMU_EVENT_FILTER
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_pmu_event_filter (in)
+Returns: 0 on success, -1 on error
+
+struct kvm_pmu_event_filter {
+       __u32 action;
+       __u32 nevents;
+       __u64 events[0];
+};
+
+This ioctl restricts the set of PMU events that the guest can program.
+The argument holds a list of events which will be allowed or denied.
+The eventsel+umask of each event the guest attempts to program is compared
+against the events field to determine whether the guest should have access.
+This only affects general purpose counters; fixed purpose counters can
+be disabled by changing the perfmon CPUID leaf.
+
+Valid values for 'action':
+#define KVM_PMU_EVENT_ALLOW 0
+#define KVM_PMU_EVENT_DENY 1
+
+
 5. The kvm_run structure
 ------------------------
 
@@ -4909,6 +4935,8 @@ Valid bits in args[0] are
 
 #define KVM_X86_DISABLE_EXITS_MWAIT            (1 << 0)
 #define KVM_X86_DISABLE_EXITS_HLT              (1 << 1)
+#define KVM_X86_DISABLE_EXITS_PAUSE            (1 << 2)
+#define KVM_X86_DISABLE_EXITS_CSTATE           (1 << 3)
 
 Enabling this capability on a VM provides userspace with a way to no
 longer intercept some instructions for improved latency in some
index aafdab8..559586f 100644 (file)
@@ -28,3 +28,34 @@ The following register is defined:
   - Allows any PSCI version implemented by KVM and compatible with
     v0.2 to be set with SET_ONE_REG
   - Affects the whole VM (even if the register view is per-vcpu)
+
+* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
+  Holds the state of the firmware support to mitigate CVE-2017-5715, as
+  offered by KVM to the guest via a HVC call. The workaround is described
+  under SMCCC_ARCH_WORKAROUND_1 in [1].
+  Accepted values are:
+    KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL: KVM does not offer
+      firmware support for the workaround. The mitigation status for the
+      guest is unknown.
+    KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL: The workaround HVC call is
+      available to the guest and required for the mitigation.
+    KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED: The workaround HVC call
+      is available to the guest, but it is not needed on this VCPU.
+
+* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
+  Holds the state of the firmware support to mitigate CVE-2018-3639, as
+  offered by KVM to the guest via a HVC call. The workaround is described
+  under SMCCC_ARCH_WORKAROUND_2 in [1].
+  Accepted values are:
+    KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL: A workaround is not
+      available. KVM does not offer firmware support for the workaround.
+    KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN: The workaround state is
+      unknown. KVM does not offer firmware support for the workaround.
+    KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL: The workaround is available,
+      and can be disabled by a vCPU. If
+      KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED is set, it is active for
+      this vCPU.
+    KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED: The workaround is
+      always active on this vCPU or it is not needed.
+
+[1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
diff --git a/Documentation/virtual/kvm/cpuid.rst b/Documentation/virtual/kvm/cpuid.rst
new file mode 100644 (file)
index 0000000..01b081f
--- /dev/null
@@ -0,0 +1,107 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==============
+KVM CPUID bits
+==============
+
+:Author: Glauber Costa <glommer@gmail.com>
+
+A guest running on a kvm host, can check some of its features using
+cpuid. This is not always guaranteed to work, since userspace can
+mask-out some, or even all KVM-related cpuid features before launching
+a guest.
+
+KVM cpuid functions are:
+
+function: KVM_CPUID_SIGNATURE (0x40000000)
+
+returns::
+
+   eax = 0x40000001
+   ebx = 0x4b4d564b
+   ecx = 0x564b4d56
+   edx = 0x4d
+
+Note that this value in ebx, ecx and edx corresponds to the string "KVMKVMKVM".
+The value in eax corresponds to the maximum cpuid function present in this leaf,
+and will be updated if more functions are added in the future.
+Note also that old hosts set eax value to 0x0. This should
+be interpreted as if the value was 0x40000001.
+This function queries the presence of KVM cpuid leafs.
+
+function: define KVM_CPUID_FEATURES (0x40000001)
+
+returns::
+
+          ebx, ecx
+          eax = an OR'ed group of (1 << flag)
+
+where ``flag`` is defined as below:
+
+================================= =========== ================================
+flag                              value       meaning
+================================= =========== ================================
+KVM_FEATURE_CLOCKSOURCE           0           kvmclock available at msrs
+                                              0x11 and 0x12
+
+KVM_FEATURE_NOP_IO_DELAY          1           not necessary to perform delays
+                                              on PIO operations
+
+KVM_FEATURE_MMU_OP                2           deprecated
+
+KVM_FEATURE_CLOCKSOURCE2          3           kvmclock available at msrs
+
+                                              0x4b564d00 and 0x4b564d01
+KVM_FEATURE_ASYNC_PF              4           async pf can be enabled by
+                                              writing to msr 0x4b564d02
+
+KVM_FEATURE_STEAL_TIME            5           steal time can be enabled by
+                                              writing to msr 0x4b564d03
+
+KVM_FEATURE_PV_EOI                6           paravirtualized end of interrupt
+                                              handler can be enabled by
+                                              writing to msr 0x4b564d04
+
+KVM_FEATURE_PV_UNHAULT            7           guest checks this feature bit
+                                              before enabling paravirtualized
+                                              spinlock support
+
+KVM_FEATURE_PV_TLB_FLUSH          9           guest checks this feature bit
+                                              before enabling paravirtualized
+                                              tlb flush
+
+KVM_FEATURE_ASYNC_PF_VMEXIT       10          paravirtualized async PF VM EXIT
+                                              can be enabled by setting bit 2
+                                              when writing to msr 0x4b564d02
+
+KVM_FEATURE_PV_SEND_IPI           11          guest checks this feature bit
+                                              before enabling paravirtualized
+                                              sebd IPIs
+
+KVM_FEATURE_PV_POLL_CONTROL       12          host-side polling on HLT can
+                                              be disabled by writing
+                                              to msr 0x4b564d05.
+
+KVM_FEATURE_PV_SCHED_YIELD        13          guest checks this feature bit
+                                              before using paravirtualized
+                                              sched yield.
+
+KVM_FEATURE_CLOCSOURCE_STABLE_BIT 24          host will warn if no guest-side
+                                              per-cpu warps are expeced in
+                                              kvmclock
+================================= =========== ================================
+
+::
+
+      edx = an OR'ed group of (1 << flag)
+
+Where ``flag`` here is defined as below:
+
+================== ============ =================================
+flag               value        meaning
+================== ============ =================================
+KVM_HINTS_REALTIME 0            guest checks this feature bit to
+                                determine that vCPUs are never
+                                preempted for an unlimited time
+                                allowing optimizations
+================== ============ =================================
diff --git a/Documentation/virtual/kvm/cpuid.txt b/Documentation/virtual/kvm/cpuid.txt
deleted file mode 100644 (file)
index 97ca194..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-KVM CPUID bits
-Glauber Costa <glommer@redhat.com>, Red Hat Inc, 2010
-=====================================================
-
-A guest running on a kvm host, can check some of its features using
-cpuid. This is not always guaranteed to work, since userspace can
-mask-out some, or even all KVM-related cpuid features before launching
-a guest.
-
-KVM cpuid functions are:
-
-function: KVM_CPUID_SIGNATURE (0x40000000)
-returns : eax = 0x40000001,
-          ebx = 0x4b4d564b,
-          ecx = 0x564b4d56,
-          edx = 0x4d.
-Note that this value in ebx, ecx and edx corresponds to the string "KVMKVMKVM".
-The value in eax corresponds to the maximum cpuid function present in this leaf,
-and will be updated if more functions are added in the future.
-Note also that old hosts set eax value to 0x0. This should
-be interpreted as if the value was 0x40000001.
-This function queries the presence of KVM cpuid leafs.
-
-
-function: define KVM_CPUID_FEATURES (0x40000001)
-returns : ebx, ecx
-          eax = an OR'ed group of (1 << flag), where each flags is:
-
-
-flag                               || value || meaning
-=============================================================================
-KVM_FEATURE_CLOCKSOURCE            ||     0 || kvmclock available at msrs
-                                   ||       || 0x11 and 0x12.
-------------------------------------------------------------------------------
-KVM_FEATURE_NOP_IO_DELAY           ||     1 || not necessary to perform delays
-                                   ||       || on PIO operations.
-------------------------------------------------------------------------------
-KVM_FEATURE_MMU_OP                 ||     2 || deprecated.
-------------------------------------------------------------------------------
-KVM_FEATURE_CLOCKSOURCE2           ||     3 || kvmclock available at msrs
-                                   ||       || 0x4b564d00 and 0x4b564d01
-------------------------------------------------------------------------------
-KVM_FEATURE_ASYNC_PF               ||     4 || async pf can be enabled by
-                                   ||       || writing to msr 0x4b564d02
-------------------------------------------------------------------------------
-KVM_FEATURE_STEAL_TIME             ||     5 || steal time can be enabled by
-                                   ||       || writing to msr 0x4b564d03.
-------------------------------------------------------------------------------
-KVM_FEATURE_PV_EOI                 ||     6 || paravirtualized end of interrupt
-                                   ||       || handler can be enabled by writing
-                                   ||       || to msr 0x4b564d04.
-------------------------------------------------------------------------------
-KVM_FEATURE_PV_UNHALT              ||     7 || guest checks this feature bit
-                                   ||       || before enabling paravirtualized
-                                   ||       || spinlock support.
-------------------------------------------------------------------------------
-KVM_FEATURE_PV_TLB_FLUSH           ||     9 || guest checks this feature bit
-                                   ||       || before enabling paravirtualized
-                                   ||       || tlb flush.
-------------------------------------------------------------------------------
-KVM_FEATURE_ASYNC_PF_VMEXIT        ||    10 || paravirtualized async PF VM exit
-                                   ||       || can be enabled by setting bit 2
-                                   ||       || when writing to msr 0x4b564d02
-------------------------------------------------------------------------------
-KVM_FEATURE_PV_SEND_IPI            ||    11 || guest checks this feature bit
-                                   ||       || before using paravirtualized
-                                   ||       || send IPIs.
-------------------------------------------------------------------------------
-KVM_FEATURE_CLOCKSOURCE_STABLE_BIT ||    24 || host will warn if no guest-side
-                                   ||       || per-cpu warps are expected in
-                                   ||       || kvmclock.
-------------------------------------------------------------------------------
-
-          edx = an OR'ed group of (1 << flag), where each flags is:
-
-
-flag                               || value || meaning
-==================================================================================
-KVM_HINTS_REALTIME                 ||     0 || guest checks this feature bit to
-                                   ||       || determine that vCPUs are never
-                                   ||       || preempted for an unlimited time,
-                                   ||       || allowing optimizations
-----------------------------------------------------------------------------------
index da24c13..da21065 100644 (file)
@@ -141,3 +141,14 @@ a0 corresponds to the APIC ID in the third argument (a2), bit 1
 corresponds to the APIC ID a2+1, and so on.
 
 Returns the number of CPUs to which the IPIs were delivered successfully.
+
+7. KVM_HC_SCHED_YIELD
+------------------------
+Architecture: x86
+Status: active
+Purpose: Hypercall used to yield if the IPI target vCPU is preempted
+
+a0: destination APIC ID
+
+Usage example: When sending a call-function IPI-many to vCPUs, yield if
+any of the IPI target vCPUs was preempted.
diff --git a/Documentation/virtual/kvm/index.rst b/Documentation/virtual/kvm/index.rst
new file mode 100644 (file)
index 0000000..0b206a0
--- /dev/null
@@ -0,0 +1,11 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===
+KVM
+===
+
+.. toctree::
+   :maxdepth: 2
+
+   amd-memory-encryption
+   cpuid
index 1bb8bca..635cd6e 100644 (file)
@@ -15,8 +15,6 @@ The acquisition orders for mutexes are as follows:
 
 On x86, vcpu->mutex is taken outside kvm->arch.hyperv.hv_lock.
 
-For spinlocks, kvm_lock is taken outside kvm->mmu_lock.
-
 Everything else is a leaf: no other lock is taken inside the critical
 sections.
 
@@ -169,7 +167,7 @@ which time it will be set using the Dirty tracking mechanism described above.
 ------------
 
 Name:          kvm_lock
-Type:          spinlock_t
+Type:          mutex
 Arch:          any
 Protects:      - vm_list
 
index f3f0d57..df1f433 100644 (file)
@@ -273,3 +273,12 @@ MSR_KVM_EOI_EN: 0x4b564d04
        guest must both read the least significant bit in the memory area and
        clear it using a single CPU instruction, such as test and clear, or
        compare and exchange.
+
+MSR_KVM_POLL_CONTROL: 0x4b564d05
+       Control host-side polling.
+
+       data: Bit 0 enables (1) or disables (0) host-side HLT polling logic.
+
+       KVM guests can request the host not to poll on HLT, for example if
+       they are performing polling themselves.
+
diff --git a/Documentation/virtual/paravirt_ops.rst b/Documentation/virtual/paravirt_ops.rst
new file mode 100644 (file)
index 0000000..6b789d2
--- /dev/null
@@ -0,0 +1,35 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+============
+Paravirt_ops
+============
+
+Linux provides support for different hypervisor virtualization technologies.
+Historically different binary kernels would be required in order to support
+different hypervisors, this restriction was removed with pv_ops.
+Linux pv_ops is a virtualization API which enables support for different
+hypervisors. It allows each hypervisor to override critical operations and
+allows a single kernel binary to run on all supported execution environments
+including native machine -- without any hypervisors.
+
+pv_ops provides a set of function pointers which represent operations
+corresponding to low level critical instructions and high level
+functionalities in various areas. pv-ops allows for optimizations at run
+time by enabling binary patching of the low-ops critical operations
+at boot time.
+
+pv_ops operations are classified into three categories:
+
+- simple indirect call
+   These operations correspond to high level functionality where it is
+   known that the overhead of indirect call isn't very important.
+
+- indirect call which allows optimization with binary patch
+   Usually these operations correspond to low level critical instructions. They
+   are called frequently and are performance critical. The overhead is
+   very important.
+
+- a set of macros for hand written assembly code
+   Hand written assembly codes (.S files) also need paravirtualization
+   because they include sensitive instructions or some of code paths in
+   them are very performance critical.
diff --git a/Documentation/virtual/paravirt_ops.txt b/Documentation/virtual/paravirt_ops.txt
deleted file mode 100644 (file)
index d4881c0..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-Paravirt_ops
-============
-
-Linux provides support for different hypervisor virtualization technologies.
-Historically different binary kernels would be required in order to support
-different hypervisors, this restriction was removed with pv_ops.
-Linux pv_ops is a virtualization API which enables support for different
-hypervisors. It allows each hypervisor to override critical operations and
-allows a single kernel binary to run on all supported execution environments
-including native machine -- without any hypervisors.
-
-pv_ops provides a set of function pointers which represent operations
-corresponding to low level critical instructions and high level
-functionalities in various areas. pv-ops allows for optimizations at run
-time by enabling binary patching of the low-ops critical operations
-at boot time.
-
-pv_ops operations are classified into three categories:
-
-- simple indirect call
-  These operations correspond to high level functionality where it is
-  known that the overhead of indirect call isn't very important.
-
-- indirect call which allows optimization with binary patch
-  Usually these operations correspond to low level critical instructions. They
-  are called frequently and are performance critical. The overhead is
-  very important.
-
-- a set of macros for hand written assembly code
-  Hand written assembly codes (.S files) also need paravirtualization
-  because they include sensitive instructions or some of code paths in
-  them are very performance critical.
index 618e497..211ea3a 100644 (file)
@@ -551,6 +551,7 @@ W:  http://wiki.analog.com/ADXL345
 W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
 F:     drivers/input/misc/adxl34x.c
+F:     Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml
 
 ADXL372 THREE-AXIS DIGITAL ACCELEROMETER DRIVER
 M:     Stefan Popa <stefan.popa@analog.com>
@@ -559,7 +560,7 @@ S:  Supported
 F:     drivers/iio/accel/adxl372.c
 F:     drivers/iio/accel/adxl372_spi.c
 F:     drivers/iio/accel/adxl372_i2c.c
-F:     Documentation/devicetree/bindings/iio/accel/adxl372.txt
+F:     Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml
 
 AF9013 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
@@ -916,6 +917,15 @@ S: Supported
 F:     drivers/iio/adc/ad7768-1.c
 F:     Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.txt
 
+ANALOG DEVICES INC AD7780 DRIVER
+M:     Michael Hennerich <Michael.Hennerich@analog.com>
+M:     Renato Lui Geh <renatogeh@gmail.com>
+L:     linux-iio@vger.kernel.org
+W:     http://ez.analog.com/community/linux-device-drivers
+S:     Supported
+F:     drivers/iio/adc/ad7780.c
+F:     Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml
+
 ANALOG DEVICES INC AD9389B DRIVER
 M:     Hans Verkuil <hverkuil-cisco@xs4all.nl>
 L:     linux-media@vger.kernel.org
@@ -928,6 +938,13 @@ S: Supported
 F:     drivers/mux/adgs1408.c
 F:     Documentation/devicetree/bindings/mux/adi,adgs1408.txt
 
+ANALOG DEVICES INC ADIS DRIVER LIBRARY
+M:     Alexandru Ardelean <alexandru.ardelean@analog.com>
+S:     Supported
+L:     linux-iio@vger.kernel.org
+F:     include/linux/iio/imu/adis.h
+F:     drivers/iio/imu/adis.c
+
 ANALOG DEVICES INC ADP5061 DRIVER
 M:     Stefan Popa <stefan.popa@analog.com>
 L:     linux-pm@vger.kernel.org
@@ -2123,7 +2140,7 @@ F:        arch/arm/boot/dts/rda8810pl-*
 F:     drivers/clocksource/timer-rda.c
 F:     drivers/irqchip/irq-rda-intc.c
 F:     drivers/tty/serial/rda-uart.c
-F:     Documentation/devicetree/bindings/arm/rda.txt
+F:     Documentation/devicetree/bindings/arm/rda.yaml
 F:     Documentation/devicetree/bindings/interrupt-controller/rda,8810pl-intc.txt
 F:     Documentation/devicetree/bindings/serial/rda,8810pl-uart.txt
 F:     Documentation/devicetree/bindings/timer/rda,8810pl-timer.txt
@@ -2608,6 +2625,15 @@ S:       Maintained
 F:     Documentation/hwmon/asc7621.rst
 F:     drivers/hwmon/asc7621.c
 
+ASPEED PINCTRL DRIVERS
+M:     Andrew Jeffery <andrew@aj.id.au>
+L:     linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
+L:     openbmc@lists.ozlabs.org (moderated for non-subscribers)
+L:     linux-gpio@vger.kernel.org
+S:     Maintained
+F:     drivers/pinctrl/aspeed/
+F:     Documentation/devicetree/bindings/pinctrl/aspeed,*
+
 ASPEED VIDEO ENGINE DRIVER
 M:     Eddie James <eajames@linux.ibm.com>
 L:     linux-media@vger.kernel.org
@@ -3775,7 +3801,7 @@ F:        scripts/extract-cert.c
 CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM:
 L:     linux-usb@vger.kernel.org
 S:     Orphan
-F:     Documentation/usb/WUSB-Design-overview.txt
+F:     Documentation/usb/wusb-design-overview.rst
 F:     Documentation/usb/wusb-cbaf
 F:     drivers/usb/host/hwa-hc.c
 F:     drivers/usb/host/whci/
@@ -6008,6 +6034,7 @@ M:        Heiner Kallweit <hkallweit1@gmail.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
 F:     Documentation/ABI/testing/sysfs-bus-mdio
+F:     Documentation/devicetree/bindings/net/ethernet-phy.yaml
 F:     Documentation/devicetree/bindings/net/mdio*
 F:     Documentation/networking/phy.rst
 F:     drivers/net/phy/
@@ -6258,6 +6285,14 @@ M:       Philip Kelleher <pjk1939@linux.ibm.com>
 S:     Maintained
 F:     drivers/block/rsxx/
 
+FLEXTIMER FTM-QUADDEC DRIVER
+M:     Patrick Havelange <patrick.havelange@essensium.com>
+L:     linux-iio@vger.kernel.org
+S:     Maintained
+F:     Documentation/ABI/testing/sysfs-bus-counter-ftm-quadddec
+F:     Documentation/devicetree/bindings/counter/ftm-quaddec.txt
+F:     drivers/counter/ftm-quaddec.c
+
 FLOPPY DRIVER
 M:     Jiri Kosina <jikos@kernel.org>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/floppy.git
@@ -6537,6 +6572,19 @@ F:       fs/crypto/
 F:     include/linux/fscrypt*.h
 F:     Documentation/filesystems/fscrypt.rst
 
+FSI SUBSYSTEM
+M:     Jeremy Kerr <jk@ozlabs.org>
+M:     Joel Stanley <joel@jms.id.au>
+R:     Alistar Popple <alistair@popple.id.au>
+R:     Eddie James <eajames@linux.ibm.com>
+L:     linux-fsi@lists.ozlabs.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joel/fsi.git
+Q:     http://patchwork.ozlabs.org/project/linux-fsi/list/
+S:     Supported
+F:     drivers/fsi/
+F:     include/linux/fsi*.h
+F:     include/trace/events/fsi*.h
+
 FSI-ATTACHED I2C DRIVER
 M:     Eddie James <eajames@linux.ibm.com>
 L:     linux-i2c@vger.kernel.org
@@ -7383,9 +7431,18 @@ F:       net/vmw_vsock/hyperv_transport.c
 F:     include/clocksource/hyperv_timer.h
 F:     include/linux/hyperv.h
 F:     include/uapi/linux/hyperv.h
+F:     include/asm-generic/mshyperv.h
 F:     tools/hv/
 F:     Documentation/ABI/stable/sysfs-bus-vmbus
 
+HYPERBUS SUPPORT
+M:     Vignesh Raghavendra <vigneshr@ti.com>
+S:     Supported
+F:     drivers/mtd/hyperbus/
+F:     include/linux/mtd/hyperbus.h
+F:     Documentation/devicetree/bindings/mtd/cypress,hyperflash.txt
+F:     Documentation/devicetree/bindings/mtd/ti,am654-hbmc.txt
+
 HYPERVISOR VIRTUAL CONSOLE DRIVER
 L:     linuxppc-dev@lists.ozlabs.org
 S:     Odd Fixes
@@ -7842,6 +7899,12 @@ W:       http://industrypack.sourceforge.net
 S:     Maintained
 F:     drivers/ipack/
 
+INFINEON DPS310 Driver
+M:     Eddie James <eajames@linux.ibm.com>
+L:     linux-iio@vger.kernel.org
+F:     drivers/iio/pressure/dps310.c
+S:     Maintained
+
 INFINIBAND SUBSYSTEM
 M:     Doug Ledford <dledford@redhat.com>
 M:     Jason Gunthorpe <jgg@mellanox.com>
@@ -8103,7 +8166,7 @@ F:        include/uapi/linux/mei.h
 F:     include/linux/mei_cl_bus.h
 F:     drivers/misc/mei/*
 F:     drivers/watchdog/mei_wdt.c
-F:     Documentation/misc-devices/mei/*
+F:     Documentation/driver-api/mei/*
 F:     samples/mei/*
 
 INTEL MENLOW THERMAL DRIVER
@@ -8936,7 +8999,7 @@ F:        include/linux/leds.h
 LEGACY EEPROM DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
 S:     Maintained
-F:     Documentation/misc-devices/eeprom
+F:     Documentation/misc-devices/eeprom.rst
 F:     drivers/misc/eeprom/eeprom.c
 
 LEGO MINDSTORMS EV3
@@ -9222,7 +9285,7 @@ F:        Documentation/memory-barriers.txt
 LIS3LV02D ACCELEROMETER DRIVER
 M:     Eric Piel <eric.piel@tremplin-utc.net>
 S:     Maintained
-F:     Documentation/misc-devices/lis3lv02d
+F:     Documentation/misc-devices/lis3lv02d.rst
 F:     drivers/misc/lis3lv02d/
 F:     drivers/platform/x86/hp_accel.c
 
@@ -11215,7 +11278,7 @@ F:      include/uapi/linux/nfs*
 F:     include/uapi/linux/sunrpc/
 
 NILFS2 FILESYSTEM
-M:     Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
+M:     Ryusuke Konishi <konishi.ryusuke@gmail.com>
 L:     linux-nilfs@vger.kernel.org
 W:     https://nilfs.sourceforge.io/
 W:     https://nilfs.osdn.jp/
@@ -11779,16 +11842,6 @@ S:     Maintained
 F:     drivers/mtd/nand/onenand/
 F:     include/linux/mtd/onenand*.h
 
-ONSTREAM SCSI TAPE DRIVER
-M:     Willem Riede <osst@riede.org>
-L:     osst-users@lists.sourceforge.net
-L:     linux-scsi@vger.kernel.org
-S:     Maintained
-F:     Documentation/scsi/osst.txt
-F:     drivers/scsi/osst.*
-F:     drivers/scsi/osst_*.h
-F:     drivers/scsi/st.h
-
 OP-TEE DRIVER
 M:     Jens Wiklander <jens.wiklander@linaro.org>
 S:     Maintained
@@ -12680,8 +12733,7 @@ S:      Orphan
 F:     drivers/scsi/pmcraid.*
 
 PMC SIERRA PM8001 DRIVER
-M:     Jack Wang <jinpu.wang@profitbricks.com>
-M:     lindar_liu@usish.com
+M:     Jack Wang <jinpu.wang@cloud.ionos.com>
 L:     linux-scsi@vger.kernel.org
 S:     Supported
 F:     drivers/scsi/pm8001/
@@ -12895,7 +12947,6 @@ F:      include/linux/regset.h
 F:     include/linux/tracehook.h
 F:     include/uapi/linux/ptrace.h
 F:     include/uapi/linux/ptrace.h
-F:     include/asm-generic/ptrace.h
 F:     kernel/ptrace.c
 F:     arch/*/ptrace*.c
 F:     arch/*/*/ptrace*.c
@@ -14277,6 +14328,12 @@ S:     Maintained
 F:     drivers/misc/phantom.c
 F:     include/uapi/linux/phantom.h
 
+SENSIRION SPS30 AIR POLLUTION SENSOR DRIVER
+M:     Tomasz Duszynski <tduszyns@gmail.com>
+S:     Maintained
+F:     drivers/iio/chemical/sps30.c
+F:     Documentation/devicetree/bindings/iio/chemical/sensirion,sps30.yaml
+
 SERIAL DEVICE BUS
 M:     Rob Herring <robh@kernel.org>
 L:     linux-serial@vger.kernel.org
@@ -15051,6 +15108,17 @@ L:     linux-erofs@lists.ozlabs.org
 S:     Maintained
 F:     drivers/staging/erofs/
 
+STAGING - FIELDBUS SUBSYSTEM
+M:     Sven Van Asbroeck <TheSven73@gmail.com>
+S:     Maintained
+F:     drivers/staging/fieldbus/*
+F:     drivers/staging/fieldbus/Documentation/
+
+STAGING - HMS ANYBUS-S BUS
+M:     Sven Van Asbroeck <TheSven73@gmail.com>
+S:     Maintained
+F:     drivers/staging/fieldbus/anybuss/
+
 STAGING - INDUSTRIAL IO
 M:     Jonathan Cameron <jic23@kernel.org>
 L:     linux-iio@vger.kernel.org
@@ -16372,7 +16440,7 @@ USB ACM DRIVER
 M:     Oliver Neukum <oneukum@suse.com>
 L:     linux-usb@vger.kernel.org
 S:     Maintained
-F:     Documentation/usb/acm.txt
+F:     Documentation/usb/acm.rst
 F:     drivers/usb/class/cdc-acm.*
 
 USB AR5523 WIRELESS DRIVER
@@ -16425,7 +16493,7 @@ USB EHCI DRIVER
 M:     Alan Stern <stern@rowland.harvard.edu>
 L:     linux-usb@vger.kernel.org
 S:     Maintained
-F:     Documentation/usb/ehci.txt
+F:     Documentation/usb/ehci.rst
 F:     drivers/usb/host/ehci*
 
 USB GADGET/PERIPHERAL SUBSYSTEM
@@ -16443,7 +16511,7 @@ M:      Benjamin Tissoires <benjamin.tissoires@redhat.com>
 L:     linux-usb@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
 S:     Maintained
-F:     Documentation/hid/hiddev.txt
+F:     Documentation/hid/hiddev.rst
 F:     drivers/hid/usbhid/
 
 USB INTEL XHCI ROLE MUX DRIVER
@@ -16499,7 +16567,7 @@ USB OHCI DRIVER
 M:     Alan Stern <stern@rowland.harvard.edu>
 L:     linux-usb@vger.kernel.org
 S:     Maintained
-F:     Documentation/usb/ohci.txt
+F:     Documentation/usb/ohci.rst
 F:     drivers/usb/host/ohci*
 
 USB OTG FSM (Finite State Machine)
@@ -16515,7 +16583,7 @@ M:      Shuah Khan <shuah@kernel.org>
 M:     Shuah Khan <skhan@linuxfoundation.org>
 L:     linux-usb@vger.kernel.org
 S:     Maintained
-F:     Documentation/usb/usbip_protocol.txt
+F:     Documentation/usb/usbip_protocol.rst
 F:     drivers/usb/usbip/
 F:     tools/usb/usbip/
 F:     tools/testing/selftests/drivers/usb/usbip/
@@ -16563,7 +16631,7 @@ M:      Johan Hovold <johan@kernel.org>
 L:     linux-usb@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial.git
 S:     Maintained
-F:     Documentation/usb/usb-serial.txt
+F:     Documentation/usb/usb-serial.rst
 F:     drivers/usb/serial/
 F:     include/linux/usb/serial.h
 
@@ -17493,7 +17561,13 @@ W:     http://xfs.org/
 T:     git git://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git
 S:     Supported
 F:     Documentation/filesystems/xfs.txt
+F:     Documentation/ABI/testing/sysfs-fs-xfs
+F:     Documentation/filesystems/xfs.txt
+F:     Documentation/filesystems/xfs-delayed-logging-design.txt
+F:     Documentation/filesystems/xfs-self-describing-metadata.txt
 F:     fs/xfs/
+F:     include/uapi/linux/dqblk_xfs.h
+F:     include/uapi/linux/fsmap.h
 
 XILINX AXI ETHERNET DRIVER
 M:     Anirudha Sarangi <anirudh@xilinx.com>
index 3e4868a..2c5d00b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -212,6 +212,13 @@ endif
 ifdef SUBDIRS
   $(warning ================= WARNING ================)
   $(warning 'SUBDIRS' will be removed after Linux 5.3)
+  $(warning )
+  $(warning If you are building an individual subdirectory)
+  $(warning in the kernel tree, you can do like this:)
+  $(warning $$ make path/to/dir/you/want/to/build/)
+  $(warning (Do not forget the trailing slash))
+  $(warning )
+  $(warning If you are building an external module,)
   $(warning Please use 'M=' or 'KBUILD_EXTMOD' instead)
   $(warning ==========================================)
   KBUILD_EXTMOD ?= $(SUBDIRS)
@@ -221,9 +228,12 @@ ifeq ("$(origin M)", "command line")
   KBUILD_EXTMOD := $(M)
 endif
 
+export KBUILD_CHECKSRC KBUILD_EXTMOD
+
 ifeq ($(abs_srctree),$(abs_objtree))
         # building in the source tree
         srctree := .
+       building_out_of_srctree :=
 else
         ifeq ($(abs_srctree)/,$(dir $(abs_objtree)))
                 # building in a subdirectory of the source tree
@@ -231,22 +241,17 @@ else
         else
                 srctree := $(abs_srctree)
         endif
-
-       # TODO:
-       # KBUILD_SRC is only used to distinguish in-tree/out-of-tree build.
-       # Replace it with $(srctree) or something.
-       KBUILD_SRC := $(abs_srctree)
+       building_out_of_srctree := 1
 endif
 
-export KBUILD_CHECKSRC KBUILD_EXTMOD KBUILD_SRC
+ifneq ($(KBUILD_ABS_SRCTREE),)
+srctree := $(abs_srctree)
+endif
 
 objtree                := .
-src            := $(srctree)
-obj            := $(objtree)
-
 VPATH          := $(srctree)
 
-export srctree objtree VPATH
+export building_out_of_srctree srctree objtree VPATH
 
 # To make sure we do not include .config for any of the *config targets
 # catch them early, and hand them over to scripts/kconfig/Makefile
@@ -262,7 +267,7 @@ old_version_h := include/linux/version.h
 clean-targets := %clean mrproper cleandocs
 no-dot-config-targets := $(clean-targets) \
                         cscope gtags TAGS tags help% %docs check% coccicheck \
-                        $(version_h) headers_% archheaders archscripts \
+                        $(version_h) headers headers_% archheaders archscripts \
                         %asm-generic kernelversion %src-pkg
 no-sync-config-targets := $(no-dot-config-targets) install %install \
                           kernelrelease
@@ -449,7 +454,7 @@ USERINCLUDE    := \
 LINUXINCLUDE    := \
                -I$(srctree)/arch/$(SRCARCH)/include \
                -I$(objtree)/arch/$(SRCARCH)/include/generated \
-               $(if $(filter .,$(srctree)),,-I$(srctree)/include) \
+               $(if $(building_out_of_srctree),-I$(srctree)/include) \
                -I$(objtree)/include \
                $(USERINCLUDE)
 
@@ -510,7 +515,7 @@ PHONY += outputmakefile
 # At the same time when output Makefile generated, generate .gitignore to
 # ignore whole output directory
 outputmakefile:
-ifneq ($(srctree),.)
+ifdef building_out_of_srctree
        $(Q)ln -fsn $(srctree) source
        $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile $(srctree)
        $(Q)test -e .gitignore || \
@@ -527,7 +532,10 @@ endif
 ifneq ($(GCC_TOOLCHAIN),)
 CLANG_FLAGS    += --gcc-toolchain=$(GCC_TOOLCHAIN)
 endif
+ifeq ($(shell $(AS) --version 2>&1 | head -n 1 | grep clang),)
 CLANG_FLAGS    += -no-integrated-as
+endif
+CLANG_FLAGS    += -Werror=unknown-warning-option
 KBUILD_CFLAGS  += $(CLANG_FLAGS)
 KBUILD_AFLAGS  += $(CLANG_FLAGS)
 export CLANG_FLAGS
@@ -608,6 +616,7 @@ ifeq ($(KBUILD_EXTMOD),)
 init-y         := init/
 drivers-y      := drivers/ sound/
 drivers-$(CONFIG_SAMPLES) += samples/
+drivers-$(CONFIG_KERNEL_HEADER_TEST) += include/
 net-y          := net/
 libs-y         := lib/
 core-y         := usr/
@@ -1053,9 +1062,6 @@ vmlinux: scripts/link-vmlinux.sh autoksyms_recursive $(vmlinux-deps) FORCE
 
 targets := vmlinux
 
-# Some samples need headers_install.
-samples: headers_install
-
 # The actual objects are generated when descending,
 # make sure no implicit rule kicks in
 $(sort $(vmlinux-deps)): $(vmlinux-dirs) ;
@@ -1096,12 +1102,12 @@ PHONY += prepare archprepare prepare1 prepare3
 # and if so do:
 # 1) Check that make has not been executed in the kernel src $(srctree)
 prepare3: include/config/kernel.release
-ifneq ($(srctree),.)
+ifdef building_out_of_srctree
        @$(kecho) '  Using $(srctree) as source for kernel'
        $(Q)if [ -f $(srctree)/.config -o \
                 -d $(srctree)/include/config -o \
                 -d $(srctree)/arch/$(SRCARCH)/include/generated ]; then \
-               echo >&2 "  $(srctree) is not clean, please run 'make mrproper'"; \
+               echo >&2 "  $(srctree) is not clean, please run 'make ARCH=$(ARCH) mrproper'"; \
                echo >&2 "  in the '$(srctree)' directory.";\
                /bin/false; \
        fi;
@@ -1181,39 +1187,44 @@ headerdep:
 #Default location for installed headers
 export INSTALL_HDR_PATH = $(objtree)/usr
 
-# If we do an all arch process set dst to include/arch-$(SRCARCH)
-hdr-dst = $(if $(KBUILD_HEADERS), dst=include/arch-$(SRCARCH), dst=include)
+quiet_cmd_headers_install = INSTALL $(INSTALL_HDR_PATH)/include
+      cmd_headers_install = \
+       mkdir -p $(INSTALL_HDR_PATH); \
+       rsync -mrl --include='*/' --include='*\.h' --exclude='*' \
+       usr/include $(INSTALL_HDR_PATH)
 
-PHONY += archheaders archscripts
+PHONY += headers_install
+headers_install: headers
+       $(call cmd,headers_install)
 
-PHONY += __headers
-__headers: $(version_h) scripts_basic uapi-asm-generic archheaders archscripts
-       $(Q)$(MAKE) $(build)=scripts build_unifdef
+PHONY += archheaders archscripts
 
-PHONY += headers_install_all
-headers_install_all:
-       $(Q)$(CONFIG_SHELL) $(srctree)/scripts/headers.sh install
+hdr-inst := -f $(srctree)/scripts/Makefile.headersinst obj
 
-PHONY += headers_install
-headers_install: __headers
+PHONY += headers
+headers: $(version_h) scripts_unifdef uapi-asm-generic archheaders archscripts
        $(if $(wildcard $(srctree)/arch/$(SRCARCH)/include/uapi/asm/Kbuild),, \
          $(error Headers not exportable for the $(SRCARCH) architecture))
-       $(Q)$(MAKE) $(hdr-inst)=include/uapi dst=include
-       $(Q)$(MAKE) $(hdr-inst)=arch/$(SRCARCH)/include/uapi $(hdr-dst)
-
-PHONY += headers_check_all
-headers_check_all: headers_install_all
-       $(Q)$(CONFIG_SHELL) $(srctree)/scripts/headers.sh check
+       $(Q)$(MAKE) $(hdr-inst)=include/uapi
+       $(Q)$(MAKE) $(hdr-inst)=arch/$(SRCARCH)/include/uapi
 
 PHONY += headers_check
-headers_check: headers_install
-       $(Q)$(MAKE) $(hdr-inst)=include/uapi dst=include HDRCHECK=1
-       $(Q)$(MAKE) $(hdr-inst)=arch/$(SRCARCH)/include/uapi $(hdr-dst) HDRCHECK=1
+headers_check: headers
+       $(Q)$(MAKE) $(hdr-inst)=include/uapi HDRCHECK=1
+       $(Q)$(MAKE) $(hdr-inst)=arch/$(SRCARCH)/include/uapi HDRCHECK=1
+
+ifdef CONFIG_HEADERS_INSTALL
+prepare: headers
+endif
 
 ifdef CONFIG_HEADERS_CHECK
 all: headers_check
 endif
 
+PHONY += scripts_unifdef
+scripts_unifdef: scripts_basic
+       $(Q)$(MAKE) $(build)=scripts scripts/unifdef
+
 # ---------------------------------------------------------------------------
 # Kernel selftest
 
@@ -1283,18 +1294,24 @@ all: modules
 # using awk while concatenating to the final file.
 
 PHONY += modules
-modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) modules.builtin
-       $(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > $(objtree)/modules.order
+modules: $(if $(KBUILD_BUILTIN),vmlinux) modules.order modules.builtin
        @$(kecho) '  Building modules, stage 2.';
        $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
        $(Q)$(CONFIG_SHELL) $(srctree)/scripts/modules-check.sh
 
-modules.builtin: $(vmlinux-dirs:%=%/modules.builtin)
-       $(Q)$(AWK) '!x[$$0]++' $^ > $(objtree)/modules.builtin
+modules.order: $(vmlinux-dirs)
+       $(Q)$(AWK) '!x[$$0]++' $(addsuffix /$@, $(vmlinux-dirs)) > $@
+
+modbuiltin-dirs := $(addprefix _modbuiltin_, $(vmlinux-dirs))
 
-%/modules.builtin: include/config/auto.conf include/config/tristate.conf
-       $(Q)$(MAKE) $(modbuiltin)=$*
+modules.builtin: $(modbuiltin-dirs)
+       $(Q)$(AWK) '!x[$$0]++' $(addsuffix /$@, $(vmlinux-dirs)) > $@
 
+PHONY += $(modbuiltin-dirs)
+# tristate.conf is not included from this Makefile. Add it as a prerequisite
+# here to make it self-healing in case somebody accidentally removes it.
+$(modbuiltin-dirs): include/config/tristate.conf
+       $(Q)$(MAKE) $(modbuiltin)=$(patsubst _modbuiltin_%,%,$@)
 
 # Target to prepare building external modules
 PHONY += modules_prepare
@@ -1360,7 +1377,7 @@ CLEAN_DIRS  += $(MODVERDIR) include/ksym
 CLEAN_FILES += modules.builtin.modinfo
 
 # Directories & files removed with 'make mrproper'
-MRPROPER_DIRS  += include/config usr/include include/generated          \
+MRPROPER_DIRS  += include/config include/generated          \
                  arch/$(SRCARCH)/include/generated .tmp_objdiff
 MRPROPER_FILES += .config .config.old .version \
                  Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \
@@ -1551,7 +1568,7 @@ $(DOC_TARGETS): scripts_basic FORCE
 # ---------------------------------------------------------------------------
 
 PHONY += scripts_gdb
-scripts_gdb: prepare
+scripts_gdb: prepare0
        $(Q)$(MAKE) $(build)=scripts/gdb
        $(Q)ln -fsn $(abspath $(srctree)/scripts/gdb/vmlinux-gdb.py)
 
@@ -1698,7 +1715,7 @@ CHECKSTACK_ARCH := $(ARCH)
 endif
 checkstack:
        $(OBJDUMP) -d vmlinux $$(find . -name '*.ko') | \
-       $(PERL) $(src)/scripts/checkstack.pl $(CHECKSTACK_ARCH)
+       $(PERL) $(srctree)/scripts/checkstack.pl $(CHECKSTACK_ARCH)
 
 kernelrelease:
        @echo "$(KERNELVERSION)$$($(CONFIG_SHELL) $(srctree)/scripts/setlocalversion $(srctree))"
@@ -1717,11 +1734,11 @@ endif
 
 tools/: FORCE
        $(Q)mkdir -p $(objtree)/tools
-       $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(tools_silent) $(filter --j% -j,$(MAKEFLAGS))" O=$(abspath $(objtree)) subdir=tools -C $(src)/tools/
+       $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(tools_silent) $(filter --j% -j,$(MAKEFLAGS))" O=$(abspath $(objtree)) subdir=tools -C $(srctree)/tools/
 
 tools/%: FORCE
        $(Q)mkdir -p $(objtree)/tools
-       $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(tools_silent) $(filter --j% -j,$(MAKEFLAGS))" O=$(abspath $(objtree)) subdir=tools -C $(src)/tools/ $*
+       $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(tools_silent) $(filter --j% -j,$(MAKEFLAGS))" O=$(abspath $(objtree)) subdir=tools -C $(srctree)/tools/ $*
 
 # Single targets
 # ---------------------------------------------------------------------------
@@ -1755,8 +1772,6 @@ build-dir = $(patsubst %/,%,$(dir $(build-target)))
 PHONY += /
 /: ./
 
-# Make sure the latest headers are built for Documentation
-Documentation/ samples/: headers_install
 %/: prepare FORCE
        $(Q)$(MAKE) KBUILD_MODULES=1 $(build)=$(build-dir)
 
index c47b328..e8d19c3 100644 (file)
@@ -260,6 +260,14 @@ config ARCH_HAS_SET_MEMORY
 config ARCH_HAS_SET_DIRECT_MAP
        bool
 
+#
+# Select if arch has an uncached kernel segment and provides the
+# uncached_kernel_address / cached_kernel_address symbols to use it
+#
+config ARCH_HAS_UNCACHED_SEGMENT
+       select ARCH_HAS_DMA_PREP_COHERENT
+       bool
+
 # Select if arch init_task must go in the __init_task_data section
 config ARCH_TASK_STRUCT_ON_STACK
        bool
index b3314e0..12dee59 100644 (file)
@@ -8,8 +8,6 @@
 # Copyright (C) 1994 by Linus Torvalds
 #
 
-KBUILD_DEFCONFIG := defconfig
-
 NM := $(NM) -B
 
 LDFLAGS_vmlinux        := -static -N #-relax
index 02f9f91..71ded3b 100644 (file)
@@ -5,6 +5,8 @@
 #include <linux/mm.h>
 #include <linux/mmzone.h>
 
+#include <asm-generic/pgalloc.h>       /* for pte_{alloc,free}_one */
+
 /*      
  * Allocate and free page tables. The xxx_kernel() versions are
  * used to allocate a kernel page table - this turns on ASN bits
@@ -41,7 +43,7 @@ pgd_free(struct mm_struct *mm, pgd_t *pgd)
 static inline pmd_t *
 pmd_alloc_one(struct mm_struct *mm, unsigned long address)
 {
-       pmd_t *ret = (pmd_t *)__get_free_page(GFP_KERNEL|__GFP_ZERO);
+       pmd_t *ret = (pmd_t *)__get_free_page(GFP_PGTABLE_USER);
        return ret;
 }
 
@@ -51,42 +53,6 @@ pmd_free(struct mm_struct *mm, pmd_t *pmd)
        free_page((unsigned long)pmd);
 }
 
-static inline pte_t *
-pte_alloc_one_kernel(struct mm_struct *mm)
-{
-       pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_ZERO);
-       return pte;
-}
-
-static inline void
-pte_free_kernel(struct mm_struct *mm, pte_t *pte)
-{
-       free_page((unsigned long)pte);
-}
-
-static inline pgtable_t
-pte_alloc_one(struct mm_struct *mm)
-{
-       pte_t *pte = pte_alloc_one_kernel(mm);
-       struct page *page;
-
-       if (!pte)
-               return NULL;
-       page = virt_to_page(pte);
-       if (!pgtable_page_ctor(page)) {
-               __free_page(page);
-               return NULL;
-       }
-       return page;
-}
-
-static inline void
-pte_free(struct mm_struct *mm, pgtable_t page)
-{
-       pgtable_page_dtor(page);
-       __free_page(page);
-}
-
 #define check_pgt_cache()      do { } while (0)
 
 #endif /* _ALPHA_PGALLOC_H */
index 1c8137e..8383155 100644 (file)
@@ -7,6 +7,7 @@ config ARC
        def_bool y
        select ARC_TIMERS
        select ARCH_HAS_DMA_COHERENT_TO_PFN
+       select ARCH_HAS_DMA_PREP_COHERENT
        select ARCH_HAS_PTE_SPECIAL
        select ARCH_HAS_SETUP_DMA_OPS
        select ARCH_HAS_SYNC_DMA_FOR_CPU
@@ -16,6 +17,7 @@ config ARC
        select BUILDTIME_EXTABLE_SORT
        select CLONE_BACKWARDS
        select COMMON_CLK
+       select DMA_DIRECT_REMAP
        select GENERIC_ATOMIC64 if !ISA_ARCV2 || !(ARC_HAS_LL64 && ARC_HAS_LLSC)
        select GENERIC_CLOCKEVENTS
        select GENERIC_FIND_FIRST_BIT
index 03a0b19..ee6d118 100644 (file)
@@ -19,7 +19,7 @@ ifdef CONFIG_ARC_CURR_IN_REG
 # any kernel headers, and missing the r25 global register
 # Can't do unconditionally because of recursive include issues
 # due to <linux/thread_info.h>
-LINUXINCLUDE   +=  -include ${src}/arch/arc/include/asm/current.h
+LINUXINCLUDE   +=  -include $(srctree)/arch/arc/include/asm/current.h
 endif
 
 cflags-y                               += -fsection-anchors
index 5b5119d..dc739bd 100644 (file)
@@ -94,6 +94,7 @@ CONFIG_CONFIGFS_FS=y
 CONFIG_DEBUG_INFO=y
 CONFIG_STRIP_ASM_SYMS=y
 CONFIG_DEBUG_FS=y
+CONFIG_HEADERS_INSTALL=y
 CONFIG_HEADERS_CHECK=y
 CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_MAGIC_SYSRQ=y
index 0bf1468..62c210e 100644 (file)
@@ -8,51 +8,15 @@
 #include <asm/cacheflush.h>
 
 /*
- * ARCH specific callbacks for generic noncoherent DMA ops (dma/noncoherent.c)
+ * ARCH specific callbacks for generic noncoherent DMA ops
  *  - hardware IOC not available (or "dma-coherent" not set for device in DT)
  *  - But still handle both coherent and non-coherent requests from caller
  *
  * For DMA coherent hardware (IOC) generic code suffices
  */
-void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
-               gfp_t gfp, unsigned long attrs)
-{
-       unsigned long order = get_order(size);
-       struct page *page;
-       phys_addr_t paddr;
-       void *kvaddr;
-       bool need_coh = !(attrs & DMA_ATTR_NON_CONSISTENT);
-
-       /*
-        * __GFP_HIGHMEM flag is cleared by upper layer functions
-        * (in include/linux/dma-mapping.h) so we should never get a
-        * __GFP_HIGHMEM here.
-        */
-       BUG_ON(gfp & __GFP_HIGHMEM);
-
-       page = alloc_pages(gfp | __GFP_ZERO, order);
-       if (!page)
-               return NULL;
-
-       /* This is linear addr (0x8000_0000 based) */
-       paddr = page_to_phys(page);
-
-       *dma_handle = paddr;
-
-       /*
-        * A coherent buffer needs MMU mapping to enforce non-cachability.
-        * kvaddr is kernel Virtual address (0x7000_0000 based).
-        */
-       if (need_coh) {
-               kvaddr = ioremap_nocache(paddr, size);
-               if (kvaddr == NULL) {
-                       __free_pages(page, order);
-                       return NULL;
-               }
-       } else {
-               kvaddr = (void *)(u32)paddr;
-       }
 
+void arch_dma_prep_coherent(struct page *page, size_t size)
+{
        /*
         * Evict any existing L1 and/or L2 lines for the backing page
         * in case it was used earlier as a normal "cached" page.
@@ -63,28 +27,7 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
         * Currently flush_cache_vmap nukes the L1 cache completely which
         * will be optimized as a separate commit
         */
-       if (need_coh)
-               dma_cache_wback_inv(paddr, size);
-
-       return kvaddr;
-}
-
-void arch_dma_free(struct device *dev, size_t size, void *vaddr,
-               dma_addr_t dma_handle, unsigned long attrs)
-{
-       phys_addr_t paddr = dma_handle;
-       struct page *page = virt_to_page(paddr);
-
-       if (!(attrs & DMA_ATTR_NON_CONSISTENT))
-               iounmap((void __force __iomem *)vaddr);
-
-       __free_pages(page, get_order(size));
-}
-
-long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr,
-               dma_addr_t dma_addr)
-{
-       return __phys_to_pfn(dma_addr);
+       dma_cache_wback_inv(page_to_phys(page), size);
 }
 
 /*
@@ -161,3 +104,9 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
        dev_info(dev, "use %sncoherent DMA ops\n",
                 dev->dma_coherent ? "" : "non");
 }
+
+static int __init atomic_pool_init(void)
+{
+       return dma_atomic_pool_init(GFP_KERNEL, pgprot_noncached(PAGE_KERNEL));
+}
+postcore_initcall(atomic_pool_init);
index d850feb..2bf1ce3 100644 (file)
@@ -75,6 +75,7 @@ config ARM
        select HAVE_DYNAMIC_FTRACE_WITH_REGS if HAVE_DYNAMIC_FTRACE
        select HAVE_EFFICIENT_UNALIGNED_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && MMU
        select HAVE_EXIT_THREAD
+       select HAVE_FAST_GUP if ARM_LPAE
        select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL
        select HAVE_FUNCTION_GRAPH_TRACER if !THUMB2_KERNEL && !CC_IS_CLANG
        select HAVE_FUNCTION_TRACER if !XIP_KERNEL
@@ -1622,16 +1623,9 @@ config ARCH_SPARSEMEM_ENABLE
 config ARCH_SPARSEMEM_DEFAULT
        def_bool ARCH_SPARSEMEM_ENABLE
 
-config ARCH_SELECT_MEMORY_MODEL
-       def_bool ARCH_SPARSEMEM_ENABLE
-
 config HAVE_ARCH_PFN_VALID
        def_bool ARCH_HAS_HOLES_MEMORYMODEL || !SPARSEMEM
 
-config HAVE_GENERIC_GUP
-       def_bool y
-       depends on ARM_LPAE
-
 config HIGHMEM
        bool "High Memory Support"
        depends on MMU
index 1252522..1d8bfed 100644 (file)
 
 &usb_host1 {
        status = "okay";
+       snps,need-phy-for-wake;
 };
 
 &usb_otg {
        assigned-clocks = <&cru SCLK_USBPHY480M_SRC>;
        assigned-clock-parents = <&usbphy0>;
        dr_mode = "host";
+       snps,need-phy-for-wake;
 };
 
 &vopb {
index 03ba90f..7e0486a 100644 (file)
@@ -89,13 +89,6 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr)
 }
 #endif
 
-/* The ARM override for dma_max_pfn() */
-static inline unsigned long dma_max_pfn(struct device *dev)
-{
-       return dma_to_pfn(dev, *dev->dma_mask);
-}
-#define dma_max_pfn(dev) dma_max_pfn(dev)
-
 /* do not use this function in a driver */
 static inline bool is_device_dma_coherent(struct device *dev)
 {
index 6b7644a..4000241 100644 (file)
@@ -271,6 +271,16 @@ static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
        return vcpu_cp15(vcpu, c0_MPIDR) & MPIDR_HWID_BITMASK;
 }
 
+static inline bool kvm_arm_get_vcpu_workaround_2_flag(struct kvm_vcpu *vcpu)
+{
+       return false;
+}
+
+static inline void kvm_arm_set_vcpu_workaround_2_flag(struct kvm_vcpu *vcpu,
+                                                     bool flag)
+{
+}
+
 static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
 {
        *vcpu_cpsr(vcpu) |= PSR_E_BIT;
index f80418d..8a37c8e 100644 (file)
@@ -15,7 +15,6 @@
 #include <asm/kvm_asm.h>
 #include <asm/kvm_mmio.h>
 #include <asm/fpstate.h>
-#include <asm/smp_plat.h>
 #include <kvm/arm_arch_timer.h>
 
 #define __KVM_HAVE_ARCH_INTC_INITIALIZED
@@ -147,11 +146,10 @@ struct kvm_host_data {
 
 typedef struct kvm_host_data kvm_host_data_t;
 
-static inline void kvm_init_host_cpu_context(struct kvm_cpu_context *cpu_ctxt,
-                                            int cpu)
+static inline void kvm_init_host_cpu_context(struct kvm_cpu_context *cpu_ctxt)
 {
        /* The host's MPIDR is immutable, so let's set it up at boot time */
-       cpu_ctxt->cp15[c0_MPIDR] = cpu_logical_map(cpu);
+       cpu_ctxt->cp15[c0_MPIDR] = read_cpuid_mpidr();
 }
 
 struct vcpu_reset_state {
@@ -362,7 +360,11 @@ static inline void kvm_vcpu_pmu_restore_host(struct kvm_vcpu *vcpu) {}
 static inline void kvm_arm_vhe_guest_enter(void) {}
 static inline void kvm_arm_vhe_guest_exit(void) {}
 
-static inline bool kvm_arm_harden_branch_predictor(void)
+#define KVM_BP_HARDEN_UNKNOWN          -1
+#define KVM_BP_HARDEN_WA_NEEDED                0
+#define KVM_BP_HARDEN_NOT_REQUIRED     1
+
+static inline int kvm_arm_harden_branch_predictor(void)
 {
        switch(read_cpuid_part()) {
 #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
@@ -370,10 +372,12 @@ static inline bool kvm_arm_harden_branch_predictor(void)
        case ARM_CPU_PART_CORTEX_A12:
        case ARM_CPU_PART_CORTEX_A15:
        case ARM_CPU_PART_CORTEX_A17:
-               return true;
+               return KVM_BP_HARDEN_WA_NEEDED;
 #endif
+       case ARM_CPU_PART_CORTEX_A7:
+               return KVM_BP_HARDEN_NOT_REQUIRED;
        default:
-               return false;
+               return KVM_BP_HARDEN_UNKNOWN;
        }
 }
 
index 71ac1c8..40e9034 100644 (file)
 #define VFP_FPEXC      __ACCESS_VFP(FPEXC)
 
 /* AArch64 compatibility macros, only for the timer so far */
-#define read_sysreg_el0(r)             read_sysreg(r##_el0)
-#define write_sysreg_el0(v, r)         write_sysreg(v, r##_el0)
+#define read_sysreg_el0(r)             read_sysreg(r##_EL0)
+#define write_sysreg_el0(v, r)         write_sysreg(v, r##_EL0)
+
+#define SYS_CNTP_CTL_EL0               CNTP_CTL
+#define SYS_CNTP_CVAL_EL0              CNTP_CVAL
+#define SYS_CNTV_CTL_EL0               CNTV_CTL
+#define SYS_CNTV_CVAL_EL0              CNTV_CVAL
 
-#define cntp_ctl_el0                   CNTP_CTL
-#define cntp_cval_el0                  CNTP_CVAL
-#define cntv_ctl_el0                   CNTV_CTL
-#define cntv_cval_el0                  CNTV_CVAL
 #define cntvoff_el2                    CNTVOFF
 #define cnthctl_el2                    CNTHCTL
 
index c038cff..a2a68b7 100644 (file)
@@ -54,8 +54,6 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
 extern pgd_t *pgd_alloc(struct mm_struct *mm);
 extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
 
-#define PGALLOC_GFP    (GFP_KERNEL | __GFP_ZERO)
-
 static inline void clean_pte_table(pte_t *pte)
 {
        clean_dcache_area(pte + PTE_HWTABLE_PTRS, PTE_HWTABLE_SIZE);
@@ -77,54 +75,41 @@ static inline void clean_pte_table(pte_t *pte)
  *  |  h/w pt 1  |
  *  +------------+
  */
+
+#define __HAVE_ARCH_PTE_ALLOC_ONE_KERNEL
+#define __HAVE_ARCH_PTE_ALLOC_ONE
+#include <asm-generic/pgalloc.h>
+
 static inline pte_t *
 pte_alloc_one_kernel(struct mm_struct *mm)
 {
-       pte_t *pte;
+       pte_t *pte = __pte_alloc_one_kernel(mm);
 
-       pte = (pte_t *)__get_free_page(PGALLOC_GFP);
        if (pte)
                clean_pte_table(pte);
 
        return pte;
 }
 
+#ifdef CONFIG_HIGHPTE
+#define PGTABLE_HIGHMEM __GFP_HIGHMEM
+#else
+#define PGTABLE_HIGHMEM 0
+#endif
+
 static inline pgtable_t
 pte_alloc_one(struct mm_struct *mm)
 {
        struct page *pte;
 
-#ifdef CONFIG_HIGHPTE
-       pte = alloc_pages(PGALLOC_GFP | __GFP_HIGHMEM, 0);
-#else
-       pte = alloc_pages(PGALLOC_GFP, 0);
-#endif
+       pte = __pte_alloc_one(mm, GFP_PGTABLE_USER | PGTABLE_HIGHMEM);
        if (!pte)
                return NULL;
        if (!PageHighMem(pte))
                clean_pte_table(page_address(pte));
-       if (!pgtable_page_ctor(pte)) {
-               __free_page(pte);
-               return NULL;
-       }
        return pte;
 }
 
-/*
- * Free one PTE table.
- */
-static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
-{
-       if (pte)
-               free_page((unsigned long)pte);
-}
-
-static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
-{
-       pgtable_page_dtor(pte);
-       __free_page(pte);
-}
-
 static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte,
                                  pmdval_t prot)
 {
index 3ebf971..0c2d3d0 100644 (file)
@@ -21,13 +21,10 @@ struct ptdump_info {
 
 void ptdump_walk_pgd(struct seq_file *s, struct ptdump_info *info);
 #ifdef CONFIG_ARM_PTDUMP_DEBUGFS
-int ptdump_debugfs_register(struct ptdump_info *info, const char *name);
+void ptdump_debugfs_register(struct ptdump_info *info, const char *name);
 #else
-static inline int ptdump_debugfs_register(struct ptdump_info *info,
-                                       const char *name)
-{
-       return 0;
-}
+static inline void ptdump_debugfs_register(struct ptdump_info *info,
+                                          const char *name) { }
 #endif /* CONFIG_ARM_PTDUMP_DEBUGFS */
 
 void ptdump_check_wx(void);
index 4602464..a4217c1 100644 (file)
@@ -214,6 +214,18 @@ struct kvm_vcpu_events {
 #define KVM_REG_ARM_FW_REG(r)          (KVM_REG_ARM | KVM_REG_SIZE_U64 | \
                                         KVM_REG_ARM_FW | ((r) & 0xffff))
 #define KVM_REG_ARM_PSCI_VERSION       KVM_REG_ARM_FW_REG(0)
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1    KVM_REG_ARM_FW_REG(1)
+       /* Higher values mean better protection. */
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL          0
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL              1
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED       2
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2    KVM_REG_ARM_FW_REG(2)
+       /* Higher values mean better protection. */
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL          0
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN            1
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL              2
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED       3
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED    (1U << 4)
 
 /* Device Control API: ARM VGIC */
 #define KVM_DEV_ARM_VGIC_GRP_ADDR      0
index ed00587..e57dbcc 100644 (file)
@@ -8,8 +8,7 @@
 #include <asm/mach/map.h>
 #include <asm/mmu_context.h>
 
-static int __init set_permissions(pte_t *ptep, pgtable_t token,
-                                 unsigned long addr, void *data)
+static int __init set_permissions(pte_t *ptep, unsigned long addr, void *data)
 {
        efi_memory_desc_t *md = data;
        pte_t pte = *ptep;
index 406fd2a..bd5be82 100644 (file)
@@ -987,84 +987,44 @@ static int debug_clock_show(struct seq_file *s, void *unused)
 
 DEFINE_SHOW_ATTRIBUTE(debug_clock);
 
-static int clk_debugfs_register_one(struct clk *c)
+static void clk_debugfs_register_one(struct clk *c)
 {
-       int err;
        struct dentry *d;
        struct clk *pa = c->parent;
 
        d = debugfs_create_dir(c->name, pa ? pa->dent : clk_debugfs_root);
-       if (!d)
-               return -ENOMEM;
        c->dent = d;
 
-       d = debugfs_create_u8("usecount", S_IRUGO, c->dent, &c->usecount);
-       if (!d) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       d = debugfs_create_ulong("rate", S_IRUGO, c->dent, &c->rate);
-       if (!d) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       d = debugfs_create_x8("flags", S_IRUGO, c->dent, &c->flags);
-       if (!d) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       return 0;
-
-err_out:
-       debugfs_remove_recursive(c->dent);
-       return err;
+       debugfs_create_u8("usecount", S_IRUGO, c->dent, &c->usecount);
+       debugfs_create_ulong("rate", S_IRUGO, c->dent, &c->rate);
+       debugfs_create_x8("flags", S_IRUGO, c->dent, &c->flags);
 }
 
-static int clk_debugfs_register(struct clk *c)
+static void clk_debugfs_register(struct clk *c)
 {
-       int err;
        struct clk *pa = c->parent;
 
-       if (pa && !pa->dent) {
-               err = clk_debugfs_register(pa);
-               if (err)
-                       return err;
-       }
+       if (pa && !pa->dent)
+               clk_debugfs_register(pa);
 
-       if (!c->dent) {
-               err = clk_debugfs_register_one(c);
-               if (err)
-                       return err;
-       }
-       return 0;
+       if (!c->dent)
+               clk_debugfs_register_one(c);
 }
 
 static int __init clk_debugfs_init(void)
 {
        struct clk *c;
        struct dentry *d;
-       int err;
 
        d = debugfs_create_dir("clock", NULL);
-       if (!d)
-               return -ENOMEM;
        clk_debugfs_root = d;
 
-       list_for_each_entry(c, &clocks, node) {
-               err = clk_debugfs_register(c);
-               if (err)
-                       goto err_out;
-       }
+       list_for_each_entry(c, &clocks, node)
+               clk_debugfs_register(c);
 
-       d = debugfs_create_file("summary", S_IRUGO,
-               d, NULL, &debug_clock_fops);
-       if (!d)
-               return -ENOMEM;
+       debugfs_create_file("summary", S_IRUGO, d, NULL, &debug_clock_fops);
 
        return 0;
-err_out:
-       debugfs_remove_recursive(clk_debugfs_root);
-       return err;
 }
 late_initcall(clk_debugfs_init);
 
index 998075d..d068958 100644 (file)
@@ -539,11 +539,8 @@ static void omap_pm_init_debugfs(void)
        struct dentry *d;
 
        d = debugfs_create_dir("pm_debug", NULL);
-       if (!d)
-               return;
-
-       (void) debugfs_create_file("omap_pm", S_IWUSR | S_IRUGO,
-                                       d, NULL, &omap_pm_debug_fops);
+       debugfs_create_file("omap_pm", S_IWUSR | S_IRUGO, d, NULL,
+                           &omap_pm_debug_fops);
 }
 
 #endif /* CONFIG_DEBUG_FS */
index fe6ec9b..fceb1e5 100644 (file)
@@ -190,9 +190,8 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir)
                return 0;
 
        d = debugfs_create_dir(pwrdm->name, (struct dentry *)dir);
-       if (d)
-               (void) debugfs_create_file("suspend", S_IRUGO|S_IWUSR, d,
-                       (void *)pwrdm, &pwrdm_suspend_fops);
+       debugfs_create_file("suspend", S_IRUGO|S_IWUSR, d, pwrdm,
+                           &pwrdm_suspend_fops);
 
        return 0;
 }
@@ -230,16 +229,14 @@ static int __init pm_dbg_init(void)
                return 0;
 
        d = debugfs_create_dir("pm_debug", NULL);
-       if (!d)
-               return -EINVAL;
 
-       (void) debugfs_create_file("count", 0444, d, NULL, &pm_dbg_counters_fops);
-       (void) debugfs_create_file("time", 0444, d, NULL, &pm_dbg_timers_fops);
+       debugfs_create_file("count", 0444, d, NULL, &pm_dbg_counters_fops);
+       debugfs_create_file("time", 0444, d, NULL, &pm_dbg_timers_fops);
 
        pwrdm_for_each(pwrdms_setup, (void *)d);
 
-       (void) debugfs_create_file("enable_off_mode", S_IRUGO | S_IWUSR, d,
-                                  &enable_off_mode, &pm_dbg_option_fops);
+       debugfs_create_file("enable_off_mode", S_IRUGO | S_IWUSR, d,
+                           &enable_off_mode, &pm_dbg_option_fops);
        pm_dbg_init_done = 1;
 
        return 0;
index 1aea01b..52b8255 100644 (file)
@@ -35,18 +35,7 @@ static void *arm_nommu_dma_alloc(struct device *dev, size_t size,
                                 unsigned long attrs)
 
 {
-       void *ret;
-
-       /*
-        * Try generic allocator first if we are advertised that
-        * consistency is not required.
-        */
-
-       if (attrs & DMA_ATTR_NON_CONSISTENT)
-               return dma_direct_alloc_pages(dev, size, dma_handle, gfp,
-                               attrs);
-
-       ret = dma_alloc_from_global_coherent(size, dma_handle);
+       void *ret = dma_alloc_from_global_coherent(size, dma_handle);
 
        /*
         * dma_alloc_from_global_coherent() may fail because:
@@ -66,16 +55,9 @@ static void arm_nommu_dma_free(struct device *dev, size_t size,
                               void *cpu_addr, dma_addr_t dma_addr,
                               unsigned long attrs)
 {
-       if (attrs & DMA_ATTR_NON_CONSISTENT) {
-               dma_direct_free_pages(dev, size, cpu_addr, dma_addr, attrs);
-       } else {
-               int ret = dma_release_from_global_coherent(get_order(size),
-                                                          cpu_addr);
-
-               WARN_ON_ONCE(ret == 0);
-       }
+       int ret = dma_release_from_global_coherent(get_order(size), cpu_addr);
 
-       return;
+       WARN_ON_ONCE(ret == 0);
 }
 
 static int arm_nommu_dma_mmap(struct device *dev, struct vm_area_struct *vma,
index 439bb6a..4789c60 100644 (file)
@@ -216,25 +216,7 @@ EXPORT_SYMBOL(arm_coherent_dma_ops);
 
 static int __dma_supported(struct device *dev, u64 mask, bool warn)
 {
-       unsigned long max_dma_pfn;
-
-       /*
-        * If the mask allows for more memory than we can address,
-        * and we actually have that much memory, then we must
-        * indicate that DMA to this device is not supported.
-        */
-       if (sizeof(mask) != sizeof(dma_addr_t) &&
-           mask > (dma_addr_t)~0 &&
-           dma_to_pfn(dev, ~0) < max_pfn - 1) {
-               if (warn) {
-                       dev_warn(dev, "Coherent DMA mask %#llx is larger than dma_addr_t allows\n",
-                                mask);
-                       dev_warn(dev, "Driver did not use or check the return value from dma_set_coherent_mask()?\n");
-               }
-               return 0;
-       }
-
-       max_dma_pfn = min(max_pfn, arm_dma_pfn_limit);
+       unsigned long max_dma_pfn = min(max_pfn, arm_dma_pfn_limit);
 
        /*
         * Translate the device's DMA mask to a PFN limit.  This
@@ -493,8 +475,7 @@ void __init dma_contiguous_remap(void)
        }
 }
 
-static int __dma_update_pte(pte_t *pte, pgtable_t token, unsigned long addr,
-                           void *data)
+static int __dma_update_pte(pte_t *pte, unsigned long addr, void *data)
 {
        struct page *page = virt_to_page(addr);
        pgprot_t prot = *(pgprot_t *)data;
index 006d27e..7d6291f 100644 (file)
@@ -446,7 +446,7 @@ void ptdump_check_wx(void)
 static int ptdump_init(void)
 {
        ptdump_initialize();
-       return ptdump_debugfs_register(&kernel_ptdump_info,
-                                       "kernel_page_tables");
+       ptdump_debugfs_register(&kernel_ptdump_info, "kernel_page_tables");
+       return 0;
 }
 __initcall(ptdump_init);
index 1aa2586..d9a0038 100644 (file)
@@ -729,7 +729,7 @@ static void __init *early_alloc(unsigned long sz)
 
 static void *__init late_alloc(unsigned long sz)
 {
-       void *ptr = (void *)__get_free_pages(PGALLOC_GFP, get_order(sz));
+       void *ptr = (void *)__get_free_pages(GFP_PGTABLE_KERNEL, get_order(sz));
 
        if (!ptr || !pgtable_page_ctor(virt_to_page(ptr)))
                BUG();
index 0f5faf3..d546efa 100644 (file)
@@ -14,8 +14,7 @@ struct page_change_data {
        pgprot_t clear_mask;
 };
 
-static int change_page_range(pte_t *ptep, pgtable_t token, unsigned long addr,
-                       void *data)
+static int change_page_range(pte_t *ptep, unsigned long addr, void *data)
 {
        struct page_change_data *cdata = data;
        pte_t pte = *ptep;
index be8d87b..598b636 100644 (file)
@@ -24,11 +24,7 @@ static const struct file_operations ptdump_fops = {
        .release        = single_release,
 };
 
-int ptdump_debugfs_register(struct ptdump_info *info, const char *name)
+void ptdump_debugfs_register(struct ptdump_info *info, const char *name)
 {
-       struct dentry *pe;
-
-       pe = debugfs_create_file(name, 0400, NULL, info, &ptdump_fops);
-       return pe ? 0 : -ENOMEM;
-
+       debugfs_create_file(name, 0400, NULL, info, &ptdump_fops);
 }
index c085aec..a36ff61 100644 (file)
@@ -143,6 +143,7 @@ config ARM64
        select HAVE_DMA_CONTIGUOUS
        select HAVE_DYNAMIC_FTRACE
        select HAVE_EFFICIENT_UNALIGNED_ACCESS
+       select HAVE_FAST_GUP
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_FUNCTION_TRACER
        select HAVE_FUNCTION_GRAPH_TRACER
@@ -267,9 +268,6 @@ config ZONE_DMA32
        bool "Support DMA32 zone" if EXPERT
        default y
 
-config HAVE_GENERIC_GUP
-       def_bool y
-
 config ARCH_ENABLE_MEMORY_HOTPLUG
        def_bool y
 
index e3d3fd0..bb1f1db 100644 (file)
@@ -30,8 +30,6 @@ LDFLAGS_vmlinux       += --fix-cortex-a53-843419
   endif
 endif
 
-KBUILD_DEFCONFIG := defconfig
-
 # Check for binutils support for specific extensions
 lseinstr := $(call as-instr,.arch_extension lse,-DCONFIG_AS_LSE=1)
 
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-pinfunc.h b/arch/arm64/boot/dts/freescale/imx8mn-pinfunc.h
new file mode 100644 (file)
index 0000000..faf1e69
--- /dev/null
@@ -0,0 +1,646 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2018-2019 NXP
+ */
+
+#ifndef __DTS_IMX8MN_PINFUNC_H
+#define __DTS_IMX8MN_PINFUNC_H
+
+/*
+ * The pin function ID is a tuple of
+ * <mux_reg conf_reg input_reg mux_mode input_val>
+ */
+
+#define MX8MN_IOMUXC_BOOT_MODE2_CCMSRCGPCMIX_BOOT_MODE2                        0x020 0x25C 0x000 0x0 0x0
+#define MX8MN_IOMUXC_BOOT_MODE2_I2C1_SCL                                       0x020 0x25C 0x55C 0x1 0x3
+#define MX8MN_IOMUXC_BOOT_MODE3_CCMSRCGPCMIX_BOOT_MODE3                        0x024 0x260 0x000 0x0 0x0
+#define MX8MN_IOMUXC_BOOT_MODE3_I2C1_SDA                                       0x024 0x260 0x56C 0x1 0x3
+#define MX8MN_IOMUXC_GPIO1_IO00_GPIO1_IO0                                      0x028 0x290 0x000 0x0 0x0
+#define MX8MN_IOMUXC_GPIO1_IO00_CCMSRCGPCMIX_ENET_PHY_REF_CLK_ROOT             0x028 0x290 0x000 0x1 0x0
+#define MX8MN_IOMUXC_GPIO1_IO00_ANAMIX_REF_CLK_32K                             0x028 0x290 0x000 0x5 0x0
+#define MX8MN_IOMUXC_GPIO1_IO00_CCMSRCGPCMIX_EXT_CLK1                          0x028 0x290 0x000 0x6 0x0
+#define MX8MN_IOMUXC_GPIO1_IO01_GPIO1_IO1                                      0x02C 0x294 0x000 0x0 0x0
+#define MX8MN_IOMUXC_GPIO1_IO01_PWM1_OUT                                       0x02C 0x294 0x000 0x1 0x0
+#define MX8MN_IOMUXC_GPIO1_IO01_ANAMIX_REF_CLK_24M                             0x02C 0x294 0x000 0x5 0x0
+#define MX8MN_IOMUXC_GPIO1_IO01_CCMSRCGPCMIX_EXT_CLK2                          0x02C 0x294 0x000 0x6 0x0
+#define MX8MN_IOMUXC_GPIO1_IO02_GPIO1_IO2                                      0x030 0x298 0x000 0x0 0x0
+#define MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B                                   0x030 0x298 0x000 0x1 0x0
+#define MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_ANY                                 0x030 0x298 0x000 0x5 0x0
+#define MX8MN_IOMUXC_GPIO1_IO03_GPIO1_IO3                                      0x034 0x29C 0x000 0x0 0x0
+#define MX8MN_IOMUXC_GPIO1_IO03_USDHC1_VSELECT                                 0x034 0x29C 0x000 0x1 0x0
+#define MX8MN_IOMUXC_GPIO1_IO03_SDMA1_EXT_EVENT0                               0x034 0x29C 0x000 0x5 0x0
+#define MX8MN_IOMUXC_GPIO1_IO03_ANAMIX_XTAL_OK                                 0x034 0x29C 0x000 0x6 0x0
+#define MX8MN_IOMUXC_GPIO1_IO04_GPIO1_IO4                                      0x038 0x2A0 0x000 0x0 0x0
+#define MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT                                 0x038 0x2A0 0x000 0x1 0x0
+#define MX8MN_IOMUXC_GPIO1_IO04_SDMA1_EXT_EVENT1                               0x038 0x2A0 0x000 0x5 0x0
+#define MX8MN_IOMUXC_GPIO1_IO04_ANAMIX_XTAL_OK_LV                              0x038 0x2A0 0x000 0x6 0x0
+#define MX8MN_IOMUXC_GPIO1_IO05_GPIO1_IO5                                      0x03C 0x2A4 0x000 0x0 0x0
+#define MX8MN_IOMUXC_GPIO1_IO05_M4_NMI                                         0x03C 0x2A4 0x000 0x1 0x0
+#define MX8MN_IOMUXC_GPIO1_IO05_CCMSRCGPCMIX_PMIC_READY                        0x03C 0x2A4 0x4BC 0x5 0x0
+#define MX8MN_IOMUXC_GPIO1_IO05_CCMSRCGPCMIX_INT_BOOT                          0x03C 0x2A4 0x000 0x6 0x0
+#define MX8MN_IOMUXC_GPIO1_IO06_GPIO1_IO6                                      0x040 0x2A8 0x000 0x0 0x0
+#define MX8MN_IOMUXC_GPIO1_IO06_ENET1_MDC                                      0x040 0x2A8 0x000 0x1 0x0
+#define MX8MN_IOMUXC_GPIO1_IO06_USDHC1_CD_B                                    0x040 0x2A8 0x000 0x5 0x0
+#define MX8MN_IOMUXC_GPIO1_IO06_CCMSRCGPCMIX_EXT_CLK3                          0x040 0x2A8 0x000 0x6 0x0
+#define MX8MN_IOMUXC_GPIO1_IO07_GPIO1_IO7                                      0x044 0x2AC 0x000 0x0 0x0
+#define MX8MN_IOMUXC_GPIO1_IO07_ENET1_MDIO                                     0x044 0x2AC 0x4C0 0x1 0x0
+#define MX8MN_IOMUXC_GPIO1_IO07_USDHC1_WP                                      0x044 0x2AC 0x000 0x5 0x0
+#define MX8MN_IOMUXC_GPIO1_IO07_CCMSRCGPCMIX_EXT_CLK4                          0x044 0x2AC 0x000 0x6 0x0
+#define MX8MN_IOMUXC_GPIO1_IO08_GPIO1_IO8                                      0x048 0x2B0 0x000 0x0 0x0
+#define MX8MN_IOMUXC_GPIO1_IO08_ENET1_1588_EVENT0_IN                           0x048 0x2B0 0x000 0x1 0x0
+#define MX8MN_IOMUXC_GPIO1_IO08_PWM1_OUT                                       0x048 0x2B0 0x000 0x2 0x0
+#define MX8MN_IOMUXC_GPIO1_IO08_USDHC2_RESET_B                                 0x048 0x2B0 0x000 0x5 0x0
+#define MX8MN_IOMUXC_GPIO1_IO08_CCMSRCGPCMIX_WAIT                              0x048 0x2B0 0x000 0x6 0x0
+#define MX8MN_IOMUXC_GPIO1_IO09_GPIO1_IO9                                      0x04C 0x2B4 0x000 0x0 0x0
+#define MX8MN_IOMUXC_GPIO1_IO09_ENET1_1588_EVENT0_OUT                          0x04C 0x2B4 0x000 0x1 0x0
+#define MX8MN_IOMUXC_GPIO1_IO09_PWM2_OUT                                       0x04C 0x2B4 0x000 0x2 0x0
+#define MX8MN_IOMUXC_GPIO1_IO09_USDHC3_RESET_B                                 0x04C 0x2B4 0x000 0x4 0x0
+#define MX8MN_IOMUXC_GPIO1_IO09_SDMA2_EXT_EVENT0                               0x04C 0x2B4 0x000 0x5 0x0
+#define MX8MN_IOMUXC_GPIO1_IO09_CCMSRCGPCMIX_STOP                              0x04C 0x2B4 0x000 0x6 0x0
+#define MX8MN_IOMUXC_GPIO1_IO10_GPIO1_IO10                                     0x050 0x2B8 0x000 0x0 0x0
+#define MX8MN_IOMUXC_GPIO1_IO10_USB1_OTG_ID                                    0x050 0x2B8 0x000 0x1 0x0
+#define MX8MN_IOMUXC_GPIO1_IO10_PWM3_OUT                                       0x050 0x2B8 0x000 0x2 0x0
+#define MX8MN_IOMUXC_GPIO1_IO11_GPIO1_IO11                                     0x054 0x2BC 0x000 0x0 0x0
+#define MX8MN_IOMUXC_GPIO1_IO11_PWM2_OUT                                       0x054 0x2BC 0x000 0x1 0x0
+#define MX8MN_IOMUXC_GPIO1_IO11_USDHC3_VSELECT                                 0x054 0x2BC 0x000 0x4 0x0
+#define MX8MN_IOMUXC_GPIO1_IO11_CCMSRCGPCMIX_PMIC_READY                        0x054 0x2BC 0x4BC 0x5 0x1
+#define MX8MN_IOMUXC_GPIO1_IO11_CCMSRCGPCMIX_OUT0                              0x054 0x2BC 0x000 0x6 0x0
+#define MX8MN_IOMUXC_GPIO1_IO12_GPIO1_IO12                                     0x058 0x2C0 0x000 0x0 0x0
+#define MX8MN_IOMUXC_GPIO1_IO12_USB1_OTG_PWR                                   0x058 0x2C0 0x000 0x1 0x0
+#define MX8MN_IOMUXC_GPIO1_IO12_SDMA2_EXT_EVENT1                               0x058 0x2C0 0x000 0x5 0x0
+#define MX8MN_IOMUXC_GPIO1_IO12_CCMSRCGPCMIX_OUT1                              0x058 0x2C0 0x000 0x6 0x0
+#define MX8MN_IOMUXC_GPIO1_IO13_GPIO1_IO13                                     0x05C 0x2C4 0x000 0x0 0x0
+#define MX8MN_IOMUXC_GPIO1_IO13_USB1_OTG_OC                                    0x05C 0x2C4 0x000 0x1 0x0
+#define MX8MN_IOMUXC_GPIO1_IO13_PWM2_OUT                                       0x05C 0x2C4 0x000 0x5 0x0
+#define MX8MN_IOMUXC_GPIO1_IO13_CCMSRCGPCMIX_OUT2                              0x05C 0x2C4 0x000 0x6 0x0
+#define MX8MN_IOMUXC_GPIO1_IO14_GPIO1_IO14                                     0x060 0x2C8 0x000 0x0 0x0
+#define MX8MN_IOMUXC_GPIO1_IO14_USDHC3_CD_B                                    0x060 0x2C8 0x598 0x4 0x2
+#define MX8MN_IOMUXC_GPIO1_IO14_PWM3_OUT                                       0x060 0x2C8 0x000 0x5 0x0
+#define MX8MN_IOMUXC_GPIO1_IO14_CCMSRCGPCMIX_CLKO1                             0x060 0x2C8 0x000 0x6 0x0
+#define MX8MN_IOMUXC_GPIO1_IO15_GPIO1_IO15                                     0x064 0x2CC 0x000 0x0 0x0
+#define MX8MN_IOMUXC_GPIO1_IO15_USDHC3_WP                                      0x064 0x2CC 0x5B8 0x4 0x2
+#define MX8MN_IOMUXC_GPIO1_IO15_PWM4_OUT                                       0x064 0x2CC 0x000 0x5 0x0
+#define MX8MN_IOMUXC_GPIO1_IO15_CCMSRCGPCMIX_CLKO2                             0x064 0x2CC 0x000 0x6 0x0
+#define MX8MN_IOMUXC_ENET_MDC_ENET1_MDC                                        0x068 0x2D0 0x000 0x0 0x0
+#define MX8MN_IOMUXC_ENET_MDC_SAI6_TX_DATA0                                    0x068 0x2D0 0x000 0x2 0x0
+#define MX8MN_IOMUXC_ENET_MDC_PDM_BIT_STREAM3                                  0x068 0x2D0 0x540 0x3 0x1
+#define MX8MN_IOMUXC_ENET_MDC_SPDIF1_OUT                                       0x068 0x2D0 0x000 0x4 0x0
+#define MX8MN_IOMUXC_ENET_MDC_GPIO1_IO16                                       0x068 0x2D0 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ENET_MDC_USDHC3_STROBE                                    0x068 0x2D0 0x59C 0x6 0x1
+#define MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO                                      0x06C 0x2D4 0x4C0 0x0 0x1
+#define MX8MN_IOMUXC_ENET_MDIO_SAI6_TX_SYNC                                    0x06C 0x2D4 0x000 0x2 0x0
+#define MX8MN_IOMUXC_ENET_MDIO_PDM_BIT_STREAM2                                 0x06C 0x2D4 0x53C 0x3 0x1
+#define MX8MN_IOMUXC_ENET_MDIO_SPDIF1_IN                                       0x06C 0x2D4 0x5CC 0x4 0x1
+#define MX8MN_IOMUXC_ENET_MDIO_GPIO1_IO17                                      0x06C 0x2D4 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ENET_MDIO_USDHC3_DATA5                                    0x06C 0x2D4 0x550 0x6 0x1
+#define MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3                                  0x070 0x2D8 0x000 0x0 0x0
+#define MX8MN_IOMUXC_ENET_TD3_SAI6_TX_BCLK                                     0x070 0x2D8 0x000 0x2 0x0
+#define MX8MN_IOMUXC_ENET_TD3_PDM_BIT_STREAM1                                  0x070 0x2D8 0x538 0x3 0x1
+#define MX8MN_IOMUXC_ENET_TD3_SPDIF1_EXT_CLK                                   0x070 0x2D8 0x568 0x4 0x1
+#define MX8MN_IOMUXC_ENET_TD3_GPIO1_IO18                                       0x070 0x2D8 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ENET_TD3_USDHC3_DATA6                                     0x070 0x2D8 0x584 0x6 0x1
+#define MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2                                  0x074 0x2DC 0x000 0x0 0x0
+#define MX8MN_IOMUXC_ENET_TD2_ENET1_TX_CLK                                     0x074 0x2DC 0x5A4 0x1 0x0
+#define MX8MN_IOMUXC_ENET_TD2_CCMSRCGPCMIX_ENET_REF_CLK_ROOT                   0x074 0x2DC 0x5A4 0x1 0x0
+#define MX8MN_IOMUXC_ENET_TD2_SAI6_RX_DATA0                                    0x074 0x2DC 0x000 0x2 0x0
+#define MX8MN_IOMUXC_ENET_TD2_PDM_BIT_STREAM3                                  0x074 0x2DC 0x540 0x3 0x2
+#define MX8MN_IOMUXC_ENET_TD2_GPIO1_IO19                                       0x074 0x2DC 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ENET_TD2_USDHC3_DATA7                                     0x074 0x2DC 0x54C 0x6 0x1
+#define MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1                                  0x078 0x2E0 0x000 0x0 0x0
+#define MX8MN_IOMUXC_ENET_TD1_SAI6_RX_SYNC                                     0x078 0x2E0 0x000 0x2 0x0
+#define MX8MN_IOMUXC_ENET_TD1_PDM_BIT_STREAM2                                  0x078 0x2E0 0x53C 0x3 0x2
+#define MX8MN_IOMUXC_ENET_TD1_GPIO1_IO20                                       0x078 0x2E0 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ENET_TD1_USDHC3_CD_B                                      0x078 0x2E0 0x598 0x6 0x3
+#define MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0                                  0x07C 0x2E4 0x000 0x0 0x0
+#define MX8MN_IOMUXC_ENET_TD0_SAI6_RX_BCLK                                     0x07C 0x2E4 0x000 0x2 0x0
+#define MX8MN_IOMUXC_ENET_TD0_PDM_BIT_STREAM1                                  0x07C 0x2E4 0x538 0x3 0x2
+#define MX8MN_IOMUXC_ENET_TD0_GPIO1_IO21                                       0x07C 0x2E4 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ENET_TD0_USDHC3_WP                                        0x07C 0x2E4 0x5B8 0x6 0x3
+#define MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL                            0x080 0x2E8 0x000 0x0 0x0
+#define MX8MN_IOMUXC_ENET_TX_CTL_SAI6_MCLK                                     0x080 0x2E8 0x000 0x2 0x0
+#define MX8MN_IOMUXC_ENET_TX_CTL_GPIO1_IO22                                    0x080 0x2E8 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ENET_TX_CTL_USDHC3_DATA0                                  0x080 0x2E8 0x5B4 0x6 0x1
+#define MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC                                  0x084 0x2EC 0x000 0x0 0x0
+#define MX8MN_IOMUXC_ENET_TXC_ENET1_TX_ER                                      0x084 0x2EC 0x000 0x1 0x0
+#define MX8MN_IOMUXC_ENET_TXC_SAI7_TX_DATA0                                    0x084 0x2EC 0x000 0x2 0x0
+#define MX8MN_IOMUXC_ENET_TXC_GPIO1_IO23                                       0x084 0x2EC 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ENET_TXC_USDHC3_DATA1                                     0x084 0x2EC 0x5B0 0x6 0x1
+#define MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL                            0x088 0x2F0 0x574 0x0 0x0
+#define MX8MN_IOMUXC_ENET_RX_CTL_SAI7_TX_SYNC                                  0x088 0x2F0 0x000 0x2 0x0
+#define MX8MN_IOMUXC_ENET_RX_CTL_PDM_BIT_STREAM3                               0x088 0x2F0 0x540 0x3 0x3
+#define MX8MN_IOMUXC_ENET_RX_CTL_GPIO1_IO24                                    0x088 0x2F0 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ENET_RX_CTL_USDHC3_DATA2                                  0x088 0x2F0 0x5E4 0x6 0x1
+#define MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC                                  0x08C 0x2F4 0x000 0x0 0x0
+#define MX8MN_IOMUXC_ENET_RXC_ENET1_RX_ER                                      0x08C 0x2F4 0x5C8 0x1 0x0
+#define MX8MN_IOMUXC_ENET_RXC_SAI7_TX_BCLK                                     0x08C 0x2F4 0x000 0x2 0x0
+#define MX8MN_IOMUXC_ENET_RXC_PDM_BIT_STREAM2                                  0x08C 0x2F4 0x53C 0x3 0x3
+#define MX8MN_IOMUXC_ENET_RXC_GPIO1_IO25                                       0x08C 0x2F4 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ENET_RXC_USDHC3_DATA3                                     0x08C 0x2F4 0x5E0 0x6 0x1
+#define MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0                                  0x090 0x2F8 0x57C 0x0 0x0
+#define MX8MN_IOMUXC_ENET_RD0_SAI7_RX_DATA0                                    0x090 0x2F8 0x000 0x2 0x0
+#define MX8MN_IOMUXC_ENET_RD0_PDM_BIT_STREAM1                                  0x090 0x2F8 0x538 0x3 0x3
+#define MX8MN_IOMUXC_ENET_RD0_GPIO1_IO26                                       0x090 0x2F8 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ENET_RD0_USDHC3_DATA4                                     0x090 0x2F8 0x558 0x6 0x1
+#define MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1                                  0x094 0x2FC 0x554 0x0 0x0
+#define MX8MN_IOMUXC_ENET_RD1_SAI7_RX_SYNC                                     0x094 0x2FC 0x000 0x2 0x0
+#define MX8MN_IOMUXC_ENET_RD1_PDM_BIT_STREAM0                                  0x094 0x2FC 0x534 0x3 0x1
+#define MX8MN_IOMUXC_ENET_RD1_GPIO1_IO27                                       0x094 0x2FC 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ENET_RD1_USDHC3_RESET_B                                   0x094 0x2FC 0x000 0x6 0x0
+#define MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2                                  0x098 0x300 0x000 0x0 0x0
+#define MX8MN_IOMUXC_ENET_RD2_SAI7_RX_BCLK                                     0x098 0x300 0x000 0x2 0x0
+#define MX8MN_IOMUXC_ENET_RD2_PDM_CLK                                          0x098 0x300 0x000 0x3 0x0
+#define MX8MN_IOMUXC_ENET_RD2_GPIO1_IO28                                       0x098 0x300 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ENET_RD2_USDHC3_CLK                                       0x098 0x300 0x5A0 0x6 0x1
+#define MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3                                  0x09C 0x304 0x000 0x0 0x0
+#define MX8MN_IOMUXC_ENET_RD3_SAI7_MCLK                                        0x09C 0x304 0x000 0x2 0x0
+#define MX8MN_IOMUXC_ENET_RD3_SPDIF1_IN                                        0x09C 0x304 0x5CC 0x3 0x5
+#define MX8MN_IOMUXC_ENET_RD3_GPIO1_IO29                                       0x09C 0x304 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ENET_RD3_USDHC3_CMD                                       0x09C 0x304 0x5DC 0x6 0x1
+#define MX8MN_IOMUXC_SD1_CLK_USDHC1_CLK                                        0x0A0 0x308 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD1_CLK_ENET1_MDC                                         0x0A0 0x308 0x000 0x1 0x0
+#define MX8MN_IOMUXC_SD1_CLK_UART1_DCE_TX                                      0x0A0 0x308 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SD1_CLK_UART1_DTE_RX                                      0x0A0 0x308 0x4F4 0x4 0x4
+#define MX8MN_IOMUXC_SD1_CLK_GPIO2_IO0                                         0x0A0 0x308 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD1_CMD_USDHC1_CMD                                        0x0A4 0x30C 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD1_CMD_ENET1_MDIO                                        0x0A4 0x30C 0x4C0 0x1 0x3
+#define MX8MN_IOMUXC_SD1_CMD_UART1_DCE_RX                                      0x0A4 0x30C 0x4F4 0x4 0x5
+#define MX8MN_IOMUXC_SD1_CMD_UART1_DTE_TX                                      0x0A4 0x30C 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SD1_CMD_GPIO2_IO1                                         0x0A4 0x30C 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD1_DATA0_USDHC1_DATA0                                    0x0A8 0x310 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD1_DATA0_ENET1_RGMII_TD1                                 0x0A8 0x310 0x000 0x1 0x0
+#define MX8MN_IOMUXC_SD1_DATA0_UART1_DCE_RTS_B                                 0x0A8 0x310 0x4F0 0x4 0x4
+#define MX8MN_IOMUXC_SD1_DATA0_UART1_DTE_CTS_B                                 0x0A8 0x310 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SD1_DATA0_GPIO2_IO2                                       0x0A8 0x310 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD1_DATA1_USDHC1_DATA1                                    0x0AC 0x314 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD1_DATA1_ENET1_RGMII_TD0                                 0x0AC 0x314 0x000 0x1 0x0
+#define MX8MN_IOMUXC_SD1_DATA1_UART1_DCE_CTS_B                                 0x0AC 0x314 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SD1_DATA1_UART1_DTE_RTS_B                                 0x0AC 0x314 0x4F0 0x4 0x5
+#define MX8MN_IOMUXC_SD1_DATA1_GPIO2_IO3                                       0x0AC 0x314 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD1_DATA2_USDHC1_DATA2                                    0x0B0 0x318 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD1_DATA2_ENET1_RGMII_RD0                                 0x0B0 0x318 0x57C 0x1 0x1
+#define MX8MN_IOMUXC_SD1_DATA2_UART2_DCE_TX                                    0x0B0 0x318 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SD1_DATA2_UART2_DTE_RX                                    0x0B0 0x318 0x4FC 0x4 0x4
+#define MX8MN_IOMUXC_SD1_DATA2_GPIO2_IO4                                       0x0B0 0x318 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD1_DATA3_USDHC1_DATA3                                    0x0B4 0x31C 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD1_DATA3_ENET1_RGMII_RD1                                 0x0B4 0x31C 0x554 0x1 0x1
+#define MX8MN_IOMUXC_SD1_DATA3_UART2_DCE_RX                                    0x0B4 0x31C 0x4FC 0x4 0x5
+#define MX8MN_IOMUXC_SD1_DATA3_UART2_DTE_TX                                    0x0B4 0x31C 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SD1_DATA3_GPIO2_IO5                                       0x0B4 0x31C 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD1_DATA4_USDHC1_DATA4                                    0x0B8 0x320 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD1_DATA4_ENET1_RGMII_TX_CTL                              0x0B8 0x320 0x000 0x1 0x0
+#define MX8MN_IOMUXC_SD1_DATA4_I2C1_SCL                                        0x0B8 0x320 0x55C 0x3 0x1
+#define MX8MN_IOMUXC_SD1_DATA4_UART2_DCE_RTS_B                                 0x0B8 0x320 0x4F8 0x4 0x4
+#define MX8MN_IOMUXC_SD1_DATA4_UART2_DTE_CTS_B                                 0x0B8 0x320 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SD1_DATA4_GPIO2_IO6                                       0x0B8 0x320 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD1_DATA5_USDHC1_DATA5                                    0x0BC 0x324 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD1_DATA5_ENET1_TX_ER                                     0x0BC 0x324 0x000 0x1 0x0
+#define MX8MN_IOMUXC_SD1_DATA5_I2C1_SDA                                        0x0BC 0x324 0x56C 0x3 0x1
+#define MX8MN_IOMUXC_SD1_DATA5_UART2_DCE_CTS_B                                 0x0BC 0x324 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SD1_DATA5_UART2_DTE_RTS_B                                 0x0BC 0x324 0x4F8 0x4 0x5
+#define MX8MN_IOMUXC_SD1_DATA5_GPIO2_IO7                                       0x0BC 0x324 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD1_DATA6_USDHC1_DATA6                                    0x0C0 0x328 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD1_DATA6_ENET1_RGMII_RX_CTL                              0x0C0 0x328 0x574 0x1 0x1
+#define MX8MN_IOMUXC_SD1_DATA6_I2C2_SCL                                        0x0C0 0x328 0x5D0 0x3 0x1
+#define MX8MN_IOMUXC_SD1_DATA6_UART3_DCE_TX                                    0x0C0 0x328 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SD1_DATA6_UART3_DTE_RX                                    0x0C0 0x328 0x504 0x4 0x4
+#define MX8MN_IOMUXC_SD1_DATA6_GPIO2_IO8                                       0x0C0 0x328 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD1_DATA7_USDHC1_DATA7                                    0x0C4 0x32C 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD1_DATA7_ENET1_RX_ER                                     0x0C4 0x32C 0x5C8 0x1 0x1
+#define MX8MN_IOMUXC_SD1_DATA7_I2C2_SDA                                        0x0C4 0x32C 0x560 0x3 0x1
+#define MX8MN_IOMUXC_SD1_DATA7_UART3_DCE_RX                                    0x0C4 0x32C 0x504 0x4 0x5
+#define MX8MN_IOMUXC_SD1_DATA7_UART3_DTE_TX                                    0x0C4 0x32C 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SD1_DATA7_GPIO2_IO9                                       0x0C4 0x32C 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD1_RESET_B_USDHC1_RESET_B                                0x0C8 0x330 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD1_RESET_B_ENET1_TX_CLK                                  0x0C8 0x330 0x5A4 0x1 0x1
+#define MX8MN_IOMUXC_SD1_RESET_B_CCMSRCGPCMIX_ENET_REF_CLK_ROOT                0x0C8 0x330 0x5A4 0x1 0x0
+#define MX8MN_IOMUXC_SD1_RESET_B_I2C3_SCL                                      0x0C8 0x330 0x588 0x3 0x1
+#define MX8MN_IOMUXC_SD1_RESET_B_UART3_DCE_RTS_B                               0x0C8 0x330 0x500 0x4 0x2
+#define MX8MN_IOMUXC_SD1_RESET_B_UART3_DTE_CTS_B                               0x0C8 0x330 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SD1_RESET_B_GPIO2_IO10                                    0x0C8 0x330 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD1_STROBE_USDHC1_STROBE                                  0x0CC 0x334 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD1_STROBE_I2C3_SDA                                       0x0CC 0x334 0x5BC 0x3 0x1
+#define MX8MN_IOMUXC_SD1_STROBE_UART3_DCE_CTS_B                                0x0CC 0x334 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SD1_STROBE_UART3_DTE_RTS_B                                0x0CC 0x334 0x500 0x4 0x3
+#define MX8MN_IOMUXC_SD1_STROBE_GPIO2_IO11                                     0x0CC 0x334 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD2_CD_B_USDHC2_CD_B                                      0x0D0 0x338 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD2_CD_B_GPIO2_IO12                                       0x0D0 0x338 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD2_CD_B_CCMSRCGPCMIX_TESTER_ACK                          0x0D0 0x338 0x000 0x6 0x0
+#define MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK                                        0x0D4 0x33C 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD2_CLK_SAI5_RX_SYNC                                      0x0D4 0x33C 0x4E4 0x1 0x1
+#define MX8MN_IOMUXC_SD2_CLK_ECSPI2_SCLK                                       0x0D4 0x33C 0x580 0x2 0x1
+#define MX8MN_IOMUXC_SD2_CLK_UART4_DCE_RX                                      0x0D4 0x33C 0x50C 0x3 0x4
+#define MX8MN_IOMUXC_SD2_CLK_UART4_DTE_TX                                      0x0D4 0x33C 0x000 0x3 0x0
+#define MX8MN_IOMUXC_SD2_CLK_SAI5_MCLK                                         0x0D4 0x33C 0x594 0x4 0x1
+#define MX8MN_IOMUXC_SD2_CLK_GPIO2_IO13                                        0x0D4 0x33C 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD2_CLK_CCMSRCGPCMIX_OBSERVE0                             0x0D4 0x33C 0x000 0x6 0x0
+#define MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD                                        0x0D8 0x340 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD2_CMD_SAI5_RX_BCLK                                      0x0D8 0x340 0x4D0 0x1 0x1
+#define MX8MN_IOMUXC_SD2_CMD_ECSPI2_MOSI                                       0x0D8 0x340 0x590 0x2 0x1
+#define MX8MN_IOMUXC_SD2_CMD_UART4_DCE_TX                                      0x0D8 0x340 0x000 0x3 0x0
+#define MX8MN_IOMUXC_SD2_CMD_UART4_DTE_RX                                      0x0D8 0x340 0x50C 0x3 0x5
+#define MX8MN_IOMUXC_SD2_CMD_PDM_CLK                                           0x0D8 0x340 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SD2_CMD_GPIO2_IO14                                        0x0D8 0x340 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD2_CMD_CCMSRCGPCMIX_OBSERVE1                             0x0D8 0x340 0x000 0x6 0x0
+#define MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0                                    0x0DC 0x344 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD2_DATA0_SAI5_RX_DATA0                                   0x0DC 0x344 0x4D4 0x1 0x1
+#define MX8MN_IOMUXC_SD2_DATA0_I2C4_SDA                                        0x0DC 0x344 0x58C 0x2 0x1
+#define MX8MN_IOMUXC_SD2_DATA0_UART2_DCE_RX                                    0x0DC 0x344 0x4FC 0x3 0x6
+#define MX8MN_IOMUXC_SD2_DATA0_UART2_DTE_TX                                    0x0DC 0x344 0x000 0x3 0x0
+#define MX8MN_IOMUXC_SD2_DATA0_PDM_BIT_STREAM0                                 0x0DC 0x344 0x534 0x4 0x2
+#define MX8MN_IOMUXC_SD2_DATA0_GPIO2_IO15                                      0x0DC 0x344 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD2_DATA0_CCMSRCGPCMIX_OBSERVE2                           0x0DC 0x344 0x000 0x6 0x0
+#define MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1                                    0x0E0 0x348 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD2_DATA1_SAI5_TX_SYNC                                    0x0E0 0x348 0x4EC 0x1 0x1
+#define MX8MN_IOMUXC_SD2_DATA1_I2C4_SCL                                        0x0E0 0x348 0x5D4 0x2 0x1
+#define MX8MN_IOMUXC_SD2_DATA1_UART2_DCE_TX                                    0x0E0 0x348 0x000 0x3 0x0
+#define MX8MN_IOMUXC_SD2_DATA1_UART2_DTE_RX                                    0x0E0 0x348 0x4FC 0x3 0x7
+#define MX8MN_IOMUXC_SD2_DATA1_PDM_BIT_STREAM1                                 0x0E0 0x348 0x538 0x4 0x4
+#define MX8MN_IOMUXC_SD2_DATA1_GPIO2_IO16                                      0x0E0 0x348 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD2_DATA1_CCMSRCGPCMIX_WAIT                               0x0E0 0x348 0x000 0x6 0x0
+#define MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2                                    0x0E4 0x34C 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD2_DATA2_SAI5_TX_BCLK                                    0x0E4 0x34C 0x4E8 0x1 0x1
+#define MX8MN_IOMUXC_SD2_DATA2_ECSPI2_SS0                                      0x0E4 0x34C 0x570 0x2 0x2
+#define MX8MN_IOMUXC_SD2_DATA2_SPDIF1_OUT                                      0x0E4 0x34C 0x000 0x3 0x0
+#define MX8MN_IOMUXC_SD2_DATA2_PDM_BIT_STREAM2                                 0x0E4 0x34C 0x53C 0x4 0x4
+#define MX8MN_IOMUXC_SD2_DATA2_GPIO2_IO17                                      0x0E4 0x34C 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD2_DATA2_CCMSRCGPCMIX_STOP                               0x0E4 0x34C 0x000 0x6 0x0
+#define MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3                                    0x0E8 0x350 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD2_DATA3_SAI5_TX_DATA0                                   0x0E8 0x350 0x000 0x1 0x0
+#define MX8MN_IOMUXC_SD2_DATA3_ECSPI2_MISO                                     0x0E8 0x350 0x578 0x2 0x1
+#define MX8MN_IOMUXC_SD2_DATA3_SPDIF1_IN                                       0x0E8 0x350 0x5CC 0x3 0x2
+#define MX8MN_IOMUXC_SD2_DATA3_PDM_BIT_STREAM3                                 0x0E8 0x350 0x540 0x4 0x4
+#define MX8MN_IOMUXC_SD2_DATA3_GPIO2_IO18                                      0x0E8 0x350 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD2_DATA3_CCMSRCGPCMIX_EARLY_RESET                        0x0E8 0x350 0x000 0x6 0x0
+#define MX8MN_IOMUXC_SD2_RESET_B_USDHC2_RESET_B                                0x0EC 0x354 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD2_RESET_B_GPIO2_IO19                                    0x0EC 0x354 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD2_RESET_B_CCMSRCGPCMIX_SYSTEM_RESET                     0x0EC 0x354 0x000 0x6 0x0
+#define MX8MN_IOMUXC_SD2_WP_USDHC2_WP                                          0x0F0 0x358 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SD2_WP_GPIO2_IO20                                         0x0F0 0x358 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SD2_WP_CORESIGHT_EVENTI                                   0x0F0 0x358 0x000 0x6 0x0
+#define MX8MN_IOMUXC_NAND_ALE_RAWNAND_ALE                                      0x0F4 0x35C 0x000 0x0 0x0
+#define MX8MN_IOMUXC_NAND_ALE_QSPI_A_SCLK                                      0x0F4 0x35C 0x000 0x1 0x0
+#define MX8MN_IOMUXC_NAND_ALE_PDM_BIT_STREAM0                                  0x0F4 0x35C 0x534 0x3 0x3
+#define MX8MN_IOMUXC_NAND_ALE_UART3_DCE_RX                                     0x0F4 0x35C 0x504 0x4 0x6
+#define MX8MN_IOMUXC_NAND_ALE_UART3_DTE_TX                                     0x0F4 0x35C 0x000 0x4 0x0
+#define MX8MN_IOMUXC_NAND_ALE_GPIO3_IO0                                        0x0F4 0x35C 0x000 0x5 0x0
+#define MX8MN_IOMUXC_NAND_ALE_CORESIGHT_TRACE_CLK                              0x0F4 0x35C 0x000 0x6 0x0
+#define MX8MN_IOMUXC_NAND_CE0_B_RAWNAND_CE0_B                                  0x0F8 0x360 0x000 0x0 0x0
+#define MX8MN_IOMUXC_NAND_CE0_B_QSPI_A_SS0_B                                   0x0F8 0x360 0x000 0x1 0x0
+#define MX8MN_IOMUXC_NAND_CE0_B_PDM_BIT_STREAM1                                0x0F8 0x360 0x538 0x3 0x5
+#define MX8MN_IOMUXC_NAND_CE0_B_UART3_DCE_TX                                   0x0F8 0x360 0x000 0x4 0x0
+#define MX8MN_IOMUXC_NAND_CE0_B_UART3_DTE_RX                                   0x0F8 0x360 0x504 0x4 0x7
+#define MX8MN_IOMUXC_NAND_CE0_B_GPIO3_IO1                                      0x0F8 0x360 0x000 0x5 0x0
+#define MX8MN_IOMUXC_NAND_CE0_B_CORESIGHT_TRACE_CTL                            0x0F8 0x360 0x000 0x6 0x0
+#define MX8MN_IOMUXC_NAND_CE1_B_RAWNAND_CE1_B                                  0x0FC 0x364 0x000 0x0 0x0
+#define MX8MN_IOMUXC_NAND_CE1_B_QSPI_A_SS1_B                                   0x0FC 0x364 0x000 0x1 0x0
+#define MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE                                  0x0FC 0x364 0x59C 0x2 0x0
+#define MX8MN_IOMUXC_NAND_CE1_B_PDM_BIT_STREAM0                                0x0FC 0x364 0x534 0x3 0x4
+#define MX8MN_IOMUXC_NAND_CE1_B_I2C4_SCL                                       0x0FC 0x364 0x5D4 0x4 0x2
+#define MX8MN_IOMUXC_NAND_CE1_B_GPIO3_IO2                                      0x0FC 0x364 0x000 0x5 0x0
+#define MX8MN_IOMUXC_NAND_CE1_B_CORESIGHT_TRACE0                               0x0FC 0x364 0x000 0x6 0x0
+#define MX8MN_IOMUXC_NAND_CE2_B_RAWNAND_CE2_B                                  0x100 0x368 0x000 0x0 0x0
+#define MX8MN_IOMUXC_NAND_CE2_B_QSPI_B_SS0_B                                   0x100 0x368 0x000 0x1 0x0
+#define MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5                                   0x100 0x368 0x550 0x2 0x0
+#define MX8MN_IOMUXC_NAND_CE2_B_PDM_BIT_STREAM1                                0x100 0x368 0x538 0x3 0x6
+#define MX8MN_IOMUXC_NAND_CE2_B_I2C4_SDA                                       0x100 0x368 0x58C 0x4 0x2
+#define MX8MN_IOMUXC_NAND_CE2_B_GPIO3_IO3                                      0x100 0x368 0x000 0x5 0x0
+#define MX8MN_IOMUXC_NAND_CE2_B_CORESIGHT_TRACE1                               0x100 0x368 0x000 0x6 0x0
+#define MX8MN_IOMUXC_NAND_CE3_B_RAWNAND_CE3_B                                  0x104 0x36C 0x000 0x0 0x0
+#define MX8MN_IOMUXC_NAND_CE3_B_QSPI_B_SS1_B                                   0x104 0x36C 0x000 0x1 0x0
+#define MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6                                   0x104 0x36C 0x584 0x2 0x0
+#define MX8MN_IOMUXC_NAND_CE3_B_PDM_BIT_STREAM2                                0x104 0x36C 0x53C 0x3 0x5
+#define MX8MN_IOMUXC_NAND_CE3_B_I2C3_SDA                                       0x104 0x36C 0x5BC 0x4 0x2
+#define MX8MN_IOMUXC_NAND_CE3_B_GPIO3_IO4                                      0x104 0x36C 0x000 0x5 0x0
+#define MX8MN_IOMUXC_NAND_CE3_B_CORESIGHT_TRACE2                               0x104 0x36C 0x000 0x6 0x0
+#define MX8MN_IOMUXC_NAND_CLE_RAWNAND_CLE                                      0x108 0x370 0x000 0x0 0x0
+#define MX8MN_IOMUXC_NAND_CLE_QSPI_B_SCLK                                      0x108 0x370 0x000 0x1 0x0
+#define MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7                                     0x108 0x370 0x54C 0x2 0x0
+#define MX8MN_IOMUXC_NAND_CLE_GPIO3_IO5                                        0x108 0x370 0x000 0x5 0x0
+#define MX8MN_IOMUXC_NAND_CLE_CORESIGHT_TRACE3                                 0x108 0x370 0x000 0x6 0x0
+#define MX8MN_IOMUXC_NAND_DATA00_RAWNAND_DATA00                                0x10C 0x374 0x000 0x0 0x0
+#define MX8MN_IOMUXC_NAND_DATA00_QSPI_A_DATA0                                  0x10C 0x374 0x000 0x1 0x0
+#define MX8MN_IOMUXC_NAND_DATA00_PDM_BIT_STREAM2                               0x10C 0x374 0x53C 0x3 0x6
+#define MX8MN_IOMUXC_NAND_DATA00_UART4_DCE_RX                                  0x10C 0x374 0x50C 0x4 0x6
+#define MX8MN_IOMUXC_NAND_DATA00_UART4_DTE_TX                                  0x10C 0x374 0x000 0x4 0x0
+#define MX8MN_IOMUXC_NAND_DATA00_GPIO3_IO6                                     0x10C 0x374 0x000 0x5 0x0
+#define MX8MN_IOMUXC_NAND_DATA00_CORESIGHT_TRACE4                              0x10C 0x374 0x000 0x6 0x0
+#define MX8MN_IOMUXC_NAND_DATA01_RAWNAND_DATA01                                0x110 0x378 0x000 0x0 0x0
+#define MX8MN_IOMUXC_NAND_DATA01_QSPI_A_DATA1                                  0x110 0x378 0x000 0x1 0x0
+#define MX8MN_IOMUXC_NAND_DATA01_PDM_BIT_STREAM3                               0x110 0x378 0x540 0x3 0x5
+#define MX8MN_IOMUXC_NAND_DATA01_UART4_DCE_TX                                  0x110 0x378 0x000 0x4 0x0
+#define MX8MN_IOMUXC_NAND_DATA01_UART4_DTE_RX                                  0x110 0x378 0x50C 0x4 0x7
+#define MX8MN_IOMUXC_NAND_DATA01_GPIO3_IO7                                     0x110 0x378 0x000 0x5 0x0
+#define MX8MN_IOMUXC_NAND_DATA01_CORESIGHT_TRACE5                              0x110 0x378 0x000 0x6 0x0
+#define MX8MN_IOMUXC_NAND_DATA02_RAWNAND_DATA02                                0x114 0x37C 0x000 0x0 0x0
+#define MX8MN_IOMUXC_NAND_DATA02_QSPI_A_DATA2                                  0x114 0x37C 0x000 0x1 0x0
+#define MX8MN_IOMUXC_NAND_DATA02_USDHC3_CD_B                                   0x114 0x37C 0x598 0x2 0x0
+#define MX8MN_IOMUXC_NAND_DATA02_I2C4_SDA                                      0x114 0x37C 0x58C 0x4 0x3
+#define MX8MN_IOMUXC_NAND_DATA02_GPIO3_IO8                                     0x114 0x37C 0x000 0x5 0x0
+#define MX8MN_IOMUXC_NAND_DATA02_CORESIGHT_TRACE6                              0x114 0x37C 0x000 0x6 0x0
+#define MX8MN_IOMUXC_NAND_DATA03_RAWNAND_DATA03                                0x118 0x380 0x000 0x0 0x0
+#define MX8MN_IOMUXC_NAND_DATA03_QSPI_A_DATA3                                  0x118 0x380 0x000 0x1 0x0
+#define MX8MN_IOMUXC_NAND_DATA03_USDHC3_WP                                     0x118 0x380 0x5B8 0x2 0x0
+#define MX8MN_IOMUXC_NAND_DATA03_GPIO3_IO9                                     0x118 0x380 0x000 0x5 0x0
+#define MX8MN_IOMUXC_NAND_DATA03_CORESIGHT_TRACE7                              0x118 0x380 0x000 0x6 0x0
+#define MX8MN_IOMUXC_NAND_DATA04_RAWNAND_DATA04                                0x11C 0x384 0x000 0x0 0x0
+#define MX8MN_IOMUXC_NAND_DATA04_QSPI_B_DATA0                                  0x11C 0x384 0x000 0x1 0x0
+#define MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0                                  0x11C 0x384 0x5B4 0x2 0x0
+#define MX8MN_IOMUXC_NAND_DATA04_GPIO3_IO10                                    0x11C 0x384 0x000 0x5 0x0
+#define MX8MN_IOMUXC_NAND_DATA04_CORESIGHT_TRACE8                              0x11C 0x384 0x000 0x6 0x0
+#define MX8MN_IOMUXC_NAND_DATA05_RAWNAND_DATA05                                0x120 0x388 0x000 0x0 0x0
+#define MX8MN_IOMUXC_NAND_DATA05_QSPI_B_DATA1                                  0x120 0x388 0x000 0x1 0x0
+#define MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1                                  0x120 0x388 0x5B0 0x2 0x0
+#define MX8MN_IOMUXC_NAND_DATA05_GPIO3_IO11                                    0x120 0x388 0x000 0x5 0x0
+#define MX8MN_IOMUXC_NAND_DATA05_CORESIGHT_TRACE9                              0x120 0x388 0x000 0x6 0x0
+#define MX8MN_IOMUXC_NAND_DATA06_RAWNAND_DATA06                                0x124 0x38C 0x000 0x0 0x0
+#define MX8MN_IOMUXC_NAND_DATA06_QSPI_B_DATA2                                  0x124 0x38C 0x000 0x1 0x0
+#define MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2                                  0x124 0x38C 0x5E4 0x2 0x0
+#define MX8MN_IOMUXC_NAND_DATA06_GPIO3_IO12                                    0x124 0x38C 0x000 0x5 0x0
+#define MX8MN_IOMUXC_NAND_DATA06_CORESIGHT_TRACE10                             0x124 0x38C 0x000 0x6 0x0
+#define MX8MN_IOMUXC_NAND_DATA07_RAWNAND_DATA07                                0x128 0x390 0x000 0x0 0x0
+#define MX8MN_IOMUXC_NAND_DATA07_QSPI_B_DATA3                                  0x128 0x390 0x000 0x1 0x0
+#define MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3                                  0x128 0x390 0x5E0 0x2 0x0
+#define MX8MN_IOMUXC_NAND_DATA07_GPIO3_IO13                                    0x128 0x390 0x000 0x5 0x0
+#define MX8MN_IOMUXC_NAND_DATA07_CORESIGHT_TRACE11                             0x128 0x390 0x000 0x6 0x0
+#define MX8MN_IOMUXC_NAND_DQS_RAWNAND_DQS                                      0x12C 0x394 0x000 0x0 0x0
+#define MX8MN_IOMUXC_NAND_DQS_QSPI_A_DQS                                       0x12C 0x394 0x000 0x1 0x0
+#define MX8MN_IOMUXC_NAND_DQS_PDM_CLK                                          0x12C 0x394 0x000 0x3 0x0
+#define MX8MN_IOMUXC_NAND_DQS_I2C3_SCL                                         0x12C 0x394 0x588 0x4 0x2
+#define MX8MN_IOMUXC_NAND_DQS_GPIO3_IO14                                       0x12C 0x394 0x000 0x5 0x0
+#define MX8MN_IOMUXC_NAND_DQS_CORESIGHT_TRACE12                                0x12C 0x394 0x000 0x6 0x0
+#define MX8MN_IOMUXC_NAND_RE_B_RAWNAND_RE_B                                    0x130 0x398 0x000 0x0 0x0
+#define MX8MN_IOMUXC_NAND_RE_B_QSPI_B_DQS                                      0x130 0x398 0x000 0x1 0x0
+#define MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4                                    0x130 0x398 0x558 0x2 0x0
+#define MX8MN_IOMUXC_NAND_RE_B_PDM_BIT_STREAM1                                 0x130 0x398 0x538 0x3 0x7
+#define MX8MN_IOMUXC_NAND_RE_B_GPIO3_IO15                                      0x130 0x398 0x000 0x5 0x0
+#define MX8MN_IOMUXC_NAND_RE_B_CORESIGHT_TRACE13                               0x130 0x398 0x000 0x6 0x0
+#define MX8MN_IOMUXC_NAND_READY_B_RAWNAND_READY_B                              0x134 0x39C 0x000 0x0 0x0
+#define MX8MN_IOMUXC_NAND_READY_B_USDHC3_RESET_B                               0x134 0x39C 0x000 0x2 0x0
+#define MX8MN_IOMUXC_NAND_READY_B_PDM_BIT_STREAM3                              0x134 0x39C 0x540 0x3 0x6
+#define MX8MN_IOMUXC_NAND_READY_B_I2C3_SCL                                     0x134 0x39C 0x588 0x4 0x3
+#define MX8MN_IOMUXC_NAND_READY_B_GPIO3_IO16                                   0x134 0x39C 0x000 0x5 0x0
+#define MX8MN_IOMUXC_NAND_READY_B_CORESIGHT_TRACE14                            0x134 0x39C 0x000 0x6 0x0
+#define MX8MN_IOMUXC_NAND_WE_B_RAWNAND_WE_B                                    0x138 0x3A0 0x000 0x0 0x0
+#define MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK                                      0x138 0x3A0 0x5A0 0x2 0x0
+#define MX8MN_IOMUXC_NAND_WE_B_I2C3_SDA                                        0x138 0x3A0 0x5BC 0x4 0x3
+#define MX8MN_IOMUXC_NAND_WE_B_GPIO3_IO17                                      0x138 0x3A0 0x000 0x5 0x0
+#define MX8MN_IOMUXC_NAND_WE_B_CORESIGHT_TRACE15                               0x138 0x3A0 0x000 0x6 0x0
+#define MX8MN_IOMUXC_NAND_WP_B_RAWNAND_WP_B                                    0x13C 0x3A4 0x000 0x0 0x0
+#define MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD                                      0x13C 0x3A4 0x5DC 0x2 0x0
+#define MX8MN_IOMUXC_NAND_WP_B_I2C4_SDA                                        0x13C 0x3A4 0x58C 0x4 0x4
+#define MX8MN_IOMUXC_NAND_WP_B_GPIO3_IO18                                      0x13C 0x3A4 0x000 0x5 0x0
+#define MX8MN_IOMUXC_NAND_WP_B_CORESIGHT_EVENTO                                0x13C 0x3A4 0x000 0x6 0x0
+#define MX8MN_IOMUXC_SAI5_RXFS_SAI5_RX_SYNC                                    0x140 0x3A8 0x4E4 0x0 0x0
+#define MX8MN_IOMUXC_SAI5_RXFS_GPIO3_IO19                                      0x140 0x3A8 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI5_RXC_SAI5_RX_BCLK                                     0x144 0x3AC 0x4D0 0x0 0x0
+#define MX8MN_IOMUXC_SAI5_RXC_PDM_CLK                                          0x144 0x3AC 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SAI5_RXC_GPIO3_IO20                                       0x144 0x3AC 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI5_RXD0_SAI5_RX_DATA0                                   0x148 0x3B0 0x4D4 0x0 0x0
+#define MX8MN_IOMUXC_SAI5_RXD0_PDM_BIT_STREAM0                                 0x148 0x3B0 0x534 0x4 0x0
+#define MX8MN_IOMUXC_SAI5_RXD0_GPIO3_IO21                                      0x148 0x3B0 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI5_RXD1_SAI5_RX_DATA1                                   0x14C 0x3B4 0x4D8 0x0 0x0
+#define MX8MN_IOMUXC_SAI5_RXD1_SAI5_TX_SYNC                                    0x14C 0x3B4 0x4EC 0x3 0x0
+#define MX8MN_IOMUXC_SAI5_RXD1_PDM_BIT_STREAM1                                 0x14C 0x3B4 0x538 0x4 0x0
+#define MX8MN_IOMUXC_SAI5_RXD1_GPIO3_IO22                                      0x14C 0x3B4 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI5_RXD2_SAI5_RX_DATA2                                   0x150 0x3B8 0x4DC 0x0 0x0
+#define MX8MN_IOMUXC_SAI5_RXD2_SAI5_TX_BCLK                                    0x150 0x3B8 0x4E8 0x3 0x0
+#define MX8MN_IOMUXC_SAI5_RXD2_PDM_BIT_STREAM2                                 0x150 0x3B8 0x53C 0x4 0x0
+#define MX8MN_IOMUXC_SAI5_RXD2_GPIO3_IO23                                      0x150 0x3B8 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI5_RXD3_SAI5_RX_DATA3                                   0x154 0x3BC 0x4E0 0x0 0x0
+#define MX8MN_IOMUXC_SAI5_RXD3_SAI5_TX_DATA0                                   0x154 0x3BC 0x000 0x3 0x0
+#define MX8MN_IOMUXC_SAI5_RXD3_PDM_BIT_STREAM3                                 0x154 0x3BC 0x540 0x4 0x0
+#define MX8MN_IOMUXC_SAI5_RXD3_GPIO3_IO24                                      0x154 0x3BC 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI5_MCLK_SAI5_MCLK                                       0x158 0x3C0 0x594 0x0 0x0
+#define MX8MN_IOMUXC_SAI5_MCLK_GPIO3_IO25                                      0x158 0x3C0 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI2_RXFS_SAI2_RX_SYNC                                    0x1B0 0x418 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SAI2_RXFS_SAI5_TX_SYNC                                    0x1B0 0x418 0x4EC 0x1 0x2
+#define MX8MN_IOMUXC_SAI2_RXFS_SAI5_TX_DATA1                                   0x1B0 0x418 0x000 0x2 0x0
+#define MX8MN_IOMUXC_SAI2_RXFS_SAI2_RX_DATA1                                   0x1B0 0x418 0x5AC 0x3 0x0
+#define MX8MN_IOMUXC_SAI2_RXFS_UART1_DCE_TX                                    0x1B0 0x418 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SAI2_RXFS_UART1_DTE_RX                                    0x1B0 0x418 0x4F4 0x4 0x2
+#define MX8MN_IOMUXC_SAI2_RXFS_GPIO4_IO21                                      0x1B0 0x418 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI2_RXFS_PDM_BIT_STREAM2                                 0x1B0 0x418 0x53C 0x6 0x7
+#define MX8MN_IOMUXC_SAI2_RXC_SAI2_RX_BCLK                                     0x1B4 0x41C 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SAI2_RXC_SAI5_TX_BCLK                                     0x1B4 0x41C 0x4E8 0x1 0x2
+#define MX8MN_IOMUXC_SAI2_RXC_UART1_DCE_RX                                     0x1B4 0x41C 0x4F4 0x4 0x3
+#define MX8MN_IOMUXC_SAI2_RXC_UART1_DTE_TX                                     0x1B4 0x41C 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SAI2_RXC_GPIO4_IO22                                       0x1B4 0x41C 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI2_RXC_PDM_BIT_STREAM1                                  0x1B4 0x41C 0x538 0x6 0x8
+#define MX8MN_IOMUXC_SAI2_RXD0_SAI2_RX_DATA0                                   0x1B8 0x420 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SAI2_RXD0_SAI5_TX_DATA0                                   0x1B8 0x420 0x000 0x1 0x0
+#define MX8MN_IOMUXC_SAI2_RXD0_SAI2_TX_DATA1                                   0x1B8 0x420 0x000 0x3 0x0
+#define MX8MN_IOMUXC_SAI2_RXD0_UART1_DCE_RTS_B                                 0x1B8 0x420 0x4F0 0x4 0x2
+#define MX8MN_IOMUXC_SAI2_RXD0_UART1_DTE_CTS_B                                 0x1B8 0x420 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SAI2_RXD0_GPIO4_IO23                                      0x1B8 0x420 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI2_RXD0_PDM_BIT_STREAM3                                 0x1B8 0x420 0x540 0x6 0x7
+#define MX8MN_IOMUXC_SAI2_TXFS_SAI2_TX_SYNC                                    0x1BC 0x424 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SAI2_TXFS_SAI5_TX_DATA1                                   0x1BC 0x424 0x000 0x1 0x0
+#define MX8MN_IOMUXC_SAI2_TXFS_SAI2_TX_DATA1                                   0x1BC 0x424 0x000 0x3 0x0
+#define MX8MN_IOMUXC_SAI2_TXFS_UART1_DCE_CTS_B                                 0x1BC 0x424 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SAI2_TXFS_UART1_DTE_RTS_B                                 0x1BC 0x424 0x4F0 0x4 0x3
+#define MX8MN_IOMUXC_SAI2_TXFS_GPIO4_IO24                                      0x1BC 0x424 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI2_TXFS_PDM_BIT_STREAM2                                 0x1BC 0x424 0x53C 0x6 0x8
+#define MX8MN_IOMUXC_SAI2_TXC_SAI2_TX_BCLK                                     0x1C0 0x428 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SAI2_TXC_SAI5_TX_DATA2                                    0x1C0 0x428 0x000 0x1 0x0
+#define MX8MN_IOMUXC_SAI2_TXC_GPIO4_IO25                                       0x1C0 0x428 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI2_TXC_PDM_BIT_STREAM1                                  0x1C0 0x428 0x538 0x6 0x9
+#define MX8MN_IOMUXC_SAI2_TXD0_SAI2_TX_DATA0                                   0x1C4 0x42C 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SAI2_TXD0_SAI5_TX_DATA3                                   0x1C4 0x42C 0x000 0x1 0x0
+#define MX8MN_IOMUXC_SAI2_TXD0_GPIO4_IO26                                      0x1C4 0x42C 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI2_TXD0_CCMSRCGPCMIX_BOOT_MODE4                         0x1C4 0x42C 0x540 0x6 0x8
+#define MX8MN_IOMUXC_SAI2_MCLK_SAI2_MCLK                                       0x1C8 0x430 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SAI2_MCLK_SAI5_MCLK                                       0x1C8 0x430 0x594 0x1 0x2
+#define MX8MN_IOMUXC_SAI2_MCLK_GPIO4_IO27                                      0x1C8 0x430 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI2_MCLK_SAI3_MCLK                                       0x1C8 0x430 0x5C0 0x6 0x1
+#define MX8MN_IOMUXC_SAI3_RXFS_SAI3_RX_SYNC                                    0x1CC 0x434 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SAI3_RXFS_GPT1_CAPTURE1                                   0x1CC 0x434 0x5F0 0x1 0x0
+#define MX8MN_IOMUXC_SAI3_RXFS_SAI5_RX_SYNC                                    0x1CC 0x434 0x4E4 0x2 0x2
+#define MX8MN_IOMUXC_SAI3_RXFS_SAI3_RX_DATA1                                   0x1CC 0x434 0x000 0x3 0x0
+#define MX8MN_IOMUXC_SAI3_RXFS_SPDIF1_IN                                       0x1CC 0x434 0x5CC 0x4 0x3
+#define MX8MN_IOMUXC_SAI3_RXFS_GPIO4_IO28                                      0x1CC 0x434 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI3_RXFS_PDM_BIT_STREAM0                                 0x1CC 0x434 0x534 0x6 0x5
+#define MX8MN_IOMUXC_SAI3_RXC_SAI3_RX_BCLK                                     0x1D0 0x438 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SAI3_RXC_GPT1_CLK                                         0x1D0 0x438 0x5E8 0x1 0x0
+#define MX8MN_IOMUXC_SAI3_RXC_SAI5_RX_BCLK                                     0x1D0 0x438 0x4D0 0x2 0x2
+#define MX8MN_IOMUXC_SAI3_RXC_SAI2_RX_DATA1                                    0x1D0 0x438 0x5AC 0x3 0x2
+#define MX8MN_IOMUXC_SAI3_RXC_UART2_DCE_CTS_B                                  0x1D0 0x438 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SAI3_RXC_UART2_DTE_RTS_B                                  0x1D0 0x438 0x4F8 0x4 0x2
+#define MX8MN_IOMUXC_SAI3_RXC_GPIO4_IO29                                       0x1D0 0x438 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI3_RXC_PDM_CLK                                          0x1D0 0x438 0x000 0x6 0x0
+#define MX8MN_IOMUXC_SAI3_RXD_SAI3_RX_DATA0                                    0x1D4 0x43C 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SAI3_RXD_GPT1_COMPARE1                                    0x1D4 0x43C 0x000 0x1 0x0
+#define MX8MN_IOMUXC_SAI3_RXD_SAI5_RX_DATA0                                    0x1D4 0x43C 0x4D4 0x2 0x2
+#define MX8MN_IOMUXC_SAI3_RXD_SAI3_TX_DATA1                                    0x1D4 0x43C 0x000 0x3 0x0
+#define MX8MN_IOMUXC_SAI3_RXD_UART2_DCE_RTS_B                                  0x1D4 0x43C 0x4F8 0x4 0x3
+#define MX8MN_IOMUXC_SAI3_RXD_UART2_DTE_CTS_B                                  0x1D4 0x43C 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SAI3_RXD_GPIO4_IO30                                       0x1D4 0x43C 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI3_RXD_PDM_BIT_STREAM1                                  0x1D4 0x43C 0x538 0x6 0x10
+#define MX8MN_IOMUXC_SAI3_TXFS_SAI3_TX_SYNC                                    0x1D8 0x440 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SAI3_TXFS_GPT1_CAPTURE2                                   0x1D8 0x440 0x5EC 0x1 0x0
+#define MX8MN_IOMUXC_SAI3_TXFS_SAI5_RX_DATA1                                   0x1D8 0x440 0x4D8 0x2 0x1
+#define MX8MN_IOMUXC_SAI3_TXFS_SAI3_TX_DATA1                                   0x1D8 0x440 0x000 0x3 0x0
+#define MX8MN_IOMUXC_SAI3_TXFS_UART2_DCE_RX                                    0x1D8 0x440 0x4FC 0x4 0x2
+#define MX8MN_IOMUXC_SAI3_TXFS_UART2_DTE_TX                                    0x1D8 0x440 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SAI3_TXFS_GPIO4_IO31                                      0x1D8 0x440 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI3_TXFS_PDM_BIT_STREAM3                                 0x1D8 0x440 0x540 0x6 0x9
+#define MX8MN_IOMUXC_SAI3_TXC_SAI3_TX_BCLK                                     0x1DC 0x444 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SAI3_TXC_GPT1_COMPARE2                                    0x1DC 0x444 0x000 0x1 0x0
+#define MX8MN_IOMUXC_SAI3_TXC_SAI5_RX_DATA2                                    0x1DC 0x444 0x4DC 0x2 0x1
+#define MX8MN_IOMUXC_SAI3_TXC_SAI2_TX_DATA1                                    0x1DC 0x444 0x000 0x3 0x0
+#define MX8MN_IOMUXC_SAI3_TXC_UART2_DCE_TX                                     0x1DC 0x444 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SAI3_TXC_UART2_DTE_RX                                     0x1DC 0x444 0x4FC 0x4 0x3
+#define MX8MN_IOMUXC_SAI3_TXC_GPIO5_IO0                                        0x1DC 0x444 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI3_TXC_PDM_BIT_STREAM2                                  0x1DC 0x444 0x53C 0x6 0x9
+#define MX8MN_IOMUXC_SAI3_TXD_SAI3_TX_DATA0                                    0x1E0 0x448 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SAI3_TXD_GPT1_COMPARE3                                    0x1E0 0x448 0x000 0x1 0x0
+#define MX8MN_IOMUXC_SAI3_TXD_SAI5_RX_DATA3                                    0x1E0 0x448 0x4E0 0x2 0x1
+#define MX8MN_IOMUXC_SAI3_TXD_SPDIF1_EXT_CLK                                   0x1E0 0x448 0x568 0x4 0x2
+#define MX8MN_IOMUXC_SAI3_TXD_GPIO5_IO1                                        0x1E0 0x448 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI3_TXD_CCMSRCGPCMIX_BOOT_MODE5                          0x1E0 0x448 0x000 0x6 0x0
+#define MX8MN_IOMUXC_SAI3_MCLK_SAI3_MCLK                                       0x1E4 0x44C 0x5C0 0x0 0x0
+#define MX8MN_IOMUXC_SAI3_MCLK_PWM4_OUT                                        0x1E4 0x44C 0x000 0x1 0x0
+#define MX8MN_IOMUXC_SAI3_MCLK_SAI5_MCLK                                       0x1E4 0x44C 0x594 0x2 0x3
+#define MX8MN_IOMUXC_SAI3_MCLK_SPDIF1_OUT                                      0x1E4 0x44C 0x000 0x4 0x0
+#define MX8MN_IOMUXC_SAI3_MCLK_GPIO5_IO2                                       0x1E4 0x44C 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SAI3_MCLK_SPDIF1_IN                                       0x1E4 0x44C 0x5CC 0x6 0x4
+#define MX8MN_IOMUXC_SPDIF_TX_SPDIF1_OUT                                       0x1E8 0x450 0x000 0x0 0x0
+#define MX8MN_IOMUXC_SPDIF_TX_PWM3_OUT                                         0x1E8 0x450 0x000 0x1 0x0
+#define MX8MN_IOMUXC_SPDIF_TX_GPIO5_IO3                                        0x1E8 0x450 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SPDIF_RX_SPDIF1_IN                                        0x1EC 0x454 0x5CC 0x0 0x0
+#define MX8MN_IOMUXC_SPDIF_RX_PWM2_OUT                                         0x1EC 0x454 0x000 0x1 0x0
+#define MX8MN_IOMUXC_SPDIF_RX_GPIO5_IO4                                        0x1EC 0x454 0x000 0x5 0x0
+#define MX8MN_IOMUXC_SPDIF_EXT_CLK_SPDIF1_EXT_CLK                              0x1F0 0x458 0x568 0x0 0x0
+#define MX8MN_IOMUXC_SPDIF_EXT_CLK_PWM1_OUT                                    0x1F0 0x458 0x000 0x1 0x0
+#define MX8MN_IOMUXC_SPDIF_EXT_CLK_GPIO5_IO5                                   0x1F0 0x458 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK                                   0x1F4 0x45C 0x5D8 0x0 0x0
+#define MX8MN_IOMUXC_ECSPI1_SCLK_UART3_DCE_RX                                  0x1F4 0x45C 0x504 0x1 0x0
+#define MX8MN_IOMUXC_ECSPI1_SCLK_UART3_DTE_TX                                  0x1F4 0x45C 0x000 0x1 0x0
+#define MX8MN_IOMUXC_ECSPI1_SCLK_I2C1_SCL                                      0x1F4 0x45C 0x55C 0x2 0x2
+#define MX8MN_IOMUXC_ECSPI1_SCLK_SAI5_RX_SYNC                                  0x1F4 0x45C 0x4DC 0x3 0x2
+#define MX8MN_IOMUXC_ECSPI1_SCLK_GPIO5_IO6                                     0x1F4 0x45C 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI                                   0x1F8 0x460 0x5A8 0x0 0x0
+#define MX8MN_IOMUXC_ECSPI1_MOSI_UART3_DCE_TX                                  0x1F8 0x460 0x000 0x1 0x0
+#define MX8MN_IOMUXC_ECSPI1_MOSI_UART3_DTE_RX                                  0x1F8 0x460 0x504 0x1 0x1
+#define MX8MN_IOMUXC_ECSPI1_MOSI_I2C1_SDA                                      0x1F8 0x460 0x56C 0x2 0x2
+#define MX8MN_IOMUXC_ECSPI1_MOSI_SAI5_RX_BCLK                                  0x1F8 0x460 0x4D0 0x3 0x3
+#define MX8MN_IOMUXC_ECSPI1_MOSI_GPIO5_IO7                                     0x1F8 0x460 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ECSPI1_MISO_ECSPI1_MISO                                   0x1FC 0x464 0x5C4 0x0 0x0
+#define MX8MN_IOMUXC_ECSPI1_MISO_UART3_DCE_CTS_B                               0x1FC 0x464 0x000 0x1 0x0
+#define MX8MN_IOMUXC_ECSPI1_MISO_UART3_DTE_RTS_B                               0x1FC 0x464 0x500 0x1 0x0
+#define MX8MN_IOMUXC_ECSPI1_MISO_I2C2_SCL                                      0x1FC 0x464 0x5D0 0x2 0x2
+#define MX8MN_IOMUXC_ECSPI1_MISO_SAI5_RX_DATA0                                 0x1FC 0x464 0x4D4 0x3 0x3
+#define MX8MN_IOMUXC_ECSPI1_MISO_GPIO5_IO8                                     0x1FC 0x464 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ECSPI1_SS0_ECSPI1_SS0                                     0x200 0x468 0x564 0x0 0x0
+#define MX8MN_IOMUXC_ECSPI1_SS0_UART3_DCE_RTS_B                                0x200 0x468 0x500 0x1 0x1
+#define MX8MN_IOMUXC_ECSPI1_SS0_UART3_DTE_CTS_B                                0x200 0x468 0x000 0x1 0x0
+#define MX8MN_IOMUXC_ECSPI1_SS0_I2C2_SDA                                       0x200 0x468 0x560 0x2 0x2
+#define MX8MN_IOMUXC_ECSPI1_SS0_SAI5_RX_DATA1                                  0x200 0x468 0x4D8 0x3 0x2
+#define MX8MN_IOMUXC_ECSPI1_SS0_SAI5_TX_SYNC                                   0x200 0x468 0x4EC 0x4 0x3
+#define MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9                                      0x200 0x468 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK                                   0x204 0x46C 0x580 0x0 0x0
+#define MX8MN_IOMUXC_ECSPI2_SCLK_UART4_DCE_RX                                  0x204 0x46C 0x50C 0x1 0x0
+#define MX8MN_IOMUXC_ECSPI2_SCLK_UART4_DTE_TX                                  0x204 0x46C 0x000 0x1 0x0
+#define MX8MN_IOMUXC_ECSPI2_SCLK_I2C3_SCL                                      0x204 0x46C 0x588 0x2 0x4
+#define MX8MN_IOMUXC_ECSPI2_SCLK_SAI5_RX_DATA2                                 0x204 0x46C 0x000 0x3 0x0
+#define MX8MN_IOMUXC_ECSPI2_SCLK_SAI5_TX_BCLK                                  0x204 0x46C 0x4E8 0x4 0x3
+#define MX8MN_IOMUXC_ECSPI2_SCLK_GPIO5_IO10                                    0x204 0x46C 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI                                   0x208 0x470 0x590 0x0 0x0
+#define MX8MN_IOMUXC_ECSPI2_MOSI_UART4_DCE_TX                                  0x208 0x470 0x000 0x1 0x0
+#define MX8MN_IOMUXC_ECSPI2_MOSI_UART4_DTE_RX                                  0x208 0x470 0x50C 0x1 0x1
+#define MX8MN_IOMUXC_ECSPI2_MOSI_I2C3_SDA                                      0x208 0x470 0x5BC 0x2 0x4
+#define MX8MN_IOMUXC_ECSPI2_MOSI_SAI5_RX_DATA3                                 0x208 0x470 0x4E0 0x3 0x2
+#define MX8MN_IOMUXC_ECSPI2_MOSI_SAI5_TX_DATA0                                 0x208 0x470 0x000 0x4 0x0
+#define MX8MN_IOMUXC_ECSPI2_MOSI_GPIO5_IO11                                    0x208 0x470 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ECSPI2_MISO_ECSPI2_MISO                                   0x20C 0x474 0x578 0x0 0x0
+#define MX8MN_IOMUXC_ECSPI2_MISO_UART4_DCE_CTS_B                               0x20C 0x474 0x000 0x1 0x0
+#define MX8MN_IOMUXC_ECSPI2_MISO_UART4_DTE_RTS_B                               0x20C 0x474 0x508 0x1 0x0
+#define MX8MN_IOMUXC_ECSPI2_MISO_I2C4_SCL                                      0x20C 0x474 0x5D4 0x2 0x3
+#define MX8MN_IOMUXC_ECSPI2_MISO_SAI5_MCLK                                     0x20C 0x474 0x594 0x3 0x4
+#define MX8MN_IOMUXC_ECSPI2_MISO_GPIO5_IO12                                    0x20C 0x474 0x000 0x5 0x0
+#define MX8MN_IOMUXC_ECSPI2_SS0_ECSPI2_SS0                                     0x210 0x478 0x570 0x0 0x0
+#define MX8MN_IOMUXC_ECSPI2_SS0_UART4_DCE_RTS_B                                0x210 0x478 0x508 0x1 0x1
+#define MX8MN_IOMUXC_ECSPI2_SS0_UART4_DTE_CTS_B                                0x210 0x478 0x000 0x1 0x0
+#define MX8MN_IOMUXC_ECSPI2_SS0_I2C4_SDA                                       0x210 0x478 0x58C 0x2 0x5
+#define MX8MN_IOMUXC_ECSPI2_SS0_GPIO5_IO13                                     0x210 0x478 0x000 0x5 0x0
+#define MX8MN_IOMUXC_I2C1_SCL_I2C1_SCL                                         0x214 0x47C 0x55C 0x0 0x0
+#define MX8MN_IOMUXC_I2C1_SCL_ENET1_MDC                                        0x214 0x47C 0x000 0x1 0x0
+#define MX8MN_IOMUXC_I2C1_SCL_ECSPI1_SCLK                                      0x214 0x47C 0x5D8 0x3 0x1
+#define MX8MN_IOMUXC_I2C1_SCL_GPIO5_IO14                                       0x214 0x47C 0x000 0x5 0x0
+#define MX8MN_IOMUXC_I2C1_SDA_I2C1_SDA                                         0x218 0x480 0x56C 0x0 0x0
+#define MX8MN_IOMUXC_I2C1_SDA_ENET1_MDIO                                       0x218 0x480 0x4C0 0x1 0x2
+#define MX8MN_IOMUXC_I2C1_SDA_ECSPI1_MOSI                                      0x218 0x480 0x5A8 0x3 0x1
+#define MX8MN_IOMUXC_I2C1_SDA_GPIO5_IO15                                       0x218 0x480 0x000 0x5 0x0
+#define MX8MN_IOMUXC_I2C2_SCL_I2C2_SCL                                         0x21C 0x484 0x5D0 0x0 0x0
+#define MX8MN_IOMUXC_I2C2_SCL_ENET1_1588_EVENT1_IN                             0x21C 0x484 0x000 0x1 0x0
+#define MX8MN_IOMUXC_I2C2_SCL_USDHC3_CD_B                                      0x21C 0x484 0x598 0x2 0x1
+#define MX8MN_IOMUXC_I2C2_SCL_ECSPI1_MISO                                      0x21C 0x484 0x5C4 0x3 0x1
+#define MX8MN_IOMUXC_I2C2_SCL_GPIO5_IO16                                       0x21C 0x484 0x000 0x5 0x0
+#define MX8MN_IOMUXC_I2C2_SDA_I2C2_SDA                                         0x220 0x488 0x560 0x0 0x0
+#define MX8MN_IOMUXC_I2C2_SDA_ENET1_1588_EVENT1_OUT                            0x220 0x488 0x000 0x1 0x0
+#define MX8MN_IOMUXC_I2C2_SDA_USDHC3_WP                                        0x220 0x488 0x5B8 0x2 0x1
+#define MX8MN_IOMUXC_I2C2_SDA_ECSPI1_SS0                                       0x220 0x488 0x564 0x3 0x1
+#define MX8MN_IOMUXC_I2C2_SDA_GPIO5_IO17                                       0x220 0x488 0x000 0x5 0x0
+#define MX8MN_IOMUXC_I2C3_SCL_I2C3_SCL                                         0x224 0x48C 0x588 0x0 0x0
+#define MX8MN_IOMUXC_I2C3_SCL_PWM4_OUT                                         0x224 0x48C 0x000 0x1 0x0
+#define MX8MN_IOMUXC_I2C3_SCL_GPT2_CLK                                         0x224 0x48C 0x000 0x2 0x0
+#define MX8MN_IOMUXC_I2C3_SCL_ECSPI2_SCLK                                      0x224 0x48C 0x580 0x3 0x2
+#define MX8MN_IOMUXC_I2C3_SCL_GPIO5_IO18                                       0x224 0x48C 0x000 0x5 0x0
+#define MX8MN_IOMUXC_I2C3_SDA_I2C3_SDA                                         0x228 0x490 0x5BC 0x0 0x0
+#define MX8MN_IOMUXC_I2C3_SDA_PWM3_OUT                                         0x228 0x490 0x000 0x1 0x0
+#define MX8MN_IOMUXC_I2C3_SDA_GPT3_CLK                                         0x228 0x490 0x000 0x2 0x0
+#define MX8MN_IOMUXC_I2C3_SDA_ECSPI2_MOSI                                      0x228 0x490 0x590 0x3 0x2
+#define MX8MN_IOMUXC_I2C3_SDA_GPIO5_IO19                                       0x228 0x490 0x000 0x5 0x0
+#define MX8MN_IOMUXC_I2C4_SCL_I2C4_SCL                                         0x22C 0x494 0x5D4 0x0 0x0
+#define MX8MN_IOMUXC_I2C4_SCL_PWM2_OUT                                         0x22C 0x494 0x000 0x1 0x0
+#define MX8MN_IOMUXC_I2C4_SCL_ECSPI2_MISO                                      0x22C 0x494 0x578 0x3 0x2
+#define MX8MN_IOMUXC_I2C4_SCL_GPIO5_IO20                                       0x22C 0x494 0x000 0x5 0x0
+#define MX8MN_IOMUXC_I2C4_SDA_I2C4_SDA                                         0x230 0x498 0x58C 0x0 0x0
+#define MX8MN_IOMUXC_I2C4_SDA_PWM1_OUT                                         0x230 0x498 0x000 0x1 0x0
+#define MX8MN_IOMUXC_I2C4_SDA_ECSPI2_SS0                                       0x230 0x498 0x570 0x3 0x1
+#define MX8MN_IOMUXC_I2C4_SDA_GPIO5_IO21                                       0x230 0x498 0x000 0x5 0x0
+#define MX8MN_IOMUXC_UART1_RXD_UART1_DCE_RX                                    0x234 0x49C 0x4F4 0x0 0x0
+#define MX8MN_IOMUXC_UART1_RXD_UART1_DTE_TX                                    0x234 0x49C 0x000 0x0 0x0
+#define MX8MN_IOMUXC_UART1_RXD_ECSPI3_SCLK                                     0x234 0x49C 0x000 0x1 0x0
+#define MX8MN_IOMUXC_UART1_RXD_GPIO5_IO22                                      0x234 0x49C 0x000 0x5 0x0
+#define MX8MN_IOMUXC_UART1_TXD_UART1_DCE_TX                                    0x238 0x4A0 0x000 0x0 0x0
+#define MX8MN_IOMUXC_UART1_TXD_UART1_DTE_RX                                    0x238 0x4A0 0x4F4 0x0 0x1
+#define MX8MN_IOMUXC_UART1_TXD_ECSPI3_MOSI                                     0x238 0x4A0 0x000 0x1 0x0
+#define MX8MN_IOMUXC_UART1_TXD_GPIO5_IO23                                      0x238 0x4A0 0x000 0x5 0x0
+#define MX8MN_IOMUXC_UART2_RXD_UART2_DCE_RX                                    0x23C 0x4A4 0x4FC 0x0 0x0
+#define MX8MN_IOMUXC_UART2_RXD_UART2_DTE_TX                                    0x23C 0x4A4 0x000 0x0 0x0
+#define MX8MN_IOMUXC_UART2_RXD_ECSPI3_MISO                                     0x23C 0x4A4 0x000 0x1 0x0
+#define MX8MN_IOMUXC_UART2_RXD_GPT1_COMPARE3                                   0x23C 0x4A4 0x000 0x3 0x0
+#define MX8MN_IOMUXC_UART2_RXD_GPIO5_IO24                                      0x23C 0x4A4 0x000 0x5 0x0
+#define MX8MN_IOMUXC_UART2_TXD_UART2_DCE_TX                                    0x240 0x4A8 0x000 0x0 0x0
+#define MX8MN_IOMUXC_UART2_TXD_UART2_DTE_RX                                    0x240 0x4A8 0x4FC 0x0 0x1
+#define MX8MN_IOMUXC_UART2_TXD_ECSPI3_SS0                                      0x240 0x4A8 0x000 0x1 0x0
+#define MX8MN_IOMUXC_UART2_TXD_GPT1_COMPARE2                                   0x240 0x4A8 0x000 0x3 0x0
+#define MX8MN_IOMUXC_UART2_TXD_GPIO5_IO25                                      0x240 0x4A8 0x000 0x5 0x0
+#define MX8MN_IOMUXC_UART3_RXD_UART3_DCE_RX                                    0x244 0x4AC 0x504 0x0 0x2
+#define MX8MN_IOMUXC_UART3_RXD_UART3_DTE_TX                                    0x244 0x4AC 0x000 0x0 0x0
+#define MX8MN_IOMUXC_UART3_RXD_UART1_DCE_CTS_B                                 0x244 0x4AC 0x000 0x1 0x0
+#define MX8MN_IOMUXC_UART3_RXD_UART1_DTE_RTS_B                                 0x244 0x4AC 0x4F0 0x1 0x0
+#define MX8MN_IOMUXC_UART3_RXD_USDHC3_RESET_B                                  0x244 0x4AC 0x000 0x2 0x0
+#define MX8MN_IOMUXC_UART3_RXD_GPT1_CAPTURE2                                   0x244 0x4AC 0x5EC 0x3 0x1
+#define MX8MN_IOMUXC_UART3_RXD_GPIO5_IO26                                      0x244 0x4AC 0x000 0x5 0x0
+#define MX8MN_IOMUXC_UART3_TXD_UART3_DCE_TX                                    0x248 0x4B0 0x000 0x0 0x0
+#define MX8MN_IOMUXC_UART3_TXD_UART3_DTE_RX                                    0x248 0x4B0 0x504 0x0 0x3
+#define MX8MN_IOMUXC_UART3_TXD_UART1_DCE_RTS_B                                 0x248 0x4B0 0x4F0 0x1 0x1
+#define MX8MN_IOMUXC_UART3_TXD_UART1_DTE_CTS_B                                 0x248 0x4B0 0x000 0x1 0x0
+#define MX8MN_IOMUXC_UART3_TXD_USDHC3_VSELECT                                  0x248 0x4B0 0x000 0x2 0x0
+#define MX8MN_IOMUXC_UART3_TXD_GPT1_CLK                                        0x248 0x4B0 0x5E8 0x3 0x1
+#define MX8MN_IOMUXC_UART3_TXD_GPIO5_IO27                                      0x248 0x4B0 0x000 0x5 0x0
+#define MX8MN_IOMUXC_UART4_RXD_UART4_DCE_RX                                    0x24C 0x4B4 0x50C 0x0 0x2
+#define MX8MN_IOMUXC_UART4_RXD_UART4_DTE_TX                                    0x24C 0x4B4 0x000 0x0 0x0
+#define MX8MN_IOMUXC_UART4_RXD_UART2_DCE_CTS_B                                 0x24C 0x4B4 0x000 0x1 0x0
+#define MX8MN_IOMUXC_UART4_RXD_UART2_DTE_RTS_B                                 0x24C 0x4B4 0x4F8 0x1 0x0
+#define MX8MN_IOMUXC_UART4_RXD_GPT1_COMPARE1                                   0x24C 0x4B4 0x000 0x3 0x0
+#define MX8MN_IOMUXC_UART4_RXD_GPIO5_IO28                                      0x24C 0x4B4 0x000 0x5 0x0
+#define MX8MN_IOMUXC_UART4_TXD_UART4_DCE_TX                                    0x250 0x4B8 0x000 0x0 0x0
+#define MX8MN_IOMUXC_UART4_TXD_UART4_DTE_RX                                    0x250 0x4B8 0x50C 0x0 0x3
+#define MX8MN_IOMUXC_UART4_TXD_UART2_DCE_RTS_B                                 0x250 0x4B8 0x4F8 0x1 0x1
+#define MX8MN_IOMUXC_UART4_TXD_UART2_DTE_CTS_B                                 0x250 0x4B8 0x000 0x1 0x0
+#define MX8MN_IOMUXC_UART4_TXD_GPT1_CAPTURE1                                   0x250 0x4B8 0x5F0 0x3 0x1
+#define MX8MN_IOMUXC_UART4_TXD_GPIO5_IO29                                      0x250 0x4B8 0x000 0x5 0x0
+
+#endif /* __DTS_IMX8MN_PINFUNC_H */
index 570d195..e3a15c7 100644 (file)
  * RAS Error Synchronization barrier
  */
        .macro  esb
+#ifdef CONFIG_ARM64_RAS_EXTN
        hint    #16
+#else
+       nop
+#endif
        .endm
 
 /*
index 3d8db50..407e2bf 100644 (file)
@@ -620,6 +620,12 @@ static inline bool system_has_prio_mask_debugging(void)
               system_uses_irq_prio_masking();
 }
 
+#define ARM64_BP_HARDEN_UNKNOWN                -1
+#define ARM64_BP_HARDEN_WA_NEEDED      0
+#define ARM64_BP_HARDEN_NOT_REQUIRED   1
+
+int get_spectre_v2_workaround_state(void);
+
 #define ARM64_SSBD_UNKNOWN             -1
 #define ARM64_SSBD_FORCE_DISABLE       0
 #define ARM64_SSBD_KERNEL              1
index 2ca437e..44a2437 100644 (file)
        {ARM_EXCEPTION_TRAP,            "TRAP"          },      \
        {ARM_EXCEPTION_HYP_GONE,        "HYP_GONE"      }
 
+/*
+ * Size of the HYP vectors preamble. kvm_patch_vector_branch() generates code
+ * that jumps over this.
+ */
+#define KVM_VECTOR_PREAMBLE    (2 * AARCH64_INSN_SIZE)
+
 #ifndef __ASSEMBLY__
 
 #include <linux/mm.h>
index 034dade..d69c1ef 100644 (file)
@@ -126,7 +126,7 @@ static inline unsigned long *__vcpu_elr_el1(const struct kvm_vcpu *vcpu)
 static inline unsigned long vcpu_read_elr_el1(const struct kvm_vcpu *vcpu)
 {
        if (vcpu->arch.sysregs_loaded_on_cpu)
-               return read_sysreg_el1(elr);
+               return read_sysreg_el1(SYS_ELR);
        else
                return *__vcpu_elr_el1(vcpu);
 }
@@ -134,7 +134,7 @@ static inline unsigned long vcpu_read_elr_el1(const struct kvm_vcpu *vcpu)
 static inline void vcpu_write_elr_el1(const struct kvm_vcpu *vcpu, unsigned long v)
 {
        if (vcpu->arch.sysregs_loaded_on_cpu)
-               write_sysreg_el1(v, elr);
+               write_sysreg_el1(v, SYS_ELR);
        else
                *__vcpu_elr_el1(vcpu) = v;
 }
@@ -186,7 +186,7 @@ static inline unsigned long vcpu_read_spsr(const struct kvm_vcpu *vcpu)
                return vcpu_read_spsr32(vcpu);
 
        if (vcpu->arch.sysregs_loaded_on_cpu)
-               return read_sysreg_el1(spsr);
+               return read_sysreg_el1(SYS_SPSR);
        else
                return vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
 }
@@ -199,7 +199,7 @@ static inline void vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long v)
        }
 
        if (vcpu->arch.sysregs_loaded_on_cpu)
-               write_sysreg_el1(v, spsr);
+               write_sysreg_el1(v, SYS_SPSR);
        else
                vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1] = v;
 }
@@ -353,6 +353,20 @@ static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
        return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
 }
 
+static inline bool kvm_arm_get_vcpu_workaround_2_flag(struct kvm_vcpu *vcpu)
+{
+       return vcpu->arch.workaround_flags & VCPU_WORKAROUND_2_FLAG;
+}
+
+static inline void kvm_arm_set_vcpu_workaround_2_flag(struct kvm_vcpu *vcpu,
+                                                     bool flag)
+{
+       if (flag)
+               vcpu->arch.workaround_flags |= VCPU_WORKAROUND_2_FLAG;
+       else
+               vcpu->arch.workaround_flags &= ~VCPU_WORKAROUND_2_FLAG;
+}
+
 static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
 {
        if (vcpu_mode_is_32bit(vcpu)) {
@@ -451,13 +465,13 @@ static inline void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr)
  */
 static inline void __hyp_text __kvm_skip_instr(struct kvm_vcpu *vcpu)
 {
-       *vcpu_pc(vcpu) = read_sysreg_el2(elr);
-       vcpu->arch.ctxt.gp_regs.regs.pstate = read_sysreg_el2(spsr);
+       *vcpu_pc(vcpu) = read_sysreg_el2(SYS_ELR);
+       vcpu->arch.ctxt.gp_regs.regs.pstate = read_sysreg_el2(SYS_SPSR);
 
        kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
 
-       write_sysreg_el2(vcpu->arch.ctxt.gp_regs.regs.pstate, spsr);
-       write_sysreg_el2(*vcpu_pc(vcpu), elr);
+       write_sysreg_el2(vcpu->arch.ctxt.gp_regs.regs.pstate, SYS_SPSR);
+       write_sysreg_el2(*vcpu_pc(vcpu), SYS_ELR);
 }
 
 #endif /* __ARM64_KVM_EMULATE_H__ */
index 9f19c35..f656169 100644 (file)
 #include <asm/arch_gicv3.h>
 #include <asm/barrier.h>
 #include <asm/cpufeature.h>
+#include <asm/cputype.h>
 #include <asm/daifflags.h>
 #include <asm/fpsimd.h>
 #include <asm/kvm.h>
 #include <asm/kvm_asm.h>
 #include <asm/kvm_mmio.h>
-#include <asm/smp_plat.h>
 #include <asm/thread_info.h>
 
 #define __KVM_HAVE_ARCH_INTC_INITIALIZED
@@ -484,11 +484,10 @@ struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
 
 DECLARE_PER_CPU(kvm_host_data_t, kvm_host_data);
 
-static inline void kvm_init_host_cpu_context(struct kvm_cpu_context *cpu_ctxt,
-                                            int cpu)
+static inline void kvm_init_host_cpu_context(struct kvm_cpu_context *cpu_ctxt)
 {
        /* The host's MPIDR is immutable, so let's set it up at boot time */
-       cpu_ctxt->sys_regs[MPIDR_EL1] = cpu_logical_map(cpu);
+       cpu_ctxt->sys_regs[MPIDR_EL1] = read_cpuid_mpidr();
 }
 
 void __kvm_enable_ssbs(void);
@@ -621,9 +620,21 @@ static inline void kvm_arm_vhe_guest_exit(void)
        isb();
 }
 
-static inline bool kvm_arm_harden_branch_predictor(void)
+#define KVM_BP_HARDEN_UNKNOWN          -1
+#define KVM_BP_HARDEN_WA_NEEDED                0
+#define KVM_BP_HARDEN_NOT_REQUIRED     1
+
+static inline int kvm_arm_harden_branch_predictor(void)
 {
-       return cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR);
+       switch (get_spectre_v2_workaround_state()) {
+       case ARM64_BP_HARDEN_WA_NEEDED:
+               return KVM_BP_HARDEN_WA_NEEDED;
+       case ARM64_BP_HARDEN_NOT_REQUIRED:
+               return KVM_BP_HARDEN_NOT_REQUIRED;
+       case ARM64_BP_HARDEN_UNKNOWN:
+       default:
+               return KVM_BP_HARDEN_UNKNOWN;
+       }
 }
 
 #define KVM_SSBD_UNKNOWN               -1
index 286f7e7..86825aa 100644 (file)
@@ -18,7 +18,7 @@
 #define read_sysreg_elx(r,nvh,vh)                                      \
        ({                                                              \
                u64 reg;                                                \
-               asm volatile(ALTERNATIVE("mrs %0, " __stringify(r##nvh),\
+               asm volatile(ALTERNATIVE(__mrs_s("%0", r##nvh), \
                                         __mrs_s("%0", r##vh),          \
                                         ARM64_HAS_VIRT_HOST_EXTN)      \
                             : "=r" (reg));                             \
@@ -28,7 +28,7 @@
 #define write_sysreg_elx(v,r,nvh,vh)                                   \
        do {                                                            \
                u64 __val = (u64)(v);                                   \
-               asm volatile(ALTERNATIVE("msr " __stringify(r##nvh) ", %x0",\
+               asm volatile(ALTERNATIVE(__msr_s(r##nvh, "%x0"),        \
                                         __msr_s(r##vh, "%x0"),         \
                                         ARM64_HAS_VIRT_HOST_EXTN)      \
                                         : : "rZ" (__val));             \
 /*
  * Unified accessors for registers that have a different encoding
  * between VHE and non-VHE. They must be specified without their "ELx"
- * encoding.
+ * encoding, but with the SYS_ prefix, as defined in asm/sysreg.h.
  */
-#define read_sysreg_el2(r)                                             \
-       ({                                                              \
-               u64 reg;                                                \
-               asm volatile(ALTERNATIVE("mrs %0, " __stringify(r##_EL2),\
-                                        "mrs %0, " __stringify(r##_EL1),\
-                                        ARM64_HAS_VIRT_HOST_EXTN)      \
-                            : "=r" (reg));                             \
-               reg;                                                    \
-       })
-
-#define write_sysreg_el2(v,r)                                          \
-       do {                                                            \
-               u64 __val = (u64)(v);                                   \
-               asm volatile(ALTERNATIVE("msr " __stringify(r##_EL2) ", %x0",\
-                                        "msr " __stringify(r##_EL1) ", %x0",\
-                                        ARM64_HAS_VIRT_HOST_EXTN)      \
-                                        : : "rZ" (__val));             \
-       } while (0)
 
 #define read_sysreg_el0(r)     read_sysreg_elx(r, _EL0, _EL02)
 #define write_sysreg_el0(v,r)  write_sysreg_elx(v, r, _EL0, _EL02)
 #define read_sysreg_el1(r)     read_sysreg_elx(r, _EL1, _EL12)
 #define write_sysreg_el1(v,r)  write_sysreg_elx(v, r, _EL1, _EL12)
-
-/* The VHE specific system registers and their encoding */
-#define sctlr_EL12              sys_reg(3, 5, 1, 0, 0)
-#define cpacr_EL12              sys_reg(3, 5, 1, 0, 2)
-#define ttbr0_EL12              sys_reg(3, 5, 2, 0, 0)
-#define ttbr1_EL12              sys_reg(3, 5, 2, 0, 1)
-#define tcr_EL12                sys_reg(3, 5, 2, 0, 2)
-#define afsr0_EL12              sys_reg(3, 5, 5, 1, 0)
-#define afsr1_EL12              sys_reg(3, 5, 5, 1, 1)
-#define esr_EL12                sys_reg(3, 5, 5, 2, 0)
-#define far_EL12                sys_reg(3, 5, 6, 0, 0)
-#define mair_EL12               sys_reg(3, 5, 10, 2, 0)
-#define amair_EL12              sys_reg(3, 5, 10, 3, 0)
-#define vbar_EL12               sys_reg(3, 5, 12, 0, 0)
-#define contextidr_EL12         sys_reg(3, 5, 13, 0, 1)
-#define cntkctl_EL12            sys_reg(3, 5, 14, 1, 0)
-#define cntp_tval_EL02          sys_reg(3, 5, 14, 2, 0)
-#define cntp_ctl_EL02           sys_reg(3, 5, 14, 2, 1)
-#define cntp_cval_EL02          sys_reg(3, 5, 14, 2, 2)
-#define cntv_tval_EL02          sys_reg(3, 5, 14, 3, 0)
-#define cntv_ctl_EL02           sys_reg(3, 5, 14, 3, 1)
-#define cntv_cval_EL02          sys_reg(3, 5, 14, 3, 2)
-#define spsr_EL12               sys_reg(3, 5, 4, 0, 0)
-#define elr_EL12                sys_reg(3, 5, 4, 0, 1)
+#define read_sysreg_el2(r)     read_sysreg_elx(r, _EL2, _EL1)
+#define write_sysreg_el2(v,r)  write_sysreg_elx(v, r, _EL2, _EL1)
 
 /**
  * hyp_alternate_select - Generates patchable code sequences that are
index cdced51..14d0bc4 100644 (file)
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 
+#include <asm-generic/pgalloc.h>       /* for pte_{alloc,free}_one */
+
 #define check_pgt_cache()              do { } while (0)
 
-#define PGALLOC_GFP    (GFP_KERNEL | __GFP_ZERO)
 #define PGD_SIZE       (PTRS_PER_PGD * sizeof(pgd_t))
 
 #if CONFIG_PGTABLE_LEVELS > 2
 
 static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
 {
+       gfp_t gfp = GFP_PGTABLE_USER;
        struct page *page;
 
-       page = alloc_page(PGALLOC_GFP);
+       if (mm == &init_mm)
+               gfp = GFP_PGTABLE_KERNEL;
+
+       page = alloc_page(gfp);
        if (!page)
                return NULL;
        if (!pgtable_pmd_page_ctor(page)) {
@@ -61,7 +66,7 @@ static inline void __pud_populate(pud_t *pudp, phys_addr_t pmdp, pudval_t prot)
 
 static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
 {
-       return (pud_t *)__get_free_page(PGALLOC_GFP);
+       return (pud_t *)__get_free_page(GFP_PGTABLE_USER);
 }
 
 static inline void pud_free(struct mm_struct *mm, pud_t *pudp)
@@ -89,42 +94,6 @@ static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t pudp, pgdval_t prot)
 extern pgd_t *pgd_alloc(struct mm_struct *mm);
 extern void pgd_free(struct mm_struct *mm, pgd_t *pgdp);
 
-static inline pte_t *
-pte_alloc_one_kernel(struct mm_struct *mm)
-{
-       return (pte_t *)__get_free_page(PGALLOC_GFP);
-}
-
-static inline pgtable_t
-pte_alloc_one(struct mm_struct *mm)
-{
-       struct page *pte;
-
-       pte = alloc_pages(PGALLOC_GFP, 0);
-       if (!pte)
-               return NULL;
-       if (!pgtable_page_ctor(pte)) {
-               __free_page(pte);
-               return NULL;
-       }
-       return pte;
-}
-
-/*
- * Free a PTE table.
- */
-static inline void pte_free_kernel(struct mm_struct *mm, pte_t *ptep)
-{
-       if (ptep)
-               free_page((unsigned long)ptep);
-}
-
-static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
-{
-       pgtable_page_dtor(pte);
-       __free_page(pte);
-}
-
 static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t ptep,
                                  pmdval_t prot)
 {
index 8169324..b1dd039 100644 (file)
@@ -223,11 +223,12 @@ static inline void forget_syscall(struct pt_regs *regs)
 #define fast_interrupts_enabled(regs) \
        (!((regs)->pstate & PSR_F_BIT))
 
-#define GET_USP(regs) \
-       (!compat_user_mode(regs) ? (regs)->sp : (regs)->compat_sp)
-
-#define SET_USP(ptregs, value) \
-       (!compat_user_mode(regs) ? ((regs)->sp = value) : ((regs)->compat_sp = value))
+static inline unsigned long user_stack_pointer(struct pt_regs *regs)
+{
+       if (compat_user_mode(regs))
+               return regs->compat_sp;
+       return regs->sp;
+}
 
 extern int regs_query_register_offset(const char *name);
 extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
@@ -326,13 +327,20 @@ static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs,
 struct task_struct;
 int valid_user_regs(struct user_pt_regs *regs, struct task_struct *task);
 
-#define GET_IP(regs)           ((unsigned long)(regs)->pc)
-#define SET_IP(regs, value)    ((regs)->pc = ((u64) (value)))
-
-#define GET_FP(ptregs)         ((unsigned long)(ptregs)->regs[29])
-#define SET_FP(ptregs, value)  ((ptregs)->regs[29] = ((u64) (value)))
+static inline unsigned long instruction_pointer(struct pt_regs *regs)
+{
+       return regs->pc;
+}
+static inline void instruction_pointer_set(struct pt_regs *regs,
+               unsigned long val)
+{
+       regs->pc = val;
+}
 
-#include <asm-generic/ptrace.h>
+static inline unsigned long frame_pointer(struct pt_regs *regs)
+{
+       return regs->regs[29];
+}
 
 #define procedure_link_pointer(regs)   ((regs)->regs[30])
 
@@ -342,7 +350,6 @@ static inline void procedure_link_pointer_set(struct pt_regs *regs,
        procedure_link_pointer(regs) = val;
 }
 
-#undef profile_pc
 extern unsigned long profile_pc(struct pt_regs *regs);
 
 #endif /* __ASSEMBLY__ */
index d0bd4ff..a7522fc 100644 (file)
 #define SYS_APGAKEYLO_EL1              sys_reg(3, 0, 2, 3, 0)
 #define SYS_APGAKEYHI_EL1              sys_reg(3, 0, 2, 3, 1)
 
+#define SYS_SPSR_EL1                   sys_reg(3, 0, 4, 0, 0)
+#define SYS_ELR_EL1                    sys_reg(3, 0, 4, 0, 1)
+
 #define SYS_ICC_PMR_EL1                        sys_reg(3, 0, 4, 6, 0)
 
 #define SYS_AFSR0_EL1                  sys_reg(3, 0, 5, 1, 0)
 #define SYS_CNTP_CTL_EL0               sys_reg(3, 3, 14, 2, 1)
 #define SYS_CNTP_CVAL_EL0              sys_reg(3, 3, 14, 2, 2)
 
+#define SYS_CNTV_CTL_EL0               sys_reg(3, 3, 14, 3, 1)
+#define SYS_CNTV_CVAL_EL0              sys_reg(3, 3, 14, 3, 2)
+
 #define SYS_AARCH32_CNTP_TVAL          sys_reg(0, 0, 14, 2, 0)
 #define SYS_AARCH32_CNTP_CTL           sys_reg(0, 0, 14, 2, 1)
 #define SYS_AARCH32_CNTP_CVAL          sys_reg(0, 2, 0, 14, 0)
 #define __TYPER_CRm(n)                 (0xc | (((n) >> 3) & 0x3))
 #define SYS_PMEVTYPERn_EL0(n)          sys_reg(3, 3, 14, __TYPER_CRm(n), __PMEV_op2(n))
 
-#define SYS_PMCCFILTR_EL0              sys_reg (3, 3, 14, 15, 7)
+#define SYS_PMCCFILTR_EL0              sys_reg(3, 3, 14, 15, 7)
 
 #define SYS_ZCR_EL2                    sys_reg(3, 4, 1, 2, 0)
-
 #define SYS_DACR32_EL2                 sys_reg(3, 4, 3, 0, 0)
+#define SYS_SPSR_EL2                   sys_reg(3, 4, 4, 0, 0)
+#define SYS_ELR_EL2                    sys_reg(3, 4, 4, 0, 1)
 #define SYS_IFSR32_EL2                 sys_reg(3, 4, 5, 0, 1)
+#define SYS_ESR_EL2                    sys_reg(3, 4, 5, 2, 0)
 #define SYS_VSESR_EL2                  sys_reg(3, 4, 5, 2, 3)
 #define SYS_FPEXC32_EL2                        sys_reg(3, 4, 5, 3, 0)
+#define SYS_FAR_EL2                    sys_reg(3, 4, 6, 0, 0)
 
 #define SYS_VDISR_EL2                  sys_reg(3, 4, 12, 1,  1)
 #define __SYS__AP0Rx_EL2(x)            sys_reg(3, 4, 12, 8, x)
 #define SYS_ICH_LR15_EL2               __SYS__LR8_EL2(7)
 
 /* VHE encodings for architectural EL0/1 system registers */
+#define SYS_SCTLR_EL12                 sys_reg(3, 5, 1, 0, 0)
+#define SYS_CPACR_EL12                 sys_reg(3, 5, 1, 0, 2)
 #define SYS_ZCR_EL12                   sys_reg(3, 5, 1, 2, 0)
+#define SYS_TTBR0_EL12                 sys_reg(3, 5, 2, 0, 0)
+#define SYS_TTBR1_EL12                 sys_reg(3, 5, 2, 0, 1)
+#define SYS_TCR_EL12                   sys_reg(3, 5, 2, 0, 2)
+#define SYS_SPSR_EL12                  sys_reg(3, 5, 4, 0, 0)
+#define SYS_ELR_EL12                   sys_reg(3, 5, 4, 0, 1)
+#define SYS_AFSR0_EL12                 sys_reg(3, 5, 5, 1, 0)
+#define SYS_AFSR1_EL12                 sys_reg(3, 5, 5, 1, 1)
+#define SYS_ESR_EL12                   sys_reg(3, 5, 5, 2, 0)
+#define SYS_FAR_EL12                   sys_reg(3, 5, 6, 0, 0)
+#define SYS_MAIR_EL12                  sys_reg(3, 5, 10, 2, 0)
+#define SYS_AMAIR_EL12                 sys_reg(3, 5, 10, 3, 0)
+#define SYS_VBAR_EL12                  sys_reg(3, 5, 12, 0, 0)
+#define SYS_CONTEXTIDR_EL12            sys_reg(3, 5, 13, 0, 1)
+#define SYS_CNTKCTL_EL12               sys_reg(3, 5, 14, 1, 0)
+#define SYS_CNTP_TVAL_EL02             sys_reg(3, 5, 14, 2, 0)
+#define SYS_CNTP_CTL_EL02              sys_reg(3, 5, 14, 2, 1)
+#define SYS_CNTP_CVAL_EL02             sys_reg(3, 5, 14, 2, 2)
+#define SYS_CNTV_TVAL_EL02             sys_reg(3, 5, 14, 3, 0)
+#define SYS_CNTV_CTL_EL02              sys_reg(3, 5, 14, 3, 1)
+#define SYS_CNTV_CVAL_EL02             sys_reg(3, 5, 14, 3, 2)
 
 /* Common SCTLR_ELx flags. */
 #define SCTLR_ELx_DSSBS        (_BITUL(44))
index d819a3e..9a50771 100644 (file)
@@ -229,6 +229,16 @@ struct kvm_vcpu_events {
 #define KVM_REG_ARM_FW_REG(r)          (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
                                         KVM_REG_ARM_FW | ((r) & 0xffff))
 #define KVM_REG_ARM_PSCI_VERSION       KVM_REG_ARM_FW_REG(0)
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1    KVM_REG_ARM_FW_REG(1)
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL          0
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL              1
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED       2
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2    KVM_REG_ARM_FW_REG(2)
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL          0
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN            1
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL              2
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED       3
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED            (1U << 4)
 
 /* SVE registers */
 #define KVM_REG_ARM64_SVE              (0x15 << KVM_REG_ARM_COPROC_SHIFT)
index ca11ff7..1e43ba5 100644 (file)
@@ -554,6 +554,17 @@ cpu_enable_cache_maint_trap(const struct arm64_cpu_capabilities *__unused)
 static bool __hardenbp_enab = true;
 static bool __spectrev2_safe = true;
 
+int get_spectre_v2_workaround_state(void)
+{
+       if (__spectrev2_safe)
+               return ARM64_BP_HARDEN_NOT_REQUIRED;
+
+       if (!__hardenbp_enab)
+               return ARM64_BP_HARDEN_UNKNOWN;
+
+       return ARM64_BP_HARDEN_WA_NEEDED;
+}
+
 /*
  * List of CPUs that do not need any Spectre-v2 mitigation at all.
  */
@@ -854,13 +865,15 @@ ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr,
 ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr,
                char *buf)
 {
-       if (__spectrev2_safe)
+       switch (get_spectre_v2_workaround_state()) {
+       case ARM64_BP_HARDEN_NOT_REQUIRED:
                return sprintf(buf, "Not affected\n");
-
-       if (__hardenbp_enab)
+        case ARM64_BP_HARDEN_WA_NEEDED:
                return sprintf(buf, "Mitigation: Branch predictor hardening\n");
-
-       return sprintf(buf, "Vulnerable\n");
+        case ARM64_BP_HARDEN_UNKNOWN:
+       default:
+               return sprintf(buf, "Vulnerable\n");
+       }
 }
 
 ssize_t cpu_show_spec_store_bypass(struct device *dev,
index 3c33d0d..d0cf596 100644 (file)
@@ -82,8 +82,7 @@ int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
        return 0;
 }
 
-static int __init set_permissions(pte_t *ptep, pgtable_t token,
-                                 unsigned long addr, void *data)
+static int __init set_permissions(pte_t *ptep, unsigned long addr, void *data)
 {
        efi_memory_desc_t *md = data;
        pte_t pte = READ_ONCE(*ptep);
index 7e541f9..9c4bad7 100644 (file)
@@ -283,6 +283,11 @@ void __init setup_arch(char **cmdline_p)
 
        setup_machine_fdt(__fdt_pointer);
 
+       /*
+        * Initialise the static keys early as they may be enabled by the
+        * cpufeature code and early parameters.
+        */
+       jump_label_init();
        parse_early_param();
 
        /*
index 9286ee6..ea90d3b 100644 (file)
@@ -420,11 +420,6 @@ void __init smp_cpus_done(unsigned int max_cpus)
 void __init smp_prepare_boot_cpu(void)
 {
        set_my_cpu_offset(per_cpu_offset(smp_processor_id()));
-       /*
-        * Initialise the static keys early as they may be enabled by the
-        * cpufeature code.
-        */
-       jump_label_init();
        cpuinfo_store_boot_cpu();
 
        /*
index 678af74..8c03456 100644 (file)
@@ -871,6 +871,10 @@ bool arm64_is_fatal_ras_serror(struct pt_regs *regs, unsigned int esr)
                /*
                 * The CPU can't make progress. The exception may have
                 * been imprecise.
+                *
+                * Neoverse-N1 #1349291 means a non-KVM SError reported as
+                * Unrecoverable should be treated as Uncontainable. We
+                * call arm64_serror_panic() in both cases.
                 */
                return true;
 
index bd34016..e5cc8d6 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/linkage.h>
 
+#include <asm/alternative.h>
 #include <asm/asm-offsets.h>
 #include <asm/assembler.h>
 #include <asm/fpsimdmacros.h>
@@ -52,6 +53,20 @@ ENTRY(__guest_enter)
        // Store the host regs
        save_callee_saved_regs x1
 
+       // Now the host state is stored if we have a pending RAS SError it must
+       // affect the host. If any asynchronous exception is pending we defer
+       // the guest entry. The DSB isn't necessary before v8.2 as any SError
+       // would be fatal.
+alternative_if ARM64_HAS_RAS_EXTN
+       dsb     nshst
+       isb
+alternative_else_nop_endif
+       mrs     x1, isr_el1
+       cbz     x1,  1f
+       mov     x0, #ARM_EXCEPTION_IRQ
+       ret
+
+1:
        add     x18, x0, #VCPU_CONTEXT
 
        // Macro ptrauth_switch_to_guest format:
@@ -127,8 +142,8 @@ ENTRY(__guest_exit)
 
 alternative_if ARM64_HAS_RAS_EXTN
        // If we have the RAS extensions we can consume a pending error
-       // without an unmask-SError and isb.
-       esb
+       // without an unmask-SError and isb. The ESB-instruction consumed any
+       // pending guest error when we took the exception from the guest.
        mrs_s   x2, SYS_DISR_EL1
        str     x2, [x1, #(VCPU_FAULT_DISR - VCPU_CONTEXT)]
        cbz     x2, 1f
@@ -136,8 +151,16 @@ alternative_if ARM64_HAS_RAS_EXTN
        orr     x0, x0, #(1<<ARM_EXIT_WITH_SERROR_BIT)
 1:     ret
 alternative_else
-       // If we have a pending asynchronous abort, now is the
-       // time to find out. From your VAXorcist book, page 666:
+       dsb     sy              // Synchronize against in-flight ld/st
+       isb                     // Prevent an early read of side-effect free ISR
+       mrs     x2, isr_el1
+       tbnz    x2, #8, 2f      // ISR_EL1.A
+       ret
+       nop
+2:
+alternative_endif
+       // We know we have a pending asynchronous abort, now is the
+       // time to flush it out. From your VAXorcist book, page 666:
        // "Threaten me not, oh Evil one!  For I speak with
        // the power of DEC, and I command thee to show thyself!"
        mrs     x2, elr_el2
@@ -145,10 +168,7 @@ alternative_else
        mrs     x4, spsr_el2
        mov     x5, x0
 
-       dsb     sy              // Synchronize against in-flight ld/st
-       nop
        msr     daifclr, #4     // Unmask aborts
-alternative_endif
 
        // This is our single instruction exception window. A pending
        // SError is guaranteed to occur at the earliest when we unmask
@@ -161,6 +181,8 @@ abort_guest_exit_start:
        .global abort_guest_exit_end
 abort_guest_exit_end:
 
+       msr     daifset, #4     // Mask aborts
+
        // If the exception took place, restore the EL1 exception
        // context so that we can report some information.
        // Merge the exception code with the SError pending bit.
index b8e0456..ffa68d5 100644 (file)
@@ -216,17 +216,34 @@ ENDPROC(\label)
 
        .align 11
 
+.macro check_preamble_length start, end
+/* kvm_patch_vector_branch() generates code that jumps over the preamble. */
+.if ((\end-\start) != KVM_VECTOR_PREAMBLE)
+       .error "KVM vector preamble length mismatch"
+.endif
+.endm
+
 .macro valid_vect target
        .align 7
+661:
+       esb
        stp     x0, x1, [sp, #-16]!
+662:
        b       \target
+
+check_preamble_length 661b, 662b
 .endm
 
 .macro invalid_vect target
        .align 7
+661:
        b       \target
+       nop
+662:
        ldp     x0, x1, [sp], #16
        b       \target
+
+check_preamble_length 661b, 662b
 .endm
 
 ENTRY(__kvm_hyp_vector)
@@ -254,13 +271,14 @@ ENDPROC(__kvm_hyp_vector)
 #ifdef CONFIG_KVM_INDIRECT_VECTORS
 .macro hyp_ventry
        .align 7
-1:     .rept 27
+1:     esb
+       .rept 26
        nop
        .endr
 /*
  * The default sequence is to directly branch to the KVM vectors,
  * using the computed offset. This applies for VHE as well as
- * !ARM64_HARDEN_EL2_VECTORS.
+ * !ARM64_HARDEN_EL2_VECTORS. The first vector must always run the preamble.
  *
  * For ARM64_HARDEN_EL2_VECTORS configurations, this gets replaced
  * with:
@@ -271,12 +289,13 @@ ENDPROC(__kvm_hyp_vector)
  * movk        x0, #((addr >> 32) & 0xffff), lsl #32
  * br  x0
  *
- * Where addr = kern_hyp_va(__kvm_hyp_vector) + vector-offset + 4.
+ * Where:
+ * addr = kern_hyp_va(__kvm_hyp_vector) + vector-offset + KVM_VECTOR_PREAMBLE.
  * See kvm_patch_vector_branch for details.
  */
 alternative_cb kvm_patch_vector_branch
-       b       __kvm_hyp_vector + (1b - 0b)
-       nop
+       stp     x0, x1, [sp, #-16]!
+       b       __kvm_hyp_vector + (1b - 0b + KVM_VECTOR_PREAMBLE)
        nop
        nop
        nop
@@ -301,6 +320,7 @@ ENTRY(__bp_harden_hyp_vecs_end)
        .popsection
 
 ENTRY(__smccc_workaround_1_smc_start)
+       esb
        sub     sp, sp, #(8 * 4)
        stp     x2, x3, [sp, #(8 * 0)]
        stp     x0, x1, [sp, #(8 * 2)]
index 58f281b..adaf266 100644 (file)
@@ -284,7 +284,7 @@ static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
        if (ec != ESR_ELx_EC_DABT_LOW && ec != ESR_ELx_EC_IABT_LOW)
                return true;
 
-       far = read_sysreg_el2(far);
+       far = read_sysreg_el2(SYS_FAR);
 
        /*
         * The HPFAR can be invalid if the stage 2 fault did not
@@ -401,7 +401,7 @@ static bool __hyp_text __hyp_handle_fpsimd(struct kvm_vcpu *vcpu)
 static bool __hyp_text fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
 {
        if (ARM_EXCEPTION_CODE(*exit_code) != ARM_EXCEPTION_IRQ)
-               vcpu->arch.fault.esr_el2 = read_sysreg_el2(esr);
+               vcpu->arch.fault.esr_el2 = read_sysreg_el2(SYS_ESR);
 
        /*
         * We're using the raw exception code in order to only process
@@ -697,8 +697,8 @@ static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par,
        asm volatile("ldr %0, =__hyp_panic_string" : "=r" (str_va));
 
        __hyp_do_panic(str_va,
-                      spsr,  elr,
-                      read_sysreg(esr_el2),   read_sysreg_el2(far),
+                      spsr, elr,
+                      read_sysreg(esr_el2), read_sysreg_el2(SYS_FAR),
                       read_sysreg(hpfar_el2), par, vcpu);
 }
 
@@ -713,15 +713,15 @@ static void __hyp_call_panic_vhe(u64 spsr, u64 elr, u64 par,
 
        panic(__hyp_panic_string,
              spsr,  elr,
-             read_sysreg_el2(esr),   read_sysreg_el2(far),
+             read_sysreg_el2(SYS_ESR),   read_sysreg_el2(SYS_FAR),
              read_sysreg(hpfar_el2), par, vcpu);
 }
 NOKPROBE_SYMBOL(__hyp_call_panic_vhe);
 
 void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *host_ctxt)
 {
-       u64 spsr = read_sysreg_el2(spsr);
-       u64 elr = read_sysreg_el2(elr);
+       u64 spsr = read_sysreg_el2(SYS_SPSR);
+       u64 elr = read_sysreg_el2(SYS_ELR);
        u64 par = read_sysreg(par_el1);
 
        if (!has_vhe())
index c283f7c..7ddbc84 100644 (file)
@@ -43,33 +43,33 @@ static void __hyp_text __sysreg_save_user_state(struct kvm_cpu_context *ctxt)
 static void __hyp_text __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
 {
        ctxt->sys_regs[CSSELR_EL1]      = read_sysreg(csselr_el1);
-       ctxt->sys_regs[SCTLR_EL1]       = read_sysreg_el1(sctlr);
+       ctxt->sys_regs[SCTLR_EL1]       = read_sysreg_el1(SYS_SCTLR);
        ctxt->sys_regs[ACTLR_EL1]       = read_sysreg(actlr_el1);
-       ctxt->sys_regs[CPACR_EL1]       = read_sysreg_el1(cpacr);
-       ctxt->sys_regs[TTBR0_EL1]       = read_sysreg_el1(ttbr0);
-       ctxt->sys_regs[TTBR1_EL1]       = read_sysreg_el1(ttbr1);
-       ctxt->sys_regs[TCR_EL1]         = read_sysreg_el1(tcr);
-       ctxt->sys_regs[ESR_EL1]         = read_sysreg_el1(esr);
-       ctxt->sys_regs[AFSR0_EL1]       = read_sysreg_el1(afsr0);
-       ctxt->sys_regs[AFSR1_EL1]       = read_sysreg_el1(afsr1);
-       ctxt->sys_regs[FAR_EL1]         = read_sysreg_el1(far);
-       ctxt->sys_regs[MAIR_EL1]        = read_sysreg_el1(mair);
-       ctxt->sys_regs[VBAR_EL1]        = read_sysreg_el1(vbar);
-       ctxt->sys_regs[CONTEXTIDR_EL1]  = read_sysreg_el1(contextidr);
-       ctxt->sys_regs[AMAIR_EL1]       = read_sysreg_el1(amair);
-       ctxt->sys_regs[CNTKCTL_EL1]     = read_sysreg_el1(cntkctl);
+       ctxt->sys_regs[CPACR_EL1]       = read_sysreg_el1(SYS_CPACR);
+       ctxt->sys_regs[TTBR0_EL1]       = read_sysreg_el1(SYS_TTBR0);
+       ctxt->sys_regs[TTBR1_EL1]       = read_sysreg_el1(SYS_TTBR1);
+       ctxt->sys_regs[TCR_EL1]         = read_sysreg_el1(SYS_TCR);
+       ctxt->sys_regs[ESR_EL1]         = read_sysreg_el1(SYS_ESR);
+       ctxt->sys_regs[AFSR0_EL1]       = read_sysreg_el1(SYS_AFSR0);
+       ctxt->sys_regs[AFSR1_EL1]       = read_sysreg_el1(SYS_AFSR1);
+       ctxt->sys_regs[FAR_EL1]         = read_sysreg_el1(SYS_FAR);
+       ctxt->sys_regs[MAIR_EL1]        = read_sysreg_el1(SYS_MAIR);
+       ctxt->sys_regs[VBAR_EL1]        = read_sysreg_el1(SYS_VBAR);
+       ctxt->sys_regs[CONTEXTIDR_EL1]  = read_sysreg_el1(SYS_CONTEXTIDR);
+       ctxt->sys_regs[AMAIR_EL1]       = read_sysreg_el1(SYS_AMAIR);
+       ctxt->sys_regs[CNTKCTL_EL1]     = read_sysreg_el1(SYS_CNTKCTL);
        ctxt->sys_regs[PAR_EL1]         = read_sysreg(par_el1);
        ctxt->sys_regs[TPIDR_EL1]       = read_sysreg(tpidr_el1);
 
        ctxt->gp_regs.sp_el1            = read_sysreg(sp_el1);
-       ctxt->gp_regs.elr_el1           = read_sysreg_el1(elr);
-       ctxt->gp_regs.spsr[KVM_SPSR_EL1]= read_sysreg_el1(spsr);
+       ctxt->gp_regs.elr_el1           = read_sysreg_el1(SYS_ELR);
+       ctxt->gp_regs.spsr[KVM_SPSR_EL1]= read_sysreg_el1(SYS_SPSR);
 }
 
 static void __hyp_text __sysreg_save_el2_return_state(struct kvm_cpu_context *ctxt)
 {
-       ctxt->gp_regs.regs.pc           = read_sysreg_el2(elr);
-       ctxt->gp_regs.regs.pstate       = read_sysreg_el2(spsr);
+       ctxt->gp_regs.regs.pc           = read_sysreg_el2(SYS_ELR);
+       ctxt->gp_regs.regs.pstate       = read_sysreg_el2(SYS_SPSR);
 
        if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN))
                ctxt->sys_regs[DISR_EL1] = read_sysreg_s(SYS_VDISR_EL2);
@@ -109,35 +109,35 @@ static void __hyp_text __sysreg_restore_common_state(struct kvm_cpu_context *ctx
 
 static void __hyp_text __sysreg_restore_user_state(struct kvm_cpu_context *ctxt)
 {
-       write_sysreg(ctxt->sys_regs[TPIDR_EL0],         tpidr_el0);
-       write_sysreg(ctxt->sys_regs[TPIDRRO_EL0],       tpidrro_el0);
+       write_sysreg(ctxt->sys_regs[TPIDR_EL0],         tpidr_el0);
+       write_sysreg(ctxt->sys_regs[TPIDRRO_EL0],       tpidrro_el0);
 }
 
 static void __hyp_text __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
 {
        write_sysreg(ctxt->sys_regs[MPIDR_EL1],         vmpidr_el2);
        write_sysreg(ctxt->sys_regs[CSSELR_EL1],        csselr_el1);
-       write_sysreg_el1(ctxt->sys_regs[SCTLR_EL1],     sctlr);
-       write_sysreg(ctxt->sys_regs[ACTLR_EL1],         actlr_el1);
-       write_sysreg_el1(ctxt->sys_regs[CPACR_EL1],     cpacr);
-       write_sysreg_el1(ctxt->sys_regs[TTBR0_EL1],     ttbr0);
-       write_sysreg_el1(ctxt->sys_regs[TTBR1_EL1],     ttbr1);
-       write_sysreg_el1(ctxt->sys_regs[TCR_EL1],       tcr);
-       write_sysreg_el1(ctxt->sys_regs[ESR_EL1],       esr);
-       write_sysreg_el1(ctxt->sys_regs[AFSR0_EL1],     afsr0);
-       write_sysreg_el1(ctxt->sys_regs[AFSR1_EL1],     afsr1);
-       write_sysreg_el1(ctxt->sys_regs[FAR_EL1],       far);
-       write_sysreg_el1(ctxt->sys_regs[MAIR_EL1],      mair);
-       write_sysreg_el1(ctxt->sys_regs[VBAR_EL1],      vbar);
-       write_sysreg_el1(ctxt->sys_regs[CONTEXTIDR_EL1],contextidr);
-       write_sysreg_el1(ctxt->sys_regs[AMAIR_EL1],     amair);
-       write_sysreg_el1(ctxt->sys_regs[CNTKCTL_EL1],   cntkctl);
+       write_sysreg_el1(ctxt->sys_regs[SCTLR_EL1],     SYS_SCTLR);
+       write_sysreg(ctxt->sys_regs[ACTLR_EL1],         actlr_el1);
+       write_sysreg_el1(ctxt->sys_regs[CPACR_EL1],     SYS_CPACR);
+       write_sysreg_el1(ctxt->sys_regs[TTBR0_EL1],     SYS_TTBR0);
+       write_sysreg_el1(ctxt->sys_regs[TTBR1_EL1],     SYS_TTBR1);
+       write_sysreg_el1(ctxt->sys_regs[TCR_EL1],       SYS_TCR);
+       write_sysreg_el1(ctxt->sys_regs[ESR_EL1],       SYS_ESR);
+       write_sysreg_el1(ctxt->sys_regs[AFSR0_EL1],     SYS_AFSR0);
+       write_sysreg_el1(ctxt->sys_regs[AFSR1_EL1],     SYS_AFSR1);
+       write_sysreg_el1(ctxt->sys_regs[FAR_EL1],       SYS_FAR);
+       write_sysreg_el1(ctxt->sys_regs[MAIR_EL1],      SYS_MAIR);
+       write_sysreg_el1(ctxt->sys_regs[VBAR_EL1],      SYS_VBAR);
+       write_sysreg_el1(ctxt->sys_regs[CONTEXTIDR_EL1],SYS_CONTEXTIDR);
+       write_sysreg_el1(ctxt->sys_regs[AMAIR_EL1],     SYS_AMAIR);
+       write_sysreg_el1(ctxt->sys_regs[CNTKCTL_EL1],   SYS_CNTKCTL);
        write_sysreg(ctxt->sys_regs[PAR_EL1],           par_el1);
        write_sysreg(ctxt->sys_regs[TPIDR_EL1],         tpidr_el1);
 
        write_sysreg(ctxt->gp_regs.sp_el1,              sp_el1);
-       write_sysreg_el1(ctxt->gp_regs.elr_el1,         elr);
-       write_sysreg_el1(ctxt->gp_regs.spsr[KVM_SPSR_EL1],spsr);
+       write_sysreg_el1(ctxt->gp_regs.elr_el1,         SYS_ELR);
+       write_sysreg_el1(ctxt->gp_regs.spsr[KVM_SPSR_EL1],SYS_SPSR);
 }
 
 static void __hyp_text
@@ -160,8 +160,8 @@ __sysreg_restore_el2_return_state(struct kvm_cpu_context *ctxt)
        if (!(mode & PSR_MODE32_BIT) && mode >= PSR_MODE_EL2t)
                pstate = PSR_MODE_EL2h | PSR_IL_BIT;
 
-       write_sysreg_el2(ctxt->gp_regs.regs.pc,         elr);
-       write_sysreg_el2(pstate,                        spsr);
+       write_sysreg_el2(ctxt->gp_regs.regs.pc,         SYS_ELR);
+       write_sysreg_el2(pstate,                        SYS_SPSR);
 
        if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN))
                write_sysreg_s(ctxt->sys_regs[DISR_EL1], SYS_VDISR_EL2);
index 32078b7..d49a144 100644 (file)
@@ -33,12 +33,12 @@ static void __hyp_text __tlb_switch_to_guest_vhe(struct kvm *kvm,
                 * in the TCR_EL1 register. We also need to prevent it to
                 * allocate IPA->PA walks, so we enable the S1 MMU...
                 */
-               val = cxt->tcr = read_sysreg_el1(tcr);
+               val = cxt->tcr = read_sysreg_el1(SYS_TCR);
                val |= TCR_EPD1_MASK | TCR_EPD0_MASK;
-               write_sysreg_el1(val, tcr);
-               val = cxt->sctlr = read_sysreg_el1(sctlr);
+               write_sysreg_el1(val, SYS_TCR);
+               val = cxt->sctlr = read_sysreg_el1(SYS_SCTLR);
                val |= SCTLR_ELx_M;
-               write_sysreg_el1(val, sctlr);
+               write_sysreg_el1(val, SYS_SCTLR);
        }
 
        /*
@@ -85,8 +85,8 @@ static void __hyp_text __tlb_switch_to_host_vhe(struct kvm *kvm,
 
        if (cpus_have_const_cap(ARM64_WORKAROUND_1165522)) {
                /* Restore the registers to what they were */
-               write_sysreg_el1(cxt->tcr, tcr);
-               write_sysreg_el1(cxt->sctlr, sctlr);
+               write_sysreg_el1(cxt->tcr, SYS_TCR);
+               write_sysreg_el1(cxt->sctlr, SYS_SCTLR);
        }
 
        local_irq_restore(cxt->flags);
index ba2aaeb..29ee1fe 100644 (file)
@@ -16,7 +16,7 @@
 static bool __hyp_text __is_be(struct kvm_vcpu *vcpu)
 {
        if (vcpu_mode_is_32bit(vcpu))
-               return !!(read_sysreg_el2(spsr) & PSR_AA32_E_BIT);
+               return !!(read_sysreg_el2(SYS_SPSR) & PSR_AA32_E_BIT);
 
        return !!(read_sysreg(SCTLR_EL1) & SCTLR_ELx_EE);
 }
index d66613e..0d60e4f 100644 (file)
@@ -152,7 +152,7 @@ unsigned long vcpu_read_spsr32(const struct kvm_vcpu *vcpu)
 
        switch (spsr_idx) {
        case KVM_SPSR_SVC:
-               return read_sysreg_el1(spsr);
+               return read_sysreg_el1(SYS_SPSR);
        case KVM_SPSR_ABT:
                return read_sysreg(spsr_abt);
        case KVM_SPSR_UND:
@@ -177,7 +177,7 @@ void vcpu_write_spsr32(struct kvm_vcpu *vcpu, unsigned long v)
 
        switch (spsr_idx) {
        case KVM_SPSR_SVC:
-               write_sysreg_el1(v, spsr);
+               write_sysreg_el1(v, SYS_SPSR);
        case KVM_SPSR_ABT:
                write_sysreg(v, spsr_abt);
        case KVM_SPSR_UND:
index ce933f2..f26e181 100644 (file)
@@ -81,24 +81,24 @@ u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg)
         */
        switch (reg) {
        case CSSELR_EL1:        return read_sysreg_s(SYS_CSSELR_EL1);
-       case SCTLR_EL1:         return read_sysreg_s(sctlr_EL12);
+       case SCTLR_EL1:         return read_sysreg_s(SYS_SCTLR_EL12);
        case ACTLR_EL1:         return read_sysreg_s(SYS_ACTLR_EL1);
-       case CPACR_EL1:         return read_sysreg_s(cpacr_EL12);
-       case TTBR0_EL1:         return read_sysreg_s(ttbr0_EL12);
-       case TTBR1_EL1:         return read_sysreg_s(ttbr1_EL12);
-       case TCR_EL1:           return read_sysreg_s(tcr_EL12);
-       case ESR_EL1:           return read_sysreg_s(esr_EL12);
-       case AFSR0_EL1:         return read_sysreg_s(afsr0_EL12);
-       case AFSR1_EL1:         return read_sysreg_s(afsr1_EL12);
-       case FAR_EL1:           return read_sysreg_s(far_EL12);
-       case MAIR_EL1:          return read_sysreg_s(mair_EL12);
-       case VBAR_EL1:          return read_sysreg_s(vbar_EL12);
-       case CONTEXTIDR_EL1:    return read_sysreg_s(contextidr_EL12);
+       case CPACR_EL1:         return read_sysreg_s(SYS_CPACR_EL12);
+       case TTBR0_EL1:         return read_sysreg_s(SYS_TTBR0_EL12);
+       case TTBR1_EL1:         return read_sysreg_s(SYS_TTBR1_EL12);
+       case TCR_EL1:           return read_sysreg_s(SYS_TCR_EL12);
+       case ESR_EL1:           return read_sysreg_s(SYS_ESR_EL12);
+       case AFSR0_EL1:         return read_sysreg_s(SYS_AFSR0_EL12);
+       case AFSR1_EL1:         return read_sysreg_s(SYS_AFSR1_EL12);
+       case FAR_EL1:           return read_sysreg_s(SYS_FAR_EL12);
+       case MAIR_EL1:          return read_sysreg_s(SYS_MAIR_EL12);
+       case VBAR_EL1:          return read_sysreg_s(SYS_VBAR_EL12);
+       case CONTEXTIDR_EL1:    return read_sysreg_s(SYS_CONTEXTIDR_EL12);
        case TPIDR_EL0:         return read_sysreg_s(SYS_TPIDR_EL0);
        case TPIDRRO_EL0:       return read_sysreg_s(SYS_TPIDRRO_EL0);
        case TPIDR_EL1:         return read_sysreg_s(SYS_TPIDR_EL1);
-       case AMAIR_EL1:         return read_sysreg_s(amair_EL12);
-       case CNTKCTL_EL1:       return read_sysreg_s(cntkctl_EL12);
+       case AMAIR_EL1:         return read_sysreg_s(SYS_AMAIR_EL12);
+       case CNTKCTL_EL1:       return read_sysreg_s(SYS_CNTKCTL_EL12);
        case PAR_EL1:           return read_sysreg_s(SYS_PAR_EL1);
        case DACR32_EL2:        return read_sysreg_s(SYS_DACR32_EL2);
        case IFSR32_EL2:        return read_sysreg_s(SYS_IFSR32_EL2);
@@ -124,24 +124,24 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg)
         */
        switch (reg) {
        case CSSELR_EL1:        write_sysreg_s(val, SYS_CSSELR_EL1);    return;
-       case SCTLR_EL1:         write_sysreg_s(val, sctlr_EL12);        return;
+       case SCTLR_EL1:         write_sysreg_s(val, SYS_SCTLR_EL12);    return;
        case ACTLR_EL1:         write_sysreg_s(val, SYS_ACTLR_EL1);     return;
-       case CPACR_EL1:         write_sysreg_s(val, cpacr_EL12);        return;
-       case TTBR0_EL1:         write_sysreg_s(val, ttbr0_EL12);        return;
-       case TTBR1_EL1:         write_sysreg_s(val, ttbr1_EL12);        return;
-       case TCR_EL1:           write_sysreg_s(val, tcr_EL12);          return;
-       case ESR_EL1:           write_sysreg_s(val, esr_EL12);          return;
-       case AFSR0_EL1:         write_sysreg_s(val, afsr0_EL12);        return;
-       case AFSR1_EL1:         write_sysreg_s(val, afsr1_EL12);        return;
-       case FAR_EL1:           write_sysreg_s(val, far_EL12);          return;
-       case MAIR_EL1:          write_sysreg_s(val, mair_EL12);         return;
-       case VBAR_EL1:          write_sysreg_s(val, vbar_EL12);         return;
-       case CONTEXTIDR_EL1:    write_sysreg_s(val, contextidr_EL12);   return;
+       case CPACR_EL1:         write_sysreg_s(val, SYS_CPACR_EL12);    return;
+       case TTBR0_EL1:         write_sysreg_s(val, SYS_TTBR0_EL12);    return;
+       case TTBR1_EL1:         write_sysreg_s(val, SYS_TTBR1_EL12);    return;
+       case TCR_EL1:           write_sysreg_s(val, SYS_TCR_EL12);      return;
+       case ESR_EL1:           write_sysreg_s(val, SYS_ESR_EL12);      return;
+       case AFSR0_EL1:         write_sysreg_s(val, SYS_AFSR0_EL12);    return;
+       case AFSR1_EL1:         write_sysreg_s(val, SYS_AFSR1_EL12);    return;
+       case FAR_EL1:           write_sysreg_s(val, SYS_FAR_EL12);      return;
+       case MAIR_EL1:          write_sysreg_s(val, SYS_MAIR_EL12);     return;
+       case VBAR_EL1:          write_sysreg_s(val, SYS_VBAR_EL12);     return;
+       case CONTEXTIDR_EL1:    write_sysreg_s(val, SYS_CONTEXTIDR_EL12); return;
        case TPIDR_EL0:         write_sysreg_s(val, SYS_TPIDR_EL0);     return;
        case TPIDRRO_EL0:       write_sysreg_s(val, SYS_TPIDRRO_EL0);   return;
        case TPIDR_EL1:         write_sysreg_s(val, SYS_TPIDR_EL1);     return;
-       case AMAIR_EL1:         write_sysreg_s(val, amair_EL12);        return;
-       case CNTKCTL_EL1:       write_sysreg_s(val, cntkctl_EL12);      return;
+       case AMAIR_EL1:         write_sysreg_s(val, SYS_AMAIR_EL12);    return;
+       case CNTKCTL_EL1:       write_sysreg_s(val, SYS_CNTKCTL_EL12);  return;
        case PAR_EL1:           write_sysreg_s(val, SYS_PAR_EL1);       return;
        case DACR32_EL2:        write_sysreg_s(val, SYS_DACR32_EL2);    return;
        case IFSR32_EL2:        write_sysreg_s(val, SYS_IFSR32_EL2);    return;
@@ -865,12 +865,12 @@ static bool access_pmcnten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
                if (r->Op2 & 0x1) {
                        /* accessing PMCNTENSET_EL0 */
                        __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) |= val;
-                       kvm_pmu_enable_counter(vcpu, val);
+                       kvm_pmu_enable_counter_mask(vcpu, val);
                        kvm_vcpu_pmu_restore_guest(vcpu);
                } else {
                        /* accessing PMCNTENCLR_EL0 */
                        __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) &= ~val;
-                       kvm_pmu_disable_counter(vcpu, val);
+                       kvm_pmu_disable_counter_mask(vcpu, val);
                }
        } else {
                p->regval = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask;
index 2947ab1..acd8084 100644 (file)
@@ -170,11 +170,10 @@ void kvm_patch_vector_branch(struct alt_instr *alt,
        addr |= ((u64)origptr & GENMASK_ULL(10, 7));
 
        /*
-        * Branch to the second instruction in the vectors in order to
-        * avoid the initial store on the stack (which we already
-        * perform in the hardening vectors).
+        * Branch over the preamble in order to avoid the initial store on
+        * the stack (which we already perform in the hardening vectors).
         */
-       addr += AARCH64_INSN_SIZE;
+       addr += KVM_VECTOR_PREAMBLE;
 
        /* stp x0, x1, [sp, #-16]! */
        insn = aarch64_insn_gen_load_store_pair(AARCH64_INSN_REG_0,
index 3645f29..1b49c08 100644 (file)
@@ -362,7 +362,7 @@ static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
 
 static phys_addr_t __pgd_pgtable_alloc(int shift)
 {
-       void *ptr = (void *)__get_free_page(PGALLOC_GFP);
+       void *ptr = (void *)__get_free_page(GFP_PGTABLE_KERNEL);
        BUG_ON(!ptr);
 
        /* Ensure the zeroed page is visible to the page table walker */
index fcdcf6c..03c53f1 100644 (file)
@@ -19,8 +19,7 @@ struct page_change_data {
 
 bool rodata_full __ro_after_init = IS_ENABLED(CONFIG_RODATA_FULL_DEFAULT_ENABLED);
 
-static int change_page_range(pte_t *ptep, pgtable_t token, unsigned long addr,
-                       void *data)
+static int change_page_range(pte_t *ptep, unsigned long addr, void *data)
 {
        struct page_change_data *cdata = data;
        pte_t pte = READ_ONCE(*ptep);
index 9a0c7d5..7548f9c 100644 (file)
@@ -19,10 +19,12 @@ static struct kmem_cache *pgd_cache __ro_after_init;
 
 pgd_t *pgd_alloc(struct mm_struct *mm)
 {
+       gfp_t gfp = GFP_PGTABLE_USER;
+
        if (PGD_SIZE == PAGE_SIZE)
-               return (pgd_t *)__get_free_page(PGALLOC_GFP);
+               return (pgd_t *)__get_free_page(gfp);
        else
-               return kmem_cache_alloc(pgd_cache, PGALLOC_GFP);
+               return kmem_cache_alloc(pgd_cache, gfp);
 }
 
 void pgd_free(struct mm_struct *mm, pgd_t *pgd)
index f9aab91..fb1bbbd 100644 (file)
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 OBJCOPYFLAGS           :=-O binary
 GZFLAGS                        :=-9
-KBUILD_DEFCONFIG       := defconfig
 
 ifdef CONFIG_CPU_HAS_FPU
 FPUEXT = f
index d213bb4..98c5716 100644 (file)
@@ -8,6 +8,9 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 
+#define __HAVE_ARCH_PTE_ALLOC_ONE_KERNEL
+#include <asm-generic/pgalloc.h>       /* for pte_{alloc,free}_one */
+
 static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
                                        pte_t *pte)
 {
@@ -39,33 +42,6 @@ static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm)
        return pte;
 }
 
-static inline struct page *pte_alloc_one(struct mm_struct *mm)
-{
-       struct page *pte;
-
-       pte = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0);
-       if (!pte)
-               return NULL;
-
-       if (!pgtable_page_ctor(pte)) {
-               __free_page(pte);
-               return NULL;
-       }
-
-       return pte;
-}
-
-static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
-{
-       free_pages((unsigned long)pte, PTE_ORDER);
-}
-
-static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
-{
-       pgtable_page_dtor(pte);
-       __free_pages(pte, PTE_ORDER);
-}
-
 static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
        free_pages((unsigned long)pgd, PGD_ORDER);
index 7aeb48a..1a338e5 100644 (file)
@@ -324,8 +324,6 @@ static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
        return -ENOIOCTLCMD;
 }
 
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
 /*
  * This routine will shutdown a serial port; interrupts are disabled, and
  * DTR is dropped if the hangup on close termio flag is on.
index 1456c5e..1a8ddbd 100644 (file)
 
 #include <asm/tlb.h>
 
+#include <asm-generic/pgalloc.h>       /* for pte_{alloc,free}_one */
+
 extern const char bad_pmd_string[];
 
 #define pmd_alloc_one(mm,address)       ({ BUG(); ((pmd_t *)2); })
 
-
-static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
-{
-        free_page((unsigned long) pte);
-}
-
-static inline void pte_free(struct mm_struct *mm, pgtable_t page)
-{
-       pgtable_page_dtor(page);
-        __free_page(page);
-}
-
 #define __pte_free_tlb(tlb,pte,addr)                   \
 do {                                                   \
        pgtable_page_dtor(pte);                         \
        tlb_remove_page((tlb), pte);                    \
 } while (0)
 
-static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm)
-{
-       unsigned long page = __get_free_page(GFP_KERNEL);
-
-       if (!page)
-               return NULL;
-
-       memset((void *)page, 0, PAGE_SIZE);
-       return (pte_t *) (page);
-}
-
-static inline pgtable_t pte_alloc_one(struct mm_struct *mm)
-{
-        struct page *page = alloc_pages(GFP_KERNEL, 0);
-
-       if (page == NULL)
-               return NULL;
-
-       clear_highpage(page);
-       if (!pgtable_page_ctor(page)) {
-               __free_page(page);
-               return NULL;
-       }
-       return page;
-
-}
-
 static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
 {
        pmd_val(*pmd) = __pa((unsigned long)pte);
index 11be08f..205ac75 100644 (file)
@@ -911,6 +911,10 @@ static const struct resource mac_scsi_iifx_rsrc[] __initconst = {
                .flags = IORESOURCE_MEM,
                .start = 0x50008000,
                .end   = 0x50009FFF,
+       }, {
+               .flags = IORESOURCE_MEM,
+               .start = 0x50008000,
+               .end   = 0x50009FFF,
        },
 };
 
@@ -1012,10 +1016,12 @@ int __init mac_platform_init(void)
        case MAC_SCSI_IIFX:
                /* Addresses from The Guide to Mac Family Hardware.
                 * $5000 8000 - $5000 9FFF: SCSI DMA
+                * $5000 A000 - $5000 BFFF: Alternate SCSI
                 * $5000 C000 - $5000 DFFF: Alternate SCSI (DMA)
                 * $5000 E000 - $5000 FFFF: Alternate SCSI (Hsk)
-                * The SCSI DMA custom IC embeds the 53C80 core. mac_scsi does
-                * not make use of its DMA or hardware handshaking logic.
+                * The A/UX header file sys/uconfig.h says $50F0 8000.
+                * The "SCSI DMA" custom IC embeds the 53C80 core and
+                * supports Programmed IO, DMA and PDMA (hardware handshake).
                 */
                platform_device_register_simple("mac_scsi", 0,
                        mac_scsi_iifx_rsrc, ARRAY_SIZE(mac_scsi_iifx_rsrc));
index 70d3200..d50fafd 100644 (file)
@@ -34,6 +34,7 @@ config MIPS
        select GENERIC_SCHED_CLOCK if !CAVIUM_OCTEON_SOC
        select GENERIC_SMP_IDLE_THREAD
        select GENERIC_TIME_VSYSCALL
+       select GUP_GET_PTE_LOW_HIGH if CPU_MIPS32 && PHYS_ADDR_T_64BIT
        select HANDLE_DOMAIN_IRQ
        select HAVE_ARCH_COMPILER_H
        select HAVE_ARCH_JUMP_LABEL
@@ -52,6 +53,7 @@ config MIPS
        select HAVE_DMA_CONTIGUOUS
        select HAVE_DYNAMIC_FTRACE
        select HAVE_EXIT_THREAD
+       select HAVE_FAST_GUP
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_FUNCTION_TRACER
@@ -1119,6 +1121,7 @@ config DMA_NONCOHERENT
        bool
        select ARCH_HAS_DMA_MMAP_PGPROT
        select ARCH_HAS_SYNC_DMA_FOR_DEVICE
+       select ARCH_HAS_UNCACHED_SEGMENT
        select NEED_DMA_MAP_STATE
        select ARCH_HAS_DMA_COHERENT_TO_PFN
        select DMA_NONCOHERENT_CACHE_SYNC
index a25643d..0ba4ce6 100644 (file)
@@ -258,9 +258,6 @@ extern bool __virt_addr_valid(const volatile void *kaddr);
         ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
         VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
-#define UNCAC_ADDR(addr)       (UNCAC_BASE + __pa(addr))
-#define CAC_ADDR(addr)         ((unsigned long)__va((addr) - UNCAC_BASE))
-
 #include <asm-generic/memory_model.h>
 #include <asm-generic/getorder.h>
 
index 27808d9..aa16b85 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 
+#include <asm-generic/pgalloc.h>       /* for pte_{alloc,free}_one */
+
 static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
        pte_t *pte)
 {
@@ -50,37 +52,6 @@ static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
        free_pages((unsigned long)pgd, PGD_ORDER);
 }
 
-static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm)
-{
-       return (pte_t *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, PTE_ORDER);
-}
-
-static inline struct page *pte_alloc_one(struct mm_struct *mm)
-{
-       struct page *pte;
-
-       pte = alloc_pages(GFP_KERNEL, PTE_ORDER);
-       if (!pte)
-               return NULL;
-       clear_highpage(pte);
-       if (!pgtable_page_ctor(pte)) {
-               __free_page(pte);
-               return NULL;
-       }
-       return pte;
-}
-
-static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
-{
-       free_pages((unsigned long)pte, PTE_ORDER);
-}
-
-static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
-{
-       pgtable_page_dtor(pte);
-       __free_pages(pte, PTE_ORDER);
-}
-
 #define __pte_free_tlb(tlb,pte,address)                        \
 do {                                                   \
        pgtable_page_dtor(pte);                         \
index 4ccb465..7d27194 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/cmpxchg.h>
 #include <asm/io.h>
 #include <asm/pgtable-bits.h>
+#include <asm/cpu-features.h>
 
 struct mm_struct;
 struct vm_area_struct;
@@ -626,6 +627,8 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
 
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
+#define gup_fast_permitted(start, end) (!cpu_has_dc_aliases)
+
 #include <asm-generic/pgtable.h>
 
 /*
index b657861..1e76774 100644 (file)
@@ -56,11 +56,6 @@ static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
        return regs->regs[31];
 }
 
-/*
- * Don't use asm-generic/ptrace.h it defines FP accessors that don't make
- * sense on MIPS.  We rather want an error if they get invoked.
- */
-
 static inline void instruction_pointer_set(struct pt_regs *regs,
                                            unsigned long val)
 {
index bedb504..1804dc9 100644 (file)
@@ -575,10 +575,6 @@ static void *jazz_dma_alloc(struct device *dev, size_t size,
                return NULL;
        }
 
-       if (!(attrs & DMA_ATTR_NON_CONSISTENT)) {
-               dma_cache_wback_inv((unsigned long)ret, size);
-               ret = (void *)UNCAC_ADDR(ret);
-       }
        return ret;
 }
 
@@ -586,8 +582,6 @@ static void jazz_dma_free(struct device *dev, size_t size, void *vaddr,
                dma_addr_t dma_handle, unsigned long attrs)
 {
        vdma_free(dma_handle);
-       if (!(attrs & DMA_ATTR_NON_CONSISTENT))
-               vaddr = (void *)CAC_ADDR((unsigned long)vaddr);
        dma_direct_free_pages(dev, size, vaddr, dma_handle, attrs);
 }
 
index 0369f26..2cfe839 100644 (file)
@@ -123,9 +123,9 @@ int kvm_arch_hardware_setup(void)
        return 0;
 }
 
-void kvm_arch_check_processor_compat(void *rtn)
+int kvm_arch_check_processor_compat(void)
 {
-       *(int *)rtn = 0;
+       return 0;
 }
 
 int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
index f34d7ff..1e8d335 100644 (file)
@@ -7,7 +7,6 @@ obj-y                           += cache.o
 obj-y                          += context.o
 obj-y                          += extable.o
 obj-y                          += fault.o
-obj-y                          += gup.o
 obj-y                          += init.o
 obj-y                          += mmap.o
 obj-y                          += page.o
index 3da2169..33b4093 100644 (file)
@@ -62,8 +62,6 @@ void (*_dma_cache_wback_inv)(unsigned long start, unsigned long size);
 void (*_dma_cache_wback)(unsigned long start, unsigned long size);
 void (*_dma_cache_inv)(unsigned long start, unsigned long size);
 
-EXPORT_SYMBOL(_dma_cache_wback_inv);
-
 #endif /* CONFIG_DMA_NONCOHERENT */
 
 /*
index f9549d2..ed56c6f 100644 (file)
@@ -44,33 +44,25 @@ static inline bool cpu_needs_post_dma_flush(struct device *dev)
        }
 }
 
-void *arch_dma_alloc(struct device *dev, size_t size,
-               dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
+void arch_dma_prep_coherent(struct page *page, size_t size)
 {
-       void *ret;
-
-       ret = dma_direct_alloc_pages(dev, size, dma_handle, gfp, attrs);
-       if (ret && !(attrs & DMA_ATTR_NON_CONSISTENT)) {
-               dma_cache_wback_inv((unsigned long) ret, size);
-               ret = (void *)UNCAC_ADDR(ret);
-       }
+       dma_cache_wback_inv((unsigned long)page_address(page), size);
+}
 
-       return ret;
+void *uncached_kernel_address(void *addr)
+{
+       return (void *)(__pa(addr) + UNCAC_BASE);
 }
 
-void arch_dma_free(struct device *dev, size_t size, void *cpu_addr,
-               dma_addr_t dma_addr, unsigned long attrs)
+void *cached_kernel_address(void *addr)
 {
-       if (!(attrs & DMA_ATTR_NON_CONSISTENT))
-               cpu_addr = (void *)CAC_ADDR((unsigned long)cpu_addr);
-       dma_direct_free_pages(dev, size, cpu_addr, dma_addr, attrs);
+       return __va(addr) - UNCAC_BASE;
 }
 
 long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr,
                dma_addr_t dma_addr)
 {
-       unsigned long addr = CAC_ADDR((unsigned long)cpu_addr);
-       return page_to_pfn(virt_to_page((void *)addr));
+       return page_to_pfn(virt_to_page(cached_kernel_address(cpu_addr)));
 }
 
 pgprot_t arch_dma_mmap_pgprot(struct device *dev, pgprot_t prot,
diff --git a/arch/mips/mm/gup.c b/arch/mips/mm/gup.c
deleted file mode 100644 (file)
index 4c2b448..0000000
+++ /dev/null
@@ -1,303 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Lockless get_user_pages_fast for MIPS
- *
- * Copyright (C) 2008 Nick Piggin
- * Copyright (C) 2008 Novell Inc.
- * Copyright (C) 2011 Ralf Baechle
- */
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/vmstat.h>
-#include <linux/highmem.h>
-#include <linux/swap.h>
-#include <linux/hugetlb.h>
-
-#include <asm/cpu-features.h>
-#include <asm/pgtable.h>
-
-static inline pte_t gup_get_pte(pte_t *ptep)
-{
-#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32)
-       pte_t pte;
-
-retry:
-       pte.pte_low = ptep->pte_low;
-       smp_rmb();
-       pte.pte_high = ptep->pte_high;
-       smp_rmb();
-       if (unlikely(pte.pte_low != ptep->pte_low))
-               goto retry;
-
-       return pte;
-#else
-       return READ_ONCE(*ptep);
-#endif
-}
-
-static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end,
-                       int write, struct page **pages, int *nr)
-{
-       pte_t *ptep = pte_offset_map(&pmd, addr);
-       do {
-               pte_t pte = gup_get_pte(ptep);
-               struct page *page;
-
-               if (!pte_present(pte) ||
-                   pte_special(pte) || (write && !pte_write(pte))) {
-                       pte_unmap(ptep);
-                       return 0;
-               }
-               VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
-               page = pte_page(pte);
-               get_page(page);
-               SetPageReferenced(page);
-               pages[*nr] = page;
-               (*nr)++;
-
-       } while (ptep++, addr += PAGE_SIZE, addr != end);
-
-       pte_unmap(ptep - 1);
-       return 1;
-}
-
-static inline void get_head_page_multiple(struct page *page, int nr)
-{
-       VM_BUG_ON(page != compound_head(page));
-       VM_BUG_ON(page_count(page) == 0);
-       page_ref_add(page, nr);
-       SetPageReferenced(page);
-}
-
-static int gup_huge_pmd(pmd_t pmd, unsigned long addr, unsigned long end,
-                       int write, struct page **pages, int *nr)
-{
-       pte_t pte = *(pte_t *)&pmd;
-       struct page *head, *page;
-       int refs;
-
-       if (write && !pte_write(pte))
-               return 0;
-       /* hugepages are never "special" */
-       VM_BUG_ON(pte_special(pte));
-       VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
-
-       refs = 0;
-       head = pte_page(pte);
-       page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
-       do {
-               VM_BUG_ON(compound_head(page) != head);
-               pages[*nr] = page;
-               (*nr)++;
-               page++;
-               refs++;
-       } while (addr += PAGE_SIZE, addr != end);
-
-       get_head_page_multiple(head, refs);
-       return 1;
-}
-
-static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
-                       int write, struct page **pages, int *nr)
-{
-       unsigned long next;
-       pmd_t *pmdp;
-
-       pmdp = pmd_offset(&pud, addr);
-       do {
-               pmd_t pmd = *pmdp;
-
-               next = pmd_addr_end(addr, end);
-               if (pmd_none(pmd))
-                       return 0;
-               if (unlikely(pmd_huge(pmd))) {
-                       if (!gup_huge_pmd(pmd, addr, next, write, pages,nr))
-                               return 0;
-               } else {
-                       if (!gup_pte_range(pmd, addr, next, write, pages,nr))
-                               return 0;
-               }
-       } while (pmdp++, addr = next, addr != end);
-
-       return 1;
-}
-
-static int gup_huge_pud(pud_t pud, unsigned long addr, unsigned long end,
-                       int write, struct page **pages, int *nr)
-{
-       pte_t pte = *(pte_t *)&pud;
-       struct page *head, *page;
-       int refs;
-
-       if (write && !pte_write(pte))
-               return 0;
-       /* hugepages are never "special" */
-       VM_BUG_ON(pte_special(pte));
-       VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
-
-       refs = 0;
-       head = pte_page(pte);
-       page = head + ((addr & ~PUD_MASK) >> PAGE_SHIFT);
-       do {
-               VM_BUG_ON(compound_head(page) != head);
-               pages[*nr] = page;
-               (*nr)++;
-               page++;
-               refs++;
-       } while (addr += PAGE_SIZE, addr != end);
-
-       get_head_page_multiple(head, refs);
-       return 1;
-}
-
-static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,
-                       int write, struct page **pages, int *nr)
-{
-       unsigned long next;
-       pud_t *pudp;
-
-       pudp = pud_offset(&pgd, addr);
-       do {
-               pud_t pud = *pudp;
-
-               next = pud_addr_end(addr, end);
-               if (pud_none(pud))
-                       return 0;
-               if (unlikely(pud_huge(pud))) {
-                       if (!gup_huge_pud(pud, addr, next, write, pages,nr))
-                               return 0;
-               } else {
-                       if (!gup_pmd_range(pud, addr, next, write, pages,nr))
-                               return 0;
-               }
-       } while (pudp++, addr = next, addr != end);
-
-       return 1;
-}
-
-/*
- * Like get_user_pages_fast() except its IRQ-safe in that it won't fall
- * back to the regular GUP.
- * Note a difference with get_user_pages_fast: this always returns the
- * number of pages pinned, 0 if no pages were pinned.
- */
-int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
-                         struct page **pages)
-{
-       struct mm_struct *mm = current->mm;
-       unsigned long addr, len, end;
-       unsigned long next;
-       unsigned long flags;
-       pgd_t *pgdp;
-       int nr = 0;
-
-       start &= PAGE_MASK;
-       addr = start;
-       len = (unsigned long) nr_pages << PAGE_SHIFT;
-       end = start + len;
-       if (unlikely(!access_ok((void __user *)start, len)))
-               return 0;
-
-       /*
-        * XXX: batch / limit 'nr', to avoid large irq off latency
-        * needs some instrumenting to determine the common sizes used by
-        * important workloads (eg. DB2), and whether limiting the batch
-        * size will decrease performance.
-        *
-        * It seems like we're in the clear for the moment. Direct-IO is
-        * the main guy that batches up lots of get_user_pages, and even
-        * they are limited to 64-at-a-time which is not so many.
-        */
-       /*
-        * This doesn't prevent pagetable teardown, but does prevent
-        * the pagetables and pages from being freed.
-        *
-        * So long as we atomically load page table pointers versus teardown,
-        * we can follow the address down to the page and take a ref on it.
-        */
-       local_irq_save(flags);
-       pgdp = pgd_offset(mm, addr);
-       do {
-               pgd_t pgd = *pgdp;
-
-               next = pgd_addr_end(addr, end);
-               if (pgd_none(pgd))
-                       break;
-               if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
-                       break;
-       } while (pgdp++, addr = next, addr != end);
-       local_irq_restore(flags);
-
-       return nr;
-}
-
-/**
- * get_user_pages_fast() - pin user pages in memory
- * @start:     starting user address
- * @nr_pages:  number of pages from start to pin
- * @gup_flags: flags modifying pin behaviour
- * @pages:     array that receives pointers to the pages pinned.
- *             Should be at least nr_pages long.
- *
- * Attempt to pin user pages in memory without taking mm->mmap_sem.
- * If not successful, it will fall back to taking the lock and
- * calling get_user_pages().
- *
- * Returns number of pages pinned. This may be fewer than the number
- * requested. If nr_pages is 0 or negative, returns 0. If no pages
- * were pinned, returns -errno.
- */
-int get_user_pages_fast(unsigned long start, int nr_pages,
-                       unsigned int gup_flags, struct page **pages)
-{
-       struct mm_struct *mm = current->mm;
-       unsigned long addr, len, end;
-       unsigned long next;
-       pgd_t *pgdp;
-       int ret, nr = 0;
-
-       start &= PAGE_MASK;
-       addr = start;
-       len = (unsigned long) nr_pages << PAGE_SHIFT;
-
-       end = start + len;
-       if (end < start || cpu_has_dc_aliases)
-               goto slow_irqon;
-
-       /* XXX: batch / limit 'nr' */
-       local_irq_disable();
-       pgdp = pgd_offset(mm, addr);
-       do {
-               pgd_t pgd = *pgdp;
-
-               next = pgd_addr_end(addr, end);
-               if (pgd_none(pgd))
-                       goto slow;
-               if (!gup_pud_range(pgd, addr, next, gup_flags & FOLL_WRITE,
-                                  pages, &nr))
-                       goto slow;
-       } while (pgdp++, addr = next, addr != end);
-       local_irq_enable();
-
-       VM_BUG_ON(nr != (end - start) >> PAGE_SHIFT);
-       return nr;
-slow:
-       local_irq_enable();
-
-slow_irqon:
-       /* Try to get the remaining pages with get_user_pages */
-       start += nr << PAGE_SHIFT;
-       pages += nr;
-
-       ret = get_user_pages_unlocked(start, (end - start) >> PAGE_SHIFT,
-                                     pages, gup_flags);
-
-       /* Have to be a bit careful with return values */
-       if (nr > 0) {
-               if (ret < 0)
-                       ret = nr;
-               else
-                       ret += nr;
-       }
-       return ret;
-}
index fd0d063..fbd6832 100644 (file)
@@ -7,12 +7,14 @@
 config NDS32
        def_bool y
        select ARCH_32BIT_OFF_T
+       select ARCH_HAS_DMA_PREP_COHERENT
        select ARCH_HAS_SYNC_DMA_FOR_CPU
        select ARCH_HAS_SYNC_DMA_FOR_DEVICE
        select ARCH_WANT_FRAME_POINTERS if FTRACE
        select CLKSRC_MMIO
        select CLONE_BACKWARDS
        select COMMON_CLK
+       select DMA_DIRECT_REMAP
        select GENERIC_ATOMIC64
        select GENERIC_CPU_DEVICES
        select GENERIC_CLOCKEVENTS
index 14dab5a..ccdca71 100644 (file)
@@ -2,8 +2,6 @@
 LDFLAGS_vmlinux        := --no-undefined -X
 OBJCOPYFLAGS   := -O binary -R .note -R .note.gnu.build-id -R .comment -S
 
-KBUILD_DEFCONFIG := defconfig
-
 ifdef CONFIG_FUNCTION_TRACER
 arch-y += -malways-save-lp -mno-relax
 endif
index 65ce925..40313a6 100644 (file)
@@ -92,6 +92,7 @@ CONFIG_DEBUG_INFO=y
 CONFIG_DEBUG_INFO_DWARF4=y
 CONFIG_GDB_SCRIPTS=y
 CONFIG_READABLE_ASM=y
+CONFIG_HEADERS_INSTALL=y
 CONFIG_HEADERS_CHECK=y
 CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_MAGIC_SYSRQ=y
index 3cbc749..e78b43d 100644 (file)
@@ -9,6 +9,9 @@
 #include <asm/tlbflush.h>
 #include <asm/proc-fns.h>
 
+#define __HAVE_ARCH_PTE_ALLOC_ONE
+#include <asm-generic/pgalloc.h>       /* for pte_{alloc,free}_one */
+
 /*
  * Since we have only two-level page tables, these are trivial
  */
@@ -22,43 +25,17 @@ extern void pgd_free(struct mm_struct *mm, pgd_t * pgd);
 
 #define check_pgt_cache()              do { } while (0)
 
-static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm)
-{
-       pte_t *pte;
-
-       pte =
-           (pte_t *) __get_free_page(GFP_KERNEL | __GFP_RETRY_MAYFAIL |
-                                     __GFP_ZERO);
-
-       return pte;
-}
-
 static inline pgtable_t pte_alloc_one(struct mm_struct *mm)
 {
        pgtable_t pte;
 
-       pte = alloc_pages(GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_ZERO, 0);
+       pte = __pte_alloc_one(mm, GFP_PGTABLE_USER);
        if (pte)
                cpu_dcache_wb_page((unsigned long)page_address(pte));
 
        return pte;
 }
 
-/*
- * Free one PTE table.
- */
-static inline void pte_free_kernel(struct mm_struct *mm, pte_t * pte)
-{
-       if (pte) {
-               free_page((unsigned long)pte);
-       }
-}
-
-static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
-{
-       __free_page(pte);
-}
-
 /*
  * Populate the pmdp entry with a pointer to the pte.  This pmd is part
  * of the mm address space.
index d0dbd4f..490e372 100644 (file)
 
 #include <linux/types.h>
 #include <linux/mm.h>
-#include <linux/string.h>
 #include <linux/dma-noncoherent.h>
-#include <linux/io.h>
 #include <linux/cache.h>
 #include <linux/highmem.h>
-#include <linux/slab.h>
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 #include <asm/proc-fns.h>
 
-/*
- * This is the page table (2MB) covering uncached, DMA consistent allocations
- */
-static pte_t *consistent_pte;
-static DEFINE_RAW_SPINLOCK(consistent_lock);
-
-/*
- * VM region handling support.
- *
- * This should become something generic, handling VM region allocations for
- * vmalloc and similar (ioremap, module space, etc).
- *
- * I envisage vmalloc()'s supporting vm_struct becoming:
- *
- *  struct vm_struct {
- *    struct vm_region region;
- *    unsigned long    flags;
- *    struct page      **pages;
- *    unsigned int     nr_pages;
- *    unsigned long    phys_addr;
- *  };
- *
- * get_vm_area() would then call vm_region_alloc with an appropriate
- * struct vm_region head (eg):
- *
- *  struct vm_region vmalloc_head = {
- *     .vm_list        = LIST_HEAD_INIT(vmalloc_head.vm_list),
- *     .vm_start       = VMALLOC_START,
- *     .vm_end         = VMALLOC_END,
- *  };
- *
- * However, vmalloc_head.vm_start is variable (typically, it is dependent on
- * the amount of RAM found at boot time.)  I would imagine that get_vm_area()
- * would have to initialise this each time prior to calling vm_region_alloc().
- */
-struct arch_vm_region {
-       struct list_head vm_list;
-       unsigned long vm_start;
-       unsigned long vm_end;
-       struct page *vm_pages;
-};
-
-static struct arch_vm_region consistent_head = {
-       .vm_list = LIST_HEAD_INIT(consistent_head.vm_list),
-       .vm_start = CONSISTENT_BASE,
-       .vm_end = CONSISTENT_END,
-};
-
-static struct arch_vm_region *vm_region_alloc(struct arch_vm_region *head,
-                                             size_t size, int gfp)
-{
-       unsigned long addr = head->vm_start, end = head->vm_end - size;
-       unsigned long flags;
-       struct arch_vm_region *c, *new;
-
-       new = kmalloc(sizeof(struct arch_vm_region), gfp);
-       if (!new)
-               goto out;
-
-       raw_spin_lock_irqsave(&consistent_lock, flags);
-
-       list_for_each_entry(c, &head->vm_list, vm_list) {
-               if ((addr + size) < addr)
-                       goto nospc;
-               if ((addr + size) <= c->vm_start)
-                       goto found;
-               addr = c->vm_end;
-               if (addr > end)
-                       goto nospc;
-       }
-
-found:
-       /*
-        * Insert this entry _before_ the one we found.
-        */
-       list_add_tail(&new->vm_list, &c->vm_list);
-       new->vm_start = addr;
-       new->vm_end = addr + size;
-
-       raw_spin_unlock_irqrestore(&consistent_lock, flags);
-       return new;
-
-nospc:
-       raw_spin_unlock_irqrestore(&consistent_lock, flags);
-       kfree(new);
-out:
-       return NULL;
-}
-
-static struct arch_vm_region *vm_region_find(struct arch_vm_region *head,
-                                            unsigned long addr)
-{
-       struct arch_vm_region *c;
-
-       list_for_each_entry(c, &head->vm_list, vm_list) {
-               if (c->vm_start == addr)
-                       goto out;
-       }
-       c = NULL;
-out:
-       return c;
-}
-
-void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
-               gfp_t gfp, unsigned long attrs)
-{
-       struct page *page;
-       struct arch_vm_region *c;
-       unsigned long order;
-       u64 mask = ~0ULL, limit;
-       pgprot_t prot = pgprot_noncached(PAGE_KERNEL);
-
-       if (!consistent_pte) {
-               pr_err("%s: not initialized\n", __func__);
-               dump_stack();
-               return NULL;
-       }
-
-       if (dev) {
-               mask = dev->coherent_dma_mask;
-
-               /*
-                * Sanity check the DMA mask - it must be non-zero, and
-                * must be able to be satisfied by a DMA allocation.
-                */
-               if (mask == 0) {
-                       dev_warn(dev, "coherent DMA mask is unset\n");
-                       goto no_page;
-               }
-
-       }
-
-       /*
-        * Sanity check the allocation size.
-        */
-       size = PAGE_ALIGN(size);
-       limit = (mask + 1) & ~mask;
-       if ((limit && size >= limit) ||
-           size >= (CONSISTENT_END - CONSISTENT_BASE)) {
-               pr_warn("coherent allocation too big "
-                       "(requested %#x mask %#llx)\n", size, mask);
-               goto no_page;
-       }
-
-       order = get_order(size);
-
-       if (mask != 0xffffffff)
-               gfp |= GFP_DMA;
-
-       page = alloc_pages(gfp, order);
-       if (!page)
-               goto no_page;
-
-       /*
-        * Invalidate any data that might be lurking in the
-        * kernel direct-mapped region for device DMA.
-        */
-       {
-               unsigned long kaddr = (unsigned long)page_address(page);
-               memset(page_address(page), 0, size);
-               cpu_dma_wbinval_range(kaddr, kaddr + size);
-       }
-
-       /*
-        * Allocate a virtual address in the consistent mapping region.
-        */
-       c = vm_region_alloc(&consistent_head, size,
-                           gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
-       if (c) {
-               pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
-               struct page *end = page + (1 << order);
-
-               c->vm_pages = page;
-
-               /*
-                * Set the "dma handle"
-                */
-               *handle = page_to_phys(page);
-
-               do {
-                       BUG_ON(!pte_none(*pte));
-
-                       /*
-                        * x86 does not mark the pages reserved...
-                        */
-                       SetPageReserved(page);
-                       set_pte(pte, mk_pte(page, prot));
-                       page++;
-                       pte++;
-               } while (size -= PAGE_SIZE);
-
-               /*
-                * Free the otherwise unused pages.
-                */
-               while (page < end) {
-                       __free_page(page);
-                       page++;
-               }
-
-               return (void *)c->vm_start;
-       }
-
-       if (page)
-               __free_pages(page, order);
-no_page:
-       *handle = ~0;
-       return NULL;
-}
-
-void arch_dma_free(struct device *dev, size_t size, void *cpu_addr,
-               dma_addr_t handle, unsigned long attrs)
-{
-       struct arch_vm_region *c;
-       unsigned long flags, addr;
-       pte_t *ptep;
-
-       size = PAGE_ALIGN(size);
-
-       raw_spin_lock_irqsave(&consistent_lock, flags);
-
-       c = vm_region_find(&consistent_head, (unsigned long)cpu_addr);
-       if (!c)
-               goto no_area;
-
-       if ((c->vm_end - c->vm_start) != size) {
-               pr_err("%s: freeing wrong coherent size (%ld != %d)\n",
-                      __func__, c->vm_end - c->vm_start, size);
-               dump_stack();
-               size = c->vm_end - c->vm_start;
-       }
-
-       ptep = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
-       addr = c->vm_start;
-       do {
-               pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep);
-               unsigned long pfn;
-
-               ptep++;
-               addr += PAGE_SIZE;
-
-               if (!pte_none(pte) && pte_present(pte)) {
-                       pfn = pte_pfn(pte);
-
-                       if (pfn_valid(pfn)) {
-                               struct page *page = pfn_to_page(pfn);
-
-                               /*
-                                * x86 does not mark the pages reserved...
-                                */
-                               ClearPageReserved(page);
-
-                               __free_page(page);
-                               continue;
-                       }
-               }
-
-               pr_crit("%s: bad page in kernel page table\n", __func__);
-       } while (size -= PAGE_SIZE);
-
-       flush_tlb_kernel_range(c->vm_start, c->vm_end);
-
-       list_del(&c->vm_list);
-
-       raw_spin_unlock_irqrestore(&consistent_lock, flags);
-
-       kfree(c);
-       return;
-
-no_area:
-       raw_spin_unlock_irqrestore(&consistent_lock, flags);
-       pr_err("%s: trying to free invalid coherent area: %p\n",
-              __func__, cpu_addr);
-       dump_stack();
-}
-
-/*
- * Initialise the consistent memory allocation.
- */
-static int __init consistent_init(void)
-{
-       pgd_t *pgd;
-       pmd_t *pmd;
-       pte_t *pte;
-       int ret = 0;
-
-       do {
-               pgd = pgd_offset(&init_mm, CONSISTENT_BASE);
-               pmd = pmd_alloc(&init_mm, pgd, CONSISTENT_BASE);
-               if (!pmd) {
-                       pr_err("%s: no pmd tables\n", __func__);
-                       ret = -ENOMEM;
-                       break;
-               }
-               /* The first level mapping may be created in somewhere.
-                * It's not necessary to warn here. */
-               /* WARN_ON(!pmd_none(*pmd)); */
-
-               pte = pte_alloc_kernel(pmd, CONSISTENT_BASE);
-               if (!pte) {
-                       ret = -ENOMEM;
-                       break;
-               }
-
-               consistent_pte = pte;
-       } while (0);
-
-       return ret;
-}
-
-core_initcall(consistent_init);
-
 static inline void cache_op(phys_addr_t paddr, size_t size,
                void (*fn)(unsigned long start, unsigned long end))
 {
@@ -389,3 +75,14 @@ void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
                BUG();
        }
 }
+
+void arch_dma_prep_coherent(struct page *page, size_t size)
+{
+       cache_op(page_to_phys(page), size, cpu_dma_wbinval_range);
+}
+
+static int __init atomic_pool_init(void)
+{
+       return dma_atomic_pool_init(GFP_KERNEL, pgprot_noncached(PAGE_KERNEL));
+}
+postcore_initcall(atomic_pool_init);
index 26a9c76..44b5da3 100644 (file)
@@ -4,6 +4,7 @@ config NIOS2
        select ARCH_32BIT_OFF_T
        select ARCH_HAS_SYNC_DMA_FOR_CPU
        select ARCH_HAS_SYNC_DMA_FOR_DEVICE
+       select ARCH_HAS_UNCACHED_SEGMENT
        select ARCH_NO_SWAP
        select TIMER_OF
        select GENERIC_ATOMIC64
index f1da8a7..a8bc06e 100644 (file)
@@ -1,8 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 
-config TRACE_IRQFLAGS_SUPPORT
-       def_bool y
-
 config EARLY_PRINTK
        bool "Activate early kernel debugging"
        default y
index 7977ab7..1137ef2 100644 (file)
@@ -35,7 +35,6 @@ CONFIG_IP_PNP_RARP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_FW_LOADER is not set
index ceb97cd..a0f160b 100644 (file)
@@ -37,7 +37,6 @@ CONFIG_IP_PNP_RARP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_FW_LOADER is not set
index f1fbdc4..79fcac6 100644 (file)
@@ -101,12 +101,6 @@ static inline bool pfn_valid(unsigned long pfn)
 # define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \
                                 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
-# define UNCAC_ADDR(addr)      \
-       ((void *)((unsigned)(addr) | CONFIG_NIOS2_IO_REGION_BASE))
-# define CAC_ADDR(addr)                \
-       ((void *)(((unsigned)(addr) & ~CONFIG_NIOS2_IO_REGION_BASE) |   \
-               CONFIG_NIOS2_KERNEL_REGION_BASE))
-
 #include <asm-generic/memory_model.h>
 
 #include <asm-generic/getorder.h>
index 3a149ea..4bc8cf7 100644 (file)
@@ -12,6 +12,8 @@
 
 #include <linux/mm.h>
 
+#include <asm-generic/pgalloc.h>       /* for pte_{alloc,free}_one */
+
 static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
        pte_t *pte)
 {
@@ -37,41 +39,6 @@ static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
        free_pages((unsigned long)pgd, PGD_ORDER);
 }
 
-static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm)
-{
-       pte_t *pte;
-
-       pte = (pte_t *) __get_free_pages(GFP_KERNEL|__GFP_ZERO, PTE_ORDER);
-
-       return pte;
-}
-
-static inline pgtable_t pte_alloc_one(struct mm_struct *mm)
-{
-       struct page *pte;
-
-       pte = alloc_pages(GFP_KERNEL, PTE_ORDER);
-       if (pte) {
-               if (!pgtable_page_ctor(pte)) {
-                       __free_page(pte);
-                       return NULL;
-               }
-               clear_highpage(pte);
-       }
-       return pte;
-}
-
-static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
-{
-       free_pages((unsigned long)pte, PTE_ORDER);
-}
-
-static inline void pte_free(struct mm_struct *mm, struct page *pte)
-{
-       pgtable_page_dtor(pte);
-       __free_pages(pte, PTE_ORDER);
-}
-
 #define __pte_free_tlb(tlb, pte, addr)                         \
        do {                                                    \
                pgtable_page_dtor(pte);                         \
index 4af9e5b..9cb2386 100644 (file)
@@ -60,32 +60,28 @@ void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
        }
 }
 
-void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
-               gfp_t gfp, unsigned long attrs)
+void arch_dma_prep_coherent(struct page *page, size_t size)
 {
-       void *ret;
+       unsigned long start = (unsigned long)page_address(page);
 
-       /* optimized page clearing */
-       gfp |= __GFP_ZERO;
+       flush_dcache_range(start, start + size);
+}
 
-       if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
-               gfp |= GFP_DMA;
+void *uncached_kernel_address(void *ptr)
+{
+       unsigned long addr = (unsigned long)ptr;
 
-       ret = (void *) __get_free_pages(gfp, get_order(size));
-       if (ret != NULL) {
-               *dma_handle = virt_to_phys(ret);
-               flush_dcache_range((unsigned long) ret,
-                       (unsigned long) ret + size);
-               ret = UNCAC_ADDR(ret);
-       }
+       addr |= CONFIG_NIOS2_IO_REGION_BASE;
 
-       return ret;
+       return (void *)ptr;
 }
 
-void arch_dma_free(struct device *dev, size_t size, void *vaddr,
-               dma_addr_t dma_handle, unsigned long attrs)
+void *cached_kernel_address(void *ptr)
 {
-       unsigned long addr = (unsigned long) CAC_ADDR((unsigned long) vaddr);
+       unsigned long addr = (unsigned long)ptr;
+
+       addr &= ~CONFIG_NIOS2_IO_REGION_BASE;
+       addr |= CONFIG_NIOS2_KERNEL_REGION_BASE;
 
-       free_pages(addr, get_order(size));
+       return (void *)ptr;
 }
index 43e340c..b41a79f 100644 (file)
@@ -94,15 +94,13 @@ arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
 
        va = (unsigned long)page;
 
-       if ((attrs & DMA_ATTR_NON_CONSISTENT) == 0) {
-               /*
-                * We need to iterate through the pages, clearing the dcache for
-                * them and setting the cache-inhibit bit.
-                */
-               if (walk_page_range(va, va + size, &walk)) {
-                       free_pages_exact(page, size);
-                       return NULL;
-               }
+       /*
+        * We need to iterate through the pages, clearing the dcache for
+        * them and setting the cache-inhibit bit.
+        */
+       if (walk_page_range(va, va + size, &walk)) {
+               free_pages_exact(page, size);
+               return NULL;
        }
 
        return (void *)va;
@@ -118,10 +116,8 @@ arch_dma_free(struct device *dev, size_t size, void *vaddr,
                .mm = &init_mm
        };
 
-       if ((attrs & DMA_ATTR_NON_CONSISTENT) == 0) {
-               /* walk_page_range shouldn't be able to fail here */
-               WARN_ON(walk_page_range(va, va + size, &walk));
-       }
+       /* walk_page_range shouldn't be able to fail here */
+       WARN_ON(walk_page_range(va, va + size, &walk));
 
        free_pages_exact(vaddr, size);
 }
index 58d4666..8acb8fa 100644 (file)
@@ -120,8 +120,8 @@ PALO := $(shell if (which palo 2>&1); then : ; \
        elif [ -x /sbin/palo ]; then echo /sbin/palo; \
        fi)
 
-PALOCONF := $(shell if [ -f $(src)/palo.conf ]; then echo $(src)/palo.conf; \
-       else echo $(obj)/palo.conf; \
+PALOCONF := $(shell if [ -f $(srctree)/palo.conf ]; then echo $(srctree)/palo.conf; \
+       else echo $(objtree)/palo.conf; \
        fi)
 
 palo lifimage: vmlinuz
@@ -131,8 +131,8 @@ palo lifimage: vmlinuz
                false; \
        fi
        @if test ! -f "$(PALOCONF)"; then \
-               cp $(src)/arch/parisc/defpalo.conf $(obj)/palo.conf; \
-               echo 'A generic palo config file ($(obj)/palo.conf) has been created for you.'; \
+               cp $(srctree)/arch/parisc/defpalo.conf $(objtree)/palo.conf; \
+               echo 'A generic palo config file ($(objree)/palo.conf) has been created for you.'; \
                echo 'You should check it and re-run "make palo".'; \
                echo 'WARNING: the "lifimage" file is now placed in this directory by default!'; \
                false; \
@@ -162,10 +162,10 @@ vmlinuz: vmlinux
 endif
 
 install:
-       $(CONFIG_SHELL) $(src)/arch/parisc/install.sh \
+       $(CONFIG_SHELL) $(srctree)/arch/parisc/install.sh \
                        $(KERNELRELEASE) vmlinux System.map "$(INSTALL_PATH)"
 zinstall:
-       $(CONFIG_SHELL) $(src)/arch/parisc/install.sh \
+       $(CONFIG_SHELL) $(srctree)/arch/parisc/install.sh \
                        $(KERNELRELEASE) vmlinuz System.map "$(INSTALL_PATH)"
 
 CLEAN_FILES    += lifimage
index a885949..3335734 100644 (file)
@@ -166,6 +166,7 @@ CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_ISO8859_15=m
 CONFIG_NLS_UTF8=m
 CONFIG_DEBUG_FS=y
+CONFIG_HEADERS_INSTALL=y
 CONFIG_HEADERS_CHECK=y
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_DEBUG_BUGVERBOSE is not set
index 0cae966..07fde5b 100644 (file)
@@ -90,6 +90,7 @@ CONFIG_NLS_ASCII=m
 CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_ISO8859_15=m
 CONFIG_NLS_UTF8=m
+CONFIG_HEADERS_INSTALL=y
 CONFIG_HEADERS_CHECK=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
index 6c29b84..64d45a8 100644 (file)
@@ -139,6 +139,7 @@ CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_ISO8859_15=m
 CONFIG_NLS_UTF8=m
 CONFIG_DEBUG_FS=y
+CONFIG_HEADERS_INSTALL=y
 CONFIG_HEADERS_CHECK=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_MUTEXES=y
index 6a91cc2..5b877ca 100644 (file)
@@ -183,6 +183,7 @@ CONFIG_NLS_KOI8_R=m
 CONFIG_NLS_KOI8_U=m
 CONFIG_NLS_UTF8=y
 CONFIG_DEBUG_FS=y
+CONFIG_HEADERS_INSTALL=y
 CONFIG_HEADERS_CHECK=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
index ea75cc9..4f2059a 100644 (file)
@@ -10,6 +10,8 @@
 
 #include <asm/cache.h>
 
+#include <asm-generic/pgalloc.h>       /* for pte_{alloc,free}_one */
+
 /* Allocate the top level pgd (page directory)
  *
  * Here (for 64 bit kernels) we implement a Hybrid L2/L3 scheme: we
@@ -122,37 +124,6 @@ pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
        pmd_populate_kernel(mm, pmd, page_address(pte_page))
 #define pmd_pgtable(pmd) pmd_page(pmd)
 
-static inline pgtable_t
-pte_alloc_one(struct mm_struct *mm)
-{
-       struct page *page = alloc_page(GFP_KERNEL|__GFP_ZERO);
-       if (!page)
-               return NULL;
-       if (!pgtable_page_ctor(page)) {
-               __free_page(page);
-               return NULL;
-       }
-       return page;
-}
-
-static inline pte_t *
-pte_alloc_one_kernel(struct mm_struct *mm)
-{
-       pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_ZERO);
-       return pte;
-}
-
-static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
-{
-       free_page((unsigned long)pte);
-}
-
-static inline void pte_free(struct mm_struct *mm, struct page *pte)
-{
-       pgtable_page_dtor(pte);
-       pte_free_kernel(mm, page_address(pte));
-}
-
 #define check_pgt_cache()      do { } while (0)
 
 #endif
index 2391623..ca35d9a 100644 (file)
@@ -394,17 +394,20 @@ pcxl_dma_init(void)
 
 __initcall(pcxl_dma_init);
 
-static void *pcxl_dma_alloc(struct device *dev, size_t size,
-               dma_addr_t *dma_handle, gfp_t flag, unsigned long attrs)
+void *arch_dma_alloc(struct device *dev, size_t size,
+               dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
 {
        unsigned long vaddr;
        unsigned long paddr;
        int order;
 
+       if (boot_cpu_data.cpu_type != pcxl2 && boot_cpu_data.cpu_type != pcxl)
+               return NULL;
+
        order = get_order(size);
        size = 1 << (order + PAGE_SHIFT);
        vaddr = pcxl_alloc_range(size);
-       paddr = __get_free_pages(flag | __GFP_ZERO, order);
+       paddr = __get_free_pages(gfp | __GFP_ZERO, order);
        flush_kernel_dcache_range(paddr, size);
        paddr = __pa(paddr);
        map_uncached_pages(vaddr, size, paddr);
@@ -421,44 +424,19 @@ static void *pcxl_dma_alloc(struct device *dev, size_t size,
        return (void *)vaddr;
 }
 
-static void *pcx_dma_alloc(struct device *dev, size_t size,
-               dma_addr_t *dma_handle, gfp_t flag, unsigned long attrs)
-{
-       void *addr;
-
-       if ((attrs & DMA_ATTR_NON_CONSISTENT) == 0)
-               return NULL;
-
-       addr = (void *)__get_free_pages(flag | __GFP_ZERO, get_order(size));
-       if (addr)
-               *dma_handle = (dma_addr_t)virt_to_phys(addr);
-
-       return addr;
-}
-
-void *arch_dma_alloc(struct device *dev, size_t size,
-               dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
-{
-
-       if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl)
-               return pcxl_dma_alloc(dev, size, dma_handle, gfp, attrs);
-       else
-               return pcx_dma_alloc(dev, size, dma_handle, gfp, attrs);
-}
-
 void arch_dma_free(struct device *dev, size_t size, void *vaddr,
                dma_addr_t dma_handle, unsigned long attrs)
 {
        int order = get_order(size);
 
-       if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) {
-               size = 1 << (order + PAGE_SHIFT);
-               unmap_uncached_pages((unsigned long)vaddr, size);
-               pcxl_free_range((unsigned long)vaddr, size);
+       WARN_ON_ONCE(boot_cpu_data.cpu_type != pcxl2 &&
+                    boot_cpu_data.cpu_type != pcxl);
 
-               vaddr = __va(dma_handle);
-       }
-       free_pages((unsigned long)vaddr, get_order(size));
+       size = 1 << (order + PAGE_SHIFT);
+       unmap_uncached_pages((unsigned long)vaddr, size);
+       pcxl_free_range((unsigned long)vaddr, size);
+
+       free_pages((unsigned long)__va(dma_handle), order);
 }
 
 void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
index 3b795a0..24a41f9 100644 (file)
@@ -125,6 +125,7 @@ config PPC
        select ARCH_HAS_FORTIFY_SOURCE
        select ARCH_HAS_GCOV_PROFILE_ALL
        select ARCH_HAS_KCOV
+       select ARCH_HAS_HUGEPD                  if HUGETLB_PAGE
        select ARCH_HAS_MMIOWB                  if PPC64
        select ARCH_HAS_PHYS_TO_DMA
        select ARCH_HAS_PMEM_API                if PPC64
@@ -185,12 +186,12 @@ config PPC
        select HAVE_DYNAMIC_FTRACE_WITH_REGS    if MPROFILE_KERNEL
        select HAVE_EBPF_JIT                    if PPC64
        select HAVE_EFFICIENT_UNALIGNED_ACCESS  if !(CPU_LITTLE_ENDIAN && POWER7_CPU)
+       select HAVE_FAST_GUP
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_FUNCTION_ERROR_INJECTION
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_FUNCTION_TRACER
        select HAVE_GCC_PLUGINS                 if GCC_VERSION >= 50200   # plugin support on gcc <= 5.1 is buggy on PPC
-       select HAVE_GENERIC_GUP
        select HAVE_HW_BREAKPOINT               if PERF_EVENTS && (PPC_BOOK3S || PPC_8xx)
        select HAVE_IDE
        select HAVE_IOREMAP_PROT
index aa51b9b..1c074fb 100644 (file)
@@ -1123,6 +1123,7 @@ CONFIG_NLS_KOI8_R=m
 CONFIG_NLS_KOI8_U=m
 CONFIG_DEBUG_INFO=y
 CONFIG_UNUSED_SYMBOLS=y
+CONFIG_HEADERS_INSTALL=y
 CONFIG_HEADERS_CHECK=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
index 3f53be6..6414575 100644 (file)
@@ -140,6 +140,20 @@ static inline void pte_frag_set(mm_context_t *ctx, void *p)
 }
 #endif
 
+#ifdef CONFIG_PPC64
+#define is_ioremap_addr is_ioremap_addr
+static inline bool is_ioremap_addr(const void *x)
+{
+#ifdef CONFIG_MMU
+       unsigned long addr = (unsigned long)x;
+
+       return addr >= IOREMAP_BASE && addr < IOREMAP_END;
+#else
+       return false;
+#endif
+}
+#endif /* CONFIG_PPC64 */
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_POWERPC_PGTABLE_H */
index faa5a33..feee1b2 100644 (file)
@@ -111,18 +111,33 @@ struct pt_regs
 
 #ifndef __ASSEMBLY__
 
-#define GET_IP(regs)           ((regs)->nip)
-#define GET_USP(regs)          ((regs)->gpr[1])
-#define GET_FP(regs)           (0)
-#define SET_FP(regs, val)
+static inline unsigned long instruction_pointer(struct pt_regs *regs)
+{
+       return regs->nip;
+}
+
+static inline void instruction_pointer_set(struct pt_regs *regs,
+               unsigned long val)
+{
+       regs->nip = val;
+}
+
+static inline unsigned long user_stack_pointer(struct pt_regs *regs)
+{
+       return regs->gpr[1];
+}
+
+static inline unsigned long frame_pointer(struct pt_regs *regs)
+{
+       return 0;
+}
 
 #ifdef CONFIG_SMP
 extern unsigned long profile_pc(struct pt_regs *regs);
-#define profile_pc profile_pc
+#else
+#define profile_pc(regs) instruction_pointer(regs)
 #endif
 
-#include <asm-generic/ptrace.h>
-
 #define kernel_stack_pointer(regs) ((regs)->gpr[1])
 static inline int is_syscall_success(struct pt_regs *regs)
 {
index e827616..381bf8d 100644 (file)
@@ -827,7 +827,7 @@ static noinline int kvmppc_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr)
         *
         * Note: If EOI is incorrectly used by SW to lower the CPPR
         * value (ie more favored), we do not check for rejection of
-        * a pending interrupt, this is a SW error and PAPR sepcifies
+        * a pending interrupt, this is a SW error and PAPR specifies
         * that we don't have to deal with it.
         *
         * The sending of an EOI to the ICS is handled after the
index 6d704ad..0dba7eb 100644 (file)
@@ -414,9 +414,9 @@ int kvm_arch_hardware_setup(void)
        return 0;
 }
 
-void kvm_arch_check_processor_compat(void *rtn)
+int kvm_arch_check_processor_compat(void)
 {
-       *(int *)rtn = kvmppc_core_check_processor_compat();
+       return kvmppc_core_check_processor_compat();
 }
 
 int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
index bb98356..ce8a77f 100644 (file)
@@ -666,6 +666,11 @@ EXPORT_SYMBOL(radix__flush_tlb_page);
 #define radix__flush_all_mm radix__local_flush_all_mm
 #endif /* CONFIG_SMP */
 
+/*
+ * If kernel TLBIs ever become local rather than global, then
+ * drivers/misc/ocxl/link.c:ocxl_link_add_pe will need some work, as it
+ * assumes kernel TLBIs are global.
+ */
 void radix__flush_tlb_kernel_range(unsigned long start, unsigned long end)
 {
        _tlbie_pid(0, RIC_FLUSH_ALL);
index b5d92dc..51716c1 100644 (file)
@@ -511,13 +511,6 @@ retry:
        return page;
 }
 
-static unsigned long hugepte_addr_end(unsigned long addr, unsigned long end,
-                                     unsigned long sz)
-{
-       unsigned long __boundary = (addr + sz) & ~(sz-1);
-       return (__boundary - 1 < end - 1) ? __boundary : end;
-}
-
 #ifdef CONFIG_PPC_MM_SLICES
 unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
                                        unsigned long len, unsigned long pgoff,
@@ -665,68 +658,3 @@ void flush_dcache_icache_hugepage(struct page *page)
                }
        }
 }
-
-static int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,
-                      unsigned long end, int write, struct page **pages, int *nr)
-{
-       unsigned long pte_end;
-       struct page *head, *page;
-       pte_t pte;
-       int refs;
-
-       pte_end = (addr + sz) & ~(sz-1);
-       if (pte_end < end)
-               end = pte_end;
-
-       pte = READ_ONCE(*ptep);
-
-       if (!pte_access_permitted(pte, write))
-               return 0;
-
-       /* hugepages are never "special" */
-       VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
-
-       refs = 0;
-       head = pte_page(pte);
-
-       page = head + ((addr & (sz-1)) >> PAGE_SHIFT);
-       do {
-               VM_BUG_ON(compound_head(page) != head);
-               pages[*nr] = page;
-               (*nr)++;
-               page++;
-               refs++;
-       } while (addr += PAGE_SIZE, addr != end);
-
-       if (!page_cache_add_speculative(head, refs)) {
-               *nr -= refs;
-               return 0;
-       }
-
-       if (unlikely(pte_val(pte) != pte_val(*ptep))) {
-               /* Could be optimized better */
-               *nr -= refs;
-               while (refs--)
-                       put_page(head);
-               return 0;
-       }
-
-       return 1;
-}
-
-int gup_huge_pd(hugepd_t hugepd, unsigned long addr, unsigned int pdshift,
-               unsigned long end, int write, struct page **pages, int *nr)
-{
-       pte_t *ptep;
-       unsigned long sz = 1UL << hugepd_shift(hugepd);
-       unsigned long next;
-
-       ptep = hugepte_offset(hugepd, addr, pdshift);
-       do {
-               next = hugepte_addr_end(addr, end, sz);
-               if (!gup_hugepte(ptep, sz, addr, end, write, pages, nr))
-                       return 0;
-       } while (ptep++, addr = next, addr != end);
-
-       return 1;
-}
index 84e8ec4..b91eb09 100644 (file)
@@ -147,13 +147,13 @@ static const struct dma_map_ops ibmebus_dma_ops = {
        .unmap_page         = ibmebus_unmap_page,
 };
 
-static int ibmebus_match_path(struct device *dev, void *data)
+static int ibmebus_match_path(struct device *dev, const void *data)
 {
        struct device_node *dn = to_platform_device(dev)->dev.of_node;
        return (of_find_node_by_path(data) == dn);
 }
 
-static int ibmebus_match_node(struct device *dev, void *data)
+static int ibmebus_match_node(struct device *dev, const void *data)
 {
        return to_platform_device(dev)->dev.of_node == data;
 }
index 6b0741c..f8b3b07 100644 (file)
@@ -16,8 +16,6 @@ endif
 KBUILD_AFLAGS_MODULE += -fPIC
 KBUILD_CFLAGS_MODULE += -fPIC
 
-KBUILD_DEFCONFIG = defconfig
-
 export BITS
 ifeq ($(CONFIG_ARCH_RV64I),y)
        BITS := 64
index eb8b019..56a67d6 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/mm.h>
 #include <asm/tlb.h>
 
+#include <asm-generic/pgalloc.h>       /* for pte_{alloc,free}_one */
+
 static inline void pmd_populate_kernel(struct mm_struct *mm,
        pmd_t *pmd, pte_t *pte)
 {
@@ -74,33 +76,6 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 
 #endif /* __PAGETABLE_PMD_FOLDED */
 
-static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm)
-{
-       return (pte_t *)__get_free_page(
-               GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_ZERO);
-}
-
-static inline struct page *pte_alloc_one(struct mm_struct *mm)
-{
-       struct page *pte;
-
-       pte = alloc_page(GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_ZERO);
-       if (likely(pte != NULL))
-               pgtable_page_ctor(pte);
-       return pte;
-}
-
-static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
-{
-       free_page((unsigned long)pte);
-}
-
-static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
-{
-       pgtable_page_dtor(pte);
-       __free_page(pte);
-}
-
 #define __pte_free_tlb(tlb, pte, buf)   \
 do {                                    \
        pgtable_page_dtor(pte);         \
index fdb4246..5d8570e 100644 (file)
@@ -139,6 +139,7 @@ config S390
        select HAVE_DMA_CONTIGUOUS
        select HAVE_DYNAMIC_FTRACE
        select HAVE_DYNAMIC_FTRACE_WITH_REGS
+       select HAVE_FAST_GUP
        select HAVE_EFFICIENT_UNALIGNED_ACCESS
        select HAVE_FENTRY
        select HAVE_FTRACE_MCOUNT_RECORD
@@ -146,7 +147,6 @@ config S390
        select HAVE_FUNCTION_TRACER
        select HAVE_FUTEX_CMPXCHG if FUTEX
        select HAVE_GCC_PLUGINS
-       select HAVE_GENERIC_GUP
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_LZ4
@@ -641,9 +641,6 @@ config ARCH_SPARSEMEM_ENABLE
 config ARCH_SPARSEMEM_DEFAULT
        def_bool y
 
-config ARCH_SELECT_MEMORY_MODEL
-       def_bool y
-
 config ARCH_ENABLE_MEMORY_HOTPLUG
        def_bool y if SPARSEMEM
 
index e48013c..e0bab7e 100644 (file)
@@ -10,8 +10,6 @@
 # Copyright (C) 1994 by Linus Torvalds
 #
 
-KBUILD_DEFCONFIG := defconfig
-
 LD_BFD         := elf64-s390
 KBUILD_LDFLAGS := -m elf64_s390
 KBUILD_AFLAGS_MODULE += -fPIC
index a6dc01a..e26d441 100644 (file)
@@ -588,6 +588,7 @@ CONFIG_GDB_SCRIPTS=y
 CONFIG_FRAME_WARN=1024
 CONFIG_READABLE_ASM=y
 CONFIG_UNUSED_SYMBOLS=y
+CONFIG_HEADERS_INSTALL=y
 CONFIG_HEADERS_CHECK=y
 CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_MAGIC_SYSRQ=y
index 4a928e2..abe6026 100644 (file)
@@ -912,7 +912,6 @@ extern int kvm_s390_gisc_register(struct kvm *kvm, u32 gisc);
 extern int kvm_s390_gisc_unregister(struct kvm *kvm, u32 gisc);
 
 static inline void kvm_arch_hardware_disable(void) {}
-static inline void kvm_arch_check_processor_compat(void *rtn) {}
 static inline void kvm_arch_sync_events(struct kvm *kvm) {}
 static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {}
 static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
index ff81ed1..61cf953 100644 (file)
@@ -143,14 +143,4 @@ static inline int zpci_set_irq_ctrl(u16 ctl, u8 isc)
        return __zpci_set_irq_ctrl(ctl, isc, &iib);
 }
 
-#ifdef CONFIG_PCI
-static inline void enable_mio_ctl(void)
-{
-       if (static_branch_likely(&have_mio))
-               __ctl_set_bit(2, 5);
-}
-#else /* CONFIG_PCI */
-static inline void enable_mio_ctl(void) {}
-#endif /* CONFIG_PCI */
-
 #endif
index 9f0195d..9b274fc 100644 (file)
@@ -1270,14 +1270,8 @@ static inline pte_t *pte_offset(pmd_t *pmd, unsigned long address)
 #define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address)
 #define pte_unmap(pte) do { } while (0)
 
-static inline bool gup_fast_permitted(unsigned long start, int nr_pages)
+static inline bool gup_fast_permitted(unsigned long start, unsigned long end)
 {
-       unsigned long len, end;
-
-       len = (unsigned long) nr_pages << PAGE_SHIFT;
-       end = start + len;
-       if (end < start)
-               return false;
        return end <= current->mm->context.asce_limit;
 }
 #define gup_fast_permitted gup_fast_permitted
index f577c5f..c563f83 100644 (file)
@@ -80,7 +80,6 @@ struct sclp_info {
        unsigned char has_gisaf : 1;
        unsigned char has_diag318 : 1;
        unsigned char has_sipl : 1;
-       unsigned char has_sipl_g2 : 1;
        unsigned char has_dirq : 1;
        unsigned int ibc;
        unsigned int mtid;
index 832be5c..9ec86fa 100644 (file)
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/* 
+/*
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * Copyright IBM Corp. 1999, 2000
 
 #define DASD_API_VERSION 6
 
-/* 
+/*
  * struct dasd_information2_t
  * represents any data about the device, which is visible to userspace.
  *  including foramt and featueres.
  */
 typedef struct dasd_information2_t {
-        unsigned int devno;         /* S/390 devno */
-        unsigned int real_devno;    /* for aliases */
-        unsigned int schid;         /* S/390 subchannel identifier */
-        unsigned int cu_type  : 16; /* from SenseID */
-        unsigned int cu_model :  8; /* from SenseID */
-        unsigned int dev_type : 16; /* from SenseID */
-        unsigned int dev_model : 8; /* from SenseID */
-        unsigned int open_count; 
-        unsigned int req_queue_len; 
-        unsigned int chanq_len;     /* length of chanq */
-        char type[4];               /* from discipline.name, 'none' for unknown */
-        unsigned int status;        /* current device level */
-        unsigned int label_block;   /* where to find the VOLSER */
-        unsigned int FBA_layout;    /* fixed block size (like AIXVOL) */
-        unsigned int characteristics_size;
-        unsigned int confdata_size;
-        char characteristics[64];   /* from read_device_characteristics */
-        char configuration_data[256]; /* from read_configuration_data */
-        unsigned int format;          /* format info like formatted/cdl/ldl/... */
-        unsigned int features;        /* dasd features like 'ro',...            */
-        unsigned int reserved0;       /* reserved for further use ,...          */
-        unsigned int reserved1;       /* reserved for further use ,...          */
-        unsigned int reserved2;       /* reserved for further use ,...          */
-        unsigned int reserved3;       /* reserved for further use ,...          */
-        unsigned int reserved4;       /* reserved for further use ,...          */
-        unsigned int reserved5;       /* reserved for further use ,...          */
-        unsigned int reserved6;       /* reserved for further use ,...          */
-        unsigned int reserved7;       /* reserved for further use ,...          */
+       unsigned int devno;         /* S/390 devno */
+       unsigned int real_devno;    /* for aliases */
+       unsigned int schid;         /* S/390 subchannel identifier */
+       unsigned int cu_type  : 16; /* from SenseID */
+       unsigned int cu_model :  8; /* from SenseID */
+       unsigned int dev_type : 16; /* from SenseID */
+       unsigned int dev_model : 8; /* from SenseID */
+       unsigned int open_count;
+       unsigned int req_queue_len;
+       unsigned int chanq_len;     /* length of chanq */
+       char type[4];               /* from discipline.name, 'none' for unknown */
+       unsigned int status;        /* current device level */
+       unsigned int label_block;   /* where to find the VOLSER */
+       unsigned int FBA_layout;    /* fixed block size (like AIXVOL) */
+       unsigned int characteristics_size;
+       unsigned int confdata_size;
+       char characteristics[64];   /* from read_device_characteristics */
+       char configuration_data[256]; /* from read_configuration_data */
+       unsigned int format;          /* format info like formatted/cdl/ldl/... */
+       unsigned int features;        /* dasd features like 'ro',...            */
+       unsigned int reserved0;       /* reserved for further use ,...          */
+       unsigned int reserved1;       /* reserved for further use ,...          */
+       unsigned int reserved2;       /* reserved for further use ,...          */
+       unsigned int reserved3;       /* reserved for further use ,...          */
+       unsigned int reserved4;       /* reserved for further use ,...          */
+       unsigned int reserved5;       /* reserved for further use ,...          */
+       unsigned int reserved6;       /* reserved for further use ,...          */
+       unsigned int reserved7;       /* reserved for further use ,...          */
 } dasd_information2_t;
 
 /*
@@ -92,34 +92,34 @@ typedef struct dasd_information2_t {
 
 #define DASD_PARTN_BITS 2
 
-/* 
+/*
  * struct dasd_information_t
  * represents any data about the data, which is visible to userspace
  */
 typedef struct dasd_information_t {
-        unsigned int devno;         /* S/390 devno */
-        unsigned int real_devno;    /* for aliases */
-        unsigned int schid;         /* S/390 subchannel identifier */
-        unsigned int cu_type  : 16; /* from SenseID */
-        unsigned int cu_model :  8; /* from SenseID */
-        unsigned int dev_type : 16; /* from SenseID */
-        unsigned int dev_model : 8; /* from SenseID */
-        unsigned int open_count; 
-        unsigned int req_queue_len; 
-        unsigned int chanq_len;     /* length of chanq */
-        char type[4];               /* from discipline.name, 'none' for unknown */
-        unsigned int status;        /* current device level */
-        unsigned int label_block;   /* where to find the VOLSER */
-        unsigned int FBA_layout;    /* fixed block size (like AIXVOL) */
-        unsigned int characteristics_size;
-        unsigned int confdata_size;
-        char characteristics[64];   /* from read_device_characteristics */
-        char configuration_data[256]; /* from read_configuration_data */
+       unsigned int devno;         /* S/390 devno */
+       unsigned int real_devno;    /* for aliases */
+       unsigned int schid;         /* S/390 subchannel identifier */
+       unsigned int cu_type  : 16; /* from SenseID */
+       unsigned int cu_model :  8; /* from SenseID */
+       unsigned int dev_type : 16; /* from SenseID */
+       unsigned int dev_model : 8; /* from SenseID */
+       unsigned int open_count;
+       unsigned int req_queue_len;
+       unsigned int chanq_len;     /* length of chanq */
+       char type[4];               /* from discipline.name, 'none' for unknown */
+       unsigned int status;        /* current device level */
+       unsigned int label_block;   /* where to find the VOLSER */
+       unsigned int FBA_layout;    /* fixed block size (like AIXVOL) */
+       unsigned int characteristics_size;
+       unsigned int confdata_size;
+       char characteristics[64];   /* from read_device_characteristics */
+       char configuration_data[256]; /* from read_configuration_data */
 } dasd_information_t;
 
 /*
  * Read Subsystem Data - Performance Statistics
- */ 
+ */
 typedef struct dasd_rssd_perf_stats_t {
        unsigned char  invalid:1;
        unsigned char  format:3;
@@ -154,21 +154,21 @@ typedef struct dasd_rssd_perf_stats_t {
        unsigned char  reseved2[96];
 } __attribute__((packed)) dasd_rssd_perf_stats_t;
 
-/* 
+/*
  * struct profile_info_t
- * holds the profinling information 
+ * holds the profinling information
  */
 typedef struct dasd_profile_info_t {
-        unsigned int dasd_io_reqs;      /* number of requests processed at all */
-        unsigned int dasd_io_sects;     /* number of sectors processed at all */
-        unsigned int dasd_io_secs[32];  /* histogram of request's sizes */
-        unsigned int dasd_io_times[32];         /* histogram of requests's times */
-        unsigned int dasd_io_timps[32];         /* histogram of requests's times per sector */
-        unsigned int dasd_io_time1[32];         /* histogram of time from build to start */
-        unsigned int dasd_io_time2[32];         /* histogram of time from start to irq */
-        unsigned int dasd_io_time2ps[32]; /* histogram of time from start to irq */
-        unsigned int dasd_io_time3[32];         /* histogram of time from irq to end */
-        unsigned int dasd_io_nr_req[32]; /* histogram of # of requests in chanq */
+       unsigned int dasd_io_reqs;       /* number of requests processed at all */
+       unsigned int dasd_io_sects;      /* number of sectors processed at all */
+       unsigned int dasd_io_secs[32];   /* histogram of request's sizes */
+       unsigned int dasd_io_times[32];  /* histogram of requests's times */
+       unsigned int dasd_io_timps[32];  /* histogram of requests's times per sector */
+       unsigned int dasd_io_time1[32];  /* histogram of time from build to start */
+       unsigned int dasd_io_time2[32];  /* histogram of time from start to irq */
+       unsigned int dasd_io_time2ps[32]; /* histogram of time from start to irq */
+       unsigned int dasd_io_time3[32];  /* histogram of time from irq to end */
+       unsigned int dasd_io_nr_req[32]; /* histogram of # of requests in chanq */
 } dasd_profile_info_t;
 
 /*
@@ -189,10 +189,12 @@ typedef struct format_data_t {
  * 3/11: also write home address
  * 4/12: invalidate track
  */
-#define DASD_FMT_INT_FMT_R0 1 /* write record zero */
-#define DASD_FMT_INT_FMT_HA 2 /* write home address, also set FMT_R0 ! */
-#define DASD_FMT_INT_INVAL  4 /* invalidate tracks */
-#define DASD_FMT_INT_COMPAT 8 /* use OS/390 compatible disk layout */
+#define DASD_FMT_INT_FMT_R0    1       /* write record zero */
+#define DASD_FMT_INT_FMT_HA    2       /* write home address, also set FMT_R0 ! */
+#define DASD_FMT_INT_INVAL     4       /* invalidate tracks */
+#define DASD_FMT_INT_COMPAT    8       /* use OS/390 compatible disk layout */
+#define DASD_FMT_INT_FMT_NOR0  16      /* remove permission to write record zero */
+#define DASD_FMT_INT_ESE_FULL  32      /* release space for entire volume */
 
 /*
  * struct format_check_t
@@ -225,7 +227,7 @@ typedef struct format_check_t {
 /* If key-length was != 0 */
 #define DASD_FMT_ERR_KEY_LENGTH                5
 
-/* 
+/*
  * struct attrib_data_t
  * represents the operation (cache) bits for the device.
  * Used in DE to influence caching of the DASD.
@@ -281,13 +283,13 @@ struct dasd_snid_ioctl_data {
  * Here ist how the ioctl-nr should be used:
  *    0 -   31   DASD driver itself
  *   32 -  239   still open
- *  240 -  255   reserved for EMC 
+ *  240 -  255  reserved for EMC
  *******************************************************************************/
 
 /* Disable the volume (for Linux) */
-#define BIODASDDISABLE _IO(DASD_IOCTL_LETTER,0) 
+#define BIODASDDISABLE _IO(DASD_IOCTL_LETTER,0)
 /* Enable the volume (for Linux) */
-#define BIODASDENABLE  _IO(DASD_IOCTL_LETTER,1)  
+#define BIODASDENABLE  _IO(DASD_IOCTL_LETTER,1)
 /* Issue a reserve/release command, rsp. */
 #define BIODASDRSRV    _IO(DASD_IOCTL_LETTER,2) /* reserve */
 #define BIODASDRLSE    _IO(DASD_IOCTL_LETTER,3) /* release */
@@ -295,9 +297,9 @@ struct dasd_snid_ioctl_data {
 /* reset profiling information of a device */
 #define BIODASDPRRST   _IO(DASD_IOCTL_LETTER,5)
 /* Quiesce IO on device */
-#define BIODASDQUIESCE _IO(DASD_IOCTL_LETTER,6) 
+#define BIODASDQUIESCE _IO(DASD_IOCTL_LETTER,6)
 /* Resume IO on device */
-#define BIODASDRESUME  _IO(DASD_IOCTL_LETTER,7) 
+#define BIODASDRESUME  _IO(DASD_IOCTL_LETTER,7)
 /* Abort all I/O on a device */
 #define BIODASDABORTIO _IO(DASD_IOCTL_LETTER, 240)
 /* Allow I/O on a device */
@@ -315,13 +317,15 @@ struct dasd_snid_ioctl_data {
 /* Performance Statistics Read */
 #define BIODASDPSRD    _IOR(DASD_IOCTL_LETTER,4,dasd_rssd_perf_stats_t)
 /* Get Attributes (cache operations) */
-#define BIODASDGATTR   _IOR(DASD_IOCTL_LETTER,5,attrib_data_t) 
+#define BIODASDGATTR   _IOR(DASD_IOCTL_LETTER,5,attrib_data_t)
 
 
 /* #define BIODASDFORMAT  _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */
-#define BIODASDFMT     _IOW(DASD_IOCTL_LETTER,1,format_data_t) 
+#define BIODASDFMT     _IOW(DASD_IOCTL_LETTER,1,format_data_t)
 /* Set Attributes (cache operations) */
-#define BIODASDSATTR   _IOW(DASD_IOCTL_LETTER,2,attrib_data_t) 
+#define BIODASDSATTR   _IOW(DASD_IOCTL_LETTER,2,attrib_data_t)
+/* Release Allocated Space */
+#define BIODASDRAS     _IOW(DASD_IOCTL_LETTER, 3, format_data_t)
 
 /* Get Sense Path Group ID (SNID) data */
 #define BIODASDSNID    _IOWR(DASD_IOCTL_LETTER, 1, struct dasd_snid_ioctl_data)
index 629f173..6312fed 100644 (file)
@@ -30,7 +30,6 @@
 #include <asm/sclp.h>
 #include <asm/facility.h>
 #include <asm/boot_data.h>
-#include <asm/pci_insn.h>
 #include "entry.h"
 
 /*
@@ -236,7 +235,6 @@ static __init void detect_machine_facilities(void)
                clock_comparator_max = -1ULL >> 1;
                __ctl_set_bit(0, 53);
        }
-       enable_mio_ctl();
 }
 
 static inline void save_vector_registers(void)
index d836af3..2c0a515 100644 (file)
@@ -286,12 +286,7 @@ static struct kobj_attribute sys_ipl_secure_attr =
 static ssize_t ipl_has_secure_show(struct kobject *kobj,
                                   struct kobj_attribute *attr, char *page)
 {
-       if (MACHINE_IS_LPAR)
-               return sprintf(page, "%i\n", !!sclp.has_sipl);
-       else if (MACHINE_IS_VM)
-               return sprintf(page, "%i\n", !!sclp.has_sipl_g2);
-       else
-               return sprintf(page, "%i\n", 0);
+       return sprintf(page, "%i\n", !!sclp.has_sipl);
 }
 
 static struct kobj_attribute sys_ipl_has_secure_attr =
index 34cc964..8b33e03 100644 (file)
@@ -624,6 +624,8 @@ __init const struct attribute_group **cpumf_cf_event_group(void)
                break;
        case 0x3906:
        case 0x3907:
+       case 0x8561:
+       case 0x8562:
                model = cpumcf_z14_pmu_event_attr;
                break;
        default:
index 3ce8a08..8fc9daa 100644 (file)
@@ -20,7 +20,7 @@ EXPORT_SYMBOL_GPL(unwind_get_return_address);
 static bool outside_of_stack(struct unwind_state *state, unsigned long sp)
 {
        return (sp <= state->sp) ||
-               (sp + sizeof(struct stack_frame) > state->stack_info.end);
+               (sp > state->stack_info.end - sizeof(struct stack_frame));
 }
 
 static bool update_stack_info(struct unwind_state *state, unsigned long sp)
index 1c4113f..3f520cd 100644 (file)
@@ -227,6 +227,11 @@ int kvm_arch_hardware_enable(void)
        return 0;
 }
 
+int kvm_arch_check_processor_compat(void)
+{
+       return 0;
+}
+
 static void kvm_gmap_notifier(struct gmap *gmap, unsigned long start,
                              unsigned long end);
 
@@ -2418,13 +2423,13 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
        kvm->arch.sca = (struct bsca_block *) get_zeroed_page(alloc_flags);
        if (!kvm->arch.sca)
                goto out_err;
-       spin_lock(&kvm_lock);
+       mutex_lock(&kvm_lock);
        sca_offset += 16;
        if (sca_offset + sizeof(struct bsca_block) > PAGE_SIZE)
                sca_offset = 0;
        kvm->arch.sca = (struct bsca_block *)
                        ((char *) kvm->arch.sca + sca_offset);
-       spin_unlock(&kvm_lock);
+       mutex_unlock(&kvm_lock);
 
        sprintf(debug_name, "kvm-%u", current->pid);
 
index b8a64cb..b0e3b9a 100644 (file)
@@ -890,8 +890,10 @@ static int __init pci_base_init(void)
        if (!test_facility(69) || !test_facility(71))
                return 0;
 
-       if (test_facility(153) && !s390_pci_no_mio)
+       if (test_facility(153) && !s390_pci_no_mio) {
                static_branch_enable(&have_mio);
+               ctl_set_bit(2, 5);
+       }
 
        rc = zpci_debug_init();
        if (rc)
index 430c14b..a433ba0 100644 (file)
@@ -37,6 +37,15 @@ zpci_attr(segment1, "0x%02x\n", pfip[1]);
 zpci_attr(segment2, "0x%02x\n", pfip[2]);
 zpci_attr(segment3, "0x%02x\n", pfip[3]);
 
+static ssize_t mio_enabled_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
+
+       return sprintf(buf, zpci_use_mio(zdev) ? "1\n" : "0\n");
+}
+static DEVICE_ATTR_RO(mio_enabled);
+
 static ssize_t recover_store(struct device *dev, struct device_attribute *attr,
                             const char *buf, size_t count)
 {
@@ -115,6 +124,7 @@ static struct attribute *zpci_dev_attrs[] = {
        &dev_attr_vfn.attr,
        &dev_attr_uid.attr,
        &dev_attr_recover.attr,
+       &dev_attr_mio_enabled.attr,
        NULL,
 };
 static struct attribute_group zpci_attr_group = {
index c7c99e1..31a7d12 100644 (file)
@@ -15,6 +15,7 @@ config SUPERH
        select HAVE_ARCH_TRACEHOOK
        select HAVE_PERF_EVENTS
        select HAVE_DEBUG_BUGVERBOSE
+       select HAVE_FAST_GUP if MMU
        select ARCH_HAVE_CUSTOM_GPIO_H
        select ARCH_HAVE_NMI_SAFE_CMPXCHG if (GUSA_RB || CPU_SH4A)
        select ARCH_HAS_GCOV_PROFILE_ALL
@@ -64,6 +65,7 @@ config SUPERH
 config SUPERH32
        def_bool "$(ARCH)" = "sh"
        select ARCH_32BIT_OFF_T
+       select GUP_GET_PTE_LOW_HIGH if X2TLB
        select HAVE_KPROBES
        select HAVE_KRETPROBES
        select HAVE_IOREMAP_PROT if MMU && !X2TLB
index 4dcf7f5..91d43e2 100644 (file)
@@ -40,7 +40,6 @@ CONFIG_FB=y
 CONFIG_FIRMWARE_EDID=y
 CONFIG_FB_HIT=y
 CONFIG_FB_SH_MOBILE_LCDC=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FONTS=y
 CONFIG_FONT_PEARL_8x8=y
index 5209889..49a2933 100644 (file)
@@ -191,7 +191,6 @@ CONFIG_CONFIGFS_FS=y
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_XATTR=y
 CONFIG_UBIFS_FS=m
-CONFIG_LOGFS=m
 CONFIG_CRAMFS=m
 CONFIG_SQUASHFS=m
 CONFIG_ROMFS_FS=m
index a1cf644..cbd6742 100644 (file)
@@ -85,7 +85,6 @@ CONFIG_WATCHDOG=y
 CONFIG_SH_WDT=y
 CONFIG_SSB=y
 CONFIG_FB=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
index c28e37a..ac05619 100644 (file)
@@ -369,7 +369,11 @@ static inline int iounmap_fixed(void __iomem *addr) { return -EINVAL; }
 
 #define ioremap_nocache        ioremap
 #define ioremap_uc     ioremap
-#define iounmap                __iounmap
+
+static inline void iounmap(void __iomem *addr)
+{
+       __iounmap(addr);
+}
 
 /*
  * Convert a physical pointer to a virtual kernel pointer for /dev/mem
index 7d8587e..779260b 100644 (file)
@@ -38,6 +38,9 @@ static inline unsigned long pud_page_vaddr(pud_t pud)
        return pud_val(pud);
 }
 
+/* only used by the stubbed out hugetlb gup code, should never be called */
+#define pud_page(pud)          NULL
+
 #define pmd_index(address)     (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
 static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address)
 {
index 3587103..9085d11 100644 (file)
@@ -149,6 +149,43 @@ extern void paging_init(void);
 extern void page_table_range_init(unsigned long start, unsigned long end,
                                  pgd_t *pgd);
 
+static inline bool __pte_access_permitted(pte_t pte, u64 prot)
+{
+       return (pte_val(pte) & (prot | _PAGE_SPECIAL)) == prot;
+}
+
+#ifdef CONFIG_X2TLB
+static inline bool pte_access_permitted(pte_t pte, bool write)
+{
+       u64 prot = _PAGE_PRESENT;
+
+       prot |= _PAGE_EXT(_PAGE_EXT_KERN_READ | _PAGE_EXT_USER_READ);
+       if (write)
+               prot |= _PAGE_EXT(_PAGE_EXT_KERN_WRITE | _PAGE_EXT_USER_WRITE);
+       return __pte_access_permitted(pte, prot);
+}
+#elif defined(CONFIG_SUPERH64)
+static inline bool pte_access_permitted(pte_t pte, bool write)
+{
+       u64 prot = _PAGE_PRESENT | _PAGE_USER | _PAGE_READ;
+
+       if (write)
+               prot |= _PAGE_WRITE;
+       return __pte_access_permitted(pte, prot);
+}
+#else
+static inline bool pte_access_permitted(pte_t pte, bool write)
+{
+       u64 prot = _PAGE_PRESENT | _PAGE_USER;
+
+       if (write)
+               prot |= _PAGE_RW;
+       return __pte_access_permitted(pte, prot);
+}
+#endif
+
+#define pte_access_permitted pte_access_permitted
+
 /* arch/sh/mm/mmap.c */
 #define HAVE_ARCH_UNMAPPED_AREA
 #define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
index 9143c7b..6c89e3e 100644 (file)
 #define user_mode(regs)                        (((regs)->sr & 0x40000000)==0)
 #define kernel_stack_pointer(_regs)    ((unsigned long)(_regs)->regs[15])
 
-#define GET_FP(regs)   ((regs)->regs[14])
-#define GET_USP(regs)  ((regs)->regs[15])
+static inline unsigned long instruction_pointer(struct pt_regs *regs)
+{
+       return regs->pc;
+}
+static inline void instruction_pointer_set(struct pt_regs *regs,
+               unsigned long val)
+{
+       regs->pc = val;
+}
+
+static inline unsigned long frame_pointer(struct pt_regs *regs)
+{
+       return regs->regs[14];
+}
+
+static inline unsigned long user_stack_pointer(struct pt_regs *regs)
+{
+       return regs->regs[15];
+}
+
+static inline void user_stack_pointer_set(struct pt_regs *regs,
+               unsigned long val)
+{
+       regs->regs[15] = val;
+}
 
 #define arch_has_single_step() (1)
 
@@ -112,7 +135,5 @@ static inline unsigned long profile_pc(struct pt_regs *regs)
 
        return pc;
 }
-#define profile_pc profile_pc
 
-#include <asm-generic/ptrace.h>
 #endif /* __ASM_SH_PTRACE_H */
index 95428e0..8b505e1 100644 (file)
@@ -9,9 +9,6 @@ EXPORT_SYMBOL(arch_debugfs_dir);
 static int __init arch_kdebugfs_init(void)
 {
        arch_debugfs_dir = debugfs_create_dir("sh", NULL);
-       if (!arch_debugfs_dir)
-               return -ENOMEM;
-
        return 0;
 }
 arch_initcall(arch_kdebugfs_init);
index fbe5e79..5051b38 100644 (file)
@@ -17,7 +17,7 @@ cacheops-$(CONFIG_CPU_SHX3)           += cache-shx3.o
 obj-y                  += $(cacheops-y)
 
 mmu-y                  := nommu.o extable_32.o
-mmu-$(CONFIG_MMU)      := extable_$(BITS).o fault.o gup.o ioremap.o kmap.o \
+mmu-$(CONFIG_MMU)      := extable_$(BITS).o fault.o ioremap.o kmap.o \
                           pgtable.o tlbex_$(BITS).o tlbflush_$(BITS).o
 
 obj-y                  += $(mmu-y)
index e5539e0..4c1ca19 100644 (file)
@@ -63,13 +63,8 @@ static const struct file_operations asids_debugfs_fops = {
 
 static int __init asids_debugfs_init(void)
 {
-       struct dentry *asids_dentry;
-
-       asids_dentry = debugfs_create_file("asids", S_IRUSR, arch_debugfs_dir,
-                                          NULL, &asids_debugfs_fops);
-       if (!asids_dentry)
-               return -ENOMEM;
-
-       return PTR_ERR_OR_ZERO(asids_dentry);
+       debugfs_create_file("asids", S_IRUSR, arch_debugfs_dir, NULL,
+                           &asids_debugfs_fops);
+       return 0;
 }
 device_initcall(asids_debugfs_init);
index 4eb9d43..17d7807 100644 (file)
@@ -109,22 +109,10 @@ static const struct file_operations cache_debugfs_fops = {
 
 static int __init cache_debugfs_init(void)
 {
-       struct dentry *dcache_dentry, *icache_dentry;
-
-       dcache_dentry = debugfs_create_file("dcache", S_IRUSR, arch_debugfs_dir,
-                                           (unsigned int *)CACHE_TYPE_DCACHE,
-                                           &cache_debugfs_fops);
-       if (!dcache_dentry)
-               return -ENOMEM;
-
-       icache_dentry = debugfs_create_file("icache", S_IRUSR, arch_debugfs_dir,
-                                           (unsigned int *)CACHE_TYPE_ICACHE,
-                                           &cache_debugfs_fops);
-       if (!icache_dentry) {
-               debugfs_remove(dcache_dentry);
-               return -ENOMEM;
-       }
-
+       debugfs_create_file("dcache", S_IRUSR, arch_debugfs_dir,
+                           (void *)CACHE_TYPE_DCACHE, &cache_debugfs_fops);
+       debugfs_create_file("icache", S_IRUSR, arch_debugfs_dir,
+                           (void *)CACHE_TYPE_ICACHE, &cache_debugfs_fops);
        return 0;
 }
 module_init(cache_debugfs_init);
diff --git a/arch/sh/mm/gup.c b/arch/sh/mm/gup.c
deleted file mode 100644 (file)
index 277c882..0000000
+++ /dev/null
@@ -1,277 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Lockless get_user_pages_fast for SuperH
- *
- * Copyright (C) 2009 - 2010  Paul Mundt
- *
- * Cloned from the x86 and PowerPC versions, by:
- *
- *     Copyright (C) 2008 Nick Piggin
- *     Copyright (C) 2008 Novell Inc.
- */
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/vmstat.h>
-#include <linux/highmem.h>
-#include <asm/pgtable.h>
-
-static inline pte_t gup_get_pte(pte_t *ptep)
-{
-#ifndef CONFIG_X2TLB
-       return READ_ONCE(*ptep);
-#else
-       /*
-        * With get_user_pages_fast, we walk down the pagetables without
-        * taking any locks.  For this we would like to load the pointers
-        * atomically, but that is not possible with 64-bit PTEs.  What
-        * we do have is the guarantee that a pte will only either go
-        * from not present to present, or present to not present or both
-        * -- it will not switch to a completely different present page
-        * without a TLB flush in between; something that we are blocking
-        * by holding interrupts off.
-        *
-        * Setting ptes from not present to present goes:
-        * ptep->pte_high = h;
-        * smp_wmb();
-        * ptep->pte_low = l;
-        *
-        * And present to not present goes:
-        * ptep->pte_low = 0;
-        * smp_wmb();
-        * ptep->pte_high = 0;
-        *
-        * We must ensure here that the load of pte_low sees l iff pte_high
-        * sees h. We load pte_high *after* loading pte_low, which ensures we
-        * don't see an older value of pte_high.  *Then* we recheck pte_low,
-        * which ensures that we haven't picked up a changed pte high. We might
-        * have got rubbish values from pte_low and pte_high, but we are
-        * guaranteed that pte_low will not have the present bit set *unless*
-        * it is 'l'. And get_user_pages_fast only operates on present ptes, so
-        * we're safe.
-        *
-        * gup_get_pte should not be used or copied outside gup.c without being
-        * very careful -- it does not atomically load the pte or anything that
-        * is likely to be useful for you.
-        */
-       pte_t pte;
-
-retry:
-       pte.pte_low = ptep->pte_low;
-       smp_rmb();
-       pte.pte_high = ptep->pte_high;
-       smp_rmb();
-       if (unlikely(pte.pte_low != ptep->pte_low))
-               goto retry;
-
-       return pte;
-#endif
-}
-
-/*
- * The performance critical leaf functions are made noinline otherwise gcc
- * inlines everything into a single function which results in too much
- * register pressure.
- */
-static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
-               unsigned long end, int write, struct page **pages, int *nr)
-{
-       u64 mask, result;
-       pte_t *ptep;
-
-#ifdef CONFIG_X2TLB
-       result = _PAGE_PRESENT | _PAGE_EXT(_PAGE_EXT_KERN_READ | _PAGE_EXT_USER_READ);
-       if (write)
-               result |= _PAGE_EXT(_PAGE_EXT_KERN_WRITE | _PAGE_EXT_USER_WRITE);
-#elif defined(CONFIG_SUPERH64)
-       result = _PAGE_PRESENT | _PAGE_USER | _PAGE_READ;
-       if (write)
-               result |= _PAGE_WRITE;
-#else
-       result = _PAGE_PRESENT | _PAGE_USER;
-       if (write)
-               result |= _PAGE_RW;
-#endif
-
-       mask = result | _PAGE_SPECIAL;
-
-       ptep = pte_offset_map(&pmd, addr);
-       do {
-               pte_t pte = gup_get_pte(ptep);
-               struct page *page;
-
-               if ((pte_val(pte) & mask) != result) {
-                       pte_unmap(ptep);
-                       return 0;
-               }
-               VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
-               page = pte_page(pte);
-               get_page(page);
-               __flush_anon_page(page, addr);
-               flush_dcache_page(page);
-               pages[*nr] = page;
-               (*nr)++;
-
-       } while (ptep++, addr += PAGE_SIZE, addr != end);
-       pte_unmap(ptep - 1);
-
-       return 1;
-}
-
-static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
-               int write, struct page **pages, int *nr)
-{
-       unsigned long next;
-       pmd_t *pmdp;
-
-       pmdp = pmd_offset(&pud, addr);
-       do {
-               pmd_t pmd = *pmdp;
-
-               next = pmd_addr_end(addr, end);
-               if (pmd_none(pmd))
-                       return 0;
-               if (!gup_pte_range(pmd, addr, next, write, pages, nr))
-                       return 0;
-       } while (pmdp++, addr = next, addr != end);
-
-       return 1;
-}
-
-static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,
-                       int write, struct page **pages, int *nr)
-{
-       unsigned long next;
-       pud_t *pudp;
-
-       pudp = pud_offset(&pgd, addr);
-       do {
-               pud_t pud = *pudp;
-
-               next = pud_addr_end(addr, end);
-               if (pud_none(pud))
-                       return 0;
-               if (!gup_pmd_range(pud, addr, next, write, pages, nr))
-                       return 0;
-       } while (pudp++, addr = next, addr != end);
-
-       return 1;
-}
-
-/*
- * Like get_user_pages_fast() except its IRQ-safe in that it won't fall
- * back to the regular GUP.
- * Note a difference with get_user_pages_fast: this always returns the
- * number of pages pinned, 0 if no pages were pinned.
- */
-int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
-                         struct page **pages)
-{
-       struct mm_struct *mm = current->mm;
-       unsigned long addr, len, end;
-       unsigned long next;
-       unsigned long flags;
-       pgd_t *pgdp;
-       int nr = 0;
-
-       start &= PAGE_MASK;
-       addr = start;
-       len = (unsigned long) nr_pages << PAGE_SHIFT;
-       end = start + len;
-       if (unlikely(!access_ok((void __user *)start, len)))
-               return 0;
-
-       /*
-        * This doesn't prevent pagetable teardown, but does prevent
-        * the pagetables and pages from being freed.
-        */
-       local_irq_save(flags);
-       pgdp = pgd_offset(mm, addr);
-       do {
-               pgd_t pgd = *pgdp;
-
-               next = pgd_addr_end(addr, end);
-               if (pgd_none(pgd))
-                       break;
-               if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
-                       break;
-       } while (pgdp++, addr = next, addr != end);
-       local_irq_restore(flags);
-
-       return nr;
-}
-
-/**
- * get_user_pages_fast() - pin user pages in memory
- * @start:     starting user address
- * @nr_pages:  number of pages from start to pin
- * @gup_flags: flags modifying pin behaviour
- * @pages:     array that receives pointers to the pages pinned.
- *             Should be at least nr_pages long.
- *
- * Attempt to pin user pages in memory without taking mm->mmap_sem.
- * If not successful, it will fall back to taking the lock and
- * calling get_user_pages().
- *
- * Returns number of pages pinned. This may be fewer than the number
- * requested. If nr_pages is 0 or negative, returns 0. If no pages
- * were pinned, returns -errno.
- */
-int get_user_pages_fast(unsigned long start, int nr_pages,
-                       unsigned int gup_flags, struct page **pages)
-{
-       struct mm_struct *mm = current->mm;
-       unsigned long addr, len, end;
-       unsigned long next;
-       pgd_t *pgdp;
-       int nr = 0;
-
-       start &= PAGE_MASK;
-       addr = start;
-       len = (unsigned long) nr_pages << PAGE_SHIFT;
-
-       end = start + len;
-       if (end < start)
-               goto slow_irqon;
-
-       local_irq_disable();
-       pgdp = pgd_offset(mm, addr);
-       do {
-               pgd_t pgd = *pgdp;
-
-               next = pgd_addr_end(addr, end);
-               if (pgd_none(pgd))
-                       goto slow;
-               if (!gup_pud_range(pgd, addr, next, gup_flags & FOLL_WRITE,
-                                  pages, &nr))
-                       goto slow;
-       } while (pgdp++, addr = next, addr != end);
-       local_irq_enable();
-
-       VM_BUG_ON(nr != (end - start) >> PAGE_SHIFT);
-       return nr;
-
-       {
-               int ret;
-
-slow:
-               local_irq_enable();
-slow_irqon:
-               /* Try to get the remaining pages with get_user_pages */
-               start += nr << PAGE_SHIFT;
-               pages += nr;
-
-               ret = get_user_pages_unlocked(start,
-                       (end - start) >> PAGE_SHIFT, pages,
-                       gup_flags);
-
-               /* Have to be a bit careful with return values */
-               if (nr > 0) {
-                       if (ret < 0)
-                               ret = nr;
-                       else
-                               ret += nr;
-               }
-
-               return ret;
-       }
-}
index a53a040..b59bad8 100644 (file)
@@ -861,13 +861,8 @@ static const struct file_operations pmb_debugfs_fops = {
 
 static int __init pmb_debugfs_init(void)
 {
-       struct dentry *dentry;
-
-       dentry = debugfs_create_file("pmb", S_IFREG | S_IRUGO,
-                                    arch_debugfs_dir, NULL, &pmb_debugfs_fops);
-       if (!dentry)
-               return -ENOMEM;
-
+       debugfs_create_file("pmb", S_IFREG | S_IRUGO, arch_debugfs_dir, NULL,
+                           &pmb_debugfs_fops);
        return 0;
 }
 subsys_initcall(pmb_debugfs_init);
index dea637a..11c6148 100644 (file)
@@ -149,22 +149,10 @@ static const struct file_operations tlb_debugfs_fops = {
 
 static int __init tlb_debugfs_init(void)
 {
-       struct dentry *itlb, *utlb;
-
-       itlb = debugfs_create_file("itlb", S_IRUSR, arch_debugfs_dir,
-                                  (unsigned int *)TLB_TYPE_ITLB,
-                                  &tlb_debugfs_fops);
-       if (unlikely(!itlb))
-               return -ENOMEM;
-
-       utlb = debugfs_create_file("utlb", S_IRUSR, arch_debugfs_dir,
-                                  (unsigned int *)TLB_TYPE_UTLB,
-                                  &tlb_debugfs_fops);
-       if (unlikely(!utlb)) {
-               debugfs_remove(itlb);
-               return -ENOMEM;
-       }
-
+       debugfs_create_file("itlb", S_IRUSR, arch_debugfs_dir,
+                           (void *)TLB_TYPE_ITLB, &tlb_debugfs_fops);
+       debugfs_create_file("utlb", S_IRUSR, arch_debugfs_dir,
+                           (void *)TLB_TYPE_UTLB, &tlb_debugfs_fops);
        return 0;
 }
 module_init(tlb_debugfs_init);
index 26ab6f5..e9f5d62 100644 (file)
@@ -28,6 +28,7 @@ config SPARC
        select RTC_DRV_M48T59
        select RTC_SYSTOHC
        select HAVE_ARCH_JUMP_LABEL if SPARC64
+       select HAVE_FAST_GUP if SPARC64
        select GENERIC_IRQ_SHOW
        select ARCH_WANT_IPC_PARSE_VERSION
        select GENERIC_PCI_IOMAP
@@ -300,9 +301,6 @@ config NODES_SPAN_OTHER_NODES
        def_bool y
        depends on NEED_MULTIPLE_NODES
 
-config ARCH_SELECT_MEMORY_MODEL
-       def_bool y if SPARC64
-
 config ARCH_SPARSEMEM_ENABLE
        def_bool y if SPARC64
        select SPARSEMEM_VMEMMAP_ENABLE
index 22500c3..1599de7 100644 (file)
@@ -864,6 +864,9 @@ static inline unsigned long pud_page_vaddr(pud_t pud)
 #define pgd_present(pgd)               (pgd_val(pgd) != 0U)
 #define pgd_clear(pgdp)                        (pgd_val(*(pgdp)) = 0UL)
 
+/* only used by the stubbed out hugetlb gup code, should never be called */
+#define pgd_page(pgd)                  NULL
+
 static inline unsigned long pud_large(pud_t pud)
 {
        pte_t pte = __pte(pud_val(pud));
@@ -1075,6 +1078,46 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma,
 }
 #define io_remap_pfn_range io_remap_pfn_range 
 
+static inline unsigned long untagged_addr(unsigned long start)
+{
+       if (adi_capable()) {
+               long addr = start;
+
+               /* If userspace has passed a versioned address, kernel
+                * will not find it in the VMAs since it does not store
+                * the version tags in the list of VMAs. Storing version
+                * tags in list of VMAs is impractical since they can be
+                * changed any time from userspace without dropping into
+                * kernel. Any address search in VMAs will be done with
+                * non-versioned addresses. Ensure the ADI version bits
+                * are dropped here by sign extending the last bit before
+                * ADI bits. IOMMU does not implement version tags.
+                */
+               return (addr << (long)adi_nbits()) >> (long)adi_nbits();
+       }
+
+       return start;
+}
+#define untagged_addr untagged_addr
+
+static inline bool pte_access_permitted(pte_t pte, bool write)
+{
+       u64 prot;
+
+       if (tlb_type == hypervisor) {
+               prot = _PAGE_PRESENT_4V | _PAGE_P_4V;
+               if (write)
+                       prot |= _PAGE_WRITE_4V;
+       } else {
+               prot = _PAGE_PRESENT_4U | _PAGE_P_4U;
+               if (write)
+                       prot |= _PAGE_WRITE_4U;
+       }
+
+       return (pte_val(pte) & (prot | _PAGE_SPECIAL)) == prot;
+}
+#define pte_access_permitted pte_access_permitted
+
 #include <asm/tlbflush.h>
 #include <asm-generic/pgtable.h>
 
index d39075b..b078205 100644 (file)
@@ -5,7 +5,7 @@
 asflags-y := -ansi
 ccflags-y := -Werror
 
-obj-$(CONFIG_SPARC64)   += ultra.o tlb.o tsb.o gup.o
+obj-$(CONFIG_SPARC64)   += ultra.o tlb.o tsb.o
 obj-y                   += fault_$(BITS).o
 obj-y                   += init_$(BITS).o
 obj-$(CONFIG_SPARC32)   += extable.o srmmu.o iommu.o io-unit.o
diff --git a/arch/sparc/mm/gup.c b/arch/sparc/mm/gup.c
deleted file mode 100644 (file)
index 1e770a5..0000000
+++ /dev/null
@@ -1,340 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Lockless get_user_pages_fast for sparc, cribbed from powerpc
- *
- * Copyright (C) 2008 Nick Piggin
- * Copyright (C) 2008 Novell Inc.
- */
-
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/vmstat.h>
-#include <linux/pagemap.h>
-#include <linux/rwsem.h>
-#include <asm/pgtable.h>
-#include <asm/adi.h>
-
-/*
- * The performance critical leaf functions are made noinline otherwise gcc
- * inlines everything into a single function which results in too much
- * register pressure.
- */
-static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
-               unsigned long end, int write, struct page **pages, int *nr)
-{
-       unsigned long mask, result;
-       pte_t *ptep;
-
-       if (tlb_type == hypervisor) {
-               result = _PAGE_PRESENT_4V|_PAGE_P_4V;
-               if (write)
-                       result |= _PAGE_WRITE_4V;
-       } else {
-               result = _PAGE_PRESENT_4U|_PAGE_P_4U;
-               if (write)
-                       result |= _PAGE_WRITE_4U;
-       }
-       mask = result | _PAGE_SPECIAL;
-
-       ptep = pte_offset_kernel(&pmd, addr);
-       do {
-               struct page *page, *head;
-               pte_t pte = *ptep;
-
-               if ((pte_val(pte) & mask) != result)
-                       return 0;
-               VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
-
-               /* The hugepage case is simplified on sparc64 because
-                * we encode the sub-page pfn offsets into the
-                * hugepage PTEs.  We could optimize this in the future
-                * use page_cache_add_speculative() for the hugepage case.
-                */
-               page = pte_page(pte);
-               head = compound_head(page);
-               if (!page_cache_get_speculative(head))
-                       return 0;
-               if (unlikely(pte_val(pte) != pte_val(*ptep))) {
-                       put_page(head);
-                       return 0;
-               }
-
-               pages[*nr] = page;
-               (*nr)++;
-       } while (ptep++, addr += PAGE_SIZE, addr != end);
-
-       return 1;
-}
-
-static int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
-                       unsigned long end, int write, struct page **pages,
-                       int *nr)
-{
-       struct page *head, *page;
-       int refs;
-
-       if (!(pmd_val(pmd) & _PAGE_VALID))
-               return 0;
-
-       if (write && !pmd_write(pmd))
-               return 0;
-
-       refs = 0;
-       page = pmd_page(pmd) + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
-       head = compound_head(page);
-       do {
-               VM_BUG_ON(compound_head(page) != head);
-               pages[*nr] = page;
-               (*nr)++;
-               page++;
-               refs++;
-       } while (addr += PAGE_SIZE, addr != end);
-
-       if (!page_cache_add_speculative(head, refs)) {
-               *nr -= refs;
-               return 0;
-       }
-
-       if (unlikely(pmd_val(pmd) != pmd_val(*pmdp))) {
-               *nr -= refs;
-               while (refs--)
-                       put_page(head);
-               return 0;
-       }
-
-       return 1;
-}
-
-static int gup_huge_pud(pud_t *pudp, pud_t pud, unsigned long addr,
-                       unsigned long end, int write, struct page **pages,
-                       int *nr)
-{
-       struct page *head, *page;
-       int refs;
-
-       if (!(pud_val(pud) & _PAGE_VALID))
-               return 0;
-
-       if (write && !pud_write(pud))
-               return 0;
-
-       refs = 0;
-       page = pud_page(pud) + ((addr & ~PUD_MASK) >> PAGE_SHIFT);
-       head = compound_head(page);
-       do {
-               VM_BUG_ON(compound_head(page) != head);
-               pages[*nr] = page;
-               (*nr)++;
-               page++;
-               refs++;
-       } while (addr += PAGE_SIZE, addr != end);
-
-       if (!page_cache_add_speculative(head, refs)) {
-               *nr -= refs;
-               return 0;
-       }
-
-       if (unlikely(pud_val(pud) != pud_val(*pudp))) {
-               *nr -= refs;
-               while (refs--)
-                       put_page(head);
-               return 0;
-       }
-
-       return 1;
-}
-
-static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
-               int write, struct page **pages, int *nr)
-{
-       unsigned long next;
-       pmd_t *pmdp;
-
-       pmdp = pmd_offset(&pud, addr);
-       do {
-               pmd_t pmd = *pmdp;
-
-               next = pmd_addr_end(addr, end);
-               if (pmd_none(pmd))
-                       return 0;
-               if (unlikely(pmd_large(pmd))) {
-                       if (!gup_huge_pmd(pmdp, pmd, addr, next,
-                                         write, pages, nr))
-                               return 0;
-               } else if (!gup_pte_range(pmd, addr, next, write,
-                                         pages, nr))
-                       return 0;
-       } while (pmdp++, addr = next, addr != end);
-
-       return 1;
-}
-
-static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,
-               int write, struct page **pages, int *nr)
-{
-       unsigned long next;
-       pud_t *pudp;
-
-       pudp = pud_offset(&pgd, addr);
-       do {
-               pud_t pud = *pudp;
-
-               next = pud_addr_end(addr, end);
-               if (pud_none(pud))
-                       return 0;
-               if (unlikely(pud_large(pud))) {
-                       if (!gup_huge_pud(pudp, pud, addr, next,
-                                         write, pages, nr))
-                               return 0;
-               } else if (!gup_pmd_range(pud, addr, next, write, pages, nr))
-                       return 0;
-       } while (pudp++, addr = next, addr != end);
-
-       return 1;
-}
-
-/*
- * Note a difference with get_user_pages_fast: this always returns the
- * number of pages pinned, 0 if no pages were pinned.
- */
-int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
-                         struct page **pages)
-{
-       struct mm_struct *mm = current->mm;
-       unsigned long addr, len, end;
-       unsigned long next, flags;
-       pgd_t *pgdp;
-       int nr = 0;
-
-#ifdef CONFIG_SPARC64
-       if (adi_capable()) {
-               long addr = start;
-
-               /* If userspace has passed a versioned address, kernel
-                * will not find it in the VMAs since it does not store
-                * the version tags in the list of VMAs. Storing version
-                * tags in list of VMAs is impractical since they can be
-                * changed any time from userspace without dropping into
-                * kernel. Any address search in VMAs will be done with
-                * non-versioned addresses. Ensure the ADI version bits
-                * are dropped here by sign extending the last bit before
-                * ADI bits. IOMMU does not implement version tags.
-                */
-               addr = (addr << (long)adi_nbits()) >> (long)adi_nbits();
-               start = addr;
-       }
-#endif
-       start &= PAGE_MASK;
-       addr = start;
-       len = (unsigned long) nr_pages << PAGE_SHIFT;
-       end = start + len;
-
-       local_irq_save(flags);
-       pgdp = pgd_offset(mm, addr);
-       do {
-               pgd_t pgd = *pgdp;
-
-               next = pgd_addr_end(addr, end);
-               if (pgd_none(pgd))
-                       break;
-               if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
-                       break;
-       } while (pgdp++, addr = next, addr != end);
-       local_irq_restore(flags);
-
-       return nr;
-}
-
-int get_user_pages_fast(unsigned long start, int nr_pages,
-                       unsigned int gup_flags, struct page **pages)
-{
-       struct mm_struct *mm = current->mm;
-       unsigned long addr, len, end;
-       unsigned long next;
-       pgd_t *pgdp;
-       int nr = 0;
-
-#ifdef CONFIG_SPARC64
-       if (adi_capable()) {
-               long addr = start;
-
-               /* If userspace has passed a versioned address, kernel
-                * will not find it in the VMAs since it does not store
-                * the version tags in the list of VMAs. Storing version
-                * tags in list of VMAs is impractical since they can be
-                * changed any time from userspace without dropping into
-                * kernel. Any address search in VMAs will be done with
-                * non-versioned addresses. Ensure the ADI version bits
-                * are dropped here by sign extending the last bit before
-                * ADI bits. IOMMU does not implements version tags,
-                */
-               addr = (addr << (long)adi_nbits()) >> (long)adi_nbits();
-               start = addr;
-       }
-#endif
-       start &= PAGE_MASK;
-       addr = start;
-       len = (unsigned long) nr_pages << PAGE_SHIFT;
-       end = start + len;
-
-       /*
-        * XXX: batch / limit 'nr', to avoid large irq off latency
-        * needs some instrumenting to determine the common sizes used by
-        * important workloads (eg. DB2), and whether limiting the batch size
-        * will decrease performance.
-        *
-        * It seems like we're in the clear for the moment. Direct-IO is
-        * the main guy that batches up lots of get_user_pages, and even
-        * they are limited to 64-at-a-time which is not so many.
-        */
-       /*
-        * This doesn't prevent pagetable teardown, but does prevent
-        * the pagetables from being freed on sparc.
-        *
-        * So long as we atomically load page table pointers versus teardown,
-        * we can follow the address down to the the page and take a ref on it.
-        */
-       local_irq_disable();
-
-       pgdp = pgd_offset(mm, addr);
-       do {
-               pgd_t pgd = *pgdp;
-
-               next = pgd_addr_end(addr, end);
-               if (pgd_none(pgd))
-                       goto slow;
-               if (!gup_pud_range(pgd, addr, next, gup_flags & FOLL_WRITE,
-                                  pages, &nr))
-                       goto slow;
-       } while (pgdp++, addr = next, addr != end);
-
-       local_irq_enable();
-
-       VM_BUG_ON(nr != (end - start) >> PAGE_SHIFT);
-       return nr;
-
-       {
-               int ret;
-
-slow:
-               local_irq_enable();
-
-               /* Try to get the remaining pages with get_user_pages */
-               start += nr << PAGE_SHIFT;
-               pages += nr;
-
-               ret = get_user_pages_unlocked(start,
-                       (end - start) >> PAGE_SHIFT, pages,
-                       gup_flags);
-
-               /* Have to be a bit careful with return values */
-               if (nr > 0) {
-                       if (ret < 0)
-                               ret = nr;
-                       else
-                               ret += nr;
-               }
-
-               return ret;
-       }
-}
index 273130c..d2daa20 100644 (file)
@@ -73,7 +73,7 @@ KBUILD_AFLAGS += $(ARCH_INCLUDE)
 USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -I%,,$(KBUILD_CFLAGS))) \
                $(ARCH_INCLUDE) $(MODE_INCLUDE) $(filter -I%,$(CFLAGS)) \
                -D_FILE_OFFSET_BITS=64 -idirafter $(srctree)/include \
-               -idirafter $(obj)/include -D__KERNEL__ -D__UM_HOST__
+               -idirafter $(objtree)/include -D__KERNEL__ -D__UM_HOST__
 
 #This will adjust *FLAGS accordingly to the platform.
 include $(ARCH_DIR)/Makefile-os-$(OS)
index 99eb568..d7b282e 100644 (file)
@@ -10,6 +10,8 @@
 
 #include <linux/mm.h>
 
+#include <asm-generic/pgalloc.h>       /* for pte_{alloc,free}_one */
+
 #define pmd_populate_kernel(mm, pmd, pte) \
        set_pmd(pmd, __pmd(_PAGE_TABLE + (unsigned long) __pa(pte)))
 
 extern pgd_t *pgd_alloc(struct mm_struct *);
 extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
 
-extern pte_t *pte_alloc_one_kernel(struct mm_struct *);
-extern pgtable_t pte_alloc_one(struct mm_struct *);
-
-static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
-{
-       free_page((unsigned long) pte);
-}
-
-static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
-{
-       pgtable_page_dtor(pte);
-       __free_page(pte);
-}
-
 #define __pte_free_tlb(tlb,pte, address)               \
 do {                                                   \
        pgtable_page_dtor(pte);                         \
index a9c9a94..de58e97 100644 (file)
@@ -208,28 +208,6 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd)
        free_page((unsigned long) pgd);
 }
 
-pte_t *pte_alloc_one_kernel(struct mm_struct *mm)
-{
-       pte_t *pte;
-
-       pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_ZERO);
-       return pte;
-}
-
-pgtable_t pte_alloc_one(struct mm_struct *mm)
-{
-       struct page *pte;
-
-       pte = alloc_page(GFP_KERNEL|__GFP_ZERO);
-       if (!pte)
-               return NULL;
-       if (!pgtable_page_ctor(pte)) {
-               __free_page(pte);
-               return NULL;
-       }
-       return pte;
-}
-
 #ifdef CONFIG_3_LEVEL_PGTABLES
 pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
 {
index 98a5ca4..3908199 100644 (file)
@@ -41,8 +41,7 @@ libs-y                        += arch/unicore32/lib/
 
 boot                   := arch/unicore32/boot
 
-# Default defconfig and target when executing plain make
-KBUILD_DEFCONFIG       := $(ARCH)_defconfig
+# Default target when executing plain make
 KBUILD_IMAGE           := $(boot)/zImage
 
 all:   zImage
diff --git a/arch/unicore32/configs/defconfig b/arch/unicore32/configs/defconfig
new file mode 100644 (file)
index 0000000..360cc9a
--- /dev/null
@@ -0,0 +1,214 @@
+### General setup
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCALVERSION="-unicore32"
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_HOTPLUG=y
+#      Initial RAM filesystem and RAM disk (initramfs/initrd) support
+#CONFIG_BLK_DEV_INITRD=y
+#CONFIG_INITRAMFS_SOURCE="arch/unicore/ramfs/ramfs_config"
+
+### Enable loadable module support
+CONFIG_MODULES=n
+CONFIG_MODULE_UNLOAD=y
+
+### System Type
+CONFIG_ARCH_PUV3=y
+#      Board Selection
+CONFIG_PUV3_NB0916=y
+#      Processor Features
+CONFIG_CPU_DCACHE_LINE_DISABLE=y
+CONFIG_CPU_TLB_SINGLE_ENTRY_DISABLE=n
+
+### Bus support
+CONFIG_PCI=y
+CONFIG_PCI_LEGACY=n
+
+### Boot options
+#      for debug, adding: earlyprintk=ocd,keep initcall_debug
+#      others support: test_suspend=mem root=/dev/sda
+#      hibernate support: resume=/dev/sda3
+CONFIG_CMDLINE="earlyprintk=ocd,keep ignore_loglevel"
+# TODO: mem=512M video=unifb:1024x600-16@75
+# for nfs: root=/dev/nfs rw nfsroot=192.168.10.88:/home/udb/nfs/,rsize=1024,wsize=1024
+#      ip=192.168.10.83:192.168.10.88:192.168.10.1:255.255.255.0::eth0:off
+CONFIG_CMDLINE_FORCE=y
+
+### Power management options
+CONFIG_PM=y
+CONFIG_HIBERNATION=y
+CONFIG_PM_STD_PARTITION="/dev/sda3"
+CONFIG_CPU_FREQ=n
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+
+### Networking support
+CONFIG_NET=y
+#      Networking options
+CONFIG_PACKET=m
+CONFIG_UNIX=m
+#      TCP/IP networking
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IPV6=n
+#      Wireless
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_MAC80211=m
+
+### PKUnity SoC Features
+CONFIG_USB_WLAN_HED_AQ3=n
+CONFIG_USB_CMMB_INNOFIDEI=n
+CONFIG_I2C_BATTERY_BQ27200=n
+CONFIG_I2C_EEPROM_AT24=n
+CONFIG_LCD_BACKLIGHT=n
+
+CONFIG_PUV3_UMAL=y
+CONFIG_PUV3_MUSB=n
+CONFIG_PUV3_AC97=n
+CONFIG_PUV3_NAND=n
+CONFIG_PUV3_MMC=n
+CONFIG_PUV3_UART=n
+
+### Device Drivers
+#      Memory Technology Device (MTD) support
+CONFIG_MTD=m
+CONFIG_MTD_UBI=m
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLKDEVS=m
+#      RAM/ROM/Flash chip drivers
+CONFIG_MTD_CFI=m
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_CFI_AMDSTD=m
+#      Mapping drivers for chip access
+CONFIG_MTD_PHYSMAP=m
+
+#      Block devices
+CONFIG_BLK_DEV_LOOP=m
+
+#      SCSI device support
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=m
+CONFIG_CHR_DEV_SG=m
+
+#      Serial ATA (prod) and Parallel ATA (experimental) drivers
+CONFIG_ATA=y
+CONFIG_SATA_VIA=y
+
+#      Network device support
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_NETDEV_1000=y
+#      Wireless LAN
+CONFIG_WLAN_80211=n
+CONFIG_RT2X00=n
+CONFIG_RT73USB=n
+
+#      Input device support
+CONFIG_INPUT_EVDEV=m
+#      Keyboards
+CONFIG_KEYBOARD_GPIO=m
+
+#      I2C support
+CONFIG_I2C=y
+CONFIG_I2C_PUV3=y
+
+#      Hardware Monitoring support
+#CONFIG_SENSORS_LM75=m
+#      Generic Thermal sysfs driver
+#CONFIG_THERMAL=y
+#CONFIG_THERMAL_HWMON=y
+
+#      Multimedia support
+CONFIG_MEDIA_SUPPORT=n
+CONFIG_VIDEO_DEV=n
+CONFIG_USB_VIDEO_CLASS=n
+
+#      Graphics support
+CONFIG_FB=y
+CONFIG_FB_PUV3_UNIGFX=y
+#      Console display driver support
+CONFIG_VGA_CONSOLE=n
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+#      Bootup logo
+CONFIG_LOGO=n
+
+#      Sound card support
+CONFIG_SOUND=m
+#      Advanced Linux Sound Architecture
+CONFIG_SND=m
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+
+#      USB support
+CONFIG_USB_ARCH_HAS_HCD=n
+CONFIG_USB=n
+CONFIG_USB_PRINTER=n
+CONFIG_USB_STORAGE=n
+#      Inventra Highspeed Dual Role Controller
+CONFIG_USB_MUSB_HDRC=n
+
+#      LED Support
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+#      LED Triggers
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_DISK=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+
+#      Real Time Clock
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_PUV3=y
+
+### File systems
+CONFIG_EXT2_FS=m
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=m
+#      CD-ROM/DVD Filesystems
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_UDF_FS=m
+#      DOS/FAT/NT Filesystems
+CONFIG_VFAT_FS=m
+#      Pseudo filesystems
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+#      Miscellaneous filesystems
+CONFIG_MISC_FILESYSTEMS=y
+CONFIG_JFFS2_FS=m
+CONFIG_UBIFS_FS=m
+#      Network File Systems
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+#      Partition Types
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_MSDOS_PARTITION=y
+#      Native language support
+CONFIG_NLS=y
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_UTF8=m
+
+### Kernel hacking
+CONFIG_FRAME_WARN=8096
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_PROVE_LOCKING=n
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_LL=y
+
diff --git a/arch/unicore32/configs/unicore32_defconfig b/arch/unicore32/configs/unicore32_defconfig
deleted file mode 100644 (file)
index 360cc9a..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-### General setup
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOCALVERSION="-unicore32"
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_HOTPLUG=y
-#      Initial RAM filesystem and RAM disk (initramfs/initrd) support
-#CONFIG_BLK_DEV_INITRD=y
-#CONFIG_INITRAMFS_SOURCE="arch/unicore/ramfs/ramfs_config"
-
-### Enable loadable module support
-CONFIG_MODULES=n
-CONFIG_MODULE_UNLOAD=y
-
-### System Type
-CONFIG_ARCH_PUV3=y
-#      Board Selection
-CONFIG_PUV3_NB0916=y
-#      Processor Features
-CONFIG_CPU_DCACHE_LINE_DISABLE=y
-CONFIG_CPU_TLB_SINGLE_ENTRY_DISABLE=n
-
-### Bus support
-CONFIG_PCI=y
-CONFIG_PCI_LEGACY=n
-
-### Boot options
-#      for debug, adding: earlyprintk=ocd,keep initcall_debug
-#      others support: test_suspend=mem root=/dev/sda
-#      hibernate support: resume=/dev/sda3
-CONFIG_CMDLINE="earlyprintk=ocd,keep ignore_loglevel"
-# TODO: mem=512M video=unifb:1024x600-16@75
-# for nfs: root=/dev/nfs rw nfsroot=192.168.10.88:/home/udb/nfs/,rsize=1024,wsize=1024
-#      ip=192.168.10.83:192.168.10.88:192.168.10.1:255.255.255.0::eth0:off
-CONFIG_CMDLINE_FORCE=y
-
-### Power management options
-CONFIG_PM=y
-CONFIG_HIBERNATION=y
-CONFIG_PM_STD_PARTITION="/dev/sda3"
-CONFIG_CPU_FREQ=n
-CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
-
-### Networking support
-CONFIG_NET=y
-#      Networking options
-CONFIG_PACKET=m
-CONFIG_UNIX=m
-#      TCP/IP networking
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_PNP=y
-CONFIG_IPV6=n
-#      Wireless
-CONFIG_WIRELESS=y
-CONFIG_WIRELESS_EXT=y
-CONFIG_MAC80211=m
-
-### PKUnity SoC Features
-CONFIG_USB_WLAN_HED_AQ3=n
-CONFIG_USB_CMMB_INNOFIDEI=n
-CONFIG_I2C_BATTERY_BQ27200=n
-CONFIG_I2C_EEPROM_AT24=n
-CONFIG_LCD_BACKLIGHT=n
-
-CONFIG_PUV3_UMAL=y
-CONFIG_PUV3_MUSB=n
-CONFIG_PUV3_AC97=n
-CONFIG_PUV3_NAND=n
-CONFIG_PUV3_MMC=n
-CONFIG_PUV3_UART=n
-
-### Device Drivers
-#      Memory Technology Device (MTD) support
-CONFIG_MTD=m
-CONFIG_MTD_UBI=m
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=m
-CONFIG_MTD_BLKDEVS=m
-#      RAM/ROM/Flash chip drivers
-CONFIG_MTD_CFI=m
-CONFIG_MTD_JEDECPROBE=m
-CONFIG_MTD_CFI_AMDSTD=m
-#      Mapping drivers for chip access
-CONFIG_MTD_PHYSMAP=m
-
-#      Block devices
-CONFIG_BLK_DEV_LOOP=m
-
-#      SCSI device support
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_BLK_DEV_SR=m
-CONFIG_CHR_DEV_SG=m
-
-#      Serial ATA (prod) and Parallel ATA (experimental) drivers
-CONFIG_ATA=y
-CONFIG_SATA_VIA=y
-
-#      Network device support
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_NETDEV_1000=y
-#      Wireless LAN
-CONFIG_WLAN_80211=n
-CONFIG_RT2X00=n
-CONFIG_RT73USB=n
-
-#      Input device support
-CONFIG_INPUT_EVDEV=m
-#      Keyboards
-CONFIG_KEYBOARD_GPIO=m
-
-#      I2C support
-CONFIG_I2C=y
-CONFIG_I2C_PUV3=y
-
-#      Hardware Monitoring support
-#CONFIG_SENSORS_LM75=m
-#      Generic Thermal sysfs driver
-#CONFIG_THERMAL=y
-#CONFIG_THERMAL_HWMON=y
-
-#      Multimedia support
-CONFIG_MEDIA_SUPPORT=n
-CONFIG_VIDEO_DEV=n
-CONFIG_USB_VIDEO_CLASS=n
-
-#      Graphics support
-CONFIG_FB=y
-CONFIG_FB_PUV3_UNIGFX=y
-#      Console display driver support
-CONFIG_VGA_CONSOLE=n
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FONTS=y
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-#      Bootup logo
-CONFIG_LOGO=n
-
-#      Sound card support
-CONFIG_SOUND=m
-#      Advanced Linux Sound Architecture
-CONFIG_SND=m
-CONFIG_SND_MIXER_OSS=m
-CONFIG_SND_PCM_OSS=m
-
-#      USB support
-CONFIG_USB_ARCH_HAS_HCD=n
-CONFIG_USB=n
-CONFIG_USB_PRINTER=n
-CONFIG_USB_STORAGE=n
-#      Inventra Highspeed Dual Role Controller
-CONFIG_USB_MUSB_HDRC=n
-
-#      LED Support
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-#      LED Triggers
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_TIMER=y
-CONFIG_LEDS_TRIGGER_DISK=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-
-#      Real Time Clock
-CONFIG_RTC_LIB=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_PUV3=y
-
-### File systems
-CONFIG_EXT2_FS=m
-CONFIG_EXT3_FS=y
-CONFIG_EXT4_FS=y
-CONFIG_FUSE_FS=m
-#      CD-ROM/DVD Filesystems
-CONFIG_ISO9660_FS=m
-CONFIG_JOLIET=y
-CONFIG_UDF_FS=m
-#      DOS/FAT/NT Filesystems
-CONFIG_VFAT_FS=m
-#      Pseudo filesystems
-CONFIG_PROC_FS=y
-CONFIG_SYSFS=y
-CONFIG_TMPFS=y
-#      Miscellaneous filesystems
-CONFIG_MISC_FILESYSTEMS=y
-CONFIG_JFFS2_FS=m
-CONFIG_UBIFS_FS=m
-#      Network File Systems
-CONFIG_NETWORK_FILESYSTEMS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_ROOT_NFS=y
-#      Partition Types
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_MSDOS_PARTITION=y
-#      Native language support
-CONFIG_NLS=y
-CONFIG_NLS_CODEPAGE_437=m
-CONFIG_NLS_CODEPAGE_936=m
-CONFIG_NLS_ISO8859_1=m
-CONFIG_NLS_UTF8=m
-
-### Kernel hacking
-CONFIG_FRAME_WARN=8096
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_PROVE_LOCKING=n
-CONFIG_DEBUG_BUGVERBOSE=y
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_LL=y
-
index ec64834..3f0903b 100644 (file)
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 
+#define __HAVE_ARCH_PTE_ALLOC_ONE_KERNEL
+#define __HAVE_ARCH_PTE_ALLOC_ONE
+#include <asm-generic/pgalloc.h>
+
 #define check_pgt_cache()              do { } while (0)
 
 #define _PAGE_USER_TABLE       (PMD_TYPE_TABLE | PMD_PRESENT)
@@ -25,17 +29,14 @@ extern void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd);
 #define pgd_alloc(mm)                  get_pgd_slow(mm)
 #define pgd_free(mm, pgd)              free_pgd_slow(mm, pgd)
 
-#define PGALLOC_GFP    (GFP_KERNEL | __GFP_ZERO)
-
 /*
  * Allocate one PTE table.
  */
 static inline pte_t *
 pte_alloc_one_kernel(struct mm_struct *mm)
 {
-       pte_t *pte;
+       pte_t *pte = __pte_alloc_one_kernel(mm);
 
-       pte = (pte_t *)__get_free_page(PGALLOC_GFP);
        if (pte)
                clean_dcache_area(pte, PTRS_PER_PTE * sizeof(pte_t));
 
@@ -47,35 +48,14 @@ pte_alloc_one(struct mm_struct *mm)
 {
        struct page *pte;
 
-       pte = alloc_pages(PGALLOC_GFP, 0);
+       pte = __pte_alloc_one(mm, GFP_PGTABLE_USER);
        if (!pte)
                return NULL;
-       if (!PageHighMem(pte)) {
-               void *page = page_address(pte);
-               clean_dcache_area(page, PTRS_PER_PTE * sizeof(pte_t));
-       }
-       if (!pgtable_page_ctor(pte)) {
-               __free_page(pte);
-       }
-
+       if (!PageHighMem(pte))
+               clean_pte_table(page_address(pte));
        return pte;
 }
 
-/*
- * Free one PTE table.
- */
-static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
-{
-       if (pte)
-               free_page((unsigned long)pte);
-}
-
-static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
-{
-       pgtable_page_dtor(pte);
-       __free_page(pte);
-}
-
 static inline void __pmd_populate(pmd_t *pmdp, unsigned long pmdval)
 {
        set_pmd(pmdp, __pmd(pmdval));
index 806350e..5fc701e 100644 (file)
@@ -32,7 +32,7 @@
  */
 #define GPIO_GEDR      (PKUNITY_GPIO_BASE + 0x0018)
 /*
- * Sepcial Voltage Detect Reg GPIO_GPIR.
+ * Special Voltage Detect Reg GPIO_GPIR.
  */
 #define GPIO_GPIR      (PKUNITY_GPIO_BASE + 0x0020)
 
index dce10b1..9df2d1c 100644 (file)
@@ -123,6 +123,7 @@ config X86
        select GENERIC_STRNLEN_USER
        select GENERIC_TIME_VSYSCALL
        select GENERIC_GETTIMEOFDAY
+       select GUP_GET_PTE_LOW_HIGH             if X86_PAE
        select HARDLOCKUP_CHECK_TIMESTAMP       if X86_64
        select HAVE_ACPI_APEI                   if ACPI
        select HAVE_ACPI_APEI_NMI               if ACPI
@@ -158,6 +159,7 @@ config X86
        select HAVE_EFFICIENT_UNALIGNED_ACCESS
        select HAVE_EISA
        select HAVE_EXIT_THREAD
+       select HAVE_FAST_GUP
        select HAVE_FENTRY                      if X86_64 || DYNAMIC_FTRACE
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_FUNCTION_GRAPH_TRACER
@@ -2906,9 +2908,6 @@ config HAVE_ATOMIC_IOMAP
 config X86_DEV_DMA_OPS
        bool
 
-config HAVE_GENERIC_GUP
-       def_bool y
-
 source "drivers/firmware/Kconfig"
 
 source "arch/x86/kvm/Kconfig"
index 1285e5a..90b4732 100644 (file)
@@ -1189,7 +1189,7 @@ common_spurious:
        movl    %esp, %eax
        call    smp_spurious_interrupt
        jmp     ret_from_intr
-ENDPROC(common_interrupt)
+ENDPROC(common_spurious)
 #endif
 
 /*
index 629d1ee..1cee100 100644 (file)
@@ -358,7 +358,7 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
                put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
 
                /* Create the ucontext.  */
-               if (boot_cpu_has(X86_FEATURE_XSAVE))
+               if (static_cpu_has(X86_FEATURE_XSAVE))
                        put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
                else
                        put_user_ex(0, &frame->uc.uc_flags);
index 8e790ec..ba15d53 100644 (file)
 #define CONST_MASK_ADDR(nr, addr)      WBYTE_ADDR((void *)(addr) + ((nr)>>3))
 #define CONST_MASK(nr)                 (1 << ((nr) & 7))
 
-/**
- * set_bit - Atomically set a bit in memory
- * @nr: the bit to set
- * @addr: the address to start counting from
- *
- * This function is atomic and may not be reordered.  See __set_bit()
- * if you do not require the atomic guarantees.
- *
- * Note: there are no guarantees that this function will not be reordered
- * on non x86 architectures, so if you are writing portable code,
- * make sure not to rely on its reordering guarantees.
- *
- * Note that @nr may be almost arbitrarily large; this function is not
- * restricted to acting on a single-word quantity.
- */
 static __always_inline void
-set_bit(long nr, volatile unsigned long *addr)
+arch_set_bit(long nr, volatile unsigned long *addr)
 {
        if (IS_IMMEDIATE(nr)) {
                asm volatile(LOCK_PREFIX "orb %1,%0"
@@ -78,32 +63,14 @@ set_bit(long nr, volatile unsigned long *addr)
        }
 }
 
-/**
- * __set_bit - Set a bit in memory
- * @nr: the bit to set
- * @addr: the address to start counting from
- *
- * Unlike set_bit(), this function is non-atomic and may be reordered.
- * If it's called on the same region of memory simultaneously, the effect
- * may be that only one operation succeeds.
- */
-static __always_inline void __set_bit(long nr, volatile unsigned long *addr)
+static __always_inline void
+arch___set_bit(long nr, volatile unsigned long *addr)
 {
        asm volatile(__ASM_SIZE(bts) " %1,%0" : : ADDR, "Ir" (nr) : "memory");
 }
 
-/**
- * clear_bit - Clears a bit in memory
- * @nr: Bit to clear
- * @addr: Address to start counting from
- *
- * clear_bit() is atomic and may not be reordered.  However, it does
- * not contain a memory barrier, so if it is used for locking purposes,
- * you should call smp_mb__before_atomic() and/or smp_mb__after_atomic()
- * in order to ensure changes are visible on other processors.
- */
 static __always_inline void
-clear_bit(long nr, volatile unsigned long *addr)
+arch_clear_bit(long nr, volatile unsigned long *addr)
 {
        if (IS_IMMEDIATE(nr)) {
                asm volatile(LOCK_PREFIX "andb %1,%0"
@@ -115,26 +82,21 @@ clear_bit(long nr, volatile unsigned long *addr)
        }
 }
 
-/*
- * clear_bit_unlock - Clears a bit in memory
- * @nr: Bit to clear
- * @addr: Address to start counting from
- *
- * clear_bit() is atomic and implies release semantics before the memory
- * operation. It can be used for an unlock.
- */
-static __always_inline void clear_bit_unlock(long nr, volatile unsigned long *addr)
+static __always_inline void
+arch_clear_bit_unlock(long nr, volatile unsigned long *addr)
 {
        barrier();
-       clear_bit(nr, addr);
+       arch_clear_bit(nr, addr);
 }
 
-static __always_inline void __clear_bit(long nr, volatile unsigned long *addr)
+static __always_inline void
+arch___clear_bit(long nr, volatile unsigned long *addr)
 {
        asm volatile(__ASM_SIZE(btr) " %1,%0" : : ADDR, "Ir" (nr) : "memory");
 }
 
-static __always_inline bool clear_bit_unlock_is_negative_byte(long nr, volatile unsigned long *addr)
+static __always_inline bool
+arch_clear_bit_unlock_is_negative_byte(long nr, volatile unsigned long *addr)
 {
        bool negative;
        asm volatile(LOCK_PREFIX "andb %2,%1"
@@ -143,48 +105,23 @@ static __always_inline bool clear_bit_unlock_is_negative_byte(long nr, volatile
                : "ir" ((char) ~(1 << nr)) : "memory");
        return negative;
 }
+#define arch_clear_bit_unlock_is_negative_byte                                 \
+       arch_clear_bit_unlock_is_negative_byte
 
-// Let everybody know we have it
-#define clear_bit_unlock_is_negative_byte clear_bit_unlock_is_negative_byte
-
-/*
- * __clear_bit_unlock - Clears a bit in memory
- * @nr: Bit to clear
- * @addr: Address to start counting from
- *
- * __clear_bit() is non-atomic and implies release semantics before the memory
- * operation. It can be used for an unlock if no other CPUs can concurrently
- * modify other bits in the word.
- */
-static __always_inline void __clear_bit_unlock(long nr, volatile unsigned long *addr)
+static __always_inline void
+arch___clear_bit_unlock(long nr, volatile unsigned long *addr)
 {
-       __clear_bit(nr, addr);
+       arch___clear_bit(nr, addr);
 }
 
-/**
- * __change_bit - Toggle a bit in memory
- * @nr: the bit to change
- * @addr: the address to start counting from
- *
- * Unlike change_bit(), this function is non-atomic and may be reordered.
- * If it's called on the same region of memory simultaneously, the effect
- * may be that only one operation succeeds.
- */
-static __always_inline void __change_bit(long nr, volatile unsigned long *addr)
+static __always_inline void
+arch___change_bit(long nr, volatile unsigned long *addr)
 {
        asm volatile(__ASM_SIZE(btc) " %1,%0" : : ADDR, "Ir" (nr) : "memory");
 }
 
-/**
- * change_bit - Toggle a bit in memory
- * @nr: Bit to change
- * @addr: Address to start counting from
- *
- * change_bit() is atomic and may not be reordered.
- * Note that @nr may be almost arbitrarily large; this function is not
- * restricted to acting on a single-word quantity.
- */
-static __always_inline void change_bit(long nr, volatile unsigned long *addr)
+static __always_inline void
+arch_change_bit(long nr, volatile unsigned long *addr)
 {
        if (IS_IMMEDIATE(nr)) {
                asm volatile(LOCK_PREFIX "xorb %1,%0"
@@ -196,42 +133,20 @@ static __always_inline void change_bit(long nr, volatile unsigned long *addr)
        }
 }
 
-/**
- * test_and_set_bit - Set a bit and return its old value
- * @nr: Bit to set
- * @addr: Address to count from
- *
- * This operation is atomic and cannot be reordered.
- * It also implies a memory barrier.
- */
-static __always_inline bool test_and_set_bit(long nr, volatile unsigned long *addr)
+static __always_inline bool
+arch_test_and_set_bit(long nr, volatile unsigned long *addr)
 {
        return GEN_BINARY_RMWcc(LOCK_PREFIX __ASM_SIZE(bts), *addr, c, "Ir", nr);
 }
 
-/**
- * test_and_set_bit_lock - Set a bit and return its old value for lock
- * @nr: Bit to set
- * @addr: Address to count from
- *
- * This is the same as test_and_set_bit on x86.
- */
 static __always_inline bool
-test_and_set_bit_lock(long nr, volatile unsigned long *addr)
+arch_test_and_set_bit_lock(long nr, volatile unsigned long *addr)
 {
-       return test_and_set_bit(nr, addr);
+       return arch_test_and_set_bit(nr, addr);
 }
 
-/**
- * __test_and_set_bit - Set a bit and return its old value
- * @nr: Bit to set
- * @addr: Address to count from
- *
- * This operation is non-atomic and can be reordered.
- * If two examples of this operation race, one can appear to succeed
- * but actually fail.  You must protect multiple accesses with a lock.
- */
-static __always_inline bool __test_and_set_bit(long nr, volatile unsigned long *addr)
+static __always_inline bool
+arch___test_and_set_bit(long nr, volatile unsigned long *addr)
 {
        bool oldbit;
 
@@ -242,28 +157,13 @@ static __always_inline bool __test_and_set_bit(long nr, volatile unsigned long *
        return oldbit;
 }
 
-/**
- * test_and_clear_bit - Clear a bit and return its old value
- * @nr: Bit to clear
- * @addr: Address to count from
- *
- * This operation is atomic and cannot be reordered.
- * It also implies a memory barrier.
- */
-static __always_inline bool test_and_clear_bit(long nr, volatile unsigned long *addr)
+static __always_inline bool
+arch_test_and_clear_bit(long nr, volatile unsigned long *addr)
 {
        return GEN_BINARY_RMWcc(LOCK_PREFIX __ASM_SIZE(btr), *addr, c, "Ir", nr);
 }
 
-/**
- * __test_and_clear_bit - Clear a bit and return its old value
- * @nr: Bit to clear
- * @addr: Address to count from
- *
- * This operation is non-atomic and can be reordered.
- * If two examples of this operation race, one can appear to succeed
- * but actually fail.  You must protect multiple accesses with a lock.
- *
+/*
  * Note: the operation is performed atomically with respect to
  * the local CPU, but not other CPUs. Portable code should not
  * rely on this behaviour.
@@ -271,7 +171,8 @@ static __always_inline bool test_and_clear_bit(long nr, volatile unsigned long *
  * accessed from a hypervisor on the same CPU if running in a VM: don't change
  * this without also updating arch/x86/kernel/kvm.c
  */
-static __always_inline bool __test_and_clear_bit(long nr, volatile unsigned long *addr)
+static __always_inline bool
+arch___test_and_clear_bit(long nr, volatile unsigned long *addr)
 {
        bool oldbit;
 
@@ -282,8 +183,8 @@ static __always_inline bool __test_and_clear_bit(long nr, volatile unsigned long
        return oldbit;
 }
 
-/* WARNING: non atomic and it can be reordered! */
-static __always_inline bool __test_and_change_bit(long nr, volatile unsigned long *addr)
+static __always_inline bool
+arch___test_and_change_bit(long nr, volatile unsigned long *addr)
 {
        bool oldbit;
 
@@ -295,15 +196,8 @@ static __always_inline bool __test_and_change_bit(long nr, volatile unsigned lon
        return oldbit;
 }
 
-/**
- * test_and_change_bit - Change a bit and return its old value
- * @nr: Bit to change
- * @addr: Address to count from
- *
- * This operation is atomic and cannot be reordered.
- * It also implies a memory barrier.
- */
-static __always_inline bool test_and_change_bit(long nr, volatile unsigned long *addr)
+static __always_inline bool
+arch_test_and_change_bit(long nr, volatile unsigned long *addr)
 {
        return GEN_BINARY_RMWcc(LOCK_PREFIX __ASM_SIZE(btc), *addr, c, "Ir", nr);
 }
@@ -326,16 +220,7 @@ static __always_inline bool variable_test_bit(long nr, volatile const unsigned l
        return oldbit;
 }
 
-#if 0 /* Fool kernel-doc since it doesn't do macros yet */
-/**
- * test_bit - Determine whether a bit is set
- * @nr: bit number to test
- * @addr: Address to start counting from
- */
-static bool test_bit(int nr, const volatile unsigned long *addr);
-#endif
-
-#define test_bit(nr, addr)                     \
+#define arch_test_bit(nr, addr)                        \
        (__builtin_constant_p((nr))             \
         ? constant_test_bit((nr), (addr))      \
         : variable_test_bit((nr), (addr)))
@@ -504,6 +389,8 @@ static __always_inline int fls64(__u64 x)
 
 #include <asm-generic/bitops/const_hweight.h>
 
+#include <asm-generic/bitops-instrumented.h>
+
 #include <asm-generic/bitops/le.h>
 
 #include <asm-generic/bitops/ext2-atomic-setbit.h>
index 26d1eb8..0cc5b61 100644 (file)
@@ -686,6 +686,7 @@ struct kvm_vcpu_arch {
        u32 virtual_tsc_mult;
        u32 virtual_tsc_khz;
        s64 ia32_tsc_adjust_msr;
+       u64 msr_ia32_power_ctl;
        u64 tsc_scaling_ratio;
 
        atomic_t nmi_queued;  /* unprocessed asynchronous NMIs */
@@ -752,6 +753,8 @@ struct kvm_vcpu_arch {
                struct gfn_to_hva_cache data;
        } pv_eoi;
 
+       u64 msr_kvm_poll_control;
+
        /*
         * Indicate whether the access faults on its page table in guest
         * which is set when fix page fault and used to detect unhandeable
@@ -879,6 +882,7 @@ struct kvm_arch {
        bool mwait_in_guest;
        bool hlt_in_guest;
        bool pause_in_guest;
+       bool cstate_in_guest;
 
        unsigned long irq_sources_bitmap;
        s64 kvmclock_offset;
@@ -926,6 +930,8 @@ struct kvm_arch {
 
        bool guest_can_read_msr_platform_info;
        bool exception_payload_enabled;
+
+       struct kvm_pmu_event_filter *pmu_event_filter;
 };
 
 struct kvm_vm_stat {
@@ -996,7 +1002,7 @@ struct kvm_x86_ops {
        int (*disabled_by_bios)(void);             /* __init */
        int (*hardware_enable)(void);
        void (*hardware_disable)(void);
-       void (*check_processor_compatibility)(void *rtn);
+       int (*check_processor_compatibility)(void);/* __init */
        int (*hardware_setup)(void);               /* __init */
        void (*hardware_unsetup)(void);            /* __exit */
        bool (*cpu_has_accelerated_tpr)(void);
@@ -1110,7 +1116,7 @@ struct kvm_x86_ops {
        int (*check_intercept)(struct kvm_vcpu *vcpu,
                               struct x86_instruction_info *info,
                               enum x86_intercept_stage stage);
-       void (*handle_external_intr)(struct kvm_vcpu *vcpu);
+       void (*handle_exit_irqoff)(struct kvm_vcpu *vcpu);
        bool (*mpx_supported)(void);
        bool (*xsaves_supported)(void);
        bool (*umip_emulated)(void);
@@ -1529,7 +1535,6 @@ int kvm_pv_send_ipi(struct kvm *kvm, unsigned long ipi_bitmap_low,
                    unsigned long ipi_bitmap_high, u32 min,
                    unsigned long icr, int op_64_bit);
 
-u64 kvm_get_arch_capabilities(void);
 void kvm_define_shared_msr(unsigned index, u32 msr);
 int kvm_set_shared_msr(unsigned index, u64 val, u64 mask);
 
index 5ff3e8a..e78c7db 100644 (file)
@@ -59,6 +59,7 @@ typedef struct {
 #define INIT_MM_CONTEXT(mm)                                            \
        .context = {                                                    \
                .ctx_id = 1,                                            \
+               .lock = __MUTEX_INITIALIZER(mm.context.lock),           \
        }
 
 void leave_mm(int cpu);
index f4fa8a9..2ef31cc 100644 (file)
@@ -3,84 +3,15 @@
 #define _ASM_X86_MSHYPER_H
 
 #include <linux/types.h>
-#include <linux/atomic.h>
 #include <linux/nmi.h>
 #include <asm/io.h>
 #include <asm/hyperv-tlfs.h>
 #include <asm/nospec-branch.h>
 
-#define VP_INVAL       U32_MAX
-
-struct ms_hyperv_info {
-       u32 features;
-       u32 misc_features;
-       u32 hints;
-       u32 nested_features;
-       u32 max_vp_index;
-       u32 max_lp_index;
-};
-
-extern struct ms_hyperv_info ms_hyperv;
-
-
 typedef int (*hyperv_fill_flush_list_func)(
                struct hv_guest_mapping_flush_list *flush,
                void *data);
 
-/*
- * Generate the guest ID.
- */
-
-static inline  __u64 generate_guest_id(__u64 d_info1, __u64 kernel_version,
-                                      __u64 d_info2)
-{
-       __u64 guest_id = 0;
-
-       guest_id = (((__u64)HV_LINUX_VENDOR_ID) << 48);
-       guest_id |= (d_info1 << 48);
-       guest_id |= (kernel_version << 16);
-       guest_id |= d_info2;
-
-       return guest_id;
-}
-
-
-/* Free the message slot and signal end-of-message if required */
-static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type)
-{
-       /*
-        * On crash we're reading some other CPU's message page and we need
-        * to be careful: this other CPU may already had cleared the header
-        * and the host may already had delivered some other message there.
-        * In case we blindly write msg->header.message_type we're going
-        * to lose it. We can still lose a message of the same type but
-        * we count on the fact that there can only be one
-        * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages
-        * on crash.
-        */
-       if (cmpxchg(&msg->header.message_type, old_msg_type,
-                   HVMSG_NONE) != old_msg_type)
-               return;
-
-       /*
-        * Make sure the write to MessageType (ie set to
-        * HVMSG_NONE) happens before we read the
-        * MessagePending and EOMing. Otherwise, the EOMing
-        * will not deliver any more messages since there is
-        * no empty slot
-        */
-       mb();
-
-       if (msg->header.message_flags.msg_pending) {
-               /*
-                * This will cause message queue rescan to
-                * possibly deliver another msg from the
-                * hypervisor
-                */
-               wrmsrl(HV_X64_MSR_EOM, 0);
-       }
-}
-
 #define hv_init_timer(timer, tick) \
        wrmsrl(HV_X64_MSR_STIMER0_COUNT + (2*timer), tick)
 #define hv_init_timer_config(timer, val) \
@@ -97,6 +28,8 @@ static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type)
 
 #define hv_get_vp_index(index) rdmsrl(HV_X64_MSR_VP_INDEX, index)
 
+#define hv_signal_eom() wrmsrl(HV_X64_MSR_EOM, 0)
+
 #define hv_get_synint_state(int_num, val) \
        rdmsrl(HV_X64_MSR_SINT0 + int_num, val)
 #define hv_set_synint_state(int_num, val) \
@@ -122,13 +55,6 @@ void hyperv_reenlightenment_vector(void);
 #define trace_hyperv_callback_vector hyperv_callback_vector
 #endif
 void hyperv_vector_handler(struct pt_regs *regs);
-void hv_setup_vmbus_irq(void (*handler)(void));
-void hv_remove_vmbus_irq(void);
-
-void hv_setup_kexec_handler(void (*handler)(void));
-void hv_remove_kexec_handler(void);
-void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs));
-void hv_remove_crash_handler(void);
 
 /*
  * Routines for stimer0 Direct Mode handling.
@@ -136,8 +62,6 @@ void hv_remove_crash_handler(void);
  */
 void hv_stimer0_vector_handler(struct pt_regs *regs);
 void hv_stimer0_callback_vector(void);
-int hv_setup_stimer0_irq(int *irq, int *vector, void (*handler)(void));
-void hv_remove_stimer0_irq(int irq);
 
 static inline void hv_enable_stimer0_percpu_irq(int irq) {}
 static inline void hv_disable_stimer0_percpu_irq(int irq) {}
@@ -282,14 +206,6 @@ static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size,
        return status;
 }
 
-/*
- * Hypervisor's notion of virtual processor ID is different from
- * Linux' notion of CPU ID. This information can only be retrieved
- * in the context of the calling CPU. Setup a map for easy access
- * to this information.
- */
-extern u32 *hv_vp_index;
-extern u32 hv_max_vp_index;
 extern struct hv_vp_assist_page **hv_vp_assist_page;
 
 static inline struct hv_vp_assist_page *hv_get_vp_assist_page(unsigned int cpu)
@@ -300,63 +216,8 @@ static inline struct hv_vp_assist_page *hv_get_vp_assist_page(unsigned int cpu)
        return hv_vp_assist_page[cpu];
 }
 
-/**
- * hv_cpu_number_to_vp_number() - Map CPU to VP.
- * @cpu_number: CPU number in Linux terms
- *
- * This function returns the mapping between the Linux processor
- * number and the hypervisor's virtual processor number, useful
- * in making hypercalls and such that talk about specific
- * processors.
- *
- * Return: Virtual processor number in Hyper-V terms
- */
-static inline int hv_cpu_number_to_vp_number(int cpu_number)
-{
-       return hv_vp_index[cpu_number];
-}
-
-static inline int cpumask_to_vpset(struct hv_vpset *vpset,
-                                   const struct cpumask *cpus)
-{
-       int cpu, vcpu, vcpu_bank, vcpu_offset, nr_bank = 1;
-
-       /* valid_bank_mask can represent up to 64 banks */
-       if (hv_max_vp_index / 64 >= 64)
-               return 0;
-
-       /*
-        * Clear all banks up to the maximum possible bank as hv_tlb_flush_ex
-        * structs are not cleared between calls, we risk flushing unneeded
-        * vCPUs otherwise.
-        */
-       for (vcpu_bank = 0; vcpu_bank <= hv_max_vp_index / 64; vcpu_bank++)
-               vpset->bank_contents[vcpu_bank] = 0;
-
-       /*
-        * Some banks may end up being empty but this is acceptable.
-        */
-       for_each_cpu(cpu, cpus) {
-               vcpu = hv_cpu_number_to_vp_number(cpu);
-               if (vcpu == VP_INVAL)
-                       return -1;
-               vcpu_bank = vcpu / 64;
-               vcpu_offset = vcpu % 64;
-               __set_bit(vcpu_offset, (unsigned long *)
-                         &vpset->bank_contents[vcpu_bank]);
-               if (vcpu_bank >= nr_bank)
-                       nr_bank = vcpu_bank + 1;
-       }
-       vpset->valid_bank_mask = GENMASK_ULL(nr_bank - 1, 0);
-       return nr_bank;
-}
-
 void __init hyperv_init(void);
 void hyperv_setup_mmu_ops(void);
-void hyperv_report_panic(struct pt_regs *regs, long err);
-void hyperv_report_panic_msg(phys_addr_t pa, size_t size);
-bool hv_is_hyperv_initialized(void);
-void hyperv_cleanup(void);
 
 void hyperv_reenlightenment_intr(struct pt_regs *regs);
 void set_hv_tscchange_cb(void (*cb)(void));
@@ -379,8 +240,6 @@ static inline void hv_apic_init(void) {}
 
 #else /* CONFIG_HYPERV */
 static inline void hyperv_init(void) {}
-static inline bool hv_is_hyperv_initialized(void) { return false; }
-static inline void hyperv_cleanup(void) {}
 static inline void hyperv_setup_mmu_ops(void) {}
 static inline void set_hv_tscchange_cb(void (*cb)(void)) {}
 static inline void clear_hv_tscchange_cb(void) {}
@@ -397,4 +256,7 @@ static inline int hyperv_flush_guest_mapping_range(u64 as,
 }
 #endif /* CONFIG_HYPERV */
 
+
+#include <asm-generic/mshyperv.h>
+
 #endif
index a281e61..29aa785 100644 (file)
@@ -6,6 +6,9 @@
 #include <linux/mm.h>          /* for struct page */
 #include <linux/pagemap.h>
 
+#define __HAVE_ARCH_PTE_ALLOC_ONE
+#include <asm-generic/pgalloc.h>       /* for pte_{alloc,free}_one */
+
 static inline int  __paravirt_pgd_alloc(struct mm_struct *mm) { return 0; }
 
 #ifdef CONFIG_PARAVIRT_XXL
@@ -47,24 +50,8 @@ extern gfp_t __userpte_alloc_gfp;
 extern pgd_t *pgd_alloc(struct mm_struct *);
 extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
 
-extern pte_t *pte_alloc_one_kernel(struct mm_struct *);
 extern pgtable_t pte_alloc_one(struct mm_struct *);
 
-/* Should really implement gc for free page table pages. This could be
-   done with a reference count in struct page. */
-
-static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
-{
-       BUG_ON((unsigned long)pte & (PAGE_SIZE-1));
-       free_page((unsigned long)pte);
-}
-
-static inline void pte_free(struct mm_struct *mm, struct page *pte)
-{
-       pgtable_page_dtor(pte);
-       __free_page(pte);
-}
-
 extern void ___pte_free_tlb(struct mmu_gather *tlb, struct page *pte);
 
 static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte,
index f8b1ad2..e363379 100644 (file)
@@ -285,53 +285,6 @@ static inline pud_t native_pudp_get_and_clear(pud_t *pudp)
 #define __pte_to_swp_entry(pte)        (__swp_entry(__pteval_swp_type(pte), \
                                             __pteval_swp_offset(pte)))
 
-#define gup_get_pte gup_get_pte
-/*
- * WARNING: only to be used in the get_user_pages_fast() implementation.
- *
- * With get_user_pages_fast(), we walk down the pagetables without taking
- * any locks.  For this we would like to load the pointers atomically,
- * but that is not possible (without expensive cmpxchg8b) on PAE.  What
- * we do have is the guarantee that a PTE will only either go from not
- * present to present, or present to not present or both -- it will not
- * switch to a completely different present page without a TLB flush in
- * between; something that we are blocking by holding interrupts off.
- *
- * Setting ptes from not present to present goes:
- *
- *   ptep->pte_high = h;
- *   smp_wmb();
- *   ptep->pte_low = l;
- *
- * And present to not present goes:
- *
- *   ptep->pte_low = 0;
- *   smp_wmb();
- *   ptep->pte_high = 0;
- *
- * We must ensure here that the load of pte_low sees 'l' iff pte_high
- * sees 'h'. We load pte_high *after* loading pte_low, which ensures we
- * don't see an older value of pte_high.  *Then* we recheck pte_low,
- * which ensures that we haven't picked up a changed pte high. We might
- * have gotten rubbish values from pte_low and pte_high, but we are
- * guaranteed that pte_low will not have the present bit set *unless*
- * it is 'l'. Because get_user_pages_fast() only operates on present ptes
- * we're safe.
- */
-static inline pte_t gup_get_pte(pte_t *ptep)
-{
-       pte_t pte;
-
-       do {
-               pte.pte_low = ptep->pte_low;
-               smp_rmb();
-               pte.pte_high = ptep->pte_high;
-               smp_rmb();
-       } while (unlikely(pte.pte_low != ptep->pte_low));
-
-       return pte;
-}
-
 #include <asm/pgtable-invert.h>
 
 #endif /* _ASM_X86_PGTABLE_3LEVEL_H */
index 4fe9e7f..c78da8e 100644 (file)
@@ -106,6 +106,6 @@ do {                                                \
  * with only a host target support using a 32-bit type for internal
  * representation.
  */
-#define LOWMEM_PAGES ((((2<<31) - __PAGE_OFFSET) >> PAGE_SHIFT))
+#define LOWMEM_PAGES ((((_ULL(2)<<31) - __PAGE_OFFSET) >> PAGE_SHIFT))
 
 #endif /* _ASM_X86_PGTABLE_32_H */
index 0bb5663..4990d26 100644 (file)
@@ -259,14 +259,8 @@ extern void init_extra_mapping_uc(unsigned long phys, unsigned long size);
 extern void init_extra_mapping_wb(unsigned long phys, unsigned long size);
 
 #define gup_fast_permitted gup_fast_permitted
-static inline bool gup_fast_permitted(unsigned long start, int nr_pages)
+static inline bool gup_fast_permitted(unsigned long start, unsigned long end)
 {
-       unsigned long len, end;
-
-       len = (unsigned long)nr_pages << PAGE_SHIFT;
-       end = start + len;
-       if (end < start)
-               return false;
        if (end >> __VIRTUAL_MASK_SHIFT)
                return false;
        return true;
index 3eab6ec..6e0a3b4 100644 (file)
@@ -741,6 +741,7 @@ extern void load_direct_gdt(int);
 extern void load_fixmap_gdt(int);
 extern void load_percpu_segment(int);
 extern void cpu_init(void);
+extern void cr4_init(void);
 
 static inline unsigned long get_debugctlmsr(void)
 {
index 78cf265..332eb35 100644 (file)
@@ -98,7 +98,6 @@ struct cpuinfo_x86;
 struct task_struct;
 
 extern unsigned long profile_pc(struct pt_regs *regs);
-#define profile_pc profile_pc
 
 extern unsigned long
 convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs);
@@ -170,11 +169,32 @@ static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
        return regs->sp;
 }
 
-#define GET_IP(regs) ((regs)->ip)
-#define GET_FP(regs) ((regs)->bp)
-#define GET_USP(regs) ((regs)->sp)
+static inline unsigned long instruction_pointer(struct pt_regs *regs)
+{
+       return regs->ip;
+}
+
+static inline void instruction_pointer_set(struct pt_regs *regs,
+               unsigned long val)
+{
+       regs->ip = val;
+}
+
+static inline unsigned long frame_pointer(struct pt_regs *regs)
+{
+       return regs->bp;
+}
 
-#include <asm-generic/ptrace.h>
+static inline unsigned long user_stack_pointer(struct pt_regs *regs)
+{
+       return regs->sp;
+}
+
+static inline void user_stack_pointer_set(struct pt_regs *regs,
+               unsigned long val)
+{
+       regs->sp = val;
+}
 
 /* Query offset/name of register from its name/offset */
 extern int regs_query_register_offset(const char *name);
index b2e84d1..219be88 100644 (file)
@@ -18,9 +18,7 @@
  */
 extern unsigned long __force_order;
 
-/* Starts false and gets enabled once CPU feature detection is done. */
-DECLARE_STATIC_KEY_FALSE(cr_pinning);
-extern unsigned long cr4_pinned_bits;
+void native_write_cr0(unsigned long val);
 
 static inline unsigned long native_read_cr0(void)
 {
@@ -29,24 +27,6 @@ static inline unsigned long native_read_cr0(void)
        return val;
 }
 
-static inline void native_write_cr0(unsigned long val)
-{
-       unsigned long bits_missing = 0;
-
-set_register:
-       asm volatile("mov %0,%%cr0": "+r" (val), "+m" (__force_order));
-
-       if (static_branch_likely(&cr_pinning)) {
-               if (unlikely((val & X86_CR0_WP) != X86_CR0_WP)) {
-                       bits_missing = X86_CR0_WP;
-                       val |= bits_missing;
-                       goto set_register;
-               }
-               /* Warn after we've set the missing bits. */
-               WARN_ONCE(bits_missing, "CR0 WP bit went missing!?\n");
-       }
-}
-
 static inline unsigned long native_read_cr2(void)
 {
        unsigned long val;
@@ -91,24 +71,7 @@ static inline unsigned long native_read_cr4(void)
        return val;
 }
 
-static inline void native_write_cr4(unsigned long val)
-{
-       unsigned long bits_missing = 0;
-
-set_register:
-       asm volatile("mov %0,%%cr4": "+r" (val), "+m" (cr4_pinned_bits));
-
-       if (static_branch_likely(&cr_pinning)) {
-               if (unlikely((val & cr4_pinned_bits) != cr4_pinned_bits)) {
-                       bits_missing = ~val & cr4_pinned_bits;
-                       val |= bits_missing;
-                       goto set_register;
-               }
-               /* Warn after we've set the missing bits. */
-               WARN_ONCE(bits_missing, "CR4 bits went missing: %lx!?\n",
-                         bits_missing);
-       }
-}
+void native_write_cr4(unsigned long val);
 
 #ifdef CONFIG_X86_64
 static inline unsigned long native_read_cr8(void)
index d6ab5b4..e901b0a 100644 (file)
@@ -378,10 +378,11 @@ struct kvm_sync_regs {
        struct kvm_vcpu_events events;
 };
 
-#define KVM_X86_QUIRK_LINT0_REENABLED  (1 << 0)
-#define KVM_X86_QUIRK_CD_NW_CLEARED    (1 << 1)
-#define KVM_X86_QUIRK_LAPIC_MMIO_HOLE  (1 << 2)
-#define KVM_X86_QUIRK_OUT_7E_INC_RIP   (1 << 3)
+#define KVM_X86_QUIRK_LINT0_REENABLED     (1 << 0)
+#define KVM_X86_QUIRK_CD_NW_CLEARED       (1 << 1)
+#define KVM_X86_QUIRK_LAPIC_MMIO_HOLE     (1 << 2)
+#define KVM_X86_QUIRK_OUT_7E_INC_RIP      (1 << 3)
+#define KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT (1 << 4)
 
 #define KVM_STATE_NESTED_FORMAT_VMX    0
 #define KVM_STATE_NESTED_FORMAT_SVM    1       /* unused */
@@ -432,4 +433,14 @@ struct kvm_nested_state {
        } data;
 };
 
+/* for KVM_CAP_PMU_EVENT_FILTER */
+struct kvm_pmu_event_filter {
+       __u32 action;
+       __u32 nevents;
+       __u64 events[0];
+};
+
+#define KVM_PMU_EVENT_ALLOW 0
+#define KVM_PMU_EVENT_DENY 1
+
 #endif /* _ASM_X86_KVM_H */
index 19980ec..2a8e0b6 100644 (file)
@@ -29,6 +29,8 @@
 #define KVM_FEATURE_PV_TLB_FLUSH       9
 #define KVM_FEATURE_ASYNC_PF_VMEXIT    10
 #define KVM_FEATURE_PV_SEND_IPI        11
+#define KVM_FEATURE_POLL_CONTROL       12
+#define KVM_FEATURE_PV_SCHED_YIELD     13
 
 #define KVM_HINTS_REALTIME      0
 
@@ -47,6 +49,7 @@
 #define MSR_KVM_ASYNC_PF_EN 0x4b564d02
 #define MSR_KVM_STEAL_TIME  0x4b564d03
 #define MSR_KVM_PV_EOI_EN      0x4b564d04
+#define MSR_KVM_POLL_CONTROL   0x4b564d05
 
 struct kvm_steal_time {
        __u64 steal;
index d213ec5..f0b0c90 100644 (file)
 
 #define VMX_ABORT_SAVE_GUEST_MSR_FAIL        1
 #define VMX_ABORT_LOAD_HOST_PDPTE_FAIL       2
-#define VMX_ABORT_VMCS_CORRUPTED             3
 #define VMX_ABORT_LOAD_HOST_MSR_FAIL         4
 
 #endif /* _UAPIVMX_H */
index 99ef8b6..ccd3201 100644 (file)
@@ -625,10 +625,23 @@ extern struct paravirt_patch_site __start_parainstructions[],
  *
  * See entry_{32,64}.S for more details.
  */
-static void __init int3_magic(unsigned int *ptr)
-{
-       *ptr = 1;
-}
+
+/*
+ * We define the int3_magic() function in assembly to control the calling
+ * convention such that we can 'call' it from assembly.
+ */
+
+extern void int3_magic(unsigned int *ptr); /* defined in asm */
+
+asm (
+"      .pushsection    .init.text, \"ax\", @progbits\n"
+"      .type           int3_magic, @function\n"
+"int3_magic:\n"
+"      movl    $1, (%" _ASM_ARG1 ")\n"
+"      ret\n"
+"      .size           int3_magic, .-int3_magic\n"
+"      .popsection\n"
+);
 
 extern __initdata unsigned long int3_selftest_ip; /* defined in asm below */
 
@@ -676,7 +689,9 @@ static void __init int3_selftest(void)
                      "int3_selftest_ip:\n\t"
                      __ASM_SEL(.long, .quad) " 1b\n\t"
                      ".popsection\n\t"
-                     : : __ASM_SEL_RAW(a, D) (&val) : "memory");
+                     : ASM_CALL_CONSTRAINT
+                     : __ASM_SEL_RAW(a, D) (&val)
+                     : "memory");
 
        BUG_ON(val != 1);
 
index 309b6b9..1147217 100644 (file)
@@ -366,10 +366,62 @@ out:
        cr4_clear_bits(X86_CR4_UMIP);
 }
 
-DEFINE_STATIC_KEY_FALSE_RO(cr_pinning);
-EXPORT_SYMBOL(cr_pinning);
-unsigned long cr4_pinned_bits __ro_after_init;
-EXPORT_SYMBOL(cr4_pinned_bits);
+static DEFINE_STATIC_KEY_FALSE_RO(cr_pinning);
+static unsigned long cr4_pinned_bits __ro_after_init;
+
+void native_write_cr0(unsigned long val)
+{
+       unsigned long bits_missing = 0;
+
+set_register:
+       asm volatile("mov %0,%%cr0": "+r" (val), "+m" (__force_order));
+
+       if (static_branch_likely(&cr_pinning)) {
+               if (unlikely((val & X86_CR0_WP) != X86_CR0_WP)) {
+                       bits_missing = X86_CR0_WP;
+                       val |= bits_missing;
+                       goto set_register;
+               }
+               /* Warn after we've set the missing bits. */
+               WARN_ONCE(bits_missing, "CR0 WP bit went missing!?\n");
+       }
+}
+EXPORT_SYMBOL(native_write_cr0);
+
+void native_write_cr4(unsigned long val)
+{
+       unsigned long bits_missing = 0;
+
+set_register:
+       asm volatile("mov %0,%%cr4": "+r" (val), "+m" (cr4_pinned_bits));
+
+       if (static_branch_likely(&cr_pinning)) {
+               if (unlikely((val & cr4_pinned_bits) != cr4_pinned_bits)) {
+                       bits_missing = ~val & cr4_pinned_bits;
+                       val |= bits_missing;
+                       goto set_register;
+               }
+               /* Warn after we've set the missing bits. */
+               WARN_ONCE(bits_missing, "CR4 bits went missing: %lx!?\n",
+                         bits_missing);
+       }
+}
+EXPORT_SYMBOL(native_write_cr4);
+
+void cr4_init(void)
+{
+       unsigned long cr4 = __read_cr4();
+
+       if (boot_cpu_has(X86_FEATURE_PCID))
+               cr4 |= X86_CR4_PCIDE;
+       if (static_branch_likely(&cr_pinning))
+               cr4 |= cr4_pinned_bits;
+
+       __write_cr4(cr4);
+
+       /* Initialize cr4 shadow for this CPU. */
+       this_cpu_write(cpu_tlbstate.cr4, cr4);
+}
 
 /*
  * Once CPU feature detection is finished (and boot params have been
@@ -1723,12 +1775,6 @@ void cpu_init(void)
 
        wait_for_master_cpu(cpu);
 
-       /*
-        * Initialize the CR4 shadow before doing anything that could
-        * try to read it.
-        */
-       cr4_init_shadow();
-
        if (cpu)
                load_ucode_ap();
 
@@ -1823,12 +1869,6 @@ void cpu_init(void)
 
        wait_for_master_cpu(cpu);
 
-       /*
-        * Initialize the CR4 shadow before doing anything that could
-        * try to read it.
-        */
-       cr4_init_shadow();
-
        show_ucode_info_early();
 
        pr_info("Initializing CPU#%d\n", cpu);
index 7670ac2..edaa30b 100644 (file)
@@ -67,33 +67,18 @@ static const struct file_operations fops_setup_data = {
        .llseek         = default_llseek,
 };
 
-static int __init
+static void __init
 create_setup_data_node(struct dentry *parent, int no,
                       struct setup_data_node *node)
 {
-       struct dentry *d, *type, *data;
+       struct dentry *d;
        char buf[16];
 
        sprintf(buf, "%d", no);
        d = debugfs_create_dir(buf, parent);
-       if (!d)
-               return -ENOMEM;
-
-       type = debugfs_create_x32("type", S_IRUGO, d, &node->type);
-       if (!type)
-               goto err_dir;
-
-       data = debugfs_create_file("data", S_IRUGO, d, node, &fops_setup_data);
-       if (!data)
-               goto err_type;
 
-       return 0;
-
-err_type:
-       debugfs_remove(type);
-err_dir:
-       debugfs_remove(d);
-       return -ENOMEM;
+       debugfs_create_x32("type", S_IRUGO, d, &node->type);
+       debugfs_create_file("data", S_IRUGO, d, node, &fops_setup_data);
 }
 
 static int __init create_setup_data_nodes(struct dentry *parent)
@@ -106,8 +91,6 @@ static int __init create_setup_data_nodes(struct dentry *parent)
        int no = 0;
 
        d = debugfs_create_dir("setup_data", parent);
-       if (!d)
-               return -ENOMEM;
 
        pa_data = boot_params.hdr.setup_data;
 
@@ -128,19 +111,17 @@ static int __init create_setup_data_nodes(struct dentry *parent)
                node->paddr = pa_data;
                node->type = data->type;
                node->len = data->len;
-               error = create_setup_data_node(d, no, node);
+               create_setup_data_node(d, no, node);
                pa_data = data->next;
 
                memunmap(data);
-               if (error)
-                       goto err_dir;
                no++;
        }
 
        return 0;
 
 err_dir:
-       debugfs_remove(d);
+       debugfs_remove_recursive(d);
        return error;
 }
 
@@ -151,35 +132,18 @@ static struct debugfs_blob_wrapper boot_params_blob = {
 
 static int __init boot_params_kdebugfs_init(void)
 {
-       struct dentry *dbp, *version, *data;
-       int error = -ENOMEM;
+       struct dentry *dbp;
+       int error;
 
        dbp = debugfs_create_dir("boot_params", arch_debugfs_dir);
-       if (!dbp)
-               return -ENOMEM;
-
-       version = debugfs_create_x16("version", S_IRUGO, dbp,
-                                    &boot_params.hdr.version);
-       if (!version)
-               goto err_dir;
 
-       data = debugfs_create_blob("data", S_IRUGO, dbp,
-                                  &boot_params_blob);
-       if (!data)
-               goto err_version;
+       debugfs_create_x16("version", S_IRUGO, dbp, &boot_params.hdr.version);
+       debugfs_create_blob("data", S_IRUGO, dbp, &boot_params_blob);
 
        error = create_setup_data_nodes(dbp);
        if (error)
-               goto err_data;
+               debugfs_remove_recursive(dbp);
 
-       return 0;
-
-err_data:
-       debugfs_remove(data);
-err_version:
-       debugfs_remove(version);
-err_dir:
-       debugfs_remove(dbp);
        return error;
 }
 #endif /* CONFIG_DEBUG_BOOT_PARAMS */
@@ -189,8 +153,6 @@ static int __init arch_kdebugfs_init(void)
        int error = 0;
 
        arch_debugfs_dir = debugfs_create_dir("x86", NULL);
-       if (!arch_debugfs_dir)
-               return -ENOMEM;
 
 #ifdef CONFIG_DEBUG_BOOT_PARAMS
        error = boot_params_kdebugfs_init();
index 5169b8c..82caf01 100644 (file)
@@ -527,6 +527,21 @@ static void kvm_setup_pv_ipi(void)
        pr_info("KVM setup pv IPIs\n");
 }
 
+static void kvm_smp_send_call_func_ipi(const struct cpumask *mask)
+{
+       int cpu;
+
+       native_send_call_func_ipi(mask);
+
+       /* Make sure other vCPUs get a chance to run if they need to. */
+       for_each_cpu(cpu, mask) {
+               if (vcpu_is_preempted(cpu)) {
+                       kvm_hypercall1(KVM_HC_SCHED_YIELD, per_cpu(x86_cpu_to_apicid, cpu));
+                       break;
+               }
+       }
+}
+
 static void __init kvm_smp_prepare_cpus(unsigned int max_cpus)
 {
        native_smp_prepare_cpus(max_cpus);
@@ -638,6 +653,12 @@ static void __init kvm_guest_init(void)
 #ifdef CONFIG_SMP
        smp_ops.smp_prepare_cpus = kvm_smp_prepare_cpus;
        smp_ops.smp_prepare_boot_cpu = kvm_smp_prepare_boot_cpu;
+       if (kvm_para_has_feature(KVM_FEATURE_PV_SCHED_YIELD) &&
+           !kvm_para_has_hint(KVM_HINTS_REALTIME) &&
+           kvm_para_has_feature(KVM_FEATURE_STEAL_TIME)) {
+               smp_ops.send_call_func_ipi = kvm_smp_send_call_func_ipi;
+               pr_info("KVM setup pv sched yield\n");
+       }
        if (cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "x86/kvm:online",
                                      kvm_cpu_online, kvm_cpu_down_prepare) < 0)
                pr_err("kvm_guest: Failed to install cpu hotplug callbacks\n");
index 7cf508f..8eb7193 100644 (file)
@@ -391,7 +391,7 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig,
                put_user_ex(&frame->uc, &frame->puc);
 
                /* Create the ucontext.  */
-               if (boot_cpu_has(X86_FEATURE_XSAVE))
+               if (static_cpu_has(X86_FEATURE_XSAVE))
                        put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
                else
                        put_user_ex(0, &frame->uc.uc_flags);
index f788011..259d1d2 100644 (file)
@@ -210,28 +210,16 @@ static int enable_start_cpu0;
  */
 static void notrace start_secondary(void *unused)
 {
-       unsigned long cr4 = __read_cr4();
-
        /*
         * Don't put *anything* except direct CPU state initialization
         * before cpu_init(), SMP booting is too fragile that we want to
         * limit the things done here to the most necessary things.
         */
-       if (boot_cpu_has(X86_FEATURE_PCID))
-               cr4 |= X86_CR4_PCIDE;
-       if (static_branch_likely(&cr_pinning))
-               cr4 |= cr4_pinned_bits;
-
-       __write_cr4(cr4);
+       cr4_init();
 
 #ifdef CONFIG_X86_32
        /* switch away from the initial page table */
        load_cr3(swapper_pg_dir);
-       /*
-        * Initialize the CR4 shadow before doing anything that could
-        * try to read it.
-        */
-       cr4_init_shadow();
        __flush_tlb_all();
 #endif
        load_current_idt();
index 2abf27d..4f36d32 100644 (file)
@@ -129,11 +129,9 @@ void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie,
                        break;
                if ((unsigned long)fp < regs->sp)
                        break;
-               if (frame.ret_addr) {
-                       if (!consume_entry(cookie, frame.ret_addr, false))
-                               return;
-               }
-               if (fp == frame.next_fp)
+               if (!frame.ret_addr)
+                       break;
+               if (!consume_entry(cookie, frame.ret_addr, false))
                        break;
                fp = frame.next_fp;
        }
index 147cd02..e2feacf 100644 (file)
@@ -141,10 +141,10 @@ SECTIONS
                *(.text.__x86.indirect_thunk)
                __indirect_thunk_end = .;
 #endif
-       } :text = 0x9090
 
-       /* End of text section */
-       _etext = .;
+               /* End of text section */
+               _etext = .;
+       } :text = 0x9090
 
        NOTES :text :note
 
index fc04241..840e125 100644 (file)
@@ -41,6 +41,7 @@ config KVM
        select PERF_EVENTS
        select HAVE_KVM_MSI
        select HAVE_KVM_CPU_RELAX_INTERCEPT
+       select HAVE_KVM_NO_POLL
        select KVM_GENERIC_DIRTYLOG_READ_PROTECT
        select KVM_VFIO
        select SRCU
index 4992e7c..ead6812 100644 (file)
@@ -134,6 +134,16 @@ int kvm_update_cpuid(struct kvm_vcpu *vcpu)
                (best->eax & (1 << KVM_FEATURE_PV_UNHALT)))
                best->eax &= ~(1 << KVM_FEATURE_PV_UNHALT);
 
+       if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT)) {
+               best = kvm_find_cpuid_entry(vcpu, 0x1, 0);
+               if (best) {
+                       if (vcpu->arch.ia32_misc_enable_msr & MSR_IA32_MISC_ENABLE_MWAIT)
+                               best->ecx |= F(MWAIT);
+                       else
+                               best->ecx &= ~F(MWAIT);
+               }
+       }
+
        /* Update physical-address width */
        vcpu->arch.maxphyaddr = cpuid_query_maxphyaddr(vcpu);
        kvm_mmu_reset_context(vcpu);
@@ -276,19 +286,38 @@ static void cpuid_mask(u32 *word, int wordnum)
        *word &= boot_cpu_data.x86_capability[wordnum];
 }
 
-static void do_cpuid_1_ent(struct kvm_cpuid_entry2 *entry, u32 function,
+static void do_host_cpuid(struct kvm_cpuid_entry2 *entry, u32 function,
                           u32 index)
 {
        entry->function = function;
        entry->index = index;
+       entry->flags = 0;
+
        cpuid_count(entry->function, entry->index,
                    &entry->eax, &entry->ebx, &entry->ecx, &entry->edx);
-       entry->flags = 0;
+
+       switch (function) {
+       case 2:
+               entry->flags |= KVM_CPUID_FLAG_STATEFUL_FUNC;
+               break;
+       case 4:
+       case 7:
+       case 0xb:
+       case 0xd:
+       case 0x14:
+       case 0x8000001d:
+               entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+               break;
+       }
 }
 
-static int __do_cpuid_ent_emulated(struct kvm_cpuid_entry2 *entry,
-                                  u32 func, u32 index, int *nent, int maxnent)
+static int __do_cpuid_func_emulated(struct kvm_cpuid_entry2 *entry,
+                                   u32 func, int *nent, int maxnent)
 {
+       entry->function = func;
+       entry->index = 0;
+       entry->flags = 0;
+
        switch (func) {
        case 0:
                entry->eax = 7;
@@ -300,21 +329,83 @@ static int __do_cpuid_ent_emulated(struct kvm_cpuid_entry2 *entry,
                break;
        case 7:
                entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
-               if (index == 0)
-                       entry->ecx = F(RDPID);
+               entry->eax = 0;
+               entry->ecx = F(RDPID);
                ++*nent;
        default:
                break;
        }
 
-       entry->function = func;
-       entry->index = index;
-
        return 0;
 }
 
-static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
-                                u32 index, int *nent, int maxnent)
+static inline void do_cpuid_7_mask(struct kvm_cpuid_entry2 *entry, int index)
+{
+       unsigned f_invpcid = kvm_x86_ops->invpcid_supported() ? F(INVPCID) : 0;
+       unsigned f_mpx = kvm_mpx_supported() ? F(MPX) : 0;
+       unsigned f_umip = kvm_x86_ops->umip_emulated() ? F(UMIP) : 0;
+       unsigned f_intel_pt = kvm_x86_ops->pt_supported() ? F(INTEL_PT) : 0;
+       unsigned f_la57;
+
+       /* cpuid 7.0.ebx */
+       const u32 kvm_cpuid_7_0_ebx_x86_features =
+               F(FSGSBASE) | F(BMI1) | F(HLE) | F(AVX2) | F(SMEP) |
+               F(BMI2) | F(ERMS) | f_invpcid | F(RTM) | f_mpx | F(RDSEED) |
+               F(ADX) | F(SMAP) | F(AVX512IFMA) | F(AVX512F) | F(AVX512PF) |
+               F(AVX512ER) | F(AVX512CD) | F(CLFLUSHOPT) | F(CLWB) | F(AVX512DQ) |
+               F(SHA_NI) | F(AVX512BW) | F(AVX512VL) | f_intel_pt;
+
+       /* cpuid 7.0.ecx*/
+       const u32 kvm_cpuid_7_0_ecx_x86_features =
+               F(AVX512VBMI) | F(LA57) | F(PKU) | 0 /*OSPKE*/ |
+               F(AVX512_VPOPCNTDQ) | F(UMIP) | F(AVX512_VBMI2) | F(GFNI) |
+               F(VAES) | F(VPCLMULQDQ) | F(AVX512_VNNI) | F(AVX512_BITALG) |
+               F(CLDEMOTE) | F(MOVDIRI) | F(MOVDIR64B);
+
+       /* cpuid 7.0.edx*/
+       const u32 kvm_cpuid_7_0_edx_x86_features =
+               F(AVX512_4VNNIW) | F(AVX512_4FMAPS) | F(SPEC_CTRL) |
+               F(SPEC_CTRL_SSBD) | F(ARCH_CAPABILITIES) | F(INTEL_STIBP) |
+               F(MD_CLEAR);
+
+       switch (index) {
+       case 0:
+               entry->eax = 0;
+               entry->ebx &= kvm_cpuid_7_0_ebx_x86_features;
+               cpuid_mask(&entry->ebx, CPUID_7_0_EBX);
+               /* TSC_ADJUST is emulated */
+               entry->ebx |= F(TSC_ADJUST);
+
+               entry->ecx &= kvm_cpuid_7_0_ecx_x86_features;
+               f_la57 = entry->ecx & F(LA57);
+               cpuid_mask(&entry->ecx, CPUID_7_ECX);
+               /* Set LA57 based on hardware capability. */
+               entry->ecx |= f_la57;
+               entry->ecx |= f_umip;
+               /* PKU is not yet implemented for shadow paging. */
+               if (!tdp_enabled || !boot_cpu_has(X86_FEATURE_OSPKE))
+                       entry->ecx &= ~F(PKU);
+
+               entry->edx &= kvm_cpuid_7_0_edx_x86_features;
+               cpuid_mask(&entry->edx, CPUID_7_EDX);
+               /*
+                * We emulate ARCH_CAPABILITIES in software even
+                * if the host doesn't support it.
+                */
+               entry->edx |= F(ARCH_CAPABILITIES);
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               entry->eax = 0;
+               entry->ebx = 0;
+               entry->ecx = 0;
+               entry->edx = 0;
+               break;
+       }
+}
+
+static inline int __do_cpuid_func(struct kvm_cpuid_entry2 *entry, u32 function,
+                                 int *nent, int maxnent)
 {
        int r;
        unsigned f_nx = is_efer_nx() ? F(NX) : 0;
@@ -327,12 +418,8 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
        unsigned f_lm = 0;
 #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_mpx_supported() ? F(MPX) : 0;
        unsigned f_xsaves = kvm_x86_ops->xsaves_supported() ? F(XSAVES) : 0;
-       unsigned f_umip = kvm_x86_ops->umip_emulated() ? F(UMIP) : 0;
        unsigned f_intel_pt = kvm_x86_ops->pt_supported() ? F(INTEL_PT) : 0;
-       unsigned f_la57 = 0;
 
        /* cpuid 1.edx */
        const u32 kvm_cpuid_1_edx_x86_features =
@@ -377,7 +464,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
        /* cpuid 0x80000008.ebx */
        const u32 kvm_cpuid_8000_0008_ebx_x86_features =
                F(WBNOINVD) | F(AMD_IBPB) | F(AMD_IBRS) | F(AMD_SSBD) | F(VIRT_SSBD) |
-               F(AMD_SSB_NO) | F(AMD_STIBP);
+               F(AMD_SSB_NO) | F(AMD_STIBP) | F(AMD_STIBP_ALWAYS_ON);
 
        /* cpuid 0xC0000001.edx */
        const u32 kvm_cpuid_C000_0001_edx_x86_features =
@@ -385,31 +472,10 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                F(ACE2) | F(ACE2_EN) | F(PHE) | F(PHE_EN) |
                F(PMM) | F(PMM_EN);
 
-       /* cpuid 7.0.ebx */
-       const u32 kvm_cpuid_7_0_ebx_x86_features =
-               F(FSGSBASE) | F(BMI1) | F(HLE) | F(AVX2) | F(SMEP) |
-               F(BMI2) | F(ERMS) | f_invpcid | F(RTM) | f_mpx | F(RDSEED) |
-               F(ADX) | F(SMAP) | F(AVX512IFMA) | F(AVX512F) | F(AVX512PF) |
-               F(AVX512ER) | F(AVX512CD) | F(CLFLUSHOPT) | F(CLWB) | F(AVX512DQ) |
-               F(SHA_NI) | F(AVX512BW) | F(AVX512VL) | f_intel_pt;
-
        /* cpuid 0xD.1.eax */
        const u32 kvm_cpuid_D_1_eax_x86_features =
                F(XSAVEOPT) | F(XSAVEC) | F(XGETBV1) | f_xsaves;
 
-       /* cpuid 7.0.ecx*/
-       const u32 kvm_cpuid_7_0_ecx_x86_features =
-               F(AVX512VBMI) | F(LA57) | F(PKU) | 0 /*OSPKE*/ |
-               F(AVX512_VPOPCNTDQ) | F(UMIP) | F(AVX512_VBMI2) | F(GFNI) |
-               F(VAES) | F(VPCLMULQDQ) | F(AVX512_VNNI) | F(AVX512_BITALG) |
-               F(CLDEMOTE) | F(MOVDIRI) | F(MOVDIR64B);
-
-       /* cpuid 7.0.edx*/
-       const u32 kvm_cpuid_7_0_edx_x86_features =
-               F(AVX512_4VNNIW) | F(AVX512_4FMAPS) | F(SPEC_CTRL) |
-               F(SPEC_CTRL_SSBD) | F(ARCH_CAPABILITIES) | F(INTEL_STIBP) |
-               F(MD_CLEAR);
-
        /* all calls to cpuid_count() should be made on the same cpu */
        get_cpu();
 
@@ -418,12 +484,13 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
        if (*nent >= maxnent)
                goto out;
 
-       do_cpuid_1_ent(entry, function, index);
+       do_host_cpuid(entry, function, 0);
        ++*nent;
 
        switch (function) {
        case 0:
-               entry->eax = min(entry->eax, (u32)(f_intel_pt ? 0x14 : 0xd));
+               /* Limited to the highest leaf implemented in KVM. */
+               entry->eax = min(entry->eax, 0x1fU);
                break;
        case 1:
                entry->edx &= kvm_cpuid_1_edx_x86_features;
@@ -441,14 +508,12 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
        case 2: {
                int t, times = entry->eax & 0xff;
 
-               entry->flags |= KVM_CPUID_FLAG_STATEFUL_FUNC;
                entry->flags |= KVM_CPUID_FLAG_STATE_READ_NEXT;
                for (t = 1; t < times; ++t) {
                        if (*nent >= maxnent)
                                goto out;
 
-                       do_cpuid_1_ent(&entry[t], function, 0);
-                       entry[t].flags |= KVM_CPUID_FLAG_STATEFUL_FUNC;
+                       do_host_cpuid(&entry[t], function, 0);
                        ++*nent;
                }
                break;
@@ -458,7 +523,6 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
        case 0x8000001d: {
                int i, cache_type;
 
-               entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
                /* read more entries until cache_type is zero */
                for (i = 1; ; ++i) {
                        if (*nent >= maxnent)
@@ -467,9 +531,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                        cache_type = entry[i - 1].eax & 0x1f;
                        if (!cache_type)
                                break;
-                       do_cpuid_1_ent(&entry[i], function, i);
-                       entry[i].flags |=
-                              KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+                       do_host_cpuid(&entry[i], function, i);
                        ++*nent;
                }
                break;
@@ -480,36 +542,21 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                entry->ecx = 0;
                entry->edx = 0;
                break;
+       /* function 7 has additional index. */
        case 7: {
-               entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
-               /* Mask ebx against host capability word 9 */
-               if (index == 0) {
-                       entry->ebx &= kvm_cpuid_7_0_ebx_x86_features;
-                       cpuid_mask(&entry->ebx, CPUID_7_0_EBX);
-                       // TSC_ADJUST is emulated
-                       entry->ebx |= F(TSC_ADJUST);
-                       entry->ecx &= kvm_cpuid_7_0_ecx_x86_features;
-                       f_la57 = entry->ecx & F(LA57);
-                       cpuid_mask(&entry->ecx, CPUID_7_ECX);
-                       /* Set LA57 based on hardware capability. */
-                       entry->ecx |= f_la57;
-                       entry->ecx |= f_umip;
-                       /* PKU is not yet implemented for shadow paging. */
-                       if (!tdp_enabled || !boot_cpu_has(X86_FEATURE_OSPKE))
-                               entry->ecx &= ~F(PKU);
-                       entry->edx &= kvm_cpuid_7_0_edx_x86_features;
-                       cpuid_mask(&entry->edx, CPUID_7_EDX);
-                       /*
-                        * We emulate ARCH_CAPABILITIES in software even
-                        * if the host doesn't support it.
-                        */
-                       entry->edx |= F(ARCH_CAPABILITIES);
-               } else {
-                       entry->ebx = 0;
-                       entry->ecx = 0;
-                       entry->edx = 0;
+               int i;
+
+               for (i = 0; ; ) {
+                       do_cpuid_7_mask(&entry[i], i);
+                       if (i == entry->eax)
+                               break;
+                       if (*nent >= maxnent)
+                               goto out;
+
+                       ++i;
+                       do_host_cpuid(&entry[i], function, i);
+                       ++*nent;
                }
-               entry->eax = 0;
                break;
        }
        case 9:
@@ -543,11 +590,14 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                entry->edx = edx.full;
                break;
        }
-       /* function 0xb has additional index. */
+       /*
+        * Per Intel's SDM, the 0x1f is a superset of 0xb,
+        * thus they can be handled by common code.
+        */
+       case 0x1f:
        case 0xb: {
                int i, level_type;
 
-               entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
                /* read more entries until level_type is zero */
                for (i = 1; ; ++i) {
                        if (*nent >= maxnent)
@@ -556,9 +606,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                        level_type = entry[i - 1].ecx & 0xff00;
                        if (!level_type)
                                break;
-                       do_cpuid_1_ent(&entry[i], function, i);
-                       entry[i].flags |=
-                              KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+                       do_host_cpuid(&entry[i], function, i);
                        ++*nent;
                }
                break;
@@ -571,7 +619,6 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                entry->ebx = xstate_required_size(supported, false);
                entry->ecx = entry->ebx;
                entry->edx &= supported >> 32;
-               entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
                if (!supported)
                        break;
 
@@ -580,7 +627,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                        if (*nent >= maxnent)
                                goto out;
 
-                       do_cpuid_1_ent(&entry[i], function, idx);
+                       do_host_cpuid(&entry[i], function, idx);
                        if (idx == 1) {
                                entry[i].eax &= kvm_cpuid_D_1_eax_x86_features;
                                cpuid_mask(&entry[i].eax, CPUID_D_1_EAX);
@@ -597,8 +644,6 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                        }
                        entry[i].ecx = 0;
                        entry[i].edx = 0;
-                       entry[i].flags |=
-                              KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
                        ++*nent;
                        ++i;
                }
@@ -611,12 +656,10 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                if (!f_intel_pt)
                        break;
 
-               entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
                for (t = 1; t <= times; ++t) {
                        if (*nent >= maxnent)
                                goto out;
-                       do_cpuid_1_ent(&entry[t], function, t);
-                       entry[t].flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+                       do_host_cpuid(&entry[t], function, t);
                        ++*nent;
                }
                break;
@@ -640,7 +683,9 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                             (1 << KVM_FEATURE_PV_UNHALT) |
                             (1 << KVM_FEATURE_PV_TLB_FLUSH) |
                             (1 << KVM_FEATURE_ASYNC_PF_VMEXIT) |
-                            (1 << KVM_FEATURE_PV_SEND_IPI);
+                            (1 << KVM_FEATURE_PV_SEND_IPI) |
+                            (1 << KVM_FEATURE_POLL_CONTROL) |
+                            (1 << KVM_FEATURE_PV_SCHED_YIELD);
 
                if (sched_info_on())
                        entry->eax |= (1 << KVM_FEATURE_STEAL_TIME);
@@ -730,21 +775,19 @@ out:
        return r;
 }
 
-static int do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 func,
-                       u32 idx, int *nent, int maxnent, unsigned int type)
+static int do_cpuid_func(struct kvm_cpuid_entry2 *entry, u32 func,
+                        int *nent, int maxnent, unsigned int type)
 {
        if (type == KVM_GET_EMULATED_CPUID)
-               return __do_cpuid_ent_emulated(entry, func, idx, nent, maxnent);
+               return __do_cpuid_func_emulated(entry, func, nent, maxnent);
 
-       return __do_cpuid_ent(entry, func, idx, nent, maxnent);
+       return __do_cpuid_func(entry, func, nent, maxnent);
 }
 
 #undef F
 
 struct kvm_cpuid_param {
        u32 func;
-       u32 idx;
-       bool has_leaf_count;
        bool (*qualifier)(const struct kvm_cpuid_param *param);
 };
 
@@ -788,11 +831,10 @@ int kvm_dev_ioctl_get_cpuid(struct kvm_cpuid2 *cpuid,
        int limit, nent = 0, r = -E2BIG, i;
        u32 func;
        static const struct kvm_cpuid_param param[] = {
-               { .func = 0, .has_leaf_count = true },
-               { .func = 0x80000000, .has_leaf_count = true },
-               { .func = 0xC0000000, .qualifier = is_centaur_cpu, .has_leaf_count = true },
+               { .func = 0 },
+               { .func = 0x80000000 },
+               { .func = 0xC0000000, .qualifier = is_centaur_cpu },
                { .func = KVM_CPUID_SIGNATURE },
-               { .func = KVM_CPUID_FEATURES },
        };
 
        if (cpuid->nent < 1)
@@ -816,19 +858,16 @@ int kvm_dev_ioctl_get_cpuid(struct kvm_cpuid2 *cpuid,
                if (ent->qualifier && !ent->qualifier(ent))
                        continue;
 
-               r = do_cpuid_ent(&cpuid_entries[nent], ent->func, ent->idx,
-                               &nent, cpuid->nent, type);
+               r = do_cpuid_func(&cpuid_entries[nent], ent->func,
+                                 &nent, cpuid->nent, type);
 
                if (r)
                        goto out_free;
 
-               if (!ent->has_leaf_count)
-                       continue;
-
                limit = cpuid_entries[nent - 1].eax;
                for (func = ent->func + 1; func <= limit && nent < cpuid->nent && r == 0; ++func)
-                       r = do_cpuid_ent(&cpuid_entries[nent], func, ent->idx,
-                                    &nent, cpuid->nent, type);
+                       r = do_cpuid_func(&cpuid_entries[nent], func,
+                                         &nent, cpuid->nent, type);
 
                if (r)
                        goto out_free;
index 4a387a2..8e409ad 100644 (file)
@@ -4258,7 +4258,7 @@ static int check_dr_read(struct x86_emulate_ctxt *ctxt)
                ulong dr6;
 
                ctxt->ops->get_dr(ctxt, 6, &dr6);
-               dr6 &= ~15;
+               dr6 &= ~DR_TRAP_BITS;
                dr6 |= DR6_BD | DR6_RTM;
                ctxt->ops->set_dr(ctxt, 6, dr6);
                return emulate_db(ctxt);
index d6519a3..7c6233d 100644 (file)
@@ -102,7 +102,6 @@ static inline int irqchip_in_kernel(struct kvm *kvm)
        return mode != KVM_IRQCHIP_NONE;
 }
 
-bool kvm_arch_irqfd_allowed(struct kvm *kvm, struct kvm_irqfd *args);
 void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu);
 void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu);
 void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu);
index 924b3bd..8ecd48d 100644 (file)
@@ -75,7 +75,7 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
                        if (r < 0)
                                r = 0;
                        r += kvm_apic_set_irq(vcpu, irq, dest_map);
-               } else if (kvm_lapic_enabled(vcpu)) {
+               } else if (kvm_apic_sw_enabled(vcpu->arch.apic)) {
                        if (!kvm_vector_hashing_enabled()) {
                                if (!lowest)
                                        lowest = vcpu;
index 4dabc31..a232e76 100644 (file)
@@ -69,6 +69,7 @@
 #define X2APIC_BROADCAST               0xFFFFFFFFul
 
 #define LAPIC_TIMER_ADVANCE_ADJUST_DONE 100
+#define LAPIC_TIMER_ADVANCE_ADJUST_INIT 1000
 /* step-by-step approximation to mitigate fluctuation */
 #define LAPIC_TIMER_ADVANCE_ADJUST_STEP 8
 
@@ -85,11 +86,6 @@ bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector)
                apic_test_vector(vector, apic->regs + APIC_IRR);
 }
 
-static inline void apic_clear_vector(int vec, void *bitmap)
-{
-       clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
-}
-
 static inline int __apic_test_and_set_vector(int vec, void *bitmap)
 {
        return __test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
@@ -443,12 +439,12 @@ static inline void apic_clear_irr(int vec, struct kvm_lapic *apic)
 
        if (unlikely(vcpu->arch.apicv_active)) {
                /* need to update RVI */
-               apic_clear_vector(vec, apic->regs + APIC_IRR);
+               kvm_lapic_clear_vector(vec, apic->regs + APIC_IRR);
                kvm_x86_ops->hwapic_irr_update(vcpu,
                                apic_find_highest_irr(apic));
        } else {
                apic->irr_pending = false;
-               apic_clear_vector(vec, apic->regs + APIC_IRR);
+               kvm_lapic_clear_vector(vec, apic->regs + APIC_IRR);
                if (apic_search_irr(apic) != -1)
                        apic->irr_pending = true;
        }
@@ -1053,9 +1049,11 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
 
                if (apic_test_vector(vector, apic->regs + APIC_TMR) != !!trig_mode) {
                        if (trig_mode)
-                               kvm_lapic_set_vector(vector, apic->regs + APIC_TMR);
+                               kvm_lapic_set_vector(vector,
+                                                    apic->regs + APIC_TMR);
                        else
-                               apic_clear_vector(vector, apic->regs + APIC_TMR);
+                               kvm_lapic_clear_vector(vector,
+                                                      apic->regs + APIC_TMR);
                }
 
                if (vcpu->arch.apicv_active)
@@ -1313,21 +1311,45 @@ static inline struct kvm_lapic *to_lapic(struct kvm_io_device *dev)
        return container_of(dev, struct kvm_lapic, dev);
 }
 
+#define APIC_REG_MASK(reg)     (1ull << ((reg) >> 4))
+#define APIC_REGS_MASK(first, count) \
+       (APIC_REG_MASK(first) * ((1ull << (count)) - 1))
+
 int kvm_lapic_reg_read(struct kvm_lapic *apic, u32 offset, int len,
                void *data)
 {
        unsigned char alignment = offset & 0xf;
        u32 result;
        /* this bitmask has a bit cleared for each reserved register */
-       static const u64 rmask = 0x43ff01ffffffe70cULL;
-
-       if ((alignment + len) > 4) {
-               apic_debug("KVM_APIC_READ: alignment error %x %d\n",
-                          offset, len);
-               return 1;
-       }
+       u64 valid_reg_mask =
+               APIC_REG_MASK(APIC_ID) |
+               APIC_REG_MASK(APIC_LVR) |
+               APIC_REG_MASK(APIC_TASKPRI) |
+               APIC_REG_MASK(APIC_PROCPRI) |
+               APIC_REG_MASK(APIC_LDR) |
+               APIC_REG_MASK(APIC_DFR) |
+               APIC_REG_MASK(APIC_SPIV) |
+               APIC_REGS_MASK(APIC_ISR, APIC_ISR_NR) |
+               APIC_REGS_MASK(APIC_TMR, APIC_ISR_NR) |
+               APIC_REGS_MASK(APIC_IRR, APIC_ISR_NR) |
+               APIC_REG_MASK(APIC_ESR) |
+               APIC_REG_MASK(APIC_ICR) |
+               APIC_REG_MASK(APIC_ICR2) |
+               APIC_REG_MASK(APIC_LVTT) |
+               APIC_REG_MASK(APIC_LVTTHMR) |
+               APIC_REG_MASK(APIC_LVTPC) |
+               APIC_REG_MASK(APIC_LVT0) |
+               APIC_REG_MASK(APIC_LVT1) |
+               APIC_REG_MASK(APIC_LVTERR) |
+               APIC_REG_MASK(APIC_TMICT) |
+               APIC_REG_MASK(APIC_TMCCT) |
+               APIC_REG_MASK(APIC_TDCR);
+
+       /* ARBPRI is not valid on x2APIC */
+       if (!apic_x2apic_mode(apic))
+               valid_reg_mask |= APIC_REG_MASK(APIC_ARBPRI);
 
-       if (offset > 0x3f0 || !(rmask & (1ULL << (offset >> 4)))) {
+       if (offset > 0x3f0 || !(valid_reg_mask & APIC_REG_MASK(offset))) {
                apic_debug("KVM_APIC_READ: read reserved register %x\n",
                           offset);
                return 1;
@@ -1499,11 +1521,40 @@ static inline void __wait_lapic_expire(struct kvm_vcpu *vcpu, u64 guest_cycles)
        }
 }
 
-void wait_lapic_expire(struct kvm_vcpu *vcpu)
+static inline void adjust_lapic_timer_advance(struct kvm_vcpu *vcpu,
+                                             s64 advance_expire_delta)
 {
        struct kvm_lapic *apic = vcpu->arch.apic;
        u32 timer_advance_ns = apic->lapic_timer.timer_advance_ns;
-       u64 guest_tsc, tsc_deadline, ns;
+       u64 ns;
+
+       /* too early */
+       if (advance_expire_delta < 0) {
+               ns = -advance_expire_delta * 1000000ULL;
+               do_div(ns, vcpu->arch.virtual_tsc_khz);
+               timer_advance_ns -= min((u32)ns,
+                       timer_advance_ns / LAPIC_TIMER_ADVANCE_ADJUST_STEP);
+       } else {
+       /* too late */
+               ns = advance_expire_delta * 1000000ULL;
+               do_div(ns, vcpu->arch.virtual_tsc_khz);
+               timer_advance_ns += min((u32)ns,
+                       timer_advance_ns / LAPIC_TIMER_ADVANCE_ADJUST_STEP);
+       }
+
+       if (abs(advance_expire_delta) < LAPIC_TIMER_ADVANCE_ADJUST_DONE)
+               apic->lapic_timer.timer_advance_adjust_done = true;
+       if (unlikely(timer_advance_ns > 5000)) {
+               timer_advance_ns = LAPIC_TIMER_ADVANCE_ADJUST_INIT;
+               apic->lapic_timer.timer_advance_adjust_done = false;
+       }
+       apic->lapic_timer.timer_advance_ns = timer_advance_ns;
+}
+
+void kvm_wait_lapic_expire(struct kvm_vcpu *vcpu)
+{
+       struct kvm_lapic *apic = vcpu->arch.apic;
+       u64 guest_tsc, tsc_deadline;
 
        if (apic->lapic_timer.expired_tscdeadline == 0)
                return;
@@ -1514,34 +1565,15 @@ void wait_lapic_expire(struct kvm_vcpu *vcpu)
        tsc_deadline = apic->lapic_timer.expired_tscdeadline;
        apic->lapic_timer.expired_tscdeadline = 0;
        guest_tsc = kvm_read_l1_tsc(vcpu, rdtsc());
-       trace_kvm_wait_lapic_expire(vcpu->vcpu_id, guest_tsc - tsc_deadline);
+       apic->lapic_timer.advance_expire_delta = guest_tsc - tsc_deadline;
 
        if (guest_tsc < tsc_deadline)
                __wait_lapic_expire(vcpu, tsc_deadline - guest_tsc);
 
-       if (!apic->lapic_timer.timer_advance_adjust_done) {
-               /* too early */
-               if (guest_tsc < tsc_deadline) {
-                       ns = (tsc_deadline - guest_tsc) * 1000000ULL;
-                       do_div(ns, vcpu->arch.virtual_tsc_khz);
-                       timer_advance_ns -= min((u32)ns,
-                               timer_advance_ns / LAPIC_TIMER_ADVANCE_ADJUST_STEP);
-               } else {
-               /* too late */
-                       ns = (guest_tsc - tsc_deadline) * 1000000ULL;
-                       do_div(ns, vcpu->arch.virtual_tsc_khz);
-                       timer_advance_ns += min((u32)ns,
-                               timer_advance_ns / LAPIC_TIMER_ADVANCE_ADJUST_STEP);
-               }
-               if (abs(guest_tsc - tsc_deadline) < LAPIC_TIMER_ADVANCE_ADJUST_DONE)
-                       apic->lapic_timer.timer_advance_adjust_done = true;
-               if (unlikely(timer_advance_ns > 5000)) {
-                       timer_advance_ns = 0;
-                       apic->lapic_timer.timer_advance_adjust_done = true;
-               }
-               apic->lapic_timer.timer_advance_ns = timer_advance_ns;
-       }
+       if (unlikely(!apic->lapic_timer.timer_advance_adjust_done))
+               adjust_lapic_timer_advance(vcpu, apic->lapic_timer.advance_expire_delta);
 }
+EXPORT_SYMBOL_GPL(kvm_wait_lapic_expire);
 
 static void start_sw_tscdeadline(struct kvm_lapic *apic)
 {
@@ -2014,7 +2046,7 @@ static int apic_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
                apic_debug("%s: offset 0x%x with length 0x%x, and value is "
                           "0x%x\n", __func__, offset, len, val);
 
-       kvm_lapic_reg_write(apic, offset & 0xff0, val);
+       kvm_lapic_reg_write(apic, offset, val);
 
        return 0;
 }
@@ -2311,7 +2343,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu, int timer_advance_ns)
                     HRTIMER_MODE_ABS_PINNED);
        apic->lapic_timer.timer.function = apic_timer_fn;
        if (timer_advance_ns == -1) {
-               apic->lapic_timer.timer_advance_ns = 1000;
+               apic->lapic_timer.timer_advance_ns = LAPIC_TIMER_ADVANCE_ADJUST_INIT;
                apic->lapic_timer.timer_advance_adjust_done = false;
        } else {
                apic->lapic_timer.timer_advance_ns = timer_advance_ns;
@@ -2321,7 +2353,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu, int timer_advance_ns)
 
        /*
         * APIC is created enabled. This will prevent kvm_lapic_set_base from
-        * thinking that APIC satet has changed.
+        * thinking that APIC state has changed.
         */
        vcpu->arch.apic_base = MSR_IA32_APICBASE_ENABLE;
        static_key_slow_inc(&apic_sw_disabled.key); /* sw disabled at reset */
@@ -2330,6 +2362,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu, int timer_advance_ns)
        return 0;
 nomem_free_apic:
        kfree(apic);
+       vcpu->arch.apic = NULL;
 nomem:
        return -ENOMEM;
 }
index d6d049b..3674717 100644 (file)
@@ -32,6 +32,7 @@ struct kvm_timer {
        u64 tscdeadline;
        u64 expired_tscdeadline;
        u32 timer_advance_ns;
+       s64 advance_expire_delta;
        atomic_t pending;                       /* accumulated triggered timers */
        bool hv_timer_in_use;
        bool timer_advance_adjust_done;
@@ -129,6 +130,11 @@ void kvm_lapic_exit(void);
 #define VEC_POS(v) ((v) & (32 - 1))
 #define REG_POS(v) (((v) >> 5) << 4)
 
+static inline void kvm_lapic_clear_vector(int vec, void *bitmap)
+{
+       clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
+}
+
 static inline void kvm_lapic_set_vector(int vec, void *bitmap)
 {
        set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
@@ -219,7 +225,7 @@ static inline int kvm_lapic_latched_init(struct kvm_vcpu *vcpu)
 
 bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector);
 
-void wait_lapic_expire(struct kvm_vcpu *vcpu);
+void kvm_wait_lapic_expire(struct kvm_vcpu *vcpu);
 
 bool kvm_intr_is_single_vcpu_fast(struct kvm *kvm, struct kvm_lapic_irq *irq,
                        struct kvm_vcpu **dest_vcpu);
index 98f6e4f..9a5814d 100644 (file)
@@ -140,9 +140,6 @@ module_param(dbg, bool, 0644);
 
 #include <trace/events/kvm.h>
 
-#define CREATE_TRACE_POINTS
-#include "mmutrace.h"
-
 #define SPTE_HOST_WRITEABLE    (1ULL << PT_FIRST_AVAIL_BITS_SHIFT)
 #define SPTE_MMU_WRITEABLE     (1ULL << (PT_FIRST_AVAIL_BITS_SHIFT + 1))
 
@@ -259,11 +256,20 @@ static const u64 shadow_nonpresent_or_rsvd_mask_len = 5;
  */
 static u64 __read_mostly shadow_nonpresent_or_rsvd_lower_gfn_mask;
 
+/*
+ * The number of non-reserved physical address bits irrespective of features
+ * that repurpose legal bits, e.g. MKTME.
+ */
+static u8 __read_mostly shadow_phys_bits;
 
 static void mmu_spte_set(u64 *sptep, u64 spte);
+static bool is_executable_pte(u64 spte);
 static union kvm_mmu_page_role
 kvm_mmu_calc_root_page_role(struct kvm_vcpu *vcpu);
 
+#define CREATE_TRACE_POINTS
+#include "mmutrace.h"
+
 
 static inline bool kvm_available_flush_tlb_with_range(void)
 {
@@ -468,6 +474,21 @@ void kvm_mmu_set_mask_ptes(u64 user_mask, u64 accessed_mask,
 }
 EXPORT_SYMBOL_GPL(kvm_mmu_set_mask_ptes);
 
+static u8 kvm_get_shadow_phys_bits(void)
+{
+       /*
+        * boot_cpu_data.x86_phys_bits is reduced when MKTME is detected
+        * in CPU detection code, but MKTME treats those reduced bits as
+        * 'keyID' thus they are not reserved bits. Therefore for MKTME
+        * we should still return physical address bits reported by CPUID.
+        */
+       if (!boot_cpu_has(X86_FEATURE_TME) ||
+           WARN_ON_ONCE(boot_cpu_data.extended_cpuid_level < 0x80000008))
+               return boot_cpu_data.x86_phys_bits;
+
+       return cpuid_eax(0x80000008) & 0xff;
+}
+
 static void kvm_mmu_reset_all_pte_masks(void)
 {
        u8 low_phys_bits;
@@ -481,6 +502,8 @@ static void kvm_mmu_reset_all_pte_masks(void)
        shadow_present_mask = 0;
        shadow_acc_track_mask = 0;
 
+       shadow_phys_bits = kvm_get_shadow_phys_bits();
+
        /*
         * If the CPU has 46 or less physical address bits, then set an
         * appropriate mask to guard against L1TF attacks. Otherwise, it is
@@ -650,7 +673,7 @@ static u64 __update_clear_spte_slow(u64 *sptep, u64 spte)
 
 /*
  * The idea using the light way get the spte on x86_32 guest is from
- * gup_get_pte(arch/x86/mm/gup.c).
+ * gup_get_pte (mm/gup.c).
  *
  * An spte tlb flush may be pending, because kvm_set_pte_rmapp
  * coalesces them and we are running out of the MMU lock.  Therefore
@@ -1073,10 +1096,16 @@ static gfn_t kvm_mmu_page_get_gfn(struct kvm_mmu_page *sp, int index)
 
 static void kvm_mmu_page_set_gfn(struct kvm_mmu_page *sp, int index, gfn_t gfn)
 {
-       if (sp->role.direct)
-               BUG_ON(gfn != kvm_mmu_page_get_gfn(sp, index));
-       else
+       if (!sp->role.direct) {
                sp->gfns[index] = gfn;
+               return;
+       }
+
+       if (WARN_ON(gfn != kvm_mmu_page_get_gfn(sp, index)))
+               pr_err_ratelimited("gfn mismatch under direct page %llx "
+                                  "(expected %llx, got %llx)\n",
+                                  sp->gfn,
+                                  kvm_mmu_page_get_gfn(sp, index), gfn);
 }
 
 /*
@@ -3055,10 +3084,7 @@ static int mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, unsigned pte_access,
                ret = RET_PF_EMULATE;
 
        pgprintk("%s: setting spte %llx\n", __func__, *sptep);
-       pgprintk("instantiating %s PTE (%s) at %llx (%llx) addr %p\n",
-                is_large_pte(*sptep)? "2MB" : "4kB",
-                *sptep & PT_WRITABLE_MASK ? "RW" : "R", gfn,
-                *sptep, sptep);
+       trace_kvm_mmu_set_spte(level, gfn, sptep);
        if (!was_rmapped && is_large_pte(*sptep))
                ++vcpu->kvm->stat.lpages;
 
@@ -3070,8 +3096,6 @@ static int mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, unsigned pte_access,
                }
        }
 
-       kvm_release_pfn_clean(pfn);
-
        return ret;
 }
 
@@ -3106,9 +3130,11 @@ static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu,
        if (ret <= 0)
                return -1;
 
-       for (i = 0; i < ret; i++, gfn++, start++)
+       for (i = 0; i < ret; i++, gfn++, start++) {
                mmu_set_spte(vcpu, start, access, 0, sp->role.level, gfn,
                             page_to_pfn(pages[i]), true, true);
+               put_page(pages[i]);
+       }
 
        return 0;
 }
@@ -3156,40 +3182,40 @@ static void direct_pte_prefetch(struct kvm_vcpu *vcpu, u64 *sptep)
        __direct_pte_prefetch(vcpu, sp, sptep);
 }
 
-static int __direct_map(struct kvm_vcpu *vcpu, int write, int map_writable,
-                       int level, gfn_t gfn, kvm_pfn_t pfn, bool prefault)
+static int __direct_map(struct kvm_vcpu *vcpu, gpa_t gpa, int write,
+                       int map_writable, int level, kvm_pfn_t pfn,
+                       bool prefault)
 {
-       struct kvm_shadow_walk_iterator iterator;
+       struct kvm_shadow_walk_iterator it;
        struct kvm_mmu_page *sp;
-       int emulate = 0;
-       gfn_t pseudo_gfn;
+       int ret;
+       gfn_t gfn = gpa >> PAGE_SHIFT;
+       gfn_t base_gfn = gfn;
 
        if (!VALID_PAGE(vcpu->arch.mmu->root_hpa))
-               return 0;
+               return RET_PF_RETRY;
 
-       for_each_shadow_entry(vcpu, (u64)gfn << PAGE_SHIFT, iterator) {
-               if (iterator.level == level) {
-                       emulate = mmu_set_spte(vcpu, iterator.sptep, ACC_ALL,
-                                              write, level, gfn, pfn, prefault,
-                                              map_writable);
-                       direct_pte_prefetch(vcpu, iterator.sptep);
-                       ++vcpu->stat.pf_fixed;
+       trace_kvm_mmu_spte_requested(gpa, level, pfn);
+       for_each_shadow_entry(vcpu, gpa, it) {
+               base_gfn = gfn & ~(KVM_PAGES_PER_HPAGE(it.level) - 1);
+               if (it.level == level)
                        break;
-               }
 
-               drop_large_spte(vcpu, iterator.sptep);
-               if (!is_shadow_present_pte(*iterator.sptep)) {
-                       u64 base_addr = iterator.addr;
+               drop_large_spte(vcpu, it.sptep);
+               if (!is_shadow_present_pte(*it.sptep)) {
+                       sp = kvm_mmu_get_page(vcpu, base_gfn, it.addr,
+                                             it.level - 1, true, ACC_ALL);
 
-                       base_addr &= PT64_LVL_ADDR_MASK(iterator.level);
-                       pseudo_gfn = base_addr >> PAGE_SHIFT;
-                       sp = kvm_mmu_get_page(vcpu, pseudo_gfn, iterator.addr,
-                                             iterator.level - 1, 1, ACC_ALL);
-
-                       link_shadow_page(vcpu, iterator.sptep, sp);
+                       link_shadow_page(vcpu, it.sptep, sp);
                }
        }
-       return emulate;
+
+       ret = mmu_set_spte(vcpu, it.sptep, ACC_ALL,
+                          write, level, base_gfn, pfn, prefault,
+                          map_writable);
+       direct_pte_prefetch(vcpu, it.sptep);
+       ++vcpu->stat.pf_fixed;
+       return ret;
 }
 
 static void kvm_send_hwpoison_signal(unsigned long address, struct task_struct *tsk)
@@ -3216,11 +3242,10 @@ static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, kvm_pfn_t pfn)
 }
 
 static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu,
-                                       gfn_t *gfnp, kvm_pfn_t *pfnp,
+                                       gfn_t gfn, kvm_pfn_t *pfnp,
                                        int *levelp)
 {
        kvm_pfn_t pfn = *pfnp;
-       gfn_t gfn = *gfnp;
        int level = *levelp;
 
        /*
@@ -3247,8 +3272,6 @@ static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu,
                mask = KVM_PAGES_PER_HPAGE(level) - 1;
                VM_BUG_ON((gfn & mask) != (pfn & mask));
                if (pfn & mask) {
-                       gfn &= ~mask;
-                       *gfnp = gfn;
                        kvm_release_pfn_clean(pfn);
                        pfn &= ~mask;
                        kvm_get_pfn(pfn);
@@ -3505,22 +3528,19 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, u32 error_code,
        if (handle_abnormal_pfn(vcpu, v, gfn, pfn, ACC_ALL, &r))
                return r;
 
+       r = RET_PF_RETRY;
        spin_lock(&vcpu->kvm->mmu_lock);
        if (mmu_notifier_retry(vcpu->kvm, mmu_seq))
                goto out_unlock;
        if (make_mmu_pages_available(vcpu) < 0)
                goto out_unlock;
        if (likely(!force_pt_level))
-               transparent_hugepage_adjust(vcpu, &gfn, &pfn, &level);
-       r = __direct_map(vcpu, write, map_writable, level, gfn, pfn, prefault);
-       spin_unlock(&vcpu->kvm->mmu_lock);
-
-       return r;
-
+               transparent_hugepage_adjust(vcpu, gfn, &pfn, &level);
+       r = __direct_map(vcpu, v, write, map_writable, level, pfn, prefault);
 out_unlock:
        spin_unlock(&vcpu->kvm->mmu_lock);
        kvm_release_pfn_clean(pfn);
-       return RET_PF_RETRY;
+       return r;
 }
 
 static void mmu_free_root_page(struct kvm *kvm, hpa_t *root_hpa,
@@ -4015,19 +4035,6 @@ static int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn)
        return kvm_setup_async_pf(vcpu, gva, kvm_vcpu_gfn_to_hva(vcpu, gfn), &arch);
 }
 
-bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu)
-{
-       if (unlikely(!lapic_in_kernel(vcpu) ||
-                    kvm_event_needs_reinjection(vcpu) ||
-                    vcpu->arch.exception.pending))
-               return false;
-
-       if (!vcpu->arch.apf.delivery_as_pf_vmexit && is_guest_mode(vcpu))
-               return false;
-
-       return kvm_x86_ops->interrupt_allowed(vcpu);
-}
-
 static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn,
                         gva_t gva, kvm_pfn_t *pfn, bool write, bool *writable)
 {
@@ -4147,22 +4154,19 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code,
        if (handle_abnormal_pfn(vcpu, 0, gfn, pfn, ACC_ALL, &r))
                return r;
 
+       r = RET_PF_RETRY;
        spin_lock(&vcpu->kvm->mmu_lock);
        if (mmu_notifier_retry(vcpu->kvm, mmu_seq))
                goto out_unlock;
        if (make_mmu_pages_available(vcpu) < 0)
                goto out_unlock;
        if (likely(!force_pt_level))
-               transparent_hugepage_adjust(vcpu, &gfn, &pfn, &level);
-       r = __direct_map(vcpu, write, map_writable, level, gfn, pfn, prefault);
-       spin_unlock(&vcpu->kvm->mmu_lock);
-
-       return r;
-
+               transparent_hugepage_adjust(vcpu, gfn, &pfn, &level);
+       r = __direct_map(vcpu, gpa, write, map_writable, level, pfn, prefault);
 out_unlock:
        spin_unlock(&vcpu->kvm->mmu_lock);
        kvm_release_pfn_clean(pfn);
-       return RET_PF_RETRY;
+       return r;
 }
 
 static void nonpaging_init_context(struct kvm_vcpu *vcpu,
@@ -4494,7 +4498,7 @@ reset_shadow_zero_bits_mask(struct kvm_vcpu *vcpu, struct kvm_mmu *context)
         */
        shadow_zero_check = &context->shadow_zero_check;
        __reset_rsvds_bits_mask(vcpu, shadow_zero_check,
-                               boot_cpu_data.x86_phys_bits,
+                               shadow_phys_bits,
                                context->shadow_root_level, uses_nx,
                                guest_cpuid_has(vcpu, X86_FEATURE_GBPAGES),
                                is_pse(vcpu), true);
@@ -4531,13 +4535,13 @@ reset_tdp_shadow_zero_bits_mask(struct kvm_vcpu *vcpu,
 
        if (boot_cpu_is_amd())
                __reset_rsvds_bits_mask(vcpu, shadow_zero_check,
-                                       boot_cpu_data.x86_phys_bits,
+                                       shadow_phys_bits,
                                        context->shadow_root_level, false,
                                        boot_cpu_has(X86_FEATURE_GBPAGES),
                                        true, true);
        else
                __reset_rsvds_bits_mask_ept(shadow_zero_check,
-                                           boot_cpu_data.x86_phys_bits,
+                                           shadow_phys_bits,
                                            false);
 
        if (!shadow_me_mask)
@@ -4558,7 +4562,7 @@ reset_ept_shadow_zero_bits_mask(struct kvm_vcpu *vcpu,
                                struct kvm_mmu *context, bool execonly)
 {
        __reset_rsvds_bits_mask_ept(&context->shadow_zero_check,
-                                   boot_cpu_data.x86_phys_bits, execonly);
+                                   shadow_phys_bits, execonly);
 }
 
 #define BYTE_MASK(access) \
@@ -5935,7 +5939,7 @@ mmu_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
        int nr_to_scan = sc->nr_to_scan;
        unsigned long freed = 0;
 
-       spin_lock(&kvm_lock);
+       mutex_lock(&kvm_lock);
 
        list_for_each_entry(kvm, &vm_list, vm_list) {
                int idx;
@@ -5977,7 +5981,7 @@ mmu_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
                break;
        }
 
-       spin_unlock(&kvm_lock);
+       mutex_unlock(&kvm_lock);
        return freed;
 }
 
@@ -5999,6 +6003,34 @@ static void mmu_destroy_caches(void)
        kmem_cache_destroy(mmu_page_header_cache);
 }
 
+static void kvm_set_mmio_spte_mask(void)
+{
+       u64 mask;
+
+       /*
+        * Set the reserved bits and the present bit of an paging-structure
+        * entry to generate page fault with PFER.RSV = 1.
+        */
+
+       /*
+        * Mask the uppermost physical address bit, which would be reserved as
+        * long as the supported physical address width is less than 52.
+        */
+       mask = 1ull << 51;
+
+       /* Set the present bit. */
+       mask |= 1ull;
+
+       /*
+        * If reserved bit is not supported, clear the present bit to disable
+        * mmio page fault.
+        */
+       if (IS_ENABLED(CONFIG_X86_64) && shadow_phys_bits == 52)
+               mask &= ~1ull;
+
+       kvm_mmu_set_mmio_spte_mask(mask, mask);
+}
+
 int kvm_mmu_module_init(void)
 {
        int ret = -ENOMEM;
@@ -6015,6 +6047,8 @@ int kvm_mmu_module_init(void)
 
        kvm_mmu_reset_all_pte_masks();
 
+       kvm_set_mmio_spte_mask();
+
        pte_list_desc_cache = kmem_cache_create("pte_list_desc",
                                            sizeof(struct pte_list_desc),
                                            0, SLAB_ACCOUNT, NULL);
index dd30dcc..d8001b4 100644 (file)
@@ -301,6 +301,65 @@ TRACE_EVENT(
                  __entry->kvm_gen == __entry->spte_gen
        )
 );
+
+TRACE_EVENT(
+       kvm_mmu_set_spte,
+       TP_PROTO(int level, gfn_t gfn, u64 *sptep),
+       TP_ARGS(level, gfn, sptep),
+
+       TP_STRUCT__entry(
+               __field(u64, gfn)
+               __field(u64, spte)
+               __field(u64, sptep)
+               __field(u8, level)
+               /* These depend on page entry type, so compute them now.  */
+               __field(bool, r)
+               __field(bool, x)
+               __field(u8, u)
+       ),
+
+       TP_fast_assign(
+               __entry->gfn = gfn;
+               __entry->spte = *sptep;
+               __entry->sptep = virt_to_phys(sptep);
+               __entry->level = level;
+               __entry->r = shadow_present_mask || (__entry->spte & PT_PRESENT_MASK);
+               __entry->x = is_executable_pte(__entry->spte);
+               __entry->u = shadow_user_mask ? !!(__entry->spte & shadow_user_mask) : -1;
+       ),
+
+       TP_printk("gfn %llx spte %llx (%s%s%s%s) level %d at %llx",
+                 __entry->gfn, __entry->spte,
+                 __entry->r ? "r" : "-",
+                 __entry->spte & PT_WRITABLE_MASK ? "w" : "-",
+                 __entry->x ? "x" : "-",
+                 __entry->u == -1 ? "" : (__entry->u ? "u" : "-"),
+                 __entry->level, __entry->sptep
+       )
+);
+
+TRACE_EVENT(
+       kvm_mmu_spte_requested,
+       TP_PROTO(gpa_t addr, int level, kvm_pfn_t pfn),
+       TP_ARGS(addr, level, pfn),
+
+       TP_STRUCT__entry(
+               __field(u64, gfn)
+               __field(u64, pfn)
+               __field(u8, level)
+       ),
+
+       TP_fast_assign(
+               __entry->gfn = addr >> PAGE_SHIFT;
+               __entry->pfn = pfn | (__entry->gfn & (KVM_PAGES_PER_HPAGE(level) - 1));
+               __entry->level = level;
+       ),
+
+       TP_printk("gfn %llx pfn %llx level %d",
+                 __entry->gfn, __entry->pfn, __entry->level
+       )
+);
+
 #endif /* _TRACE_KVMMMU_H */
 
 #undef TRACE_INCLUDE_PATH
index d583bcd..7d5cdb3 100644 (file)
@@ -540,6 +540,7 @@ FNAME(prefetch_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
        mmu_set_spte(vcpu, spte, pte_access, 0, PT_PAGE_TABLE_LEVEL, gfn, pfn,
                     true, true);
 
+       kvm_release_pfn_clean(pfn);
        return true;
 }
 
@@ -619,6 +620,7 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
        struct kvm_shadow_walk_iterator it;
        unsigned direct_access, access = gw->pt_access;
        int top_level, ret;
+       gfn_t base_gfn;
 
        direct_access = gw->pte_access;
 
@@ -663,35 +665,34 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
                        link_shadow_page(vcpu, it.sptep, sp);
        }
 
-       for (;
-            shadow_walk_okay(&it) && it.level > hlevel;
-            shadow_walk_next(&it)) {
-               gfn_t direct_gfn;
+       base_gfn = gw->gfn;
+
+       trace_kvm_mmu_spte_requested(addr, gw->level, pfn);
 
+       for (; shadow_walk_okay(&it); shadow_walk_next(&it)) {
                clear_sp_write_flooding_count(it.sptep);
+               base_gfn = gw->gfn & ~(KVM_PAGES_PER_HPAGE(it.level) - 1);
+               if (it.level == hlevel)
+                       break;
+
                validate_direct_spte(vcpu, it.sptep, direct_access);
 
                drop_large_spte(vcpu, it.sptep);
 
-               if (is_shadow_present_pte(*it.sptep))
-                       continue;
-
-               direct_gfn = gw->gfn & ~(KVM_PAGES_PER_HPAGE(it.level) - 1);
-
-               sp = kvm_mmu_get_page(vcpu, direct_gfn, addr, it.level-1,
-                                     true, direct_access);
-               link_shadow_page(vcpu, it.sptep, sp);
+               if (!is_shadow_present_pte(*it.sptep)) {
+                       sp = kvm_mmu_get_page(vcpu, base_gfn, addr,
+                                             it.level - 1, true, direct_access);
+                       link_shadow_page(vcpu, it.sptep, sp);
+               }
        }
 
-       clear_sp_write_flooding_count(it.sptep);
        ret = mmu_set_spte(vcpu, it.sptep, gw->pte_access, write_fault,
-                          it.level, gw->gfn, pfn, prefault, map_writable);
+                          it.level, base_gfn, pfn, prefault, map_writable);
        FNAME(pte_prefetch)(vcpu, gw, it.sptep);
-
+       ++vcpu->stat.pf_fixed;
        return ret;
 
 out_gpte_changed:
-       kvm_release_pfn_clean(pfn);
        return RET_PF_RETRY;
 }
 
@@ -839,6 +840,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code,
                        walker.pte_access &= ~ACC_EXEC_MASK;
        }
 
+       r = RET_PF_RETRY;
        spin_lock(&vcpu->kvm->mmu_lock);
        if (mmu_notifier_retry(vcpu->kvm, mmu_seq))
                goto out_unlock;
@@ -847,19 +849,15 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code,
        if (make_mmu_pages_available(vcpu) < 0)
                goto out_unlock;
        if (!force_pt_level)
-               transparent_hugepage_adjust(vcpu, &walker.gfn, &pfn, &level);
+               transparent_hugepage_adjust(vcpu, walker.gfn, &pfn, &level);
        r = FNAME(fetch)(vcpu, addr, &walker, write_fault,
                         level, pfn, map_writable, prefault);
-       ++vcpu->stat.pf_fixed;
        kvm_mmu_audit(vcpu, AUDIT_POST_PAGE_FAULT);
-       spin_unlock(&vcpu->kvm->mmu_lock);
-
-       return r;
 
 out_unlock:
        spin_unlock(&vcpu->kvm->mmu_lock);
        kvm_release_pfn_clean(pfn);
-       return RET_PF_RETRY;
+       return r;
 }
 
 static gpa_t FNAME(get_level1_sp_gpa)(struct kvm_mmu_page *sp)
index ab73a9a..aa5a259 100644 (file)
@@ -19,6 +19,9 @@
 #include "lapic.h"
 #include "pmu.h"
 
+/* This keeps the total size of the filter under 4k. */
+#define KVM_PMU_EVENT_FILTER_MAX_EVENTS 63
+
 /* NOTE:
  * - Each perf counter is defined as "struct kvm_pmc";
  * - There are two types of perf counters: general purpose (gp) and fixed.
@@ -141,6 +144,10 @@ void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
 {
        unsigned config, type = PERF_TYPE_RAW;
        u8 event_select, unit_mask;
+       struct kvm *kvm = pmc->vcpu->kvm;
+       struct kvm_pmu_event_filter *filter;
+       int i;
+       bool allow_event = true;
 
        if (eventsel & ARCH_PERFMON_EVENTSEL_PIN_CONTROL)
                printk_once("kvm pmu: pin control bit is ignored\n");
@@ -152,6 +159,22 @@ void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
        if (!(eventsel & ARCH_PERFMON_EVENTSEL_ENABLE) || !pmc_is_enabled(pmc))
                return;
 
+       filter = srcu_dereference(kvm->arch.pmu_event_filter, &kvm->srcu);
+       if (filter) {
+               for (i = 0; i < filter->nevents; i++)
+                       if (filter->events[i] ==
+                           (eventsel & AMD64_RAW_EVENT_MASK_NB))
+                               break;
+               if (filter->action == KVM_PMU_EVENT_ALLOW &&
+                   i == filter->nevents)
+                       allow_event = false;
+               if (filter->action == KVM_PMU_EVENT_DENY &&
+                   i < filter->nevents)
+                       allow_event = false;
+       }
+       if (!allow_event)
+               return;
+
        event_select = eventsel & ARCH_PERFMON_EVENTSEL_EVENT;
        unit_mask = (eventsel & ARCH_PERFMON_EVENTSEL_UMASK) >> 8;
 
@@ -348,3 +371,43 @@ void kvm_pmu_destroy(struct kvm_vcpu *vcpu)
 {
        kvm_pmu_reset(vcpu);
 }
+
+int kvm_vm_ioctl_set_pmu_event_filter(struct kvm *kvm, void __user *argp)
+{
+       struct kvm_pmu_event_filter tmp, *filter;
+       size_t size;
+       int r;
+
+       if (copy_from_user(&tmp, argp, sizeof(tmp)))
+               return -EFAULT;
+
+       if (tmp.action != KVM_PMU_EVENT_ALLOW &&
+           tmp.action != KVM_PMU_EVENT_DENY)
+               return -EINVAL;
+
+       if (tmp.nevents > KVM_PMU_EVENT_FILTER_MAX_EVENTS)
+               return -E2BIG;
+
+       size = struct_size(filter, events, tmp.nevents);
+       filter = kmalloc(size, GFP_KERNEL_ACCOUNT);
+       if (!filter)
+               return -ENOMEM;
+
+       r = -EFAULT;
+       if (copy_from_user(filter, argp, size))
+               goto cleanup;
+
+       /* Ensure nevents can't be changed between the user copies. */
+       *filter = tmp;
+
+       mutex_lock(&kvm->lock);
+       rcu_swap_protected(kvm->arch.pmu_event_filter, filter,
+                          mutex_is_locked(&kvm->lock));
+       mutex_unlock(&kvm->lock);
+
+       synchronize_srcu_expedited(&kvm->srcu);
+       r = 0;
+cleanup:
+       kfree(filter);
+       return r;
+}
index 22dff66..58265f7 100644 (file)
@@ -118,6 +118,7 @@ void kvm_pmu_refresh(struct kvm_vcpu *vcpu);
 void kvm_pmu_reset(struct kvm_vcpu *vcpu);
 void kvm_pmu_init(struct kvm_vcpu *vcpu);
 void kvm_pmu_destroy(struct kvm_vcpu *vcpu);
+int kvm_vm_ioctl_set_pmu_event_filter(struct kvm *kvm, void __user *argp);
 
 bool is_vmware_backdoor_pmc(u32 pmc_idx);
 
index 48c865a..583b9fa 100644 (file)
@@ -364,6 +364,10 @@ static int avic;
 module_param(avic, int, S_IRUGO);
 #endif
 
+/* enable/disable Next RIP Save */
+static int nrips = true;
+module_param(nrips, int, 0444);
+
 /* enable/disable Virtual VMLOAD VMSAVE */
 static int vls = true;
 module_param(vls, int, 0444);
@@ -770,7 +774,7 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
-       if (svm->vmcb->control.next_rip != 0) {
+       if (nrips && svm->vmcb->control.next_rip != 0) {
                WARN_ON_ONCE(!static_cpu_has(X86_FEATURE_NRIPS));
                svm->next_rip = svm->vmcb->control.next_rip;
        }
@@ -807,7 +811,7 @@ static void svm_queue_exception(struct kvm_vcpu *vcpu)
 
        kvm_deliver_exception_payload(&svm->vcpu);
 
-       if (nr == BP_VECTOR && !static_cpu_has(X86_FEATURE_NRIPS)) {
+       if (nr == BP_VECTOR && !nrips) {
                unsigned long rip, old_rip = kvm_rip_read(&svm->vcpu);
 
                /*
@@ -1364,6 +1368,11 @@ static __init int svm_hardware_setup(void)
        } else
                kvm_disable_tdp();
 
+       if (nrips) {
+               if (!boot_cpu_has(X86_FEATURE_NRIPS))
+                       nrips = false;
+       }
+
        if (avic) {
                if (!npt_enabled ||
                    !boot_cpu_has(X86_FEATURE_AVIC) ||
@@ -3290,7 +3299,7 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
                                       vmcb->control.exit_int_info_err,
                                       KVM_ISA_SVM);
 
-       rc = kvm_vcpu_map(&svm->vcpu, gfn_to_gpa(svm->nested.vmcb), &map);
+       rc = kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(svm->nested.vmcb), &map);
        if (rc) {
                if (rc == -EINVAL)
                        kvm_inject_gp(&svm->vcpu, 0);
@@ -3580,7 +3589,7 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
 
        vmcb_gpa = svm->vmcb->save.rax;
 
-       rc = kvm_vcpu_map(&svm->vcpu, gfn_to_gpa(vmcb_gpa), &map);
+       rc = kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(vmcb_gpa), &map);
        if (rc) {
                if (rc == -EINVAL)
                        kvm_inject_gp(&svm->vcpu, 0);
@@ -3935,7 +3944,7 @@ static int rdpmc_interception(struct vcpu_svm *svm)
 {
        int err;
 
-       if (!static_cpu_has(X86_FEATURE_NRIPS))
+       if (!nrips)
                return emulate_on_interception(svm);
 
        err = kvm_rdpmc(&svm->vcpu);
@@ -5160,10 +5169,13 @@ static void svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec)
        kvm_lapic_set_irr(vec, vcpu->arch.apic);
        smp_mb__after_atomic();
 
-       if (avic_vcpu_is_running(vcpu))
-               wrmsrl(SVM_AVIC_DOORBELL,
-                      kvm_cpu_get_apicid(vcpu->cpu));
-       else
+       if (avic_vcpu_is_running(vcpu)) {
+               int cpuid = vcpu->cpu;
+
+               if (cpuid != get_cpu())
+                       wrmsrl(SVM_AVIC_DOORBELL, kvm_cpu_get_apicid(cpuid));
+               put_cpu();
+       } else
                kvm_vcpu_wake_up(vcpu);
 }
 
@@ -5640,6 +5652,10 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
        clgi();
        kvm_load_guest_xcr0(vcpu);
 
+       if (lapic_in_kernel(vcpu) &&
+               vcpu->arch.apic->lapic_timer.timer_advance_ns)
+               kvm_wait_lapic_expire(vcpu);
+
        /*
         * If this vCPU has touched SPEC_CTRL, restore the guest's value if
         * it's non-zero. Since vmentry is serialising on affected CPUs, there
@@ -5861,9 +5877,9 @@ svm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
        hypercall[2] = 0xd9;
 }
 
-static void svm_check_processor_compat(void *rtn)
+static int __init svm_check_processor_compat(void)
 {
-       *(int *)rtn = 0;
+       return 0;
 }
 
 static bool svm_cpu_has_accelerated_tpr(void)
@@ -5875,6 +5891,7 @@ static bool svm_has_emulated_msr(int index)
 {
        switch (index) {
        case MSR_IA32_MCG_EXT_CTL:
+       case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC:
                return false;
        default:
                break;
@@ -6162,15 +6179,9 @@ out:
        return ret;
 }
 
-static void svm_handle_external_intr(struct kvm_vcpu *vcpu)
+static void svm_handle_exit_irqoff(struct kvm_vcpu *vcpu)
 {
-       local_irq_enable();
-       /*
-        * We must have an instruction with interrupts enabled, so
-        * the timer interrupt isn't delayed by the interrupt shadow.
-        */
-       asm("nop");
-       local_irq_disable();
+
 }
 
 static void svm_sched_in(struct kvm_vcpu *vcpu, int cpu)
@@ -7256,7 +7267,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
        .set_tdp_cr3 = set_tdp_cr3,
 
        .check_intercept = svm_check_intercept,
-       .handle_external_intr = svm_handle_external_intr,
+       .handle_exit_irqoff = svm_handle_exit_irqoff,
 
        .request_immediate_exit = __kvm_request_immediate_exit,
 
index 4d47a26..b5c831e 100644 (file)
@@ -1365,7 +1365,7 @@ TRACE_EVENT(kvm_hv_timer_state,
                        __entry->vcpu_id = vcpu_id;
                        __entry->hv_timer_in_use = hv_timer_in_use;
                        ),
-               TP_printk("vcpu_id %x hv_timer %x\n",
+               TP_printk("vcpu_id %x hv_timer %x",
                        __entry->vcpu_id,
                        __entry->hv_timer_in_use)
 );
index 5466c6d..7235970 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/errno.h>
 #include <linux/smp.h>
 
+#include "../hyperv.h"
 #include "evmcs.h"
 #include "vmcs.h"
 #include "vmx.h"
@@ -313,6 +314,23 @@ void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf)
 }
 #endif
 
+bool nested_enlightened_vmentry(struct kvm_vcpu *vcpu, u64 *evmcs_gpa)
+{
+       struct hv_vp_assist_page assist_page;
+
+       *evmcs_gpa = -1ull;
+
+       if (unlikely(!kvm_hv_get_assist_page(vcpu, &assist_page)))
+               return false;
+
+       if (unlikely(!assist_page.enlighten_vmentry))
+               return false;
+
+       *evmcs_gpa = assist_page.current_nested_vmcs;
+
+       return true;
+}
+
 uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
index e0fcef8..39a24ee 100644 (file)
@@ -195,6 +195,7 @@ static inline void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf) {}
 static inline void evmcs_touch_msr_bitmap(void) {}
 #endif /* IS_ENABLED(CONFIG_HYPERV) */
 
+bool nested_enlightened_vmentry(struct kvm_vcpu *vcpu, u64 *evmcs_gpa);
 uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu);
 int nested_enable_evmcs(struct kvm_vcpu *vcpu,
                        uint16_t *vmcs_version);
index 46af3a5..bb509c2 100644 (file)
@@ -41,15 +41,19 @@ static unsigned long *vmx_bitmap[VMX_BITMAP_NR];
 #define vmx_vmread_bitmap                    (vmx_bitmap[VMX_VMREAD_BITMAP])
 #define vmx_vmwrite_bitmap                   (vmx_bitmap[VMX_VMWRITE_BITMAP])
 
-static u16 shadow_read_only_fields[] = {
-#define SHADOW_FIELD_RO(x) x,
+struct shadow_vmcs_field {
+       u16     encoding;
+       u16     offset;
+};
+static struct shadow_vmcs_field shadow_read_only_fields[] = {
+#define SHADOW_FIELD_RO(x, y) { x, offsetof(struct vmcs12, y) },
 #include "vmcs_shadow_fields.h"
 };
 static int max_shadow_read_only_fields =
        ARRAY_SIZE(shadow_read_only_fields);
 
-static u16 shadow_read_write_fields[] = {
-#define SHADOW_FIELD_RW(x) x,
+static struct shadow_vmcs_field shadow_read_write_fields[] = {
+#define SHADOW_FIELD_RW(x, y) { x, offsetof(struct vmcs12, y) },
 #include "vmcs_shadow_fields.h"
 };
 static int max_shadow_read_write_fields =
@@ -63,34 +67,40 @@ static void init_vmcs_shadow_fields(void)
        memset(vmx_vmwrite_bitmap, 0xff, PAGE_SIZE);
 
        for (i = j = 0; i < max_shadow_read_only_fields; i++) {
-               u16 field = shadow_read_only_fields[i];
+               struct shadow_vmcs_field entry = shadow_read_only_fields[i];
+               u16 field = entry.encoding;
 
                if (vmcs_field_width(field) == VMCS_FIELD_WIDTH_U64 &&
                    (i + 1 == max_shadow_read_only_fields ||
-                    shadow_read_only_fields[i + 1] != field + 1))
+                    shadow_read_only_fields[i + 1].encoding != field + 1))
                        pr_err("Missing field from shadow_read_only_field %x\n",
                               field + 1);
 
                clear_bit(field, vmx_vmread_bitmap);
-#ifdef CONFIG_X86_64
                if (field & 1)
+#ifdef CONFIG_X86_64
                        continue;
+#else
+                       entry.offset += sizeof(u32);
 #endif
-               if (j < i)
-                       shadow_read_only_fields[j] = field;
-               j++;
+               shadow_read_only_fields[j++] = entry;
        }
        max_shadow_read_only_fields = j;
 
        for (i = j = 0; i < max_shadow_read_write_fields; i++) {
-               u16 field = shadow_read_write_fields[i];
+               struct shadow_vmcs_field entry = shadow_read_write_fields[i];
+               u16 field = entry.encoding;
 
                if (vmcs_field_width(field) == VMCS_FIELD_WIDTH_U64 &&
                    (i + 1 == max_shadow_read_write_fields ||
-                    shadow_read_write_fields[i + 1] != field + 1))
+                    shadow_read_write_fields[i + 1].encoding != field + 1))
                        pr_err("Missing field from shadow_read_write_field %x\n",
                               field + 1);
 
+               WARN_ONCE(field >= GUEST_ES_AR_BYTES &&
+                         field <= GUEST_TR_AR_BYTES,
+                         "Update vmcs12_write_any() to drop reserved bits from AR_BYTES");
+
                /*
                 * PML and the preemption timer can be emulated, but the
                 * processor cannot vmwrite to fields that don't exist
@@ -115,13 +125,13 @@ static void init_vmcs_shadow_fields(void)
 
                clear_bit(field, vmx_vmwrite_bitmap);
                clear_bit(field, vmx_vmread_bitmap);
-#ifdef CONFIG_X86_64
                if (field & 1)
+#ifdef CONFIG_X86_64
                        continue;
+#else
+                       entry.offset += sizeof(u32);
 #endif
-               if (j < i)
-                       shadow_read_write_fields[j] = field;
-               j++;
+               shadow_read_write_fields[j++] = entry;
        }
        max_shadow_read_write_fields = j;
 }
@@ -182,7 +192,7 @@ static void nested_vmx_abort(struct kvm_vcpu *vcpu, u32 indicator)
 
 static void vmx_disable_shadow_vmcs(struct vcpu_vmx *vmx)
 {
-       vmcs_clear_bits(SECONDARY_VM_EXEC_CONTROL, SECONDARY_EXEC_SHADOW_VMCS);
+       secondary_exec_controls_clearbit(vmx, SECONDARY_EXEC_SHADOW_VMCS);
        vmcs_write64(VMCS_LINK_POINTER, -1ull);
 }
 
@@ -238,22 +248,41 @@ static void free_nested(struct kvm_vcpu *vcpu)
        free_loaded_vmcs(&vmx->nested.vmcs02);
 }
 
+static void vmx_sync_vmcs_host_state(struct vcpu_vmx *vmx,
+                                    struct loaded_vmcs *prev)
+{
+       struct vmcs_host_state *dest, *src;
+
+       if (unlikely(!vmx->guest_state_loaded))
+               return;
+
+       src = &prev->host_state;
+       dest = &vmx->loaded_vmcs->host_state;
+
+       vmx_set_host_fs_gs(dest, src->fs_sel, src->gs_sel, src->fs_base, src->gs_base);
+       dest->ldt_sel = src->ldt_sel;
+#ifdef CONFIG_X86_64
+       dest->ds_sel = src->ds_sel;
+       dest->es_sel = src->es_sel;
+#endif
+}
+
 static void vmx_switch_vmcs(struct kvm_vcpu *vcpu, struct loaded_vmcs *vmcs)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
+       struct loaded_vmcs *prev;
        int cpu;
 
        if (vmx->loaded_vmcs == vmcs)
                return;
 
        cpu = get_cpu();
-       vmx_vcpu_put(vcpu);
+       prev = vmx->loaded_vmcs;
        vmx->loaded_vmcs = vmcs;
-       vmx_vcpu_load(vcpu, cpu);
+       vmx_vcpu_load_vmcs(vcpu, cpu);
+       vmx_sync_vmcs_host_state(vmx, prev);
        put_cpu();
 
-       vm_entry_controls_reset_shadow(vmx);
-       vm_exit_controls_reset_shadow(vmx);
        vmx_segment_cache_clear(vmx);
 }
 
@@ -930,8 +959,7 @@ static int nested_vmx_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3, bool ne
                 * If PAE paging and EPT are both on, CR3 is not used by the CPU and
                 * must not be dereferenced.
                 */
-               if (!is_long_mode(vcpu) && is_pae(vcpu) && is_paging(vcpu) &&
-                   !nested_ept) {
+               if (is_pae_paging(vcpu) && !nested_ept) {
                        if (!load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3)) {
                                *entry_failure_code = ENTRY_FAIL_PDPTE;
                                return -EINVAL;
@@ -1105,14 +1133,6 @@ static int vmx_restore_vmx_misc(struct vcpu_vmx *vmx, u64 data)
        vmx->nested.msrs.misc_low = data;
        vmx->nested.msrs.misc_high = data >> 32;
 
-       /*
-        * If L1 has read-only VM-exit information fields, use the
-        * less permissive vmx_vmwrite_bitmap to specify write
-        * permissions for the shadow VMCS.
-        */
-       if (enable_shadow_vmcs && !nested_cpu_has_vmwrite_any_field(&vmx->vcpu))
-               vmcs_write64(VMWRITE_BITMAP, __pa(vmx_vmwrite_bitmap));
-
        return 0;
 }
 
@@ -1214,6 +1234,11 @@ int vmx_set_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
        case MSR_IA32_VMX_VMCS_ENUM:
                vmx->nested.msrs.vmcs_enum = data;
                return 0;
+       case MSR_IA32_VMX_VMFUNC:
+               if (data & ~vmx->nested.msrs.vmfunc_controls)
+                       return -EINVAL;
+               vmx->nested.msrs.vmfunc_controls = data;
+               return 0;
        default:
                /*
                 * The rest of the VMX capability MSRs do not support restore.
@@ -1301,41 +1326,29 @@ int vmx_get_vmx_msr(struct nested_vmx_msrs *msrs, u32 msr_index, u64 *pdata)
 }
 
 /*
- * Copy the writable VMCS shadow fields back to the VMCS12, in case
- * they have been modified by the L1 guest. Note that the "read-only"
- * VM-exit information fields are actually writable if the vCPU is
- * configured to support "VMWRITE to any supported field in the VMCS."
+ * Copy the writable VMCS shadow fields back to the VMCS12, in case they have
+ * been modified by the L1 guest.  Note, "writable" in this context means
+ * "writable by the guest", i.e. tagged SHADOW_FIELD_RW; the set of
+ * fields tagged SHADOW_FIELD_RO may or may not align with the "read-only"
+ * VM-exit information fields (which are actually writable if the vCPU is
+ * configured to support "VMWRITE to any supported field in the VMCS").
  */
 static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx)
 {
-       const u16 *fields[] = {
-               shadow_read_write_fields,
-               shadow_read_only_fields
-       };
-       const int max_fields[] = {
-               max_shadow_read_write_fields,
-               max_shadow_read_only_fields
-       };
-       int i, q;
-       unsigned long field;
-       u64 field_value;
        struct vmcs *shadow_vmcs = vmx->vmcs01.shadow_vmcs;
+       struct vmcs12 *vmcs12 = get_vmcs12(&vmx->vcpu);
+       struct shadow_vmcs_field field;
+       unsigned long val;
+       int i;
 
        preempt_disable();
 
        vmcs_load(shadow_vmcs);
 
-       for (q = 0; q < ARRAY_SIZE(fields); q++) {
-               for (i = 0; i < max_fields[q]; i++) {
-                       field = fields[q][i];
-                       field_value = __vmcs_readl(field);
-                       vmcs12_write_any(get_vmcs12(&vmx->vcpu), field, field_value);
-               }
-               /*
-                * Skip the VM-exit information fields if they are read-only.
-                */
-               if (!nested_cpu_has_vmwrite_any_field(&vmx->vcpu))
-                       break;
+       for (i = 0; i < max_shadow_read_write_fields; i++) {
+               field = shadow_read_write_fields[i];
+               val = __vmcs_readl(field.encoding);
+               vmcs12_write_any(vmcs12, field.encoding, field.offset, val);
        }
 
        vmcs_clear(shadow_vmcs);
@@ -1346,7 +1359,7 @@ static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx)
 
 static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
 {
-       const u16 *fields[] = {
+       const struct shadow_vmcs_field *fields[] = {
                shadow_read_write_fields,
                shadow_read_only_fields
        };
@@ -1354,18 +1367,20 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
                max_shadow_read_write_fields,
                max_shadow_read_only_fields
        };
-       int i, q;
-       unsigned long field;
-       u64 field_value = 0;
        struct vmcs *shadow_vmcs = vmx->vmcs01.shadow_vmcs;
+       struct vmcs12 *vmcs12 = get_vmcs12(&vmx->vcpu);
+       struct shadow_vmcs_field field;
+       unsigned long val;
+       int i, q;
 
        vmcs_load(shadow_vmcs);
 
        for (q = 0; q < ARRAY_SIZE(fields); q++) {
                for (i = 0; i < max_fields[q]; i++) {
                        field = fields[q][i];
-                       vmcs12_read_any(get_vmcs12(&vmx->vcpu), field, &field_value);
-                       __vmcs_writel(field, field_value);
+                       val = vmcs12_read_any(vmcs12, field.encoding,
+                                             field.offset);
+                       __vmcs_writel(field.encoding, val);
                }
        }
 
@@ -1623,7 +1638,7 @@ static int copy_vmcs12_to_enlightened(struct vcpu_vmx *vmx)
         * evmcs->host_gdtr_base = vmcs12->host_gdtr_base;
         * evmcs->host_idtr_base = vmcs12->host_idtr_base;
         * evmcs->host_rsp = vmcs12->host_rsp;
-        * sync_vmcs12() doesn't read these:
+        * sync_vmcs02_to_vmcs12() doesn't read these:
         * evmcs->io_bitmap_a = vmcs12->io_bitmap_a;
         * evmcs->io_bitmap_b = vmcs12->io_bitmap_b;
         * evmcs->msr_bitmap = vmcs12->msr_bitmap;
@@ -1768,26 +1783,22 @@ static int nested_vmx_handle_enlightened_vmptrld(struct kvm_vcpu *vcpu,
                                                 bool from_launch)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
-       struct hv_vp_assist_page assist_page;
+       bool evmcs_gpa_changed = false;
+       u64 evmcs_gpa;
 
        if (likely(!vmx->nested.enlightened_vmcs_enabled))
                return 1;
 
-       if (unlikely(!kvm_hv_get_assist_page(vcpu, &assist_page)))
-               return 1;
-
-       if (unlikely(!assist_page.enlighten_vmentry))
+       if (!nested_enlightened_vmentry(vcpu, &evmcs_gpa))
                return 1;
 
-       if (unlikely(assist_page.current_nested_vmcs !=
-                    vmx->nested.hv_evmcs_vmptr)) {
-
+       if (unlikely(evmcs_gpa != vmx->nested.hv_evmcs_vmptr)) {
                if (!vmx->nested.hv_evmcs)
                        vmx->nested.current_vmptr = -1ull;
 
                nested_release_evmcs(vcpu);
 
-               if (kvm_vcpu_map(vcpu, gpa_to_gfn(assist_page.current_nested_vmcs),
+               if (kvm_vcpu_map(vcpu, gpa_to_gfn(evmcs_gpa),
                                 &vmx->nested.hv_evmcs_map))
                        return 0;
 
@@ -1822,15 +1833,9 @@ static int nested_vmx_handle_enlightened_vmptrld(struct kvm_vcpu *vcpu,
                }
 
                vmx->nested.dirty_vmcs12 = true;
-               /*
-                * As we keep L2 state for one guest only 'hv_clean_fields' mask
-                * can't be used when we switch between them. Reset it here for
-                * simplicity.
-                */
-               vmx->nested.hv_evmcs->hv_clean_fields &=
-                       ~HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL;
-               vmx->nested.hv_evmcs_vmptr = assist_page.current_nested_vmcs;
+               vmx->nested.hv_evmcs_vmptr = evmcs_gpa;
 
+               evmcs_gpa_changed = true;
                /*
                 * Unlike normal vmcs12, enlightened vmcs12 is not fully
                 * reloaded from guest's memory (read only fields, fields not
@@ -1844,10 +1849,19 @@ static int nested_vmx_handle_enlightened_vmptrld(struct kvm_vcpu *vcpu,
                }
 
        }
+
+       /*
+        * Clean fields data can't de used on VMLAUNCH and when we switch
+        * between different L2 guests as KVM keeps a single VMCS12 per L1.
+        */
+       if (from_launch || evmcs_gpa_changed)
+               vmx->nested.hv_evmcs->hv_clean_fields &=
+                       ~HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL;
+
        return 1;
 }
 
-void nested_sync_from_vmcs12(struct kvm_vcpu *vcpu)
+void nested_sync_vmcs12_to_shadow(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
@@ -1868,7 +1882,7 @@ void nested_sync_from_vmcs12(struct kvm_vcpu *vcpu)
                copy_vmcs12_to_shadow(vmx);
        }
 
-       vmx->nested.need_vmcs12_sync = false;
+       vmx->nested.need_vmcs12_to_shadow_sync = false;
 }
 
 static enum hrtimer_restart vmx_preemption_timer_fn(struct hrtimer *timer)
@@ -1948,8 +1962,20 @@ static void prepare_vmcs02_constant_state(struct vcpu_vmx *vmx)
        if (cpu_has_vmx_msr_bitmap())
                vmcs_write64(MSR_BITMAP, __pa(vmx->nested.vmcs02.msr_bitmap));
 
-       if (enable_pml)
+       /*
+        * The PML address never changes, so it is constant in vmcs02.
+        * Conceptually we want to copy the PML index from vmcs01 here,
+        * and then back to vmcs01 on nested vmexit.  But since we flush
+        * the log and reset GUEST_PML_INDEX on each vmexit, the PML
+        * index is also effectively constant in vmcs02.
+        */
+       if (enable_pml) {
                vmcs_write64(PML_ADDRESS, page_to_phys(vmx->pml_pg));
+               vmcs_write16(GUEST_PML_INDEX, PML_ENTITY_NUM - 1);
+       }
+
+       if (cpu_has_vmx_encls_vmexit())
+               vmcs_write64(ENCLS_EXITING_BITMAP, -1ull);
 
        /*
         * Set the MSR load/store lists to match L0's settings.  Only the
@@ -1963,7 +1989,7 @@ static void prepare_vmcs02_constant_state(struct vcpu_vmx *vmx)
        vmx_set_constant_host_state(vmx);
 }
 
-static void prepare_vmcs02_early_full(struct vcpu_vmx *vmx,
+static void prepare_vmcs02_early_rare(struct vcpu_vmx *vmx,
                                      struct vmcs12 *vmcs12)
 {
        prepare_vmcs02_constant_state(vmx);
@@ -1984,17 +2010,14 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
        u64 guest_efer = nested_vmx_calc_efer(vmx, vmcs12);
 
        if (vmx->nested.dirty_vmcs12 || vmx->nested.hv_evmcs)
-               prepare_vmcs02_early_full(vmx, vmcs12);
+               prepare_vmcs02_early_rare(vmx, vmcs12);
 
        /*
         * PIN CONTROLS
         */
-       exec_control = vmcs12->pin_based_vm_exec_control;
-
-       /* Preemption timer setting is computed directly in vmx_vcpu_run.  */
-       exec_control |= vmcs_config.pin_based_exec_ctrl;
-       exec_control &= ~PIN_BASED_VMX_PREEMPTION_TIMER;
-       vmx->loaded_vmcs->hv_timer_armed = false;
+       exec_control = vmx_pin_based_exec_ctrl(vmx);
+       exec_control |= (vmcs12->pin_based_vm_exec_control &
+                        ~PIN_BASED_VMX_PREEMPTION_TIMER);
 
        /* Posted interrupts setting is only taken from vmcs12.  */
        if (nested_cpu_has_posted_intr(vmcs12)) {
@@ -2003,7 +2026,7 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
        } else {
                exec_control &= ~PIN_BASED_POSTED_INTR;
        }
-       vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, exec_control);
+       pin_controls_set(vmx, exec_control);
 
        /*
         * EXEC CONTROLS
@@ -2014,28 +2037,31 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
        exec_control &= ~CPU_BASED_TPR_SHADOW;
        exec_control |= vmcs12->cpu_based_vm_exec_control;
 
-       /*
-        * Write an illegal value to VIRTUAL_APIC_PAGE_ADDR. Later, if
-        * nested_get_vmcs12_pages can't fix it up, the illegal value
-        * will result in a VM entry failure.
-        */
-       if (exec_control & CPU_BASED_TPR_SHADOW) {
-               vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, -1ull);
+       if (exec_control & CPU_BASED_TPR_SHADOW)
                vmcs_write32(TPR_THRESHOLD, vmcs12->tpr_threshold);
-       } else {
 #ifdef CONFIG_X86_64
+       else
                exec_control |= CPU_BASED_CR8_LOAD_EXITING |
                                CPU_BASED_CR8_STORE_EXITING;
 #endif
-       }
 
        /*
         * A vmexit (to either L1 hypervisor or L0 userspace) is always needed
         * for I/O port accesses.
         */
-       exec_control &= ~CPU_BASED_USE_IO_BITMAPS;
        exec_control |= CPU_BASED_UNCOND_IO_EXITING;
-       vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, exec_control);
+       exec_control &= ~CPU_BASED_USE_IO_BITMAPS;
+
+       /*
+        * This bit will be computed in nested_get_vmcs12_pages, because
+        * we do not have access to L1's MSR bitmap yet.  For now, keep
+        * the same bit as before, hoping to avoid multiple VMWRITEs that
+        * only set/clear this bit.
+        */
+       exec_control &= ~CPU_BASED_USE_MSR_BITMAPS;
+       exec_control |= exec_controls_get(vmx) & CPU_BASED_USE_MSR_BITMAPS;
+
+       exec_controls_set(vmx, exec_control);
 
        /*
         * SECONDARY EXEC CONTROLS
@@ -2061,22 +2087,19 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
                /* VMCS shadowing for L2 is emulated for now */
                exec_control &= ~SECONDARY_EXEC_SHADOW_VMCS;
 
-               if (exec_control & SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY)
-                       vmcs_write16(GUEST_INTR_STATUS,
-                               vmcs12->guest_intr_status);
-
                /*
-                * Write an illegal value to APIC_ACCESS_ADDR. Later,
-                * nested_get_vmcs12_pages will either fix it up or
-                * remove the VM execution control.
+                * Preset *DT exiting when emulating UMIP, so that vmx_set_cr4()
+                * will not have to rewrite the controls just for this bit.
                 */
-               if (exec_control & SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)
-                       vmcs_write64(APIC_ACCESS_ADDR, -1ull);
+               if (!boot_cpu_has(X86_FEATURE_UMIP) && vmx_umip_emulated() &&
+                   (vmcs12->guest_cr4 & X86_CR4_UMIP))
+                       exec_control |= SECONDARY_EXEC_DESC;
 
-               if (exec_control & SECONDARY_EXEC_ENCLS_EXITING)
-                       vmcs_write64(ENCLS_EXITING_BITMAP, -1ull);
+               if (exec_control & SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY)
+                       vmcs_write16(GUEST_INTR_STATUS,
+                               vmcs12->guest_intr_status);
 
-               vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control);
+               secondary_exec_controls_set(vmx, exec_control);
        }
 
        /*
@@ -2095,7 +2118,7 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
                if (guest_efer != host_efer)
                        exec_control |= VM_ENTRY_LOAD_IA32_EFER;
        }
-       vm_entry_controls_init(vmx, exec_control);
+       vm_entry_controls_set(vmx, exec_control);
 
        /*
         * EXIT CONTROLS
@@ -2107,17 +2130,7 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
        exec_control = vmx_vmexit_ctrl();
        if (cpu_has_load_ia32_efer() && guest_efer != host_efer)
                exec_control |= VM_EXIT_LOAD_IA32_EFER;
-       vm_exit_controls_init(vmx, exec_control);
-
-       /*
-        * Conceptually we want to copy the PML address and index from
-        * vmcs01 here, and then back to vmcs01 on nested vmexit. But,
-        * since we always flush the log on each vmexit and never change
-        * the PML address (once set), this happens to be equivalent to
-        * simply resetting the index in vmcs02.
-        */
-       if (enable_pml)
-               vmcs_write16(GUEST_PML_INDEX, PML_ENTITY_NUM - 1);
+       vm_exit_controls_set(vmx, exec_control);
 
        /*
         * Interrupt/Exception Fields
@@ -2138,7 +2151,7 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
        }
 }
 
-static void prepare_vmcs02_full(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
+static void prepare_vmcs02_rare(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
 {
        struct hv_enlightened_vmcs *hv_evmcs = vmx->nested.hv_evmcs;
 
@@ -2162,6 +2175,8 @@ static void prepare_vmcs02_full(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
                vmcs_write32(GUEST_TR_LIMIT, vmcs12->guest_tr_limit);
                vmcs_write32(GUEST_GDTR_LIMIT, vmcs12->guest_gdtr_limit);
                vmcs_write32(GUEST_IDTR_LIMIT, vmcs12->guest_idtr_limit);
+               vmcs_write32(GUEST_CS_AR_BYTES, vmcs12->guest_cs_ar_bytes);
+               vmcs_write32(GUEST_SS_AR_BYTES, vmcs12->guest_ss_ar_bytes);
                vmcs_write32(GUEST_ES_AR_BYTES, vmcs12->guest_es_ar_bytes);
                vmcs_write32(GUEST_DS_AR_BYTES, vmcs12->guest_ds_ar_bytes);
                vmcs_write32(GUEST_FS_AR_BYTES, vmcs12->guest_fs_ar_bytes);
@@ -2198,6 +2213,10 @@ static void prepare_vmcs02_full(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
                        vmcs_write64(GUEST_PDPTR2, vmcs12->guest_pdptr2);
                        vmcs_write64(GUEST_PDPTR3, vmcs12->guest_pdptr3);
                }
+
+               if (kvm_mpx_supported() && vmx->nested.nested_run_pending &&
+                   (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS))
+                       vmcs_write64(GUEST_BNDCFGS, vmcs12->guest_bndcfgs);
        }
 
        if (nested_cpu_has_xsaves(vmcs12))
@@ -2233,14 +2252,6 @@ static void prepare_vmcs02_full(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
        vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr);
 
        set_cr4_guest_host_mask(vmx);
-
-       if (kvm_mpx_supported()) {
-               if (vmx->nested.nested_run_pending &&
-                       (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS))
-                       vmcs_write64(GUEST_BNDCFGS, vmcs12->guest_bndcfgs);
-               else
-                       vmcs_write64(GUEST_BNDCFGS, vmx->nested.vmcs01_guest_bndcfgs);
-       }
 }
 
 /*
@@ -2259,20 +2270,15 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        struct hv_enlightened_vmcs *hv_evmcs = vmx->nested.hv_evmcs;
+       bool load_guest_pdptrs_vmcs12 = false;
 
-       if (vmx->nested.dirty_vmcs12 || vmx->nested.hv_evmcs) {
-               prepare_vmcs02_full(vmx, vmcs12);
+       if (vmx->nested.dirty_vmcs12 || hv_evmcs) {
+               prepare_vmcs02_rare(vmx, vmcs12);
                vmx->nested.dirty_vmcs12 = false;
-       }
 
-       /*
-        * First, the fields that are shadowed.  This must be kept in sync
-        * with vmcs_shadow_fields.h.
-        */
-       if (!hv_evmcs || !(hv_evmcs->hv_clean_fields &
-                          HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2)) {
-               vmcs_write32(GUEST_CS_AR_BYTES, vmcs12->guest_cs_ar_bytes);
-               vmcs_write32(GUEST_SS_AR_BYTES, vmcs12->guest_ss_ar_bytes);
+               load_guest_pdptrs_vmcs12 = !hv_evmcs ||
+                       !(hv_evmcs->hv_clean_fields &
+                         HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1);
        }
 
        if (vmx->nested.nested_run_pending &&
@@ -2283,6 +2289,9 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
                kvm_set_dr(vcpu, 7, vcpu->arch.dr7);
                vmcs_write64(GUEST_IA32_DEBUGCTL, vmx->nested.vmcs01_debugctl);
        }
+       if (kvm_mpx_supported() && (!vmx->nested.nested_run_pending ||
+           !(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS)))
+               vmcs_write64(GUEST_BNDCFGS, vmx->nested.vmcs01_guest_bndcfgs);
        vmx_set_rflags(vcpu, vmcs12->guest_rflags);
 
        /* EXCEPTION_BITMAP and CR0_GUEST_HOST_MASK should basically be the
@@ -2372,6 +2381,15 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
                                entry_failure_code))
                return -EINVAL;
 
+       /* Late preparation of GUEST_PDPTRs now that EFER and CRs are set. */
+       if (load_guest_pdptrs_vmcs12 && nested_cpu_has_ept(vmcs12) &&
+           is_pae_paging(vcpu)) {
+               vmcs_write64(GUEST_PDPTR0, vmcs12->guest_pdptr0);
+               vmcs_write64(GUEST_PDPTR1, vmcs12->guest_pdptr1);
+               vmcs_write64(GUEST_PDPTR2, vmcs12->guest_pdptr2);
+               vmcs_write64(GUEST_PDPTR3, vmcs12->guest_pdptr3);
+       }
+
        if (!enable_ept)
                vcpu->arch.walk_mmu->inject_page_fault = vmx_inject_page_fault_nested;
 
@@ -2609,6 +2627,30 @@ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu,
            !kvm_pat_valid(vmcs12->host_ia32_pat))
                return -EINVAL;
 
+       ia32e = (vmcs12->vm_exit_controls &
+                VM_EXIT_HOST_ADDR_SPACE_SIZE) != 0;
+
+       if (vmcs12->host_cs_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
+           vmcs12->host_ss_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
+           vmcs12->host_ds_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
+           vmcs12->host_es_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
+           vmcs12->host_fs_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
+           vmcs12->host_gs_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
+           vmcs12->host_tr_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
+           vmcs12->host_cs_selector == 0 ||
+           vmcs12->host_tr_selector == 0 ||
+           (vmcs12->host_ss_selector == 0 && !ia32e))
+               return -EINVAL;
+
+#ifdef CONFIG_X86_64
+       if (is_noncanonical_address(vmcs12->host_fs_base, vcpu) ||
+           is_noncanonical_address(vmcs12->host_gs_base, vcpu) ||
+           is_noncanonical_address(vmcs12->host_gdtr_base, vcpu) ||
+           is_noncanonical_address(vmcs12->host_idtr_base, vcpu) ||
+           is_noncanonical_address(vmcs12->host_tr_base, vcpu))
+               return -EINVAL;
+#endif
+
        /*
         * If the load IA32_EFER VM-exit control is 1, bits reserved in the
         * IA32_EFER MSR must be 0 in the field for that register. In addition,
@@ -2616,8 +2658,6 @@ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu,
         * the host address-space size VM-exit control.
         */
        if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_EFER) {
-               ia32e = (vmcs12->vm_exit_controls &
-                        VM_EXIT_HOST_ADDR_SPACE_SIZE) != 0;
                if (!kvm_valid_efer(vcpu, vmcs12->host_ia32_efer) ||
                    ia32e != !!(vmcs12->host_ia32_efer & EFER_LMA) ||
                    ia32e != !!(vmcs12->host_ia32_efer & EFER_LME))
@@ -2781,7 +2821,7 @@ static int nested_vmx_check_vmentry_hw(struct kvm_vcpu *vcpu)
                [launched]"i"(offsetof(struct loaded_vmcs, launched)),
                [host_state_rsp]"i"(offsetof(struct loaded_vmcs, host_state.rsp)),
                [wordsize]"i"(sizeof(ulong))
-             : "cc", "memory"
+             : "memory"
        );
 
        if (vmx->msr_autoload.host.nr)
@@ -2851,18 +2891,14 @@ static void nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
                        hpa = page_to_phys(vmx->nested.apic_access_page);
                        vmcs_write64(APIC_ACCESS_ADDR, hpa);
                } else {
-                       vmcs_clear_bits(SECONDARY_VM_EXEC_CONTROL,
-                                       SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES);
+                       secondary_exec_controls_clearbit(vmx,
+                               SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES);
                }
        }
 
        if (nested_cpu_has(vmcs12, CPU_BASED_TPR_SHADOW)) {
                map = &vmx->nested.virtual_apic_map;
 
-               /*
-                * If translation failed, VM entry will fail because
-                * prepare_vmcs02 set VIRTUAL_APIC_PAGE_ADDR to -1ull.
-                */
                if (!kvm_vcpu_map(vcpu, gpa_to_gfn(vmcs12->virtual_apic_page_addr), map)) {
                        vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, pfn_to_hpa(map->pfn));
                } else if (nested_cpu_has(vmcs12, CPU_BASED_CR8_LOAD_EXITING) &&
@@ -2876,11 +2912,13 @@ static void nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
                         * _not_ what the processor does but it's basically the
                         * only possibility we have.
                         */
-                       vmcs_clear_bits(CPU_BASED_VM_EXEC_CONTROL,
-                                       CPU_BASED_TPR_SHADOW);
+                       exec_controls_clearbit(vmx, CPU_BASED_TPR_SHADOW);
                } else {
-                       printk("bad virtual-APIC page address\n");
-                       dump_vmcs();
+                       /*
+                        * Write an illegal value to VIRTUAL_APIC_PAGE_ADDR to
+                        * force VM-Entry to fail.
+                        */
+                       vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, -1ull);
                }
        }
 
@@ -2896,11 +2934,9 @@ static void nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
                }
        }
        if (nested_vmx_prepare_msr_bitmap(vcpu, vmcs12))
-               vmcs_set_bits(CPU_BASED_VM_EXEC_CONTROL,
-                             CPU_BASED_USE_MSR_BITMAPS);
+               exec_controls_setbit(vmx, CPU_BASED_USE_MSR_BITMAPS);
        else
-               vmcs_clear_bits(CPU_BASED_VM_EXEC_CONTROL,
-                               CPU_BASED_USE_MSR_BITMAPS);
+               exec_controls_clearbit(vmx, CPU_BASED_USE_MSR_BITMAPS);
 }
 
 /*
@@ -2953,7 +2989,7 @@ int nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, bool from_vmentry)
        u32 exit_reason = EXIT_REASON_INVALID_STATE;
        u32 exit_qual;
 
-       evaluate_pending_interrupts = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL) &
+       evaluate_pending_interrupts = exec_controls_get(vmx) &
                (CPU_BASED_VIRTUAL_INTR_PENDING | CPU_BASED_VIRTUAL_NMI_PENDING);
        if (likely(!evaluate_pending_interrupts) && kvm_vcpu_apicv_active(vcpu))
                evaluate_pending_interrupts |= vmx_has_apicv_interrupt(vcpu);
@@ -2964,6 +3000,25 @@ int nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, bool from_vmentry)
                !(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS))
                vmx->nested.vmcs01_guest_bndcfgs = vmcs_read64(GUEST_BNDCFGS);
 
+       /*
+        * Overwrite vmcs01.GUEST_CR3 with L1's CR3 if EPT is disabled *and*
+        * nested early checks are disabled.  In the event of a "late" VM-Fail,
+        * i.e. a VM-Fail detected by hardware but not KVM, KVM must unwind its
+        * software model to the pre-VMEntry host state.  When EPT is disabled,
+        * GUEST_CR3 holds KVM's shadow CR3, not L1's "real" CR3, which causes
+        * nested_vmx_restore_host_state() to corrupt vcpu->arch.cr3.  Stuffing
+        * vmcs01.GUEST_CR3 results in the unwind naturally setting arch.cr3 to
+        * the correct value.  Smashing vmcs01.GUEST_CR3 is safe because nested
+        * VM-Exits, and the unwind, reset KVM's MMU, i.e. vmcs01.GUEST_CR3 is
+        * guaranteed to be overwritten with a shadow CR3 prior to re-entering
+        * L1.  Don't stuff vmcs01.GUEST_CR3 when using nested early checks as
+        * KVM modifies vcpu->arch.cr3 if and only if the early hardware checks
+        * pass, and early VM-Fails do not reset KVM's MMU, i.e. the VM-Fail
+        * path would need to manually save/restore vmcs01.GUEST_CR3.
+        */
+       if (!enable_ept && !nested_early_check)
+               vmcs_writel(GUEST_CR3, vcpu->arch.cr3);
+
        vmx_switch_vmcs(vcpu, &vmx->nested.vmcs02);
 
        prepare_vmcs02_early(vmx, vmcs12);
@@ -3059,7 +3114,7 @@ vmentry_fail_vmexit:
        vmcs12->vm_exit_reason = exit_reason | VMX_EXIT_REASONS_FAILED_VMENTRY;
        vmcs12->exit_qualification = exit_qual;
        if (enable_shadow_vmcs || vmx->nested.hv_evmcs)
-               vmx->nested.need_vmcs12_sync = true;
+               vmx->nested.need_vmcs12_to_shadow_sync = true;
        return 1;
 }
 
@@ -3077,7 +3132,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
        if (!nested_vmx_check_permission(vcpu))
                return 1;
 
-       if (!nested_vmx_handle_enlightened_vmptrld(vcpu, true))
+       if (!nested_vmx_handle_enlightened_vmptrld(vcpu, launch))
                return 1;
 
        if (!vmx->nested.hv_evmcs && vmx->nested.current_vmptr == -1ull)
@@ -3393,20 +3448,57 @@ static u32 vmx_get_preemption_timer_value(struct kvm_vcpu *vcpu)
        return value >> VMX_MISC_EMULATED_PREEMPTION_TIMER_RATE;
 }
 
-/*
- * Update the guest state fields of vmcs12 to reflect changes that
- * occurred while L2 was running. (The "IA-32e mode guest" bit of the
- * VM-entry controls is also updated, since this is really a guest
- * state bit.)
- */
-static void sync_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
-{
-       vmcs12->guest_cr0 = vmcs12_guest_cr0(vcpu, vmcs12);
-       vmcs12->guest_cr4 = vmcs12_guest_cr4(vcpu, vmcs12);
+static bool is_vmcs12_ext_field(unsigned long field)
+{
+       switch (field) {
+       case GUEST_ES_SELECTOR:
+       case GUEST_CS_SELECTOR:
+       case GUEST_SS_SELECTOR:
+       case GUEST_DS_SELECTOR:
+       case GUEST_FS_SELECTOR:
+       case GUEST_GS_SELECTOR:
+       case GUEST_LDTR_SELECTOR:
+       case GUEST_TR_SELECTOR:
+       case GUEST_ES_LIMIT:
+       case GUEST_CS_LIMIT:
+       case GUEST_SS_LIMIT:
+       case GUEST_DS_LIMIT:
+       case GUEST_FS_LIMIT:
+       case GUEST_GS_LIMIT:
+       case GUEST_LDTR_LIMIT:
+       case GUEST_TR_LIMIT:
+       case GUEST_GDTR_LIMIT:
+       case GUEST_IDTR_LIMIT:
+       case GUEST_ES_AR_BYTES:
+       case GUEST_DS_AR_BYTES:
+       case GUEST_FS_AR_BYTES:
+       case GUEST_GS_AR_BYTES:
+       case GUEST_LDTR_AR_BYTES:
+       case GUEST_TR_AR_BYTES:
+       case GUEST_ES_BASE:
+       case GUEST_CS_BASE:
+       case GUEST_SS_BASE:
+       case GUEST_DS_BASE:
+       case GUEST_FS_BASE:
+       case GUEST_GS_BASE:
+       case GUEST_LDTR_BASE:
+       case GUEST_TR_BASE:
+       case GUEST_GDTR_BASE:
+       case GUEST_IDTR_BASE:
+       case GUEST_PENDING_DBG_EXCEPTIONS:
+       case GUEST_BNDCFGS:
+               return true;
+       default:
+               break;
+       }
 
-       vmcs12->guest_rsp = kvm_rsp_read(vcpu);
-       vmcs12->guest_rip = kvm_rip_read(vcpu);
-       vmcs12->guest_rflags = vmcs_readl(GUEST_RFLAGS);
+       return false;
+}
+
+static void sync_vmcs02_to_vmcs12_rare(struct kvm_vcpu *vcpu,
+                                      struct vmcs12 *vmcs12)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
 
        vmcs12->guest_es_selector = vmcs_read16(GUEST_ES_SELECTOR);
        vmcs12->guest_cs_selector = vmcs_read16(GUEST_CS_SELECTOR);
@@ -3427,8 +3519,6 @@ static void sync_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
        vmcs12->guest_gdtr_limit = vmcs_read32(GUEST_GDTR_LIMIT);
        vmcs12->guest_idtr_limit = vmcs_read32(GUEST_IDTR_LIMIT);
        vmcs12->guest_es_ar_bytes = vmcs_read32(GUEST_ES_AR_BYTES);
-       vmcs12->guest_cs_ar_bytes = vmcs_read32(GUEST_CS_AR_BYTES);
-       vmcs12->guest_ss_ar_bytes = vmcs_read32(GUEST_SS_AR_BYTES);
        vmcs12->guest_ds_ar_bytes = vmcs_read32(GUEST_DS_AR_BYTES);
        vmcs12->guest_fs_ar_bytes = vmcs_read32(GUEST_FS_AR_BYTES);
        vmcs12->guest_gs_ar_bytes = vmcs_read32(GUEST_GS_AR_BYTES);
@@ -3444,11 +3534,69 @@ static void sync_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
        vmcs12->guest_tr_base = vmcs_readl(GUEST_TR_BASE);
        vmcs12->guest_gdtr_base = vmcs_readl(GUEST_GDTR_BASE);
        vmcs12->guest_idtr_base = vmcs_readl(GUEST_IDTR_BASE);
+       vmcs12->guest_pending_dbg_exceptions =
+               vmcs_readl(GUEST_PENDING_DBG_EXCEPTIONS);
+       if (kvm_mpx_supported())
+               vmcs12->guest_bndcfgs = vmcs_read64(GUEST_BNDCFGS);
+
+       vmx->nested.need_sync_vmcs02_to_vmcs12_rare = false;
+}
+
+static void copy_vmcs02_to_vmcs12_rare(struct kvm_vcpu *vcpu,
+                                      struct vmcs12 *vmcs12)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       int cpu;
+
+       if (!vmx->nested.need_sync_vmcs02_to_vmcs12_rare)
+               return;
+
+
+       WARN_ON_ONCE(vmx->loaded_vmcs != &vmx->vmcs01);
+
+       cpu = get_cpu();
+       vmx->loaded_vmcs = &vmx->nested.vmcs02;
+       vmx_vcpu_load(&vmx->vcpu, cpu);
+
+       sync_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
+
+       vmx->loaded_vmcs = &vmx->vmcs01;
+       vmx_vcpu_load(&vmx->vcpu, cpu);
+       put_cpu();
+}
+
+/*
+ * Update the guest state fields of vmcs12 to reflect changes that
+ * occurred while L2 was running. (The "IA-32e mode guest" bit of the
+ * VM-entry controls is also updated, since this is really a guest
+ * state bit.)
+ */
+static void sync_vmcs02_to_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+       if (vmx->nested.hv_evmcs)
+               sync_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
+
+       vmx->nested.need_sync_vmcs02_to_vmcs12_rare = !vmx->nested.hv_evmcs;
+
+       vmcs12->guest_cr0 = vmcs12_guest_cr0(vcpu, vmcs12);
+       vmcs12->guest_cr4 = vmcs12_guest_cr4(vcpu, vmcs12);
+
+       vmcs12->guest_rsp = kvm_rsp_read(vcpu);
+       vmcs12->guest_rip = kvm_rip_read(vcpu);
+       vmcs12->guest_rflags = vmcs_readl(GUEST_RFLAGS);
+
+       vmcs12->guest_cs_ar_bytes = vmcs_read32(GUEST_CS_AR_BYTES);
+       vmcs12->guest_ss_ar_bytes = vmcs_read32(GUEST_SS_AR_BYTES);
+
+       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);
 
        vmcs12->guest_interruptibility_info =
                vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
-       vmcs12->guest_pending_dbg_exceptions =
-               vmcs_readl(GUEST_PENDING_DBG_EXCEPTIONS);
+
        if (vcpu->arch.mp_state == KVM_MP_STATE_HALTED)
                vmcs12->guest_activity_state = GUEST_ACTIVITY_HLT;
        else
@@ -3469,10 +3617,12 @@ static void sync_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
         */
        if (enable_ept) {
                vmcs12->guest_cr3 = vmcs_readl(GUEST_CR3);
-               vmcs12->guest_pdptr0 = vmcs_read64(GUEST_PDPTR0);
-               vmcs12->guest_pdptr1 = vmcs_read64(GUEST_PDPTR1);
-               vmcs12->guest_pdptr2 = vmcs_read64(GUEST_PDPTR2);
-               vmcs12->guest_pdptr3 = vmcs_read64(GUEST_PDPTR3);
+               if (nested_cpu_has_ept(vmcs12) && is_pae_paging(vcpu)) {
+                       vmcs12->guest_pdptr0 = vmcs_read64(GUEST_PDPTR0);
+                       vmcs12->guest_pdptr1 = vmcs_read64(GUEST_PDPTR1);
+                       vmcs12->guest_pdptr2 = vmcs_read64(GUEST_PDPTR2);
+                       vmcs12->guest_pdptr3 = vmcs_read64(GUEST_PDPTR3);
+               }
        }
 
        vmcs12->guest_linear_address = vmcs_readl(GUEST_LINEAR_ADDRESS);
@@ -3484,22 +3634,11 @@ static void sync_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
                (vmcs12->vm_entry_controls & ~VM_ENTRY_IA32E_MODE) |
                (vm_entry_controls_get(to_vmx(vcpu)) & VM_ENTRY_IA32E_MODE);
 
-       if (vmcs12->vm_exit_controls & VM_EXIT_SAVE_DEBUG_CONTROLS) {
+       if (vmcs12->vm_exit_controls & VM_EXIT_SAVE_DEBUG_CONTROLS)
                kvm_get_dr(vcpu, 7, (unsigned long *)&vmcs12->guest_dr7);
-               vmcs12->guest_ia32_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL);
-       }
 
-       /* TODO: These cannot have changed unless we have MSR bitmaps and
-        * the relevant bit asks not to trap the change */
-       if (vmcs12->vm_exit_controls & VM_EXIT_SAVE_IA32_PAT)
-               vmcs12->guest_ia32_pat = vmcs_read64(GUEST_IA32_PAT);
        if (vmcs12->vm_exit_controls & VM_EXIT_SAVE_IA32_EFER)
                vmcs12->guest_ia32_efer = vcpu->arch.efer;
-       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 (kvm_mpx_supported())
-               vmcs12->guest_bndcfgs = vmcs_read64(GUEST_BNDCFGS);
 }
 
 /*
@@ -3517,11 +3656,7 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
                           u32 exit_reason, u32 exit_intr_info,
                           unsigned long exit_qualification)
 {
-       /* update guest state fields: */
-       sync_vmcs12(vcpu, vmcs12);
-
        /* update exit information fields: */
-
        vmcs12->vm_exit_reason = exit_reason;
        vmcs12->exit_qualification = exit_qualification;
        vmcs12->vm_exit_intr_info = exit_intr_info;
@@ -3775,18 +3910,8 @@ static void nested_vmx_restore_host_state(struct kvm_vcpu *vcpu)
        vmx_set_cr4(vcpu, vmcs_readl(CR4_READ_SHADOW));
 
        nested_ept_uninit_mmu_context(vcpu);
-
-       /*
-        * This is only valid if EPT is in use, otherwise the vmcs01 GUEST_CR3
-        * points to shadow pages!  Fortunately we only get here after a WARN_ON
-        * if EPT is disabled, so a VMabort is perfectly fine.
-        */
-       if (enable_ept) {
-               vcpu->arch.cr3 = vmcs_readl(GUEST_CR3);
-               __set_bit(VCPU_EXREG_CR3, (ulong *)&vcpu->arch.regs_avail);
-       } else {
-               nested_vmx_abort(vcpu, VMX_ABORT_VMCS_CORRUPTED);
-       }
+       vcpu->arch.cr3 = vmcs_readl(GUEST_CR3);
+       __set_bit(VCPU_EXREG_CR3, (ulong *)&vcpu->arch.regs_avail);
 
        /*
         * Use ept_save_pdptrs(vcpu) to load the MMU's cached PDPTRs
@@ -3794,7 +3919,8 @@ static void nested_vmx_restore_host_state(struct kvm_vcpu *vcpu)
         * VMFail, like everything else we just need to ensure our
         * software model is up-to-date.
         */
-       ept_save_pdptrs(vcpu);
+       if (enable_ept)
+               ept_save_pdptrs(vcpu);
 
        kvm_mmu_reset_context(vcpu);
 
@@ -3882,14 +4008,14 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
                vcpu->arch.tsc_offset -= vmcs12->tsc_offset;
 
        if (likely(!vmx->fail)) {
-               if (exit_reason == -1)
-                       sync_vmcs12(vcpu, vmcs12);
-               else
+               sync_vmcs02_to_vmcs12(vcpu, vmcs12);
+
+               if (exit_reason != -1)
                        prepare_vmcs12(vcpu, vmcs12, exit_reason, exit_intr_info,
                                       exit_qualification);
 
                /*
-                * Must happen outside of sync_vmcs12() as it will
+                * Must happen outside of sync_vmcs02_to_vmcs12() as it will
                 * also be used to capture vmcs12 cache as part of
                 * capturing nVMX state for snapshot (migration).
                 *
@@ -3945,7 +4071,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
        kvm_make_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu);
 
        if ((exit_reason != -1) && (enable_shadow_vmcs || vmx->nested.hv_evmcs))
-               vmx->nested.need_vmcs12_sync = true;
+               vmx->nested.need_vmcs12_to_shadow_sync = true;
 
        /* in case we halted in L2 */
        vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
@@ -4008,7 +4134,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
  * #UD or #GP.
  */
 int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
-                       u32 vmx_instruction_info, bool wr, gva_t *ret)
+                       u32 vmx_instruction_info, bool wr, int len, gva_t *ret)
 {
        gva_t off;
        bool exn;
@@ -4115,7 +4241,7 @@ int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
                 */
                if (!(s.base == 0 && s.limit == 0xffffffff &&
                     ((s.type & 8) || !(s.type & 4))))
-                       exn = exn || (off + sizeof(u64) > s.limit);
+                       exn = exn || ((u64)off + len - 1 > s.limit);
        }
        if (exn) {
                kvm_queue_exception_e(vcpu,
@@ -4134,7 +4260,8 @@ static int nested_vmx_get_vmptr(struct kvm_vcpu *vcpu, gpa_t *vmpointer)
        struct x86_exception e;
 
        if (get_vmx_mem_address(vcpu, vmcs_readl(EXIT_QUALIFICATION),
-                       vmcs_read32(VMX_INSTRUCTION_INFO), false, &gva))
+                               vmcs_read32(VMX_INSTRUCTION_INFO), false,
+                               sizeof(*vmpointer), &gva))
                return 1;
 
        if (kvm_read_guest_virt(vcpu, gva, vmpointer, sizeof(*vmpointer), &e)) {
@@ -4300,11 +4427,13 @@ static inline void nested_release_vmcs12(struct kvm_vcpu *vcpu)
        if (vmx->nested.current_vmptr == -1ull)
                return;
 
+       copy_vmcs02_to_vmcs12_rare(vcpu, get_vmcs12(vcpu));
+
        if (enable_shadow_vmcs) {
                /* copy to memory all shadowed fields in case
                   they were modified */
                copy_shadow_to_vmcs12(vmx);
-               vmx->nested.need_vmcs12_sync = false;
+               vmx->nested.need_vmcs12_to_shadow_sync = false;
                vmx_disable_shadow_vmcs(vmx);
        }
        vmx->nested.posted_intr_nv = -1;
@@ -4334,6 +4463,7 @@ static int handle_vmclear(struct kvm_vcpu *vcpu)
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        u32 zero = 0;
        gpa_t vmptr;
+       u64 evmcs_gpa;
 
        if (!nested_vmx_check_permission(vcpu))
                return 1;
@@ -4349,10 +4479,18 @@ static int handle_vmclear(struct kvm_vcpu *vcpu)
                return nested_vmx_failValid(vcpu,
                        VMXERR_VMCLEAR_VMXON_POINTER);
 
-       if (vmx->nested.hv_evmcs_map.hva) {
-               if (vmptr == vmx->nested.hv_evmcs_vmptr)
-                       nested_release_evmcs(vcpu);
-       } else {
+       /*
+        * When Enlightened VMEntry is enabled on the calling CPU we treat
+        * memory area pointer by vmptr as Enlightened VMCS (as there's no good
+        * way to distinguish it from VMCS12) and we must not corrupt it by
+        * writing to the non-existent 'launch_state' field. The area doesn't
+        * have to be the currently active EVMCS on the calling CPU and there's
+        * nothing KVM has to do to transition it from 'active' to 'non-active'
+        * state. It is possible that the area will stay mapped as
+        * vmx->nested.hv_evmcs but this shouldn't be a problem.
+        */
+       if (likely(!vmx->nested.enlightened_vmcs_enabled ||
+                  !nested_enlightened_vmentry(vcpu, &evmcs_gpa))) {
                if (vmptr == vmx->nested.current_vmptr)
                        nested_release_vmcs12(vcpu);
 
@@ -4386,8 +4524,10 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
        u64 field_value;
        unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
        u32 vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
+       int len;
        gva_t gva = 0;
        struct vmcs12 *vmcs12;
+       short offset;
 
        if (!nested_vmx_check_permission(vcpu))
                return 1;
@@ -4409,11 +4549,18 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
 
        /* Decode instruction info and find the field to read */
        field = kvm_register_readl(vcpu, (((vmx_instruction_info) >> 28) & 0xf));
-       /* Read the field, zero-extended to a u64 field_value */
-       if (vmcs12_read_any(vmcs12, field, &field_value) < 0)
+
+       offset = vmcs_field_to_offset(field);
+       if (offset < 0)
                return nested_vmx_failValid(vcpu,
                        VMXERR_UNSUPPORTED_VMCS_COMPONENT);
 
+       if (!is_guest_mode(vcpu) && is_vmcs12_ext_field(field))
+               copy_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
+
+       /* Read the field, zero-extended to a u64 field_value */
+       field_value = vmcs12_read_any(vmcs12, field, offset);
+
        /*
         * Now copy part of this value to register or memory, as requested.
         * Note that the number of bits actually copied is 32 or 64 depending
@@ -4423,21 +4570,45 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
                kvm_register_writel(vcpu, (((vmx_instruction_info) >> 3) & 0xf),
                        field_value);
        } else {
+               len = is_64_bit_mode(vcpu) ? 8 : 4;
                if (get_vmx_mem_address(vcpu, exit_qualification,
-                               vmx_instruction_info, true, &gva))
+                               vmx_instruction_info, true, len, &gva))
                        return 1;
                /* _system ok, nested_vmx_check_permission has verified cpl=0 */
-               kvm_write_guest_virt_system(vcpu, gva, &field_value,
-                                           (is_long_mode(vcpu) ? 8 : 4), NULL);
+               kvm_write_guest_virt_system(vcpu, gva, &field_value, len, NULL);
        }
 
        return nested_vmx_succeed(vcpu);
 }
 
+static bool is_shadow_field_rw(unsigned long field)
+{
+       switch (field) {
+#define SHADOW_FIELD_RW(x, y) case x:
+#include "vmcs_shadow_fields.h"
+               return true;
+       default:
+               break;
+       }
+       return false;
+}
+
+static bool is_shadow_field_ro(unsigned long field)
+{
+       switch (field) {
+#define SHADOW_FIELD_RO(x, y) case x:
+#include "vmcs_shadow_fields.h"
+               return true;
+       default:
+               break;
+       }
+       return false;
+}
 
 static int handle_vmwrite(struct kvm_vcpu *vcpu)
 {
        unsigned long field;
+       int len;
        gva_t gva;
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
@@ -4452,6 +4623,7 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu)
        u64 field_value = 0;
        struct x86_exception e;
        struct vmcs12 *vmcs12;
+       short offset;
 
        if (!nested_vmx_check_permission(vcpu))
                return 1;
@@ -4463,11 +4635,11 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu)
                field_value = kvm_register_readl(vcpu,
                        (((vmx_instruction_info) >> 3) & 0xf));
        else {
+               len = is_64_bit_mode(vcpu) ? 8 : 4;
                if (get_vmx_mem_address(vcpu, exit_qualification,
-                               vmx_instruction_info, false, &gva))
+                               vmx_instruction_info, false, len, &gva))
                        return 1;
-               if (kvm_read_guest_virt(vcpu, gva, &field_value,
-                                       (is_64_bit_mode(vcpu) ? 8 : 4), &e)) {
+               if (kvm_read_guest_virt(vcpu, gva, &field_value, len, &e)) {
                        kvm_inject_page_fault(vcpu, &e);
                        return 1;
                }
@@ -4484,9 +4656,16 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu)
                return nested_vmx_failValid(vcpu,
                        VMXERR_VMWRITE_READ_ONLY_VMCS_COMPONENT);
 
-       if (!is_guest_mode(vcpu))
+       if (!is_guest_mode(vcpu)) {
                vmcs12 = get_vmcs12(vcpu);
-       else {
+
+               /*
+                * Ensure vmcs12 is up-to-date before any VMWRITE that dirties
+                * vmcs12, else we may crush a field or consume a stale value.
+                */
+               if (!is_shadow_field_rw(field))
+                       copy_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
+       } else {
                /*
                 * When vmcs->vmcs_link_pointer is -1ull, any VMWRITE
                 * to shadowed-field sets the ALU flags for VMfailInvalid.
@@ -4496,28 +4675,46 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu)
                vmcs12 = get_shadow_vmcs12(vcpu);
        }
 
-       if (vmcs12_write_any(vmcs12, field, field_value) < 0)
+       offset = vmcs_field_to_offset(field);
+       if (offset < 0)
                return nested_vmx_failValid(vcpu,
                        VMXERR_UNSUPPORTED_VMCS_COMPONENT);
 
        /*
-        * Do not track vmcs12 dirty-state if in guest-mode
-        * as we actually dirty shadow vmcs12 instead of vmcs12.
+        * Some Intel CPUs intentionally drop the reserved bits of the AR byte
+        * fields on VMWRITE.  Emulate this behavior to ensure consistent KVM
+        * behavior regardless of the underlying hardware, e.g. if an AR_BYTE
+        * field is intercepted for VMWRITE but not VMREAD (in L1), then VMREAD
+        * from L1 will return a different value than VMREAD from L2 (L1 sees
+        * the stripped down value, L2 sees the full value as stored by KVM).
         */
-       if (!is_guest_mode(vcpu)) {
-               switch (field) {
-#define SHADOW_FIELD_RW(x) case x:
-#include "vmcs_shadow_fields.h"
-                       /*
-                        * The fields that can be updated by L1 without a vmexit are
-                        * always updated in the vmcs02, the others go down the slow
-                        * path of prepare_vmcs02.
-                        */
-                       break;
-               default:
-                       vmx->nested.dirty_vmcs12 = true;
-                       break;
+       if (field >= GUEST_ES_AR_BYTES && field <= GUEST_TR_AR_BYTES)
+               field_value &= 0x1f0ff;
+
+       vmcs12_write_any(vmcs12, field, offset, field_value);
+
+       /*
+        * Do not track vmcs12 dirty-state if in guest-mode as we actually
+        * dirty shadow vmcs12 instead of vmcs12.  Fields that can be updated
+        * by L1 without a vmexit are always updated in the vmcs02, i.e. don't
+        * "dirty" vmcs12, all others go down the prepare_vmcs02() slow path.
+        */
+       if (!is_guest_mode(vcpu) && !is_shadow_field_rw(field)) {
+               /*
+                * L1 can read these fields without exiting, ensure the
+                * shadow VMCS is up-to-date.
+                */
+               if (enable_shadow_vmcs && is_shadow_field_ro(field)) {
+                       preempt_disable();
+                       vmcs_load(vmx->vmcs01.shadow_vmcs);
+
+                       __vmcs_writel(field, field_value);
+
+                       vmcs_clear(vmx->vmcs01.shadow_vmcs);
+                       vmcs_load(vmx->loaded_vmcs->vmcs);
+                       preempt_enable();
                }
+               vmx->nested.dirty_vmcs12 = true;
        }
 
        return nested_vmx_succeed(vcpu);
@@ -4527,11 +4724,10 @@ static void set_current_vmptr(struct vcpu_vmx *vmx, gpa_t vmptr)
 {
        vmx->nested.current_vmptr = vmptr;
        if (enable_shadow_vmcs) {
-               vmcs_set_bits(SECONDARY_VM_EXEC_CONTROL,
-                             SECONDARY_EXEC_SHADOW_VMCS);
+               secondary_exec_controls_setbit(vmx, SECONDARY_EXEC_SHADOW_VMCS);
                vmcs_write64(VMCS_LINK_POINTER,
                             __pa(vmx->vmcs01.shadow_vmcs));
-               vmx->nested.need_vmcs12_sync = true;
+               vmx->nested.need_vmcs12_to_shadow_sync = true;
        }
        vmx->nested.dirty_vmcs12 = true;
 }
@@ -4615,7 +4811,8 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu)
        if (unlikely(to_vmx(vcpu)->nested.hv_evmcs))
                return 1;
 
-       if (get_vmx_mem_address(vcpu, exit_qual, instr_info, true, &gva))
+       if (get_vmx_mem_address(vcpu, exit_qual, instr_info,
+                               true, sizeof(gpa_t), &gva))
                return 1;
        /* *_system ok, nested_vmx_check_permission has verified cpl=0 */
        if (kvm_write_guest_virt_system(vcpu, gva, (void *)&current_vmptr,
@@ -4661,7 +4858,7 @@ static int handle_invept(struct kvm_vcpu *vcpu)
         * operand is read even if it isn't needed (e.g., for type==global)
         */
        if (get_vmx_mem_address(vcpu, vmcs_readl(EXIT_QUALIFICATION),
-                       vmx_instruction_info, false, &gva))
+                       vmx_instruction_info, false, sizeof(operand), &gva))
                return 1;
        if (kvm_read_guest_virt(vcpu, gva, &operand, sizeof(operand), &e)) {
                kvm_inject_page_fault(vcpu, &e);
@@ -4670,13 +4867,11 @@ static int handle_invept(struct kvm_vcpu *vcpu)
 
        switch (type) {
        case VMX_EPT_EXTENT_GLOBAL:
+       case VMX_EPT_EXTENT_CONTEXT:
        /*
-        * TODO: track mappings and invalidate
-        * single context requests appropriately
+        * TODO: Sync the necessary shadow EPT roots here, rather than
+        * at the next emulated VM-entry.
         */
-       case VMX_EPT_EXTENT_CONTEXT:
-               kvm_mmu_sync_roots(vcpu);
-               kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
                break;
        default:
                BUG_ON(1);
@@ -4723,7 +4918,7 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
         * operand is read even if it isn't needed (e.g., for type==global)
         */
        if (get_vmx_mem_address(vcpu, vmcs_readl(EXIT_QUALIFICATION),
-                       vmx_instruction_info, false, &gva))
+                       vmx_instruction_info, false, sizeof(operand), &gva))
                return 1;
        if (kvm_read_guest_virt(vcpu, gva, &operand, sizeof(operand), &e)) {
                kvm_inject_page_fault(vcpu, &e);
@@ -5284,12 +5479,13 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
         * When running L2, the authoritative vmcs12 state is in the
         * vmcs02. When running L1, the authoritative vmcs12 state is
         * in the shadow or enlightened vmcs linked to vmcs01, unless
-        * need_vmcs12_sync is set, in which case, the authoritative
+        * need_vmcs12_to_shadow_sync is set, in which case, the authoritative
         * vmcs12 state is in the vmcs12 already.
         */
        if (is_guest_mode(vcpu)) {
-               sync_vmcs12(vcpu, vmcs12);
-       } else if (!vmx->nested.need_vmcs12_sync) {
+               sync_vmcs02_to_vmcs12(vcpu, vmcs12);
+               sync_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
+       } else if (!vmx->nested.need_vmcs12_to_shadow_sync) {
                if (vmx->nested.hv_evmcs)
                        copy_enlightened_to_vmcs12(vmx);
                else if (enable_shadow_vmcs)
@@ -5421,7 +5617,7 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
                 * Sync eVMCS upon entry as we may not have
                 * HV_X64_MSR_VP_ASSIST_PAGE set up yet.
                 */
-               vmx->nested.need_vmcs12_sync = true;
+               vmx->nested.need_vmcs12_to_shadow_sync = true;
        } else {
                return -EINVAL;
        }
@@ -5489,14 +5685,8 @@ error_guest_mode:
 void nested_vmx_vcpu_setup(void)
 {
        if (enable_shadow_vmcs) {
-               /*
-                * At vCPU creation, "VMWRITE to any supported field
-                * in the VMCS" is supported, so use the more
-                * permissive vmx_vmread_bitmap to specify both read
-                * and write permissions for the shadow VMCS.
-                */
                vmcs_write64(VMREAD_BITMAP, __pa(vmx_vmread_bitmap));
-               vmcs_write64(VMWRITE_BITMAP, __pa(vmx_vmread_bitmap));
+               vmcs_write64(VMWRITE_BITMAP, __pa(vmx_vmwrite_bitmap));
        }
 }
 
@@ -5626,10 +5816,15 @@ void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps,
        msrs->secondary_ctls_low = 0;
        msrs->secondary_ctls_high &=
                SECONDARY_EXEC_DESC |
+               SECONDARY_EXEC_RDTSCP |
                SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE |
+               SECONDARY_EXEC_WBINVD_EXITING |
                SECONDARY_EXEC_APIC_REGISTER_VIRT |
                SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY |
-               SECONDARY_EXEC_WBINVD_EXITING;
+               SECONDARY_EXEC_RDRAND_EXITING |
+               SECONDARY_EXEC_ENABLE_INVPCID |
+               SECONDARY_EXEC_RDSEED_EXITING |
+               SECONDARY_EXEC_XSAVES;
 
        /*
         * We can emulate "VMCS shadowing," even if the hardware
@@ -5749,14 +5944,6 @@ __init int nested_vmx_hardware_setup(int (*exit_handlers[])(struct kvm_vcpu *))
 {
        int i;
 
-       /*
-        * Without EPT it is not possible to restore L1's CR3 and PDPTR on
-        * VMfail, because they are not available in vmcs01.  Just always
-        * use hardware checks.
-        */
-       if (!enable_ept)
-               nested_early_check = 1;
-
        if (!cpu_has_vmx_shadow_vmcs())
                enable_shadow_vmcs = 0;
        if (enable_shadow_vmcs) {
index e847ff1..187d39b 100644 (file)
@@ -17,11 +17,11 @@ int nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, bool from_vmentry);
 bool nested_vmx_exit_reflected(struct kvm_vcpu *vcpu, u32 exit_reason);
 void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
                       u32 exit_intr_info, unsigned long exit_qualification);
-void nested_sync_from_vmcs12(struct kvm_vcpu *vcpu);
+void nested_sync_vmcs12_to_shadow(struct kvm_vcpu *vcpu);
 int vmx_set_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
 int vmx_get_vmx_msr(struct nested_vmx_msrs *msrs, u32 msr_index, u64 *pdata);
 int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
-                       u32 vmx_instruction_info, bool wr, gva_t *ret);
+                       u32 vmx_instruction_info, bool wr, int len, gva_t *ret);
 
 static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
 {
index b8e50f7..2200fb6 100644 (file)
@@ -146,7 +146,6 @@ static __always_inline void vmcs_write64(unsigned long field, u64 value)
 
        __vmcs_writel(field, value);
 #ifndef CONFIG_X86_64
-       asm volatile ("");
        __vmcs_writel(field+1, value >> 32);
 #endif
 }
index cb6079f..481ad87 100644 (file)
@@ -42,6 +42,14 @@ struct vmcs_host_state {
 #endif
 };
 
+struct vmcs_controls_shadow {
+       u32 vm_entry;
+       u32 vm_exit;
+       u32 pin;
+       u32 exec;
+       u32 secondary_exec;
+};
+
 /*
  * Track a VMCS that may be loaded on a certain CPU. If it is (cpu!=-1), also
  * remember whether it was VMLAUNCHed, and maintain a linked list of all VMCSs
@@ -53,7 +61,7 @@ struct loaded_vmcs {
        int cpu;
        bool launched;
        bool nmi_known_unmasked;
-       bool hv_timer_armed;
+       bool hv_timer_soft_disabled;
        /* Support for vnmi-less CPUs */
        int soft_vnmi_blocked;
        ktime_t entry_time;
@@ -61,6 +69,7 @@ struct loaded_vmcs {
        unsigned long *msr_bitmap;
        struct list_head loaded_vmcss_on_cpu_link;
        struct vmcs_host_state host_state;
+       struct vmcs_controls_shadow controls_shadow;
 };
 
 static inline bool is_exception_n(u32 intr_info, u8 vector)
@@ -115,6 +124,12 @@ static inline bool is_nmi(u32 intr_info)
                == (INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK);
 }
 
+static inline bool is_external_intr(u32 intr_info)
+{
+       return (intr_info & (INTR_INFO_VALID_MASK | INTR_INFO_INTR_TYPE_MASK))
+               == (INTR_INFO_VALID_MASK | INTR_TYPE_EXT_INTR);
+}
+
 enum vmcs_field_width {
        VMCS_FIELD_WIDTH_U16 = 0,
        VMCS_FIELD_WIDTH_U64 = 1,
index 337718f..d0c6df3 100644 (file)
@@ -395,69 +395,48 @@ static inline short vmcs_field_to_offset(unsigned long field)
 
 #undef ROL16
 
-/*
- * Read a vmcs12 field. Since these can have varying lengths and we return
- * one type, we chose the biggest type (u64) and zero-extend the return value
- * to that size. Note that the caller, handle_vmread, might need to use only
- * some of the bits we return here (e.g., on 32-bit guests, only 32 bits of
- * 64-bit fields are to be returned).
- */
-static inline int vmcs12_read_any(struct vmcs12 *vmcs12,
-                                 unsigned long field, u64 *ret)
+static inline u64 vmcs12_read_any(struct vmcs12 *vmcs12, unsigned long field,
+                                 u16 offset)
 {
-       short offset = vmcs_field_to_offset(field);
-       char *p;
-
-       if (offset < 0)
-               return offset;
-
-       p = (char *)vmcs12 + offset;
+       char *p = (char *)vmcs12 + offset;
 
        switch (vmcs_field_width(field)) {
        case VMCS_FIELD_WIDTH_NATURAL_WIDTH:
-               *ret = *((natural_width *)p);
-               return 0;
+               return *((natural_width *)p);
        case VMCS_FIELD_WIDTH_U16:
-               *ret = *((u16 *)p);
-               return 0;
+               return *((u16 *)p);
        case VMCS_FIELD_WIDTH_U32:
-               *ret = *((u32 *)p);
-               return 0;
+               return *((u32 *)p);
        case VMCS_FIELD_WIDTH_U64:
-               *ret = *((u64 *)p);
-               return 0;
+               return *((u64 *)p);
        default:
-               WARN_ON(1);
-               return -ENOENT;
+               WARN_ON_ONCE(1);
+               return -1;
        }
 }
 
-static inline int vmcs12_write_any(struct vmcs12 *vmcs12,
-                                  unsigned long field, u64 field_value){
-       short offset = vmcs_field_to_offset(field);
+static inline void vmcs12_write_any(struct vmcs12 *vmcs12, unsigned long field,
+                                   u16 offset, u64 field_value)
+{
        char *p = (char *)vmcs12 + offset;
 
-       if (offset < 0)
-               return offset;
-
        switch (vmcs_field_width(field)) {
        case VMCS_FIELD_WIDTH_U16:
                *(u16 *)p = field_value;
-               return 0;
+               break;
        case VMCS_FIELD_WIDTH_U32:
                *(u32 *)p = field_value;
-               return 0;
+               break;
        case VMCS_FIELD_WIDTH_U64:
                *(u64 *)p = field_value;
-               return 0;
+               break;
        case VMCS_FIELD_WIDTH_NATURAL_WIDTH:
                *(natural_width *)p = field_value;
-               return 0;
+               break;
        default:
-               WARN_ON(1);
-               return -ENOENT;
+               WARN_ON_ONCE(1);
+               break;
        }
-
 }
 
 #endif /* __KVM_X86_VMX_VMCS12_H */
index 132432f..eb1ecd1 100644 (file)
@@ -1,8 +1,12 @@
+#if !defined(SHADOW_FIELD_RO) && !defined(SHADOW_FIELD_RW)
+BUILD_BUG_ON(1)
+#endif
+
 #ifndef SHADOW_FIELD_RO
-#define SHADOW_FIELD_RO(x)
+#define SHADOW_FIELD_RO(x, y)
 #endif
 #ifndef SHADOW_FIELD_RW
-#define SHADOW_FIELD_RW(x)
+#define SHADOW_FIELD_RW(x, y)
 #endif
 
 /*
  */
 
 /* 16-bits */
-SHADOW_FIELD_RW(GUEST_INTR_STATUS)
-SHADOW_FIELD_RW(GUEST_PML_INDEX)
-SHADOW_FIELD_RW(HOST_FS_SELECTOR)
-SHADOW_FIELD_RW(HOST_GS_SELECTOR)
+SHADOW_FIELD_RW(GUEST_INTR_STATUS, guest_intr_status)
+SHADOW_FIELD_RW(GUEST_PML_INDEX, guest_pml_index)
+SHADOW_FIELD_RW(HOST_FS_SELECTOR, host_fs_selector)
+SHADOW_FIELD_RW(HOST_GS_SELECTOR, host_gs_selector)
 
 /* 32-bits */
-SHADOW_FIELD_RO(VM_EXIT_REASON)
-SHADOW_FIELD_RO(VM_EXIT_INTR_INFO)
-SHADOW_FIELD_RO(VM_EXIT_INSTRUCTION_LEN)
-SHADOW_FIELD_RO(IDT_VECTORING_INFO_FIELD)
-SHADOW_FIELD_RO(IDT_VECTORING_ERROR_CODE)
-SHADOW_FIELD_RO(VM_EXIT_INTR_ERROR_CODE)
-SHADOW_FIELD_RW(CPU_BASED_VM_EXEC_CONTROL)
-SHADOW_FIELD_RW(EXCEPTION_BITMAP)
-SHADOW_FIELD_RW(VM_ENTRY_EXCEPTION_ERROR_CODE)
-SHADOW_FIELD_RW(VM_ENTRY_INTR_INFO_FIELD)
-SHADOW_FIELD_RW(VM_ENTRY_INSTRUCTION_LEN)
-SHADOW_FIELD_RW(TPR_THRESHOLD)
-SHADOW_FIELD_RW(GUEST_CS_AR_BYTES)
-SHADOW_FIELD_RW(GUEST_SS_AR_BYTES)
-SHADOW_FIELD_RW(GUEST_INTERRUPTIBILITY_INFO)
-SHADOW_FIELD_RW(VMX_PREEMPTION_TIMER_VALUE)
+SHADOW_FIELD_RO(VM_EXIT_REASON, vm_exit_reason)
+SHADOW_FIELD_RO(VM_EXIT_INTR_INFO, vm_exit_intr_info)
+SHADOW_FIELD_RO(VM_EXIT_INSTRUCTION_LEN, vm_exit_instruction_len)
+SHADOW_FIELD_RO(IDT_VECTORING_INFO_FIELD, idt_vectoring_info_field)
+SHADOW_FIELD_RO(IDT_VECTORING_ERROR_CODE, idt_vectoring_error_code)
+SHADOW_FIELD_RO(VM_EXIT_INTR_ERROR_CODE, vm_exit_intr_error_code)
+SHADOW_FIELD_RO(GUEST_CS_AR_BYTES, guest_cs_ar_bytes)
+SHADOW_FIELD_RO(GUEST_SS_AR_BYTES, guest_ss_ar_bytes)
+SHADOW_FIELD_RW(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control)
+SHADOW_FIELD_RW(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_control)
+SHADOW_FIELD_RW(EXCEPTION_BITMAP, exception_bitmap)
+SHADOW_FIELD_RW(VM_ENTRY_EXCEPTION_ERROR_CODE, vm_entry_exception_error_code)
+SHADOW_FIELD_RW(VM_ENTRY_INTR_INFO_FIELD, vm_entry_intr_info_field)
+SHADOW_FIELD_RW(VM_ENTRY_INSTRUCTION_LEN, vm_entry_instruction_len)
+SHADOW_FIELD_RW(TPR_THRESHOLD, tpr_threshold)
+SHADOW_FIELD_RW(GUEST_INTERRUPTIBILITY_INFO, guest_interruptibility_info)
+SHADOW_FIELD_RW(VMX_PREEMPTION_TIMER_VALUE, vmx_preemption_timer_value)
 
 /* Natural width */
-SHADOW_FIELD_RO(EXIT_QUALIFICATION)
-SHADOW_FIELD_RO(GUEST_LINEAR_ADDRESS)
-SHADOW_FIELD_RW(GUEST_RIP)
-SHADOW_FIELD_RW(GUEST_RSP)
-SHADOW_FIELD_RW(GUEST_CR0)
-SHADOW_FIELD_RW(GUEST_CR3)
-SHADOW_FIELD_RW(GUEST_CR4)
-SHADOW_FIELD_RW(GUEST_RFLAGS)
-SHADOW_FIELD_RW(CR0_GUEST_HOST_MASK)
-SHADOW_FIELD_RW(CR0_READ_SHADOW)
-SHADOW_FIELD_RW(CR4_READ_SHADOW)
-SHADOW_FIELD_RW(HOST_FS_BASE)
-SHADOW_FIELD_RW(HOST_GS_BASE)
+SHADOW_FIELD_RO(EXIT_QUALIFICATION, exit_qualification)
+SHADOW_FIELD_RO(GUEST_LINEAR_ADDRESS, guest_linear_address)
+SHADOW_FIELD_RW(GUEST_RIP, guest_rip)
+SHADOW_FIELD_RW(GUEST_RSP, guest_rsp)
+SHADOW_FIELD_RW(GUEST_CR0, guest_cr0)
+SHADOW_FIELD_RW(GUEST_CR3, guest_cr3)
+SHADOW_FIELD_RW(GUEST_CR4, guest_cr4)
+SHADOW_FIELD_RW(GUEST_RFLAGS, guest_rflags)
+SHADOW_FIELD_RW(CR0_GUEST_HOST_MASK, cr0_guest_host_mask)
+SHADOW_FIELD_RW(CR0_READ_SHADOW, cr0_read_shadow)
+SHADOW_FIELD_RW(CR4_READ_SHADOW, cr4_read_shadow)
+SHADOW_FIELD_RW(HOST_FS_BASE, host_fs_base)
+SHADOW_FIELD_RW(HOST_GS_BASE, host_gs_base)
 
 /* 64-bit */
-SHADOW_FIELD_RO(GUEST_PHYSICAL_ADDRESS)
-SHADOW_FIELD_RO(GUEST_PHYSICAL_ADDRESS_HIGH)
+SHADOW_FIELD_RO(GUEST_PHYSICAL_ADDRESS, guest_physical_address)
+SHADOW_FIELD_RO(GUEST_PHYSICAL_ADDRESS_HIGH, guest_physical_address)
 
 #undef SHADOW_FIELD_RO
 #undef SHADOW_FIELD_RW
index d98eac3..6953655 100644 (file)
@@ -389,6 +389,7 @@ static const struct kvm_vmx_segment_field {
 };
 
 u64 host_efer;
+static unsigned long host_idt_base;
 
 /*
  * Though SYSCALL is only supported in 64-bit mode on Intel CPUs, kvm
@@ -1035,6 +1036,33 @@ static void pt_guest_exit(struct vcpu_vmx *vmx)
        wrmsrl(MSR_IA32_RTIT_CTL, vmx->pt_desc.host.ctl);
 }
 
+void vmx_set_host_fs_gs(struct vmcs_host_state *host, u16 fs_sel, u16 gs_sel,
+                       unsigned long fs_base, unsigned long gs_base)
+{
+       if (unlikely(fs_sel != host->fs_sel)) {
+               if (!(fs_sel & 7))
+                       vmcs_write16(HOST_FS_SELECTOR, fs_sel);
+               else
+                       vmcs_write16(HOST_FS_SELECTOR, 0);
+               host->fs_sel = fs_sel;
+       }
+       if (unlikely(gs_sel != host->gs_sel)) {
+               if (!(gs_sel & 7))
+                       vmcs_write16(HOST_GS_SELECTOR, gs_sel);
+               else
+                       vmcs_write16(HOST_GS_SELECTOR, 0);
+               host->gs_sel = gs_sel;
+       }
+       if (unlikely(fs_base != host->fs_base)) {
+               vmcs_writel(HOST_FS_BASE, fs_base);
+               host->fs_base = fs_base;
+       }
+       if (unlikely(gs_base != host->gs_base)) {
+               vmcs_writel(HOST_GS_BASE, gs_base);
+               host->gs_base = gs_base;
+       }
+}
+
 void vmx_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -1053,20 +1081,18 @@ void vmx_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
         * when guest state is loaded. This happens when guest transitions
         * to/from long-mode by setting MSR_EFER.LMA.
         */
-       if (!vmx->loaded_cpu_state || vmx->guest_msrs_dirty) {
-               vmx->guest_msrs_dirty = false;
+       if (!vmx->guest_msrs_ready) {
+               vmx->guest_msrs_ready = true;
                for (i = 0; i < vmx->save_nmsrs; ++i)
                        kvm_set_shared_msr(vmx->guest_msrs[i].index,
                                           vmx->guest_msrs[i].data,
                                           vmx->guest_msrs[i].mask);
 
        }
-
-       if (vmx->loaded_cpu_state)
+       if (vmx->guest_state_loaded)
                return;
 
-       vmx->loaded_cpu_state = vmx->loaded_vmcs;
-       host_state = &vmx->loaded_cpu_state->host_state;
+       host_state = &vmx->loaded_vmcs->host_state;
 
        /*
         * Set host fs and gs selectors.  Unfortunately, 22.2.3 does not
@@ -1100,42 +1126,20 @@ void vmx_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
        gs_base = segment_base(gs_sel);
 #endif
 
-       if (unlikely(fs_sel != host_state->fs_sel)) {
-               if (!(fs_sel & 7))
-                       vmcs_write16(HOST_FS_SELECTOR, fs_sel);
-               else
-                       vmcs_write16(HOST_FS_SELECTOR, 0);
-               host_state->fs_sel = fs_sel;
-       }
-       if (unlikely(gs_sel != host_state->gs_sel)) {
-               if (!(gs_sel & 7))
-                       vmcs_write16(HOST_GS_SELECTOR, gs_sel);
-               else
-                       vmcs_write16(HOST_GS_SELECTOR, 0);
-               host_state->gs_sel = gs_sel;
-       }
-       if (unlikely(fs_base != host_state->fs_base)) {
-               vmcs_writel(HOST_FS_BASE, fs_base);
-               host_state->fs_base = fs_base;
-       }
-       if (unlikely(gs_base != host_state->gs_base)) {
-               vmcs_writel(HOST_GS_BASE, gs_base);
-               host_state->gs_base = gs_base;
-       }
+       vmx_set_host_fs_gs(host_state, fs_sel, gs_sel, fs_base, gs_base);
+       vmx->guest_state_loaded = true;
 }
 
 static void vmx_prepare_switch_to_host(struct vcpu_vmx *vmx)
 {
        struct vmcs_host_state *host_state;
 
-       if (!vmx->loaded_cpu_state)
+       if (!vmx->guest_state_loaded)
                return;
 
-       WARN_ON_ONCE(vmx->loaded_cpu_state != vmx->loaded_vmcs);
-       host_state = &vmx->loaded_cpu_state->host_state;
+       host_state = &vmx->loaded_vmcs->host_state;
 
        ++vmx->vcpu.stat.host_state_reload;
-       vmx->loaded_cpu_state = NULL;
 
 #ifdef CONFIG_X86_64
        rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
@@ -1161,13 +1165,15 @@ static void vmx_prepare_switch_to_host(struct vcpu_vmx *vmx)
        wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
 #endif
        load_fixmap_gdt(raw_smp_processor_id());
+       vmx->guest_state_loaded = false;
+       vmx->guest_msrs_ready = false;
 }
 
 #ifdef CONFIG_X86_64
 static u64 vmx_read_guest_kernel_gs_base(struct vcpu_vmx *vmx)
 {
        preempt_disable();
-       if (vmx->loaded_cpu_state)
+       if (vmx->guest_state_loaded)
                rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
        preempt_enable();
        return vmx->msr_guest_kernel_gs_base;
@@ -1176,7 +1182,7 @@ static u64 vmx_read_guest_kernel_gs_base(struct vcpu_vmx *vmx)
 static void vmx_write_guest_kernel_gs_base(struct vcpu_vmx *vmx, u64 data)
 {
        preempt_disable();
-       if (vmx->loaded_cpu_state)
+       if (vmx->guest_state_loaded)
                wrmsrl(MSR_KERNEL_GS_BASE, data);
        preempt_enable();
        vmx->msr_guest_kernel_gs_base = data;
@@ -1225,11 +1231,7 @@ static void vmx_vcpu_pi_load(struct kvm_vcpu *vcpu, int cpu)
                pi_set_on(pi_desc);
 }
 
-/*
- * Switches to specified vcpu, until a matching vcpu_put(), but assumes
- * vcpu mutex is already taken.
- */
-void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
+void vmx_vcpu_load_vmcs(struct kvm_vcpu *vcpu, int cpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        bool already_loaded = vmx->loaded_vmcs->cpu == cpu;
@@ -1290,8 +1292,20 @@ void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
        if (kvm_has_tsc_control &&
            vmx->current_tsc_ratio != vcpu->arch.tsc_scaling_ratio)
                decache_tsc_multiplier(vmx);
+}
+
+/*
+ * Switches to specified vcpu, until a matching vcpu_put(), but assumes
+ * vcpu mutex is already taken.
+ */
+void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+       vmx_vcpu_load_vmcs(vcpu, cpu);
 
        vmx_vcpu_pi_load(vcpu, cpu);
+
        vmx->host_pkru = read_pkru();
        vmx->host_debugctlmsr = get_debugctlmsr();
 }
@@ -1310,7 +1324,7 @@ static void vmx_vcpu_pi_put(struct kvm_vcpu *vcpu)
                pi_set_sn(pi_desc);
 }
 
-void vmx_vcpu_put(struct kvm_vcpu *vcpu)
+static void vmx_vcpu_put(struct kvm_vcpu *vcpu)
 {
        vmx_vcpu_pi_put(vcpu);
 
@@ -1579,7 +1593,7 @@ static void setup_msrs(struct vcpu_vmx *vmx)
                move_msr_up(vmx, index, save_nmsrs++);
 
        vmx->save_nmsrs = save_nmsrs;
-       vmx->guest_msrs_dirty = true;
+       vmx->guest_msrs_ready = false;
 
        if (cpu_has_vmx_msr_bitmap())
                vmx_update_msr_bitmap(&vmx->vcpu);
@@ -1692,9 +1706,6 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case MSR_IA32_SYSENTER_ESP:
                msr_info->data = vmcs_readl(GUEST_SYSENTER_ESP);
                break;
-       case MSR_IA32_POWER_CTL:
-               msr_info->data = vmx->msr_ia32_power_ctl;
-               break;
        case MSR_IA32_BNDCFGS:
                if (!kvm_mpx_supported() ||
                    (!msr_info->host_initiated &&
@@ -1718,7 +1729,10 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                return vmx_get_vmx_msr(&vmx->nested.msrs, msr_info->index,
                                       &msr_info->data);
        case MSR_IA32_XSS:
-               if (!vmx_xsaves_supported())
+               if (!vmx_xsaves_supported() ||
+                   (!msr_info->host_initiated &&
+                    !(guest_cpuid_has(vcpu, X86_FEATURE_XSAVE) &&
+                      guest_cpuid_has(vcpu, X86_FEATURE_XSAVES))))
                        return 1;
                msr_info->data = vcpu->arch.ia32_xss;
                break;
@@ -1817,17 +1831,28 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                break;
 #endif
        case MSR_IA32_SYSENTER_CS:
+               if (is_guest_mode(vcpu))
+                       get_vmcs12(vcpu)->guest_sysenter_cs = data;
                vmcs_write32(GUEST_SYSENTER_CS, data);
                break;
        case MSR_IA32_SYSENTER_EIP:
+               if (is_guest_mode(vcpu))
+                       get_vmcs12(vcpu)->guest_sysenter_eip = data;
                vmcs_writel(GUEST_SYSENTER_EIP, data);
                break;
        case MSR_IA32_SYSENTER_ESP:
+               if (is_guest_mode(vcpu))
+                       get_vmcs12(vcpu)->guest_sysenter_esp = data;
                vmcs_writel(GUEST_SYSENTER_ESP, data);
                break;
-       case MSR_IA32_POWER_CTL:
-               vmx->msr_ia32_power_ctl = data;
+       case MSR_IA32_DEBUGCTLMSR:
+               if (is_guest_mode(vcpu) && get_vmcs12(vcpu)->vm_exit_controls &
+                                               VM_EXIT_SAVE_DEBUG_CONTROLS)
+                       get_vmcs12(vcpu)->guest_ia32_debugctl = data;
+
+               ret = kvm_set_msr_common(vcpu, msr_info);
                break;
+
        case MSR_IA32_BNDCFGS:
                if (!kvm_mpx_supported() ||
                    (!msr_info->host_initiated &&
@@ -1896,9 +1921,14 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                                              MSR_TYPE_W);
                break;
        case MSR_IA32_CR_PAT:
+               if (!kvm_pat_valid(data))
+                       return 1;
+
+               if (is_guest_mode(vcpu) &&
+                   get_vmcs12(vcpu)->vm_exit_controls & VM_EXIT_SAVE_IA32_PAT)
+                       get_vmcs12(vcpu)->guest_ia32_pat = data;
+
                if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT) {
-                       if (!kvm_pat_valid(data))
-                               return 1;
                        vmcs_write64(GUEST_IA32_PAT, data);
                        vcpu->arch.pat = data;
                        break;
@@ -1932,7 +1962,10 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                        return 1;
                return vmx_set_vmx_msr(vcpu, msr_index, data);
        case MSR_IA32_XSS:
-               if (!vmx_xsaves_supported())
+               if (!vmx_xsaves_supported() ||
+                   (!msr_info->host_initiated &&
+                    !(guest_cpuid_has(vcpu, X86_FEATURE_XSAVE) &&
+                      guest_cpuid_has(vcpu, X86_FEATURE_XSAVES))))
                        return 1;
                /*
                 * The only supported bit as of Skylake is bit 8, but
@@ -2435,6 +2468,7 @@ int alloc_loaded_vmcs(struct loaded_vmcs *loaded_vmcs)
                return -ENOMEM;
 
        loaded_vmcs->shadow_vmcs = NULL;
+       loaded_vmcs->hv_timer_soft_disabled = false;
        loaded_vmcs_init(loaded_vmcs);
 
        if (cpu_has_vmx_msr_bitmap()) {
@@ -2455,6 +2489,8 @@ int alloc_loaded_vmcs(struct loaded_vmcs *loaded_vmcs)
        }
 
        memset(&loaded_vmcs->host_state, 0, sizeof(struct vmcs_host_state));
+       memset(&loaded_vmcs->controls_shadow, 0,
+               sizeof(struct vmcs_controls_shadow));
 
        return 0;
 
@@ -2737,7 +2773,7 @@ static void ept_load_pdptrs(struct kvm_vcpu *vcpu)
                      (unsigned long *)&vcpu->arch.regs_dirty))
                return;
 
-       if (is_paging(vcpu) && is_pae(vcpu) && !is_long_mode(vcpu)) {
+       if (is_pae_paging(vcpu)) {
                vmcs_write64(GUEST_PDPTR0, mmu->pdptrs[0]);
                vmcs_write64(GUEST_PDPTR1, mmu->pdptrs[1]);
                vmcs_write64(GUEST_PDPTR2, mmu->pdptrs[2]);
@@ -2749,7 +2785,7 @@ void ept_save_pdptrs(struct kvm_vcpu *vcpu)
 {
        struct kvm_mmu *mmu = vcpu->arch.walk_mmu;
 
-       if (is_paging(vcpu) && is_pae(vcpu) && !is_long_mode(vcpu)) {
+       if (is_pae_paging(vcpu)) {
                mmu->pdptrs[0] = vmcs_read64(GUEST_PDPTR0);
                mmu->pdptrs[1] = vmcs_read64(GUEST_PDPTR1);
                mmu->pdptrs[2] = vmcs_read64(GUEST_PDPTR2);
@@ -2766,22 +2802,20 @@ static void ept_update_paging_mode_cr0(unsigned long *hw_cr0,
                                        unsigned long cr0,
                                        struct kvm_vcpu *vcpu)
 {
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+
        if (!test_bit(VCPU_EXREG_CR3, (ulong *)&vcpu->arch.regs_avail))
                vmx_decache_cr3(vcpu);
        if (!(cr0 & X86_CR0_PG)) {
                /* From paging/starting to nonpaging */
-               vmcs_write32(CPU_BASED_VM_EXEC_CONTROL,
-                            vmcs_read32(CPU_BASED_VM_EXEC_CONTROL) |
-                            (CPU_BASED_CR3_LOAD_EXITING |
-                             CPU_BASED_CR3_STORE_EXITING));
+               exec_controls_setbit(vmx, CPU_BASED_CR3_LOAD_EXITING |
+                                         CPU_BASED_CR3_STORE_EXITING);
                vcpu->arch.cr0 = cr0;
                vmx_set_cr4(vcpu, kvm_read_cr4(vcpu));
        } else if (!is_paging(vcpu)) {
                /* From nonpaging to paging */
-               vmcs_write32(CPU_BASED_VM_EXEC_CONTROL,
-                            vmcs_read32(CPU_BASED_VM_EXEC_CONTROL) &
-                            ~(CPU_BASED_CR3_LOAD_EXITING |
-                              CPU_BASED_CR3_STORE_EXITING));
+               exec_controls_clearbit(vmx, CPU_BASED_CR3_LOAD_EXITING |
+                                           CPU_BASED_CR3_STORE_EXITING);
                vcpu->arch.cr0 = cr0;
                vmx_set_cr4(vcpu, kvm_read_cr4(vcpu));
        }
@@ -2881,6 +2915,7 @@ void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
 
 int vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
 {
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
        /*
         * Pass through host's Machine Check Enable value to hw_cr4, which
         * is in force while we are in guest mode.  Do not let guests control
@@ -2891,20 +2926,19 @@ int vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
        hw_cr4 = (cr4_read_shadow() & X86_CR4_MCE) | (cr4 & ~X86_CR4_MCE);
        if (enable_unrestricted_guest)
                hw_cr4 |= KVM_VM_CR4_ALWAYS_ON_UNRESTRICTED_GUEST;
-       else if (to_vmx(vcpu)->rmode.vm86_active)
+       else if (vmx->rmode.vm86_active)
                hw_cr4 |= KVM_RMODE_VM_CR4_ALWAYS_ON;
        else
                hw_cr4 |= KVM_PMODE_VM_CR4_ALWAYS_ON;
 
        if (!boot_cpu_has(X86_FEATURE_UMIP) && vmx_umip_emulated()) {
                if (cr4 & X86_CR4_UMIP) {
-                       vmcs_set_bits(SECONDARY_VM_EXEC_CONTROL,
-                               SECONDARY_EXEC_DESC);
+                       secondary_exec_controls_setbit(vmx, SECONDARY_EXEC_DESC);
                        hw_cr4 &= ~X86_CR4_UMIP;
                } else if (!is_guest_mode(vcpu) ||
-                       !nested_cpu_has2(get_vmcs12(vcpu), SECONDARY_EXEC_DESC))
-                       vmcs_clear_bits(SECONDARY_VM_EXEC_CONTROL,
-                                       SECONDARY_EXEC_DESC);
+                       !nested_cpu_has2(get_vmcs12(vcpu), SECONDARY_EXEC_DESC)) {
+                       secondary_exec_controls_clearbit(vmx, SECONDARY_EXEC_DESC);
+               }
        }
 
        if (cr4 & X86_CR4_VMXE) {
@@ -2919,7 +2953,7 @@ int vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
                        return 1;
        }
 
-       if (to_vmx(vcpu)->nested.vmxon && !nested_cr4_valid(vcpu, cr4))
+       if (vmx->nested.vmxon && !nested_cr4_valid(vcpu, cr4))
                return 1;
 
        vcpu->arch.cr4 = cr4;
@@ -3537,7 +3571,7 @@ static u8 vmx_msr_bitmap_mode(struct kvm_vcpu *vcpu)
        u8 mode = 0;
 
        if (cpu_has_secondary_exec_ctrls() &&
-           (vmcs_read32(SECONDARY_VM_EXEC_CONTROL) &
+           (secondary_exec_controls_get(to_vmx(vcpu)) &
             SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE)) {
                mode |= MSR_BITMAP_MODE_X2APIC;
                if (enable_apicv && kvm_vcpu_apicv_active(vcpu))
@@ -3731,7 +3765,6 @@ void vmx_set_constant_host_state(struct vcpu_vmx *vmx)
 {
        u32 low32, high32;
        unsigned long tmpl;
-       struct desc_ptr dt;
        unsigned long cr0, cr3, cr4;
 
        cr0 = read_cr0();
@@ -3767,9 +3800,7 @@ void vmx_set_constant_host_state(struct vcpu_vmx *vmx)
        vmcs_write16(HOST_SS_SELECTOR, __KERNEL_DS);  /* 22.2.4 */
        vmcs_write16(HOST_TR_SELECTOR, GDT_ENTRY_TSS*8);  /* 22.2.4 */
 
-       store_idt(&dt);
-       vmcs_writel(HOST_IDTR_BASE, dt.address);   /* 22.2.4 */
-       vmx->host_idt_base = dt.address;
+       vmcs_writel(HOST_IDTR_BASE, host_idt_base);   /* 22.2.4 */
 
        vmcs_writel(HOST_RIP, (unsigned long)vmx_vmexit); /* 22.2.5 */
 
@@ -3798,7 +3829,7 @@ void set_cr4_guest_host_mask(struct vcpu_vmx *vmx)
        vmcs_writel(CR4_GUEST_HOST_MASK, ~vmx->vcpu.arch.cr4_guest_owned_bits);
 }
 
-static u32 vmx_pin_based_exec_ctrl(struct vcpu_vmx *vmx)
+u32 vmx_pin_based_exec_ctrl(struct vcpu_vmx *vmx)
 {
        u32 pin_based_exec_ctrl = vmcs_config.pin_based_exec_ctrl;
 
@@ -3808,8 +3839,9 @@ static u32 vmx_pin_based_exec_ctrl(struct vcpu_vmx *vmx)
        if (!enable_vnmi)
                pin_based_exec_ctrl &= ~PIN_BASED_VIRTUAL_NMIS;
 
-       /* Enable the preemption timer dynamically */
-       pin_based_exec_ctrl &= ~PIN_BASED_VMX_PREEMPTION_TIMER;
+       if (!enable_preemption_timer)
+               pin_based_exec_ctrl &= ~PIN_BASED_VMX_PREEMPTION_TIMER;
+
        return pin_based_exec_ctrl;
 }
 
@@ -3817,14 +3849,14 @@ static void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
-       vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, vmx_pin_based_exec_ctrl(vmx));
+       pin_controls_set(vmx, vmx_pin_based_exec_ctrl(vmx));
        if (cpu_has_secondary_exec_ctrls()) {
                if (kvm_vcpu_apicv_active(vcpu))
-                       vmcs_set_bits(SECONDARY_VM_EXEC_CONTROL,
+                       secondary_exec_controls_setbit(vmx,
                                      SECONDARY_EXEC_APIC_REGISTER_VIRT |
                                      SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY);
                else
-                       vmcs_clear_bits(SECONDARY_VM_EXEC_CONTROL,
+                       secondary_exec_controls_clearbit(vmx,
                                        SECONDARY_EXEC_APIC_REGISTER_VIRT |
                                        SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY);
        }
@@ -4015,15 +4047,14 @@ static void vmx_vcpu_setup(struct vcpu_vmx *vmx)
        vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */
 
        /* Control */
-       vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, vmx_pin_based_exec_ctrl(vmx));
+       pin_controls_set(vmx, vmx_pin_based_exec_ctrl(vmx));
        vmx->hv_deadline_tsc = -1;
 
-       vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, vmx_exec_control(vmx));
+       exec_controls_set(vmx, vmx_exec_control(vmx));
 
        if (cpu_has_secondary_exec_ctrls()) {
                vmx_compute_secondary_exec_control(vmx);
-               vmcs_write32(SECONDARY_VM_EXEC_CONTROL,
-                            vmx->secondary_exec_control);
+               secondary_exec_controls_set(vmx, vmx->secondary_exec_control);
        }
 
        if (kvm_vcpu_apicv_active(&vmx->vcpu)) {
@@ -4081,10 +4112,10 @@ static void vmx_vcpu_setup(struct vcpu_vmx *vmx)
                ++vmx->nmsrs;
        }
 
-       vm_exit_controls_init(vmx, vmx_vmexit_ctrl());
+       vm_exit_controls_set(vmx, vmx_vmexit_ctrl());
 
        /* 22.2.1, 20.8.1 */
-       vm_entry_controls_init(vmx, vmx_vmentry_ctrl());
+       vm_entry_controls_set(vmx, vmx_vmentry_ctrl());
 
        vmx->vcpu.arch.cr0_guest_owned_bits = X86_CR0_TS;
        vmcs_writel(CR0_GUEST_HOST_MASK, ~X86_CR0_TS);
@@ -4208,8 +4239,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
 
 static void enable_irq_window(struct kvm_vcpu *vcpu)
 {
-       vmcs_set_bits(CPU_BASED_VM_EXEC_CONTROL,
-                     CPU_BASED_VIRTUAL_INTR_PENDING);
+       exec_controls_setbit(to_vmx(vcpu), CPU_BASED_VIRTUAL_INTR_PENDING);
 }
 
 static void enable_nmi_window(struct kvm_vcpu *vcpu)
@@ -4220,8 +4250,7 @@ static void enable_nmi_window(struct kvm_vcpu *vcpu)
                return;
        }
 
-       vmcs_set_bits(CPU_BASED_VM_EXEC_CONTROL,
-                     CPU_BASED_VIRTUAL_NMI_PENDING);
+       exec_controls_setbit(to_vmx(vcpu), CPU_BASED_VIRTUAL_NMI_PENDING);
 }
 
 static void vmx_inject_irq(struct kvm_vcpu *vcpu)
@@ -4442,11 +4471,11 @@ static void kvm_machine_check(void)
 
 static int handle_machine_check(struct kvm_vcpu *vcpu)
 {
-       /* already handled by vcpu_run */
+       /* handled by vmx_vcpu_run() */
        return 1;
 }
 
-static int handle_exception(struct kvm_vcpu *vcpu)
+static int handle_exception_nmi(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        struct kvm_run *kvm_run = vcpu->run;
@@ -4458,11 +4487,8 @@ static int handle_exception(struct kvm_vcpu *vcpu)
        vect_info = vmx->idt_vectoring_info;
        intr_info = vmx->exit_intr_info;
 
-       if (is_machine_check(intr_info))
-               return handle_machine_check(vcpu);
-
-       if (is_nmi(intr_info))
-               return 1;  /* already handled by vmx_vcpu_run() */
+       if (is_machine_check(intr_info) || is_nmi(intr_info))
+               return 1; /* handled by handle_exception_nmi_irqoff() */
 
        if (is_invalid_opcode(intr_info))
                return handle_ud(vcpu);
@@ -4518,7 +4544,7 @@ static int handle_exception(struct kvm_vcpu *vcpu)
                dr6 = vmcs_readl(EXIT_QUALIFICATION);
                if (!(vcpu->guest_debug &
                      (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))) {
-                       vcpu->arch.dr6 &= ~15;
+                       vcpu->arch.dr6 &= ~DR_TRAP_BITS;
                        vcpu->arch.dr6 |= dr6 | DR6_RTM;
                        if (is_icebp(intr_info))
                                skip_emulated_instruction(vcpu);
@@ -4763,7 +4789,7 @@ static int handle_dr(struct kvm_vcpu *vcpu)
                        vcpu->run->exit_reason = KVM_EXIT_DEBUG;
                        return 0;
                } else {
-                       vcpu->arch.dr6 &= ~15;
+                       vcpu->arch.dr6 &= ~DR_TRAP_BITS;
                        vcpu->arch.dr6 |= DR6_BD | DR6_RTM;
                        kvm_queue_exception(vcpu, DB_VECTOR);
                        return 1;
@@ -4771,8 +4797,7 @@ static int handle_dr(struct kvm_vcpu *vcpu)
        }
 
        if (vcpu->guest_debug == 0) {
-               vmcs_clear_bits(CPU_BASED_VM_EXEC_CONTROL,
-                               CPU_BASED_MOV_DR_EXITING);
+               exec_controls_clearbit(to_vmx(vcpu), CPU_BASED_MOV_DR_EXITING);
 
                /*
                 * No more DR vmexits; force a reload of the debug registers
@@ -4816,7 +4841,7 @@ static void vmx_sync_dirty_debug_regs(struct kvm_vcpu *vcpu)
        vcpu->arch.dr7 = vmcs_readl(GUEST_DR7);
 
        vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_WONT_EXIT;
-       vmcs_set_bits(CPU_BASED_VM_EXEC_CONTROL, CPU_BASED_MOV_DR_EXITING);
+       exec_controls_setbit(to_vmx(vcpu), CPU_BASED_MOV_DR_EXITING);
 }
 
 static void vmx_set_dr7(struct kvm_vcpu *vcpu, unsigned long val)
@@ -4876,8 +4901,7 @@ static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu)
 
 static int handle_interrupt_window(struct kvm_vcpu *vcpu)
 {
-       vmcs_clear_bits(CPU_BASED_VM_EXEC_CONTROL,
-                       CPU_BASED_VIRTUAL_INTR_PENDING);
+       exec_controls_clearbit(to_vmx(vcpu), CPU_BASED_VIRTUAL_INTR_PENDING);
 
        kvm_make_request(KVM_REQ_EVENT, vcpu);
 
@@ -5131,8 +5155,7 @@ static int handle_ept_misconfig(struct kvm_vcpu *vcpu)
 static int handle_nmi_window(struct kvm_vcpu *vcpu)
 {
        WARN_ON_ONCE(!enable_vnmi);
-       vmcs_clear_bits(CPU_BASED_VM_EXEC_CONTROL,
-                       CPU_BASED_VIRTUAL_NMI_PENDING);
+       exec_controls_clearbit(to_vmx(vcpu), CPU_BASED_VIRTUAL_NMI_PENDING);
        ++vcpu->stat.nmi_window_exits;
        kvm_make_request(KVM_REQ_EVENT, vcpu);
 
@@ -5144,7 +5167,6 @@ static int handle_invalid_guest_state(struct kvm_vcpu *vcpu)
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        enum emulation_result err = EMULATE_DONE;
        int ret = 1;
-       u32 cpu_exec_ctrl;
        bool intr_window_requested;
        unsigned count = 130;
 
@@ -5155,8 +5177,8 @@ static int handle_invalid_guest_state(struct kvm_vcpu *vcpu)
         */
        WARN_ON_ONCE(vmx->emulation_required && vmx->nested.nested_run_pending);
 
-       cpu_exec_ctrl = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
-       intr_window_requested = cpu_exec_ctrl & CPU_BASED_VIRTUAL_INTR_PENDING;
+       intr_window_requested = exec_controls_get(vmx) &
+                               CPU_BASED_VIRTUAL_INTR_PENDING;
 
        while (vmx->emulation_required && count-- != 0) {
                if (intr_window_requested && vmx_interrupt_allowed(vcpu))
@@ -5342,7 +5364,8 @@ static int handle_invpcid(struct kvm_vcpu *vcpu)
         * is read even if it isn't needed (e.g., for type==all)
         */
        if (get_vmx_mem_address(vcpu, vmcs_readl(EXIT_QUALIFICATION),
-                               vmx_instruction_info, false, &gva))
+                               vmx_instruction_info, false,
+                               sizeof(operand), &gva))
                return 1;
 
        if (kvm_read_guest_virt(vcpu, gva, &operand, sizeof(operand), &e)) {
@@ -5437,8 +5460,12 @@ static int handle_pml_full(struct kvm_vcpu *vcpu)
 
 static int handle_preemption_timer(struct kvm_vcpu *vcpu)
 {
-       if (!to_vmx(vcpu)->req_immediate_exit)
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+       if (!vmx->req_immediate_exit &&
+           !unlikely(vmx->loaded_vmcs->hv_timer_soft_disabled))
                kvm_lapic_expired_hv_timer(vcpu);
+
        return 1;
 }
 
@@ -5469,7 +5496,7 @@ static int handle_encls(struct kvm_vcpu *vcpu)
  * to be done to userspace and return 0.
  */
 static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = {
-       [EXIT_REASON_EXCEPTION_NMI]           = handle_exception,
+       [EXIT_REASON_EXCEPTION_NMI]           = handle_exception_nmi,
        [EXIT_REASON_EXTERNAL_INTERRUPT]      = handle_external_interrupt,
        [EXIT_REASON_TRIPLE_FAULT]            = handle_triple_fault,
        [EXIT_REASON_NMI_WINDOW]              = handle_nmi_window,
@@ -5952,6 +5979,7 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
 
 void vmx_set_virtual_apic_mode(struct kvm_vcpu *vcpu)
 {
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
        u32 sec_exec_control;
 
        if (!lapic_in_kernel(vcpu))
@@ -5963,11 +5991,11 @@ void vmx_set_virtual_apic_mode(struct kvm_vcpu *vcpu)
 
        /* Postpone execution until vmcs01 is the current VMCS. */
        if (is_guest_mode(vcpu)) {
-               to_vmx(vcpu)->nested.change_vmcs01_virtual_apic_mode = true;
+               vmx->nested.change_vmcs01_virtual_apic_mode = true;
                return;
        }
 
-       sec_exec_control = vmcs_read32(SECONDARY_VM_EXEC_CONTROL);
+       sec_exec_control = secondary_exec_controls_get(vmx);
        sec_exec_control &= ~(SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES |
                              SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE);
 
@@ -5989,7 +6017,7 @@ void vmx_set_virtual_apic_mode(struct kvm_vcpu *vcpu)
                                SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE;
                break;
        }
-       vmcs_write32(SECONDARY_VM_EXEC_CONTROL, sec_exec_control);
+       secondary_exec_controls_set(vmx, sec_exec_control);
 
        vmx_update_msr_bitmap(vcpu);
 }
@@ -6107,76 +6135,81 @@ static void vmx_apicv_post_state_restore(struct kvm_vcpu *vcpu)
        memset(vmx->pi_desc.pir, 0, sizeof(vmx->pi_desc.pir));
 }
 
-static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx)
+static void handle_exception_nmi_irqoff(struct vcpu_vmx *vmx)
 {
-       u32 exit_intr_info = 0;
-       u16 basic_exit_reason = (u16)vmx->exit_reason;
-
-       if (!(basic_exit_reason == EXIT_REASON_MCE_DURING_VMENTRY
-             || basic_exit_reason == EXIT_REASON_EXCEPTION_NMI))
-               return;
-
-       if (!(vmx->exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY))
-               exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
-       vmx->exit_intr_info = exit_intr_info;
+       vmx->exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
 
        /* if exit due to PF check for async PF */
-       if (is_page_fault(exit_intr_info))
+       if (is_page_fault(vmx->exit_intr_info))
                vmx->vcpu.arch.apf.host_apf_reason = kvm_read_and_reset_pf_reason();
 
        /* Handle machine checks before interrupts are enabled */
-       if (basic_exit_reason == EXIT_REASON_MCE_DURING_VMENTRY ||
-           is_machine_check(exit_intr_info))
+       if (is_machine_check(vmx->exit_intr_info))
                kvm_machine_check();
 
        /* We need to handle NMIs before interrupts are enabled */
-       if (is_nmi(exit_intr_info)) {
+       if (is_nmi(vmx->exit_intr_info)) {
                kvm_before_interrupt(&vmx->vcpu);
                asm("int $2");
                kvm_after_interrupt(&vmx->vcpu);
        }
 }
 
-static void vmx_handle_external_intr(struct kvm_vcpu *vcpu)
+static void handle_external_interrupt_irqoff(struct kvm_vcpu *vcpu)
 {
-       u32 exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
-
-       if ((exit_intr_info & (INTR_INFO_VALID_MASK | INTR_INFO_INTR_TYPE_MASK))
-                       == (INTR_INFO_VALID_MASK | INTR_TYPE_EXT_INTR)) {
-               unsigned int vector;
-               unsigned long entry;
-               gate_desc *desc;
-               struct vcpu_vmx *vmx = to_vmx(vcpu);
+       unsigned int vector;
+       unsigned long entry;
 #ifdef CONFIG_X86_64
-               unsigned long tmp;
+       unsigned long tmp;
 #endif
+       gate_desc *desc;
+       u32 intr_info;
+
+       intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
+       if (WARN_ONCE(!is_external_intr(intr_info),
+           "KVM: unexpected VM-Exit interrupt info: 0x%x", intr_info))
+               return;
 
-               vector =  exit_intr_info & INTR_INFO_VECTOR_MASK;
-               desc = (gate_desc *)vmx->host_idt_base + vector;
-               entry = gate_offset(desc);
-               asm volatile(
+       vector = intr_info & INTR_INFO_VECTOR_MASK;
+       desc = (gate_desc *)host_idt_base + vector;
+       entry = gate_offset(desc);
+
+       kvm_before_interrupt(vcpu);
+
+       asm volatile(
 #ifdef CONFIG_X86_64
-                       "mov %%" _ASM_SP ", %[sp]\n\t"
-                       "and $0xfffffffffffffff0, %%" _ASM_SP "\n\t"
-                       "push $%c[ss]\n\t"
-                       "push %[sp]\n\t"
+               "mov %%" _ASM_SP ", %[sp]\n\t"
+               "and $0xfffffffffffffff0, %%" _ASM_SP "\n\t"
+               "push $%c[ss]\n\t"
+               "push %[sp]\n\t"
 #endif
-                       "pushf\n\t"
-                       __ASM_SIZE(push) " $%c[cs]\n\t"
-                       CALL_NOSPEC
-                       :
+               "pushf\n\t"
+               __ASM_SIZE(push) " $%c[cs]\n\t"
+               CALL_NOSPEC
+               :
 #ifdef CONFIG_X86_64
-                       [sp]"=&r"(tmp),
+               [sp]"=&r"(tmp),
 #endif
-                       ASM_CALL_CONSTRAINT
-                       :
-                       THUNK_TARGET(entry),
-                       [ss]"i"(__KERNEL_DS),
-                       [cs]"i"(__KERNEL_CS)
-                       );
-       }
+               ASM_CALL_CONSTRAINT
+               :
+               THUNK_TARGET(entry),
+               [ss]"i"(__KERNEL_DS),
+               [cs]"i"(__KERNEL_CS)
+       );
+
+       kvm_after_interrupt(vcpu);
+}
+STACK_FRAME_NON_STANDARD(handle_external_interrupt_irqoff);
+
+static void vmx_handle_exit_irqoff(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+       if (vmx->exit_reason == EXIT_REASON_EXTERNAL_INTERRUPT)
+               handle_external_interrupt_irqoff(vcpu);
+       else if (vmx->exit_reason == EXIT_REASON_EXCEPTION_NMI)
+               handle_exception_nmi_irqoff(vmx);
 }
-STACK_FRAME_NON_STANDARD(vmx_handle_external_intr);
 
 static bool vmx_has_emulated_msr(int index)
 {
@@ -6187,6 +6220,8 @@ static bool vmx_has_emulated_msr(int index)
                 * real mode.
                 */
                return enable_unrestricted_guest || emulate_invalid_guest_state;
+       case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC:
+               return nested;
        case MSR_AMD64_VIRT_SPEC_CTRL:
                /* This is AMD only.  */
                return false;
@@ -6332,15 +6367,6 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx)
                                        msrs[i].host, false);
 }
 
-static void vmx_arm_hv_timer(struct vcpu_vmx *vmx, u32 val)
-{
-       vmcs_write32(VMX_PREEMPTION_TIMER_VALUE, val);
-       if (!vmx->loaded_vmcs->hv_timer_armed)
-               vmcs_set_bits(PIN_BASED_VM_EXEC_CONTROL,
-                             PIN_BASED_VMX_PREEMPTION_TIMER);
-       vmx->loaded_vmcs->hv_timer_armed = true;
-}
-
 static void vmx_update_hv_timer(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -6348,11 +6374,9 @@ static void vmx_update_hv_timer(struct kvm_vcpu *vcpu)
        u32 delta_tsc;
 
        if (vmx->req_immediate_exit) {
-               vmx_arm_hv_timer(vmx, 0);
-               return;
-       }
-
-       if (vmx->hv_deadline_tsc != -1) {
+               vmcs_write32(VMX_PREEMPTION_TIMER_VALUE, 0);
+               vmx->loaded_vmcs->hv_timer_soft_disabled = false;
+       } else if (vmx->hv_deadline_tsc != -1) {
                tscl = rdtsc();
                if (vmx->hv_deadline_tsc > tscl)
                        /* set_hv_timer ensures the delta fits in 32-bits */
@@ -6361,14 +6385,12 @@ static void vmx_update_hv_timer(struct kvm_vcpu *vcpu)
                else
                        delta_tsc = 0;
 
-               vmx_arm_hv_timer(vmx, delta_tsc);
-               return;
+               vmcs_write32(VMX_PREEMPTION_TIMER_VALUE, delta_tsc);
+               vmx->loaded_vmcs->hv_timer_soft_disabled = false;
+       } else if (!vmx->loaded_vmcs->hv_timer_soft_disabled) {
+               vmcs_write32(VMX_PREEMPTION_TIMER_VALUE, -1);
+               vmx->loaded_vmcs->hv_timer_soft_disabled = true;
        }
-
-       if (vmx->loaded_vmcs->hv_timer_armed)
-               vmcs_clear_bits(PIN_BASED_VM_EXEC_CONTROL,
-                               PIN_BASED_VMX_PREEMPTION_TIMER);
-       vmx->loaded_vmcs->hv_timer_armed = false;
 }
 
 void vmx_update_host_rsp(struct vcpu_vmx *vmx, unsigned long host_rsp)
@@ -6401,8 +6423,8 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu)
                vmcs_write32(PLE_WINDOW, vmx->ple_window);
        }
 
-       if (vmx->nested.need_vmcs12_sync)
-               nested_sync_from_vmcs12(vcpu);
+       if (vmx->nested.need_vmcs12_to_shadow_sync)
+               nested_sync_vmcs12_to_shadow(vcpu);
 
        if (test_bit(VCPU_REGS_RSP, (unsigned long *)&vcpu->arch.regs_dirty))
                vmcs_writel(GUEST_RSP, vcpu->arch.regs[VCPU_REGS_RSP]);
@@ -6440,7 +6462,12 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu)
 
        atomic_switch_perf_msrs(vmx);
 
-       vmx_update_hv_timer(vcpu);
+       if (enable_preemption_timer)
+               vmx_update_hv_timer(vcpu);
+
+       if (lapic_in_kernel(vcpu) &&
+               vcpu->arch.apic->lapic_timer.timer_advance_ns)
+               kvm_wait_lapic_expire(vcpu);
 
        /*
         * If this vCPU has touched SPEC_CTRL, restore the guest's value if
@@ -6533,13 +6560,15 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu)
        vmx->idt_vectoring_info = 0;
 
        vmx->exit_reason = vmx->fail ? 0xdead : vmcs_read32(VM_EXIT_REASON);
+       if ((u16)vmx->exit_reason == EXIT_REASON_MCE_DURING_VMENTRY)
+               kvm_machine_check();
+
        if (vmx->fail || (vmx->exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY))
                return;
 
        vmx->loaded_vmcs->launched = 1;
        vmx->idt_vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
 
-       vmx_complete_atomic_exit(vmx);
        vmx_recover_nmi_blocking(vmx);
        vmx_complete_interrupts(vmx);
 }
@@ -6630,6 +6659,12 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
        vmx_disable_intercept_for_msr(msr_bitmap, MSR_IA32_SYSENTER_CS, MSR_TYPE_RW);
        vmx_disable_intercept_for_msr(msr_bitmap, MSR_IA32_SYSENTER_ESP, MSR_TYPE_RW);
        vmx_disable_intercept_for_msr(msr_bitmap, MSR_IA32_SYSENTER_EIP, MSR_TYPE_RW);
+       if (kvm_cstate_in_guest(kvm)) {
+               vmx_disable_intercept_for_msr(msr_bitmap, MSR_CORE_C1_RES, MSR_TYPE_R);
+               vmx_disable_intercept_for_msr(msr_bitmap, MSR_CORE_C3_RESIDENCY, MSR_TYPE_R);
+               vmx_disable_intercept_for_msr(msr_bitmap, MSR_CORE_C6_RESIDENCY, MSR_TYPE_R);
+               vmx_disable_intercept_for_msr(msr_bitmap, MSR_CORE_C7_RESIDENCY, MSR_TYPE_R);
+       }
        vmx->msr_bitmap_mode = 0;
 
        vmx->loaded_vmcs = &vmx->vmcs01;
@@ -6726,22 +6761,22 @@ static int vmx_vm_init(struct kvm *kvm)
        return 0;
 }
 
-static void __init vmx_check_processor_compat(void *rtn)
+static int __init vmx_check_processor_compat(void)
 {
        struct vmcs_config vmcs_conf;
        struct vmx_capability vmx_cap;
 
-       *(int *)rtn = 0;
        if (setup_vmcs_config(&vmcs_conf, &vmx_cap) < 0)
-               *(int *)rtn = -EIO;
+               return -EIO;
        if (nested)
                nested_vmx_setup_ctls_msrs(&vmcs_conf.nested, vmx_cap.ept,
                                           enable_apicv);
        if (memcmp(&vmcs_config, &vmcs_conf, sizeof(struct vmcs_config)) != 0) {
                printk(KERN_ERR "kvm: CPU %d feature inconsistency!\n",
                                smp_processor_id());
-               *(int *)rtn = -EIO;
+               return -EIO;
        }
+       return 0;
 }
 
 static u64 vmx_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
@@ -6795,7 +6830,7 @@ static int vmx_get_lpage_level(void)
                return PT_PDPE_LEVEL;
 }
 
-static void vmcs_set_secondary_exec_control(u32 new_ctl)
+static void vmcs_set_secondary_exec_control(struct vcpu_vmx *vmx)
 {
        /*
         * These bits in the secondary execution controls field
@@ -6809,10 +6844,10 @@ static void vmcs_set_secondary_exec_control(u32 new_ctl)
                SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES |
                SECONDARY_EXEC_DESC;
 
-       u32 cur_ctl = vmcs_read32(SECONDARY_VM_EXEC_CONTROL);
+       u32 new_ctl = vmx->secondary_exec_control;
+       u32 cur_ctl = secondary_exec_controls_get(vmx);
 
-       vmcs_write32(SECONDARY_VM_EXEC_CONTROL,
-                    (new_ctl & ~mask) | (cur_ctl & mask));
+       secondary_exec_controls_set(vmx, (new_ctl & ~mask) | (cur_ctl & mask));
 }
 
 /*
@@ -6950,7 +6985,7 @@ static void vmx_cpuid_update(struct kvm_vcpu *vcpu)
 
        if (cpu_has_secondary_exec_ctrls()) {
                vmx_compute_secondary_exec_control(vmx);
-               vmcs_set_secondary_exec_control(vmx->secondary_exec_control);
+               vmcs_set_secondary_exec_control(vmx);
        }
 
        if (nested_vmx_allowed(vcpu))
@@ -7424,10 +7459,14 @@ static bool vmx_need_emulation_on_page_fault(struct kvm_vcpu *vcpu)
 static __init int hardware_setup(void)
 {
        unsigned long host_bndcfgs;
+       struct desc_ptr dt;
        int r, i;
 
        rdmsrl_safe(MSR_EFER, &host_efer);
 
+       store_idt(&dt);
+       host_idt_base = dt.address;
+
        for (i = 0; i < ARRAY_SIZE(vmx_msr_index); ++i)
                kvm_define_shared_msr(i, vmx_msr_index[i]);
 
@@ -7531,17 +7570,33 @@ static __init int hardware_setup(void)
        }
 
        if (!cpu_has_vmx_preemption_timer())
-               kvm_x86_ops->request_immediate_exit = __kvm_request_immediate_exit;
+               enable_preemption_timer = false;
 
-       if (cpu_has_vmx_preemption_timer() && enable_preemption_timer) {
+       if (enable_preemption_timer) {
+               u64 use_timer_freq = 5000ULL * 1000 * 1000;
                u64 vmx_msr;
 
                rdmsrl(MSR_IA32_VMX_MISC, vmx_msr);
                cpu_preemption_timer_multi =
                        vmx_msr & VMX_MISC_PREEMPTION_TIMER_RATE_MASK;
-       } else {
+
+               if (tsc_khz)
+                       use_timer_freq = (u64)tsc_khz * 1000;
+               use_timer_freq >>= cpu_preemption_timer_multi;
+
+               /*
+                * KVM "disables" the preemption timer by setting it to its max
+                * value.  Don't use the timer if it might cause spurious exits
+                * at a rate faster than 0.1 Hz (of uninterrupted guest time).
+                */
+               if (use_timer_freq > 0xffffffffu / 10)
+                       enable_preemption_timer = false;
+       }
+
+       if (!enable_preemption_timer) {
                kvm_x86_ops->set_hv_timer = NULL;
                kvm_x86_ops->cancel_hv_timer = NULL;
+               kvm_x86_ops->request_immediate_exit = __kvm_request_immediate_exit;
        }
 
        kvm_set_posted_intr_wakeup_handler(wakeup_handler);
@@ -7683,7 +7738,7 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
        .set_tdp_cr3 = vmx_set_cr3,
 
        .check_intercept = vmx_check_intercept,
-       .handle_external_intr = vmx_handle_external_intr,
+       .handle_exit_irqoff = vmx_handle_exit_irqoff,
        .mpx_supported = vmx_mpx_supported,
        .xsaves_supported = vmx_xsaves_supported,
        .umip_emulated = vmx_umip_emulated,
index 61128b4..82d0bc3 100644 (file)
@@ -109,13 +109,20 @@ struct nested_vmx {
         * to guest memory during VM exit.
         */
        struct vmcs12 *cached_shadow_vmcs12;
+
        /*
         * Indicates if the shadow vmcs or enlightened vmcs must be updated
         * with the data held by struct vmcs12.
         */
-       bool need_vmcs12_sync;
+       bool need_vmcs12_to_shadow_sync;
        bool dirty_vmcs12;
 
+       /*
+        * Indicates lazily loaded guest state has not yet been decached from
+        * vmcs02.
+        */
+       bool need_sync_vmcs02_to_vmcs12_rare;
+
        /*
         * vmcs02 has been initialized, i.e. state that is constant for
         * vmcs02 has been written to the backing VMCS.  Initialization
@@ -180,14 +187,24 @@ struct vcpu_vmx {
        struct kvm_vcpu       vcpu;
        u8                    fail;
        u8                    msr_bitmap_mode;
+
+       /*
+        * If true, host state has been stored in vmx->loaded_vmcs for
+        * the CPU registers that only need to be switched when transitioning
+        * to/from the kernel, and the registers have been loaded with guest
+        * values.  If false, host state is loaded in the CPU registers
+        * and vmx->loaded_vmcs->host_state is invalid.
+        */
+       bool                  guest_state_loaded;
+
        u32                   exit_intr_info;
        u32                   idt_vectoring_info;
        ulong                 rflags;
+
        struct shared_msr_entry *guest_msrs;
        int                   nmsrs;
        int                   save_nmsrs;
-       bool                  guest_msrs_dirty;
-       unsigned long         host_idt_base;
+       bool                  guest_msrs_ready;
 #ifdef CONFIG_X86_64
        u64                   msr_host_kernel_gs_base;
        u64                   msr_guest_kernel_gs_base;
@@ -195,21 +212,15 @@ struct vcpu_vmx {
 
        u64                   spec_ctrl;
 
-       u32 vm_entry_controls_shadow;
-       u32 vm_exit_controls_shadow;
        u32 secondary_exec_control;
 
        /*
         * loaded_vmcs points to the VMCS currently used in this vcpu. For a
         * non-nested (L1) guest, it always points to vmcs01. For a nested
-        * guest (L2), it points to a different VMCS.  loaded_cpu_state points
-        * to the VMCS whose state is loaded into the CPU registers that only
-        * need to be switched when transitioning to/from the kernel; a NULL
-        * value indicates that host state is loaded.
+        * guest (L2), it points to a different VMCS.
         */
        struct loaded_vmcs    vmcs01;
        struct loaded_vmcs   *loaded_vmcs;
-       struct loaded_vmcs   *loaded_cpu_state;
 
        struct msr_autoload {
                struct vmx_msrs guest;
@@ -260,8 +271,6 @@ struct vcpu_vmx {
 
        unsigned long host_debugctlmsr;
 
-       u64 msr_ia32_power_ctl;
-
        /*
         * Only bits masked by msr_ia32_feature_control_valid_bits can be set in
         * msr_ia32_feature_control. FEATURE_CONTROL_LOCKED is always included
@@ -292,12 +301,14 @@ struct kvm_vmx {
 };
 
 bool nested_vmx_allowed(struct kvm_vcpu *vcpu);
+void vmx_vcpu_load_vmcs(struct kvm_vcpu *vcpu, int cpu);
 void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu);
-void vmx_vcpu_put(struct kvm_vcpu *vcpu);
 int allocate_vpid(void);
 void free_vpid(int vpid);
 void vmx_set_constant_host_state(struct vcpu_vmx *vmx);
 void vmx_prepare_switch_to_guest(struct kvm_vcpu *vcpu);
+void vmx_set_host_fs_gs(struct vmcs_host_state *host, u16 fs_sel, u16 gs_sel,
+                       unsigned long fs_base, unsigned long gs_base);
 int vmx_get_cpl(struct kvm_vcpu *vcpu);
 unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu);
 void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags);
@@ -376,69 +387,31 @@ static inline u8 vmx_get_rvi(void)
        return vmcs_read16(GUEST_INTR_STATUS) & 0xff;
 }
 
-static inline void vm_entry_controls_reset_shadow(struct vcpu_vmx *vmx)
-{
-       vmx->vm_entry_controls_shadow = vmcs_read32(VM_ENTRY_CONTROLS);
-}
-
-static inline void vm_entry_controls_init(struct vcpu_vmx *vmx, u32 val)
-{
-       vmcs_write32(VM_ENTRY_CONTROLS, val);
-       vmx->vm_entry_controls_shadow = val;
-}
-
-static inline void vm_entry_controls_set(struct vcpu_vmx *vmx, u32 val)
-{
-       if (vmx->vm_entry_controls_shadow != val)
-               vm_entry_controls_init(vmx, val);
-}
-
-static inline u32 vm_entry_controls_get(struct vcpu_vmx *vmx)
-{
-       return vmx->vm_entry_controls_shadow;
-}
-
-static inline void vm_entry_controls_setbit(struct vcpu_vmx *vmx, u32 val)
-{
-       vm_entry_controls_set(vmx, vm_entry_controls_get(vmx) | val);
-}
-
-static inline void vm_entry_controls_clearbit(struct vcpu_vmx *vmx, u32 val)
-{
-       vm_entry_controls_set(vmx, vm_entry_controls_get(vmx) & ~val);
-}
-
-static inline void vm_exit_controls_reset_shadow(struct vcpu_vmx *vmx)
-{
-       vmx->vm_exit_controls_shadow = vmcs_read32(VM_EXIT_CONTROLS);
-}
-
-static inline void vm_exit_controls_init(struct vcpu_vmx *vmx, u32 val)
-{
-       vmcs_write32(VM_EXIT_CONTROLS, val);
-       vmx->vm_exit_controls_shadow = val;
-}
-
-static inline void vm_exit_controls_set(struct vcpu_vmx *vmx, u32 val)
-{
-       if (vmx->vm_exit_controls_shadow != val)
-               vm_exit_controls_init(vmx, val);
-}
-
-static inline u32 vm_exit_controls_get(struct vcpu_vmx *vmx)
-{
-       return vmx->vm_exit_controls_shadow;
-}
-
-static inline void vm_exit_controls_setbit(struct vcpu_vmx *vmx, u32 val)
-{
-       vm_exit_controls_set(vmx, vm_exit_controls_get(vmx) | val);
-}
-
-static inline void vm_exit_controls_clearbit(struct vcpu_vmx *vmx, u32 val)
-{
-       vm_exit_controls_set(vmx, vm_exit_controls_get(vmx) & ~val);
+#define BUILD_CONTROLS_SHADOW(lname, uname)                                \
+static inline void lname##_controls_set(struct vcpu_vmx *vmx, u32 val)     \
+{                                                                          \
+       if (vmx->loaded_vmcs->controls_shadow.lname != val) {               \
+               vmcs_write32(uname, val);                                   \
+               vmx->loaded_vmcs->controls_shadow.lname = val;              \
+       }                                                                   \
+}                                                                          \
+static inline u32 lname##_controls_get(struct vcpu_vmx *vmx)               \
+{                                                                          \
+       return vmx->loaded_vmcs->controls_shadow.lname;                     \
+}                                                                          \
+static inline void lname##_controls_setbit(struct vcpu_vmx *vmx, u32 val)   \
+{                                                                          \
+       lname##_controls_set(vmx, lname##_controls_get(vmx) | val);         \
+}                                                                          \
+static inline void lname##_controls_clearbit(struct vcpu_vmx *vmx, u32 val) \
+{                                                                          \
+       lname##_controls_set(vmx, lname##_controls_get(vmx) & ~val);        \
 }
+BUILD_CONTROLS_SHADOW(vm_entry, VM_ENTRY_CONTROLS)
+BUILD_CONTROLS_SHADOW(vm_exit, VM_EXIT_CONTROLS)
+BUILD_CONTROLS_SHADOW(pin, PIN_BASED_VM_EXEC_CONTROL)
+BUILD_CONTROLS_SHADOW(exec, CPU_BASED_VM_EXEC_CONTROL)
+BUILD_CONTROLS_SHADOW(secondary_exec, SECONDARY_VM_EXEC_CONTROL)
 
 static inline void vmx_segment_cache_clear(struct vcpu_vmx *vmx)
 {
@@ -468,6 +441,7 @@ static inline u32 vmx_vmexit_ctrl(void)
 }
 
 u32 vmx_exec_control(struct vcpu_vmx *vmx);
+u32 vmx_pin_based_exec_ctrl(struct vcpu_vmx *vmx);
 
 static inline struct kvm_vmx *to_kvm_vmx(struct kvm *kvm)
 {
index 63bb1ee..4a0b74e 100644 (file)
@@ -717,7 +717,7 @@ bool pdptrs_changed(struct kvm_vcpu *vcpu)
        gfn_t gfn;
        int r;
 
-       if (is_long_mode(vcpu) || !is_pae(vcpu) || !is_paging(vcpu))
+       if (!is_pae_paging(vcpu))
                return false;
 
        if (!test_bit(VCPU_EXREG_PDPTR,
@@ -960,8 +960,8 @@ int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
        if (is_long_mode(vcpu) &&
            (cr3 & rsvd_bits(cpuid_maxphyaddr(vcpu), 63)))
                return 1;
-       else if (is_pae(vcpu) && is_paging(vcpu) &&
-                  !load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3))
+       else if (is_pae_paging(vcpu) &&
+                !load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3))
                return 1;
 
        kvm_mmu_new_cr3(vcpu, cr3, skip_tlb_flush);
@@ -1174,7 +1174,28 @@ static u32 emulated_msrs[] = {
        MSR_AMD64_VIRT_SPEC_CTRL,
        MSR_IA32_POWER_CTL,
 
+       /*
+        * The following list leaves out MSRs whose values are determined
+        * by arch/x86/kvm/vmx/nested.c based on CPUID or other MSRs.
+        * We always support the "true" VMX control MSRs, even if the host
+        * processor does not, so I am putting these registers here rather
+        * than in msrs_to_save.
+        */
+       MSR_IA32_VMX_BASIC,
+       MSR_IA32_VMX_TRUE_PINBASED_CTLS,
+       MSR_IA32_VMX_TRUE_PROCBASED_CTLS,
+       MSR_IA32_VMX_TRUE_EXIT_CTLS,
+       MSR_IA32_VMX_TRUE_ENTRY_CTLS,
+       MSR_IA32_VMX_MISC,
+       MSR_IA32_VMX_CR0_FIXED0,
+       MSR_IA32_VMX_CR4_FIXED0,
+       MSR_IA32_VMX_VMCS_ENUM,
+       MSR_IA32_VMX_PROCBASED_CTLS2,
+       MSR_IA32_VMX_EPT_VPID_CAP,
+       MSR_IA32_VMX_VMFUNC,
+
        MSR_K7_HWCR,
+       MSR_KVM_POLL_CONTROL,
 };
 
 static unsigned num_emulated_msrs;
@@ -1210,11 +1231,12 @@ static u32 msr_based_features[] = {
 
 static unsigned int num_msr_based_features;
 
-u64 kvm_get_arch_capabilities(void)
+static u64 kvm_get_arch_capabilities(void)
 {
-       u64 data;
+       u64 data = 0;
 
-       rdmsrl_safe(MSR_IA32_ARCH_CAPABILITIES, &data);
+       if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES))
+               rdmsrl(MSR_IA32_ARCH_CAPABILITIES, data);
 
        /*
         * If we're doing cache flushes (either "always" or "cond")
@@ -1230,7 +1252,6 @@ u64 kvm_get_arch_capabilities(void)
 
        return data;
 }
-EXPORT_SYMBOL_GPL(kvm_get_arch_capabilities);
 
 static int kvm_get_msr_feature(struct kvm_msr_entry *msr)
 {
@@ -2545,13 +2566,24 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                }
                break;
        case MSR_IA32_MISC_ENABLE:
-               vcpu->arch.ia32_misc_enable_msr = data;
+               if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT) &&
+                   ((vcpu->arch.ia32_misc_enable_msr ^ data) & MSR_IA32_MISC_ENABLE_MWAIT)) {
+                       if (!guest_cpuid_has(vcpu, X86_FEATURE_XMM3))
+                               return 1;
+                       vcpu->arch.ia32_misc_enable_msr = data;
+                       kvm_update_cpuid(vcpu);
+               } else {
+                       vcpu->arch.ia32_misc_enable_msr = data;
+               }
                break;
        case MSR_IA32_SMBASE:
                if (!msr_info->host_initiated)
                        return 1;
                vcpu->arch.smbase = data;
                break;
+       case MSR_IA32_POWER_CTL:
+               vcpu->arch.msr_ia32_power_ctl = data;
+               break;
        case MSR_IA32_TSC:
                kvm_write_tsc(vcpu, msr_info);
                break;
@@ -2626,6 +2658,14 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                        return 1;
                break;
 
+       case MSR_KVM_POLL_CONTROL:
+               /* only enable bit supported */
+               if (data & (-1ULL << 1))
+                       return 1;
+
+               vcpu->arch.msr_kvm_poll_control = data;
+               break;
+
        case MSR_IA32_MCG_CTL:
        case MSR_IA32_MCG_STATUS:
        case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1:
@@ -2803,6 +2843,9 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                        return 1;
                msr_info->data = vcpu->arch.arch_capabilities;
                break;
+       case MSR_IA32_POWER_CTL:
+               msr_info->data = vcpu->arch.msr_ia32_power_ctl;
+               break;
        case MSR_IA32_TSC:
                msr_info->data = kvm_scale_tsc(vcpu, rdtsc()) + vcpu->arch.tsc_offset;
                break;
@@ -2875,6 +2918,9 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case MSR_KVM_PV_EOI_EN:
                msr_info->data = vcpu->arch.pv_eoi.msr_val;
                break;
+       case MSR_KVM_POLL_CONTROL:
+               msr_info->data = vcpu->arch.msr_kvm_poll_control;
+               break;
        case MSR_IA32_P5_MC_ADDR:
        case MSR_IA32_P5_MC_TYPE:
        case MSR_IA32_MCG_CAP:
@@ -3084,6 +3130,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_SET_BOOT_CPU_ID:
        case KVM_CAP_SPLIT_IRQCHIP:
        case KVM_CAP_IMMEDIATE_EXIT:
+       case KVM_CAP_PMU_EVENT_FILTER:
        case KVM_CAP_GET_MSR_FEATURES:
        case KVM_CAP_MSR_PLATFORM_INFO:
        case KVM_CAP_EXCEPTION_PAYLOAD:
@@ -3096,7 +3143,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
                r = KVM_CLOCK_TSC_STABLE;
                break;
        case KVM_CAP_X86_DISABLE_EXITS:
-               r |=  KVM_X86_DISABLE_EXITS_HLT | KVM_X86_DISABLE_EXITS_PAUSE;
+               r |=  KVM_X86_DISABLE_EXITS_HLT | KVM_X86_DISABLE_EXITS_PAUSE |
+                     KVM_X86_DISABLE_EXITS_CSTATE;
                if(kvm_can_mwait_in_guest())
                        r |= KVM_X86_DISABLE_EXITS_MWAIT;
                break;
@@ -4613,6 +4661,8 @@ split_irqchip_unlock:
                        kvm->arch.hlt_in_guest = true;
                if (cap->args[0] & KVM_X86_DISABLE_EXITS_PAUSE)
                        kvm->arch.pause_in_guest = true;
+               if (cap->args[0] & KVM_X86_DISABLE_EXITS_CSTATE)
+                       kvm->arch.cstate_in_guest = true;
                r = 0;
                break;
        case KVM_CAP_MSR_PLATFORM_INFO:
@@ -4927,6 +4977,9 @@ set_identity_unlock:
                r = kvm_vm_ioctl_hv_eventfd(kvm, &hvevfd);
                break;
        }
+       case KVM_SET_PMU_EVENT_FILTER:
+               r = kvm_vm_ioctl_set_pmu_event_filter(kvm, argp);
+               break;
        default:
                r = -ENOTTY;
        }
@@ -6379,7 +6432,7 @@ static bool kvm_vcpu_check_breakpoint(struct kvm_vcpu *vcpu, int *r)
                                           vcpu->arch.db);
 
                if (dr6 != 0) {
-                       vcpu->arch.dr6 &= ~15;
+                       vcpu->arch.dr6 &= ~DR_TRAP_BITS;
                        vcpu->arch.dr6 |= dr6 | DR6_RTM;
                        kvm_queue_exception(vcpu, DB_VECTOR);
                        *r = EMULATE_DONE;
@@ -6706,7 +6759,7 @@ static void kvm_hyperv_tsc_notifier(void)
        struct kvm_vcpu *vcpu;
        int cpu;
 
-       spin_lock(&kvm_lock);
+       mutex_lock(&kvm_lock);
        list_for_each_entry(kvm, &vm_list, vm_list)
                kvm_make_mclock_inprogress_request(kvm);
 
@@ -6732,7 +6785,7 @@ static void kvm_hyperv_tsc_notifier(void)
 
                spin_unlock(&ka->pvclock_gtod_sync_lock);
        }
-       spin_unlock(&kvm_lock);
+       mutex_unlock(&kvm_lock);
 }
 #endif
 
@@ -6783,17 +6836,17 @@ static void __kvmclock_cpufreq_notifier(struct cpufreq_freqs *freq, int cpu)
 
        smp_call_function_single(cpu, tsc_khz_changed, freq, 1);
 
-       spin_lock(&kvm_lock);
+       mutex_lock(&kvm_lock);
        list_for_each_entry(kvm, &vm_list, vm_list) {
                kvm_for_each_vcpu(i, vcpu, kvm) {
                        if (vcpu->cpu != cpu)
                                continue;
                        kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
-                       if (vcpu->cpu != smp_processor_id())
+                       if (vcpu->cpu != raw_smp_processor_id())
                                send_ipi = 1;
                }
        }
-       spin_unlock(&kvm_lock);
+       mutex_unlock(&kvm_lock);
 
        if (freq->old < freq->new && send_ipi) {
                /*
@@ -6908,35 +6961,6 @@ static struct perf_guest_info_callbacks kvm_guest_cbs = {
        .handle_intel_pt_intr   = kvm_handle_intel_pt_intr,
 };
 
-static void kvm_set_mmio_spte_mask(void)
-{
-       u64 mask;
-       int maxphyaddr = boot_cpu_data.x86_phys_bits;
-
-       /*
-        * Set the reserved bits and the present bit of an paging-structure
-        * entry to generate page fault with PFER.RSV = 1.
-        */
-
-       /*
-        * Mask the uppermost physical address bit, which would be reserved as
-        * long as the supported physical address width is less than 52.
-        */
-       mask = 1ull << 51;
-
-       /* Set the present bit. */
-       mask |= 1ull;
-
-       /*
-        * If reserved bit is not supported, clear the present bit to disable
-        * mmio page fault.
-        */
-       if (IS_ENABLED(CONFIG_X86_64) && maxphyaddr == 52)
-               mask &= ~1ull;
-
-       kvm_mmu_set_mmio_spte_mask(mask, mask);
-}
-
 #ifdef CONFIG_X86_64
 static void pvclock_gtod_update_fn(struct work_struct *work)
 {
@@ -6945,12 +6969,12 @@ static void pvclock_gtod_update_fn(struct work_struct *work)
        struct kvm_vcpu *vcpu;
        int i;
 
-       spin_lock(&kvm_lock);
+       mutex_lock(&kvm_lock);
        list_for_each_entry(kvm, &vm_list, vm_list)
                kvm_for_each_vcpu(i, vcpu, kvm)
                        kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);
        atomic_set(&kvm_guest_has_master_clock, 0);
-       spin_unlock(&kvm_lock);
+       mutex_unlock(&kvm_lock);
 }
 
 static DECLARE_WORK(pvclock_gtod_work, pvclock_gtod_update_fn);
@@ -7033,8 +7057,6 @@ int kvm_arch_init(void *opaque)
        if (r)
                goto out_free_percpu;
 
-       kvm_set_mmio_spte_mask();
-
        kvm_x86_ops = ops;
 
        kvm_mmu_set_mask_ptes(PT_USER_MASK, PT_ACCESSED_MASK,
@@ -7173,6 +7195,23 @@ void kvm_vcpu_deactivate_apicv(struct kvm_vcpu *vcpu)
        kvm_x86_ops->refresh_apicv_exec_ctrl(vcpu);
 }
 
+static void kvm_sched_yield(struct kvm *kvm, unsigned long dest_id)
+{
+       struct kvm_vcpu *target = NULL;
+       struct kvm_apic_map *map;
+
+       rcu_read_lock();
+       map = rcu_dereference(kvm->arch.apic_map);
+
+       if (likely(map) && dest_id <= map->max_apic_id && map->phys_map[dest_id])
+               target = map->phys_map[dest_id]->vcpu;
+
+       rcu_read_unlock();
+
+       if (target)
+               kvm_vcpu_yield_to(target);
+}
+
 int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
 {
        unsigned long nr, a0, a1, a2, a3, ret;
@@ -7219,6 +7258,10 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
        case KVM_HC_SEND_IPI:
                ret = kvm_pv_send_ipi(vcpu->kvm, a0, a1, a2, a3, op_64_bit);
                break;
+       case KVM_HC_SCHED_YIELD:
+               kvm_sched_yield(vcpu->kvm, a0);
+               ret = 0;
+               break;
        default:
                ret = -KVM_ENOSYS;
                break;
@@ -7951,9 +7994,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
        }
 
        trace_kvm_entry(vcpu->vcpu_id);
-       if (lapic_in_kernel(vcpu) &&
-           vcpu->arch.apic->lapic_timer.timer_advance_ns)
-               wait_lapic_expire(vcpu);
        guest_enter_irqoff();
 
        fpregs_assert_state_consistent();
@@ -8002,13 +8042,29 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
        vcpu->mode = OUTSIDE_GUEST_MODE;
        smp_wmb();
 
-       kvm_before_interrupt(vcpu);
-       kvm_x86_ops->handle_external_intr(vcpu);
-       kvm_after_interrupt(vcpu);
+       kvm_x86_ops->handle_exit_irqoff(vcpu);
 
+       /*
+        * Consume any pending interrupts, including the possible source of
+        * VM-Exit on SVM and any ticks that occur between VM-Exit and now.
+        * An instruction is required after local_irq_enable() to fully unblock
+        * interrupts on processors that implement an interrupt shadow, the
+        * stat.exits increment will do nicely.
+        */
+       kvm_before_interrupt(vcpu);
+       local_irq_enable();
        ++vcpu->stat.exits;
+       local_irq_disable();
+       kvm_after_interrupt(vcpu);
 
        guest_exit_irqoff();
+       if (lapic_in_kernel(vcpu)) {
+               s64 delta = vcpu->arch.apic->lapic_timer.advance_expire_delta;
+               if (delta != S64_MIN) {
+                       trace_kvm_wait_lapic_expire(vcpu->vcpu_id, delta);
+                       vcpu->arch.apic->lapic_timer.advance_expire_delta = S64_MIN;
+               }
+       }
 
        local_irq_enable();
        preempt_enable();
@@ -8594,7 +8650,7 @@ static int __set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
                kvm_update_cpuid(vcpu);
 
        idx = srcu_read_lock(&vcpu->kvm->srcu);
-       if (!is_long_mode(vcpu) && is_pae(vcpu) && is_paging(vcpu)) {
+       if (is_pae_paging(vcpu)) {
                load_pdptrs(vcpu, vcpu->arch.walk_mmu, kvm_read_cr3(vcpu));
                mmu_reset_needed = 1;
        }
@@ -8875,6 +8931,10 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
        msr.host_initiated = true;
        kvm_write_tsc(vcpu, &msr);
        vcpu_put(vcpu);
+
+       /* poll control enabled by default */
+       vcpu->arch.msr_kvm_poll_control = 1;
+
        mutex_unlock(&vcpu->mutex);
 
        if (!kvmclock_periodic_sync)
@@ -9107,9 +9167,9 @@ void kvm_arch_hardware_unsetup(void)
        kvm_x86_ops->hardware_unsetup();
 }
 
-void kvm_arch_check_processor_compat(void *rtn)
+int kvm_arch_check_processor_compat(void)
 {
-       kvm_x86_ops->check_processor_compatibility(rtn);
+       return kvm_x86_ops->check_processor_compatibility();
 }
 
 bool kvm_vcpu_is_reset_bsp(struct kvm_vcpu *vcpu)
@@ -9381,6 +9441,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
        kvm_ioapic_destroy(kvm);
        kvm_free_vcpus(kvm);
        kvfree(rcu_dereference_check(kvm->arch.apic_map, 1));
+       kfree(srcu_dereference_check(kvm->arch.pmu_event_filter, &kvm->srcu, 1));
        kvm_mmu_uninit_vm(kvm);
        kvm_page_track_cleanup(kvm);
        kvm_hv_destroy_vm(kvm);
@@ -9789,6 +9850,36 @@ static int apf_get_user(struct kvm_vcpu *vcpu, u32 *val)
                                      sizeof(u32));
 }
 
+static bool kvm_can_deliver_async_pf(struct kvm_vcpu *vcpu)
+{
+       if (!vcpu->arch.apf.delivery_as_pf_vmexit && is_guest_mode(vcpu))
+               return false;
+
+       if (!(vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED) ||
+           (vcpu->arch.apf.send_user_only &&
+            kvm_x86_ops->get_cpl(vcpu) == 0))
+               return false;
+
+       return true;
+}
+
+bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu)
+{
+       if (unlikely(!lapic_in_kernel(vcpu) ||
+                    kvm_event_needs_reinjection(vcpu) ||
+                    vcpu->arch.exception.pending))
+               return false;
+
+       if (kvm_hlt_in_guest(vcpu->kvm) && !kvm_can_deliver_async_pf(vcpu))
+               return false;
+
+       /*
+        * If interrupts are off we cannot even use an artificial
+        * halt state.
+        */
+       return kvm_x86_ops->interrupt_allowed(vcpu);
+}
+
 void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
                                     struct kvm_async_pf *work)
 {
@@ -9797,11 +9888,8 @@ void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
        trace_kvm_async_pf_not_present(work->arch.token, work->gva);
        kvm_add_async_pf_gfn(vcpu, work->arch.gfn);
 
-       if (!(vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED) ||
-           (vcpu->arch.apf.send_user_only &&
-            kvm_x86_ops->get_cpl(vcpu) == 0))
-               kvm_make_request(KVM_REQ_APF_HALT, vcpu);
-       else if (!apf_put_user(vcpu, KVM_PV_REASON_PAGE_NOT_PRESENT)) {
+       if (kvm_can_deliver_async_pf(vcpu) &&
+           !apf_put_user(vcpu, KVM_PV_REASON_PAGE_NOT_PRESENT)) {
                fault.vector = PF_VECTOR;
                fault.error_code_valid = true;
                fault.error_code = 0;
@@ -9809,6 +9897,16 @@ void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
                fault.address = work->arch.token;
                fault.async_page_fault = true;
                kvm_inject_page_fault(vcpu, &fault);
+       } else {
+               /*
+                * It is not possible to deliver a paravirtualized asynchronous
+                * page fault, but putting the guest in an artificial halt state
+                * can be beneficial nevertheless: if an interrupt arrives, we
+                * can deliver it timely and perhaps the guest will schedule
+                * another process.  When the instruction that triggered a page
+                * fault is retried, hopefully the page will be ready in the host.
+                */
+               kvm_make_request(KVM_REQ_APF_HALT, vcpu);
        }
 }
 
@@ -9949,6 +10047,13 @@ bool kvm_vector_hashing_enabled(void)
 }
 EXPORT_SYMBOL_GPL(kvm_vector_hashing_enabled);
 
+bool kvm_arch_no_poll(struct kvm_vcpu *vcpu)
+{
+       return (vcpu->arch.msr_kvm_poll_control & 1) == 0;
+}
+EXPORT_SYMBOL_GPL(kvm_arch_no_poll);
+
+
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_exit);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_fast_mmio);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_inj_virq);
index a470ff0..e08a128 100644 (file)
@@ -139,6 +139,11 @@ static inline int is_paging(struct kvm_vcpu *vcpu)
        return likely(kvm_read_cr0_bits(vcpu, X86_CR0_PG));
 }
 
+static inline bool is_pae_paging(struct kvm_vcpu *vcpu)
+{
+       return !is_long_mode(vcpu) && is_pae(vcpu) && is_paging(vcpu);
+}
+
 static inline u32 bit(int bitno)
 {
        return 1 << (bitno & 31);
@@ -333,6 +338,11 @@ static inline bool kvm_pause_in_guest(struct kvm *kvm)
        return kvm->arch.pause_in_guest;
 }
 
+static inline bool kvm_cstate_in_guest(struct kvm *kvm)
+{
+       return kvm->arch.cstate_in_guest;
+}
+
 DECLARE_PER_CPU(struct kvm_vcpu *, current_vcpu);
 
 static inline void kvm_before_interrupt(struct kvm_vcpu *vcpu)
index c6f4982..39001a4 100644 (file)
@@ -26,8 +26,6 @@ static int ptdump_curknl_show(struct seq_file *m, void *v)
 DEFINE_SHOW_ATTRIBUTE(ptdump_curknl);
 
 #ifdef CONFIG_PAGE_TABLE_ISOLATION
-static struct dentry *pe_curusr;
-
 static int ptdump_curusr_show(struct seq_file *m, void *v)
 {
        if (current->mm->pgd) {
@@ -42,8 +40,6 @@ DEFINE_SHOW_ATTRIBUTE(ptdump_curusr);
 #endif
 
 #if defined(CONFIG_EFI) && defined(CONFIG_X86_64)
-static struct dentry *pe_efi;
-
 static int ptdump_efi_show(struct seq_file *m, void *v)
 {
        if (efi_mm.pgd)
@@ -54,41 +50,24 @@ static int ptdump_efi_show(struct seq_file *m, void *v)
 DEFINE_SHOW_ATTRIBUTE(ptdump_efi);
 #endif
 
-static struct dentry *dir, *pe_knl, *pe_curknl;
+static struct dentry *dir;
 
 static int __init pt_dump_debug_init(void)
 {
        dir = debugfs_create_dir("page_tables", NULL);
-       if (!dir)
-               return -ENOMEM;
-
-       pe_knl = debugfs_create_file("kernel", 0400, dir, NULL,
-                                    &ptdump_fops);
-       if (!pe_knl)
-               goto err;
 
-       pe_curknl = debugfs_create_file("current_kernel", 0400,
-                                       dir, NULL, &ptdump_curknl_fops);
-       if (!pe_curknl)
-               goto err;
+       debugfs_create_file("kernel", 0400, dir, NULL, &ptdump_fops);
+       debugfs_create_file("current_kernel", 0400, dir, NULL,
+                           &ptdump_curknl_fops);
 
 #ifdef CONFIG_PAGE_TABLE_ISOLATION
-       pe_curusr = debugfs_create_file("current_user", 0400,
-                                       dir, NULL, &ptdump_curusr_fops);
-       if (!pe_curusr)
-               goto err;
+       debugfs_create_file("current_user", 0400, dir, NULL,
+                           &ptdump_curusr_fops);
 #endif
-
 #if defined(CONFIG_EFI) && defined(CONFIG_X86_64)
-       pe_efi = debugfs_create_file("efi", 0400, dir, NULL, &ptdump_efi_fops);
-       if (!pe_efi)
-               goto err;
+       debugfs_create_file("efi", 0400, dir, NULL, &ptdump_efi_fops);
 #endif
-
        return 0;
-err:
-       debugfs_remove_recursive(dir);
-       return -ENOMEM;
 }
 
 static void __exit pt_dump_debug_exit(void)
index 1f67b1e..44816ff 100644 (file)
@@ -13,33 +13,17 @@ phys_addr_t physical_mask __ro_after_init = (1ULL << __PHYSICAL_MASK_SHIFT) - 1;
 EXPORT_SYMBOL(physical_mask);
 #endif
 
-#define PGALLOC_GFP (GFP_KERNEL_ACCOUNT | __GFP_ZERO)
-
 #ifdef CONFIG_HIGHPTE
-#define PGALLOC_USER_GFP __GFP_HIGHMEM
+#define PGTABLE_HIGHMEM __GFP_HIGHMEM
 #else
-#define PGALLOC_USER_GFP 0
+#define PGTABLE_HIGHMEM 0
 #endif
 
-gfp_t __userpte_alloc_gfp = PGALLOC_GFP | PGALLOC_USER_GFP;
-
-pte_t *pte_alloc_one_kernel(struct mm_struct *mm)
-{
-       return (pte_t *)__get_free_page(PGALLOC_GFP & ~__GFP_ACCOUNT);
-}
+gfp_t __userpte_alloc_gfp = GFP_PGTABLE_USER | PGTABLE_HIGHMEM;
 
 pgtable_t pte_alloc_one(struct mm_struct *mm)
 {
-       struct page *pte;
-
-       pte = alloc_pages(__userpte_alloc_gfp, 0);
-       if (!pte)
-               return NULL;
-       if (!pgtable_page_ctor(pte)) {
-               __free_page(pte);
-               return NULL;
-       }
-       return pte;
+       return __pte_alloc_one(mm, __userpte_alloc_gfp);
 }
 
 static int __init setup_userpte(char *arg)
@@ -235,7 +219,7 @@ static int preallocate_pmds(struct mm_struct *mm, pmd_t *pmds[], int count)
 {
        int i;
        bool failed = false;
-       gfp_t gfp = PGALLOC_GFP;
+       gfp_t gfp = GFP_PGTABLE_USER;
 
        if (mm == &init_mm)
                gfp &= ~__GFP_ACCOUNT;
@@ -399,14 +383,14 @@ static inline pgd_t *_pgd_alloc(void)
         * We allocate one page for pgd.
         */
        if (!SHARED_KERNEL_PMD)
-               return (pgd_t *)__get_free_pages(PGALLOC_GFP,
+               return (pgd_t *)__get_free_pages(GFP_PGTABLE_USER,
                                                 PGD_ALLOCATION_ORDER);
 
        /*
         * Now PAE kernel is not running as a Xen domain. We can allocate
         * a 32-byte slab for pgd to save memory space.
         */
-       return kmem_cache_alloc(pgd_cache, PGALLOC_GFP);
+       return kmem_cache_alloc(pgd_cache, GFP_PGTABLE_USER);
 }
 
 static inline void _pgd_free(pgd_t *pgd)
@@ -424,7 +408,8 @@ void __init pgd_cache_init(void)
 
 static inline pgd_t *_pgd_alloc(void)
 {
-       return (pgd_t *)__get_free_pages(PGALLOC_GFP, PGD_ALLOCATION_ORDER);
+       return (pgd_t *)__get_free_pages(GFP_PGTABLE_USER,
+                                        PGD_ALLOCATION_ORDER);
 }
 
 static inline void _pgd_free(pgd_t *pgd)
index 17185d7..ee6b078 100644 (file)
@@ -104,24 +104,12 @@ DEFINE_SHOW_ATTRIBUTE(punit_dev_state);
 
 static struct dentry *punit_dbg_file;
 
-static int punit_dbgfs_register(struct punit_device *punit_device)
+static void punit_dbgfs_register(struct punit_device *punit_device)
 {
-       struct dentry *dev_state;
-
        punit_dbg_file = debugfs_create_dir("punit_atom", NULL);
-       if (!punit_dbg_file)
-               return -ENXIO;
-
-       dev_state = debugfs_create_file("dev_power_state", 0444,
-                                       punit_dbg_file, punit_device,
-                                       &punit_dev_state_fops);
-       if (!dev_state) {
-               pr_err("punit_dev_state register failed\n");
-               debugfs_remove(punit_dbg_file);
-               return -ENXIO;
-       }
 
-       return 0;
+       debugfs_create_file("dev_power_state", 0444, punit_dbg_file,
+                           punit_device, &punit_dev_state_fops);
 }
 
 static void punit_dbgfs_unregister(void)
@@ -145,15 +133,12 @@ MODULE_DEVICE_TABLE(x86cpu, intel_punit_cpu_ids);
 static int __init punit_atom_debug_init(void)
 {
        const struct x86_cpu_id *id;
-       int ret;
 
        id = x86_match_cpu(intel_punit_cpu_ids);
        if (!id)
                return -ENODEV;
 
-       ret = punit_dbgfs_register((struct punit_device *)id->driver_data);
-       if (ret < 0)
-               return ret;
+       punit_dbgfs_register((struct punit_device *)id->driver_data);
 
        return 0;
 }
index b542037..6dd25dc 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/types.h>
 
 struct imr_device {
-       struct dentry   *file;
        bool            init;
        struct mutex    lock;
        int             max_imr;
@@ -231,13 +230,11 @@ DEFINE_SHOW_ATTRIBUTE(imr_dbgfs_state);
  * imr_debugfs_register - register debugfs hooks.
  *
  * @idev:      pointer to imr_device structure.
- * @return:    0 on success - errno on failure.
  */
-static int imr_debugfs_register(struct imr_device *idev)
+static void imr_debugfs_register(struct imr_device *idev)
 {
-       idev->file = debugfs_create_file("imr_state", 0444, NULL, idev,
-                                        &imr_dbgfs_state_fops);
-       return PTR_ERR_OR_ZERO(idev->file);
+       debugfs_create_file("imr_state", 0444, NULL, idev,
+                           &imr_dbgfs_state_fops);
 }
 
 /**
@@ -582,7 +579,6 @@ static const struct x86_cpu_id imr_ids[] __initconst = {
 static int __init imr_init(void)
 {
        struct imr_device *idev = &imr_dev;
-       int ret;
 
        if (!x86_match_cpu(imr_ids) || !iosf_mbi_available())
                return -ENODEV;
@@ -592,9 +588,7 @@ static int __init imr_init(void)
        idev->init = true;
 
        mutex_init(&idev->lock);
-       ret = imr_debugfs_register(idev);
-       if (ret != 0)
-               pr_warn("debugfs register failed!\n");
+       imr_debugfs_register(idev);
        imr_fixup_memmap(idev);
        return 0;
 }
index b393eaa..2e796b5 100644 (file)
@@ -461,31 +461,16 @@ static struct dentry *iosf_dbg;
 
 static void iosf_sideband_debug_init(void)
 {
-       struct dentry *d;
-
        iosf_dbg = debugfs_create_dir("iosf_sb", NULL);
-       if (IS_ERR_OR_NULL(iosf_dbg))
-               return;
 
        /* mdr */
-       d = debugfs_create_x32("mdr", 0660, iosf_dbg, &dbg_mdr);
-       if (!d)
-               goto cleanup;
+       debugfs_create_x32("mdr", 0660, iosf_dbg, &dbg_mdr);
 
        /* mcrx */
-       d = debugfs_create_x32("mcrx", 0660, iosf_dbg, &dbg_mcrx);
-       if (!d)
-               goto cleanup;
+       debugfs_create_x32("mcrx", 0660, iosf_dbg, &dbg_mcrx);
 
        /* mcr - initiates mailbox tranaction */
-       d = debugfs_create_file("mcr", 0660, iosf_dbg, &dbg_mcr, &iosf_mcr_fops);
-       if (!d)
-               goto cleanup;
-
-       return;
-
-cleanup:
-       debugfs_remove_recursive(d);
+       debugfs_create_file("mcr", 0660, iosf_dbg, &dbg_mcr, &iosf_mcr_fops);
 }
 
 static void iosf_debugfs_init(void)
index 0c7dfec..20c389a 100644 (file)
@@ -66,7 +66,6 @@ static struct tunables tunables[] = {
 };
 
 static struct dentry *tunables_dir;
-static struct dentry *tunables_file;
 
 /* these correspond to the statistics printed by ptc_seq_show() */
 static char *stat_description[] = {
@@ -1700,18 +1699,8 @@ static int __init uv_ptc_init(void)
        }
 
        tunables_dir = debugfs_create_dir(UV_BAU_TUNABLES_DIR, NULL);
-       if (!tunables_dir) {
-               pr_err("unable to create debugfs directory %s\n",
-                      UV_BAU_TUNABLES_DIR);
-               return -EINVAL;
-       }
-       tunables_file = debugfs_create_file(UV_BAU_TUNABLES_FILE, 0600,
-                                       tunables_dir, NULL, &tunables_fops);
-       if (!tunables_file) {
-               pr_err("unable to create debugfs file %s\n",
-                      UV_BAU_TUNABLES_FILE);
-               return -EINVAL;
-       }
+       debugfs_create_file(UV_BAU_TUNABLES_FILE, 0600, tunables_dir, NULL,
+                           &tunables_fops);
        return 0;
 }
 
index 13da879..5324109 100644 (file)
@@ -9,13 +9,8 @@ static struct dentry *d_xen_debug;
 
 struct dentry * __init xen_init_debugfs(void)
 {
-       if (!d_xen_debug) {
+       if (!d_xen_debug)
                d_xen_debug = debugfs_create_dir("xen", NULL);
-
-               if (!d_xen_debug)
-                       pr_warning("Could not create 'xen' debugfs directory\n");
-       }
-
        return d_xen_debug;
 }
 
index beb44e2..f6e5eee 100644 (file)
@@ -2700,8 +2700,7 @@ struct remap_data {
        struct mmu_update *mmu_update;
 };
 
-static int remap_area_pfn_pte_fn(pte_t *ptep, pgtable_t token,
-                                unsigned long addr, void *data)
+static int remap_area_pfn_pte_fn(pte_t *ptep, unsigned long addr, void *data)
 {
        struct remap_data *rmd = data;
        pte_t pte = pte_mkspecial(mfn_pte(*rmd->pfn, rmd->prot));
index 95ce9b5..0acba2c 100644 (file)
@@ -817,9 +817,6 @@ static int __init xen_p2m_debugfs(void)
 {
        struct dentry *d_xen = xen_init_debugfs();
 
-       if (d_xen == NULL)
-               return -ENOMEM;
-
        d_mmu_debug = debugfs_create_dir("mmu", d_xen);
 
        debugfs_create_file("p2m", 0600, d_mmu_debug, NULL, &p2m_dump_fops);
index 77d81c1..802ee5b 100644 (file)
@@ -58,6 +58,7 @@ static void cpu_bringup(void)
 {
        int cpu;
 
+       cr4_init();
        cpu_init();
        touch_softlockup_watchdog();
        preempt_disable();
index a87f8a3..65f0577 100644 (file)
@@ -163,10 +163,6 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
 
        *handle = phys_to_dma(dev, page_to_phys(page));
 
-       if (attrs & DMA_ATTR_NO_KERNEL_MAPPING) {
-               return page;
-       }
-
 #ifdef CONFIG_MMU
        if (PageHighMem(page)) {
                void *p;
@@ -192,9 +188,7 @@ void arch_dma_free(struct device *dev, size_t size, void *vaddr,
        unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
        struct page *page;
 
-       if (attrs & DMA_ATTR_NO_KERNEL_MAPPING) {
-               page = vaddr;
-       } else if (platform_vaddr_uncached(vaddr)) {
+       if (platform_vaddr_uncached(vaddr)) {
                page = virt_to_page(platform_vaddr_to_cached(vaddr));
        } else {
 #ifdef CONFIG_MMU
index 8c24605..380eb61 100644 (file)
@@ -1009,3 +1009,4 @@ MODULE_DESCRIPTION("Counter with CBC MAC");
 MODULE_ALIAS_CRYPTO("ccm_base");
 MODULE_ALIAS_CRYPTO("rfc4309");
 MODULE_ALIAS_CRYPTO("ccm");
+MODULE_ALIAS_CRYPTO("cbcmac");
index 8159f0a..49b781a 100644 (file)
 
 static const struct acpi_device_id amba_id_list[] = {
        {"ARMH0061", 0}, /* PL061 GPIO Device */
+       {"ARMHC500", 0}, /* ARM CoreSight ETM4x */
+       {"ARMHC501", 0}, /* ARM CoreSight ETR */
+       {"ARMHC502", 0}, /* ARM CoreSight STM */
+       {"ARMHC503", 0}, /* ARM CoreSight Debug */
+       {"ARMHC979", 0}, /* ARM CoreSight TPIU */
+       {"ARMHC97C", 0}, /* ARM CoreSight SoC-400 TMC, SoC-600 ETF/ETB */
+       {"ARMHC98D", 0}, /* ARM CoreSight Dynamic Replicator */
+       {"ARMHC9CA", 0}, /* ARM CoreSight CATU */
+       {"ARMHC9FF", 0}, /* ARM CoreSight Dynamic Funnel */
        {"", 0},
 };
 
index 3984518..d696f16 100644 (file)
@@ -508,10 +508,10 @@ struct hid_uid {
        const char *uid;
 };
 
-static int match_hid_uid(struct device *dev, void *data)
+static int match_hid_uid(struct device *dev, const void *data)
 {
        struct acpi_device *adev = ACPI_COMPANION(dev);
-       struct hid_uid *id = data;
+       const struct hid_uid *id = data;
 
        if (!adev)
                return 0;
index 7def63a..e3974a8 100644 (file)
@@ -725,17 +725,15 @@ bool acpi_dev_found(const char *hid)
 EXPORT_SYMBOL(acpi_dev_found);
 
 struct acpi_dev_match_info {
-       const char *dev_name;
-       struct acpi_device *adev;
        struct acpi_device_id hid[2];
        const char *uid;
        s64 hrv;
 };
 
-static int acpi_dev_match_cb(struct device *dev, void *data)
+static int acpi_dev_match_cb(struct device *dev, const void *data)
 {
        struct acpi_device *adev = to_acpi_device(dev);
-       struct acpi_dev_match_info *match = data;
+       const struct acpi_dev_match_info *match = data;
        unsigned long long hrv;
        acpi_status status;
 
@@ -746,9 +744,6 @@ static int acpi_dev_match_cb(struct device *dev, void *data)
            strcmp(adev->pnp.unique_id, match->uid)))
                return 0;
 
-       match->dev_name = acpi_dev_name(adev);
-       match->adev = adev;
-
        if (match->hrv == -1)
                return 1;
 
@@ -818,7 +813,7 @@ acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv)
        match.hrv = hrv;
 
        dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb);
-       return dev ? match.adev : NULL;
+       return dev ? to_acpi_device(dev) : NULL;
 }
 EXPORT_SYMBOL(acpi_dev_get_first_match_dev);
 
index 3eaa459..aa64eec 100644 (file)
@@ -134,10 +134,10 @@ static inline void gizmo_writel(struct tegra_ahb *ahb, u32 value, u32 offset)
 }
 
 #ifdef CONFIG_TEGRA_IOMMU_SMMU
-static int tegra_ahb_match_by_smmu(struct device *dev, void *data)
+static int tegra_ahb_match_by_smmu(struct device *dev, const void *data)
 {
        struct tegra_ahb *ahb = dev_get_drvdata(dev);
-       struct device_node *dn = data;
+       const struct device_node *dn = data;
 
        return (ahb->dev->of_node == dn) ? 1 : 0;
 }
index bc26b55..38a59a6 100644 (file)
@@ -2059,10 +2059,9 @@ static size_t binder_get_object(struct binder_proc *proc,
 
        read_size = min_t(size_t, sizeof(*object), buffer->data_size - offset);
        if (offset > buffer->data_size || read_size < sizeof(*hdr) ||
-           !IS_ALIGNED(offset, sizeof(u32)))
+           binder_alloc_copy_from_buffer(&proc->alloc, object, buffer,
+                                         offset, read_size))
                return 0;
-       binder_alloc_copy_from_buffer(&proc->alloc, object, buffer,
-                                     offset, read_size);
 
        /* Ok, now see if we read a complete object. */
        hdr = &object->hdr;
@@ -2131,8 +2130,10 @@ static struct binder_buffer_object *binder_validate_ptr(
                return NULL;
 
        buffer_offset = start_offset + sizeof(binder_size_t) * index;
-       binder_alloc_copy_from_buffer(&proc->alloc, &object_offset,
-                                     b, buffer_offset, sizeof(object_offset));
+       if (binder_alloc_copy_from_buffer(&proc->alloc, &object_offset,
+                                         b, buffer_offset,
+                                         sizeof(object_offset)))
+               return NULL;
        object_size = binder_get_object(proc, b, object_offset, object);
        if (!object_size || object->hdr.type != BINDER_TYPE_PTR)
                return NULL;
@@ -2212,10 +2213,12 @@ static bool binder_validate_fixup(struct binder_proc *proc,
                        return false;
                last_min_offset = last_bbo->parent_offset + sizeof(uintptr_t);
                buffer_offset = objects_start_offset +
-                       sizeof(binder_size_t) * last_bbo->parent,
-               binder_alloc_copy_from_buffer(&proc->alloc, &last_obj_offset,
-                                             b, buffer_offset,
-                                             sizeof(last_obj_offset));
+                       sizeof(binder_size_t) * last_bbo->parent;
+               if (binder_alloc_copy_from_buffer(&proc->alloc,
+                                                 &last_obj_offset,
+                                                 b, buffer_offset,
+                                                 sizeof(last_obj_offset)))
+                       return false;
        }
        return (fixup_offset >= last_min_offset);
 }
@@ -2301,15 +2304,15 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
        for (buffer_offset = off_start_offset; buffer_offset < off_end_offset;
             buffer_offset += sizeof(binder_size_t)) {
                struct binder_object_header *hdr;
-               size_t object_size;
+               size_t object_size = 0;
                struct binder_object object;
                binder_size_t object_offset;
 
-               binder_alloc_copy_from_buffer(&proc->alloc, &object_offset,
-                                             buffer, buffer_offset,
-                                             sizeof(object_offset));
-               object_size = binder_get_object(proc, buffer,
-                                               object_offset, &object);
+               if (!binder_alloc_copy_from_buffer(&proc->alloc, &object_offset,
+                                                  buffer, buffer_offset,
+                                                  sizeof(object_offset)))
+                       object_size = binder_get_object(proc, buffer,
+                                                       object_offset, &object);
                if (object_size == 0) {
                        pr_err("transaction release %d bad object at offset %lld, size %zd\n",
                               debug_id, (u64)object_offset, buffer->data_size);
@@ -2432,15 +2435,16 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
                        for (fd_index = 0; fd_index < fda->num_fds;
                             fd_index++) {
                                u32 fd;
+                               int err;
                                binder_size_t offset = fda_offset +
                                        fd_index * sizeof(fd);
 
-                               binder_alloc_copy_from_buffer(&proc->alloc,
-                                                             &fd,
-                                                             buffer,
-                                                             offset,
-                                                             sizeof(fd));
-                               binder_deferred_fd_close(fd);
+                               err = binder_alloc_copy_from_buffer(
+                                               &proc->alloc, &fd, buffer,
+                                               offset, sizeof(fd));
+                               WARN_ON(err);
+                               if (!err)
+                                       binder_deferred_fd_close(fd);
                        }
                } break;
                default:
@@ -2683,11 +2687,12 @@ static int binder_translate_fd_array(struct binder_fd_array_object *fda,
                int ret;
                binder_size_t offset = fda_offset + fdi * sizeof(fd);
 
-               binder_alloc_copy_from_buffer(&target_proc->alloc,
-                                             &fd, t->buffer,
-                                             offset, sizeof(fd));
-               ret = binder_translate_fd(fd, offset, t, thread,
-                                         in_reply_to);
+               ret = binder_alloc_copy_from_buffer(&target_proc->alloc,
+                                                   &fd, t->buffer,
+                                                   offset, sizeof(fd));
+               if (!ret)
+                       ret = binder_translate_fd(fd, offset, t, thread,
+                                                 in_reply_to);
                if (ret < 0)
                        return ret;
        }
@@ -2740,8 +2745,12 @@ static int binder_fixup_parent(struct binder_transaction *t,
        }
        buffer_offset = bp->parent_offset +
                        (uintptr_t)parent->buffer - (uintptr_t)b->user_data;
-       binder_alloc_copy_to_buffer(&target_proc->alloc, b, buffer_offset,
-                                   &bp->buffer, sizeof(bp->buffer));
+       if (binder_alloc_copy_to_buffer(&target_proc->alloc, b, buffer_offset,
+                                       &bp->buffer, sizeof(bp->buffer))) {
+               binder_user_error("%d:%d got transaction with invalid parent offset\n",
+                                 proc->pid, thread->pid);
+               return -EINVAL;
+       }
 
        return 0;
 }
@@ -3160,15 +3169,20 @@ static void binder_transaction(struct binder_proc *proc,
                goto err_binder_alloc_buf_failed;
        }
        if (secctx) {
+               int err;
                size_t buf_offset = ALIGN(tr->data_size, sizeof(void *)) +
                                    ALIGN(tr->offsets_size, sizeof(void *)) +
                                    ALIGN(extra_buffers_size, sizeof(void *)) -
                                    ALIGN(secctx_sz, sizeof(u64));
 
                t->security_ctx = (uintptr_t)t->buffer->user_data + buf_offset;
-               binder_alloc_copy_to_buffer(&target_proc->alloc,
-                                           t->buffer, buf_offset,
-                                           secctx, secctx_sz);
+               err = binder_alloc_copy_to_buffer(&target_proc->alloc,
+                                                 t->buffer, buf_offset,
+                                                 secctx, secctx_sz);
+               if (err) {
+                       t->security_ctx = 0;
+                       WARN_ON(1);
+               }
                security_release_secctx(secctx, secctx_sz);
                secctx = NULL;
        }
@@ -3234,11 +3248,16 @@ static void binder_transaction(struct binder_proc *proc,
                struct binder_object object;
                binder_size_t object_offset;
 
-               binder_alloc_copy_from_buffer(&target_proc->alloc,
-                                             &object_offset,
-                                             t->buffer,
-                                             buffer_offset,
-                                             sizeof(object_offset));
+               if (binder_alloc_copy_from_buffer(&target_proc->alloc,
+                                                 &object_offset,
+                                                 t->buffer,
+                                                 buffer_offset,
+                                                 sizeof(object_offset))) {
+                       return_error = BR_FAILED_REPLY;
+                       return_error_param = -EINVAL;
+                       return_error_line = __LINE__;
+                       goto err_bad_offset;
+               }
                object_size = binder_get_object(target_proc, t->buffer,
                                                object_offset, &object);
                if (object_size == 0 || object_offset < off_min) {
@@ -3262,15 +3281,17 @@ static void binder_transaction(struct binder_proc *proc,
 
                        fp = to_flat_binder_object(hdr);
                        ret = binder_translate_binder(fp, t, thread);
-                       if (ret < 0) {
+
+                       if (ret < 0 ||
+                           binder_alloc_copy_to_buffer(&target_proc->alloc,
+                                                       t->buffer,
+                                                       object_offset,
+                                                       fp, sizeof(*fp))) {
                                return_error = BR_FAILED_REPLY;
                                return_error_param = ret;
                                return_error_line = __LINE__;
                                goto err_translate_failed;
                        }
-                       binder_alloc_copy_to_buffer(&target_proc->alloc,
-                                                   t->buffer, object_offset,
-                                                   fp, sizeof(*fp));
                } break;
                case BINDER_TYPE_HANDLE:
                case BINDER_TYPE_WEAK_HANDLE: {
@@ -3278,15 +3299,16 @@ static void binder_transaction(struct binder_proc *proc,
 
                        fp = to_flat_binder_object(hdr);
                        ret = binder_translate_handle(fp, t, thread);
-                       if (ret < 0) {
+                       if (ret < 0 ||
+                           binder_alloc_copy_to_buffer(&target_proc->alloc,
+                                                       t->buffer,
+                                                       object_offset,
+                                                       fp, sizeof(*fp))) {
                                return_error = BR_FAILED_REPLY;
                                return_error_param = ret;
                                return_error_line = __LINE__;
                                goto err_translate_failed;
                        }
-                       binder_alloc_copy_to_buffer(&target_proc->alloc,
-                                                   t->buffer, object_offset,
-                                                   fp, sizeof(*fp));
                } break;
 
                case BINDER_TYPE_FD: {
@@ -3296,16 +3318,17 @@ static void binder_transaction(struct binder_proc *proc,
                        int ret = binder_translate_fd(fp->fd, fd_offset, t,
                                                      thread, in_reply_to);
 
-                       if (ret < 0) {
+                       fp->pad_binder = 0;
+                       if (ret < 0 ||
+                           binder_alloc_copy_to_buffer(&target_proc->alloc,
+                                                       t->buffer,
+                                                       object_offset,
+                                                       fp, sizeof(*fp))) {
                                return_error = BR_FAILED_REPLY;
                                return_error_param = ret;
                                return_error_line = __LINE__;
                                goto err_translate_failed;
                        }
-                       fp->pad_binder = 0;
-                       binder_alloc_copy_to_buffer(&target_proc->alloc,
-                                                   t->buffer, object_offset,
-                                                   fp, sizeof(*fp));
                } break;
                case BINDER_TYPE_FDA: {
                        struct binder_object ptr_object;
@@ -3393,15 +3416,16 @@ static void binder_transaction(struct binder_proc *proc,
                                                  num_valid,
                                                  last_fixup_obj_off,
                                                  last_fixup_min_off);
-                       if (ret < 0) {
+                       if (ret < 0 ||
+                           binder_alloc_copy_to_buffer(&target_proc->alloc,
+                                                       t->buffer,
+                                                       object_offset,
+                                                       bp, sizeof(*bp))) {
                                return_error = BR_FAILED_REPLY;
                                return_error_param = ret;
                                return_error_line = __LINE__;
                                goto err_translate_failed;
                        }
-                       binder_alloc_copy_to_buffer(&target_proc->alloc,
-                                                   t->buffer, object_offset,
-                                                   bp, sizeof(*bp));
                        last_fixup_obj_off = object_offset;
                        last_fixup_min_off = 0;
                } break;
@@ -4140,20 +4164,27 @@ static int binder_apply_fd_fixups(struct binder_proc *proc,
                trace_binder_transaction_fd_recv(t, fd, fixup->offset);
                fd_install(fd, fixup->file);
                fixup->file = NULL;
-               binder_alloc_copy_to_buffer(&proc->alloc, t->buffer,
-                                           fixup->offset, &fd,
-                                           sizeof(u32));
+               if (binder_alloc_copy_to_buffer(&proc->alloc, t->buffer,
+                                               fixup->offset, &fd,
+                                               sizeof(u32))) {
+                       ret = -EINVAL;
+                       break;
+               }
        }
        list_for_each_entry_safe(fixup, tmp, &t->fd_fixups, fixup_entry) {
                if (fixup->file) {
                        fput(fixup->file);
                } else if (ret) {
                        u32 fd;
-
-                       binder_alloc_copy_from_buffer(&proc->alloc, &fd,
-                                                     t->buffer, fixup->offset,
-                                                     sizeof(fd));
-                       binder_deferred_fd_close(fd);
+                       int err;
+
+                       err = binder_alloc_copy_from_buffer(&proc->alloc, &fd,
+                                                           t->buffer,
+                                                           fixup->offset,
+                                                           sizeof(fd));
+                       WARN_ON(err);
+                       if (!err)
+                               binder_deferred_fd_close(fd);
                }
                list_del(&fixup->fixup_entry);
                kfree(fixup);
@@ -4268,6 +4299,8 @@ retry:
                case BINDER_WORK_TRANSACTION_COMPLETE: {
                        binder_inner_proc_unlock(proc);
                        cmd = BR_TRANSACTION_COMPLETE;
+                       kfree(w);
+                       binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
                        if (put_user(cmd, (uint32_t __user *)ptr))
                                return -EFAULT;
                        ptr += sizeof(uint32_t);
@@ -4276,8 +4309,6 @@ retry:
                        binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE,
                                     "%d:%d BR_TRANSACTION_COMPLETE\n",
                                     proc->pid, thread->pid);
-                       kfree(w);
-                       binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
                } break;
                case BINDER_WORK_NODE: {
                        struct binder_node *node = container_of(w, struct binder_node, work);
index ce5603c..6d79a1b 100644 (file)
@@ -1119,15 +1119,16 @@ binder_alloc_copy_user_to_buffer(struct binder_alloc *alloc,
        return 0;
 }
 
-static void binder_alloc_do_buffer_copy(struct binder_alloc *alloc,
-                                       bool to_buffer,
-                                       struct binder_buffer *buffer,
-                                       binder_size_t buffer_offset,
-                                       void *ptr,
-                                       size_t bytes)
+static int binder_alloc_do_buffer_copy(struct binder_alloc *alloc,
+                                      bool to_buffer,
+                                      struct binder_buffer *buffer,
+                                      binder_size_t buffer_offset,
+                                      void *ptr,
+                                      size_t bytes)
 {
        /* All copies must be 32-bit aligned and 32-bit size */
-       BUG_ON(!check_buffer(alloc, buffer, buffer_offset, bytes));
+       if (!check_buffer(alloc, buffer, buffer_offset, bytes))
+               return -EINVAL;
 
        while (bytes) {
                unsigned long size;
@@ -1155,25 +1156,26 @@ static void binder_alloc_do_buffer_copy(struct binder_alloc *alloc,
                ptr = ptr + size;
                buffer_offset += size;
        }
+       return 0;
 }
 
-void binder_alloc_copy_to_buffer(struct binder_alloc *alloc,
-                                struct binder_buffer *buffer,
-                                binder_size_t buffer_offset,
-                                void *src,
-                                size_t bytes)
+int binder_alloc_copy_to_buffer(struct binder_alloc *alloc,
+                               struct binder_buffer *buffer,
+                               binder_size_t buffer_offset,
+                               void *src,
+                               size_t bytes)
 {
-       binder_alloc_do_buffer_copy(alloc, true, buffer, buffer_offset,
-                                   src, bytes);
+       return binder_alloc_do_buffer_copy(alloc, true, buffer, buffer_offset,
+                                          src, bytes);
 }
 
-void binder_alloc_copy_from_buffer(struct binder_alloc *alloc,
-                                  void *dest,
-                                  struct binder_buffer *buffer,
-                                  binder_size_t buffer_offset,
-                                  size_t bytes)
+int binder_alloc_copy_from_buffer(struct binder_alloc *alloc,
+                                 void *dest,
+                                 struct binder_buffer *buffer,
+                                 binder_size_t buffer_offset,
+                                 size_t bytes)
 {
-       binder_alloc_do_buffer_copy(alloc, false, buffer, buffer_offset,
-                                   dest, bytes);
+       return binder_alloc_do_buffer_copy(alloc, false, buffer, buffer_offset,
+                                          dest, bytes);
 }
 
index 71bfa95..db9c1b9 100644 (file)
@@ -159,17 +159,17 @@ binder_alloc_copy_user_to_buffer(struct binder_alloc *alloc,
                                 const void __user *from,
                                 size_t bytes);
 
-void binder_alloc_copy_to_buffer(struct binder_alloc *alloc,
-                                struct binder_buffer *buffer,
-                                binder_size_t buffer_offset,
-                                void *src,
-                                size_t bytes);
-
-void binder_alloc_copy_from_buffer(struct binder_alloc *alloc,
-                                  void *dest,
-                                  struct binder_buffer *buffer,
-                                  binder_size_t buffer_offset,
-                                  size_t bytes);
+int binder_alloc_copy_to_buffer(struct binder_alloc *alloc,
+                               struct binder_buffer *buffer,
+                               binder_size_t buffer_offset,
+                               void *src,
+                               size_t bytes);
+
+int binder_alloc_copy_from_buffer(struct binder_alloc *alloc,
+                                 void *dest,
+                                 struct binder_buffer *buffer,
+                                 binder_size_t buffer_offset,
+                                 size_t bytes);
 
 #endif /* _LINUX_BINDER_ALLOC_H */
 
index 9b09e31..63c1e76 100644 (file)
@@ -137,7 +137,6 @@ bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu)
                                               sizeof(*raw_capacity),
                                               GFP_KERNEL);
                        if (!raw_capacity) {
-                               pr_err("cpu_capacity: failed to allocate memory for raw capacities\n");
                                cap_parsing_failed = true;
                                return false;
                        }
@@ -217,10 +216,8 @@ static int __init register_cpufreq_notifier(void)
        if (!acpi_disabled || !raw_capacity)
                return -EINVAL;
 
-       if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL)) {
-               pr_err("cpu_capacity: failed to allocate memory for cpus_to_visit\n");
+       if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL))
                return -ENOMEM;
-       }
 
        cpumask_copy(cpus_to_visit, cpu_possible_mask);
 
index 0a58e96..df3cac7 100644 (file)
@@ -323,8 +323,8 @@ EXPORT_SYMBOL_GPL(bus_for_each_dev);
  * return to the caller and not iterate over any more devices.
  */
 struct device *bus_find_device(struct bus_type *bus,
-                              struct device *start, void *data,
-                              int (*match)(struct device *dev, void *data))
+                              struct device *start, const void *data,
+                              int (*match)(struct device *dev, const void *data))
 {
        struct klist_iter i;
        struct device *dev;
@@ -342,7 +342,7 @@ struct device *bus_find_device(struct bus_type *bus,
 }
 EXPORT_SYMBOL_GPL(bus_find_device);
 
-static int match_name(struct device *dev, void *data)
+static int match_name(struct device *dev, const void *data)
 {
        const char *name = data;
 
index 8827c60..8d553c9 100644 (file)
@@ -660,7 +660,8 @@ static int cacheinfo_cpu_pre_down(unsigned int cpu)
 
 static int __init cacheinfo_sysfs_init(void)
 {
-       return cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "base/cacheinfo:online",
+       return cpuhp_setup_state(CPUHP_AP_BASE_CACHEINFO_ONLINE,
+                                "base/cacheinfo:online",
                                 cacheinfo_cpu_online, cacheinfo_cpu_pre_down);
 }
 device_initcall(cacheinfo_sysfs_init);
index b4c6452..da84a73 100644 (file)
@@ -3356,3 +3356,9 @@ void device_set_of_node_from_dev(struct device *dev, const struct device *dev2)
        dev->of_node_reused = true;
 }
 EXPORT_SYMBOL_GPL(device_set_of_node_from_dev);
+
+int device_match_of_node(struct device *dev, const void *np)
+{
+       return dev->of_node == np;
+}
+EXPORT_SYMBOL_GPL(device_match_of_node);
index 0df9b44..994a907 100644 (file)
@@ -235,6 +235,19 @@ static int __init deferred_probe_timeout_setup(char *str)
 }
 __setup("deferred_probe_timeout=", deferred_probe_timeout_setup);
 
+static int __driver_deferred_probe_check_state(struct device *dev)
+{
+       if (!initcalls_done)
+               return -EPROBE_DEFER;
+
+       if (!deferred_probe_timeout) {
+               dev_WARN(dev, "deferred probe timeout, ignoring dependency");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
 /**
  * driver_deferred_probe_check_state() - Check deferred probe state
  * @dev: device to check
@@ -248,14 +261,40 @@ __setup("deferred_probe_timeout=", deferred_probe_timeout_setup);
  */
 int driver_deferred_probe_check_state(struct device *dev)
 {
-       if (initcalls_done) {
-               if (!deferred_probe_timeout) {
-                       dev_WARN(dev, "deferred probe timeout, ignoring dependency");
-                       return -ETIMEDOUT;
-               }
-               dev_warn(dev, "ignoring dependency for device, assuming no driver");
-               return -ENODEV;
-       }
+       int ret;
+
+       ret = __driver_deferred_probe_check_state(dev);
+       if (ret < 0)
+               return ret;
+
+       dev_warn(dev, "ignoring dependency for device, assuming no driver");
+
+       return -ENODEV;
+}
+
+/**
+ * driver_deferred_probe_check_state_continue() - check deferred probe state
+ * @dev: device to check
+ *
+ * Returns -ETIMEDOUT if deferred probe debug timeout has expired, or
+ * -EPROBE_DEFER otherwise.
+ *
+ * Drivers or subsystems can opt-in to calling this function instead of
+ * directly returning -EPROBE_DEFER.
+ *
+ * This is similar to driver_deferred_probe_check_state(), but it allows the
+ * subsystem to keep deferring probe after built-in drivers have had a chance
+ * to probe. One scenario where that is useful is if built-in drivers rely on
+ * resources that are provided by modular drivers.
+ */
+int driver_deferred_probe_check_state_continue(struct device *dev)
+{
+       int ret;
+
+       ret = __driver_deferred_probe_check_state(dev);
+       if (ret < 0)
+               return ret;
+
        return -EPROBE_DEFER;
 }
 
index f7035fc..09f2847 100644 (file)
@@ -133,7 +133,7 @@ static struct bus_type *generic_match_buses[] = {
        NULL,
 };
 
-static int device_fwnode_match(struct device *dev, void *fwnode)
+static int device_fwnode_match(struct device *dev, const void *fwnode)
 {
        return dev_fwnode(dev) == fwnode;
 }
index 857c8f1..4e5ca63 100644 (file)
@@ -73,8 +73,8 @@ EXPORT_SYMBOL_GPL(driver_for_each_device);
  * return to the caller and not iterate over any more devices.
  */
 struct device *driver_find_device(struct device_driver *drv,
-                                 struct device *start, void *data,
-                                 int (*match)(struct device *dev, void *data))
+                                 struct device *start, const void *data,
+                                 int (*match)(struct device *dev, const void *data))
 {
        struct klist_iter i;
        struct device *dev;
index 38f2da6..3f9e274 100644 (file)
@@ -26,6 +26,9 @@ config FW_LOADER
 
 if FW_LOADER
 
+config FW_LOADER_PAGED_BUF
+       bool
+
 config EXTRA_FIRMWARE
        string "Build named firmware blobs into the kernel binary"
        help
@@ -67,6 +70,7 @@ config EXTRA_FIRMWARE_DIR
 
 config FW_LOADER_USER_HELPER
        bool "Enable the firmware sysfs fallback mechanism"
+       select FW_LOADER_PAGED_BUF
        help
          This option enables a sysfs loading facility to enable firmware
          loading to the kernel through userspace as a fallback mechanism
@@ -151,5 +155,19 @@ config FW_LOADER_USER_HELPER_FALLBACK
 
          If you are unsure about this, say N here.
 
+config FW_LOADER_COMPRESS
+       bool "Enable compressed firmware support"
+       select FW_LOADER_PAGED_BUF
+       select XZ_DEC
+       help
+         This option enables the support for loading compressed firmware
+         files. The caller of firmware API receives the decompressed file
+         content. The compressed file is loaded as a fallback, only after
+         loading the raw file failed at first.
+
+         Currently only XZ-compressed files are supported, and they have to
+         be compressed with either none or crc32 integrity check type (pass
+         "-C crc32" option to xz command).
+
 endif # FW_LOADER
 endmenu
index f962488..62ee90b 100644 (file)
@@ -219,20 +219,6 @@ static ssize_t firmware_loading_show(struct device *dev,
        return sprintf(buf, "%d\n", loading);
 }
 
-/* one pages buffer should be mapped/unmapped only once */
-static int map_fw_priv_pages(struct fw_priv *fw_priv)
-{
-       if (!fw_priv->is_paged_buf)
-               return 0;
-
-       vunmap(fw_priv->data);
-       fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0,
-                            PAGE_KERNEL_RO);
-       if (!fw_priv->data)
-               return -ENOMEM;
-       return 0;
-}
-
 /**
  * firmware_loading_store() - set value in the 'loading' control file
  * @dev: device pointer
@@ -254,7 +240,6 @@ static ssize_t firmware_loading_store(struct device *dev,
        struct fw_priv *fw_priv;
        ssize_t written = count;
        int loading = simple_strtol(buf, NULL, 10);
-       int i;
 
        mutex_lock(&fw_lock);
        fw_priv = fw_sysfs->fw_priv;
@@ -265,12 +250,7 @@ static ssize_t firmware_loading_store(struct device *dev,
        case 1:
                /* discarding any previous partial load */
                if (!fw_sysfs_done(fw_priv)) {
-                       for (i = 0; i < fw_priv->nr_pages; i++)
-                               __free_page(fw_priv->pages[i]);
-                       vfree(fw_priv->pages);
-                       fw_priv->pages = NULL;
-                       fw_priv->page_array_size = 0;
-                       fw_priv->nr_pages = 0;
+                       fw_free_paged_buf(fw_priv);
                        fw_state_start(fw_priv);
                }
                break;
@@ -284,7 +264,7 @@ static ssize_t firmware_loading_store(struct device *dev,
                         * see the mapped 'buf->data' once the loading
                         * is completed.
                         * */
-                       rc = map_fw_priv_pages(fw_priv);
+                       rc = fw_map_paged_buf(fw_priv);
                        if (rc)
                                dev_err(dev, "%s: map pages failed\n",
                                        __func__);
@@ -389,40 +369,13 @@ out:
 
 static int fw_realloc_pages(struct fw_sysfs *fw_sysfs, int min_size)
 {
-       struct fw_priv *fw_priv= fw_sysfs->fw_priv;
-       int pages_needed = PAGE_ALIGN(min_size) >> PAGE_SHIFT;
-
-       /* If the array of pages is too small, grow it... */
-       if (fw_priv->page_array_size < pages_needed) {
-               int new_array_size = max(pages_needed,
-                                        fw_priv->page_array_size * 2);
-               struct page **new_pages;
+       int err;
 
-               new_pages = vmalloc(array_size(new_array_size, sizeof(void *)));
-               if (!new_pages) {
-                       fw_load_abort(fw_sysfs);
-                       return -ENOMEM;
-               }
-               memcpy(new_pages, fw_priv->pages,
-                      fw_priv->page_array_size * sizeof(void *));
-               memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) *
-                      (new_array_size - fw_priv->page_array_size));
-               vfree(fw_priv->pages);
-               fw_priv->pages = new_pages;
-               fw_priv->page_array_size = new_array_size;
-       }
-
-       while (fw_priv->nr_pages < pages_needed) {
-               fw_priv->pages[fw_priv->nr_pages] =
-                       alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
-
-               if (!fw_priv->pages[fw_priv->nr_pages]) {
-                       fw_load_abort(fw_sysfs);
-                       return -ENOMEM;
-               }
-               fw_priv->nr_pages++;
-       }
-       return 0;
+       err = fw_grow_paged_buf(fw_sysfs->fw_priv,
+                               PAGE_ALIGN(min_size) >> PAGE_SHIFT);
+       if (err)
+               fw_load_abort(fw_sysfs);
+       return err;
 }
 
 /**
@@ -659,7 +612,7 @@ static bool fw_run_sysfs_fallback(enum fw_opt opt_flags)
        /* Also permit LSMs and IMA to fail firmware sysfs fallback */
        ret = security_kernel_load_data(LOADING_FIRMWARE);
        if (ret < 0)
-               return ret;
+               return false;
 
        return fw_force_sysfs_fallback(opt_flags);
 }
index 4c1395f..7048a41 100644 (file)
@@ -64,12 +64,14 @@ struct fw_priv {
        void *data;
        size_t size;
        size_t allocated_size;
-#ifdef CONFIG_FW_LOADER_USER_HELPER
+#ifdef CONFIG_FW_LOADER_PAGED_BUF
        bool is_paged_buf;
-       bool need_uevent;
        struct page **pages;
        int nr_pages;
        int page_array_size;
+#endif
+#ifdef CONFIG_FW_LOADER_USER_HELPER
+       bool need_uevent;
        struct list_head pending_list;
 #endif
        const char *fw_name;
@@ -133,4 +135,14 @@ static inline void fw_state_done(struct fw_priv *fw_priv)
 int assign_fw(struct firmware *fw, struct device *device,
              enum fw_opt opt_flags);
 
+#ifdef CONFIG_FW_LOADER_PAGED_BUF
+void fw_free_paged_buf(struct fw_priv *fw_priv);
+int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed);
+int fw_map_paged_buf(struct fw_priv *fw_priv);
+#else
+static inline void fw_free_paged_buf(struct fw_priv *fw_priv) {}
+int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed) { return -ENXIO; }
+int fw_map_paged_buf(struct fw_priv *fw_priv) { return -ENXIO; }
+#endif
+
 #endif /* __FIRMWARE_LOADER_H */
index 7eaaf5e..bf44c79 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/syscore_ops.h>
 #include <linux/reboot.h>
 #include <linux/security.h>
+#include <linux/xz.h>
 
 #include <generated/utsrelease.h>
 
@@ -251,15 +252,7 @@ static void __free_fw_priv(struct kref *ref)
        list_del(&fw_priv->list);
        spin_unlock(&fwc->lock);
 
-#ifdef CONFIG_FW_LOADER_USER_HELPER
-       if (fw_priv->is_paged_buf) {
-               int i;
-               vunmap(fw_priv->data);
-               for (i = 0; i < fw_priv->nr_pages; i++)
-                       __free_page(fw_priv->pages[i]);
-               vfree(fw_priv->pages);
-       } else
-#endif
+       fw_free_paged_buf(fw_priv); /* free leftover pages */
        if (!fw_priv->allocated_size)
                vfree(fw_priv->data);
        kfree_const(fw_priv->fw_name);
@@ -274,6 +267,174 @@ static void free_fw_priv(struct fw_priv *fw_priv)
                spin_unlock(&fwc->lock);
 }
 
+#ifdef CONFIG_FW_LOADER_PAGED_BUF
+void fw_free_paged_buf(struct fw_priv *fw_priv)
+{
+       int i;
+
+       if (!fw_priv->pages)
+               return;
+
+       for (i = 0; i < fw_priv->nr_pages; i++)
+               __free_page(fw_priv->pages[i]);
+       kvfree(fw_priv->pages);
+       fw_priv->pages = NULL;
+       fw_priv->page_array_size = 0;
+       fw_priv->nr_pages = 0;
+}
+
+int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed)
+{
+       /* If the array of pages is too small, grow it */
+       if (fw_priv->page_array_size < pages_needed) {
+               int new_array_size = max(pages_needed,
+                                        fw_priv->page_array_size * 2);
+               struct page **new_pages;
+
+               new_pages = kvmalloc_array(new_array_size, sizeof(void *),
+                                          GFP_KERNEL);
+               if (!new_pages)
+                       return -ENOMEM;
+               memcpy(new_pages, fw_priv->pages,
+                      fw_priv->page_array_size * sizeof(void *));
+               memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) *
+                      (new_array_size - fw_priv->page_array_size));
+               kvfree(fw_priv->pages);
+               fw_priv->pages = new_pages;
+               fw_priv->page_array_size = new_array_size;
+       }
+
+       while (fw_priv->nr_pages < pages_needed) {
+               fw_priv->pages[fw_priv->nr_pages] =
+                       alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+
+               if (!fw_priv->pages[fw_priv->nr_pages])
+                       return -ENOMEM;
+               fw_priv->nr_pages++;
+       }
+
+       return 0;
+}
+
+int fw_map_paged_buf(struct fw_priv *fw_priv)
+{
+       /* one pages buffer should be mapped/unmapped only once */
+       if (!fw_priv->pages)
+               return 0;
+
+       vunmap(fw_priv->data);
+       fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0,
+                            PAGE_KERNEL_RO);
+       if (!fw_priv->data)
+               return -ENOMEM;
+
+       /* page table is no longer needed after mapping, let's free */
+       kvfree(fw_priv->pages);
+       fw_priv->pages = NULL;
+
+       return 0;
+}
+#endif
+
+/*
+ * XZ-compressed firmware support
+ */
+#ifdef CONFIG_FW_LOADER_COMPRESS
+/* show an error and return the standard error code */
+static int fw_decompress_xz_error(struct device *dev, enum xz_ret xz_ret)
+{
+       if (xz_ret != XZ_STREAM_END) {
+               dev_warn(dev, "xz decompression failed (xz_ret=%d)\n", xz_ret);
+               return xz_ret == XZ_MEM_ERROR ? -ENOMEM : -EINVAL;
+       }
+       return 0;
+}
+
+/* single-shot decompression onto the pre-allocated buffer */
+static int fw_decompress_xz_single(struct device *dev, struct fw_priv *fw_priv,
+                                  size_t in_size, const void *in_buffer)
+{
+       struct xz_dec *xz_dec;
+       struct xz_buf xz_buf;
+       enum xz_ret xz_ret;
+
+       xz_dec = xz_dec_init(XZ_SINGLE, (u32)-1);
+       if (!xz_dec)
+               return -ENOMEM;
+
+       xz_buf.in_size = in_size;
+       xz_buf.in = in_buffer;
+       xz_buf.in_pos = 0;
+       xz_buf.out_size = fw_priv->allocated_size;
+       xz_buf.out = fw_priv->data;
+       xz_buf.out_pos = 0;
+
+       xz_ret = xz_dec_run(xz_dec, &xz_buf);
+       xz_dec_end(xz_dec);
+
+       fw_priv->size = xz_buf.out_pos;
+       return fw_decompress_xz_error(dev, xz_ret);
+}
+
+/* decompression on paged buffer and map it */
+static int fw_decompress_xz_pages(struct device *dev, struct fw_priv *fw_priv,
+                                 size_t in_size, const void *in_buffer)
+{
+       struct xz_dec *xz_dec;
+       struct xz_buf xz_buf;
+       enum xz_ret xz_ret;
+       struct page *page;
+       int err = 0;
+
+       xz_dec = xz_dec_init(XZ_DYNALLOC, (u32)-1);
+       if (!xz_dec)
+               return -ENOMEM;
+
+       xz_buf.in_size = in_size;
+       xz_buf.in = in_buffer;
+       xz_buf.in_pos = 0;
+
+       fw_priv->is_paged_buf = true;
+       fw_priv->size = 0;
+       do {
+               if (fw_grow_paged_buf(fw_priv, fw_priv->nr_pages + 1)) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+
+               /* decompress onto the new allocated page */
+               page = fw_priv->pages[fw_priv->nr_pages - 1];
+               xz_buf.out = kmap(page);
+               xz_buf.out_pos = 0;
+               xz_buf.out_size = PAGE_SIZE;
+               xz_ret = xz_dec_run(xz_dec, &xz_buf);
+               kunmap(page);
+               fw_priv->size += xz_buf.out_pos;
+               /* partial decompression means either end or error */
+               if (xz_buf.out_pos != PAGE_SIZE)
+                       break;
+       } while (xz_ret == XZ_OK);
+
+       err = fw_decompress_xz_error(dev, xz_ret);
+       if (!err)
+               err = fw_map_paged_buf(fw_priv);
+
+ out:
+       xz_dec_end(xz_dec);
+       return err;
+}
+
+static int fw_decompress_xz(struct device *dev, struct fw_priv *fw_priv,
+                           size_t in_size, const void *in_buffer)
+{
+       /* if the buffer is pre-allocated, we can perform in single-shot mode */
+       if (fw_priv->data)
+               return fw_decompress_xz_single(dev, fw_priv, in_size, in_buffer);
+       else
+               return fw_decompress_xz_pages(dev, fw_priv, in_size, in_buffer);
+}
+#endif /* CONFIG_FW_LOADER_COMPRESS */
+
 /* direct firmware loading support */
 static char fw_path_para[256];
 static const char * const fw_path[] = {
@@ -293,7 +454,12 @@ module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644);
 MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path");
 
 static int
-fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv)
+fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv,
+                          const char *suffix,
+                          int (*decompress)(struct device *dev,
+                                            struct fw_priv *fw_priv,
+                                            size_t in_size,
+                                            const void *in_buffer))
 {
        loff_t size;
        int i, len;
@@ -301,9 +467,11 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv)
        char *path;
        enum kernel_read_file_id id = READING_FIRMWARE;
        size_t msize = INT_MAX;
+       void *buffer = NULL;
 
        /* Already populated data member means we're loading into a buffer */
-       if (fw_priv->data) {
+       if (!decompress && fw_priv->data) {
+               buffer = fw_priv->data;
                id = READING_FIRMWARE_PREALLOC_BUFFER;
                msize = fw_priv->allocated_size;
        }
@@ -317,15 +485,15 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv)
                if (!fw_path[i][0])
                        continue;
 
-               len = snprintf(path, PATH_MAX, "%s/%s",
-                              fw_path[i], fw_priv->fw_name);
+               len = snprintf(path, PATH_MAX, "%s/%s%s",
+                              fw_path[i], fw_priv->fw_name, suffix);
                if (len >= PATH_MAX) {
                        rc = -ENAMETOOLONG;
                        break;
                }
 
                fw_priv->size = 0;
-               rc = kernel_read_file_from_path(path, &fw_priv->data, &size,
+               rc = kernel_read_file_from_path(path, &buffer, &size,
                                                msize, id);
                if (rc) {
                        if (rc != -ENOENT)
@@ -336,8 +504,24 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv)
                                         path);
                        continue;
                }
-               dev_dbg(device, "direct-loading %s\n", fw_priv->fw_name);
-               fw_priv->size = size;
+               if (decompress) {
+                       dev_dbg(device, "f/w decompressing %s\n",
+                               fw_priv->fw_name);
+                       rc = decompress(device, fw_priv, size, buffer);
+                       /* discard the superfluous original content */
+                       vfree(buffer);
+                       buffer = NULL;
+                       if (rc) {
+                               fw_free_paged_buf(fw_priv);
+                               continue;
+                       }
+               } else {
+                       dev_dbg(device, "direct-loading %s\n",
+                               fw_priv->fw_name);
+                       if (!fw_priv->data)
+                               fw_priv->data = buffer;
+                       fw_priv->size = size;
+               }
                fw_state_done(fw_priv);
                break;
        }
@@ -584,7 +768,13 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
        if (ret <= 0) /* error or already assigned */
                goto out;
 
-       ret = fw_get_filesystem_firmware(device, fw->priv);
+       ret = fw_get_filesystem_firmware(device, fw->priv, "", NULL);
+#ifdef CONFIG_FW_LOADER_COMPRESS
+       if (ret == -ENOENT)
+               ret = fw_get_filesystem_firmware(device, fw->priv, ".xz",
+                                                fw_decompress_xz);
+#endif
+
        if (ret) {
                if (!(opt_flags & FW_OPT_NO_WARN))
                        dev_warn(device,
index 8598fcb..aa878fb 100644 (file)
@@ -66,6 +66,7 @@ static DEVICE_ATTR(cpulist, S_IRUGO, node_read_cpulist, NULL);
  * @dev:       Device for this memory access class
  * @list_node: List element in the node's access list
  * @access:    The access class rank
+ * @hmem_attrs: Heterogeneous memory performance attributes
  */
 struct node_access_nodes {
        struct device           dev;
@@ -673,8 +674,8 @@ int register_cpu_under_node(unsigned int cpu, unsigned int nid)
 /**
  * register_memory_node_under_compute_node - link memory node to its compute
  *                                          node for a given access class.
- * @mem_node:  Memory node number
- * @cpu_node:  Cpu  node number
+ * @mem_nid:   Memory node number
+ * @cpu_nid:   Cpu  node number
  * @access:    Access class to register
  *
  * Description:
index 4d17298..7139032 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (c) 2002-3 Patrick Mochel
  * Copyright (c) 2002-3 Open Source Development Labs
  *
- * Please see Documentation/driver-model/platform.txt for more
+ * Please see Documentation/driver-model/platform.rst for more
  * information.
  */
 
index 167e737..e5e5333 100644 (file)
@@ -134,7 +134,7 @@ static int bsr_mmap(struct file *filp, struct vm_area_struct *vma)
        return 0;
 }
 
-static int bsr_open(struct inode * inode, struct file * filp)
+static int bsr_open(struct inode *inode, struct file *filp)
 {
        struct cdev *cdev = inode->i_cdev;
        struct bsr_dev *dev = container_of(cdev, struct bsr_dev, bsr_cdev);
@@ -309,7 +309,8 @@ static int __init bsr_init(void)
                goto out_err_2;
        }
 
-       if ((ret = bsr_create_devs(np)) < 0) {
+       ret = bsr_create_devs(np);
+       if (ret < 0) {
                np = NULL;
                goto out_err_3;
        }
index caac5d2..4bad061 100644 (file)
@@ -132,3 +132,12 @@ config ASPEED_BT_IPMI_BMC
          Provides a driver for the BT (Block Transfer) IPMI interface
          found on Aspeed SOCs (AST2400 and AST2500). The driver
          implements the BMC side of the BT interface.
+
+config IPMB_DEVICE_INTERFACE
+       tristate 'IPMB Interface handler'
+       depends on I2C
+       depends on I2C_SLAVE
+       help
+         Provides a driver for a device (Satellite MC) to
+         receive requests and send responses back to the BMC via
+         the IPMB interface. This module requires I2C support.
index 3f06b20..0822adc 100644 (file)
@@ -26,3 +26,4 @@ obj-$(CONFIG_IPMI_KCS_BMC) += kcs_bmc.o
 obj-$(CONFIG_ASPEED_BT_IPMI_BMC) += bt-bmc.o
 obj-$(CONFIG_ASPEED_KCS_IPMI_BMC) += kcs_bmc_aspeed.o
 obj-$(CONFIG_NPCM7XX_KCS_IPMI_BMC) += kcs_bmc_npcm7xx.o
+obj-$(CONFIG_IPMB_DEVICE_INTERFACE) += ipmb_dev_int.o
diff --git a/drivers/char/ipmi/ipmb_dev_int.c b/drivers/char/ipmi/ipmb_dev_int.c
new file mode 100644 (file)
index 0000000..5720433
--- /dev/null
@@ -0,0 +1,364 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * IPMB driver to receive a request and send a response
+ *
+ * Copyright (C) 2019 Mellanox Techologies, Ltd.
+ *
+ * This was inspired by Brendan Higgins' ipmi-bmc-bt-i2c driver.
+ */
+
+#include <linux/acpi.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+
+#define MAX_MSG_LEN            128
+#define IPMB_REQUEST_LEN_MIN   7
+#define NETFN_RSP_BIT_MASK     0x4
+#define REQUEST_QUEUE_MAX_LEN  256
+
+#define IPMB_MSG_LEN_IDX       0
+#define RQ_SA_8BIT_IDX         1
+#define NETFN_LUN_IDX          2
+
+#define GET_7BIT_ADDR(addr_8bit)       (addr_8bit >> 1)
+#define GET_8BIT_ADDR(addr_7bit)       ((addr_7bit << 1) & 0xff)
+
+#define IPMB_MSG_PAYLOAD_LEN_MAX (MAX_MSG_LEN - IPMB_REQUEST_LEN_MIN - 1)
+
+#define SMBUS_MSG_HEADER_LENGTH        2
+#define SMBUS_MSG_IDX_OFFSET   (SMBUS_MSG_HEADER_LENGTH + 1)
+
+struct ipmb_msg {
+       u8 len;
+       u8 rs_sa;
+       u8 netfn_rs_lun;
+       u8 checksum1;
+       u8 rq_sa;
+       u8 rq_seq_rq_lun;
+       u8 cmd;
+       u8 payload[IPMB_MSG_PAYLOAD_LEN_MAX];
+       /* checksum2 is included in payload */
+} __packed;
+
+struct ipmb_request_elem {
+       struct list_head list;
+       struct ipmb_msg request;
+};
+
+struct ipmb_dev {
+       struct i2c_client *client;
+       struct miscdevice miscdev;
+       struct ipmb_msg request;
+       struct list_head request_queue;
+       atomic_t request_queue_len;
+       size_t msg_idx;
+       spinlock_t lock;
+       wait_queue_head_t wait_queue;
+       struct mutex file_mutex;
+};
+
+static inline struct ipmb_dev *to_ipmb_dev(struct file *file)
+{
+       return container_of(file->private_data, struct ipmb_dev, miscdev);
+}
+
+static ssize_t ipmb_read(struct file *file, char __user *buf, size_t count,
+                       loff_t *ppos)
+{
+       struct ipmb_dev *ipmb_dev = to_ipmb_dev(file);
+       struct ipmb_request_elem *queue_elem;
+       struct ipmb_msg msg;
+       ssize_t ret;
+
+       memset(&msg, 0, sizeof(msg));
+
+       spin_lock_irq(&ipmb_dev->lock);
+
+       while (list_empty(&ipmb_dev->request_queue)) {
+               spin_unlock_irq(&ipmb_dev->lock);
+
+               if (file->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+
+               ret = wait_event_interruptible(ipmb_dev->wait_queue,
+                               !list_empty(&ipmb_dev->request_queue));
+               if (ret)
+                       return ret;
+
+               spin_lock_irq(&ipmb_dev->lock);
+       }
+
+       queue_elem = list_first_entry(&ipmb_dev->request_queue,
+                                       struct ipmb_request_elem, list);
+       memcpy(&msg, &queue_elem->request, sizeof(msg));
+       list_del(&queue_elem->list);
+       kfree(queue_elem);
+       atomic_dec(&ipmb_dev->request_queue_len);
+
+       spin_unlock_irq(&ipmb_dev->lock);
+
+       count = min_t(size_t, count, msg.len + 1);
+       if (copy_to_user(buf, &msg, count))
+               ret = -EFAULT;
+
+       return ret < 0 ? ret : count;
+}
+
+static ssize_t ipmb_write(struct file *file, const char __user *buf,
+                       size_t count, loff_t *ppos)
+{
+       struct ipmb_dev *ipmb_dev = to_ipmb_dev(file);
+       u8 rq_sa, netf_rq_lun, msg_len;
+       union i2c_smbus_data data;
+       u8 msg[MAX_MSG_LEN];
+       ssize_t ret;
+
+       if (count > sizeof(msg))
+               return -EINVAL;
+
+       if (copy_from_user(&msg, buf, count))
+               return -EFAULT;
+
+       if (count < msg[0])
+               return -EINVAL;
+
+       rq_sa = GET_7BIT_ADDR(msg[RQ_SA_8BIT_IDX]);
+       netf_rq_lun = msg[NETFN_LUN_IDX];
+
+       if (!(netf_rq_lun & NETFN_RSP_BIT_MASK))
+               return -EINVAL;
+
+       /*
+        * subtract rq_sa and netf_rq_lun from the length of the msg passed to
+        * i2c_smbus_xfer
+        */
+       msg_len = msg[IPMB_MSG_LEN_IDX] - SMBUS_MSG_HEADER_LENGTH;
+       if (msg_len > I2C_SMBUS_BLOCK_MAX)
+               msg_len = I2C_SMBUS_BLOCK_MAX;
+
+       data.block[0] = msg_len;
+       memcpy(&data.block[1], msg + SMBUS_MSG_IDX_OFFSET, msg_len);
+       ret = i2c_smbus_xfer(ipmb_dev->client->adapter, rq_sa,
+                            ipmb_dev->client->flags,
+                            I2C_SMBUS_WRITE, netf_rq_lun,
+                            I2C_SMBUS_BLOCK_DATA, &data);
+
+       return ret ? : count;
+}
+
+static unsigned int ipmb_poll(struct file *file, poll_table *wait)
+{
+       struct ipmb_dev *ipmb_dev = to_ipmb_dev(file);
+       unsigned int mask = POLLOUT;
+
+       mutex_lock(&ipmb_dev->file_mutex);
+       poll_wait(file, &ipmb_dev->wait_queue, wait);
+
+       if (atomic_read(&ipmb_dev->request_queue_len))
+               mask |= POLLIN;
+       mutex_unlock(&ipmb_dev->file_mutex);
+
+       return mask;
+}
+
+static const struct file_operations ipmb_fops = {
+       .owner  = THIS_MODULE,
+       .read   = ipmb_read,
+       .write  = ipmb_write,
+       .poll   = ipmb_poll,
+};
+
+/* Called with ipmb_dev->lock held. */
+static void ipmb_handle_request(struct ipmb_dev *ipmb_dev)
+{
+       struct ipmb_request_elem *queue_elem;
+
+       if (atomic_read(&ipmb_dev->request_queue_len) >=
+                       REQUEST_QUEUE_MAX_LEN)
+               return;
+
+       queue_elem = kmalloc(sizeof(*queue_elem), GFP_ATOMIC);
+       if (!queue_elem)
+               return;
+
+       memcpy(&queue_elem->request, &ipmb_dev->request,
+               sizeof(struct ipmb_msg));
+       list_add(&queue_elem->list, &ipmb_dev->request_queue);
+       atomic_inc(&ipmb_dev->request_queue_len);
+       wake_up_all(&ipmb_dev->wait_queue);
+}
+
+static u8 ipmb_verify_checksum1(struct ipmb_dev *ipmb_dev, u8 rs_sa)
+{
+       /* The 8 lsb of the sum is 0 when the checksum is valid */
+       return (rs_sa + ipmb_dev->request.netfn_rs_lun +
+               ipmb_dev->request.checksum1);
+}
+
+static bool is_ipmb_request(struct ipmb_dev *ipmb_dev, u8 rs_sa)
+{
+       if (ipmb_dev->msg_idx >= IPMB_REQUEST_LEN_MIN) {
+               if (ipmb_verify_checksum1(ipmb_dev, rs_sa))
+                       return false;
+
+               /*
+                * Check whether this is an IPMB request or
+                * response.
+                * The 6 MSB of netfn_rs_lun are dedicated to the netfn
+                * while the remaining bits are dedicated to the lun.
+                * If the LSB of the netfn is cleared, it is associated
+                * with an IPMB request.
+                * If the LSB of the netfn is set, it is associated with
+                * an IPMB response.
+                */
+               if (!(ipmb_dev->request.netfn_rs_lun & NETFN_RSP_BIT_MASK))
+                       return true;
+       }
+       return false;
+}
+
+/*
+ * The IPMB protocol only supports I2C Writes so there is no need
+ * to support I2C_SLAVE_READ* events.
+ * This i2c callback function only monitors IPMB request messages
+ * and adds them in a queue, so that they can be handled by
+ * receive_ipmb_request.
+ */
+static int ipmb_slave_cb(struct i2c_client *client,
+                       enum i2c_slave_event event, u8 *val)
+{
+       struct ipmb_dev *ipmb_dev = i2c_get_clientdata(client);
+       u8 *buf = (u8 *)&ipmb_dev->request;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ipmb_dev->lock, flags);
+       switch (event) {
+       case I2C_SLAVE_WRITE_REQUESTED:
+               memset(&ipmb_dev->request, 0, sizeof(ipmb_dev->request));
+               ipmb_dev->msg_idx = 0;
+
+               /*
+                * At index 0, ipmb_msg stores the length of msg,
+                * skip it for now.
+                * The len will be populated once the whole
+                * buf is populated.
+                *
+                * The I2C bus driver's responsibility is to pass the
+                * data bytes to the backend driver; it does not
+                * forward the i2c slave address.
+                * Since the first byte in the IPMB message is the
+                * address of the responder, it is the responsibility
+                * of the IPMB driver to format the message properly.
+                * So this driver prepends the address of the responder
+                * to the received i2c data before the request message
+                * is handled in userland.
+                */
+               buf[++ipmb_dev->msg_idx] = GET_8BIT_ADDR(client->addr);
+               break;
+
+       case I2C_SLAVE_WRITE_RECEIVED:
+               if (ipmb_dev->msg_idx >= sizeof(struct ipmb_msg))
+                       break;
+
+               buf[++ipmb_dev->msg_idx] = *val;
+               break;
+
+       case I2C_SLAVE_STOP:
+               ipmb_dev->request.len = ipmb_dev->msg_idx;
+
+               if (is_ipmb_request(ipmb_dev, GET_8BIT_ADDR(client->addr)))
+                       ipmb_handle_request(ipmb_dev);
+               break;
+
+       default:
+               break;
+       }
+       spin_unlock_irqrestore(&ipmb_dev->lock, flags);
+
+       return 0;
+}
+
+static int ipmb_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct ipmb_dev *ipmb_dev;
+       int ret;
+
+       ipmb_dev = devm_kzalloc(&client->dev, sizeof(*ipmb_dev),
+                                       GFP_KERNEL);
+       if (!ipmb_dev)
+               return -ENOMEM;
+
+       spin_lock_init(&ipmb_dev->lock);
+       init_waitqueue_head(&ipmb_dev->wait_queue);
+       atomic_set(&ipmb_dev->request_queue_len, 0);
+       INIT_LIST_HEAD(&ipmb_dev->request_queue);
+
+       mutex_init(&ipmb_dev->file_mutex);
+
+       ipmb_dev->miscdev.minor = MISC_DYNAMIC_MINOR;
+
+       ipmb_dev->miscdev.name = devm_kasprintf(&client->dev, GFP_KERNEL,
+                                               "%s%d", "ipmb-",
+                                               client->adapter->nr);
+       ipmb_dev->miscdev.fops = &ipmb_fops;
+       ipmb_dev->miscdev.parent = &client->dev;
+       ret = misc_register(&ipmb_dev->miscdev);
+       if (ret)
+               return ret;
+
+       ipmb_dev->client = client;
+       i2c_set_clientdata(client, ipmb_dev);
+       ret = i2c_slave_register(client, ipmb_slave_cb);
+       if (ret) {
+               misc_deregister(&ipmb_dev->miscdev);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int ipmb_remove(struct i2c_client *client)
+{
+       struct ipmb_dev *ipmb_dev = i2c_get_clientdata(client);
+
+       i2c_slave_unregister(client);
+       misc_deregister(&ipmb_dev->miscdev);
+
+       return 0;
+}
+
+static const struct i2c_device_id ipmb_id[] = {
+       { "ipmb-dev", 0 },
+       {},
+};
+MODULE_DEVICE_TABLE(i2c, ipmb_id);
+
+static const struct acpi_device_id acpi_ipmb_id[] = {
+       { "IPMB0001", 0 },
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, acpi_ipmb_id);
+
+static struct i2c_driver ipmb_driver = {
+       .driver = {
+               .name = "ipmb-dev",
+               .acpi_match_table = ACPI_PTR(acpi_ipmb_id),
+       },
+       .probe = ipmb_probe,
+       .remove = ipmb_remove,
+       .id_table = ipmb_id,
+};
+module_i2c_driver(ipmb_driver);
+
+MODULE_AUTHOR("Mellanox Technologies");
+MODULE_DESCRIPTION("IPMB driver");
+MODULE_LICENSE("GPL v2");
index 1dc1074..6707659 100644 (file)
@@ -2819,9 +2819,9 @@ static const struct device_type bmc_device_type = {
        .groups         = bmc_dev_attr_groups,
 };
 
-static int __find_bmc_guid(struct device *dev, void *data)
+static int __find_bmc_guid(struct device *dev, const void *data)
 {
-       guid_t *guid = data;
+       const guid_t *guid = data;
        struct bmc_device *bmc;
        int rv;
 
@@ -2857,9 +2857,9 @@ struct prod_dev_id {
        unsigned char device_id;
 };
 
-static int __find_bmc_prod_dev_id(struct device *dev, void *data)
+static int __find_bmc_prod_dev_id(struct device *dev, const void *data)
 {
-       struct prod_dev_id *cid = data;
+       const struct prod_dev_id *cid = data;
        struct bmc_device *bmc;
        int rv;
 
index f124a2d..da5b672 100644 (file)
@@ -71,7 +71,7 @@ enum si_intf_state {
 
 static const char * const si_to_str[] = { "invalid", "kcs", "smic", "bt" };
 
-static int initialized;
+static bool initialized;
 
 /*
  * Indexes into stats[] in smi_info below.
@@ -2124,7 +2124,7 @@ static int __init init_ipmi_si(void)
        }
 
 skip_fallback_noirq:
-       initialized = 1;
+       initialized = true;
        mutex_unlock(&smi_infos_lock);
 
        if (type)
index f2a91c4..22f6c9b 100644 (file)
@@ -19,6 +19,7 @@
 #include "ipmi_si.h"
 #include "ipmi_dmi.h"
 
+static bool platform_registered;
 static bool si_tryplatform = true;
 #ifdef CONFIG_ACPI
 static bool          si_tryacpi = true;
@@ -426,7 +427,7 @@ static int ipmi_remove(struct platform_device *pdev)
        return ipmi_si_remove_by_dev(&pdev->dev);
 }
 
-static int pdev_match_name(struct device *dev, void *data)
+static int pdev_match_name(struct device *dev, const void *data)
 {
        struct platform_device *pdev = to_platform_device(dev);
        const char *name = data;
@@ -443,6 +444,7 @@ void ipmi_remove_platform_device_by_name(char *name)
                struct platform_device *pdev = to_platform_device(dev);
 
                platform_device_unregister(pdev);
+               put_device(dev);
        }
 }
 
@@ -469,9 +471,12 @@ void ipmi_si_platform_init(void)
        int rv = platform_driver_register(&ipmi_platform_driver);
        if (rv)
                pr_err("Unable to register driver: %d\n", rv);
+       else
+               platform_registered = true;
 }
 
 void ipmi_si_platform_shutdown(void)
 {
-       platform_driver_unregister(&ipmi_platform_driver);
+       if (platform_registered)
+               platform_driver_unregister(&ipmi_platform_driver);
 }
index cf8156d..305fa50 100644 (file)
@@ -303,6 +303,7 @@ struct ssif_info {
        ((unsigned int) atomic_read(&(ssif)->stats[SSIF_STAT_ ## stat]))
 
 static bool initialized;
+static bool platform_registered;
 
 static void return_hosed_msg(struct ssif_info *ssif_info,
                             struct ipmi_smi_msg *msg);
@@ -2088,6 +2089,8 @@ static int init_ipmi_ssif(void)
                rv = platform_driver_register(&ipmi_driver);
                if (rv)
                        pr_err("Unable to register driver: %d\n", rv);
+               else
+                       platform_registered = true;
        }
 
        ssif_i2c_driver.address_list = ssif_address_list();
@@ -2111,7 +2114,7 @@ static void cleanup_ipmi_ssif(void)
 
        kfree(ssif_i2c_driver.address_list);
 
-       if (ssif_trydmi)
+       if (ssif_trydmi && platform_registered)
                platform_driver_unregister(&ipmi_driver);
 
        free_ssif_clients();
index 53cfe57..f6a1474 100644 (file)
@@ -226,6 +226,7 @@ int misc_register(struct miscdevice *misc)
        mutex_unlock(&misc_mtx);
        return err;
 }
+EXPORT_SYMBOL(misc_register);
 
 /**
  *     misc_deregister - unregister a miscellaneous device
@@ -249,8 +250,6 @@ void misc_deregister(struct miscdevice *misc)
                clear_bit(i, misc_minors);
        mutex_unlock(&misc_mtx);
 }
-
-EXPORT_SYMBOL(misc_register);
 EXPORT_SYMBOL(misc_deregister);
 
 static char *misc_devnode(struct device *dev, umode_t *mode)
index ab0fb10..d81ae65 100644 (file)
@@ -175,7 +175,7 @@ static const unsigned int r8a77470_crit_mod_clks[] __initconst = {
  *---------------------------------------------------
  * 0  0                20              x80     x78     x50
  * 0  1                26              x60     x60     x56
- * 1  0                Prohibitted setting
+ * 1  0                Prohibited setting
  * 1  1                30              x52     x52     x50
  *
  * *1 :        Table 7.4 indicates VCO output (PLL0 = VCO)
index 7a9bb55..8a30da7 100644 (file)
@@ -32,7 +32,7 @@
 #define NPCM7XX_Tx_INTEN               BIT(29)
 #define NPCM7XX_Tx_COUNTEN             BIT(30)
 #define NPCM7XX_Tx_ONESHOT             0x0
-#define NPCM7XX_Tx_OPER                        GENMASK(3, 27)
+#define NPCM7XX_Tx_OPER                        GENMASK(27, 3)
 #define NPCM7XX_Tx_MIN_PRESCALE                0x1
 #define NPCM7XX_Tx_TDR_MASK_BITS       24
 #define NPCM7XX_Tx_MAX_CNT             0xFFFFFF
index 4fa2931..00b113f 100644 (file)
@@ -833,7 +833,7 @@ static int quad8_action_get(struct counter_device *counter,
        return 0;
 }
 
-const struct counter_ops quad8_ops = {
+static const struct counter_ops quad8_ops = {
        .signal_read = quad8_signal_read,
        .count_read = quad8_count_read,
        .count_write = quad8_count_write,
index c83c887..68a9b73 100644 (file)
@@ -352,5 +352,5 @@ static struct platform_driver ftm_quaddec_driver = {
 module_platform_driver(ftm_quaddec_driver);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kjeld Flarup <kfa@deif.com");
-MODULE_AUTHOR("Patrick Havelange <patrick.havelange@essensium.com");
+MODULE_AUTHOR("Kjeld Flarup <kfa@deif.com>");
+MODULE_AUTHOR("Patrick Havelange <patrick.havelange@essensium.com>");
index 22cc7f6..20a9cb7 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/of_device.h>
 #include <linux/of_dma.h>
 #include <linux/list.h>
+#include <linux/dma/mxs-dma.h>
 
 #include <asm/irq.h>
 
@@ -77,6 +78,7 @@
 #define BM_CCW_COMMAND         (3 << 0)
 #define CCW_CHAIN              (1 << 2)
 #define CCW_IRQ                        (1 << 3)
+#define CCW_WAIT4RDY           (1 << 5)
 #define CCW_DEC_SEM            (1 << 6)
 #define CCW_WAIT4END           (1 << 7)
 #define CCW_HALT_ON_TERM       (1 << 8)
@@ -477,16 +479,16 @@ static void mxs_dma_free_chan_resources(struct dma_chan *chan)
  *            ......
  *            ->device_prep_slave_sg(0);
  *            ......
- *            ->device_prep_slave_sg(DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ *            ->device_prep_slave_sg(DMA_CTRL_ACK);
  *            ......
  *    [3] If there are more than two DMA commands in the DMA chain, the code
  *        should be:
  *            ......
  *            ->device_prep_slave_sg(0);                                // First
  *            ......
- *            ->device_prep_slave_sg(DMA_PREP_INTERRUPT [| DMA_CTRL_ACK]);
+ *            ->device_prep_slave_sg(DMA_CTRL_ACK]);
  *            ......
- *            ->device_prep_slave_sg(DMA_PREP_INTERRUPT | DMA_CTRL_ACK); // Last
+ *            ->device_prep_slave_sg(DMA_CTRL_ACK); // Last
  *            ......
  */
 static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
@@ -500,13 +502,12 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
        struct scatterlist *sg;
        u32 i, j;
        u32 *pio;
-       bool append = flags & DMA_PREP_INTERRUPT;
-       int idx = append ? mxs_chan->desc_count : 0;
+       int idx = 0;
 
-       if (mxs_chan->status == DMA_IN_PROGRESS && !append)
-               return NULL;
+       if (mxs_chan->status == DMA_IN_PROGRESS)
+               idx = mxs_chan->desc_count;
 
-       if (sg_len + (append ? idx : 0) > NUM_CCW) {
+       if (sg_len + idx > NUM_CCW) {
                dev_err(mxs_dma->dma_device.dev,
                                "maximum number of sg exceeded: %d > %d\n",
                                sg_len, NUM_CCW);
@@ -520,7 +521,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
         * If the sg is prepared with append flag set, the sg
         * will be appended to the last prepared sg.
         */
-       if (append) {
+       if (idx) {
                BUG_ON(idx < 1);
                ccw = &mxs_chan->ccw[idx - 1];
                ccw->next = mxs_chan->ccw_phys + sizeof(*ccw) * idx;
@@ -541,12 +542,14 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
                ccw->bits = 0;
                ccw->bits |= CCW_IRQ;
                ccw->bits |= CCW_DEC_SEM;
-               if (flags & DMA_CTRL_ACK)
+               if (flags & MXS_DMA_CTRL_WAIT4END)
                        ccw->bits |= CCW_WAIT4END;
                ccw->bits |= CCW_HALT_ON_TERM;
                ccw->bits |= CCW_TERM_FLUSH;
                ccw->bits |= BF_CCW(sg_len, PIO_NUM);
                ccw->bits |= BF_CCW(MXS_DMA_CMD_NO_XFER, COMMAND);
+               if (flags & MXS_DMA_CTRL_WAIT4RDY)
+                       ccw->bits |= CCW_WAIT4RDY;
        } else {
                for_each_sg(sgl, sg, sg_len, i) {
                        if (sg_dma_len(sg) > MAX_XFER_BYTES) {
@@ -573,7 +576,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
                                ccw->bits &= ~CCW_CHAIN;
                                ccw->bits |= CCW_IRQ;
                                ccw->bits |= CCW_DEC_SEM;
-                               if (flags & DMA_CTRL_ACK)
+                               if (flags & MXS_DMA_CTRL_WAIT4END)
                                        ccw->bits |= CCW_WAIT4END;
                        }
                }
index 6f5af41..fa18044 100644 (file)
@@ -37,6 +37,18 @@ config EXTCON_AXP288
          Say Y here to enable support for USB peripheral detection
          and USB MUX switching by X-Power AXP288 PMIC.
 
+config EXTCON_FSA9480
+       tristate "FSA9480 EXTCON Support"
+       depends on INPUT && I2C
+       select IRQ_DOMAIN
+       select REGMAP_I2C
+       help
+         If you say yes here you get support for the Fairchild Semiconductor
+         FSA9480 microUSB switch and accessory detector chip. The FSA9480 is a USB
+         port accessory detector and switch. The FSA9480 is fully controlled using
+         I2C and enables USB data, stereo and mono audio, video, microphone
+         and UART data to use a common connector port.
+
 config EXTCON_GPIO
        tristate "GPIO extcon support"
        depends on GPIOLIB || COMPILE_TEST
index d3941a7..52096fd 100644 (file)
@@ -8,6 +8,7 @@ extcon-core-objs                += extcon.o devres.o
 obj-$(CONFIG_EXTCON_ADC_JACK)  += extcon-adc-jack.o
 obj-$(CONFIG_EXTCON_ARIZONA)   += extcon-arizona.o
 obj-$(CONFIG_EXTCON_AXP288)    += extcon-axp288.o
+obj-$(CONFIG_EXTCON_FSA9480)   += extcon-fsa9480.o
 obj-$(CONFIG_EXTCON_GPIO)      += extcon-gpio.o
 obj-$(CONFIG_EXTCON_INTEL_INT3496) += extcon-intel-int3496.o
 obj-$(CONFIG_EXTCON_INTEL_CHT_WC) += extcon-intel-cht-wc.o
index bb64347..7e9f4c9 100644 (file)
@@ -326,10 +326,12 @@ static void arizona_start_mic(struct arizona_extcon_info *info)
 
        arizona_extcon_pulse_micbias(info);
 
-       regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
-                                ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
-                                &change);
-       if (!change) {
+       ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
+                                      ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
+                                      &change);
+       if (ret < 0) {
+               dev_err(arizona->dev, "Failed to enable micd: %d\n", ret);
+       } else if (!change) {
                regulator_disable(info->micvdd);
                pm_runtime_put_autosuspend(info->dev);
        }
@@ -341,12 +343,14 @@ static void arizona_stop_mic(struct arizona_extcon_info *info)
        const char *widget = arizona_extcon_get_micbias(info);
        struct snd_soc_dapm_context *dapm = arizona->dapm;
        struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
-       bool change;
+       bool change = false;
        int ret;
 
-       regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
-                                ARIZONA_MICD_ENA, 0,
-                                &change);
+       ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
+                                      ARIZONA_MICD_ENA, 0,
+                                      &change);
+       if (ret < 0)
+               dev_err(arizona->dev, "Failed to disable micd: %d\n", ret);
 
        ret = snd_soc_component_disable_pin(component, widget);
        if (ret != 0)
@@ -1718,12 +1722,15 @@ static int arizona_extcon_remove(struct platform_device *pdev)
        struct arizona *arizona = info->arizona;
        int jack_irq_rise, jack_irq_fall;
        bool change;
+       int ret;
 
-       regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
-                                ARIZONA_MICD_ENA, 0,
-                                &change);
-
-       if (change) {
+       ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
+                                      ARIZONA_MICD_ENA, 0,
+                                      &change);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to disable micd on remove: %d\n",
+                       ret);
+       } else if (change) {
                regulator_disable(info->micvdd);
                pm_runtime_put(info->dev);
        }
diff --git a/drivers/extcon/extcon-fsa9480.c b/drivers/extcon/extcon-fsa9480.c
new file mode 100644 (file)
index 0000000..350fb34
--- /dev/null
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * extcon-fsa9480.c - Fairchild Semiconductor FSA9480 extcon driver
+ *
+ * Copyright (c) 2019 Tomasz Figa <tomasz.figa@gmail.com>
+ *
+ * Loosely based on old fsa9480 misc-device driver.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/kobject.h>
+#include <linux/extcon-provider.h>
+#include <linux/irqdomain.h>
+#include <linux/regmap.h>
+
+/* FSA9480 I2C registers */
+#define FSA9480_REG_DEVID               0x01
+#define FSA9480_REG_CTRL                0x02
+#define FSA9480_REG_INT1                0x03
+#define FSA9480_REG_INT2                0x04
+#define FSA9480_REG_INT1_MASK           0x05
+#define FSA9480_REG_INT2_MASK           0x06
+#define FSA9480_REG_ADC                 0x07
+#define FSA9480_REG_TIMING1             0x08
+#define FSA9480_REG_TIMING2             0x09
+#define FSA9480_REG_DEV_T1              0x0a
+#define FSA9480_REG_DEV_T2              0x0b
+#define FSA9480_REG_BTN1                0x0c
+#define FSA9480_REG_BTN2                0x0d
+#define FSA9480_REG_CK                  0x0e
+#define FSA9480_REG_CK_INT1             0x0f
+#define FSA9480_REG_CK_INT2             0x10
+#define FSA9480_REG_CK_INTMASK1         0x11
+#define FSA9480_REG_CK_INTMASK2         0x12
+#define FSA9480_REG_MANSW1              0x13
+#define FSA9480_REG_MANSW2              0x14
+#define FSA9480_REG_END                 0x15
+
+/* Control */
+#define CON_SWITCH_OPEN         (1 << 4)
+#define CON_RAW_DATA            (1 << 3)
+#define CON_MANUAL_SW           (1 << 2)
+#define CON_WAIT                (1 << 1)
+#define CON_INT_MASK            (1 << 0)
+#define CON_MASK                (CON_SWITCH_OPEN | CON_RAW_DATA | \
+                                CON_MANUAL_SW | CON_WAIT)
+
+/* Device Type 1 */
+#define DEV_USB_OTG             7
+#define DEV_DEDICATED_CHG       6
+#define DEV_USB_CHG             5
+#define DEV_CAR_KIT             4
+#define DEV_UART                3
+#define DEV_USB                 2
+#define DEV_AUDIO_2             1
+#define DEV_AUDIO_1             0
+
+#define DEV_T1_USB_MASK         (DEV_USB_OTG | DEV_USB)
+#define DEV_T1_UART_MASK        (DEV_UART)
+#define DEV_T1_CHARGER_MASK     (DEV_DEDICATED_CHG | DEV_USB_CHG)
+
+/* Device Type 2 */
+#define DEV_AV                  14
+#define DEV_TTY                 13
+#define DEV_PPD                 12
+#define DEV_JIG_UART_OFF        11
+#define DEV_JIG_UART_ON         10
+#define DEV_JIG_USB_OFF         9
+#define DEV_JIG_USB_ON          8
+
+#define DEV_T2_USB_MASK         (DEV_JIG_USB_OFF | DEV_JIG_USB_ON)
+#define DEV_T2_UART_MASK        (DEV_JIG_UART_OFF | DEV_JIG_UART_ON)
+#define DEV_T2_JIG_MASK         (DEV_JIG_USB_OFF | DEV_JIG_USB_ON | \
+                                DEV_JIG_UART_OFF | DEV_JIG_UART_ON)
+
+/*
+ * Manual Switch
+ * D- [7:5] / D+ [4:2]
+ * 000: Open all / 001: USB / 010: AUDIO / 011: UART / 100: V_AUDIO
+ */
+#define SW_VAUDIO               ((4 << 5) | (4 << 2))
+#define SW_UART                 ((3 << 5) | (3 << 2))
+#define SW_AUDIO                ((2 << 5) | (2 << 2))
+#define SW_DHOST                ((1 << 5) | (1 << 2))
+#define SW_AUTO                 ((0 << 5) | (0 << 2))
+
+/* Interrupt 1 */
+#define INT1_MASK               (0xff << 0)
+#define INT_DETACH              (1 << 1)
+#define INT_ATTACH              (1 << 0)
+
+/* Interrupt 2 mask */
+#define INT2_MASK               (0x1f << 0)
+
+/* Timing Set 1 */
+#define TIMING1_ADC_500MS       (0x6 << 0)
+
+struct fsa9480_usbsw {
+       struct device *dev;
+       struct regmap *regmap;
+       struct extcon_dev *edev;
+       u16 cable;
+};
+
+static const unsigned int fsa9480_extcon_cable[] = {
+       EXTCON_USB_HOST,
+       EXTCON_USB,
+       EXTCON_CHG_USB_DCP,
+       EXTCON_CHG_USB_SDP,
+       EXTCON_CHG_USB_ACA,
+       EXTCON_JACK_LINE_OUT,
+       EXTCON_JACK_VIDEO_OUT,
+       EXTCON_JIG,
+
+       EXTCON_NONE,
+};
+
+static const u64 cable_types[] = {
+       [DEV_USB_OTG] = BIT_ULL(EXTCON_USB_HOST),
+       [DEV_DEDICATED_CHG] = BIT_ULL(EXTCON_USB) | BIT_ULL(EXTCON_CHG_USB_DCP),
+       [DEV_USB_CHG] = BIT_ULL(EXTCON_USB) | BIT_ULL(EXTCON_CHG_USB_SDP),
+       [DEV_CAR_KIT] = BIT_ULL(EXTCON_USB) | BIT_ULL(EXTCON_CHG_USB_SDP)
+                       | BIT_ULL(EXTCON_JACK_LINE_OUT),
+       [DEV_UART] = BIT_ULL(EXTCON_JIG),
+       [DEV_USB] = BIT_ULL(EXTCON_USB) | BIT_ULL(EXTCON_CHG_USB_SDP),
+       [DEV_AUDIO_2] = BIT_ULL(EXTCON_JACK_LINE_OUT),
+       [DEV_AUDIO_1] = BIT_ULL(EXTCON_JACK_LINE_OUT),
+       [DEV_AV] = BIT_ULL(EXTCON_JACK_LINE_OUT)
+                  | BIT_ULL(EXTCON_JACK_VIDEO_OUT),
+       [DEV_TTY] = BIT_ULL(EXTCON_JIG),
+       [DEV_PPD] = BIT_ULL(EXTCON_JACK_LINE_OUT) | BIT_ULL(EXTCON_CHG_USB_ACA),
+       [DEV_JIG_UART_OFF] = BIT_ULL(EXTCON_JIG),
+       [DEV_JIG_UART_ON] = BIT_ULL(EXTCON_JIG),
+       [DEV_JIG_USB_OFF] = BIT_ULL(EXTCON_USB) | BIT_ULL(EXTCON_JIG),
+       [DEV_JIG_USB_ON] = BIT_ULL(EXTCON_USB) | BIT_ULL(EXTCON_JIG),
+};
+
+/* Define regmap configuration of FSA9480 for I2C communication  */
+static bool fsa9480_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case FSA9480_REG_INT1_MASK:
+               return true;
+       default:
+               break;
+       }
+       return false;
+}
+
+static const struct regmap_config fsa9480_regmap_config = {
+       .reg_bits       = 8,
+       .val_bits       = 8,
+       .volatile_reg   = fsa9480_volatile_reg,
+       .max_register   = FSA9480_REG_END,
+};
+
+static int fsa9480_write_reg(struct fsa9480_usbsw *usbsw, int reg, int value)
+{
+       int ret;
+
+       ret = regmap_write(usbsw->regmap, reg, value);
+       if (ret < 0)
+               dev_err(usbsw->dev, "%s: err %d\n", __func__, ret);
+
+       return ret;
+}
+
+static int fsa9480_read_reg(struct fsa9480_usbsw *usbsw, int reg)
+{
+       int ret, val;
+
+       ret = regmap_read(usbsw->regmap, reg, &val);
+       if (ret < 0) {
+               dev_err(usbsw->dev, "%s: err %d\n", __func__, ret);
+               return ret;
+       }
+
+       return val;
+}
+
+static int fsa9480_read_irq(struct fsa9480_usbsw *usbsw, int *value)
+{
+       u8 regs[2];
+       int ret;
+
+       ret = regmap_bulk_read(usbsw->regmap, FSA9480_REG_INT1, regs, 2);
+       if (ret < 0)
+               dev_err(usbsw->dev, "%s: err %d\n", __func__, ret);
+
+       *value = regs[1] << 8 | regs[0];
+       return ret;
+}
+
+static void fsa9480_handle_change(struct fsa9480_usbsw *usbsw,
+                                 u16 mask, bool attached)
+{
+       while (mask) {
+               int dev = fls64(mask) - 1;
+               u64 cables = cable_types[dev];
+
+               while (cables) {
+                       int cable = fls64(cables) - 1;
+
+                       extcon_set_state_sync(usbsw->edev, cable, attached);
+                       cables &= ~BIT_ULL(cable);
+               }
+
+               mask &= ~BIT_ULL(dev);
+       }
+}
+
+static void fsa9480_detect_dev(struct fsa9480_usbsw *usbsw)
+{
+       int val1, val2;
+       u16 val;
+
+       val1 = fsa9480_read_reg(usbsw, FSA9480_REG_DEV_T1);
+       val2 = fsa9480_read_reg(usbsw, FSA9480_REG_DEV_T2);
+       if (val1 < 0 || val2 < 0) {
+               dev_err(usbsw->dev, "%s: failed to read registers", __func__);
+               return;
+       }
+       val = val2 << 8 | val1;
+
+       dev_info(usbsw->dev, "dev1: 0x%x, dev2: 0x%x\n", val1, val2);
+
+       /* handle detached cables first */
+       fsa9480_handle_change(usbsw, usbsw->cable & ~val, false);
+
+       /* then handle attached ones */
+       fsa9480_handle_change(usbsw, val & ~usbsw->cable, true);
+
+       usbsw->cable = val;
+}
+
+static irqreturn_t fsa9480_irq_handler(int irq, void *data)
+{
+       struct fsa9480_usbsw *usbsw = data;
+       int intr = 0;
+
+       /* clear interrupt */
+       fsa9480_read_irq(usbsw, &intr);
+       if (!intr)
+               return IRQ_NONE;
+
+       /* device detection */
+       fsa9480_detect_dev(usbsw);
+
+       return IRQ_HANDLED;
+}
+
+static int fsa9480_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct fsa9480_usbsw *info;
+       int ret;
+
+       if (!client->irq) {
+               dev_err(&client->dev, "no interrupt provided\n");
+               return -EINVAL;
+       }
+
+       info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+       info->dev = &client->dev;
+
+       i2c_set_clientdata(client, info);
+
+       /* External connector */
+       info->edev = devm_extcon_dev_allocate(info->dev,
+                                             fsa9480_extcon_cable);
+       if (IS_ERR(info->edev)) {
+               dev_err(info->dev, "failed to allocate memory for extcon\n");
+               ret = -ENOMEM;
+               return ret;
+       }
+
+       ret = devm_extcon_dev_register(info->dev, info->edev);
+       if (ret) {
+               dev_err(info->dev, "failed to register extcon device\n");
+               return ret;
+       }
+
+       info->regmap = devm_regmap_init_i2c(client, &fsa9480_regmap_config);
+       if (IS_ERR(info->regmap)) {
+               ret = PTR_ERR(info->regmap);
+               dev_err(info->dev, "failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       /* ADC Detect Time: 500ms */
+       fsa9480_write_reg(info, FSA9480_REG_TIMING1, TIMING1_ADC_500MS);
+
+       /* configure automatic switching */
+       fsa9480_write_reg(info, FSA9480_REG_CTRL, CON_MASK);
+
+       /* unmask interrupt (attach/detach only) */
+       fsa9480_write_reg(info, FSA9480_REG_INT1_MASK,
+                         INT1_MASK & ~(INT_ATTACH | INT_DETACH));
+       fsa9480_write_reg(info, FSA9480_REG_INT2_MASK, INT2_MASK);
+
+       ret = devm_request_threaded_irq(info->dev, client->irq, NULL,
+                                       fsa9480_irq_handler,
+                                       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                       "fsa9480", info);
+       if (ret) {
+               dev_err(info->dev, "failed to request IRQ\n");
+               return ret;
+       }
+
+       device_init_wakeup(info->dev, true);
+       fsa9480_detect_dev(info);
+
+       return 0;
+}
+
+static int fsa9480_remove(struct i2c_client *client)
+{
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int fsa9480_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       if (device_may_wakeup(&client->dev) && client->irq)
+               enable_irq_wake(client->irq);
+
+       return 0;
+}
+
+static int fsa9480_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       if (device_may_wakeup(&client->dev) && client->irq)
+               disable_irq_wake(client->irq);
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops fsa9480_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(fsa9480_suspend, fsa9480_resume)
+};
+
+static const struct i2c_device_id fsa9480_id[] = {
+       { "fsa9480", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, fsa9480_id);
+
+static const struct of_device_id fsa9480_of_match[] = {
+       { .compatible = "fcs,fsa9480", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, fsa9480_of_match);
+
+static struct i2c_driver fsa9480_i2c_driver = {
+       .driver                 = {
+               .name           = "fsa9480",
+               .pm             = &fsa9480_pm_ops,
+               .of_match_table = fsa9480_of_match,
+       },
+       .probe                  = fsa9480_probe,
+       .remove                 = fsa9480_remove,
+       .id_table               = fsa9480_id,
+};
+
+static int __init fsa9480_module_init(void)
+{
+       return i2c_add_driver(&fsa9480_i2c_driver);
+}
+subsys_initcall(fsa9480_module_init);
+
+static void __exit fsa9480_module_exit(void)
+{
+       i2c_del_driver(&fsa9480_i2c_driver);
+}
+module_exit(fsa9480_module_exit);
+
+MODULE_DESCRIPTION("Fairchild Semiconductor FSA9480 extcon driver");
+MODULE_AUTHOR("Tomasz Figa <tomasz.figa@gmail.com>");
+MODULE_LICENSE("GPL");
index 937a930..44fd4f9 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * System Control and Management Interface (SCMI) Message Protocol
  * driver common header file containing some definitions, structures
index 85ec99f..2012338 100644 (file)
@@ -17,9 +17,9 @@ struct acpi_hid_uid {
        char uid[11]; /* UINT_MAX + null byte */
 };
 
-static int __init match_acpi_dev(struct device *dev, void *data)
+static int __init match_acpi_dev(struct device *dev, const void *data)
 {
-       struct acpi_hid_uid hid_uid = *(struct acpi_hid_uid *)data;
+       struct acpi_hid_uid hid_uid = *(const struct acpi_hid_uid *)data;
        struct acpi_device *adev = to_acpi_device(dev);
 
        if (acpi_match_device_ids(adev, hid_uid.hid))
index 1f63b30..7b7b4a6 100644 (file)
@@ -12,7 +12,7 @@
 #ifndef __COREBOOT_TABLE_H
 #define __COREBOOT_TABLE_H
 
-#include <linux/io.h>
+#include <linux/device.h>
 
 /* Coreboot table header structure */
 struct coreboot_table_header {
@@ -83,4 +83,13 @@ int coreboot_driver_register(struct coreboot_driver *driver);
 /* Unregister a driver that uses the data from a coreboot table. */
 void coreboot_driver_unregister(struct coreboot_driver *driver);
 
+/* module_coreboot_driver() - Helper macro for drivers that don't do
+ * anything special in module init/exit.  This eliminates a lot of
+ * boilerplate.  Each module may only use this macro once, and
+ * calling it replaces module_init() and module_exit()
+ */
+#define module_coreboot_driver(__coreboot_driver) \
+       module_driver(__coreboot_driver, coreboot_driver_register, \
+                       coreboot_driver_unregister)
+
 #endif /* __COREBOOT_TABLE_H */
index 7e67b65..916f26a 100644 (file)
@@ -89,19 +89,7 @@ static struct coreboot_driver framebuffer_driver = {
        },
        .tag = CB_TAG_FRAMEBUFFER,
 };
-
-static int __init coreboot_framebuffer_init(void)
-{
-       return coreboot_driver_register(&framebuffer_driver);
-}
-
-static void coreboot_framebuffer_exit(void)
-{
-       coreboot_driver_unregister(&framebuffer_driver);
-}
-
-module_init(coreboot_framebuffer_init);
-module_exit(coreboot_framebuffer_exit);
+module_coreboot_driver(framebuffer_driver);
 
 MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
 MODULE_LICENSE("GPL");
index ac90e85..fd7f0fb 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 
@@ -26,7 +27,7 @@ struct cbmem_cons {
 #define CURSOR_MASK ((1 << 28) - 1)
 #define OVERFLOW (1 << 31)
 
-static struct cbmem_cons __iomem *cbmem_console;
+static struct cbmem_cons *cbmem_console;
 static u32 cbmem_console_size;
 
 /*
@@ -67,7 +68,7 @@ static ssize_t memconsole_coreboot_read(char *buf, loff_t pos, size_t count)
 
 static int memconsole_probe(struct coreboot_device *dev)
 {
-       struct cbmem_cons __iomem *tmp_cbmc;
+       struct cbmem_cons *tmp_cbmc;
 
        tmp_cbmc = memremap(dev->cbmem_ref.cbmem_addr,
                            sizeof(*tmp_cbmc), MEMREMAP_WB);
@@ -77,13 +78,13 @@ static int memconsole_probe(struct coreboot_device *dev)
 
        /* Read size only once to prevent overrun attack through /dev/mem. */
        cbmem_console_size = tmp_cbmc->size_dont_access_after_boot;
-       cbmem_console = memremap(dev->cbmem_ref.cbmem_addr,
+       cbmem_console = devm_memremap(&dev->dev, dev->cbmem_ref.cbmem_addr,
                                 cbmem_console_size + sizeof(*cbmem_console),
                                 MEMREMAP_WB);
        memunmap(tmp_cbmc);
 
-       if (!cbmem_console)
-               return -ENOMEM;
+       if (IS_ERR(cbmem_console))
+               return PTR_ERR(cbmem_console);
 
        memconsole_setup(memconsole_coreboot_read);
 
@@ -94,9 +95,6 @@ static int memconsole_remove(struct coreboot_device *dev)
 {
        memconsole_exit();
 
-       if (cbmem_console)
-               memunmap(cbmem_console);
-
        return 0;
 }
 
@@ -108,19 +106,7 @@ static struct coreboot_driver memconsole_driver = {
        },
        .tag = CB_TAG_CBMEM_CONSOLE,
 };
-
-static void coreboot_memconsole_exit(void)
-{
-       coreboot_driver_unregister(&memconsole_driver);
-}
-
-static int __init coreboot_memconsole_init(void)
-{
-       return coreboot_driver_register(&memconsole_driver);
-}
-
-module_exit(coreboot_memconsole_exit);
-module_init(coreboot_memconsole_init);
+module_coreboot_driver(memconsole_driver);
 
 MODULE_AUTHOR("Google, Inc.");
 MODULE_LICENSE("GPL");
index fe5aa74..44d314a 100644 (file)
@@ -7,21 +7,22 @@
  * Copyright 2017 Google Inc.
  */
 
-#include <linux/init.h>
 #include <linux/sysfs.h>
 #include <linux/kobject.h>
 #include <linux/module.h>
 
 #include "memconsole.h"
 
-static ssize_t (*memconsole_read_func)(char *, loff_t, size_t);
-
 static ssize_t memconsole_read(struct file *filp, struct kobject *kobp,
                               struct bin_attribute *bin_attr, char *buf,
                               loff_t pos, size_t count)
 {
+       ssize_t (*memconsole_read_func)(char *, loff_t, size_t);
+
+       memconsole_read_func = bin_attr->private;
        if (WARN_ON_ONCE(!memconsole_read_func))
                return -EIO;
+
        return memconsole_read_func(buf, pos, count);
 }
 
@@ -32,7 +33,7 @@ static struct bin_attribute memconsole_bin_attr = {
 
 void memconsole_setup(ssize_t (*read_func)(char *, loff_t, size_t))
 {
-       memconsole_read_func = read_func;
+       memconsole_bin_attr.private = read_func;
 }
 EXPORT_SYMBOL(memconsole_setup);
 
index fd5212c..0739f3b 100644 (file)
@@ -316,19 +316,7 @@ static struct coreboot_driver vpd_driver = {
        },
        .tag = CB_TAG_VPD,
 };
-
-static int __init coreboot_vpd_init(void)
-{
-       return coreboot_driver_register(&vpd_driver);
-}
-
-static void __exit coreboot_vpd_exit(void)
-{
-       coreboot_driver_unregister(&vpd_driver);
-}
-
-module_init(coreboot_vpd_init);
-module_exit(coreboot_vpd_exit);
+module_coreboot_driver(vpd_driver);
 
 MODULE_AUTHOR("Google, Inc.");
 MODULE_LICENSE("GPL");
index c62fa70..92e3258 100644 (file)
@@ -7,8 +7,6 @@
  * Copyright 2017 Google Inc.
  */
 
-#include <linux/export.h>
-
 #include "vpd_decode.h"
 
 static int vpd_decode_len(const s32 max_len, const u8 *in,
index 4983827..adbeeef 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: BSD-3-Clause
+/* SPDX-License-Identifier: BSD-3-Clause */
 /*
  * Texas Instruments System Control Interface (TISCI) Protocol
  *
index 8072c19..474f304 100644 (file)
@@ -26,9 +26,9 @@ config FPGA_MGR_SOCFPGA_A10
          FPGA manager driver support for Altera Arria10 SoCFPGA.
 
 config ALTERA_PR_IP_CORE
-        tristate "Altera Partial Reconfiguration IP Core"
-        help
-          Core driver support for Altera Partial Reconfiguration IP component
+       tristate "Altera Partial Reconfiguration IP Core"
+       help
+         Core driver support for Altera Partial Reconfiguration IP component
 
 config ALTERA_PR_IP_CORE_PLAT
        tristate "Platform support of Altera Partial Reconfiguration IP Core"
index 76f3770..b3f7eee 100644 (file)
@@ -30,8 +30,8 @@
 #define FME_PR_STS             0x10
 #define FME_PR_DATA            0x18
 #define FME_PR_ERR             0x20
-#define FME_PR_INTFC_ID_H      0xA8
-#define FME_PR_INTFC_ID_L      0xB0
+#define FME_PR_INTFC_ID_L      0xA8
+#define FME_PR_INTFC_ID_H      0xB0
 
 /* FME PR Control Register Bitfield */
 #define FME_PR_CTRL_PR_RST     BIT_ULL(0)  /* Reset PR engine */
index d9ca955..3c71dc3 100644 (file)
@@ -74,6 +74,7 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg)
        struct dfl_fme *fme;
        unsigned long minsz;
        void *buf = NULL;
+       size_t length;
        int ret = 0;
        u64 v;
 
@@ -85,9 +86,6 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg)
        if (port_pr.argsz < minsz || port_pr.flags)
                return -EINVAL;
 
-       if (!IS_ALIGNED(port_pr.buffer_size, 4))
-               return -EINVAL;
-
        /* get fme header region */
        fme_hdr = dfl_get_feature_ioaddr_by_id(&pdev->dev,
                                               FME_FEATURE_ID_HEADER);
@@ -103,7 +101,13 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg)
                       port_pr.buffer_size))
                return -EFAULT;
 
-       buf = vmalloc(port_pr.buffer_size);
+       /*
+        * align PR buffer per PR bandwidth, as HW ignores the extra padding
+        * data automatically.
+        */
+       length = ALIGN(port_pr.buffer_size, 4);
+
+       buf = vmalloc(length);
        if (!buf)
                return -ENOMEM;
 
@@ -140,7 +144,7 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg)
        fpga_image_info_free(region->info);
 
        info->buf = buf;
-       info->count = port_pr.buffer_size;
+       info->count = length;
        info->region_id = port_pr.port_id;
        region->info = info;
 
@@ -159,9 +163,6 @@ unlock_exit:
        mutex_unlock(&pdata->lock);
 free_exit:
        vfree(buf);
-       if (copy_to_user((void __user *)arg, &port_pr, minsz))
-               return -EFAULT;
-
        return ret;
 }
 
index 75f64ab..e405309 100644 (file)
@@ -22,11 +22,6 @@ static const struct of_device_id fpga_region_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, fpga_region_of_match);
 
-static int fpga_region_of_node_match(struct device *dev, const void *data)
-{
-       return dev->of_node == data;
-}
-
 /**
  * of_fpga_region_find - find FPGA region
  * @np: device node of FPGA Region
@@ -37,7 +32,7 @@ static int fpga_region_of_node_match(struct device *dev, const void *data)
  */
 static struct fpga_region *of_fpga_region_find(struct device_node *np)
 {
-       return fpga_region_class_find(NULL, np, fpga_region_of_node_match);
+       return fpga_region_class_find(NULL, np, device_match_of_node);
 }
 
 /**
index 712df04..1118eaf 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+/* SPDX-License-Identifier: GPL-2.0+ */
 #ifndef __CF_FSI_FW_H
 #define __CF_FSI_FW_H
 
index 1d83f3b..1f76740 100644 (file)
@@ -1029,6 +1029,14 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
 
        }
 
+       rc = fsi_slave_set_smode(slave);
+       if (rc) {
+               dev_warn(&master->dev,
+                               "can't set smode on slave:%02x:%02x %d\n",
+                               link, id, rc);
+               goto err_free;
+       }
+
        /* Allocate a minor in the FSI space */
        rc = __fsi_get_new_minor(slave, fsi_dev_cfam, &slave->dev.devt,
                                 &slave->cdev_idx);
@@ -1040,17 +1048,14 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
        rc = cdev_device_add(&slave->cdev, &slave->dev);
        if (rc) {
                dev_err(&slave->dev, "Error %d creating slave device\n", rc);
-               goto err_free;
+               goto err_free_ida;
        }
 
-       rc = fsi_slave_set_smode(slave);
-       if (rc) {
-               dev_warn(&master->dev,
-                               "can't set smode on slave:%02x:%02x %d\n",
-                               link, id, rc);
-               kfree(slave);
-               return -ENODEV;
-       }
+       /* Now that we have the cdev registered with the core, any fatal
+        * failures beyond this point will need to clean up through
+        * cdev_device_del(). Fortunately though, nothing past here is fatal.
+        */
+
        if (master->link_config)
                master->link_config(master, link,
                                    slave->t_send_delay,
@@ -1067,10 +1072,13 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
                dev_dbg(&master->dev, "failed during slave scan with: %d\n",
                                rc);
 
-       return rc;
+       return 0;
 
- err_free:
-       put_device(&slave->dev);
+err_free_ida:
+       fsi_free_minor(slave->dev.devt);
+err_free:
+       of_node_put(slave->dev.of_node);
+       kfree(slave);
        return rc;
 }
 
index a2301ce..7da9c81 100644 (file)
@@ -412,6 +412,7 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
                msecs_to_jiffies(OCC_CMD_IN_PRG_WAIT_MS);
        struct occ *occ = dev_get_drvdata(dev);
        struct occ_response *resp = response;
+       u8 seq_no;
        u16 resp_data_length;
        unsigned long start;
        int rc;
@@ -426,6 +427,8 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
 
        mutex_lock(&occ->occ_lock);
 
+       /* Extract the seq_no from the command (first byte) */
+       seq_no = *(const u8 *)request;
        rc = occ_putsram(occ, OCC_SRAM_CMD_ADDR, request, req_len);
        if (rc)
                goto done;
@@ -441,11 +444,17 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
                if (rc)
                        goto done;
 
-               if (resp->return_status == OCC_RESP_CMD_IN_PRG) {
+               if (resp->return_status == OCC_RESP_CMD_IN_PRG ||
+                   resp->seq_no != seq_no) {
                        rc = -ETIMEDOUT;
 
-                       if (time_after(jiffies, start + timeout))
-                               break;
+                       if (time_after(jiffies, start + timeout)) {
+                               dev_err(occ->dev, "resp timeout status=%02x "
+                                       "resp seq_no=%d our seq_no=%d\n",
+                                       resp->return_status, resp->seq_no,
+                                       seq_no);
+                               goto done;
+                       }
 
                        set_current_state(TASK_UNINTERRUPTIBLE);
                        schedule_timeout(wait_time);
index d92f5b8..f54df9e 100644 (file)
@@ -289,11 +289,11 @@ static int sbefifo_check_sbe_state(struct sbefifo *sbefifo)
        switch ((sbm & CFAM_SBM_SBE_STATE_MASK) >> CFAM_SBM_SBE_STATE_SHIFT) {
        case SBE_STATE_UNKNOWN:
                return -ESHUTDOWN;
+       case SBE_STATE_DMT:
+               return -EBUSY;
        case SBE_STATE_IPLING:
        case SBE_STATE_ISTEP:
        case SBE_STATE_MPIPL:
-       case SBE_STATE_DMT:
-               return -EBUSY;
        case SBE_STATE_RUNTIME:
        case SBE_STATE_DUMP: /* Not sure about that one */
                break;
index 6314225..3611a05 100644 (file)
@@ -41,7 +41,7 @@ MODULE_PARM_DESC(mask, "GPIO channel mask.");
 
 /*
  * FIXME: convert this singleton driver to use the state container
- * design pattern, see Documentation/driver-model/design-patterns.txt
+ * design pattern, see Documentation/driver-model/design-patterns.rst
  */
 static struct cs5535_gpio_chip {
        struct gpio_chip chip;
index 80b7550..ad19df0 100644 (file)
@@ -93,7 +93,7 @@ static struct bus_type mipi_dsi_bus_type = {
        .pm = &mipi_dsi_device_pm_ops,
 };
 
-static int of_device_match(struct device *dev, void *data)
+static int of_device_match(struct device *dev, const void *data)
 {
        return dev->of_node == data;
 }
diff --git a/drivers/gpu/drm/i915/.gitignore b/drivers/gpu/drm/i915/.gitignore
deleted file mode 100644 (file)
index cff45d8..0000000
+++ /dev/null
@@ -1 +0,0 @@
-header_test_*.c
index c1c3918..639b596 100644 (file)
@@ -2,7 +2,7 @@
 # Copyright © 2019 Intel Corporation
 
 # Test the headers are compilable as standalone units
-header_test := \
+header-test-$(CONFIG_DRM_I915_WERROR) := \
        i915_active_types.h \
        i915_gem_context_types.h \
        i915_priolist_types.h \
@@ -35,13 +35,3 @@ header_test := \
        intel_sprite.h \
        intel_tv.h \
        intel_workarounds_types.h
-
-quiet_cmd_header_test = HDRTEST $@
-      cmd_header_test = echo "\#include \"$(<F)\"" > $@
-
-header_test_%.c: %.h
-       $(call cmd,header_test)
-
-i915-$(CONFIG_DRM_I915_WERROR) += $(foreach h,$(header_test),$(patsubst %.h,header_test_%.o,$(h)))
-
-clean-files += $(foreach h,$(header_test),$(patsubst %.h,header_test_%.c,$(h)))
index e4935dd..c23bb29 100644 (file)
@@ -35,8 +35,7 @@ struct remap_pfn {
        pgprot_t prot;
 };
 
-static int remap_pfn(pte_t *pte, pgtable_t token,
-                    unsigned long addr, void *data)
+static int remap_pfn(pte_t *pte, unsigned long addr, void *data)
 {
        struct remap_pfn *r = data;
 
index 826b3f0..cf25f18 100644 (file)
@@ -2372,10 +2372,10 @@ static int tegra_dc_parse_dt(struct tegra_dc *dc)
        return 0;
 }
 
-static int tegra_dc_match_by_pipe(struct device *dev, void *data)
+static int tegra_dc_match_by_pipe(struct device *dev, const void *data)
 {
        struct tegra_dc *dc = dev_get_drvdata(dev);
-       unsigned int pipe = (unsigned long)data;
+       unsigned int pipe = (unsigned long)(void *)data;
 
        return dc->pipe == pipe;
 }
index b032d38..0d695f8 100644 (file)
 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042
 #define USB_DEVICE_ID_UGEE_TABLET_G5           0x0074
 #define USB_DEVICE_ID_UGEE_TABLET_EX07S                0x0071
+#define USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720        0x0055
 
 #define USB_VENDOR_ID_UNITEC   0x227d
 #define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709    0x0709
 #define USB_DEVICE_ID_PRIMAX_KEYBOARD  0x4e05
 #define USB_DEVICE_ID_PRIMAX_REZEL     0x4e72
 #define USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F 0x4d0f
+#define USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D65 0x4d65
 #define USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4E22 0x4e22
 
 
index c8c6d04..5008a3d 100644 (file)
@@ -869,8 +869,6 @@ static void lg_remove(struct hid_device *hdev)
 }
 
 static const struct hid_device_id lg_devices[] = {
-       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
-               .driver_data = LG_RDESC | LG_WIRELESS },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
                .driver_data = LG_RDESC | LG_WIRELESS },
 
index bfcf2ee..6196217 100644 (file)
@@ -1103,12 +1103,14 @@ static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
 
 static int logi_dj_recv_query_hidpp_devices(struct dj_receiver_dev *djrcv_dev)
 {
-       const u8 template[] = {REPORT_ID_HIDPP_SHORT,
-                              HIDPP_RECEIVER_INDEX,
-                              HIDPP_SET_REGISTER,
-                              HIDPP_REG_CONNECTION_STATE,
-                              HIDPP_FAKE_DEVICE_ARRIVAL,
-                              0x00, 0x00};
+       static const u8 template[] = {
+               REPORT_ID_HIDPP_SHORT,
+               HIDPP_RECEIVER_INDEX,
+               HIDPP_SET_REGISTER,
+               HIDPP_REG_CONNECTION_STATE,
+               HIDPP_FAKE_DEVICE_ARRIVAL,
+               0x00, 0x00
+       };
        u8 *hidpp_report;
        int retval;
 
@@ -1123,7 +1125,7 @@ static int logi_dj_recv_query_hidpp_devices(struct dj_receiver_dev *djrcv_dev)
                                    HID_REQ_SET_REPORT);
 
        kfree(hidpp_report);
-       return 0;
+       return retval;
 }
 
 static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
@@ -1834,6 +1836,9 @@ static const struct hid_device_id logi_dj_receivers[] = {
          HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
                USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_GAMING),
         .driver_data = recvr_type_gaming_hidpp},
+       { /* Logitech 27 MHz HID++ 1.0 receiver (0xc513) */
+         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
+        .driver_data = recvr_type_27mhz},
        { /* Logitech 27 MHz HID++ 1.0 receiver (0xc517) */
          HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
                USB_DEVICE_ID_S510_RECEIVER_2),
index cf05816..e3b6245 100644 (file)
@@ -2858,7 +2858,7 @@ static u8 *hidpp10_consumer_keys_report_fixup(struct hidpp_device *hidpp,
                                              u8 *_rdesc, unsigned int *rsize)
 {
        /* Note 0 terminated so we can use strnstr to search for this. */
-       const char consumer_rdesc_start[] = {
+       static const char consumer_rdesc_start[] = {
                0x05, 0x0C,     /* USAGE_PAGE (Consumer Devices)       */
                0x09, 0x01,     /* USAGE (Consumer Control)            */
                0xA1, 0x01,     /* COLLECTION (Application)            */
index 671a285..185a577 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
+#include <linux/input/elan-i2c-ids.h>
 
 #include "hid-ids.h"
 
@@ -130,6 +131,7 @@ static const struct hid_device_id hid_quirks[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
        { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_MOUSE_4D22), HID_QUIRK_ALWAYS_POLL },
        { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F), HID_QUIRK_ALWAYS_POLL },
+       { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D65), HID_QUIRK_ALWAYS_POLL },
        { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4E22), HID_QUIRK_ALWAYS_POLL },
        { HID_USB_DEVICE(USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS), HID_QUIRK_NOGET },
        { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001), HID_QUIRK_NOGET },
@@ -915,6 +917,8 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
 
 bool hid_ignore(struct hid_device *hdev)
 {
+       int i;
+
        if (hdev->quirks & HID_QUIRK_NO_IGNORE)
                return false;
        if (hdev->quirks & HID_QUIRK_IGNORE)
@@ -979,18 +983,15 @@ bool hid_ignore(struct hid_device *hdev)
                break;
        case USB_VENDOR_ID_ELAN:
                /*
-                * Many Elan devices have a product id of 0x0401 and are handled
-                * by the elan_i2c input driver. But the ACPI HID ELAN0800 dev
-                * is not (and cannot be) handled by that driver ->
-                * Ignore all 0x0401 devs except for the ELAN0800 dev.
+                * Blacklist of everything that gets handled by the elan_i2c
+                * input driver.  This avoids disabling valid touchpads and
+                * other ELAN devices.
                 */
-               if (hdev->product == 0x0401 &&
-                   strncmp(hdev->name, "ELAN0800", 8) != 0)
-                       return true;
-               /* Same with product id 0x0400 */
-               if (hdev->product == 0x0400 &&
-                   strncmp(hdev->name, "QTEC0001", 8) != 0)
-                       return true;
+               if ((hdev->product == 0x0401 || hdev->product == 0x0400))
+                       for (i = 0; strlen(elan_acpi_id[i].id); ++i)
+                               if (!strncmp(hdev->name, elan_acpi_id[i].id,
+                                            strlen(elan_acpi_id[i].id)))
+                                       return true;
                break;
        }
 
index 914fb52..86b5680 100644 (file)
@@ -389,6 +389,8 @@ static const struct hid_device_id uclogic_devices[] = {
                                USB_DEVICE_ID_UGEE_TABLET_G5) },
        { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
                                USB_DEVICE_ID_UGEE_TABLET_EX07S) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
+                               USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720) },
        { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
                                USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540) },
        { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
index 273d784..78a364a 100644 (file)
@@ -1001,6 +1001,8 @@ int uclogic_params_init(struct uclogic_params *params,
                     USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540):
        case VID_PID(USB_VENDOR_ID_UGEE,
                     USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640):
+       case VID_PID(USB_VENDOR_ID_UGEE,
+                    USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720):
                /* If this is the pen interface */
                if (bInterfaceNumber == 1) {
                        /* Probe v1 pen parameters */
index 17ae49f..aa80b4d 100644 (file)
@@ -184,6 +184,7 @@ static void ish_remove(struct pci_dev *pdev)
        struct ishtp_device *ishtp_dev = pci_get_drvdata(pdev);
 
        ishtp_bus_remove_all_clients(ishtp_dev, false);
+       pdev->dev_flags &= ~PCI_DEV_FLAGS_NO_D3;
        ish_device_disable(ishtp_dev);
 }
 
index 83dd3a2..53bddb5 100644 (file)
@@ -304,18 +304,23 @@ static void wacom_feature_mapping(struct hid_device *hdev,
        wacom_hid_usage_quirk(hdev, field, usage);
 
        switch (equivalent_usage) {
+       case WACOM_HID_WD_TOUCH_RING_SETTING:
+               wacom->generic_has_leds = true;
+               break;
        case HID_DG_CONTACTMAX:
                /* leave touch_max as is if predefined */
                if (!features->touch_max) {
                        /* read manually */
-                       data = kzalloc(2, GFP_KERNEL);
+                       n = hid_report_len(field->report);
+                       data = hid_alloc_report_buf(field->report, GFP_KERNEL);
                        if (!data)
                                break;
                        data[0] = field->report->id;
                        ret = wacom_get_report(hdev, HID_FEATURE_REPORT,
-                                               data, 2, WAC_CMD_RETRIES);
-                       if (ret == 2) {
-                               features->touch_max = data[1];
+                                              data, n, WAC_CMD_RETRIES);
+                       if (ret == n) {
+                               ret = hid_report_raw_event(hdev,
+                                       HID_FEATURE_REPORT, data, n, 0);
                        } else {
                                features->touch_max = 16;
                                hid_warn(hdev, "wacom_feature_mapping: "
index 43f6da3..8fc36a2 100644 (file)
@@ -1216,7 +1216,8 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
        unsigned char *data = wacom->data;
        int i;
 
-       if (wacom->features.type == INTUOSP2_BT) {
+       if (wacom->features.type == INTUOSP2_BT ||
+           wacom->features.type == INTUOSP2S_BT) {
                wacom->serial[0] = get_unaligned_le64(&data[99]);
                wacom->id[0]     = get_unaligned_le16(&data[107]);
                pen_frame_len = 14;
@@ -1268,7 +1269,8 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
                        input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1]));
                        input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3]));
 
-                       if (wacom->features.type == INTUOSP2_BT) {
+                       if (wacom->features.type == INTUOSP2_BT ||
+                           wacom->features.type == INTUOSP2S_BT) {
                                /* Fix rotation alignment: userspace expects zero at left */
                                int16_t rotation =
                                        (int16_t)get_unaligned_le16(&frame[9]);
@@ -1286,7 +1288,6 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
                                                 get_unaligned_le16(&frame[11]));
                        }
                }
-
                if (wacom->tool[0]) {
                        input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5]));
                        if (wacom->features.type == INTUOSP2_BT) {
@@ -1456,7 +1457,8 @@ static int wacom_intuos_pro2_bt_irq(struct wacom_wac *wacom, size_t len)
        }
 
        wacom_intuos_pro2_bt_pen(wacom);
-       if (wacom->features.type == INTUOSP2_BT) {
+       if (wacom->features.type == INTUOSP2_BT ||
+           wacom->features.type == INTUOSP2S_BT) {
                wacom_intuos_pro2_bt_touch(wacom);
                wacom_intuos_pro2_bt_pad(wacom);
                wacom_intuos_pro2_bt_battery(wacom);
@@ -1768,6 +1770,9 @@ int wacom_equivalent_usage(int usage)
                int subpage = (usage & 0xFF00) << 8;
                int subusage = (usage & 0xFF);
 
+               if (usage == WACOM_HID_WT_REPORT_VALID)
+                       return usage;
+
                if (subpage == HID_UP_UNDEFINED)
                        subpage = WACOM_HID_SP_DIGITIZER;
 
@@ -1926,8 +1931,6 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
                features->device_type |= WACOM_DEVICETYPE_PAD;
                break;
        case WACOM_HID_WD_BUTTONCENTER:
-               wacom->generic_has_leds = true;
-               /* fall through */
        case WACOM_HID_WD_BUTTONHOME:
        case WACOM_HID_WD_BUTTONUP:
        case WACOM_HID_WD_BUTTONDOWN:
@@ -2043,12 +2046,16 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
                 */
                if (hdev->vendor == 0x56a &&
                    (hdev->product == 0x34d || hdev->product == 0x34e ||  /* MobileStudio Pro */
-                    hdev->product == 0x357 || hdev->product == 0x358)) { /* Intuos Pro 2 */
+                    hdev->product == 0x357 || hdev->product == 0x358 ||  /* Intuos Pro 2 */
+                    hdev->product == 0x392 ||                            /* Intuos Pro 2 */
+                    hdev->product == 0x399)) {                           /* MobileStudio Pro */
                        value = (field->logical_maximum - value);
 
-                       if (hdev->product == 0x357 || hdev->product == 0x358)
+                       if (hdev->product == 0x357 || hdev->product == 0x358 ||
+                           hdev->product == 0x392)
                                value = wacom_offset_rotation(input, usage, value, 3, 16);
-                       else if (hdev->product == 0x34d || hdev->product == 0x34e)
+                       else if (hdev->product == 0x34d || hdev->product == 0x34e ||
+                                hdev->product == 0x399)
                                value = wacom_offset_rotation(input, usage, value, 1, 2);
                }
                else {
@@ -2119,14 +2126,12 @@ static void wacom_wac_pad_report(struct hid_device *hdev,
        bool active = wacom_wac->hid_data.inrange_state != 0;
 
        /* report prox for expresskey events */
-       if ((wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) &&
-           wacom_wac->hid_data.pad_input_event_flag) {
+       if (wacom_wac->hid_data.pad_input_event_flag) {
                input_event(input, EV_ABS, ABS_MISC, active ? PAD_DEVICE_ID : 0);
                input_sync(input);
                if (!active)
                        wacom_wac->hid_data.pad_input_event_flag = false;
        }
-
 }
 
 static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
@@ -2512,6 +2517,10 @@ static void wacom_wac_finger_event(struct hid_device *hdev,
        struct wacom *wacom = hid_get_drvdata(hdev);
        struct wacom_wac *wacom_wac = &wacom->wacom_wac;
        unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
+       struct wacom_features *features = &wacom->wacom_wac.features;
+
+       if (wacom_wac->is_invalid_bt_frame)
+               return;
 
        switch (equivalent_usage) {
        case HID_GD_X:
@@ -2532,9 +2541,14 @@ static void wacom_wac_finger_event(struct hid_device *hdev,
        case HID_DG_TIPSWITCH:
                wacom_wac->hid_data.tipswitch = value;
                break;
+       case WACOM_HID_WT_REPORT_VALID:
+               wacom_wac->is_invalid_bt_frame = !value;
+               return;
+       case HID_DG_CONTACTMAX:
+               features->touch_max = value;
+               return;
        }
 
-
        if (usage->usage_index + 1 == field->report_count) {
                if (equivalent_usage == wacom_wac->hid_data.last_slot_field)
                        wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input);
@@ -2549,6 +2563,8 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev,
        struct hid_data* hid_data = &wacom_wac->hid_data;
        int i;
 
+       wacom_wac->is_invalid_bt_frame = false;
+
        for (i = 0; i < report->maxfield; i++) {
                struct hid_field *field = report->field[i];
                int j;
@@ -2569,25 +2585,9 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev,
                        case HID_DG_TIPSWITCH:
                                hid_data->last_slot_field = equivalent_usage;
                                break;
-                       case HID_DG_CONTACTCOUNT:
-                               hid_data->cc_report = report->id;
-                               hid_data->cc_index = i;
-                               hid_data->cc_value_index = j;
-                               break;
                        }
                }
        }
-
-       if (hid_data->cc_report != 0 &&
-           hid_data->cc_index >= 0) {
-               struct hid_field *field = report->field[hid_data->cc_index];
-               int value = field->value[hid_data->cc_value_index];
-               if (value)
-                       hid_data->num_expected = value;
-       }
-       else {
-               hid_data->num_expected = wacom_wac->features.touch_max;
-       }
 }
 
 static void wacom_wac_finger_report(struct hid_device *hdev,
@@ -2597,6 +2597,7 @@ static void wacom_wac_finger_report(struct hid_device *hdev,
        struct wacom_wac *wacom_wac = &wacom->wacom_wac;
        struct input_dev *input = wacom_wac->touch_input;
        unsigned touch_max = wacom_wac->features.touch_max;
+       struct hid_data *hid_data = &wacom_wac->hid_data;
 
        /* If more packets of data are expected, give us a chance to
         * process them rather than immediately syncing a partial
@@ -2610,6 +2611,7 @@ static void wacom_wac_finger_report(struct hid_device *hdev,
 
        input_sync(input);
        wacom_wac->hid_data.num_received = 0;
+       hid_data->num_expected = 0;
 
        /* keep touch state for pen event */
        wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(wacom_wac);
@@ -2684,12 +2686,73 @@ static void wacom_report_events(struct hid_device *hdev,
        }
 }
 
+static void wacom_set_num_expected(struct hid_device *hdev,
+                                  struct hid_report *report,
+                                  int collection_index,
+                                  struct hid_field *field,
+                                  int field_index)
+{
+       struct wacom *wacom = hid_get_drvdata(hdev);
+       struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+       struct hid_data *hid_data = &wacom_wac->hid_data;
+       unsigned int original_collection_level =
+               hdev->collection[collection_index].level;
+       bool end_collection = false;
+       int i;
+
+       if (hid_data->num_expected)
+               return;
+
+       // find the contact count value for this segment
+       for (i = field_index; i < report->maxfield && !end_collection; i++) {
+               struct hid_field *field = report->field[i];
+               unsigned int field_level =
+                       hdev->collection[field->usage[0].collection_index].level;
+               unsigned int j;
+
+               if (field_level != original_collection_level)
+                       continue;
+
+               for (j = 0; j < field->maxusage; j++) {
+                       struct hid_usage *usage = &field->usage[j];
+
+                       if (usage->collection_index != collection_index) {
+                               end_collection = true;
+                               break;
+                       }
+                       if (wacom_equivalent_usage(usage->hid) == HID_DG_CONTACTCOUNT) {
+                               hid_data->cc_report = report->id;
+                               hid_data->cc_index = i;
+                               hid_data->cc_value_index = j;
+
+                               if (hid_data->cc_report != 0 &&
+                                   hid_data->cc_index >= 0) {
+
+                                       struct hid_field *field =
+                                               report->field[hid_data->cc_index];
+                                       int value =
+                                               field->value[hid_data->cc_value_index];
+
+                                       if (value)
+                                               hid_data->num_expected = value;
+                               }
+                       }
+               }
+       }
+
+       if (hid_data->cc_report == 0 || hid_data->cc_index < 0)
+               hid_data->num_expected = wacom_wac->features.touch_max;
+}
+
 static int wacom_wac_collection(struct hid_device *hdev, struct hid_report *report,
                         int collection_index, struct hid_field *field,
                         int field_index)
 {
        struct wacom *wacom = hid_get_drvdata(hdev);
 
+       if (WACOM_FINGER_FIELD(field))
+               wacom_set_num_expected(hdev, report, collection_index, field,
+                                      field_index);
        wacom_report_events(hdev, report, collection_index, field_index);
 
        /*
@@ -2702,9 +2765,7 @@ static int wacom_wac_collection(struct hid_device *hdev, struct hid_report *repo
        if (report->type != HID_INPUT_REPORT)
                return -1;
 
-       if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input)
-               wacom_wac_pad_report(hdev, report, field);
-       else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
+       if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
                wacom_wac_pen_report(hdev, report);
        else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input)
                wacom_wac_finger_report(hdev, report);
@@ -2718,7 +2779,7 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
        struct wacom_wac *wacom_wac = &wacom->wacom_wac;
        struct hid_field *field;
        bool pad_in_hid_field = false, pen_in_hid_field = false,
-               finger_in_hid_field = false;
+               finger_in_hid_field = false, true_pad = false;
        int r;
        int prev_collection = -1;
 
@@ -2734,6 +2795,8 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
                        pen_in_hid_field = true;
                if (WACOM_FINGER_FIELD(field))
                        finger_in_hid_field = true;
+               if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY)
+                       true_pad = true;
        }
 
        wacom_wac_battery_pre_report(hdev, report);
@@ -2757,6 +2820,9 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
        }
 
        wacom_wac_battery_report(hdev, report);
+
+       if (true_pad && wacom->wacom_wac.pad_input)
+               wacom_wac_pad_report(hdev, report, field);
 }
 
 static int wacom_bpt_touch(struct wacom_wac *wacom)
@@ -3225,6 +3291,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
                break;
 
        case INTUOSP2_BT:
+       case INTUOSP2S_BT:
        case INTUOSHT3_BT:
                sync = wacom_intuos_pro2_bt_irq(wacom_wac, len);
                break;
@@ -3405,7 +3472,8 @@ void wacom_setup_device_quirks(struct wacom *wacom)
        if (features->type == REMOTE)
                features->device_type = WACOM_DEVICETYPE_PAD;
 
-       if (features->type == INTUOSP2_BT) {
+       if (features->type == INTUOSP2_BT ||
+           features->type == INTUOSP2S_BT) {
                features->device_type |= WACOM_DEVICETYPE_PEN |
                                         WACOM_DEVICETYPE_PAD |
                                         WACOM_DEVICETYPE_TOUCH;
@@ -3586,6 +3654,7 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
        case INTUOS5S:
        case INTUOSPS:
        case INTUOSP2_BT:
+       case INTUOSP2S_BT:
                input_set_abs_params(input_dev, ABS_DISTANCE, 0,
                                      features->distance_max,
                                      features->distance_fuzz, 0);
@@ -3697,6 +3766,7 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
 
        switch (features->type) {
        case INTUOSP2_BT:
+       case INTUOSP2S_BT:
                input_dev->evbit[0] |= BIT_MASK(EV_SW);
                __set_bit(SW_MUTE_DEVICE, input_dev->swbit);
 
@@ -3712,8 +3782,14 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
                        input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
                                             0, 5920, 4, 0);
                }
+               else if (wacom_wac->shared->touch->product == 0x393) {
+                       input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+                                            0, 6400, 4, 0);
+                       input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+                                            0, 4000, 4, 0);
+               }
                input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40);
-               input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40);
+               input_abs_set_res(input_dev, ABS_MT_POSITION_Y, 40);
 
                /* fall through */
 
@@ -4021,6 +4097,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
        case INTUOS5S:
        case INTUOSPS:
        case INTUOSP2_BT:
+       case INTUOSP2S_BT:
                input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
                break;
 
@@ -4598,6 +4675,10 @@ static const struct wacom_features wacom_features_0x37A =
 static const struct wacom_features wacom_features_0x37B =
        { "Wacom One by Wacom M", 21600, 13500, 2047, 63,
          BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x393 =
+       { "Wacom Intuos Pro S", 31920, 19950, 8191, 63,
+         INTUOSP2S_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7,
+         .touch_max = 10 };
 
 static const struct wacom_features wacom_features_HID_ANY_ID =
        { "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID };
@@ -4770,6 +4851,7 @@ const struct hid_device_id wacom_ids[] = {
        { BT_DEVICE_WACOM(0x379) },
        { USB_DEVICE_WACOM(0x37A) },
        { USB_DEVICE_WACOM(0x37B) },
+       { BT_DEVICE_WACOM(0x393) },
        { USB_DEVICE_WACOM(0x4001) },
        { USB_DEVICE_WACOM(0x4004) },
        { USB_DEVICE_WACOM(0x5000) },
index cac68d1..da612b6 100644 (file)
 #define WACOM_HID_WD_OFFSETBOTTOM       (WACOM_HID_UP_WACOMDIGITIZER | 0x0d33)
 #define WACOM_HID_WD_DATAMODE           (WACOM_HID_UP_WACOMDIGITIZER | 0x1002)
 #define WACOM_HID_WD_DIGITIZERINFO      (WACOM_HID_UP_WACOMDIGITIZER | 0x1013)
+#define WACOM_HID_WD_TOUCH_RING_SETTING (WACOM_HID_UP_WACOMDIGITIZER | 0x1032)
 #define WACOM_HID_UP_G9                 0xff090000
 #define WACOM_HID_G9_PEN                (WACOM_HID_UP_G9 | 0x02)
 #define WACOM_HID_G9_TOUCHSCREEN        (WACOM_HID_UP_G9 | 0x11)
 #define WACOM_HID_WT_SERIALNUMBER       (WACOM_HID_UP_WACOMTOUCH | 0x5b)
 #define WACOM_HID_WT_X                  (WACOM_HID_UP_WACOMTOUCH | 0x130)
 #define WACOM_HID_WT_Y                  (WACOM_HID_UP_WACOMTOUCH | 0x131)
+#define WACOM_HID_WT_REPORT_VALID       (WACOM_HID_UP_WACOMTOUCH | 0x1d0)
 
 #define WACOM_BATTERY_USAGE(f) (((f)->hid == HID_DG_BATTERYSTRENGTH) || \
                                 ((f)->hid == WACOM_HID_WD_BATTERY_CHARGING) || \
@@ -210,6 +212,7 @@ enum {
        INTUOSPM,
        INTUOSPL,
        INTUOSP2_BT,
+       INTUOSP2S_BT,
        INTUOSHT3_BT,
        WACOM_21UX2,
        WACOM_22HD,
index 72d5a7c..894da5a 100644 (file)
@@ -2163,6 +2163,7 @@ static void __exit vmbus_exit(void)
 
 
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Microsoft Hyper-V VMBus Driver");
 
 subsys_initcall(hv_acpi_init);
 module_exit(vmbus_exit);
index 388060f..f7752a5 100644 (file)
  * Very rare chip please let me know if you use it
  *
  * http://www.analog.com/UploadedFiles/Data_Sheets/ADM1029.pdf
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #include <linux/module.h>
index 8dd5b1b..ff64a39 100644 (file)
@@ -789,33 +789,16 @@ static const struct file_operations atk_debugfs_ggrp_fops = {
 static void atk_debugfs_init(struct atk_data *data)
 {
        struct dentry *d;
-       struct dentry *f;
 
        data->debugfs.id = 0;
 
        d = debugfs_create_dir("asus_atk0110", NULL);
-       if (!d || IS_ERR(d))
-               return;
 
-       f = debugfs_create_x32("id", 0600, d, &data->debugfs.id);
-       if (!f || IS_ERR(f))
-               goto cleanup;
-
-       f = debugfs_create_file_unsafe("gitm", 0400, d, data,
-                                      &atk_debugfs_gitm);
-       if (!f || IS_ERR(f))
-               goto cleanup;
-
-       f = debugfs_create_file("ggrp", 0400, d, data,
-                               &atk_debugfs_ggrp_fops);
-       if (!f || IS_ERR(f))
-               goto cleanup;
+       debugfs_create_x32("id", 0600, d, &data->debugfs.id);
+       debugfs_create_file_unsafe("gitm", 0400, d, data, &atk_debugfs_gitm);
+       debugfs_create_file("ggrp", 0400, d, data, &atk_debugfs_ggrp_fops);
 
        data->debugfs.root = d;
-
-       return;
-cleanup:
-       debugfs_remove_recursive(d);
 }
 
 static void atk_debugfs_cleanup(struct atk_data *data)
index 8475368..3ea4021 100644 (file)
@@ -54,8 +54,8 @@ static void fan_alarm_notify(struct work_struct *ws)
        struct gpio_fan_data *fan_data =
                container_of(ws, struct gpio_fan_data, alarm_work);
 
-       sysfs_notify(&fan_data->dev->kobj, NULL, "fan1_alarm");
-       kobject_uevent(&fan_data->dev->kobj, KOBJ_CHANGE);
+       sysfs_notify(&fan_data->hwmon_dev->kobj, NULL, "fan1_alarm");
+       kobject_uevent(&fan_data->hwmon_dev->kobj, KOBJ_CHANGE);
 }
 
 static irqreturn_t fan_alarm_irq_handler(int irq, void *dev_id)
@@ -510,13 +510,6 @@ static int gpio_fan_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, fan_data);
        mutex_init(&fan_data->lock);
 
-       /* Configure alarm GPIO if available. */
-       if (fan_data->alarm_gpio) {
-               err = fan_alarm_init(fan_data);
-               if (err)
-                       return err;
-       }
-
        /* Configure control GPIOs if available. */
        if (fan_data->gpios && fan_data->num_gpios > 0) {
                if (!fan_data->speed || fan_data->num_speed <= 1)
@@ -524,7 +517,9 @@ static int gpio_fan_probe(struct platform_device *pdev)
                err = fan_ctrl_init(fan_data);
                if (err)
                        return err;
-               devm_add_action_or_reset(dev, gpio_fan_stop, fan_data);
+               err = devm_add_action_or_reset(dev, gpio_fan_stop, fan_data);
+               if (err)
+                       return err;
        }
 
        /* Make this driver part of hwmon class. */
@@ -535,6 +530,13 @@ static int gpio_fan_probe(struct platform_device *pdev)
        if (IS_ERR(fan_data->hwmon_dev))
                return PTR_ERR(fan_data->hwmon_dev);
 
+       /* Configure alarm GPIO if available. */
+       if (fan_data->alarm_gpio) {
+               err = fan_alarm_init(fan_data);
+               if (err)
+                       return err;
+       }
+
        /* Optional cooling device register for Device tree platforms */
        fan_data->cdev = devm_thermal_of_cooling_device_register(dev, np,
                                "gpio-fan", fan_data, &gpio_fan_cool_ops);
index 05e120e..1f3b30b 100644 (file)
@@ -651,6 +651,12 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
                                                                hwdev, j);
                                        if (err) {
                                                device_unregister(hdev);
+                                               /*
+                                                * Don't worry about hwdev;
+                                                * hwmon_dev_release(), called
+                                                * from device_unregister(),
+                                                * will free it.
+                                                */
                                                goto ida_remove;
                                        }
                                }
index 55943b4..0037e2b 100644 (file)
@@ -713,8 +713,10 @@ static int ina3221_probe_from_dt(struct device *dev, struct ina3221_data *ina)
 
        for_each_child_of_node(np, child) {
                ret = ina3221_probe_child_from_dt(dev, child, ina);
-               if (ret)
+               if (ret) {
+                       of_node_put(child);
                        return ret;
+               }
        }
 
        return 0;
index e562a57..9b3c9f3 100644 (file)
@@ -174,6 +174,7 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
 #define LM90_HAVE_EMERGENCY_ALARM (1 << 5)/* emergency alarm           */
 #define LM90_HAVE_TEMP3                (1 << 6) /* 3rd temperature sensor      */
 #define LM90_HAVE_BROKEN_ALERT (1 << 7) /* Broken alert                */
+#define LM90_PAUSE_FOR_CONFIG  (1 << 8) /* Pause conversion for config */
 
 /* LM90 status */
 #define LM90_STATUS_LTHRM      (1 << 0) /* local THERM limit tripped */
@@ -367,6 +368,7 @@ static const struct lm90_params lm90_params[] = {
                .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
        },
        [max6657] = {
+               .flags = LM90_PAUSE_FOR_CONFIG,
                .alert_alarms = 0x7c,
                .max_convrate = 8,
                .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
@@ -457,6 +459,7 @@ struct lm90_data {
 
        unsigned int update_interval; /* in milliseconds */
 
+       u8 config;              /* Current configuration register value */
        u8 config_orig;         /* Original configuration register value */
        u8 convrate_orig;       /* Original conversion rate register value */
        u16 alert_alarms;       /* Which alarm bits trigger ALERT# */
@@ -540,6 +543,21 @@ static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl)
        return (newh << 8) | l;
 }
 
+static int lm90_update_confreg(struct lm90_data *data, u8 config)
+{
+       if (data->config != config) {
+               int err;
+
+               err = i2c_smbus_write_byte_data(data->client,
+                                               LM90_REG_W_CONFIG1,
+                                               config);
+               if (err)
+                       return err;
+               data->config = config;
+       }
+       return 0;
+}
+
 /*
  * client->update_lock must be held when calling this function (unless we are
  * in detection or initialization steps), and while a remote channel other
@@ -548,23 +566,39 @@ static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl)
  * various registers have different meanings as a result of selecting a
  * non-default remote channel.
  */
-static inline int lm90_select_remote_channel(struct i2c_client *client,
-                                            struct lm90_data *data,
-                                            int channel)
+static int lm90_select_remote_channel(struct lm90_data *data, int channel)
 {
-       int config;
+       int err = 0;
 
        if (data->kind == max6696) {
-               config = lm90_read_reg(client, LM90_REG_R_CONFIG1);
-               if (config < 0)
-                       return config;
-               config &= ~0x08;
+               u8 config = data->config & ~0x08;
+
                if (channel)
                        config |= 0x08;
-               i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
-                                         config);
+               err = lm90_update_confreg(data, config);
        }
-       return 0;
+       return err;
+}
+
+static int lm90_write_convrate(struct lm90_data *data, int val)
+{
+       u8 config = data->config;
+       int err;
+
+       /* Save config and pause conversion */
+       if (data->flags & LM90_PAUSE_FOR_CONFIG) {
+               err = lm90_update_confreg(data, config | 0x40);
+               if (err < 0)
+                       return err;
+       }
+
+       /* Set conv rate */
+       err = i2c_smbus_write_byte_data(data->client, LM90_REG_W_CONVRATE, val);
+
+       /* Revert change to config */
+       lm90_update_confreg(data, config);
+
+       return err;
 }
 
 /*
@@ -587,7 +621,7 @@ static int lm90_set_convrate(struct i2c_client *client, struct lm90_data *data,
                if (interval >= update_interval * 3 / 4)
                        break;
 
-       err = i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, i);
+       err = lm90_write_convrate(data, i);
        data->update_interval = DIV_ROUND_CLOSEST(update_interval, 64);
        return err;
 }
@@ -658,7 +692,7 @@ static int lm90_update_limits(struct device *dev)
        }
 
        if (data->kind == max6696) {
-               val = lm90_select_remote_channel(client, data, 1);
+               val = lm90_select_remote_channel(data, 1);
                if (val < 0)
                        return val;
 
@@ -682,7 +716,7 @@ static int lm90_update_limits(struct device *dev)
                        return val;
                data->temp11[REMOTE2_HIGH] = val << 8;
 
-               lm90_select_remote_channel(client, data, 0);
+               lm90_select_remote_channel(data, 0);
        }
 
        return 0;
@@ -742,19 +776,19 @@ static int lm90_update_device(struct device *dev)
                data->alarms = val;     /* lower 8 bit of alarms */
 
                if (data->kind == max6696) {
-                       val = lm90_select_remote_channel(client, data, 1);
+                       val = lm90_select_remote_channel(data, 1);
                        if (val < 0)
                                return val;
 
                        val = lm90_read16(client, LM90_REG_R_REMOTE_TEMPH,
                                          LM90_REG_R_REMOTE_TEMPL);
                        if (val < 0) {
-                               lm90_select_remote_channel(client, data, 0);
+                               lm90_select_remote_channel(data, 0);
                                return val;
                        }
                        data->temp11[REMOTE2_TEMP] = val;
 
-                       lm90_select_remote_channel(client, data, 0);
+                       lm90_select_remote_channel(data, 0);
 
                        val = lm90_read_reg(client, MAX6696_REG_R_STATUS2);
                        if (val < 0)
@@ -768,15 +802,9 @@ static int lm90_update_device(struct device *dev)
                 */
                if (!(data->config_orig & 0x80) &&
                    !(data->alarms & data->alert_alarms)) {
-                       val = lm90_read_reg(client, LM90_REG_R_CONFIG1);
-                       if (val < 0)
-                               return val;
-
-                       if (val & 0x80) {
+                       if (data->config & 0x80) {
                                dev_dbg(&client->dev, "Re-enabling ALERT#\n");
-                               i2c_smbus_write_byte_data(client,
-                                                         LM90_REG_W_CONFIG1,
-                                                         val & ~0x80);
+                               lm90_update_confreg(data, data->config & ~0x80);
                        }
                }
 
@@ -994,7 +1022,7 @@ static int lm90_set_temp11(struct lm90_data *data, int index, long val)
        else
                data->temp11[index] = temp_to_s8(val) << 8;
 
-       lm90_select_remote_channel(client, data, index >= 3);
+       lm90_select_remote_channel(data, index >= 3);
        err = i2c_smbus_write_byte_data(client, regp->high,
                                  data->temp11[index] >> 8);
        if (err < 0)
@@ -1003,7 +1031,7 @@ static int lm90_set_temp11(struct lm90_data *data, int index, long val)
                err = i2c_smbus_write_byte_data(client, regp->low,
                                                data->temp11[index] & 0xff);
 
-       lm90_select_remote_channel(client, data, 0);
+       lm90_select_remote_channel(data, 0);
        return err;
 }
 
@@ -1052,9 +1080,9 @@ static int lm90_set_temp8(struct lm90_data *data, int index, long val)
        else
                data->temp8[index] = temp_to_s8(val);
 
-       lm90_select_remote_channel(client, data, index >= 6);
+       lm90_select_remote_channel(data, index >= 6);
        err = i2c_smbus_write_byte_data(client, reg[index], data->temp8[index]);
-       lm90_select_remote_channel(client, data, 0);
+       lm90_select_remote_channel(data, 0);
 
        return err;
 }
@@ -1593,8 +1621,7 @@ static void lm90_restore_conf(void *_data)
        struct i2c_client *client = data->client;
 
        /* Restore initial configuration */
-       i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE,
-                                 data->convrate_orig);
+       lm90_write_convrate(data, data->convrate_orig);
        i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
                                  data->config_orig);
 }
@@ -1611,11 +1638,13 @@ static int lm90_init_client(struct i2c_client *client, struct lm90_data *data)
        /*
         * Start the conversions.
         */
-       lm90_set_convrate(client, data, 500);   /* 500ms; 2Hz conversion rate */
        config = lm90_read_reg(client, LM90_REG_R_CONFIG1);
        if (config < 0)
                return config;
        data->config_orig = config;
+       data->config = config;
+
+       lm90_set_convrate(client, data, 500); /* 500ms; 2Hz conversion rate */
 
        /* Check Temperature Range Select */
        if (data->kind == adt7461 || data->kind == tmp451) {
@@ -1638,8 +1667,7 @@ static int lm90_init_client(struct i2c_client *client, struct lm90_data *data)
                config &= ~0x08;
 
        config &= 0xBF; /* run */
-       if (config != data->config_orig) /* Only write if changed */
-               i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
+       lm90_update_confreg(data, config);
 
        return devm_add_action_or_reset(&client->dev, lm90_restore_conf, data);
 }
@@ -1718,7 +1746,7 @@ static int lm90_probe(struct i2c_client *client,
                      const struct i2c_device_id *id)
 {
        struct device *dev = &client->dev;
-       struct i2c_adapter *adapter = to_i2c_adapter(dev->parent);
+       struct i2c_adapter *adapter = client->adapter;
        struct hwmon_channel_info *info;
        struct regulator *regulator;
        struct device *hwmon_dev;
@@ -1873,14 +1901,8 @@ static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type,
 
                if ((data->flags & LM90_HAVE_BROKEN_ALERT) &&
                    (alarms & data->alert_alarms)) {
-                       int config;
-
                        dev_dbg(&client->dev, "Disabling ALERT#\n");
-                       config = lm90_read_reg(client, LM90_REG_R_CONFIG1);
-                       if (config >= 0)
-                               i2c_smbus_write_byte_data(client,
-                                                         LM90_REG_W_CONFIG1,
-                                                         config | 0x80);
+                       lm90_update_confreg(data, data->config | 0x80);
                }
        } else {
                dev_info(&client->dev, "Everything OK\n");
index 6b9056f..3d9d371 100644 (file)
@@ -92,7 +92,8 @@ module_param(clock, int, 0444);
 #define FAN_RPM_MIN 240
 #define FAN_RPM_MAX 30000
 
-#define DIV_FROM_REG(reg) (1 << (reg & 7))
+#define DIV_FROM_REG(reg)      (1 << ((reg) & 7))
+#define DAC_LIMIT(v12)         ((v12) ? 180 : 76)
 
 /*
  * Client data (each client gets its own)
@@ -100,11 +101,9 @@ module_param(clock, int, 0444);
 
 struct max6650_data {
        struct i2c_client *client;
-       const struct attribute_group *groups[3];
-       struct thermal_cooling_device *cooling_dev;
-       struct mutex update_lock;
+       struct mutex update_lock; /* protect alarm register updates */
        int nr_fans;
-       char valid; /* zero until following fields are valid */
+       bool valid; /* false until following fields are valid */
        unsigned long last_updated; /* in jiffies */
 
        /* register values */
@@ -114,6 +113,7 @@ struct max6650_data {
        u8 count;
        u8 dac;
        u8 alarm;
+       u8 alarm_en;
        unsigned long cooling_dev_state;
 };
 
@@ -137,41 +137,60 @@ static const struct of_device_id __maybe_unused max6650_dt_match[] = {
 };
 MODULE_DEVICE_TABLE(of, max6650_dt_match);
 
+static int dac_to_pwm(int dac, bool v12)
+{
+       /*
+        * Useful range for dac is 0-180 for 12V fans and 0-76 for 5V fans.
+        * Lower DAC values mean higher speeds.
+        */
+       return clamp_val(255 - (255 * dac) / DAC_LIMIT(v12), 0, 255);
+}
+
+static u8 pwm_to_dac(unsigned int pwm, bool v12)
+{
+       int limit = DAC_LIMIT(v12);
+
+       return limit - (limit * pwm) / 255;
+}
+
 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 reg, err = 0;
        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]);
+                       reg = i2c_smbus_read_byte_data(client, tach_reg[i]);
+                       if (reg < 0) {
+                               err = reg;
+                               goto error;
+                       }
+                       data->tach[i] = reg;
                }
-               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);
-
+               reg = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM);
+               if (reg < 0) {
+                       err = reg;
+                       goto error;
+               }
+               data->alarm |= reg;
                data->last_updated = jiffies;
-               data->valid = 1;
+               data->valid = true;
        }
 
+error:
        mutex_unlock(&data->update_lock);
-
+       if (err)
+               data = ERR_PTR(err);
        return data;
 }
 
@@ -199,26 +218,6 @@ static int max6650_set_operating_mode(struct max6650_data *data, u8 mode)
        return 0;
 }
 
-static ssize_t fan_show(struct device *dev, struct device_attribute *devattr,
-                       char *buf)
-{
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       struct max6650_data *data = max6650_update_device(dev);
-       int rpm;
-
-       /*
-        * Calculation details:
-        *
-        * Each tachometer counts over an interval given by the "count"
-        * register (0.25, 0.5, 1 or 2 seconds). This module assumes
-        * that the fans produce two pulses per revolution (this seems
-        * to be the most common).
-        */
-
-       rpm = ((data->tach[attr->index] * 120) / DIV_FROM_REG(data->count));
-       return sprintf(buf, "%d\n", rpm);
-}
-
 /*
  * Set the fan speed to the specified RPM (or read back the RPM setting).
  * This works in closed loop mode only. Use pwm1 for open loop speed setting.
@@ -260,26 +259,6 @@ static ssize_t fan_show(struct device *dev, struct device_attribute *devattr,
  * controlled.
  */
 
-static ssize_t fan1_target_show(struct device *dev,
-                               struct device_attribute *devattr, char *buf)
-{
-       struct max6650_data *data = max6650_update_device(dev);
-       int kscale, ktach, rpm;
-
-       /*
-        * Use the datasheet equation:
-        *
-        *    FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)]
-        *
-        * then multiply by 60 to give rpm.
-        */
-
-       kscale = DIV_FROM_REG(data->config);
-       ktach = data->speed;
-       rpm = 60 * kscale * clock / (256 * (ktach + 1));
-       return sprintf(buf, "%d\n", rpm);
-}
-
 static int max6650_set_target(struct max6650_data *data, unsigned long rpm)
 {
        int kscale, ktach;
@@ -308,197 +287,8 @@ static int max6650_set_target(struct max6650_data *data, unsigned long rpm)
                                         data->speed);
 }
 
-static ssize_t fan1_target_store(struct device *dev,
-                                struct device_attribute *devattr,
-                                const char *buf, size_t count)
-{
-       struct max6650_data *data = dev_get_drvdata(dev);
-       unsigned long rpm;
-       int err;
-
-       err = kstrtoul(buf, 10, &rpm);
-       if (err)
-               return err;
-
-       mutex_lock(&data->update_lock);
-
-       err = max6650_set_target(data, rpm);
-
-       mutex_unlock(&data->update_lock);
-
-       if (err < 0)
-               return err;
-
-       return count;
-}
-
-/*
- * Get/set the fan speed in open loop mode using pwm1 sysfs file.
- * Speed is given as a relative value from 0 to 255, where 255 is maximum
- * speed. Note that this is done by writing directly to the chip's DAC,
- * it won't change the closed loop speed set by fan1_target.
- * Also note that due to rounding errors it is possible that you don't read
- * back exactly the value you have set.
- */
-
-static ssize_t pwm1_show(struct device *dev, struct device_attribute *devattr,
-                        char *buf)
-{
-       int pwm;
-       struct max6650_data *data = max6650_update_device(dev);
-
-       /*
-        * Useful range for dac is 0-180 for 12V fans and 0-76 for 5V fans.
-        * Lower DAC values mean higher speeds.
-        */
-       if (data->config & MAX6650_CFG_V12)
-               pwm = 255 - (255 * (int)data->dac)/180;
-       else
-               pwm = 255 - (255 * (int)data->dac)/76;
-
-       if (pwm < 0)
-               pwm = 0;
-
-       return sprintf(buf, "%d\n", pwm);
-}
-
-static ssize_t pwm1_store(struct device *dev,
-                         struct device_attribute *devattr, const char *buf,
-                         size_t count)
-{
-       struct max6650_data *data = dev_get_drvdata(dev);
-       struct i2c_client *client = data->client;
-       unsigned long pwm;
-       int err;
-
-       err = kstrtoul(buf, 10, &pwm);
-       if (err)
-               return err;
-
-       pwm = clamp_val(pwm, 0, 255);
-
-       mutex_lock(&data->update_lock);
-
-       if (data->config & MAX6650_CFG_V12)
-               data->dac = 180 - (180 * pwm)/255;
-       else
-               data->dac = 76 - (76 * pwm)/255;
-       err = i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, data->dac);
-
-       mutex_unlock(&data->update_lock);
-
-       return err < 0 ? err : count;
-}
-
 /*
- * Get/Set controller mode:
- * Possible values:
- * 0 = Fan always on
- * 1 = Open loop, Voltage is set according to speed, not regulated.
- * 2 = Closed loop, RPM for all fans regulated by fan1 tachometer
- * 3 = Fan off
- */
-static ssize_t pwm1_enable_show(struct device *dev,
-                               struct device_attribute *devattr, char *buf)
-{
-       struct max6650_data *data = max6650_update_device(dev);
-       int mode = (data->config & MAX6650_CFG_MODE_MASK) >> 4;
-       int sysfs_modes[4] = {0, 3, 2, 1};
-
-       return sprintf(buf, "%d\n", sysfs_modes[mode]);
-}
-
-static ssize_t pwm1_enable_store(struct device *dev,
-                                struct device_attribute *devattr,
-                                const char *buf, size_t count)
-{
-       struct max6650_data *data = dev_get_drvdata(dev);
-       unsigned long mode;
-       int err;
-       const u8 max6650_modes[] = {
-               MAX6650_CFG_MODE_ON,
-               MAX6650_CFG_MODE_OPEN_LOOP,
-               MAX6650_CFG_MODE_CLOSED_LOOP,
-               MAX6650_CFG_MODE_OFF,
-               };
-
-       err = kstrtoul(buf, 10, &mode);
-       if (err)
-               return err;
-
-       if (mode >= ARRAY_SIZE(max6650_modes))
-               return -EINVAL;
-
-       mutex_lock(&data->update_lock);
-
-       max6650_set_operating_mode(data, max6650_modes[mode]);
-
-       mutex_unlock(&data->update_lock);
-
-       return count;
-}
-
-/*
- * Read/write functions for fan1_div sysfs file. The MAX6650 has no such
- * divider. We handle this by converting between divider and counttime:
- *
- * (counttime == k) <==> (divider == 2^k), k = 0, 1, 2, or 3
- *
- * Lower values of k allow to connect a faster fan without the risk of
- * counter overflow. The price is lower resolution. You can also set counttime
- * using the module parameter. Note that the module parameter "prescaler" also
- * influences the behaviour. Unfortunately, there's no sysfs attribute
- * defined for that. See the data sheet for details.
- */
-
-static ssize_t fan1_div_show(struct device *dev,
-                            struct device_attribute *devattr, char *buf)
-{
-       struct max6650_data *data = max6650_update_device(dev);
-
-       return sprintf(buf, "%d\n", DIV_FROM_REG(data->count));
-}
-
-static ssize_t fan1_div_store(struct device *dev,
-                             struct device_attribute *devattr,
-                             const char *buf, size_t count)
-{
-       struct max6650_data *data = dev_get_drvdata(dev);
-       struct i2c_client *client = data->client;
-       unsigned long div;
-       int err;
-
-       err = kstrtoul(buf, 10, &div);
-       if (err)
-               return err;
-
-       mutex_lock(&data->update_lock);
-       switch (div) {
-       case 1:
-               data->count = 0;
-               break;
-       case 2:
-               data->count = 1;
-               break;
-       case 4:
-               data->count = 2;
-               break;
-       case 8:
-               data->count = 3;
-               break;
-       default:
-               mutex_unlock(&data->update_lock);
-               return -EINVAL;
-       }
-
-       i2c_smbus_write_byte_data(client, MAX6650_REG_COUNT, data->count);
-       mutex_unlock(&data->update_lock);
-
-       return count;
-}
-
-/*
- * Get alarm stati:
+ * Get gpio alarm status:
  * Possible values:
  * 0 = no alarm
  * 1 = alarm
@@ -509,42 +299,30 @@ static ssize_t alarm_show(struct device *dev,
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct max6650_data *data = max6650_update_device(dev);
-       struct i2c_client *client = data->client;
-       int alarm = 0;
+       bool alarm;
 
-       if (data->alarm & attr->index) {
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       alarm = data->alarm & attr->index;
+       if (alarm) {
                mutex_lock(&data->update_lock);
-               alarm = 1;
                data->alarm &= ~attr->index;
-               data->alarm |= i2c_smbus_read_byte_data(client,
-                                                       MAX6650_REG_ALARM);
+               data->valid = false;
                mutex_unlock(&data->update_lock);
        }
 
        return sprintf(buf, "%d\n", alarm);
 }
 
-static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0);
-static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1);
-static SENSOR_DEVICE_ATTR_RO(fan3_input, fan, 2);
-static SENSOR_DEVICE_ATTR_RO(fan4_input, fan, 3);
-static DEVICE_ATTR_RW(fan1_target);
-static DEVICE_ATTR_RW(fan1_div);
-static DEVICE_ATTR_RW(pwm1_enable);
-static DEVICE_ATTR_RW(pwm1);
-static SENSOR_DEVICE_ATTR_RO(fan1_max_alarm, alarm, MAX6650_ALRM_MAX);
-static SENSOR_DEVICE_ATTR_RO(fan1_min_alarm, alarm, MAX6650_ALRM_MIN);
-static SENSOR_DEVICE_ATTR_RO(fan1_fault, alarm, MAX6650_ALRM_TACH);
 static SENSOR_DEVICE_ATTR_RO(gpio1_alarm, alarm, MAX6650_ALRM_GPIO1);
 static SENSOR_DEVICE_ATTR_RO(gpio2_alarm, alarm, MAX6650_ALRM_GPIO2);
 
 static umode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
-                                   int n)
+                                    int n)
 {
        struct device *dev = container_of(kobj, struct device, kobj);
        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;
 
        /*
@@ -552,12 +330,9 @@ static umode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
         */
 
        devattr = container_of(a, struct device_attribute, attr);
-       if (devattr == &sensor_dev_attr_fan1_max_alarm.dev_attr
-        || devattr == &sensor_dev_attr_fan1_min_alarm.dev_attr
-        || devattr == &sensor_dev_attr_fan1_fault.dev_attr
-        || devattr == &sensor_dev_attr_gpio1_alarm.dev_attr
-        || devattr == &sensor_dev_attr_gpio2_alarm.dev_attr) {
-               if (!(alarm_en & to_sensor_dev_attr(devattr)->index))
+       if (devattr == &sensor_dev_attr_gpio1_alarm.dev_attr ||
+           devattr == &sensor_dev_attr_gpio2_alarm.dev_attr) {
+               if (!(data->alarm_en & to_sensor_dev_attr(devattr)->index))
                        return 0;
        }
 
@@ -565,14 +340,6 @@ static umode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
 }
 
 static struct attribute *max6650_attrs[] = {
-       &sensor_dev_attr_fan1_input.dev_attr.attr,
-       &dev_attr_fan1_target.attr,
-       &dev_attr_fan1_div.attr,
-       &dev_attr_pwm1_enable.attr,
-       &dev_attr_pwm1.attr,
-       &sensor_dev_attr_fan1_max_alarm.dev_attr.attr,
-       &sensor_dev_attr_fan1_min_alarm.dev_attr.attr,
-       &sensor_dev_attr_fan1_fault.dev_attr.attr,
        &sensor_dev_attr_gpio1_alarm.dev_attr.attr,
        &sensor_dev_attr_gpio2_alarm.dev_attr.attr,
        NULL
@@ -583,27 +350,17 @@ static const struct attribute_group max6650_group = {
        .is_visible = max6650_attrs_visible,
 };
 
-static struct attribute *max6651_attrs[] = {
-       &sensor_dev_attr_fan2_input.dev_attr.attr,
-       &sensor_dev_attr_fan3_input.dev_attr.attr,
-       &sensor_dev_attr_fan4_input.dev_attr.attr,
+static const struct attribute_group *max6650_groups[] = {
+       &max6650_group,
        NULL
 };
 
-static const struct attribute_group max6651_group = {
-       .attrs = max6651_attrs,
-};
-
-/*
- * Real code
- */
-
 static int max6650_init_client(struct max6650_data *data,
                               struct i2c_client *client)
 {
        struct device *dev = &client->dev;
-       int config;
-       int err = -EIO;
+       int reg;
+       int err;
        u32 voltage;
        u32 prescale;
        u32 target_rpm;
@@ -617,21 +374,20 @@ static int max6650_init_client(struct max6650_data *data,
                                 &prescale))
                prescale = prescaler;
 
-       config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);
-
-       if (config < 0) {
-               dev_err(dev, "Error reading config, aborting.\n");
-               return err;
+       reg = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);
+       if (reg < 0) {
+               dev_err(dev, "Error reading config register, aborting.\n");
+               return reg;
        }
 
        switch (voltage) {
        case 0:
                break;
        case 5:
-               config &= ~MAX6650_CFG_V12;
+               reg &= ~MAX6650_CFG_V12;
                break;
        case 12:
-               config |= MAX6650_CFG_V12;
+               reg |= MAX6650_CFG_V12;
                break;
        default:
                dev_err(dev, "illegal value for fan_voltage (%d)\n", voltage);
@@ -641,22 +397,22 @@ static int max6650_init_client(struct max6650_data *data,
        case 0:
                break;
        case 1:
-               config &= ~MAX6650_CFG_PRESCALER_MASK;
+               reg &= ~MAX6650_CFG_PRESCALER_MASK;
                break;
        case 2:
-               config = (config & ~MAX6650_CFG_PRESCALER_MASK)
+               reg = (reg & ~MAX6650_CFG_PRESCALER_MASK)
                         | MAX6650_CFG_PRESCALER_2;
                break;
        case  4:
-               config = (config & ~MAX6650_CFG_PRESCALER_MASK)
+               reg = (reg & ~MAX6650_CFG_PRESCALER_MASK)
                         | MAX6650_CFG_PRESCALER_4;
                break;
        case  8:
-               config = (config & ~MAX6650_CFG_PRESCALER_MASK)
+               reg = (reg & ~MAX6650_CFG_PRESCALER_MASK)
                         | MAX6650_CFG_PRESCALER_8;
                break;
        case 16:
-               config = (config & ~MAX6650_CFG_PRESCALER_MASK)
+               reg = (reg & ~MAX6650_CFG_PRESCALER_MASK)
                         | MAX6650_CFG_PRESCALER_16;
                break;
        default:
@@ -664,16 +420,43 @@ static int max6650_init_client(struct max6650_data *data,
        }
 
        dev_info(dev, "Fan voltage: %dV, prescaler: %d.\n",
-                (config & MAX6650_CFG_V12) ? 12 : 5,
-                1 << (config & MAX6650_CFG_PRESCALER_MASK));
+                (reg & MAX6650_CFG_V12) ? 12 : 5,
+                1 << (reg & MAX6650_CFG_PRESCALER_MASK));
 
-       if (i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, config)) {
+       err = i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, reg);
+       if (err) {
                dev_err(dev, "Config write error, aborting.\n");
                return err;
        }
+       data->config = reg;
 
-       data->config = config;
-       data->count = i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT);
+       reg = i2c_smbus_read_byte_data(client, MAX6650_REG_SPEED);
+       if (reg < 0) {
+               dev_err(dev, "Failed to read speed register, aborting.\n");
+               return reg;
+       }
+       data->speed = reg;
+
+       reg = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
+       if (reg < 0) {
+               dev_err(dev, "Failed to read DAC register, aborting.\n");
+               return reg;
+       }
+       data->dac = reg;
+
+       reg = i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT);
+       if (reg < 0) {
+               dev_err(dev, "Failed to read count register, aborting.\n");
+               return reg;
+       }
+       data->count = reg;
+
+       reg = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN);
+       if (reg < 0) {
+               dev_err(dev, "Failed to read alarm configuration, aborting.\n");
+               return reg;
+       }
+       data->alarm_en = reg;
 
        if (!of_property_read_u32(client->dev.of_node, "maxim,fan-target-rpm",
                                  &target_rpm)) {
@@ -684,8 +467,6 @@ static int max6650_init_client(struct max6650_data *data,
        return 0;
 }
 
-#if IS_ENABLED(CONFIG_THERMAL)
-
 static int max6650_get_max_state(struct thermal_cooling_device *cdev,
                                 unsigned long *state)
 {
@@ -715,23 +496,18 @@ static int max6650_set_cur_state(struct thermal_cooling_device *cdev,
 
        mutex_lock(&data->update_lock);
 
-       if (data->config & MAX6650_CFG_V12)
-               data->dac = 180 - (180 * state)/255;
-       else
-               data->dac = 76 - (76 * state)/255;
-
+       data->dac = pwm_to_dac(state, data->config & MAX6650_CFG_V12);
        err = i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, data->dac);
-
        if (!err) {
                max6650_set_operating_mode(data, state ?
-                                                  MAX6650_CFG_MODE_OPEN_LOOP :
-                                                  MAX6650_CFG_MODE_OFF);
+                                          MAX6650_CFG_MODE_OPEN_LOOP :
+                                          MAX6650_CFG_MODE_OFF);
                data->cooling_dev_state = state;
        }
 
        mutex_unlock(&data->update_lock);
 
-       return err < 0 ? err : 0;
+       return err;
 }
 
 static const struct thermal_cooling_device_ops max6650_cooling_ops = {
@@ -739,11 +515,252 @@ static const struct thermal_cooling_device_ops max6650_cooling_ops = {
        .get_cur_state = max6650_get_cur_state,
        .set_cur_state = max6650_set_cur_state,
 };
-#endif
+
+static int max6650_read(struct device *dev, enum hwmon_sensor_types type,
+                       u32 attr, int channel, long *val)
+{
+       struct max6650_data *data = max6650_update_device(dev);
+       int mode;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       switch (type) {
+       case hwmon_pwm:
+               switch (attr) {
+               case hwmon_pwm_input:
+                       *val = dac_to_pwm(data->dac,
+                                         data->config & MAX6650_CFG_V12);
+                       break;
+               case hwmon_pwm_enable:
+                       /*
+                        * Possible values:
+                        * 0 = Fan always on
+                        * 1 = Open loop, Voltage is set according to speed,
+                        *     not regulated.
+                        * 2 = Closed loop, RPM for all fans regulated by fan1
+                        *     tachometer
+                        * 3 = Fan off
+                        */
+                       mode = (data->config & MAX6650_CFG_MODE_MASK) >> 4;
+                       *val = (4 - mode) & 3; /* {0 1 2 3} -> {0 3 2 1} */
+                       break;
+               default:
+                       return -EOPNOTSUPP;
+               }
+               break;
+       case hwmon_fan:
+               switch (attr) {
+               case hwmon_fan_input:
+                       /*
+                        * Calculation details:
+                        *
+                        * Each tachometer counts over an interval given by the
+                        * "count" register (0.25, 0.5, 1 or 2 seconds).
+                        * The driver assumes that the fans produce two pulses
+                        * per revolution (this seems to be the most common).
+                        */
+                       *val = DIV_ROUND_CLOSEST(data->tach[channel] * 120,
+                                                DIV_FROM_REG(data->count));
+                       break;
+               case hwmon_fan_div:
+                       *val = DIV_FROM_REG(data->count);
+                       break;
+               case hwmon_fan_target:
+                       /*
+                        * Use the datasheet equation:
+                        *    FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)]
+                        * then multiply by 60 to give rpm.
+                        */
+                       *val = 60 * DIV_FROM_REG(data->config) * clock /
+                               (256 * (data->speed + 1));
+                       break;
+               case hwmon_fan_min_alarm:
+                       *val = !!(data->alarm & MAX6650_ALRM_MIN);
+                       data->alarm &= ~MAX6650_ALRM_MIN;
+                       data->valid = false;
+                       break;
+               case hwmon_fan_max_alarm:
+                       *val = !!(data->alarm & MAX6650_ALRM_MAX);
+                       data->alarm &= ~MAX6650_ALRM_MAX;
+                       data->valid = false;
+                       break;
+               case hwmon_fan_fault:
+                       *val = !!(data->alarm & MAX6650_ALRM_TACH);
+                       data->alarm &= ~MAX6650_ALRM_TACH;
+                       data->valid = false;
+                       break;
+               default:
+                       return -EOPNOTSUPP;
+               }
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+static const u8 max6650_pwm_modes[] = {
+       MAX6650_CFG_MODE_ON,
+       MAX6650_CFG_MODE_OPEN_LOOP,
+       MAX6650_CFG_MODE_CLOSED_LOOP,
+       MAX6650_CFG_MODE_OFF,
+};
+
+static int max6650_write(struct device *dev, enum hwmon_sensor_types type,
+                        u32 attr, int channel, long val)
+{
+       struct max6650_data *data = dev_get_drvdata(dev);
+       int ret = 0;
+       u8 reg;
+
+       mutex_lock(&data->update_lock);
+
+       switch (type) {
+       case hwmon_pwm:
+               switch (attr) {
+               case hwmon_pwm_input:
+                       reg = pwm_to_dac(clamp_val(val, 0, 255),
+                                        data->config & MAX6650_CFG_V12);
+                       ret = i2c_smbus_write_byte_data(data->client,
+                                                       MAX6650_REG_DAC, reg);
+                       if (ret)
+                               break;
+                       data->dac = reg;
+                       break;
+               case hwmon_pwm_enable:
+                       if (val < 0 || val >= ARRAY_SIZE(max6650_pwm_modes)) {
+                               ret = -EINVAL;
+                               break;
+                       }
+                       ret = max6650_set_operating_mode(data,
+                                               max6650_pwm_modes[val]);
+                       break;
+               default:
+                       ret = -EOPNOTSUPP;
+                       break;
+               }
+               break;
+       case hwmon_fan:
+               switch (attr) {
+               case hwmon_fan_div:
+                       switch (val) {
+                       case 1:
+                               reg = 0;
+                               break;
+                       case 2:
+                               reg = 1;
+                               break;
+                       case 4:
+                               reg = 2;
+                               break;
+                       case 8:
+                               reg = 3;
+                               break;
+                       default:
+                               ret = -EINVAL;
+                               goto error;
+                       }
+                       ret = i2c_smbus_write_byte_data(data->client,
+                                                       MAX6650_REG_COUNT, reg);
+                       if (ret)
+                               break;
+                       data->count = reg;
+                       break;
+               case hwmon_fan_target:
+                       if (val < 0) {
+                               ret = -EINVAL;
+                               break;
+                       }
+                       ret = max6650_set_target(data, val);
+                       break;
+               default:
+                       ret = -EOPNOTSUPP;
+                       break;
+               }
+               break;
+       default:
+               ret = -EOPNOTSUPP;
+               break;
+       }
+
+error:
+       mutex_unlock(&data->update_lock);
+       return ret;
+}
+
+static umode_t max6650_is_visible(const void *_data,
+                                 enum hwmon_sensor_types type, u32 attr,
+                                 int channel)
+{
+       const struct max6650_data *data = _data;
+
+       if (channel && (channel >= data->nr_fans || type != hwmon_fan))
+               return 0;
+
+       switch (type) {
+       case hwmon_fan:
+               switch (attr) {
+               case hwmon_fan_input:
+                       return 0444;
+               case hwmon_fan_target:
+               case hwmon_fan_div:
+                       return 0644;
+               case hwmon_fan_min_alarm:
+                       if (data->alarm_en & MAX6650_ALRM_MIN)
+                               return 0444;
+                       break;
+               case hwmon_fan_max_alarm:
+                       if (data->alarm_en & MAX6650_ALRM_MAX)
+                               return 0444;
+                       break;
+               case hwmon_fan_fault:
+                       if (data->alarm_en & MAX6650_ALRM_TACH)
+                               return 0444;
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case hwmon_pwm:
+               switch (attr) {
+               case hwmon_pwm_input:
+               case hwmon_pwm_enable:
+                       return 0644;
+               default:
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static const struct hwmon_channel_info *max6650_info[] = {
+       HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_DIV |
+                          HWMON_F_MIN_ALARM | HWMON_F_MAX_ALARM |
+                          HWMON_F_FAULT,
+                          HWMON_F_INPUT, HWMON_F_INPUT, HWMON_F_INPUT),
+       HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
+       NULL
+};
+
+static const struct hwmon_ops max6650_hwmon_ops = {
+       .read = max6650_read,
+       .write = max6650_write,
+       .is_visible = max6650_is_visible,
+};
+
+static const struct hwmon_chip_info max6650_chip_info = {
+       .ops = &max6650_hwmon_ops,
+       .info = max6650_info,
+};
 
 static int max6650_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
+       struct thermal_cooling_device *cooling_dev;
        struct device *dev = &client->dev;
        const struct of_device_id *of_id =
                of_match_device(of_match_ptr(max6650_dt_match), dev);
@@ -767,37 +784,23 @@ static int max6650_probe(struct i2c_client *client,
        if (err)
                return err;
 
-       data->groups[0] = &max6650_group;
-       /* 3 additional fan inputs for the MAX6651 */
-       if (data->nr_fans == 4)
-               data->groups[1] = &max6651_group;
-
-       hwmon_dev = devm_hwmon_device_register_with_groups(dev,
-                                                          client->name, data,
-                                                          data->groups);
+       hwmon_dev = devm_hwmon_device_register_with_info(dev,
+                                                        client->name, data,
+                                                        &max6650_chip_info,
+                                                        max6650_groups);
        err = PTR_ERR_OR_ZERO(hwmon_dev);
        if (err)
                return err;
 
-#if IS_ENABLED(CONFIG_THERMAL)
-       data->cooling_dev =
-               thermal_of_cooling_device_register(client->dev.of_node,
-                                                  client->name, data,
-                                                  &max6650_cooling_ops);
-       if (IS_ERR(data->cooling_dev))
-               dev_warn(&client->dev,
-                        "thermal cooling device register failed: %ld\n",
-                        PTR_ERR(data->cooling_dev));
-#endif
-       return 0;
-}
-
-static int max6650_remove(struct i2c_client *client)
-{
-       struct max6650_data *data = i2c_get_clientdata(client);
-
-       if (!IS_ERR(data->cooling_dev))
-               thermal_cooling_device_unregister(data->cooling_dev);
+       if (IS_ENABLED(CONFIG_THERMAL)) {
+               cooling_dev = devm_thermal_of_cooling_device_register(dev,
+                                               dev->of_node, client->name,
+                                               data, &max6650_cooling_ops);
+               if (IS_ERR(cooling_dev)) {
+                       dev_warn(dev, "thermal cooling device register failed: %ld\n",
+                                PTR_ERR(cooling_dev));
+               }
+       }
 
        return 0;
 }
@@ -815,7 +818,6 @@ static struct i2c_driver max6650_driver = {
                .of_match_table = of_match_ptr(max6650_dt_match),
        },
        .probe          = max6650_probe,
-       .remove         = max6650_remove,
        .id_table       = max6650_id,
 };
 
index 58a9574..710c305 100644 (file)
@@ -4,6 +4,9 @@
  *
  * Copyright (c) 2015 Kontron
  * Author: Vadim V. Vlasov <vvlasov@dev.rtsoft.ru>
+ *
+ * Copyright (c) 2019 Advantech
+ * Author: Amy.Shih <amy.shih@advantech.com.tw>
  */
 
 #include <linux/module.h>
@@ -50,6 +53,8 @@
 #define T_CPU1_HV_REG          0xA0    /* Bank 0; 2 regs (HV/LV) per sensor */
 
 #define PRTS_REG               0x03    /* Bank 2 */
+#define PFE_REG                        0x00    /* Bank 2; PECI Function Enable */
+#define TSI_CTRL_REG           0x50    /* Bank 2; TSI Control Register */
 #define FANCTL1_FMR_REG                0x00    /* Bank 3; 1 reg per channel */
 #define FANCTL1_OUT_REG                0x10    /* Bank 3; 1 reg per channel */
 
@@ -65,6 +70,8 @@ struct nct7904_data {
        u32 vsen_mask;
        u32 tcpu_mask;
        u8 fan_mode[FANCTL_MAX];
+       u8 enable_dts;
+       u8 has_dts;
 };
 
 /* Access functions */
@@ -229,11 +236,15 @@ static int nct7904_read_temp(struct device *dev, u32 attr, int channel,
 
        switch (attr) {
        case hwmon_temp_input:
-               if (channel == 0)
+               if (channel == 4)
                        ret = nct7904_read_reg16(data, BANK_0, LTD_HV_REG);
+               else if (channel < 5)
+                       ret = nct7904_read_reg16(data, BANK_0,
+                                                TEMP_CH1_HV_REG + channel * 4);
                else
                        ret = nct7904_read_reg16(data, BANK_0,
-                                       T_CPU1_HV_REG + (channel - 1) * 2);
+                                                T_CPU1_HV_REG + (channel - 5)
+                                                * 2);
                if (ret < 0)
                        return ret;
                temp = ((ret & 0xff00) >> 5) | (ret & 0x7);
@@ -249,11 +260,11 @@ static umode_t nct7904_temp_is_visible(const void *_data, u32 attr, int channel)
        const struct nct7904_data *data = _data;
 
        if (attr == hwmon_temp_input) {
-               if (channel == 0) {
-                       if (data->vsen_mask & BIT(17))
+               if (channel < 5) {
+                       if (data->tcpu_mask & BIT(channel))
                                return 0444;
                } else {
-                       if (data->tcpu_mask & BIT(channel - 1))
+                       if (data->has_dts & BIT(channel - 5))
                                return 0444;
                }
        }
@@ -460,6 +471,7 @@ static int nct7904_probe(struct i2c_client *client,
        struct device *dev = &client->dev;
        int ret, i;
        u32 mask;
+       u8 val, bit;
 
        data = devm_kzalloc(dev, sizeof(struct nct7904_data), GFP_KERNEL);
        if (!data)
@@ -493,10 +505,65 @@ static int nct7904_probe(struct i2c_client *client,
        data->vsen_mask = mask;
 
        /* CPU_TEMP attributes */
-       ret = nct7904_read_reg16(data, BANK_0, DTS_T_CTRL0_REG);
+       ret = nct7904_read_reg(data, BANK_0, VT_ADC_CTRL0_REG);
+       if (ret < 0)
+               return ret;
+
+       if ((ret & 0x6) == 0x6)
+               data->tcpu_mask |= 1; /* TR1 */
+       if ((ret & 0x18) == 0x18)
+               data->tcpu_mask |= 2; /* TR2 */
+       if ((ret & 0x20) == 0x20)
+               data->tcpu_mask |= 4; /* TR3 */
+       if ((ret & 0x80) == 0x80)
+               data->tcpu_mask |= 8; /* TR4 */
+
+       /* LTD */
+       ret = nct7904_read_reg(data, BANK_0, VT_ADC_CTRL2_REG);
+       if (ret < 0)
+               return ret;
+       if ((ret & 0x02) == 0x02)
+               data->tcpu_mask |= 0x10;
+
+       /* Multi-Function detecting for Volt and TR/TD */
+       ret = nct7904_read_reg(data, BANK_0, VT_ADC_MD_REG);
        if (ret < 0)
                return ret;
-       data->tcpu_mask = ((ret >> 8) & 0xf) | ((ret & 0xf) << 4);
+
+       for (i = 0; i < 4; i++) {
+               val = (ret & (0x03 << i)) >> (i * 2);
+               bit = (1 << i);
+               if (val == 0)
+                       data->tcpu_mask &= ~bit;
+       }
+
+       /* PECI */
+       ret = nct7904_read_reg(data, BANK_2, PFE_REG);
+       if (ret < 0)
+               return ret;
+       if (ret & 0x80) {
+               data->enable_dts = 1; /* Enable DTS & PECI */
+       } else {
+               ret = nct7904_read_reg(data, BANK_2, TSI_CTRL_REG);
+               if (ret < 0)
+                       return ret;
+               if (ret & 0x80)
+                       data->enable_dts = 0x3; /* Enable DTS & TSI */
+       }
+
+       /* Check DTS enable status */
+       if (data->enable_dts) {
+               ret = nct7904_read_reg(data, BANK_0, DTS_T_CTRL0_REG);
+               if (ret < 0)
+                       return ret;
+               data->has_dts = ret & 0xF;
+               if (data->enable_dts & 0x2) {
+                       ret = nct7904_read_reg(data, BANK_0, DTS_T_CTRL1_REG);
+                       if (ret < 0)
+                               return ret;
+                       data->has_dts |= (ret & 0xF) << 4;
+               }
+       }
 
        for (i = 0; i < FANCTL_MAX; i++) {
                ret = nct7904_read_reg(data, BANK_3, FANCTL1_FMR_REG + i);
index 13a6290..a7d2b16 100644 (file)
@@ -124,12 +124,12 @@ struct extended_sensor {
 static int occ_poll(struct occ *occ)
 {
        int rc;
-       u16 checksum = occ->poll_cmd_data + 1;
+       u16 checksum = occ->poll_cmd_data + occ->seq_no + 1;
        u8 cmd[8];
        struct occ_poll_response_header *header;
 
        /* big endian */
-       cmd[0] = 0;                     /* sequence number */
+       cmd[0] = occ->seq_no++;         /* sequence number */
        cmd[1] = 0;                     /* cmd type */
        cmd[2] = 0;                     /* data length msb */
        cmd[3] = 1;                     /* data length lsb */
@@ -241,6 +241,12 @@ static ssize_t occ_show_temp_1(struct device *dev,
                val = get_unaligned_be16(&temp->sensor_id);
                break;
        case 1:
+               /*
+                * If a sensor reading has expired and couldn't be refreshed,
+                * OCC returns 0xFFFF for that sensor.
+                */
+               if (temp->value == 0xFFFF)
+                       return -EREMOTEIO;
                val = get_unaligned_be16(&temp->value) * 1000;
                break;
        default:
index fc13f3c..67e6968 100644 (file)
@@ -95,6 +95,7 @@ struct occ {
        struct occ_sensors sensors;
 
        int powr_sample_time_us;        /* average power sample time */
+       u8 seq_no;
        u8 poll_cmd_data;               /* to perform OCC poll command */
        int (*send_cmd)(struct occ *occ, u8 *cmd);
 
index 30751eb..b658848 100644 (file)
@@ -64,6 +64,15 @@ config SENSORS_IR38064
          This driver can also be built as a module. If so, the module will
          be called ir38064.
 
+config SENSORS_IRPS5401
+       tristate "Infineon IRPS5401"
+       help
+         If you say yes here you get hardware monitoring support for the
+         Infineon IRPS5401 controller.
+
+         This driver can also be built as a module. If so, the module will
+         be called irps5401.
+
 config SENSORS_ISL68137
        tristate "Intersil ISL68137"
        help
@@ -154,6 +163,15 @@ config SENSORS_MAX8688
          This driver can also be built as a module. If so, the module will
          be called max8688.
 
+config SENSORS_PXE1610
+       tristate "Infineon PXE1610"
+       help
+         If you say yes here you get hardware monitoring support for Infineon
+         PXE1610.
+
+         This driver can also be built as a module. If so, the module will
+         be called pxe1610.
+
 config SENSORS_TPS40422
        tristate "TI TPS40422"
        help
index 2219b93..c950ea9 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_SENSORS_ADM1275)   += adm1275.o
 obj-$(CONFIG_SENSORS_IBM_CFFPS)        += ibm-cffps.o
 obj-$(CONFIG_SENSORS_IR35221)  += ir35221.o
 obj-$(CONFIG_SENSORS_IR38064)  += ir38064.o
+obj-$(CONFIG_SENSORS_IRPS5401) += irps5401.o
 obj-$(CONFIG_SENSORS_ISL68137) += isl68137.o
 obj-$(CONFIG_SENSORS_LM25066)  += lm25066.o
 obj-$(CONFIG_SENSORS_LTC2978)  += ltc2978.o
@@ -18,6 +19,7 @@ obj-$(CONFIG_SENSORS_MAX20751)        += max20751.o
 obj-$(CONFIG_SENSORS_MAX31785) += max31785.o
 obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
 obj-$(CONFIG_SENSORS_MAX8688)  += max8688.o
+obj-$(CONFIG_SENSORS_PXE1610)  += pxe1610.o
 obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o
 obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o
 obj-$(CONFIG_SENSORS_UCD9000)  += ucd9000.o
index 82052b6..5caa37f 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/bitops.h>
+#include <linux/bitfield.h>
+#include <linux/log2.h>
 #include "pmbus.h"
 
 enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1293, adm1294 };
@@ -69,6 +71,18 @@ enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1293, adm1294 };
 #define ADM1075_VAUX_OV_WARN           BIT(7)
 #define ADM1075_VAUX_UV_WARN           BIT(6)
 
+#define ADM1275_VI_AVG_SHIFT           0
+#define ADM1275_VI_AVG_MASK            GENMASK(ADM1275_VI_AVG_SHIFT + 2, \
+                                               ADM1275_VI_AVG_SHIFT)
+#define ADM1275_SAMPLES_AVG_MAX                128
+
+#define ADM1278_PWR_AVG_SHIFT          11
+#define ADM1278_PWR_AVG_MASK           GENMASK(ADM1278_PWR_AVG_SHIFT + 2, \
+                                               ADM1278_PWR_AVG_SHIFT)
+#define ADM1278_VI_AVG_SHIFT           8
+#define ADM1278_VI_AVG_MASK            GENMASK(ADM1278_VI_AVG_SHIFT + 2, \
+                                               ADM1278_VI_AVG_SHIFT)
+
 struct adm1275_data {
        int id;
        bool have_oc_fault;
@@ -80,6 +94,7 @@ struct adm1275_data {
        bool have_pin_min;
        bool have_pin_max;
        bool have_temp_max;
+       bool have_power_sampling;
        struct pmbus_driver_info info;
 };
 
@@ -155,6 +170,62 @@ static const struct coefficients adm1293_coefficients[] = {
        [18] = { 7658, 0, -3 },         /* power, 21V, irange200 */
 };
 
+static int adm1275_read_pmon_config(const struct adm1275_data *data,
+                                   struct i2c_client *client, bool is_power)
+{
+       int shift, ret;
+       u16 mask;
+
+       /*
+        * The PMON configuration register is a 16-bit register only on chips
+        * supporting power average sampling. On other chips it is an 8-bit
+        * register.
+        */
+       if (data->have_power_sampling) {
+               ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG);
+               mask = is_power ? ADM1278_PWR_AVG_MASK : ADM1278_VI_AVG_MASK;
+               shift = is_power ? ADM1278_PWR_AVG_SHIFT : ADM1278_VI_AVG_SHIFT;
+       } else {
+               ret = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
+               mask = ADM1275_VI_AVG_MASK;
+               shift = ADM1275_VI_AVG_SHIFT;
+       }
+       if (ret < 0)
+               return ret;
+
+       return (ret & mask) >> shift;
+}
+
+static int adm1275_write_pmon_config(const struct adm1275_data *data,
+                                    struct i2c_client *client,
+                                    bool is_power, u16 word)
+{
+       int shift, ret;
+       u16 mask;
+
+       if (data->have_power_sampling) {
+               ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG);
+               mask = is_power ? ADM1278_PWR_AVG_MASK : ADM1278_VI_AVG_MASK;
+               shift = is_power ? ADM1278_PWR_AVG_SHIFT : ADM1278_VI_AVG_SHIFT;
+       } else {
+               ret = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
+               mask = ADM1275_VI_AVG_MASK;
+               shift = ADM1275_VI_AVG_SHIFT;
+       }
+       if (ret < 0)
+               return ret;
+
+       word = (ret & ~mask) | ((word << shift) & mask);
+       if (data->have_power_sampling)
+               ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG,
+                                               word);
+       else
+               ret = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONFIG,
+                                               word);
+
+       return ret;
+}
+
 static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
 {
        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
@@ -233,6 +304,21 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
                if (!data->have_temp_max)
                        return -ENXIO;
                break;
+       case PMBUS_VIRT_POWER_SAMPLES:
+               if (!data->have_power_sampling)
+                       return -ENXIO;
+               ret = adm1275_read_pmon_config(data, client, true);
+               if (ret < 0)
+                       break;
+               ret = BIT(ret);
+               break;
+       case PMBUS_VIRT_IN_SAMPLES:
+       case PMBUS_VIRT_CURR_SAMPLES:
+               ret = adm1275_read_pmon_config(data, client, false);
+               if (ret < 0)
+                       break;
+               ret = BIT(ret);
+               break;
        default:
                ret = -ENODATA;
                break;
@@ -277,6 +363,19 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
        case PMBUS_VIRT_RESET_TEMP_HISTORY:
                ret = pmbus_write_word_data(client, 0, ADM1278_PEAK_TEMP, 0);
                break;
+       case PMBUS_VIRT_POWER_SAMPLES:
+               if (!data->have_power_sampling)
+                       return -ENXIO;
+               word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX);
+               ret = adm1275_write_pmon_config(data, client, true,
+                                               ilog2(word));
+               break;
+       case PMBUS_VIRT_IN_SAMPLES:
+       case PMBUS_VIRT_CURR_SAMPLES:
+               word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX);
+               ret = adm1275_write_pmon_config(data, client, false,
+                                               ilog2(word));
+               break;
        default:
                ret = -ENODATA;
                break;
@@ -430,7 +529,8 @@ static int adm1275_probe(struct i2c_client *client,
        info->format[PSC_CURRENT_OUT] = direct;
        info->format[PSC_POWER] = direct;
        info->format[PSC_TEMPERATURE] = direct;
-       info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
+       info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
+                       PMBUS_HAVE_SAMPLES;
 
        info->read_word_data = adm1275_read_word_data;
        info->read_byte_data = adm1275_read_byte_data;
@@ -471,6 +571,7 @@ static int adm1275_probe(struct i2c_client *client,
                data->have_vout = true;
                data->have_pin_max = true;
                data->have_temp_max = true;
+               data->have_power_sampling = true;
 
                coefficients = adm1272_coefficients;
                vindex = (config & ADM1275_VRANGE) ? 1 : 0;
@@ -556,6 +657,7 @@ static int adm1275_probe(struct i2c_client *client,
                data->have_vout = true;
                data->have_pin_max = true;
                data->have_temp_max = true;
+               data->have_power_sampling = true;
 
                coefficients = adm1278_coefficients;
                vindex = 0;
@@ -591,6 +693,7 @@ static int adm1275_probe(struct i2c_client *client,
                data->have_pin_min = true;
                data->have_pin_max = true;
                data->have_mfr_vaux_status = true;
+               data->have_power_sampling = true;
 
                coefficients = adm1293_coefficients;
 
diff --git a/drivers/hwmon/pmbus/irps5401.c b/drivers/hwmon/pmbus/irps5401.c
new file mode 100644 (file)
index 0000000..d37daa0
--- /dev/null
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Hardware monitoring driver for the Infineon IRPS5401M PMIC.
+ *
+ * Copyright (c) 2019 SED Systems, a division of Calian Ltd.
+ *
+ * The device supports VOUT_PEAK, IOUT_PEAK, and TEMPERATURE_PEAK, however
+ * this driver does not currently support them.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include "pmbus.h"
+
+#define IRPS5401_SW_FUNC (PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | \
+                         PMBUS_HAVE_STATUS_INPUT | \
+                         PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | \
+                         PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | \
+                         PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | \
+                         PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP)
+
+#define IRPS5401_LDO_FUNC (PMBUS_HAVE_VIN | \
+                          PMBUS_HAVE_STATUS_INPUT | \
+                          PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | \
+                          PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | \
+                          PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | \
+                          PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP)
+
+static struct pmbus_driver_info irps5401_info = {
+       .pages = 5,
+       .func[0] = IRPS5401_SW_FUNC,
+       .func[1] = IRPS5401_SW_FUNC,
+       .func[2] = IRPS5401_SW_FUNC,
+       .func[3] = IRPS5401_SW_FUNC,
+       .func[4] = IRPS5401_LDO_FUNC,
+};
+
+static int irps5401_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
+{
+       return pmbus_do_probe(client, id, &irps5401_info);
+}
+
+static const struct i2c_device_id irps5401_id[] = {
+       {"irps5401", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, irps5401_id);
+
+static struct i2c_driver irps5401_driver = {
+       .driver = {
+                  .name = "irps5401",
+                  },
+       .probe = irps5401_probe,
+       .remove = pmbus_do_remove,
+       .id_table = irps5401_id,
+};
+
+module_i2c_driver(irps5401_driver);
+
+MODULE_AUTHOR("Robert Hancock");
+MODULE_DESCRIPTION("PMBus driver for Infineon IRPS5401");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/pmbus/pxe1610.c b/drivers/hwmon/pmbus/pxe1610.c
new file mode 100644 (file)
index 0000000..ebe3f02
--- /dev/null
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Hardware monitoring driver for Infineon PXE1610
+ *
+ * Copyright (c) 2019 Facebook Inc
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include "pmbus.h"
+
+#define PXE1610_NUM_PAGES 3
+
+/* Identify chip parameters. */
+static int pxe1610_identify(struct i2c_client *client,
+                            struct pmbus_driver_info *info)
+{
+       if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) {
+               u8 vout_mode;
+               int ret;
+
+               /* Read the register with VOUT scaling value.*/
+               ret = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
+               if (ret < 0)
+                       return ret;
+
+               vout_mode = ret & GENMASK(4, 0);
+
+               switch (vout_mode) {
+               case 1:
+                       info->vrm_version = vr12;
+                       break;
+               case 2:
+                       info->vrm_version = vr13;
+                       break;
+               default:
+                       return -ENODEV;
+               }
+       }
+
+       return 0;
+}
+
+static struct pmbus_driver_info pxe1610_info = {
+       .pages = PXE1610_NUM_PAGES,
+       .format[PSC_VOLTAGE_IN] = linear,
+       .format[PSC_VOLTAGE_OUT] = vid,
+       .format[PSC_CURRENT_IN] = linear,
+       .format[PSC_CURRENT_OUT] = linear,
+       .format[PSC_TEMPERATURE] = linear,
+       .format[PSC_POWER] = linear,
+       .func[0] = PMBUS_HAVE_VIN
+               | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
+               | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
+               | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
+               | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
+               | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
+       .func[1] = PMBUS_HAVE_VIN
+               | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
+               | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
+               | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
+               | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
+               | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
+       .func[2] = PMBUS_HAVE_VIN
+               | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
+               | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
+               | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
+               | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
+               | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
+       .identify = pxe1610_identify,
+};
+
+static int pxe1610_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
+{
+       struct pmbus_driver_info *info;
+       u8 buf[I2C_SMBUS_BLOCK_MAX];
+       int ret;
+
+       if (!i2c_check_functionality(
+                       client->adapter,
+                       I2C_FUNC_SMBUS_READ_BYTE_DATA
+                       | I2C_FUNC_SMBUS_READ_WORD_DATA
+                       | I2C_FUNC_SMBUS_READ_BLOCK_DATA))
+               return -ENODEV;
+
+       /*
+        * By default this device doesn't boot to page 0, so set page 0
+        * to access all pmbus registers.
+        */
+       i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
+
+       /* Read Manufacturer id */
+       ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed to read PMBUS_MFR_ID\n");
+               return ret;
+       }
+       if (ret != 2 || strncmp(buf, "XP", 2)) {
+               dev_err(&client->dev, "MFR_ID unrecognized\n");
+               return -ENODEV;
+       }
+
+       info = devm_kmemdup(&client->dev, &pxe1610_info,
+                           sizeof(struct pmbus_driver_info),
+                           GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       return pmbus_do_probe(client, id, info);
+}
+
+static const struct i2c_device_id pxe1610_id[] = {
+       {"pxe1610", 0},
+       {"pxe1110", 0},
+       {"pxm1310", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, pxe1610_id);
+
+static struct i2c_driver pxe1610_driver = {
+       .driver = {
+                       .name = "pxe1610",
+                       },
+       .probe = pxe1610_probe,
+       .remove = pmbus_do_remove,
+       .id_table = pxe1610_id,
+};
+
+module_i2c_driver(pxe1610_driver);
+
+MODULE_AUTHOR("Vijay Khemka <vijaykhemka@fb.com>");
+MODULE_DESCRIPTION("PMBus driver for Infineon PXE1610, PXE1110 and PXM1310");
+MODULE_LICENSE("GPL");
index 08c9b9f..54c0ff0 100644 (file)
@@ -320,8 +320,10 @@ static int pwm_fan_probe(struct platform_device *pdev)
                        dev_err(dev, "Failed to enable fan supply: %d\n", ret);
                        return ret;
                }
-               devm_add_action_or_reset(dev, pwm_fan_regulator_disable,
-                                        ctx->reg_en);
+               ret = devm_add_action_or_reset(dev, pwm_fan_regulator_disable,
+                                              ctx->reg_en);
+               if (ret)
+                       return ret;
        }
 
        ctx->pwm_value = MAX_PWM;
@@ -337,7 +339,9 @@ static int pwm_fan_probe(struct platform_device *pdev)
                return ret;
        }
        timer_setup(&ctx->rpm_timer, sample_timer, 0);
-       devm_add_action_or_reset(dev, pwm_fan_pwm_disable, ctx);
+       ret = devm_add_action_or_reset(dev, pwm_fan_pwm_disable, ctx);
+       if (ret)
+               return ret;
 
        of_property_read_u32(dev->of_node, "pulses-per-revolution", &ppr);
        ctx->pulses_per_revolution = ppr;
index 9bfa228..25aac40 100644 (file)
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * System Control and Power Interface(SCPI) based hwmon sensor driver
  *
  * Copyright (C) 2015 ARM Ltd.
  * Punit Agrawal <punit.agrawal@arm.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 express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
  */
 
 #include <linux/hwmon.h>
index cc6aca6..b637836 100644 (file)
@@ -351,6 +351,8 @@ static ssize_t fan_div_store(struct device *dev,
                tmp |= data->fan_div[2] << 4;
                smsc47m1_write_value(data, SMSC47M2_REG_FANDIV3, tmp);
                break;
+       default:
+               BUG();
        }
 
        /* Preserve fan min */
index 5487d4a..14638db 100644 (file)
@@ -4,6 +4,7 @@
 #
 menuconfig CORESIGHT
        bool "CoreSight Tracing Support"
+       depends on OF || ACPI
        select ARM_AMBA
        select PERF_EVENTS
        help
index 3b435aa..3c0ac42 100644 (file)
@@ -2,8 +2,7 @@
 #
 # Makefile for CoreSight drivers.
 #
-obj-$(CONFIG_CORESIGHT) += coresight.o coresight-etm-perf.o
-obj-$(CONFIG_OF) += of_coresight.o
+obj-$(CONFIG_CORESIGHT) += coresight.o coresight-etm-perf.o coresight-platform.o
 obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o \
                                             coresight-tmc-etf.o \
                                             coresight-tmc-etr.o
index 4ea68a3..16ebf38 100644 (file)
@@ -28,6 +28,8 @@
 #define catu_dbg(x, ...) do {} while (0)
 #endif
 
+DEFINE_CORESIGHT_DEVLIST(catu_devs, "catu");
+
 struct catu_etr_buf {
        struct tmc_sg_table *catu_table;
        dma_addr_t sladdr;
@@ -328,19 +330,18 @@ static int catu_alloc_etr_buf(struct tmc_drvdata *tmc_drvdata,
                              struct etr_buf *etr_buf, int node, void **pages)
 {
        struct coresight_device *csdev;
-       struct device *catu_dev;
        struct tmc_sg_table *catu_table;
        struct catu_etr_buf *catu_buf;
 
        csdev = tmc_etr_get_catu_device(tmc_drvdata);
        if (!csdev)
                return -ENODEV;
-       catu_dev = csdev->dev.parent;
        catu_buf = kzalloc(sizeof(*catu_buf), GFP_KERNEL);
        if (!catu_buf)
                return -ENOMEM;
 
-       catu_table = catu_init_sg_table(catu_dev, node, etr_buf->size, pages);
+       catu_table = catu_init_sg_table(&csdev->dev, node,
+                                       etr_buf->size, pages);
        if (IS_ERR(catu_table)) {
                kfree(catu_buf);
                return PTR_ERR(catu_table);
@@ -409,13 +410,14 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
        int rc;
        u32 control, mode;
        struct etr_buf *etr_buf = data;
+       struct device *dev = &drvdata->csdev->dev;
 
        if (catu_wait_for_ready(drvdata))
-               dev_warn(drvdata->dev, "Timeout while waiting for READY\n");
+               dev_warn(dev, "Timeout while waiting for READY\n");
 
        control = catu_read_control(drvdata);
        if (control & BIT(CATU_CONTROL_ENABLE)) {
-               dev_warn(drvdata->dev, "CATU is already enabled\n");
+               dev_warn(dev, "CATU is already enabled\n");
                return -EBUSY;
        }
 
@@ -441,7 +443,7 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
        catu_write_irqen(drvdata, 0);
        catu_write_mode(drvdata, mode);
        catu_write_control(drvdata, control);
-       dev_dbg(drvdata->dev, "Enabled in %s mode\n",
+       dev_dbg(dev, "Enabled in %s mode\n",
                (mode == CATU_MODE_PASS_THROUGH) ?
                "Pass through" :
                "Translate");
@@ -462,15 +464,16 @@ static int catu_enable(struct coresight_device *csdev, void *data)
 static int catu_disable_hw(struct catu_drvdata *drvdata)
 {
        int rc = 0;
+       struct device *dev = &drvdata->csdev->dev;
 
        catu_write_control(drvdata, 0);
        coresight_disclaim_device_unlocked(drvdata->base);
        if (catu_wait_for_ready(drvdata)) {
-               dev_info(drvdata->dev, "Timeout while waiting for READY\n");
+               dev_info(dev, "Timeout while waiting for READY\n");
                rc = -EAGAIN;
        }
 
-       dev_dbg(drvdata->dev, "Disabled\n");
+       dev_dbg(dev, "Disabled\n");
        return rc;
 }
 
@@ -502,17 +505,11 @@ static int catu_probe(struct amba_device *adev, const struct amba_id *id)
        struct coresight_desc catu_desc;
        struct coresight_platform_data *pdata = NULL;
        struct device *dev = &adev->dev;
-       struct device_node *np = dev->of_node;
        void __iomem *base;
 
-       if (np) {
-               pdata = of_get_coresight_platform_data(dev, np);
-               if (IS_ERR(pdata)) {
-                       ret = PTR_ERR(pdata);
-                       goto out;
-               }
-               dev->platform_data = pdata;
-       }
+       catu_desc.name = coresight_alloc_device_name(&catu_devs, dev);
+       if (!catu_desc.name)
+               return -ENOMEM;
 
        drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
        if (!drvdata) {
@@ -520,7 +517,6 @@ static int catu_probe(struct amba_device *adev, const struct amba_id *id)
                goto out;
        }
 
-       drvdata->dev = dev;
        dev_set_drvdata(dev, drvdata);
        base = devm_ioremap_resource(dev, &adev->res);
        if (IS_ERR(base)) {
@@ -547,6 +543,13 @@ static int catu_probe(struct amba_device *adev, const struct amba_id *id)
        if (ret)
                goto out;
 
+       pdata = coresight_get_platform_data(dev);
+       if (IS_ERR(pdata)) {
+               ret = PTR_ERR(pdata);
+               goto out;
+       }
+       dev->platform_data = pdata;
+
        drvdata->base = base;
        catu_desc.pdata = pdata;
        catu_desc.dev = dev;
@@ -554,6 +557,7 @@ static int catu_probe(struct amba_device *adev, const struct amba_id *id)
        catu_desc.type = CORESIGHT_DEV_TYPE_HELPER;
        catu_desc.subtype.helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_CATU;
        catu_desc.ops = &catu_ops;
+
        drvdata->csdev = coresight_register(&catu_desc);
        if (IS_ERR(drvdata->csdev))
                ret = PTR_ERR(drvdata->csdev);
index 1d2ad18..80ceee3 100644 (file)
@@ -61,7 +61,6 @@
 #define CATU_IRQEN_OFF         0x0
 
 struct catu_drvdata {
-       struct device *dev;
        void __iomem *base;
        struct coresight_device *csdev;
        int irq;
index e8819d7..2463aa7 100644 (file)
@@ -525,23 +525,12 @@ static const struct file_operations debug_func_knob_fops = {
 
 static int debug_func_init(void)
 {
-       struct dentry *file;
        int ret;
 
        /* Create debugfs node */
        debug_debugfs_dir = debugfs_create_dir("coresight_cpu_debug", NULL);
-       if (!debug_debugfs_dir) {
-               pr_err("%s: unable to create debugfs directory\n", __func__);
-               return -ENOMEM;
-       }
-
-       file = debugfs_create_file("enable", 0644, debug_debugfs_dir, NULL,
-                                  &debug_func_knob_fops);
-       if (!file) {
-               pr_err("%s: unable to create enable knob file\n", __func__);
-               ret = -ENOMEM;
-               goto err;
-       }
+       debugfs_create_file("enable", 0644, debug_debugfs_dir, NULL,
+                           &debug_func_knob_fops);
 
        /* Register function to be called for panic */
        ret = atomic_notifier_chain_register(&panic_notifier_list,
@@ -572,14 +561,16 @@ static int debug_probe(struct amba_device *adev, const struct amba_id *id)
        struct device *dev = &adev->dev;
        struct debug_drvdata *drvdata;
        struct resource *res = &adev->res;
-       struct device_node *np = adev->dev.of_node;
        int ret;
 
        drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
        if (!drvdata)
                return -ENOMEM;
 
-       drvdata->cpu = np ? of_coresight_get_cpu(np) : 0;
+       drvdata->cpu = coresight_get_cpu(dev);
+       if (drvdata->cpu < 0)
+               return drvdata->cpu;
+
        if (per_cpu(debug_drvdata, drvdata->cpu)) {
                dev_err(dev, "CPU%d drvdata has already been initialized\n",
                        drvdata->cpu);
index 4ee4c80..3810290 100644 (file)
 #define ETB_FFSR_BIT           1
 #define ETB_FRAME_SIZE_WORDS   4
 
+DEFINE_CORESIGHT_DEVLIST(etb_devs, "etb");
+
 /**
  * struct etb_drvdata - specifics associated to an ETB component
  * @base:      memory mapped base address for this component.
- * @dev:       the device entity associated to this component.
  * @atclk:     optional clock for the core parts of the ETB.
  * @csdev:     component vitals needed by the framework.
  * @miscdev:   specifics to handle "/dev/xyz.etb" entry.
@@ -81,7 +82,6 @@
  */
 struct etb_drvdata {
        void __iomem            *base;
-       struct device           *dev;
        struct clk              *atclk;
        struct coresight_device *csdev;
        struct miscdevice       miscdev;
@@ -227,7 +227,6 @@ out:
 static int etb_enable(struct coresight_device *csdev, u32 mode, void *data)
 {
        int ret;
-       struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
        switch (mode) {
        case CS_MODE_SYSFS:
@@ -244,13 +243,14 @@ static int etb_enable(struct coresight_device *csdev, u32 mode, void *data)
        if (ret)
                return ret;
 
-       dev_dbg(drvdata->dev, "ETB enabled\n");
+       dev_dbg(&csdev->dev, "ETB enabled\n");
        return 0;
 }
 
 static void __etb_disable_hw(struct etb_drvdata *drvdata)
 {
        u32 ffcr;
+       struct device *dev = &drvdata->csdev->dev;
 
        CS_UNLOCK(drvdata->base);
 
@@ -263,7 +263,7 @@ static void __etb_disable_hw(struct etb_drvdata *drvdata)
        writel_relaxed(ffcr, drvdata->base + ETB_FFCR);
 
        if (coresight_timeout(drvdata->base, ETB_FFCR, ETB_FFCR_BIT, 0)) {
-               dev_err(drvdata->dev,
+               dev_err(dev,
                "timeout while waiting for completion of Manual Flush\n");
        }
 
@@ -271,7 +271,7 @@ static void __etb_disable_hw(struct etb_drvdata *drvdata)
        writel_relaxed(0x0, drvdata->base + ETB_CTL_REG);
 
        if (coresight_timeout(drvdata->base, ETB_FFSR, ETB_FFSR_BIT, 1)) {
-               dev_err(drvdata->dev,
+               dev_err(dev,
                        "timeout while waiting for Formatter to Stop\n");
        }
 
@@ -286,6 +286,7 @@ static void etb_dump_hw(struct etb_drvdata *drvdata)
        u32 read_data, depth;
        u32 read_ptr, write_ptr;
        u32 frame_off, frame_endoff;
+       struct device *dev = &drvdata->csdev->dev;
 
        CS_UNLOCK(drvdata->base);
 
@@ -295,10 +296,10 @@ static void etb_dump_hw(struct etb_drvdata *drvdata)
        frame_off = write_ptr % ETB_FRAME_SIZE_WORDS;
        frame_endoff = ETB_FRAME_SIZE_WORDS - frame_off;
        if (frame_off) {
-               dev_err(drvdata->dev,
+               dev_err(dev,
                        "write_ptr: %lu not aligned to formatter frame size\n",
                        (unsigned long)write_ptr);
-               dev_err(drvdata->dev, "frameoff: %lu, frame_endoff: %lu\n",
+               dev_err(dev, "frameoff: %lu, frame_endoff: %lu\n",
                        (unsigned long)frame_off, (unsigned long)frame_endoff);
                write_ptr += frame_endoff;
        }
@@ -365,7 +366,7 @@ static int etb_disable(struct coresight_device *csdev)
        drvdata->mode = CS_MODE_DISABLED;
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
-       dev_dbg(drvdata->dev, "ETB disabled\n");
+       dev_dbg(&csdev->dev, "ETB disabled\n");
        return 0;
 }
 
@@ -373,12 +374,10 @@ static void *etb_alloc_buffer(struct coresight_device *csdev,
                              struct perf_event *event, void **pages,
                              int nr_pages, bool overwrite)
 {
-       int node, cpu = event->cpu;
+       int node;
        struct cs_buffers *buf;
 
-       if (cpu == -1)
-               cpu = smp_processor_id();
-       node = cpu_to_node(cpu);
+       node = (event->cpu == -1) ? NUMA_NO_NODE : cpu_to_node(event->cpu);
 
        buf = kzalloc_node(sizeof(struct cs_buffers), GFP_KERNEL, node);
        if (!buf)
@@ -460,7 +459,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
         * chance to fix things.
         */
        if (write_ptr % ETB_FRAME_SIZE_WORDS) {
-               dev_err(drvdata->dev,
+               dev_err(&csdev->dev,
                        "write_ptr: %lu not aligned to formatter frame size\n",
                        (unsigned long)write_ptr);
 
@@ -512,7 +511,13 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
                lost = true;
        }
 
-       if (lost)
+       /*
+        * Don't set the TRUNCATED flag in snapshot mode because 1) the
+        * captured buffer is expected to be truncated and 2) a full buffer
+        * prevents the event from being re-enabled by the perf core,
+        * resulting in stale data being send to user space.
+        */
+       if (!buf->snapshot && lost)
                perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
 
        /* finally tell HW where we want to start reading from */
@@ -548,13 +553,14 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
        writel_relaxed(0x0, drvdata->base + ETB_RAM_WRITE_POINTER);
 
        /*
-        * In snapshot mode we have to update the handle->head to point
-        * to the new location.
+        * In snapshot mode we simply increment the head by the number of byte
+        * that were written.  User space function  cs_etm_find_snapshot() will
+        * figure out how many bytes to get from the AUX buffer based on the
+        * position of the head.
         */
-       if (buf->snapshot) {
-               handle->head = (cur * PAGE_SIZE) + offset;
-               to_read = buf->nr_pages << PAGE_SHIFT;
-       }
+       if (buf->snapshot)
+               handle->head += to_read;
+
        __etb_enable_hw(drvdata);
        CS_LOCK(drvdata->base);
 out:
@@ -587,7 +593,7 @@ static void etb_dump(struct etb_drvdata *drvdata)
        }
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
-       dev_dbg(drvdata->dev, "ETB dumped\n");
+       dev_dbg(&drvdata->csdev->dev, "ETB dumped\n");
 }
 
 static int etb_open(struct inode *inode, struct file *file)
@@ -598,7 +604,7 @@ static int etb_open(struct inode *inode, struct file *file)
        if (local_cmpxchg(&drvdata->reading, 0, 1))
                return -EBUSY;
 
-       dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
+       dev_dbg(&drvdata->csdev->dev, "%s: successfully opened\n", __func__);
        return 0;
 }
 
@@ -608,6 +614,7 @@ static ssize_t etb_read(struct file *file, char __user *data,
        u32 depth;
        struct etb_drvdata *drvdata = container_of(file->private_data,
                                                   struct etb_drvdata, miscdev);
+       struct device *dev = &drvdata->csdev->dev;
 
        etb_dump(drvdata);
 
@@ -616,13 +623,14 @@ static ssize_t etb_read(struct file *file, char __user *data,
                len = depth * 4 - *ppos;
 
        if (copy_to_user(data, drvdata->buf + *ppos, len)) {
-               dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__);
+               dev_dbg(dev,
+                       "%s: copy_to_user failed\n", __func__);
                return -EFAULT;
        }
 
        *ppos += len;
 
-       dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n",
+       dev_dbg(dev, "%s: %zu bytes copied, %d bytes left\n",
                __func__, len, (int)(depth * 4 - *ppos));
        return len;
 }
@@ -633,7 +641,7 @@ static int etb_release(struct inode *inode, struct file *file)
                                                   struct etb_drvdata, miscdev);
        local_set(&drvdata->reading, 0);
 
-       dev_dbg(drvdata->dev, "%s: released\n", __func__);
+       dev_dbg(&drvdata->csdev->dev, "%s: released\n", __func__);
        return 0;
 }
 
@@ -724,20 +732,15 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id)
        struct etb_drvdata *drvdata;
        struct resource *res = &adev->res;
        struct coresight_desc desc = { 0 };
-       struct device_node *np = adev->dev.of_node;
 
-       if (np) {
-               pdata = of_get_coresight_platform_data(dev, np);
-               if (IS_ERR(pdata))
-                       return PTR_ERR(pdata);
-               adev->dev.platform_data = pdata;
-       }
+       desc.name = coresight_alloc_device_name(&etb_devs, dev);
+       if (!desc.name)
+               return -ENOMEM;
 
        drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
        if (!drvdata)
                return -ENOMEM;
 
-       drvdata->dev = &adev->dev;
        drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */
        if (!IS_ERR(drvdata->atclk)) {
                ret = clk_prepare_enable(drvdata->atclk);
@@ -768,6 +771,11 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id)
        /* This device is not associated with a session */
        drvdata->pid = -1;
 
+       pdata = coresight_get_platform_data(dev);
+       if (IS_ERR(pdata))
+               return PTR_ERR(pdata);
+       adev->dev.platform_data = pdata;
+
        desc.type = CORESIGHT_DEV_TYPE_SINK;
        desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
        desc.ops = &etb_cs_ops;
@@ -778,7 +786,7 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id)
        if (IS_ERR(drvdata->csdev))
                return PTR_ERR(drvdata->csdev);
 
-       drvdata->miscdev.name = pdata->name;
+       drvdata->miscdev.name = desc.name;
        drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
        drvdata->miscdev.fops = &etb_fops;
        ret = misc_register(&drvdata->miscdev);
index 3c62944..5c1ca0d 100644 (file)
@@ -523,7 +523,7 @@ int etm_perf_add_symlink_sink(struct coresight_device *csdev)
        unsigned long hash;
        const char *name;
        struct device *pmu_dev = etm_pmu.dev;
-       struct device *pdev = csdev->dev.parent;
+       struct device *dev = &csdev->dev;
        struct dev_ext_attribute *ea;
 
        if (csdev->type != CORESIGHT_DEV_TYPE_SINK &&
@@ -536,15 +536,15 @@ int etm_perf_add_symlink_sink(struct coresight_device *csdev)
        if (!etm_perf_up)
                return -EPROBE_DEFER;
 
-       ea = devm_kzalloc(pdev, sizeof(*ea), GFP_KERNEL);
+       ea = devm_kzalloc(dev, sizeof(*ea), GFP_KERNEL);
        if (!ea)
                return -ENOMEM;
 
-       name = dev_name(pdev);
+       name = dev_name(dev);
        /* See function coresight_get_sink_by_id() to know where this is used */
        hash = hashlen_hash(hashlen_string(NULL, name));
 
-       ea->attr.attr.name = devm_kstrdup(pdev, name, GFP_KERNEL);
+       ea->attr.attr.name = devm_kstrdup(dev, name, GFP_KERNEL);
        if (!ea->attr.attr.name)
                return -ENOMEM;
 
index 79e1ad8..f3ab96e 100644 (file)
@@ -208,7 +208,6 @@ struct etm_config {
 /**
  * struct etm_drvdata - specifics associated to an ETM component
  * @base:      memory mapped base address for this component.
- * @dev:       the device entity associated to this component.
  * @atclk:     optional clock for the core parts of the ETM.
  * @csdev:     component vitals needed by the framework.
  * @spinlock:  only one at a time pls.
@@ -232,7 +231,6 @@ struct etm_config {
  */
 struct etm_drvdata {
        void __iomem                    *base;
-       struct device                   *dev;
        struct clk                      *atclk;
        struct coresight_device         *csdev;
        spinlock_t                      spinlock;
@@ -260,7 +258,7 @@ static inline void etm_writel(struct etm_drvdata *drvdata,
 {
        if (drvdata->use_cp14) {
                if (etm_writel_cp14(off, val)) {
-                       dev_err(drvdata->dev,
+                       dev_err(&drvdata->csdev->dev,
                                "invalid CP14 access to ETM reg: %#x", off);
                }
        } else {
@@ -274,7 +272,7 @@ static inline unsigned int etm_readl(struct etm_drvdata *drvdata, u32 off)
 
        if (drvdata->use_cp14) {
                if (etm_readl_cp14(off, &val)) {
-                       dev_err(drvdata->dev,
+                       dev_err(&drvdata->csdev->dev,
                                "invalid CP14 access to ETM reg: %#x", off);
                }
        } else {
index 75487b3..e8c7649 100644 (file)
@@ -48,7 +48,7 @@ static ssize_t etmsr_show(struct device *dev,
        unsigned long flags, val;
        struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 
-       pm_runtime_get_sync(drvdata->dev);
+       pm_runtime_get_sync(dev->parent);
        spin_lock_irqsave(&drvdata->spinlock, flags);
        CS_UNLOCK(drvdata->base);
 
@@ -56,7 +56,7 @@ static ssize_t etmsr_show(struct device *dev,
 
        CS_LOCK(drvdata->base);
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
-       pm_runtime_put(drvdata->dev);
+       pm_runtime_put(dev->parent);
 
        return sprintf(buf, "%#lx\n", val);
 }
@@ -131,7 +131,7 @@ static ssize_t mode_store(struct device *dev,
 
        if (config->mode & ETM_MODE_STALL) {
                if (!(drvdata->etmccr & ETMCCR_FIFOFULL)) {
-                       dev_warn(drvdata->dev, "stall mode not supported\n");
+                       dev_warn(dev, "stall mode not supported\n");
                        ret = -EINVAL;
                        goto err_unlock;
                }
@@ -141,7 +141,7 @@ static ssize_t mode_store(struct device *dev,
 
        if (config->mode & ETM_MODE_TIMESTAMP) {
                if (!(drvdata->etmccer & ETMCCER_TIMESTAMP)) {
-                       dev_warn(drvdata->dev, "timestamp not supported\n");
+                       dev_warn(dev, "timestamp not supported\n");
                        ret = -EINVAL;
                        goto err_unlock;
                }
@@ -945,7 +945,7 @@ static ssize_t seq_curr_state_show(struct device *dev,
                goto out;
        }
 
-       pm_runtime_get_sync(drvdata->dev);
+       pm_runtime_get_sync(dev->parent);
        spin_lock_irqsave(&drvdata->spinlock, flags);
 
        CS_UNLOCK(drvdata->base);
@@ -953,7 +953,7 @@ static ssize_t seq_curr_state_show(struct device *dev,
        CS_LOCK(drvdata->base);
 
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
-       pm_runtime_put(drvdata->dev);
+       pm_runtime_put(dev->parent);
 out:
        return sprintf(buf, "%#lx\n", val);
 }
index be302ec..e2cb687 100644 (file)
@@ -165,7 +165,7 @@ static void etm_set_prog(struct etm_drvdata *drvdata)
         */
        isb();
        if (coresight_timeout_etm(drvdata, ETMSR, ETMSR_PROG_BIT, 1)) {
-               dev_err(drvdata->dev,
+               dev_err(&drvdata->csdev->dev,
                        "%s: timeout observed when probing at offset %#x\n",
                        __func__, ETMSR);
        }
@@ -184,7 +184,7 @@ static void etm_clr_prog(struct etm_drvdata *drvdata)
         */
        isb();
        if (coresight_timeout_etm(drvdata, ETMSR, ETMSR_PROG_BIT, 0)) {
-               dev_err(drvdata->dev,
+               dev_err(&drvdata->csdev->dev,
                        "%s: timeout observed when probing at offset %#x\n",
                        __func__, ETMSR);
        }
@@ -425,7 +425,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
 done:
        CS_LOCK(drvdata->base);
 
-       dev_dbg(drvdata->dev, "cpu: %d enable smp call done: %d\n",
+       dev_dbg(&drvdata->csdev->dev, "cpu: %d enable smp call done: %d\n",
                drvdata->cpu, rc);
        return rc;
 }
@@ -455,14 +455,16 @@ int etm_get_trace_id(struct etm_drvdata *drvdata)
 {
        unsigned long flags;
        int trace_id = -1;
+       struct device *etm_dev;
 
        if (!drvdata)
                goto out;
 
+       etm_dev = drvdata->csdev->dev.parent;
        if (!local_read(&drvdata->mode))
                return drvdata->traceid;
 
-       pm_runtime_get_sync(drvdata->dev);
+       pm_runtime_get_sync(etm_dev);
 
        spin_lock_irqsave(&drvdata->spinlock, flags);
 
@@ -471,7 +473,7 @@ int etm_get_trace_id(struct etm_drvdata *drvdata)
        CS_LOCK(drvdata->base);
 
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
-       pm_runtime_put(drvdata->dev);
+       pm_runtime_put(etm_dev);
 
 out:
        return trace_id;
@@ -526,7 +528,7 @@ static int etm_enable_sysfs(struct coresight_device *csdev)
        spin_unlock(&drvdata->spinlock);
 
        if (!ret)
-               dev_dbg(drvdata->dev, "ETM tracing enabled\n");
+               dev_dbg(&csdev->dev, "ETM tracing enabled\n");
        return ret;
 }
 
@@ -581,7 +583,8 @@ static void etm_disable_hw(void *info)
 
        CS_LOCK(drvdata->base);
 
-       dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
+       dev_dbg(&drvdata->csdev->dev,
+               "cpu: %d disable smp call done\n", drvdata->cpu);
 }
 
 static void etm_disable_perf(struct coresight_device *csdev)
@@ -628,7 +631,7 @@ static void etm_disable_sysfs(struct coresight_device *csdev)
        spin_unlock(&drvdata->spinlock);
        cpus_read_unlock();
 
-       dev_dbg(drvdata->dev, "ETM tracing disabled\n");
+       dev_dbg(&csdev->dev, "ETM tracing disabled\n");
 }
 
 static void etm_disable(struct coresight_device *csdev,
@@ -788,22 +791,12 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
        struct etm_drvdata *drvdata;
        struct resource *res = &adev->res;
        struct coresight_desc desc = { 0 };
-       struct device_node *np = adev->dev.of_node;
 
        drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
        if (!drvdata)
                return -ENOMEM;
 
-       if (np) {
-               pdata = of_get_coresight_platform_data(dev, np);
-               if (IS_ERR(pdata))
-                       return PTR_ERR(pdata);
-
-               adev->dev.platform_data = pdata;
-               drvdata->use_cp14 = of_property_read_bool(np, "arm,cp14");
-       }
-
-       drvdata->dev = &adev->dev;
+       drvdata->use_cp14 = fwnode_property_read_bool(dev->fwnode, "arm,cp14");
        dev_set_drvdata(dev, drvdata);
 
        /* Validity for the resource is already checked by the AMBA core */
@@ -822,7 +815,13 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
                        return ret;
        }
 
-       drvdata->cpu = pdata ? pdata->cpu : 0;
+       drvdata->cpu = coresight_get_cpu(dev);
+       if (drvdata->cpu < 0)
+               return drvdata->cpu;
+
+       desc.name  = devm_kasprintf(dev, GFP_KERNEL, "etm%d", drvdata->cpu);
+       if (!desc.name)
+               return -ENOMEM;
 
        cpus_read_lock();
        etmdrvdata[drvdata->cpu] = drvdata;
@@ -852,6 +851,13 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
        etm_init_trace_id(drvdata);
        etm_set_default(&drvdata->config);
 
+       pdata = coresight_get_platform_data(dev);
+       if (IS_ERR(pdata)) {
+               ret = PTR_ERR(pdata);
+               goto err_arch_supported;
+       }
+       adev->dev.platform_data = pdata;
+
        desc.type = CORESIGHT_DEV_TYPE_SOURCE;
        desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
        desc.ops = &etm_cs_ops;
@@ -871,7 +877,8 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
        }
 
        pm_runtime_put(&adev->dev);
-       dev_info(dev, "%s initialized\n", (char *)coresight_get_uci_data(id));
+       dev_info(&drvdata->csdev->dev,
+                "%s initialized\n", (char *)coresight_get_uci_data(id));
        if (boot_enable) {
                coresight_enable(drvdata->csdev);
                drvdata->boot_enable = true;
index 8bb0092..7bcac88 100644 (file)
@@ -88,6 +88,7 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
 {
        int i, rc;
        struct etmv4_config *config = &drvdata->config;
+       struct device *etm_dev = &drvdata->csdev->dev;
 
        CS_UNLOCK(drvdata->base);
 
@@ -102,7 +103,7 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
 
        /* wait for TRCSTATR.IDLE to go up */
        if (coresight_timeout(drvdata->base, TRCSTATR, TRCSTATR_IDLE_BIT, 1))
-               dev_err(drvdata->dev,
+               dev_err(etm_dev,
                        "timeout while waiting for Idle Trace Status\n");
 
        writel_relaxed(config->pe_sel, drvdata->base + TRCPROCSELR);
@@ -184,13 +185,13 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
 
        /* wait for TRCSTATR.IDLE to go back down to '0' */
        if (coresight_timeout(drvdata->base, TRCSTATR, TRCSTATR_IDLE_BIT, 0))
-               dev_err(drvdata->dev,
+               dev_err(etm_dev,
                        "timeout while waiting for Idle Trace Status\n");
 
 done:
        CS_LOCK(drvdata->base);
 
-       dev_dbg(drvdata->dev, "cpu: %d enable smp call done: %d\n",
+       dev_dbg(etm_dev, "cpu: %d enable smp call done: %d\n",
                drvdata->cpu, rc);
        return rc;
 }
@@ -400,7 +401,7 @@ static int etm4_enable_sysfs(struct coresight_device *csdev)
        spin_unlock(&drvdata->spinlock);
 
        if (!ret)
-               dev_dbg(drvdata->dev, "ETM tracing enabled\n");
+               dev_dbg(&csdev->dev, "ETM tracing enabled\n");
        return ret;
 }
 
@@ -461,7 +462,8 @@ static void etm4_disable_hw(void *info)
 
        CS_LOCK(drvdata->base);
 
-       dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
+       dev_dbg(&drvdata->csdev->dev,
+               "cpu: %d disable smp call done\n", drvdata->cpu);
 }
 
 static int etm4_disable_perf(struct coresight_device *csdev,
@@ -511,7 +513,7 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
        spin_unlock(&drvdata->spinlock);
        cpus_read_unlock();
 
-       dev_dbg(drvdata->dev, "ETM tracing disabled\n");
+       dev_dbg(&csdev->dev, "ETM tracing disabled\n");
 }
 
 static void etm4_disable(struct coresight_device *csdev,
@@ -1082,20 +1084,11 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
        struct etmv4_drvdata *drvdata;
        struct resource *res = &adev->res;
        struct coresight_desc desc = { 0 };
-       struct device_node *np = adev->dev.of_node;
 
        drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
        if (!drvdata)
                return -ENOMEM;
 
-       if (np) {
-               pdata = of_get_coresight_platform_data(dev, np);
-               if (IS_ERR(pdata))
-                       return PTR_ERR(pdata);
-               adev->dev.platform_data = pdata;
-       }
-
-       drvdata->dev = &adev->dev;
        dev_set_drvdata(dev, drvdata);
 
        /* Validity for the resource is already checked by the AMBA core */
@@ -1107,7 +1100,13 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
 
        spin_lock_init(&drvdata->spinlock);
 
-       drvdata->cpu = pdata ? pdata->cpu : 0;
+       drvdata->cpu = coresight_get_cpu(dev);
+       if (drvdata->cpu < 0)
+               return drvdata->cpu;
+
+       desc.name = devm_kasprintf(dev, GFP_KERNEL, "etm%d", drvdata->cpu);
+       if (!desc.name)
+               return -ENOMEM;
 
        cpus_read_lock();
        etmdrvdata[drvdata->cpu] = drvdata;
@@ -1138,6 +1137,13 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
        etm4_init_trace_id(drvdata);
        etm4_set_default(&drvdata->config);
 
+       pdata = coresight_get_platform_data(dev);
+       if (IS_ERR(pdata)) {
+               ret = PTR_ERR(pdata);
+               goto err_arch_supported;
+       }
+       adev->dev.platform_data = pdata;
+
        desc.type = CORESIGHT_DEV_TYPE_SOURCE;
        desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
        desc.ops = &etm4_cs_ops;
@@ -1157,7 +1163,7 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
        }
 
        pm_runtime_put(&adev->dev);
-       dev_info(dev, "CPU%d: ETM v%d.%d initialized\n",
+       dev_info(&drvdata->csdev->dev, "CPU%d: ETM v%d.%d initialized\n",
                 drvdata->cpu, drvdata->arch >> 4, drvdata->arch & 0xf);
 
        if (boot_enable) {
index 52786e9..4523f10 100644 (file)
@@ -284,7 +284,6 @@ struct etmv4_config {
 /**
  * struct etm4_drvdata - specifics associated to an ETM component
  * @base:       Memory mapped base address for this component.
- * @dev:        The device entity associated to this component.
  * @csdev:      Component vitals needed by the framework.
  * @spinlock:   Only one at a time pls.
  * @mode:      This tracer's mode, i.e sysFS, Perf or disabled.
@@ -340,7 +339,6 @@ struct etmv4_config {
  */
 struct etmv4_drvdata {
        void __iomem                    *base;
-       struct device                   *dev;
        struct coresight_device         *csdev;
        spinlock_t                      spinlock;
        local_t                         mode;
index 16b0c0e..fa97cb9 100644 (file)
 #define FUNNEL_HOLDTIME                (0x7 << FUNNEL_HOLDTIME_SHFT)
 #define FUNNEL_ENSx_MASK       0xff
 
+DEFINE_CORESIGHT_DEVLIST(funnel_devs, "funnel");
+
 /**
  * struct funnel_drvdata - specifics associated to a funnel component
  * @base:      memory mapped base address for this component.
- * @dev:       the device entity associated to this component.
  * @atclk:     optional clock for the core parts of the funnel.
  * @csdev:     component vitals needed by the framework.
  * @priority:  port selection order.
  */
 struct funnel_drvdata {
        void __iomem            *base;
-       struct device           *dev;
        struct clk              *atclk;
        struct coresight_device *csdev;
        unsigned long           priority;
@@ -80,7 +80,7 @@ static int funnel_enable(struct coresight_device *csdev, int inport,
                rc = dynamic_funnel_enable_hw(drvdata, inport);
 
        if (!rc)
-               dev_dbg(drvdata->dev, "FUNNEL inport %d enabled\n", inport);
+               dev_dbg(&csdev->dev, "FUNNEL inport %d enabled\n", inport);
        return rc;
 }
 
@@ -110,7 +110,7 @@ static void funnel_disable(struct coresight_device *csdev, int inport,
        if (drvdata->base)
                dynamic_funnel_disable_hw(drvdata, inport);
 
-       dev_dbg(drvdata->dev, "FUNNEL inport %d disabled\n", inport);
+       dev_dbg(&csdev->dev, "FUNNEL inport %d disabled\n", inport);
 }
 
 static const struct coresight_ops_link funnel_link_ops = {
@@ -165,11 +165,11 @@ static ssize_t funnel_ctrl_show(struct device *dev,
        u32 val;
        struct funnel_drvdata *drvdata = dev_get_drvdata(dev->parent);
 
-       pm_runtime_get_sync(drvdata->dev);
+       pm_runtime_get_sync(dev->parent);
 
        val = get_funnel_ctrl_hw(drvdata);
 
-       pm_runtime_put(drvdata->dev);
+       pm_runtime_put(dev->parent);
 
        return sprintf(buf, "%#x\n", val);
 }
@@ -189,23 +189,19 @@ static int funnel_probe(struct device *dev, struct resource *res)
        struct coresight_platform_data *pdata = NULL;
        struct funnel_drvdata *drvdata;
        struct coresight_desc desc = { 0 };
-       struct device_node *np = dev->of_node;
-
-       if (np) {
-               pdata = of_get_coresight_platform_data(dev, np);
-               if (IS_ERR(pdata))
-                       return PTR_ERR(pdata);
-               dev->platform_data = pdata;
-       }
 
-       if (of_device_is_compatible(np, "arm,coresight-funnel"))
+       if (is_of_node(dev_fwnode(dev)) &&
+           of_device_is_compatible(dev->of_node, "arm,coresight-funnel"))
                pr_warn_once("Uses OBSOLETE CoreSight funnel binding\n");
 
+       desc.name = coresight_alloc_device_name(&funnel_devs, dev);
+       if (!desc.name)
+               return -ENOMEM;
+
        drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
        if (!drvdata)
                return -ENOMEM;
 
-       drvdata->dev = dev;
        drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */
        if (!IS_ERR(drvdata->atclk)) {
                ret = clk_prepare_enable(drvdata->atclk);
@@ -229,6 +225,13 @@ static int funnel_probe(struct device *dev, struct resource *res)
 
        dev_set_drvdata(dev, drvdata);
 
+       pdata = coresight_get_platform_data(dev);
+       if (IS_ERR(pdata)) {
+               ret = PTR_ERR(pdata);
+               goto out_disable_clk;
+       }
+       dev->platform_data = pdata;
+
        desc.type = CORESIGHT_DEV_TYPE_LINK;
        desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG;
        desc.ops = &funnel_cs_ops;
@@ -241,6 +244,7 @@ static int funnel_probe(struct device *dev, struct resource *res)
        }
 
        pm_runtime_put(dev);
+       ret = 0;
 
 out_disable_clk:
        if (ret && !IS_ERR_OR_NULL(drvdata->atclk))
diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
new file mode 100644 (file)
index 0000000..dad7d96
--- /dev/null
@@ -0,0 +1,815 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/acpi.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_graph.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/amba/bus.h>
+#include <linux/coresight.h>
+#include <linux/cpumask.h>
+#include <asm/smp_plat.h>
+
+#include "coresight-priv.h"
+/*
+ * coresight_alloc_conns: Allocate connections record for each output
+ * port from the device.
+ */
+static int coresight_alloc_conns(struct device *dev,
+                                struct coresight_platform_data *pdata)
+{
+       if (pdata->nr_outport) {
+               pdata->conns = devm_kzalloc(dev, pdata->nr_outport *
+                                           sizeof(*pdata->conns),
+                                           GFP_KERNEL);
+               if (!pdata->conns)
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
+
+int coresight_device_fwnode_match(struct device *dev, const void *fwnode)
+{
+       return dev_fwnode(dev) == fwnode;
+}
+
+static struct device *
+coresight_find_device_by_fwnode(struct fwnode_handle *fwnode)
+{
+       struct device *dev = NULL;
+
+       /*
+        * If we have a non-configurable replicator, it will be found on the
+        * platform bus.
+        */
+       dev = bus_find_device(&platform_bus_type, NULL,
+                             fwnode, coresight_device_fwnode_match);
+       if (dev)
+               return dev;
+
+       /*
+        * We have a configurable component - circle through the AMBA bus
+        * looking for the device that matches the endpoint node.
+        */
+       return bus_find_device(&amba_bustype, NULL,
+                              fwnode, coresight_device_fwnode_match);
+}
+
+#ifdef CONFIG_OF
+static inline bool of_coresight_legacy_ep_is_input(struct device_node *ep)
+{
+       return of_property_read_bool(ep, "slave-mode");
+}
+
+static void of_coresight_get_ports_legacy(const struct device_node *node,
+                                         int *nr_inport, int *nr_outport)
+{
+       struct device_node *ep = NULL;
+       int in = 0, out = 0;
+
+       do {
+               ep = of_graph_get_next_endpoint(node, ep);
+               if (!ep)
+                       break;
+
+               if (of_coresight_legacy_ep_is_input(ep))
+                       in++;
+               else
+                       out++;
+
+       } while (ep);
+
+       *nr_inport = in;
+       *nr_outport = out;
+}
+
+static struct device_node *of_coresight_get_port_parent(struct device_node *ep)
+{
+       struct device_node *parent = of_graph_get_port_parent(ep);
+
+       /*
+        * Skip one-level up to the real device node, if we
+        * are using the new bindings.
+        */
+       if (of_node_name_eq(parent, "in-ports") ||
+           of_node_name_eq(parent, "out-ports"))
+               parent = of_get_next_parent(parent);
+
+       return parent;
+}
+
+static inline struct device_node *
+of_coresight_get_input_ports_node(const struct device_node *node)
+{
+       return of_get_child_by_name(node, "in-ports");
+}
+
+static inline struct device_node *
+of_coresight_get_output_ports_node(const struct device_node *node)
+{
+       return of_get_child_by_name(node, "out-ports");
+}
+
+static inline int
+of_coresight_count_ports(struct device_node *port_parent)
+{
+       int i = 0;
+       struct device_node *ep = NULL;
+
+       while ((ep = of_graph_get_next_endpoint(port_parent, ep)))
+               i++;
+       return i;
+}
+
+static void of_coresight_get_ports(const struct device_node *node,
+                                  int *nr_inport, int *nr_outport)
+{
+       struct device_node *input_ports = NULL, *output_ports = NULL;
+
+       input_ports = of_coresight_get_input_ports_node(node);
+       output_ports = of_coresight_get_output_ports_node(node);
+
+       if (input_ports || output_ports) {
+               if (input_ports) {
+                       *nr_inport = of_coresight_count_ports(input_ports);
+                       of_node_put(input_ports);
+               }
+               if (output_ports) {
+                       *nr_outport = of_coresight_count_ports(output_ports);
+                       of_node_put(output_ports);
+               }
+       } else {
+               /* Fall back to legacy DT bindings parsing */
+               of_coresight_get_ports_legacy(node, nr_inport, nr_outport);
+       }
+}
+
+static int of_coresight_get_cpu(struct device *dev)
+{
+       int cpu;
+       struct device_node *dn;
+
+       if (!dev->of_node)
+               return -ENODEV;
+
+       dn = of_parse_phandle(dev->of_node, "cpu", 0);
+       if (!dn)
+               return -ENODEV;
+
+       cpu = of_cpu_node_to_id(dn);
+       of_node_put(dn);
+
+       return cpu;
+}
+
+/*
+ * of_coresight_parse_endpoint : Parse the given output endpoint @ep
+ * and fill the connection information in @conn
+ *
+ * Parses the local port, remote device name and the remote port.
+ *
+ * Returns :
+ *      1      - If the parsing is successful and a connection record
+ *               was created for an output connection.
+ *      0      - If the parsing completed without any fatal errors.
+ *     -Errno  - Fatal error, abort the scanning.
+ */
+static int of_coresight_parse_endpoint(struct device *dev,
+                                      struct device_node *ep,
+                                      struct coresight_connection *conn)
+{
+       int ret = 0;
+       struct of_endpoint endpoint, rendpoint;
+       struct device_node *rparent = NULL;
+       struct device_node *rep = NULL;
+       struct device *rdev = NULL;
+       struct fwnode_handle *rdev_fwnode;
+
+       do {
+               /* Parse the local port details */
+               if (of_graph_parse_endpoint(ep, &endpoint))
+                       break;
+               /*
+                * Get a handle on the remote endpoint and the device it is
+                * attached to.
+                */
+               rep = of_graph_get_remote_endpoint(ep);
+               if (!rep)
+                       break;
+               rparent = of_coresight_get_port_parent(rep);
+               if (!rparent)
+                       break;
+               if (of_graph_parse_endpoint(rep, &rendpoint))
+                       break;
+
+               rdev_fwnode = of_fwnode_handle(rparent);
+               /* If the remote device is not available, defer probing */
+               rdev = coresight_find_device_by_fwnode(rdev_fwnode);
+               if (!rdev) {
+                       ret = -EPROBE_DEFER;
+                       break;
+               }
+
+               conn->outport = endpoint.port;
+               /*
+                * Hold the refcount to the target device. This could be
+                * released via:
+                * 1) coresight_release_platform_data() if the probe fails or
+                *    this device is unregistered.
+                * 2) While removing the target device via
+                *    coresight_remove_match()
+                */
+               conn->child_fwnode = fwnode_handle_get(rdev_fwnode);
+               conn->child_port = rendpoint.port;
+               /* Connection record updated */
+               ret = 1;
+       } while (0);
+
+       of_node_put(rparent);
+       of_node_put(rep);
+       put_device(rdev);
+
+       return ret;
+}
+
+static int of_get_coresight_platform_data(struct device *dev,
+                                         struct coresight_platform_data *pdata)
+{
+       int ret = 0;
+       struct coresight_connection *conn;
+       struct device_node *ep = NULL;
+       const struct device_node *parent = NULL;
+       bool legacy_binding = false;
+       struct device_node *node = dev->of_node;
+
+       /* Get the number of input and output port for this component */
+       of_coresight_get_ports(node, &pdata->nr_inport, &pdata->nr_outport);
+
+       /* If there are no output connections, we are done */
+       if (!pdata->nr_outport)
+               return 0;
+
+       ret = coresight_alloc_conns(dev, pdata);
+       if (ret)
+               return ret;
+
+       parent = of_coresight_get_output_ports_node(node);
+       /*
+        * If the DT uses obsoleted bindings, the ports are listed
+        * under the device and we need to filter out the input
+        * ports.
+        */
+       if (!parent) {
+               legacy_binding = true;
+               parent = node;
+               dev_warn_once(dev, "Uses obsolete Coresight DT bindings\n");
+       }
+
+       conn = pdata->conns;
+
+       /* Iterate through each output port to discover topology */
+       while ((ep = of_graph_get_next_endpoint(parent, ep))) {
+               /*
+                * Legacy binding mixes input/output ports under the
+                * same parent. So, skip the input ports if we are dealing
+                * with legacy binding, as they processed with their
+                * connected output ports.
+                */
+               if (legacy_binding && of_coresight_legacy_ep_is_input(ep))
+                       continue;
+
+               ret = of_coresight_parse_endpoint(dev, ep, conn);
+               switch (ret) {
+               case 1:
+                       conn++;         /* Fall through */
+               case 0:
+                       break;
+               default:
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+#else
+static inline int
+of_get_coresight_platform_data(struct device *dev,
+                              struct coresight_platform_data *pdata)
+{
+       return -ENOENT;
+}
+
+static inline int of_coresight_get_cpu(struct device *dev)
+{
+       return -ENODEV;
+}
+#endif
+
+#ifdef CONFIG_ACPI
+
+#include <acpi/actypes.h>
+#include <acpi/processor.h>
+
+/* ACPI Graph _DSD UUID : "ab02a46b-74c7-45a2-bd68-f7d344ef2153" */
+static const guid_t acpi_graph_uuid = GUID_INIT(0xab02a46b, 0x74c7, 0x45a2,
+                                               0xbd, 0x68, 0xf7, 0xd3,
+                                               0x44, 0xef, 0x21, 0x53);
+/* Coresight ACPI Graph UUID : "3ecbc8b6-1d0e-4fb3-8107-e627f805c6cd" */
+static const guid_t coresight_graph_uuid = GUID_INIT(0x3ecbc8b6, 0x1d0e, 0x4fb3,
+                                                    0x81, 0x07, 0xe6, 0x27,
+                                                    0xf8, 0x05, 0xc6, 0xcd);
+#define ACPI_CORESIGHT_LINK_SLAVE      0
+#define ACPI_CORESIGHT_LINK_MASTER     1
+
+static inline bool is_acpi_guid(const union acpi_object *obj)
+{
+       return (obj->type == ACPI_TYPE_BUFFER) && (obj->buffer.length == 16);
+}
+
+/*
+ * acpi_guid_matches   - Checks if the given object is a GUID object and
+ * that it matches the supplied the GUID.
+ */
+static inline bool acpi_guid_matches(const union acpi_object *obj,
+                                  const guid_t *guid)
+{
+       return is_acpi_guid(obj) &&
+              guid_equal((guid_t *)obj->buffer.pointer, guid);
+}
+
+static inline bool is_acpi_dsd_graph_guid(const union acpi_object *obj)
+{
+       return acpi_guid_matches(obj, &acpi_graph_uuid);
+}
+
+static inline bool is_acpi_coresight_graph_guid(const union acpi_object *obj)
+{
+       return acpi_guid_matches(obj, &coresight_graph_uuid);
+}
+
+static inline bool is_acpi_coresight_graph(const union acpi_object *obj)
+{
+       const union acpi_object *graphid, *guid, *links;
+
+       if (obj->type != ACPI_TYPE_PACKAGE ||
+           obj->package.count < 3)
+               return false;
+
+       graphid = &obj->package.elements[0];
+       guid = &obj->package.elements[1];
+       links = &obj->package.elements[2];
+
+       if (graphid->type != ACPI_TYPE_INTEGER ||
+           links->type != ACPI_TYPE_INTEGER)
+               return false;
+
+       return is_acpi_coresight_graph_guid(guid);
+}
+
+/*
+ * acpi_validate_dsd_graph     - Make sure the given _DSD graph conforms
+ * to the ACPI _DSD Graph specification.
+ *
+ * ACPI Devices Graph property has the following format:
+ *  {
+ *     Revision        - Integer, must be 0
+ *     NumberOfGraphs  - Integer, N indicating the following list.
+ *     Graph[1],
+ *      ...
+ *     Graph[N]
+ *  }
+ *
+ * And each Graph entry has the following format:
+ *  {
+ *     GraphID         - Integer, identifying a graph the device belongs to.
+ *     UUID            - UUID identifying the specification that governs
+ *                       this graph. (e.g, see is_acpi_coresight_graph())
+ *     NumberOfLinks   - Number "N" of connections on this node of the graph.
+ *     Links[1]
+ *     ...
+ *     Links[N]
+ *  }
+ *
+ * Where each "Links" entry has the following format:
+ *
+ * {
+ *     SourcePortAddress       - Integer
+ *     DestinationPortAddress  - Integer
+ *     DestinationDeviceName   - Reference to another device
+ *     ( --- CoreSight specific extensions below ---)
+ *     DirectionOfFlow         - Integer 1 for output(master)
+ *                               0 for input(slave)
+ * }
+ *
+ * e.g:
+ * For a Funnel device
+ *
+ * Device(MFUN) {
+ *   ...
+ *
+ *   Name (_DSD, Package() {
+ *     // DSD Package contains tuples of {  Proeprty_Type_UUID, Package() }
+ *     ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), //Std. Property UUID
+ *     Package() {
+ *             Package(2) { "property-name", <property-value> }
+ *     },
+ *
+ *     ToUUID("ab02a46b-74c7-45a2-bd68-f7d344ef2153"), // ACPI Graph UUID
+ *     Package() {
+ *       0,            // Revision
+ *       1,            // NumberOfGraphs.
+ *       Package() {   // Graph[0] Package
+ *          1,         // GraphID
+ *          // Coresight Graph UUID
+ *          ToUUID("3ecbc8b6-1d0e-4fb3-8107-e627f805c6cd"),
+ *          3,         // NumberOfLinks aka ports
+ *          // Link[0]: Output_0 -> Replicator:Input_0
+ *          Package () { 0, 0, \_SB_.RPL0, 1 },
+ *          // Link[1]: Input_0 <- Cluster0_Funnel0:Output_0
+ *          Package () { 0, 0, \_SB_.CLU0.FUN0, 0 },
+ *          // Link[2]: Input_1 <- Cluster1_Funnel0:Output_0
+ *           Package () { 1, 0, \_SB_.CLU1.FUN0, 0 },
+ *       }     // End of Graph[0] Package
+ *
+ *     }, // End of ACPI Graph Property
+ *  })
+ */
+static inline bool acpi_validate_dsd_graph(const union acpi_object *graph)
+{
+       int i, n;
+       const union acpi_object *rev, *nr_graphs;
+
+       /* The graph must contain at least the Revision and Number of Graphs */
+       if (graph->package.count < 2)
+               return false;
+
+       rev = &graph->package.elements[0];
+       nr_graphs = &graph->package.elements[1];
+
+       if (rev->type != ACPI_TYPE_INTEGER ||
+           nr_graphs->type != ACPI_TYPE_INTEGER)
+               return false;
+
+       /* We only support revision 0 */
+       if (rev->integer.value != 0)
+               return false;
+
+       n = nr_graphs->integer.value;
+       /* CoreSight devices are only part of a single Graph */
+       if (n != 1)
+               return false;
+
+       /* Make sure the ACPI graph package has right number of elements */
+       if (graph->package.count != (n + 2))
+               return false;
+
+       /*
+        * Each entry must be a graph package with at least 3 members :
+        * { GraphID, UUID, NumberOfLinks(n), Links[.],... }
+        */
+       for (i = 2; i < n + 2; i++) {
+               const union acpi_object *obj = &graph->package.elements[i];
+
+               if (obj->type != ACPI_TYPE_PACKAGE ||
+                   obj->package.count < 3)
+                       return false;
+       }
+
+       return true;
+}
+
+/* acpi_get_dsd_graph  - Find the _DSD Graph property for the given device. */
+const union acpi_object *
+acpi_get_dsd_graph(struct acpi_device *adev)
+{
+       int i;
+       struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+       acpi_status status;
+       const union acpi_object *dsd;
+
+       status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL,
+                                           &buf, ACPI_TYPE_PACKAGE);
+       if (ACPI_FAILURE(status))
+               return NULL;
+
+       dsd = buf.pointer;
+
+       /*
+        * _DSD property consists tuples { Prop_UUID, Package() }
+        * Iterate through all the packages and find the Graph.
+        */
+       for (i = 0; i + 1 < dsd->package.count; i += 2) {
+               const union acpi_object *guid, *package;
+
+               guid = &dsd->package.elements[i];
+               package = &dsd->package.elements[i + 1];
+
+               /* All _DSD elements must have a UUID and a Package */
+               if (!is_acpi_guid(guid) || package->type != ACPI_TYPE_PACKAGE)
+                       break;
+               /* Skip the non-Graph _DSD packages */
+               if (!is_acpi_dsd_graph_guid(guid))
+                       continue;
+               if (acpi_validate_dsd_graph(package))
+                       return package;
+               /* Invalid graph format, continue */
+               dev_warn(&adev->dev, "Invalid Graph _DSD property\n");
+       }
+
+       return NULL;
+}
+
+static inline bool
+acpi_validate_coresight_graph(const union acpi_object *cs_graph)
+{
+       int nlinks;
+
+       nlinks = cs_graph->package.elements[2].integer.value;
+       /*
+        * Graph must have the following fields :
+        * { GraphID, GraphUUID, NumberOfLinks, Links... }
+        */
+       if (cs_graph->package.count != (nlinks + 3))
+               return false;
+       /* The links are validated in acpi_coresight_parse_link() */
+       return true;
+}
+
+/*
+ * acpi_get_coresight_graph    - Parse the device _DSD tables and find
+ * the Graph property matching the CoreSight Graphs.
+ *
+ * Returns the pointer to the CoreSight Graph Package when found. Otherwise
+ * returns NULL.
+ */
+const union acpi_object *
+acpi_get_coresight_graph(struct acpi_device *adev)
+{
+       const union acpi_object *graph_list, *graph;
+       int i, nr_graphs;
+
+       graph_list = acpi_get_dsd_graph(adev);
+       if (!graph_list)
+               return graph_list;
+
+       nr_graphs = graph_list->package.elements[1].integer.value;
+
+       for (i = 2; i < nr_graphs + 2; i++) {
+               graph = &graph_list->package.elements[i];
+               if (!is_acpi_coresight_graph(graph))
+                       continue;
+               if (acpi_validate_coresight_graph(graph))
+                       return graph;
+               /* Invalid graph format */
+               break;
+       }
+
+       return NULL;
+}
+
+/*
+ * acpi_coresight_parse_link   - Parse the given Graph connection
+ * of the device and populate the coresight_connection for an output
+ * connection.
+ *
+ * CoreSight Graph specification mandates that the direction of the data
+ * flow must be specified in the link. i.e,
+ *
+ *     SourcePortAddress,      // Integer
+ *     DestinationPortAddress, // Integer
+ *     DestinationDeviceName,  // Reference to another device
+ *     DirectionOfFlow,        // 1 for output(master), 0 for input(slave)
+ *
+ * Returns the direction of the data flow [ Input(slave) or Output(master) ]
+ * upon success.
+ * Returns an negative error number otherwise.
+ */
+static int acpi_coresight_parse_link(struct acpi_device *adev,
+                                    const union acpi_object *link,
+                                    struct coresight_connection *conn)
+{
+       int rc, dir;
+       const union acpi_object *fields;
+       struct acpi_device *r_adev;
+       struct device *rdev;
+
+       if (link->type != ACPI_TYPE_PACKAGE ||
+           link->package.count != 4)
+               return -EINVAL;
+
+       fields = link->package.elements;
+
+       if (fields[0].type != ACPI_TYPE_INTEGER ||
+           fields[1].type != ACPI_TYPE_INTEGER ||
+           fields[2].type != ACPI_TYPE_LOCAL_REFERENCE ||
+           fields[3].type != ACPI_TYPE_INTEGER)
+               return -EINVAL;
+
+       rc = acpi_bus_get_device(fields[2].reference.handle, &r_adev);
+       if (rc)
+               return rc;
+
+       dir = fields[3].integer.value;
+       if (dir == ACPI_CORESIGHT_LINK_MASTER) {
+               conn->outport = fields[0].integer.value;
+               conn->child_port = fields[1].integer.value;
+               rdev = coresight_find_device_by_fwnode(&r_adev->fwnode);
+               if (!rdev)
+                       return -EPROBE_DEFER;
+               /*
+                * Hold the refcount to the target device. This could be
+                * released via:
+                * 1) coresight_release_platform_data() if the probe fails or
+                *    this device is unregistered.
+                * 2) While removing the target device via
+                *    coresight_remove_match().
+                */
+               conn->child_fwnode = fwnode_handle_get(&r_adev->fwnode);
+       }
+
+       return dir;
+}
+
+/*
+ * acpi_coresight_parse_graph  - Parse the _DSD CoreSight graph
+ * connection information and populate the supplied coresight_platform_data
+ * instance.
+ */
+static int acpi_coresight_parse_graph(struct acpi_device *adev,
+                                     struct coresight_platform_data *pdata)
+{
+       int rc, i, nlinks;
+       const union acpi_object *graph;
+       struct coresight_connection *conns, *ptr;
+
+       pdata->nr_inport = pdata->nr_outport = 0;
+       graph = acpi_get_coresight_graph(adev);
+       if (!graph)
+               return -ENOENT;
+
+       nlinks = graph->package.elements[2].integer.value;
+       if (!nlinks)
+               return 0;
+
+       /*
+        * To avoid scanning the table twice (once for finding the number of
+        * output links and then later for parsing the output links),
+        * cache the links information in one go and then later copy
+        * it to the pdata.
+        */
+       conns = devm_kcalloc(&adev->dev, nlinks, sizeof(*conns), GFP_KERNEL);
+       if (!conns)
+               return -ENOMEM;
+       ptr = conns;
+       for (i = 0; i < nlinks; i++) {
+               const union acpi_object *link = &graph->package.elements[3 + i];
+               int dir;
+
+               dir = acpi_coresight_parse_link(adev, link, ptr);
+               if (dir < 0)
+                       return dir;
+
+               if (dir == ACPI_CORESIGHT_LINK_MASTER) {
+                       pdata->nr_outport++;
+                       ptr++;
+               } else {
+                       pdata->nr_inport++;
+               }
+       }
+
+       rc = coresight_alloc_conns(&adev->dev, pdata);
+       if (rc)
+               return rc;
+
+       /* Copy the connection information to the final location */
+       for (i = 0; i < pdata->nr_outport; i++)
+               pdata->conns[i] = conns[i];
+
+       devm_kfree(&adev->dev, conns);
+       return 0;
+}
+
+/*
+ * acpi_handle_to_logical_cpuid - Map a given acpi_handle to the
+ * logical CPU id of the corresponding CPU device.
+ *
+ * Returns the logical CPU id when found. Otherwise returns >= nr_cpus_id.
+ */
+static int
+acpi_handle_to_logical_cpuid(acpi_handle handle)
+{
+       int i;
+       struct acpi_processor *pr;
+
+       for_each_possible_cpu(i) {
+               pr = per_cpu(processors, i);
+               if (pr && pr->handle == handle)
+                       break;
+       }
+
+       return i;
+}
+
+/*
+ * acpi_coresigh_get_cpu - Find the logical CPU id of the CPU associated
+ * with this coresight device. With ACPI bindings, the CoreSight components
+ * are listed as child device of the associated CPU.
+ *
+ * Returns the logical CPU id when found. Otherwise returns 0.
+ */
+static int acpi_coresight_get_cpu(struct device *dev)
+{
+       int cpu;
+       acpi_handle cpu_handle;
+       acpi_status status;
+       struct acpi_device *adev = ACPI_COMPANION(dev);
+
+       if (!adev)
+               return -ENODEV;
+       status = acpi_get_parent(adev->handle, &cpu_handle);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       cpu = acpi_handle_to_logical_cpuid(cpu_handle);
+       if (cpu >= nr_cpu_ids)
+               return -ENODEV;
+       return cpu;
+}
+
+static int
+acpi_get_coresight_platform_data(struct device *dev,
+                                struct coresight_platform_data *pdata)
+{
+       struct acpi_device *adev;
+
+       adev = ACPI_COMPANION(dev);
+       if (!adev)
+               return -EINVAL;
+
+       return acpi_coresight_parse_graph(adev, pdata);
+}
+
+#else
+
+static inline int
+acpi_get_coresight_platform_data(struct device *dev,
+                                struct coresight_platform_data *pdata)
+{
+       return -ENOENT;
+}
+
+static inline int acpi_coresight_get_cpu(struct device *dev)
+{
+       return -ENODEV;
+}
+#endif
+
+int coresight_get_cpu(struct device *dev)
+{
+       if (is_of_node(dev->fwnode))
+               return of_coresight_get_cpu(dev);
+       else if (is_acpi_device_node(dev->fwnode))
+               return acpi_coresight_get_cpu(dev);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(coresight_get_cpu);
+
+struct coresight_platform_data *
+coresight_get_platform_data(struct device *dev)
+{
+       int ret = -ENOENT;
+       struct coresight_platform_data *pdata = NULL;
+       struct fwnode_handle *fwnode = dev_fwnode(dev);
+
+       if (IS_ERR_OR_NULL(fwnode))
+               goto error;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata) {
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       if (is_of_node(fwnode))
+               ret = of_get_coresight_platform_data(dev, pdata);
+       else if (is_acpi_device_node(fwnode))
+               ret = acpi_get_coresight_platform_data(dev, pdata);
+
+       if (!ret)
+               return pdata;
+error:
+       if (!IS_ERR_OR_NULL(pdata))
+               /* Cleanup the connection information */
+               coresight_release_platform_data(pdata);
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(coresight_get_platform_data);
index e0684d0..7d40179 100644 (file)
@@ -200,4 +200,8 @@ static inline void *coresight_get_uci_data(const struct amba_id *id)
        return 0;
 }
 
+void coresight_release_platform_data(struct coresight_platform_data *pdata);
+
+int coresight_device_fwnode_match(struct device *dev, const void *fwnode);
+
 #endif
index 8c9ce74..b7d6d59 100644 (file)
@@ -5,6 +5,7 @@
  * Description: CoreSight Replicator driver
  */
 
+#include <linux/acpi.h>
 #include <linux/amba/bus.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
 #define REPLICATOR_IDFILTER0           0x000
 #define REPLICATOR_IDFILTER1           0x004
 
+DEFINE_CORESIGHT_DEVLIST(replicator_devs, "replicator");
+
 /**
  * struct replicator_drvdata - specifics associated to a replicator component
  * @base:      memory mapped base address for this component. Also indicates
  *             whether this one is programmable or not.
- * @dev:       the device entity associated with this component
  * @atclk:     optional clock for the core parts of the replicator.
  * @csdev:     component vitals needed by the framework
  */
 struct replicator_drvdata {
        void __iomem            *base;
-       struct device           *dev;
        struct clk              *atclk;
        struct coresight_device *csdev;
 };
@@ -100,7 +101,7 @@ static int replicator_enable(struct coresight_device *csdev, int inport,
        if (drvdata->base)
                rc = dynamic_replicator_enable(drvdata, inport, outport);
        if (!rc)
-               dev_dbg(drvdata->dev, "REPLICATOR enabled\n");
+               dev_dbg(&csdev->dev, "REPLICATOR enabled\n");
        return rc;
 }
 
@@ -139,7 +140,7 @@ static void replicator_disable(struct coresight_device *csdev, int inport,
 
        if (drvdata->base)
                dynamic_replicator_disable(drvdata, inport, outport);
-       dev_dbg(drvdata->dev, "REPLICATOR disabled\n");
+       dev_dbg(&csdev->dev, "REPLICATOR disabled\n");
 }
 
 static const struct coresight_ops_link replicator_link_ops = {
@@ -179,24 +180,20 @@ static int replicator_probe(struct device *dev, struct resource *res)
        struct coresight_platform_data *pdata = NULL;
        struct replicator_drvdata *drvdata;
        struct coresight_desc desc = { 0 };
-       struct device_node *np = dev->of_node;
        void __iomem *base;
 
-       if (np) {
-               pdata = of_get_coresight_platform_data(dev, np);
-               if (IS_ERR(pdata))
-                       return PTR_ERR(pdata);
-               dev->platform_data = pdata;
-       }
-
-       if (of_device_is_compatible(np, "arm,coresight-replicator"))
+       if (is_of_node(dev_fwnode(dev)) &&
+           of_device_is_compatible(dev->of_node, "arm,coresight-replicator"))
                pr_warn_once("Uses OBSOLETE CoreSight replicator binding\n");
 
+       desc.name = coresight_alloc_device_name(&replicator_devs, dev);
+       if (!desc.name)
+               return -ENOMEM;
+
        drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
        if (!drvdata)
                return -ENOMEM;
 
-       drvdata->dev = dev;
        drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */
        if (!IS_ERR(drvdata->atclk)) {
                ret = clk_prepare_enable(drvdata->atclk);
@@ -220,11 +217,19 @@ static int replicator_probe(struct device *dev, struct resource *res)
 
        dev_set_drvdata(dev, drvdata);
 
+       pdata = coresight_get_platform_data(dev);
+       if (IS_ERR(pdata)) {
+               ret = PTR_ERR(pdata);
+               goto out_disable_clk;
+       }
+       dev->platform_data = pdata;
+
        desc.type = CORESIGHT_DEV_TYPE_LINK;
        desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
        desc.ops = &replicator_cs_ops;
        desc.pdata = dev->platform_data;
        desc.dev = dev;
+
        drvdata->csdev = coresight_register(&desc);
        if (IS_ERR(drvdata->csdev)) {
                ret = PTR_ERR(drvdata->csdev);
@@ -292,11 +297,19 @@ static const struct of_device_id static_replicator_match[] = {
        {}
 };
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id static_replicator_acpi_ids[] = {
+       {"ARMHC985", 0}, /* ARM CoreSight Static Replicator */
+       {}
+};
+#endif
+
 static struct platform_driver static_replicator_driver = {
        .probe          = static_replicator_probe,
        .driver         = {
                .name   = "coresight-static-replicator",
-               .of_match_table = static_replicator_match,
+               .of_match_table = of_match_ptr(static_replicator_match),
+               .acpi_match_table = ACPI_PTR(static_replicator_acpi_ids),
                .pm     = &replicator_dev_pm_ops,
                .suppress_bind_attrs = true,
        },
index 9f8a844..b908ca1 100644 (file)
@@ -16,6 +16,7 @@
  * (C) 2015-2016 Chunyan Zhang <zhang.chunyan@linaro.org>
  */
 #include <asm/local.h>
+#include <linux/acpi.h>
 #include <linux/amba/bus.h>
 #include <linux/bitmap.h>
 #include <linux/clk.h>
@@ -107,10 +108,11 @@ struct channel_space {
        unsigned long           *guaranteed;
 };
 
+DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm");
+
 /**
  * struct stm_drvdata - specifics associated to an STM component
  * @base:              memory mapped base address for this component.
- * @dev:               the device entity associated to this component.
  * @atclk:             optional clock for the core parts of the STM.
  * @csdev:             component vitals needed by the framework.
  * @spinlock:          only one at a time pls.
@@ -128,7 +130,6 @@ struct channel_space {
  */
 struct stm_drvdata {
        void __iomem            *base;
-       struct device           *dev;
        struct clk              *atclk;
        struct coresight_device *csdev;
        spinlock_t              spinlock;
@@ -205,13 +206,13 @@ static int stm_enable(struct coresight_device *csdev,
        if (val)
                return -EBUSY;
 
-       pm_runtime_get_sync(drvdata->dev);
+       pm_runtime_get_sync(csdev->dev.parent);
 
        spin_lock(&drvdata->spinlock);
        stm_enable_hw(drvdata);
        spin_unlock(&drvdata->spinlock);
 
-       dev_dbg(drvdata->dev, "STM tracing enabled\n");
+       dev_dbg(&csdev->dev, "STM tracing enabled\n");
        return 0;
 }
 
@@ -271,10 +272,10 @@ static void stm_disable(struct coresight_device *csdev,
                /* Wait until the engine has completely stopped */
                coresight_timeout(drvdata->base, STMTCSR, STMTCSR_BUSY_BIT, 0);
 
-               pm_runtime_put(drvdata->dev);
+               pm_runtime_put(csdev->dev.parent);
 
                local_set(&drvdata->mode, CS_MODE_DISABLED);
-               dev_dbg(drvdata->dev, "STM tracing disabled\n");
+               dev_dbg(&csdev->dev, "STM tracing disabled\n");
        }
 }
 
@@ -685,14 +686,15 @@ static const struct attribute_group *coresight_stm_groups[] = {
        NULL,
 };
 
-static int stm_get_resource_byname(struct device_node *np,
-                                  char *ch_base, struct resource *res)
+#ifdef CONFIG_OF
+static int of_stm_get_stimulus_area(struct device *dev, struct resource *res)
 {
        const char *name = NULL;
        int index = 0, found = 0;
+       struct device_node *np = dev->of_node;
 
        while (!of_property_read_string_index(np, "reg-names", index, &name)) {
-               if (strcmp(ch_base, name)) {
+               if (strcmp("stm-stimulus-base", name)) {
                        index++;
                        continue;
                }
@@ -707,6 +709,70 @@ static int stm_get_resource_byname(struct device_node *np,
 
        return of_address_to_resource(np, index, res);
 }
+#else
+static inline int of_stm_get_stimulus_area(struct device *dev,
+                                          struct resource *res)
+{
+       return -ENOENT;
+}
+#endif
+
+#ifdef CONFIG_ACPI
+static int acpi_stm_get_stimulus_area(struct device *dev, struct resource *res)
+{
+       int rc;
+       bool found_base = false;
+       struct resource_entry *rent;
+       LIST_HEAD(res_list);
+
+       struct acpi_device *adev = ACPI_COMPANION(dev);
+
+       if (!adev)
+               return -ENODEV;
+       rc = acpi_dev_get_resources(adev, &res_list, NULL, NULL);
+       if (rc < 0)
+               return rc;
+
+       /*
+        * The stimulus base for STM device must be listed as the second memory
+        * resource, followed by the programming base address as described in
+        * "Section 2.3 Resources" in ACPI for CoreSightTM 1.0 Platform Design
+        * document (DEN0067).
+        */
+       rc = -ENOENT;
+       list_for_each_entry(rent, &res_list, node) {
+               if (resource_type(rent->res) != IORESOURCE_MEM)
+                       continue;
+               if (found_base) {
+                       *res = *rent->res;
+                       rc = 0;
+                       break;
+               }
+
+               found_base = true;
+       }
+
+       acpi_dev_free_resource_list(&res_list);
+       return rc;
+}
+#else
+static inline int acpi_stm_get_stimulus_area(struct device *dev,
+                                            struct resource *res)
+{
+       return -ENOENT;
+}
+#endif
+
+static int stm_get_stimulus_area(struct device *dev, struct resource *res)
+{
+       struct fwnode_handle *fwnode = dev_fwnode(dev);
+
+       if (is_of_node(fwnode))
+               return of_stm_get_stimulus_area(dev, res);
+       else if (is_acpi_node(fwnode))
+               return acpi_stm_get_stimulus_area(dev, res);
+       return -ENOENT;
+}
 
 static u32 stm_fundamental_data_size(struct stm_drvdata *drvdata)
 {
@@ -763,9 +829,10 @@ static void stm_init_default_data(struct stm_drvdata *drvdata)
        bitmap_clear(drvdata->chs.guaranteed, 0, drvdata->numsp);
 }
 
-static void stm_init_generic_data(struct stm_drvdata *drvdata)
+static void stm_init_generic_data(struct stm_drvdata *drvdata,
+                                 const char *name)
 {
-       drvdata->stm.name = dev_name(drvdata->dev);
+       drvdata->stm.name = name;
 
        /*
         * MasterIDs are assigned at HW design phase. As such the core is
@@ -795,19 +862,15 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
        struct resource ch_res;
        size_t bitmap_size;
        struct coresight_desc desc = { 0 };
-       struct device_node *np = adev->dev.of_node;
 
-       if (np) {
-               pdata = of_get_coresight_platform_data(dev, np);
-               if (IS_ERR(pdata))
-                       return PTR_ERR(pdata);
-               adev->dev.platform_data = pdata;
-       }
+       desc.name = coresight_alloc_device_name(&stm_devs, dev);
+       if (!desc.name)
+               return -ENOMEM;
+
        drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
        if (!drvdata)
                return -ENOMEM;
 
-       drvdata->dev = &adev->dev;
        drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */
        if (!IS_ERR(drvdata->atclk)) {
                ret = clk_prepare_enable(drvdata->atclk);
@@ -821,7 +884,7 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
                return PTR_ERR(base);
        drvdata->base = base;
 
-       ret = stm_get_resource_byname(np, "stm-stimulus-base", &ch_res);
+       ret = stm_get_stimulus_area(dev, &ch_res);
        if (ret)
                return ret;
        drvdata->chs.phys = ch_res.start;
@@ -848,14 +911,22 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
        spin_lock_init(&drvdata->spinlock);
 
        stm_init_default_data(drvdata);
-       stm_init_generic_data(drvdata);
+       stm_init_generic_data(drvdata, desc.name);
 
        if (stm_register_device(dev, &drvdata->stm, THIS_MODULE)) {
                dev_info(dev,
-                        "stm_register_device failed, probing deferred\n");
+                        "%s : stm_register_device failed, probing deferred\n",
+                        desc.name);
                return -EPROBE_DEFER;
        }
 
+       pdata = coresight_get_platform_data(dev);
+       if (IS_ERR(pdata)) {
+               ret = PTR_ERR(pdata);
+               goto stm_unregister;
+       }
+       adev->dev.platform_data = pdata;
+
        desc.type = CORESIGHT_DEV_TYPE_SOURCE;
        desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE;
        desc.ops = &stm_cs_ops;
@@ -870,7 +941,8 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
 
        pm_runtime_put(&adev->dev);
 
-       dev_info(dev, "%s initialized\n", (char *)coresight_get_uci_data(id));
+       dev_info(&drvdata->csdev->dev, "%s initialized\n",
+                (char *)coresight_get_uci_data(id));
        return 0;
 
 stm_unregister:
index 2527b5d..23b7ff0 100644 (file)
@@ -280,7 +280,6 @@ static int tmc_enable_etf_sink(struct coresight_device *csdev,
                               u32 mode, void *data)
 {
        int ret;
-       struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
        switch (mode) {
        case CS_MODE_SYSFS:
@@ -298,7 +297,7 @@ static int tmc_enable_etf_sink(struct coresight_device *csdev,
        if (ret)
                return ret;
 
-       dev_dbg(drvdata->dev, "TMC-ETB/ETF enabled\n");
+       dev_dbg(&csdev->dev, "TMC-ETB/ETF enabled\n");
        return 0;
 }
 
@@ -328,7 +327,7 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev)
 
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
-       dev_dbg(drvdata->dev, "TMC-ETB/ETF disabled\n");
+       dev_dbg(&csdev->dev, "TMC-ETB/ETF disabled\n");
        return 0;
 }
 
@@ -351,7 +350,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
        if (!ret)
-               dev_dbg(drvdata->dev, "TMC-ETF enabled\n");
+               dev_dbg(&csdev->dev, "TMC-ETF enabled\n");
        return ret;
 }
 
@@ -371,19 +370,17 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
        drvdata->mode = CS_MODE_DISABLED;
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
-       dev_dbg(drvdata->dev, "TMC-ETF disabled\n");
+       dev_dbg(&csdev->dev, "TMC-ETF disabled\n");
 }
 
 static void *tmc_alloc_etf_buffer(struct coresight_device *csdev,
                                  struct perf_event *event, void **pages,
                                  int nr_pages, bool overwrite)
 {
-       int node, cpu = event->cpu;
+       int node;
        struct cs_buffers *buf;
 
-       if (cpu == -1)
-               cpu = smp_processor_id();
-       node = cpu_to_node(cpu);
+       node = (event->cpu == -1) ? NUMA_NO_NODE : cpu_to_node(event->cpu);
 
        /* Allocate memory structure for interaction with Perf */
        buf = kzalloc_node(sizeof(struct cs_buffers), GFP_KERNEL, node);
@@ -477,9 +474,11 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
        /*
         * The TMC RAM buffer may be bigger than the space available in the
         * perf ring buffer (handle->size).  If so advance the RRP so that we
-        * get the latest trace data.
+        * get the latest trace data.  In snapshot mode none of that matters
+        * since we are expected to clobber stale data in favour of the latest
+        * traces.
         */
-       if (to_read > handle->size) {
+       if (!buf->snapshot && to_read > handle->size) {
                u32 mask = 0;
 
                /*
@@ -516,7 +515,13 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
                lost = true;
        }
 
-       if (lost)
+       /*
+        * Don't set the TRUNCATED flag in snapshot mode because 1) the
+        * captured buffer is expected to be truncated and 2) a full buffer
+        * prevents the event from being re-enabled by the perf core,
+        * resulting in stale data being send to user space.
+        */
+       if (!buf->snapshot && lost)
                perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
 
        cur = buf->cur;
@@ -542,11 +547,15 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
                }
        }
 
-       /* In snapshot mode we have to update the head */
-       if (buf->snapshot) {
-               handle->head = (cur * PAGE_SIZE) + offset;
-               to_read = buf->nr_pages << PAGE_SHIFT;
-       }
+       /*
+        * In snapshot mode we simply increment the head by the number of byte
+        * that were written.  User space function  cs_etm_find_snapshot() will
+        * figure out how many bytes to get from the AUX buffer based on the
+        * position of the head.
+        */
+       if (buf->snapshot)
+               handle->head += to_read;
+
        CS_LOCK(drvdata->base);
 out:
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
index df6e4b0..1700670 100644 (file)
@@ -162,10 +162,11 @@ static void tmc_pages_free(struct tmc_pages *tmc_pages,
                           struct device *dev, enum dma_data_direction dir)
 {
        int i;
+       struct device *real_dev = dev->parent;
 
        for (i = 0; i < tmc_pages->nr_pages; i++) {
                if (tmc_pages->daddrs && tmc_pages->daddrs[i])
-                       dma_unmap_page(dev, tmc_pages->daddrs[i],
+                       dma_unmap_page(real_dev, tmc_pages->daddrs[i],
                                         PAGE_SIZE, dir);
                if (tmc_pages->pages && tmc_pages->pages[i])
                        __free_page(tmc_pages->pages[i]);
@@ -193,6 +194,7 @@ static int tmc_pages_alloc(struct tmc_pages *tmc_pages,
        int i, nr_pages;
        dma_addr_t paddr;
        struct page *page;
+       struct device *real_dev = dev->parent;
 
        nr_pages = tmc_pages->nr_pages;
        tmc_pages->daddrs = kcalloc(nr_pages, sizeof(*tmc_pages->daddrs),
@@ -216,8 +218,8 @@ static int tmc_pages_alloc(struct tmc_pages *tmc_pages,
                        page = alloc_pages_node(node,
                                                GFP_KERNEL | __GFP_ZERO, 0);
                }
-               paddr = dma_map_page(dev, page, 0, PAGE_SIZE, dir);
-               if (dma_mapping_error(dev, paddr))
+               paddr = dma_map_page(real_dev, page, 0, PAGE_SIZE, dir);
+               if (dma_mapping_error(real_dev, paddr))
                        goto err;
                tmc_pages->daddrs[i] = paddr;
                tmc_pages->pages[i] = page;
@@ -304,7 +306,7 @@ static int tmc_alloc_data_pages(struct tmc_sg_table *sg_table, void **pages)
  * and data buffers. TMC writes to the data buffers and reads from the SG
  * Table pages.
  *
- * @dev                - Device to which page should be DMA mapped.
+ * @dev                - Coresight device to which page should be DMA mapped.
  * @node       - Numa node for mem allocations
  * @nr_tpages  - Number of pages for the table entries.
  * @nr_dpages  - Number of pages for Data buffer.
@@ -348,13 +350,13 @@ void tmc_sg_table_sync_data_range(struct tmc_sg_table *table,
 {
        int i, index, start;
        int npages = DIV_ROUND_UP(size, PAGE_SIZE);
-       struct device *dev = table->dev;
+       struct device *real_dev = table->dev->parent;
        struct tmc_pages *data = &table->data_pages;
 
        start = offset >> PAGE_SHIFT;
        for (i = start; i < (start + npages); i++) {
                index = i % data->nr_pages;
-               dma_sync_single_for_cpu(dev, data->daddrs[index],
+               dma_sync_single_for_cpu(real_dev, data->daddrs[index],
                                        PAGE_SIZE, DMA_FROM_DEVICE);
        }
 }
@@ -363,11 +365,11 @@ void tmc_sg_table_sync_data_range(struct tmc_sg_table *table,
 void tmc_sg_table_sync_table(struct tmc_sg_table *sg_table)
 {
        int i;
-       struct device *dev = sg_table->dev;
+       struct device *real_dev = sg_table->dev->parent;
        struct tmc_pages *table_pages = &sg_table->table_pages;
 
        for (i = 0; i < table_pages->nr_pages; i++)
-               dma_sync_single_for_device(dev, table_pages->daddrs[i],
+               dma_sync_single_for_device(real_dev, table_pages->daddrs[i],
                                           PAGE_SIZE, DMA_TO_DEVICE);
 }
 
@@ -590,6 +592,7 @@ static int tmc_etr_alloc_flat_buf(struct tmc_drvdata *drvdata,
                                  void **pages)
 {
        struct etr_flat_buf *flat_buf;
+       struct device *real_dev = drvdata->csdev->dev.parent;
 
        /* We cannot reuse existing pages for flat buf */
        if (pages)
@@ -599,7 +602,7 @@ static int tmc_etr_alloc_flat_buf(struct tmc_drvdata *drvdata,
        if (!flat_buf)
                return -ENOMEM;
 
-       flat_buf->vaddr = dma_alloc_coherent(drvdata->dev, etr_buf->size,
+       flat_buf->vaddr = dma_alloc_coherent(real_dev, etr_buf->size,
                                             &flat_buf->daddr, GFP_KERNEL);
        if (!flat_buf->vaddr) {
                kfree(flat_buf);
@@ -607,7 +610,7 @@ static int tmc_etr_alloc_flat_buf(struct tmc_drvdata *drvdata,
        }
 
        flat_buf->size = etr_buf->size;
-       flat_buf->dev = drvdata->dev;
+       flat_buf->dev = &drvdata->csdev->dev;
        etr_buf->hwaddr = flat_buf->daddr;
        etr_buf->mode = ETR_MODE_FLAT;
        etr_buf->private = flat_buf;
@@ -618,9 +621,12 @@ static void tmc_etr_free_flat_buf(struct etr_buf *etr_buf)
 {
        struct etr_flat_buf *flat_buf = etr_buf->private;
 
-       if (flat_buf && flat_buf->daddr)
-               dma_free_coherent(flat_buf->dev, flat_buf->size,
+       if (flat_buf && flat_buf->daddr) {
+               struct device *real_dev = flat_buf->dev->parent;
+
+               dma_free_coherent(real_dev, flat_buf->size,
                                  flat_buf->vaddr, flat_buf->daddr);
+       }
        kfree(flat_buf);
 }
 
@@ -666,8 +672,9 @@ static int tmc_etr_alloc_sg_buf(struct tmc_drvdata *drvdata,
                                void **pages)
 {
        struct etr_sg_table *etr_table;
+       struct device *dev = &drvdata->csdev->dev;
 
-       etr_table = tmc_init_etr_sg_table(drvdata->dev, node,
+       etr_table = tmc_init_etr_sg_table(dev, node,
                                          etr_buf->size, pages);
        if (IS_ERR(etr_table))
                return -ENOMEM;
@@ -751,8 +758,8 @@ tmc_etr_get_catu_device(struct tmc_drvdata *drvdata)
        if (!IS_ENABLED(CONFIG_CORESIGHT_CATU))
                return NULL;
 
-       for (i = 0; i < etr->nr_outport; i++) {
-               tmp = etr->conns[i].child_dev;
+       for (i = 0; i < etr->pdata->nr_outport; i++) {
+               tmp = etr->pdata->conns[i].child_dev;
                if (tmp && coresight_is_catu_device(tmp))
                        return tmp;
        }
@@ -823,9 +830,10 @@ static struct etr_buf *tmc_alloc_etr_buf(struct tmc_drvdata *drvdata,
        bool has_etr_sg, has_iommu;
        bool has_sg, has_catu;
        struct etr_buf *etr_buf;
+       struct device *dev = &drvdata->csdev->dev;
 
        has_etr_sg = tmc_etr_has_cap(drvdata, TMC_ETR_SG);
-       has_iommu = iommu_get_domain_for_dev(drvdata->dev);
+       has_iommu = iommu_get_domain_for_dev(dev->parent);
        has_catu = !!tmc_etr_get_catu_device(drvdata);
 
        has_sg = has_catu || has_etr_sg;
@@ -863,7 +871,7 @@ static struct etr_buf *tmc_alloc_etr_buf(struct tmc_drvdata *drvdata,
                return ERR_PTR(rc);
        }
 
-       dev_dbg(drvdata->dev, "allocated buffer of size %ldKB in mode %d\n",
+       dev_dbg(dev, "allocated buffer of size %ldKB in mode %d\n",
                (unsigned long)size >> 10, etr_buf->mode);
        return etr_buf;
 }
@@ -1162,7 +1170,7 @@ out:
                tmc_etr_free_sysfs_buf(free_buf);
 
        if (!ret)
-               dev_dbg(drvdata->dev, "TMC-ETR enabled\n");
+               dev_dbg(&csdev->dev, "TMC-ETR enabled\n");
 
        return ret;
 }
@@ -1178,14 +1186,11 @@ static struct etr_buf *
 alloc_etr_buf(struct tmc_drvdata *drvdata, struct perf_event *event,
              int nr_pages, void **pages, bool snapshot)
 {
-       int node, cpu = event->cpu;
+       int node;
        struct etr_buf *etr_buf;
        unsigned long size;
 
-       if (cpu == -1)
-               cpu = smp_processor_id();
-       node = cpu_to_node(cpu);
-
+       node = (event->cpu == -1) ? NUMA_NO_NODE : cpu_to_node(event->cpu);
        /*
         * Try to match the perf ring buffer size if it is larger
         * than the size requested via sysfs.
@@ -1317,13 +1322,11 @@ static struct etr_perf_buffer *
 tmc_etr_setup_perf_buf(struct tmc_drvdata *drvdata, struct perf_event *event,
                       int nr_pages, void **pages, bool snapshot)
 {
-       int node, cpu = event->cpu;
+       int node;
        struct etr_buf *etr_buf;
        struct etr_perf_buffer *etr_perf;
 
-       if (cpu == -1)
-               cpu = smp_processor_id();
-       node = cpu_to_node(cpu);
+       node = (event->cpu == -1) ? NUMA_NO_NODE : cpu_to_node(event->cpu);
 
        etr_perf = kzalloc_node(sizeof(*etr_perf), GFP_KERNEL, node);
        if (!etr_perf)
@@ -1358,7 +1361,7 @@ static void *tmc_alloc_etr_buffer(struct coresight_device *csdev,
        etr_perf = tmc_etr_setup_perf_buf(drvdata, event,
                                          nr_pages, pages, snapshot);
        if (IS_ERR(etr_perf)) {
-               dev_dbg(drvdata->dev, "Unable to allocate ETR buffer\n");
+               dev_dbg(&csdev->dev, "Unable to allocate ETR buffer\n");
                return NULL;
        }
 
@@ -1501,18 +1504,23 @@ tmc_update_etr_buffer(struct coresight_device *csdev,
        tmc_etr_sync_perf_buffer(etr_perf);
 
        /*
-        * Update handle->head in snapshot mode. Also update the size to the
-        * hardware buffer size if there was an overflow.
+        * In snapshot mode we simply increment the head by the number of byte
+        * that were written.  User space function  cs_etm_find_snapshot() will
+        * figure out how many bytes to get from the AUX buffer based on the
+        * position of the head.
         */
-       if (etr_perf->snapshot) {
+       if (etr_perf->snapshot)
                handle->head += size;
-               if (etr_buf->full)
-                       size = etr_buf->size;
-       }
 
        lost |= etr_buf->full;
 out:
-       if (lost)
+       /*
+        * Don't set the TRUNCATED flag in snapshot mode because 1) the
+        * captured buffer is expected to be truncated and 2) a full buffer
+        * prevents the event from being re-enabled by the perf core,
+        * resulting in stale data being send to user space.
+        */
+       if (!etr_perf->snapshot && lost)
                perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
        return size;
 }
@@ -1612,7 +1620,7 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev)
 
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
-       dev_dbg(drvdata->dev, "TMC-ETR disabled\n");
+       dev_dbg(&csdev->dev, "TMC-ETR disabled\n");
        return 0;
 }
 
index 3f71872..be37aff 100644 (file)
 #include "coresight-priv.h"
 #include "coresight-tmc.h"
 
+DEFINE_CORESIGHT_DEVLIST(etb_devs, "tmc_etb");
+DEFINE_CORESIGHT_DEVLIST(etf_devs, "tmc_etf");
+DEFINE_CORESIGHT_DEVLIST(etr_devs, "tmc_etr");
+
 void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata)
 {
        /* Ensure formatter, unformatter and hardware fifo are empty */
        if (coresight_timeout(drvdata->base,
                              TMC_STS, TMC_STS_TMCREADY_BIT, 1)) {
-               dev_err(drvdata->dev,
+               dev_err(&drvdata->csdev->dev,
                        "timeout while waiting for TMC to be Ready\n");
        }
 }
@@ -49,7 +53,7 @@ void tmc_flush_and_stop(struct tmc_drvdata *drvdata)
        /* Ensure flush completes */
        if (coresight_timeout(drvdata->base,
                              TMC_FFCR, TMC_FFCR_FLUSHMAN_BIT, 0)) {
-               dev_err(drvdata->dev,
+               dev_err(&drvdata->csdev->dev,
                "timeout while waiting for completion of Manual Flush\n");
        }
 
@@ -83,7 +87,7 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata)
        }
 
        if (!ret)
-               dev_dbg(drvdata->dev, "TMC read start\n");
+               dev_dbg(&drvdata->csdev->dev, "TMC read start\n");
 
        return ret;
 }
@@ -105,7 +109,7 @@ static int tmc_read_unprepare(struct tmc_drvdata *drvdata)
        }
 
        if (!ret)
-               dev_dbg(drvdata->dev, "TMC read end\n");
+               dev_dbg(&drvdata->csdev->dev, "TMC read end\n");
 
        return ret;
 }
@@ -122,7 +126,7 @@ static int tmc_open(struct inode *inode, struct file *file)
 
        nonseekable_open(inode, file);
 
-       dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
+       dev_dbg(&drvdata->csdev->dev, "%s: successfully opened\n", __func__);
        return 0;
 }
 
@@ -152,12 +156,13 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
                return 0;
 
        if (copy_to_user(data, bufp, actual)) {
-               dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__);
+               dev_dbg(&drvdata->csdev->dev,
+                       "%s: copy_to_user failed\n", __func__);
                return -EFAULT;
        }
 
        *ppos += actual;
-       dev_dbg(drvdata->dev, "%zu bytes copied\n", actual);
+       dev_dbg(&drvdata->csdev->dev, "%zu bytes copied\n", actual);
 
        return actual;
 }
@@ -172,7 +177,7 @@ static int tmc_release(struct inode *inode, struct file *file)
        if (ret)
                return ret;
 
-       dev_dbg(drvdata->dev, "%s: released\n", __func__);
+       dev_dbg(&drvdata->csdev->dev, "%s: released\n", __func__);
        return 0;
 }
 
@@ -332,24 +337,22 @@ const struct attribute_group *coresight_tmc_groups[] = {
        NULL,
 };
 
-static inline bool tmc_etr_can_use_sg(struct tmc_drvdata *drvdata)
+static inline bool tmc_etr_can_use_sg(struct device *dev)
 {
-       return fwnode_property_present(drvdata->dev->fwnode,
-                                      "arm,scatter-gather");
+       return fwnode_property_present(dev->fwnode, "arm,scatter-gather");
 }
 
 /* Detect and initialise the capabilities of a TMC ETR */
-static int tmc_etr_setup_caps(struct tmc_drvdata *drvdata,
-                            u32 devid, void *dev_caps)
+static int tmc_etr_setup_caps(struct device *parent, u32 devid, void *dev_caps)
 {
        int rc;
-
        u32 dma_mask = 0;
+       struct tmc_drvdata *drvdata = dev_get_drvdata(parent);
 
        /* Set the unadvertised capabilities */
        tmc_etr_init_caps(drvdata, (u32)(unsigned long)dev_caps);
 
-       if (!(devid & TMC_DEVID_NOSCAT) && tmc_etr_can_use_sg(drvdata))
+       if (!(devid & TMC_DEVID_NOSCAT) && tmc_etr_can_use_sg(parent))
                tmc_etr_set_cap(drvdata, TMC_ETR_SG);
 
        /* Check if the AXI address width is available */
@@ -367,18 +370,27 @@ static int tmc_etr_setup_caps(struct tmc_drvdata *drvdata,
        case 44:
        case 48:
        case 52:
-               dev_info(drvdata->dev, "Detected dma mask %dbits\n", dma_mask);
+               dev_info(parent, "Detected dma mask %dbits\n", dma_mask);
                break;
        default:
                dma_mask = 40;
        }
 
-       rc = dma_set_mask_and_coherent(drvdata->dev, DMA_BIT_MASK(dma_mask));
+       rc = dma_set_mask_and_coherent(parent, DMA_BIT_MASK(dma_mask));
        if (rc)
-               dev_err(drvdata->dev, "Failed to setup DMA mask: %d\n", rc);
+               dev_err(parent, "Failed to setup DMA mask: %d\n", rc);
        return rc;
 }
 
+static u32 tmc_etr_get_default_buffer_size(struct device *dev)
+{
+       u32 size;
+
+       if (fwnode_property_read_u32(dev->fwnode, "arm,buffer-size", &size))
+               size = SZ_1M;
+       return size;
+}
+
 static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
 {
        int ret = 0;
@@ -389,23 +401,13 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
        struct tmc_drvdata *drvdata;
        struct resource *res = &adev->res;
        struct coresight_desc desc = { 0 };
-       struct device_node *np = adev->dev.of_node;
-
-       if (np) {
-               pdata = of_get_coresight_platform_data(dev, np);
-               if (IS_ERR(pdata)) {
-                       ret = PTR_ERR(pdata);
-                       goto out;
-               }
-               adev->dev.platform_data = pdata;
-       }
+       struct coresight_dev_list *dev_list = NULL;
 
        ret = -ENOMEM;
        drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
        if (!drvdata)
                goto out;
 
-       drvdata->dev = &adev->dev;
        dev_set_drvdata(dev, drvdata);
 
        /* Validity for the resource is already checked by the AMBA core */
@@ -425,18 +427,11 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
        /* This device is not associated with a session */
        drvdata->pid = -1;
 
-       if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-               if (np)
-                       ret = of_property_read_u32(np,
-                                                  "arm,buffer-size",
-                                                  &drvdata->size);
-               if (ret)
-                       drvdata->size = SZ_1M;
-       } else {
+       if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
+               drvdata->size = tmc_etr_get_default_buffer_size(dev);
+       else
                drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4;
-       }
 
-       desc.pdata = pdata;
        desc.dev = dev;
        desc.groups = coresight_tmc_groups;
 
@@ -445,36 +440,53 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
                desc.type = CORESIGHT_DEV_TYPE_SINK;
                desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
                desc.ops = &tmc_etb_cs_ops;
+               dev_list = &etb_devs;
                break;
        case TMC_CONFIG_TYPE_ETR:
                desc.type = CORESIGHT_DEV_TYPE_SINK;
                desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
                desc.ops = &tmc_etr_cs_ops;
-               ret = tmc_etr_setup_caps(drvdata, devid,
+               ret = tmc_etr_setup_caps(dev, devid,
                                         coresight_get_uci_data(id));
                if (ret)
                        goto out;
                idr_init(&drvdata->idr);
                mutex_init(&drvdata->idr_mutex);
+               dev_list = &etr_devs;
                break;
        case TMC_CONFIG_TYPE_ETF:
                desc.type = CORESIGHT_DEV_TYPE_LINKSINK;
                desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO;
                desc.ops = &tmc_etf_cs_ops;
+               dev_list = &etf_devs;
                break;
        default:
-               pr_err("%s: Unsupported TMC config\n", pdata->name);
+               pr_err("%s: Unsupported TMC config\n", desc.name);
                ret = -EINVAL;
                goto out;
        }
 
+       desc.name = coresight_alloc_device_name(dev_list, dev);
+       if (!desc.name) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       pdata = coresight_get_platform_data(dev);
+       if (IS_ERR(pdata)) {
+               ret = PTR_ERR(pdata);
+               goto out;
+       }
+       adev->dev.platform_data = pdata;
+       desc.pdata = pdata;
+
        drvdata->csdev = coresight_register(&desc);
        if (IS_ERR(drvdata->csdev)) {
                ret = PTR_ERR(drvdata->csdev);
                goto out;
        }
 
-       drvdata->miscdev.name = pdata->name;
+       drvdata->miscdev.name = desc.name;
        drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
        drvdata->miscdev.fops = &tmc_fops;
        ret = misc_register(&drvdata->miscdev);
index 503f1b3..1ed5041 100644 (file)
@@ -161,7 +161,6 @@ struct etr_buf {
 /**
  * struct tmc_drvdata - specifics associated to an TMC component
  * @base:      memory mapped base address for this component.
- * @dev:       the device entity associated to this component.
  * @csdev:     component vitals needed by the framework.
  * @miscdev:   specifics to handle "/dev/xyz.tmc" entry.
  * @spinlock:  only one at a time pls.
@@ -184,7 +183,6 @@ struct etr_buf {
  */
 struct tmc_drvdata {
        void __iomem            *base;
-       struct device           *dev;
        struct coresight_device *csdev;
        struct miscdevice       miscdev;
        spinlock_t              spinlock;
index 63d9af3..f8583e4 100644 (file)
 #define FFCR_FON_MAN           BIT(6)
 #define FFCR_STOP_FI           BIT(12)
 
+DEFINE_CORESIGHT_DEVLIST(tpiu_devs, "tpiu");
+
 /**
  * @base:      memory mapped base address for this component.
- * @dev:       the device entity associated to this component.
  * @atclk:     optional clock for the core parts of the TPIU.
  * @csdev:     component vitals needed by the framework.
  */
 struct tpiu_drvdata {
        void __iomem            *base;
-       struct device           *dev;
        struct clk              *atclk;
        struct coresight_device *csdev;
 };
@@ -75,7 +75,7 @@ static int tpiu_enable(struct coresight_device *csdev, u32 mode, void *__unused)
 
        tpiu_enable_hw(drvdata);
        atomic_inc(csdev->refcnt);
-       dev_dbg(drvdata->dev, "TPIU enabled\n");
+       dev_dbg(&csdev->dev, "TPIU enabled\n");
        return 0;
 }
 
@@ -104,7 +104,7 @@ static int tpiu_disable(struct coresight_device *csdev)
 
        tpiu_disable_hw(drvdata);
 
-       dev_dbg(drvdata->dev, "TPIU disabled\n");
+       dev_dbg(&csdev->dev, "TPIU disabled\n");
        return 0;
 }
 
@@ -126,20 +126,15 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)
        struct tpiu_drvdata *drvdata;
        struct resource *res = &adev->res;
        struct coresight_desc desc = { 0 };
-       struct device_node *np = adev->dev.of_node;
 
-       if (np) {
-               pdata = of_get_coresight_platform_data(dev, np);
-               if (IS_ERR(pdata))
-                       return PTR_ERR(pdata);
-               adev->dev.platform_data = pdata;
-       }
+       desc.name = coresight_alloc_device_name(&tpiu_devs, dev);
+       if (!desc.name)
+               return -ENOMEM;
 
        drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
        if (!drvdata)
                return -ENOMEM;
 
-       drvdata->dev = &adev->dev;
        drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */
        if (!IS_ERR(drvdata->atclk)) {
                ret = clk_prepare_enable(drvdata->atclk);
@@ -158,6 +153,11 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)
        /* Disable tpiu to support older devices */
        tpiu_disable_hw(drvdata);
 
+       pdata = coresight_get_platform_data(dev);
+       if (IS_ERR(pdata))
+               return PTR_ERR(pdata);
+       dev->platform_data = pdata;
+
        desc.type = CORESIGHT_DEV_TYPE_SINK;
        desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_PORT;
        desc.ops = &tpiu_cs_ops;
index 4b13028..55db77f 100644 (file)
@@ -100,8 +100,8 @@ static int coresight_find_link_inport(struct coresight_device *csdev,
        int i;
        struct coresight_connection *conn;
 
-       for (i = 0; i < parent->nr_outport; i++) {
-               conn = &parent->conns[i];
+       for (i = 0; i < parent->pdata->nr_outport; i++) {
+               conn = &parent->pdata->conns[i];
                if (conn->child_dev == csdev)
                        return conn->child_port;
        }
@@ -118,8 +118,8 @@ static int coresight_find_link_outport(struct coresight_device *csdev,
        int i;
        struct coresight_connection *conn;
 
-       for (i = 0; i < csdev->nr_outport; i++) {
-               conn = &csdev->conns[i];
+       for (i = 0; i < csdev->pdata->nr_outport; i++) {
+               conn = &csdev->pdata->conns[i];
                if (conn->child_dev == child)
                        return conn->outport;
        }
@@ -306,10 +306,10 @@ static void coresight_disable_link(struct coresight_device *csdev,
 
        if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
                refport = inport;
-               nr_conns = csdev->nr_inport;
+               nr_conns = csdev->pdata->nr_inport;
        } else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
                refport = outport;
-               nr_conns = csdev->nr_outport;
+               nr_conns = csdev->pdata->nr_outport;
        } else {
                refport = 0;
                nr_conns = 1;
@@ -498,9 +498,9 @@ struct coresight_device *coresight_get_sink(struct list_head *path)
        return csdev;
 }
 
-static int coresight_enabled_sink(struct device *dev, void *data)
+static int coresight_enabled_sink(struct device *dev, const void *data)
 {
-       bool *reset = data;
+       const bool *reset = data;
        struct coresight_device *csdev = to_coresight_device(dev);
 
        if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
@@ -544,7 +544,7 @@ struct coresight_device *coresight_get_enabled_sink(bool deactivate)
        return dev ? to_coresight_device(dev) : NULL;
 }
 
-static int coresight_sink_by_id(struct device *dev, void *data)
+static int coresight_sink_by_id(struct device *dev, const void *data)
 {
        struct coresight_device *csdev = to_coresight_device(dev);
        unsigned long hash;
@@ -595,9 +595,10 @@ static void coresight_grab_device(struct coresight_device *csdev)
 {
        int i;
 
-       for (i = 0; i < csdev->nr_outport; i++) {
-               struct coresight_device *child = csdev->conns[i].child_dev;
+       for (i = 0; i < csdev->pdata->nr_outport; i++) {
+               struct coresight_device *child;
 
+               child  = csdev->pdata->conns[i].child_dev;
                if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
                        pm_runtime_get_sync(child->dev.parent);
        }
@@ -613,9 +614,10 @@ static void coresight_drop_device(struct coresight_device *csdev)
        int i;
 
        pm_runtime_put(csdev->dev.parent);
-       for (i = 0; i < csdev->nr_outport; i++) {
-               struct coresight_device *child = csdev->conns[i].child_dev;
+       for (i = 0; i < csdev->pdata->nr_outport; i++) {
+               struct coresight_device *child;
 
+               child  = csdev->pdata->conns[i].child_dev;
                if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
                        pm_runtime_put(child->dev.parent);
        }
@@ -645,9 +647,10 @@ static int _coresight_build_path(struct coresight_device *csdev,
                goto out;
 
        /* Not a sink - recursively explore each port found on this element */
-       for (i = 0; i < csdev->nr_outport; i++) {
-               struct coresight_device *child_dev = csdev->conns[i].child_dev;
+       for (i = 0; i < csdev->pdata->nr_outport; i++) {
+               struct coresight_device *child_dev;
 
+               child_dev = csdev->pdata->conns[i].child_dev;
                if (child_dev &&
                    _coresight_build_path(child_dev, sink, path) == 0) {
                        found = true;
@@ -975,6 +978,7 @@ static void coresight_device_release(struct device *dev)
 {
        struct coresight_device *csdev = to_coresight_device(dev);
 
+       fwnode_handle_put(csdev->dev.fwnode);
        kfree(csdev->refcnt);
        kfree(csdev);
 }
@@ -1000,19 +1004,17 @@ static int coresight_orphan_match(struct device *dev, void *data)
         * Circle throuch all the connection of that component.  If we find
         * an orphan connection whose name matches @csdev, link it.
         */
-       for (i = 0; i < i_csdev->nr_outport; i++) {
-               conn = &i_csdev->conns[i];
+       for (i = 0; i < i_csdev->pdata->nr_outport; i++) {
+               conn = &i_csdev->pdata->conns[i];
 
                /* We have found at least one orphan connection */
                if (conn->child_dev == NULL) {
                        /* Does it match this newly added device? */
-                       if (conn->child_name &&
-                           !strcmp(dev_name(&csdev->dev), conn->child_name)) {
+                       if (conn->child_fwnode == csdev->dev.fwnode)
                                conn->child_dev = csdev;
-                       } else {
+                       else
                                /* This component still has an orphan */
                                still_orphan = true;
-                       }
                }
        }
 
@@ -1040,13 +1042,13 @@ static void coresight_fixup_device_conns(struct coresight_device *csdev)
 {
        int i;
 
-       for (i = 0; i < csdev->nr_outport; i++) {
-               struct coresight_connection *conn = &csdev->conns[i];
+       for (i = 0; i < csdev->pdata->nr_outport; i++) {
+               struct coresight_connection *conn = &csdev->pdata->conns[i];
                struct device *dev = NULL;
 
-               if (conn->child_name)
-                       dev = bus_find_device_by_name(&coresight_bustype, NULL,
-                                                     conn->child_name);
+               dev = bus_find_device(&coresight_bustype, NULL,
+                                     (void *)conn->child_fwnode,
+                                     coresight_device_fwnode_match);
                if (dev) {
                        conn->child_dev = to_coresight_device(dev);
                        /* and put reference from 'bus_find_device()' */
@@ -1075,15 +1077,21 @@ static int coresight_remove_match(struct device *dev, void *data)
         * Circle throuch all the connection of that component.  If we find
         * a connection whose name matches @csdev, remove it.
         */
-       for (i = 0; i < iterator->nr_outport; i++) {
-               conn = &iterator->conns[i];
+       for (i = 0; i < iterator->pdata->nr_outport; i++) {
+               conn = &iterator->pdata->conns[i];
 
                if (conn->child_dev == NULL)
                        continue;
 
-               if (!strcmp(dev_name(&csdev->dev), conn->child_name)) {
+               if (csdev->dev.fwnode == conn->child_fwnode) {
                        iterator->orphan = true;
                        conn->child_dev = NULL;
+                       /*
+                        * Drop the reference to the handle for the remote
+                        * device acquired in parsing the connections from
+                        * platform data.
+                        */
+                       fwnode_handle_put(conn->child_fwnode);
                        /* No need to continue */
                        break;
                }
@@ -1096,10 +1104,21 @@ static int coresight_remove_match(struct device *dev, void *data)
        return 0;
 }
 
+/*
+ * coresight_remove_conns - Remove references to this given devices
+ * from the connections of other devices.
+ */
 static void coresight_remove_conns(struct coresight_device *csdev)
 {
-       bus_for_each_dev(&coresight_bustype, NULL,
-                        csdev, coresight_remove_match);
+       /*
+        * Another device will point to this device only if there is
+        * an output port connected to this one. i.e, if the device
+        * doesn't have at least one input port, there is no point
+        * in searching all the devices.
+        */
+       if (csdev->pdata->nr_inport)
+               bus_for_each_dev(&coresight_bustype, NULL,
+                                csdev, coresight_remove_match);
 }
 
 /**
@@ -1152,6 +1171,22 @@ static int __init coresight_init(void)
 }
 postcore_initcall(coresight_init);
 
+/*
+ * coresight_release_platform_data: Release references to the devices connected
+ * to the output port of this device.
+ */
+void coresight_release_platform_data(struct coresight_platform_data *pdata)
+{
+       int i;
+
+       for (i = 0; i < pdata->nr_outport; i++) {
+               if (pdata->conns[i].child_fwnode) {
+                       fwnode_handle_put(pdata->conns[i].child_fwnode);
+                       pdata->conns[i].child_fwnode = NULL;
+               }
+       }
+}
+
 struct coresight_device *coresight_register(struct coresight_desc *desc)
 {
        int ret;
@@ -1184,10 +1219,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
 
        csdev->refcnt = refcnts;
 
-       csdev->nr_inport = desc->pdata->nr_inport;
-       csdev->nr_outport = desc->pdata->nr_outport;
-
-       csdev->conns = desc->pdata->conns;
+       csdev->pdata = desc->pdata;
 
        csdev->type = desc->type;
        csdev->subtype = desc->subtype;
@@ -1199,7 +1231,12 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
        csdev->dev.parent = desc->dev;
        csdev->dev.release = coresight_device_release;
        csdev->dev.bus = &coresight_bustype;
-       dev_set_name(&csdev->dev, "%s", desc->pdata->name);
+       /*
+        * Hold the reference to our parent device. This will be
+        * dropped only in coresight_device_release().
+        */
+       csdev->dev.fwnode = fwnode_handle_get(dev_fwnode(desc->dev));
+       dev_set_name(&csdev->dev, "%s", desc->name);
 
        ret = device_register(&csdev->dev);
        if (ret) {
@@ -1239,6 +1276,8 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
 err_free_csdev:
        kfree(csdev);
 err_out:
+       /* Cleanup the connection information */
+       coresight_release_platform_data(desc->pdata);
        return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(coresight_register);
@@ -1248,6 +1287,65 @@ void coresight_unregister(struct coresight_device *csdev)
        etm_perf_del_symlink_sink(csdev);
        /* Remove references of that device in the topology */
        coresight_remove_conns(csdev);
+       coresight_release_platform_data(csdev->pdata);
        device_unregister(&csdev->dev);
 }
 EXPORT_SYMBOL_GPL(coresight_unregister);
+
+
+/*
+ * coresight_search_device_idx - Search the fwnode handle of a device
+ * in the given dev_idx list. Must be called with the coresight_mutex held.
+ *
+ * Returns the index of the entry, when found. Otherwise, -ENOENT.
+ */
+static inline int coresight_search_device_idx(struct coresight_dev_list *dict,
+                                             struct fwnode_handle *fwnode)
+{
+       int i;
+
+       for (i = 0; i < dict->nr_idx; i++)
+               if (dict->fwnode_list[i] == fwnode)
+                       return i;
+       return -ENOENT;
+}
+
+/*
+ * coresight_alloc_device_name - Get an index for a given device in the
+ * device index list specific to a driver. An index is allocated for a
+ * device and is tracked with the fwnode_handle to prevent allocating
+ * duplicate indices for the same device (e.g, if we defer probing of
+ * a device due to dependencies), in case the index is requested again.
+ */
+char *coresight_alloc_device_name(struct coresight_dev_list *dict,
+                                 struct device *dev)
+{
+       int idx;
+       char *name = NULL;
+       struct fwnode_handle **list;
+
+       mutex_lock(&coresight_mutex);
+
+       idx = coresight_search_device_idx(dict, dev_fwnode(dev));
+       if (idx < 0) {
+               /* Make space for the new entry */
+               idx = dict->nr_idx;
+               list = krealloc(dict->fwnode_list,
+                               (idx + 1) * sizeof(*dict->fwnode_list),
+                               GFP_KERNEL);
+               if (ZERO_OR_NULL_PTR(list)) {
+                       idx = -ENOMEM;
+                       goto done;
+               }
+
+               list[idx] = dev_fwnode(dev);
+               dict->fwnode_list = list;
+               dict->nr_idx = idx + 1;
+       }
+
+       name = devm_kasprintf(dev, GFP_KERNEL, "%s%d", dict->pfx, idx);
+done:
+       mutex_unlock(&coresight_mutex);
+       return name;
+}
+EXPORT_SYMBOL_GPL(coresight_alloc_device_name);
diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c
deleted file mode 100644 (file)
index 7045930..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
- */
-
-#include <linux/types.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_graph.h>
-#include <linux/of_platform.h>
-#include <linux/platform_device.h>
-#include <linux/amba/bus.h>
-#include <linux/coresight.h>
-#include <linux/cpumask.h>
-#include <asm/smp_plat.h>
-
-
-static int of_dev_node_match(struct device *dev, void *data)
-{
-       return dev->of_node == data;
-}
-
-static struct device *
-of_coresight_get_endpoint_device(struct device_node *endpoint)
-{
-       struct device *dev = NULL;
-
-       /*
-        * If we have a non-configurable replicator, it will be found on the
-        * platform bus.
-        */
-       dev = bus_find_device(&platform_bus_type, NULL,
-                             endpoint, of_dev_node_match);
-       if (dev)
-               return dev;
-
-       /*
-        * We have a configurable component - circle through the AMBA bus
-        * looking for the device that matches the endpoint node.
-        */
-       return bus_find_device(&amba_bustype, NULL,
-                              endpoint, of_dev_node_match);
-}
-
-static inline bool of_coresight_legacy_ep_is_input(struct device_node *ep)
-{
-       return of_property_read_bool(ep, "slave-mode");
-}
-
-static void of_coresight_get_ports_legacy(const struct device_node *node,
-                                         int *nr_inport, int *nr_outport)
-{
-       struct device_node *ep = NULL;
-       int in = 0, out = 0;
-
-       do {
-               ep = of_graph_get_next_endpoint(node, ep);
-               if (!ep)
-                       break;
-
-               if (of_coresight_legacy_ep_is_input(ep))
-                       in++;
-               else
-                       out++;
-
-       } while (ep);
-
-       *nr_inport = in;
-       *nr_outport = out;
-}
-
-static struct device_node *of_coresight_get_port_parent(struct device_node *ep)
-{
-       struct device_node *parent = of_graph_get_port_parent(ep);
-
-       /*
-        * Skip one-level up to the real device node, if we
-        * are using the new bindings.
-        */
-       if (of_node_name_eq(parent, "in-ports") ||
-           of_node_name_eq(parent, "out-ports"))
-               parent = of_get_next_parent(parent);
-
-       return parent;
-}
-
-static inline struct device_node *
-of_coresight_get_input_ports_node(const struct device_node *node)
-{
-       return of_get_child_by_name(node, "in-ports");
-}
-
-static inline struct device_node *
-of_coresight_get_output_ports_node(const struct device_node *node)
-{
-       return of_get_child_by_name(node, "out-ports");
-}
-
-static inline int
-of_coresight_count_ports(struct device_node *port_parent)
-{
-       int i = 0;
-       struct device_node *ep = NULL;
-
-       while ((ep = of_graph_get_next_endpoint(port_parent, ep)))
-               i++;
-       return i;
-}
-
-static void of_coresight_get_ports(const struct device_node *node,
-                                  int *nr_inport, int *nr_outport)
-{
-       struct device_node *input_ports = NULL, *output_ports = NULL;
-
-       input_ports = of_coresight_get_input_ports_node(node);
-       output_ports = of_coresight_get_output_ports_node(node);
-
-       if (input_ports || output_ports) {
-               if (input_ports) {
-                       *nr_inport = of_coresight_count_ports(input_ports);
-                       of_node_put(input_ports);
-               }
-               if (output_ports) {
-                       *nr_outport = of_coresight_count_ports(output_ports);
-                       of_node_put(output_ports);
-               }
-       } else {
-               /* Fall back to legacy DT bindings parsing */
-               of_coresight_get_ports_legacy(node, nr_inport, nr_outport);
-       }
-}
-
-static int of_coresight_alloc_memory(struct device *dev,
-                       struct coresight_platform_data *pdata)
-{
-       if (pdata->nr_outport) {
-               pdata->conns = devm_kzalloc(dev, pdata->nr_outport *
-                                           sizeof(*pdata->conns),
-                                           GFP_KERNEL);
-               if (!pdata->conns)
-                       return -ENOMEM;
-       }
-
-       return 0;
-}
-
-int of_coresight_get_cpu(const struct device_node *node)
-{
-       int cpu;
-       struct device_node *dn;
-
-       dn = of_parse_phandle(node, "cpu", 0);
-       /* Affinity defaults to CPU0 */
-       if (!dn)
-               return 0;
-       cpu = of_cpu_node_to_id(dn);
-       of_node_put(dn);
-
-       /* Affinity to CPU0 if no cpu nodes are found */
-       return (cpu < 0) ? 0 : cpu;
-}
-EXPORT_SYMBOL_GPL(of_coresight_get_cpu);
-
-/*
- * of_coresight_parse_endpoint : Parse the given output endpoint @ep
- * and fill the connection information in @conn
- *
- * Parses the local port, remote device name and the remote port.
- *
- * Returns :
- *      1      - If the parsing is successful and a connection record
- *               was created for an output connection.
- *      0      - If the parsing completed without any fatal errors.
- *     -Errno  - Fatal error, abort the scanning.
- */
-static int of_coresight_parse_endpoint(struct device *dev,
-                                      struct device_node *ep,
-                                      struct coresight_connection *conn)
-{
-       int ret = 0;
-       struct of_endpoint endpoint, rendpoint;
-       struct device_node *rparent = NULL;
-       struct device_node *rep = NULL;
-       struct device *rdev = NULL;
-
-       do {
-               /* Parse the local port details */
-               if (of_graph_parse_endpoint(ep, &endpoint))
-                       break;
-               /*
-                * Get a handle on the remote endpoint and the device it is
-                * attached to.
-                */
-               rep = of_graph_get_remote_endpoint(ep);
-               if (!rep)
-                       break;
-               rparent = of_coresight_get_port_parent(rep);
-               if (!rparent)
-                       break;
-               if (of_graph_parse_endpoint(rep, &rendpoint))
-                       break;
-
-               /* If the remote device is not available, defer probing */
-               rdev = of_coresight_get_endpoint_device(rparent);
-               if (!rdev) {
-                       ret = -EPROBE_DEFER;
-                       break;
-               }
-
-               conn->outport = endpoint.port;
-               conn->child_name = devm_kstrdup(dev,
-                                               dev_name(rdev),
-                                               GFP_KERNEL);
-               conn->child_port = rendpoint.port;
-               /* Connection record updated */
-               ret = 1;
-       } while (0);
-
-       of_node_put(rparent);
-       of_node_put(rep);
-       put_device(rdev);
-
-       return ret;
-}
-
-struct coresight_platform_data *
-of_get_coresight_platform_data(struct device *dev,
-                              const struct device_node *node)
-{
-       int ret = 0;
-       struct coresight_platform_data *pdata;
-       struct coresight_connection *conn;
-       struct device_node *ep = NULL;
-       const struct device_node *parent = NULL;
-       bool legacy_binding = false;
-
-       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
-       if (!pdata)
-               return ERR_PTR(-ENOMEM);
-
-       /* Use device name as sysfs handle */
-       pdata->name = dev_name(dev);
-       pdata->cpu = of_coresight_get_cpu(node);
-
-       /* Get the number of input and output port for this component */
-       of_coresight_get_ports(node, &pdata->nr_inport, &pdata->nr_outport);
-
-       /* If there are no output connections, we are done */
-       if (!pdata->nr_outport)
-               return pdata;
-
-       ret = of_coresight_alloc_memory(dev, pdata);
-       if (ret)
-               return ERR_PTR(ret);
-
-       parent = of_coresight_get_output_ports_node(node);
-       /*
-        * If the DT uses obsoleted bindings, the ports are listed
-        * under the device and we need to filter out the input
-        * ports.
-        */
-       if (!parent) {
-               legacy_binding = true;
-               parent = node;
-               dev_warn_once(dev, "Uses obsolete Coresight DT bindings\n");
-       }
-
-       conn = pdata->conns;
-
-       /* Iterate through each output port to discover topology */
-       while ((ep = of_graph_get_next_endpoint(parent, ep))) {
-               /*
-                * Legacy binding mixes input/output ports under the
-                * same parent. So, skip the input ports if we are dealing
-                * with legacy binding, as they processed with their
-                * connected output ports.
-                */
-               if (legacy_binding && of_coresight_legacy_ep_is_input(ep))
-                       continue;
-
-               ret = of_coresight_parse_endpoint(dev, ep, conn);
-               switch (ret) {
-               case 1:
-                       conn++;         /* Fall through */
-               case 0:
-                       break;
-               default:
-                       return ERR_PTR(ret);
-               }
-       }
-
-       return pdata;
-}
-EXPORT_SYMBOL_GPL(of_get_coresight_platform_data);
index 033dce5..5592289 100644 (file)
@@ -789,10 +789,9 @@ static int intel_th_populate(struct intel_th *th)
        return 0;
 }
 
-static int match_devt(struct device *dev, void *data)
+static int match_devt(struct device *dev, const void *data)
 {
-       dev_t devt = (dev_t)(unsigned long)data;
-
+       dev_t devt = (dev_t)(unsigned long)(void *)data;
        return dev->devt == devt;
 }
 
index 81bb54f..8ab28e5 100644 (file)
  * @entry:     window list linkage (msc::win_list)
  * @pgoff:     page offset into the buffer that this window starts at
  * @nr_blocks: number of blocks (pages) in this window
+ * @nr_segs:   number of segments in this window (<= @nr_blocks)
+ * @_sgt:      array of block descriptors
  * @sgt:       array of block descriptors
  */
 struct msc_window {
        struct list_head        entry;
        unsigned long           pgoff;
        unsigned int            nr_blocks;
+       unsigned int            nr_segs;
        struct msc              *msc;
-       struct sg_table         sgt;
+       struct sg_table         _sgt;
+       struct sg_table         *sgt;
 };
 
 /**
@@ -138,13 +142,19 @@ static inline bool msc_block_is_empty(struct msc_block_desc *bdesc)
 static inline struct msc_block_desc *
 msc_win_block(struct msc_window *win, unsigned int block)
 {
-       return sg_virt(&win->sgt.sgl[block]);
+       return sg_virt(&win->sgt->sgl[block]);
+}
+
+static inline size_t
+msc_win_actual_bsz(struct msc_window *win, unsigned int block)
+{
+       return win->sgt->sgl[block].length;
 }
 
 static inline dma_addr_t
 msc_win_baddr(struct msc_window *win, unsigned int block)
 {
-       return sg_dma_address(&win->sgt.sgl[block]);
+       return sg_dma_address(&win->sgt->sgl[block]);
 }
 
 static inline unsigned long
@@ -179,17 +189,18 @@ static struct msc_window *msc_next_window(struct msc_window *win)
 }
 
 /**
- * msc_oldest_window() - locate the window with oldest data
+ * msc_find_window() - find a window matching a given sg_table
  * @msc:       MSC device
+ * @sgt:       SG table of the window
+ * @nonempty:  skip over empty windows
  *
- * This should only be used in multiblock mode. Caller should hold the
- * msc::user_count reference.
- *
- * Return:     the oldest window with valid data
+ * Return:     MSC window structure pointer or NULL if the window
+ *             could not be found.
  */
-static struct msc_window *msc_oldest_window(struct msc *msc)
+static struct msc_window *
+msc_find_window(struct msc *msc, struct sg_table *sgt, bool nonempty)
 {
-       struct msc_window *win, *next = msc_next_window(msc->cur_win);
+       struct msc_window *win;
        unsigned int found = 0;
 
        if (list_empty(&msc->win_list))
@@ -201,17 +212,40 @@ static struct msc_window *msc_oldest_window(struct msc *msc)
         * something like 2, in which case we're good
         */
        list_for_each_entry(win, &msc->win_list, entry) {
-               if (win == next)
+               if (win->sgt == sgt)
                        found++;
 
                /* skip the empty ones */
-               if (msc_block_is_empty(msc_win_block(win, 0)))
+               if (nonempty && msc_block_is_empty(msc_win_block(win, 0)))
                        continue;
 
                if (found)
                        return win;
        }
 
+       return NULL;
+}
+
+/**
+ * msc_oldest_window() - locate the window with oldest data
+ * @msc:       MSC device
+ *
+ * This should only be used in multiblock mode. Caller should hold the
+ * msc::user_count reference.
+ *
+ * Return:     the oldest window with valid data
+ */
+static struct msc_window *msc_oldest_window(struct msc *msc)
+{
+       struct msc_window *win;
+
+       if (list_empty(&msc->win_list))
+               return NULL;
+
+       win = msc_find_window(msc, msc_next_window(msc->cur_win)->sgt, true);
+       if (win)
+               return win;
+
        return list_first_entry(&msc->win_list, struct msc_window, entry);
 }
 
@@ -234,7 +268,7 @@ static unsigned int msc_win_oldest_block(struct msc_window *win)
         * with wrapping, last written block contains both the newest and the
         * oldest data for this window.
         */
-       for (blk = 0; blk < win->nr_blocks; blk++) {
+       for (blk = 0; blk < win->nr_segs; blk++) {
                bdesc = msc_win_block(win, blk);
 
                if (msc_block_last_written(bdesc))
@@ -366,7 +400,7 @@ static int msc_iter_block_advance(struct msc_iter *iter)
                return msc_iter_win_advance(iter);
 
        /* block advance */
-       if (++iter->block == iter->win->nr_blocks)
+       if (++iter->block == iter->win->nr_segs)
                iter->block = 0;
 
        /* no wrapping, sanity check in case there is no last written block */
@@ -478,7 +512,7 @@ static void msc_buffer_clear_hw_header(struct msc *msc)
                size_t hw_sz = sizeof(struct msc_block_desc) -
                        offsetof(struct msc_block_desc, hw_tag);
 
-               for (blk = 0; blk < win->nr_blocks; blk++) {
+               for (blk = 0; blk < win->nr_segs; blk++) {
                        struct msc_block_desc *bdesc = msc_win_block(win, blk);
 
                        memset(&bdesc->hw_tag, 0, hw_sz);
@@ -667,7 +701,7 @@ static int msc_buffer_contig_alloc(struct msc *msc, unsigned long size)
                goto err_out;
 
        ret = -ENOMEM;
-       page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
+       page = alloc_pages(GFP_KERNEL | __GFP_ZERO | GFP_DMA32, order);
        if (!page)
                goto err_free_sgt;
 
@@ -734,17 +768,17 @@ static struct page *msc_buffer_contig_get_page(struct msc *msc,
 }
 
 static int __msc_buffer_win_alloc(struct msc_window *win,
-                                 unsigned int nr_blocks)
+                                 unsigned int nr_segs)
 {
        struct scatterlist *sg_ptr;
        void *block;
        int i, ret;
 
-       ret = sg_alloc_table(&win->sgt, nr_blocks, GFP_KERNEL);
+       ret = sg_alloc_table(win->sgt, nr_segs, GFP_KERNEL);
        if (ret)
                return -ENOMEM;
 
-       for_each_sg(win->sgt.sgl, sg_ptr, nr_blocks, i) {
+       for_each_sg(win->sgt->sgl, sg_ptr, nr_segs, i) {
                block = dma_alloc_coherent(msc_dev(win->msc)->parent->parent,
                                          PAGE_SIZE, &sg_dma_address(sg_ptr),
                                          GFP_KERNEL);
@@ -754,7 +788,7 @@ static int __msc_buffer_win_alloc(struct msc_window *win,
                sg_set_buf(sg_ptr, block, PAGE_SIZE);
        }
 
-       return nr_blocks;
+       return nr_segs;
 
 err_nomem:
        for (i--; i >= 0; i--)
@@ -762,11 +796,35 @@ err_nomem:
                                  msc_win_block(win, i),
                                  msc_win_baddr(win, i));
 
-       sg_free_table(&win->sgt);
+       sg_free_table(win->sgt);
 
        return -ENOMEM;
 }
 
+#ifdef CONFIG_X86
+static void msc_buffer_set_uc(struct msc_window *win, unsigned int nr_segs)
+{
+       int i;
+
+       for (i = 0; i < nr_segs; i++)
+               /* Set the page as uncached */
+               set_memory_uc((unsigned long)msc_win_block(win, i), 1);
+}
+
+static void msc_buffer_set_wb(struct msc_window *win)
+{
+       int i;
+
+       for (i = 0; i < win->nr_segs; i++)
+               /* Reset the page to write-back */
+               set_memory_wb((unsigned long)msc_win_block(win, i), 1);
+}
+#else /* !X86 */
+static inline void
+msc_buffer_set_uc(struct msc_window *win, unsigned int nr_segs) {}
+static inline void msc_buffer_set_wb(struct msc_window *win) {}
+#endif /* CONFIG_X86 */
+
 /**
  * msc_buffer_win_alloc() - alloc a window for a multiblock mode
  * @msc:       MSC device
@@ -780,7 +838,7 @@ err_nomem:
 static int msc_buffer_win_alloc(struct msc *msc, unsigned int nr_blocks)
 {
        struct msc_window *win;
-       int ret = -ENOMEM, i;
+       int ret = -ENOMEM;
 
        if (!nr_blocks)
                return 0;
@@ -797,13 +855,13 @@ static int msc_buffer_win_alloc(struct msc *msc, unsigned int nr_blocks)
                return -ENOMEM;
 
        win->msc = msc;
+       win->sgt = &win->_sgt;
 
        if (!list_empty(&msc->win_list)) {
                struct msc_window *prev = list_last_entry(&msc->win_list,
                                                          struct msc_window,
                                                          entry);
 
-               /* This works as long as blocks are page-sized */
                win->pgoff = prev->pgoff + prev->nr_blocks;
        }
 
@@ -811,13 +869,10 @@ static int msc_buffer_win_alloc(struct msc *msc, unsigned int nr_blocks)
        if (ret < 0)
                goto err_nomem;
 
-#ifdef CONFIG_X86
-       for (i = 0; i < ret; i++)
-               /* Set the page as uncached */
-               set_memory_uc((unsigned long)msc_win_block(win, i), 1);
-#endif
+       msc_buffer_set_uc(win, ret);
 
-       win->nr_blocks = ret;
+       win->nr_segs = ret;
+       win->nr_blocks = nr_blocks;
 
        if (list_empty(&msc->win_list)) {
                msc->base = msc_win_block(win, 0);
@@ -840,14 +895,14 @@ static void __msc_buffer_win_free(struct msc *msc, struct msc_window *win)
 {
        int i;
 
-       for (i = 0; i < win->nr_blocks; i++) {
-               struct page *page = sg_page(&win->sgt.sgl[i]);
+       for (i = 0; i < win->nr_segs; i++) {
+               struct page *page = sg_page(&win->sgt->sgl[i]);
 
                page->mapping = NULL;
                dma_free_coherent(msc_dev(win->msc)->parent->parent, PAGE_SIZE,
                                  msc_win_block(win, i), msc_win_baddr(win, i));
        }
-       sg_free_table(&win->sgt);
+       sg_free_table(win->sgt);
 }
 
 /**
@@ -860,8 +915,6 @@ static void __msc_buffer_win_free(struct msc *msc, struct msc_window *win)
  */
 static void msc_buffer_win_free(struct msc *msc, struct msc_window *win)
 {
-       int i;
-
        msc->nr_pages -= win->nr_blocks;
 
        list_del(&win->entry);
@@ -870,11 +923,7 @@ static void msc_buffer_win_free(struct msc *msc, struct msc_window *win)
                msc->base_addr = 0;
        }
 
-#ifdef CONFIG_X86
-       for (i = 0; i < win->nr_blocks; i++)
-               /* Reset the page to write-back */
-               set_memory_wb((unsigned long)msc_win_block(win, i), 1);
-#endif
+       msc_buffer_set_wb(win);
 
        __msc_buffer_win_free(msc, win);
 
@@ -909,7 +958,7 @@ static void msc_buffer_relink(struct msc *msc)
                        next_win = list_next_entry(win, entry);
                }
 
-               for (blk = 0; blk < win->nr_blocks; blk++) {
+               for (blk = 0; blk < win->nr_segs; blk++) {
                        struct msc_block_desc *bdesc = msc_win_block(win, blk);
 
                        memset(bdesc, 0, sizeof(*bdesc));
@@ -920,7 +969,7 @@ static void msc_buffer_relink(struct msc *msc)
                         * Similarly to last window, last block should point
                         * to the first one.
                         */
-                       if (blk == win->nr_blocks - 1) {
+                       if (blk == win->nr_segs - 1) {
                                sw_tag |= MSC_SW_TAG_LASTBLK;
                                bdesc->next_blk = msc_win_bpfn(win, 0);
                        } else {
@@ -928,7 +977,7 @@ static void msc_buffer_relink(struct msc *msc)
                        }
 
                        bdesc->sw_tag = sw_tag;
-                       bdesc->block_sz = PAGE_SIZE / 64;
+                       bdesc->block_sz = msc_win_actual_bsz(win, blk) / 64;
                }
        }
 
@@ -1087,6 +1136,7 @@ static int msc_buffer_free_unless_used(struct msc *msc)
 static struct page *msc_buffer_get_page(struct msc *msc, unsigned long pgoff)
 {
        struct msc_window *win;
+       unsigned int blk;
 
        if (msc->mode == MSC_MODE_SINGLE)
                return msc_buffer_contig_get_page(msc, pgoff);
@@ -1099,7 +1149,18 @@ static struct page *msc_buffer_get_page(struct msc *msc, unsigned long pgoff)
 
 found:
        pgoff -= win->pgoff;
-       return sg_page(&win->sgt.sgl[pgoff]);
+
+       for (blk = 0; blk < win->nr_segs; blk++) {
+               struct page *page = sg_page(&win->sgt->sgl[blk]);
+               size_t pgsz = PFN_DOWN(msc_win_actual_bsz(win, blk));
+
+               if (pgoff < pgsz)
+                       return page + pgoff;
+
+               pgoff -= pgsz;
+       }
+
+       return NULL;
 }
 
 /**
@@ -1386,10 +1447,9 @@ static int intel_th_msc_init(struct msc *msc)
 
 static void msc_win_switch(struct msc *msc)
 {
-       struct msc_window *last, *first;
+       struct msc_window *first;
 
        first = list_first_entry(&msc->win_list, struct msc_window, entry);
-       last = list_last_entry(&msc->win_list, struct msc_window, entry);
 
        if (msc_is_last_win(msc->cur_win))
                msc->cur_win = first;
index f122870..c0378c3 100644 (file)
@@ -194,6 +194,11 @@ static const struct pci_device_id intel_th_pci_id_table[] = {
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x02a6),
                .driver_data = (kernel_ulong_t)&intel_th_2x,
        },
+       {
+               /* Ice Lake NNPI */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x45c5),
+               .driver_data = (kernel_ulong_t)&intel_th_2x,
+       },
        { 0 },
 };
 
index 455e1f3..c7fe3b4 100644 (file)
@@ -457,7 +457,7 @@ static struct pci_driver amd_mp2_pci_driver = {
 };
 module_pci_driver(amd_mp2_pci_driver);
 
-static int amd_mp2_device_match(struct device *dev, void *data)
+static int amd_mp2_device_match(struct device *dev, const void *data)
 {
        return 1;
 }
index 1969bfd..428a82c 100644 (file)
@@ -320,7 +320,7 @@ u32 i2c_acpi_find_bus_speed(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed);
 
-static int i2c_acpi_find_match_adapter(struct device *dev, void *data)
+static int i2c_acpi_find_match_adapter(struct device *dev, const void *data)
 {
        struct i2c_adapter *adapter = i2c_verify_adapter(dev);
 
@@ -330,7 +330,7 @@ static int i2c_acpi_find_match_adapter(struct device *dev, void *data)
        return ACPI_HANDLE(dev) == (acpi_handle)data;
 }
 
-static int i2c_acpi_find_match_device(struct device *dev, void *data)
+static int i2c_acpi_find_match_device(struct device *dev, const void *data)
 {
        return ACPI_COMPANION(dev) == data;
 }
index 406e5f6..2eb59a2 100644 (file)
@@ -112,12 +112,12 @@ void of_i2c_register_devices(struct i2c_adapter *adap)
        of_node_put(bus);
 }
 
-static int of_dev_node_match(struct device *dev, void *data)
+static int of_dev_node_match(struct device *dev, const void *data)
 {
        return dev->of_node == data;
 }
 
-static int of_dev_or_parent_node_match(struct device *dev, void *data)
+static int of_dev_or_parent_node_match(struct device *dev, const void *data)
 {
        if (dev->of_node == data)
                return 1;
index 1d736a4..5bd5185 100644 (file)
@@ -28,7 +28,7 @@ config IIO_CONFIGFS
        help
          This allows configuring various IIO bits through configfs
          (e.g. software triggers). For more info see
-         Documentation/iio/iio_configfs.txt.
+         Documentation/iio/iio_configfs.rst.
 
 config IIO_TRIGGER
        bool "Enable triggered sampling support"
index 0af4b28..c4810c7 100644 (file)
@@ -70,7 +70,7 @@
 #define  ADIS16201_DIAG_STAT_FLASH_UPT_FAIL_BIT                2
 /* Power supply above 3.625 V */
 #define  ADIS16201_DIAG_STAT_POWER_HIGH_BIT            1
-/* Power supply below 3.15 V */
+/* Power supply below 2.975 V */
 #define  ADIS16201_DIAG_STAT_POWER_LOW_BIT             0
 
 /* System Command Register Definition */
@@ -230,7 +230,7 @@ static const char * const adis16201_status_error_msgs[] = {
        [ADIS16201_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
        [ADIS16201_DIAG_STAT_FLASH_UPT_FAIL_BIT] = "Flash update failed",
        [ADIS16201_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
-       [ADIS16201_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V",
+       [ADIS16201_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 2.975V",
 };
 
 static const struct adis_data adis16201_data = {
index 40be7ad..98d77af 100644 (file)
@@ -72,7 +72,7 @@
 #define  ADIS16209_STAT_FLASH_UPT_FAIL_BIT     2
 /* Power supply above 3.625 V */
 #define  ADIS16209_STAT_POWER_HIGH_BIT         1
-/* Power supply below 3.15 V */
+/* Power supply below 2.975 V */
 #define  ADIS16209_STAT_POWER_LOW_BIT          0
 
 #define ADIS16209_CMD_REG                      0x3E
@@ -240,7 +240,7 @@ static const char * const adis16209_status_error_msgs[] = {
        [ADIS16209_STAT_SPI_FAIL_BIT] = "SPI failure",
        [ADIS16209_STAT_FLASH_UPT_FAIL_BIT] = "Flash update failed",
        [ADIS16209_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
-       [ADIS16209_STAT_POWER_LOW_BIT] = "Power supply below 3.15V",
+       [ADIS16209_STAT_POWER_LOW_BIT] = "Power supply below 2.975V",
 };
 
 static const struct adis_data adis16209_data = {
index 3b84cb2..055227c 100644 (file)
@@ -782,10 +782,14 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev)
        unsigned int mask;
        int i, ret;
 
-       ret = adxl372_set_interrupts(st, ADXL372_INT1_MAP_FIFO_FULL_MSK, 0);
+       ret = iio_triggered_buffer_postenable(indio_dev);
        if (ret < 0)
                return ret;
 
+       ret = adxl372_set_interrupts(st, ADXL372_INT1_MAP_FIFO_FULL_MSK, 0);
+       if (ret < 0)
+               goto err;
+
        mask = *indio_dev->active_scan_mask;
 
        for (i = 0; i < ARRAY_SIZE(adxl372_axis_lookup_table); i++) {
@@ -793,8 +797,10 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev)
                        break;
        }
 
-       if (i == ARRAY_SIZE(adxl372_axis_lookup_table))
-               return -EINVAL;
+       if (i == ARRAY_SIZE(adxl372_axis_lookup_table)) {
+               ret = -EINVAL;
+               goto err;
+       }
 
        st->fifo_format = adxl372_axis_lookup_table[i].fifo_format;
        st->fifo_set_size = bitmap_weight(indio_dev->active_scan_mask,
@@ -814,26 +820,25 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev)
        if (ret < 0) {
                st->fifo_mode = ADXL372_FIFO_BYPASSED;
                adxl372_set_interrupts(st, 0, 0);
-               return ret;
+               goto err;
        }
 
-       return iio_triggered_buffer_postenable(indio_dev);
+       return 0;
+
+err:
+       iio_triggered_buffer_predisable(indio_dev);
+       return ret;
 }
 
 static int adxl372_buffer_predisable(struct iio_dev *indio_dev)
 {
        struct adxl372_state *st = iio_priv(indio_dev);
-       int ret;
-
-       ret = iio_triggered_buffer_predisable(indio_dev);
-       if (ret < 0)
-               return ret;
 
        adxl372_set_interrupts(st, 0, 0);
        st->fifo_mode = ADXL372_FIFO_BYPASSED;
        adxl372_configure_fifo(st);
 
-       return 0;
+       return iio_triggered_buffer_predisable(indio_dev);
 }
 
 static const struct iio_buffer_setup_ops adxl372_buffer_ops = {
index e14e655..3ef7e3a 100644 (file)
@@ -7,6 +7,8 @@
 
 #include <linux/module.h>
 #include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/spi/spi.h>
 
 #include "adxl372.h"
@@ -37,9 +39,16 @@ static const struct spi_device_id adxl372_spi_id[] = {
 };
 MODULE_DEVICE_TABLE(spi, adxl372_spi_id);
 
+static const struct of_device_id adxl372_of_match[] = {
+        { .compatible = "adi,adxl372" },
+        { },
+};
+MODULE_DEVICE_TABLE(of, adxl372_of_match);
+
 static struct spi_driver adxl372_spi_driver = {
        .driver = {
                .name = "adxl372_spi",
+               .of_match_table = adxl372_of_match,
        },
        .probe = adxl372_spi_probe,
        .id_table = adxl372_spi_id,
index e589f64..6645771 100644 (file)
@@ -1487,6 +1487,7 @@ static const struct acpi_device_id kx_acpi_match[] = {
        {"KIOX0009", KXTJ21009},
        {"KIOX000A", KXCJ91008},
        {"KIOX010A", KXCJ91008}, /* KXCJ91008 inside the display of a 2-in-1 */
+       {"KIOX020A", KXCJ91008},
        {"KXTJ1009", KXTJ21009},
        {"KXJ2109",  KXTJ21009},
        {"SMO8500",  KXCJ91008},
index 011aeff..7971ec1 100644 (file)
@@ -1,6 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0-only
 #include <linux/device.h>
 #include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/spi/spi.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -41,10 +43,17 @@ static const struct spi_device_id kxsd9_spi_id[] = {
 };
 MODULE_DEVICE_TABLE(spi, kxsd9_spi_id);
 
+static const struct of_device_id kxsd9_of_match[] = {
+        { .compatible = "kionix,kxsd9" },
+        { },
+};
+MODULE_DEVICE_TABLE(of, kxsd9_of_match);
+
 static struct spi_driver kxsd9_spi_driver = {
        .driver = {
                .name = "kxsd9",
                .pm = &kxsd9_dev_pm_ops,
+               .of_match_table = kxsd9_of_match,
        },
        .probe = kxsd9_spi_probe,
        .remove = kxsd9_spi_remove,
index 274ce2f..a923f90 100644 (file)
@@ -869,8 +869,9 @@ static int sca3000_read_event_value(struct iio_dev *indio_dev,
                                    enum iio_event_info info,
                                    int *val, int *val2)
 {
-       int ret, i;
        struct sca3000_state *st = iio_priv(indio_dev);
+       long ret;
+       int i;
 
        switch (info) {
        case IIO_EV_INFO_VALUE:
@@ -882,11 +883,11 @@ static int sca3000_read_event_value(struct iio_dev *indio_dev,
                        return ret;
                *val = 0;
                if (chan->channel2 == IIO_MOD_Y)
-                       for_each_set_bit(i, (unsigned long *)&ret,
+                       for_each_set_bit(i, &ret,
                                         ARRAY_SIZE(st->info->mot_det_mult_y))
                                *val += st->info->mot_det_mult_y[i];
                else
-                       for_each_set_bit(i, (unsigned long *)&ret,
+                       for_each_set_bit(i, &ret,
                                         ARRAY_SIZE(st->info->mot_det_mult_xz))
                                *val += st->info->mot_det_mult_xz[i];
 
index 54f2ae9..0205c01 100644 (file)
@@ -45,17 +45,19 @@ static int st_accel_buffer_postenable(struct iio_dev *indio_dev)
                goto allocate_memory_error;
        }
 
-       err = st_sensors_set_axis_enable(indio_dev,
-                                       (u8)indio_dev->active_scan_mask[0]);
+       err = iio_triggered_buffer_postenable(indio_dev);
        if (err < 0)
                goto st_accel_buffer_postenable_error;
 
-       err = iio_triggered_buffer_postenable(indio_dev);
+       err = st_sensors_set_axis_enable(indio_dev,
+                                       (u8)indio_dev->active_scan_mask[0]);
        if (err < 0)
-               goto st_accel_buffer_postenable_error;
+               goto st_sensors_set_axis_enable_error;
 
        return err;
 
+st_sensors_set_axis_enable_error:
+       iio_triggered_buffer_predisable(indio_dev);
 st_accel_buffer_postenable_error:
        kfree(adata->buffer_data);
 allocate_memory_error:
@@ -64,20 +66,22 @@ allocate_memory_error:
 
 static int st_accel_buffer_predisable(struct iio_dev *indio_dev)
 {
-       int err;
+       int err, err2;
        struct st_sensor_data *adata = iio_priv(indio_dev);
 
-       err = iio_triggered_buffer_predisable(indio_dev);
-       if (err < 0)
-               goto st_accel_buffer_predisable_error;
-
        err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
        if (err < 0)
                goto st_accel_buffer_predisable_error;
 
        err = st_sensors_set_enable(indio_dev, false);
+       if (err < 0)
+               goto st_accel_buffer_predisable_error;
 
 st_accel_buffer_predisable_error:
+       err2 = iio_triggered_buffer_predisable(indio_dev);
+       if (!err)
+               err = err2;
+
        kfree(adata->buffer_data);
        return err;
 }
index f96a770..7e32862 100644 (file)
@@ -1085,7 +1085,6 @@ config VIPERBOARD_ADC
 
 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
index 659ef37..edc6f1c 100644 (file)
@@ -61,6 +61,8 @@
 #define AD7124_CONFIG_REF_SEL(x)       FIELD_PREP(AD7124_CONFIG_REF_SEL_MSK, x)
 #define AD7124_CONFIG_PGA_MSK          GENMASK(2, 0)
 #define AD7124_CONFIG_PGA(x)           FIELD_PREP(AD7124_CONFIG_PGA_MSK, x)
+#define AD7124_CONFIG_IN_BUFF_MSK      GENMASK(7, 6)
+#define AD7124_CONFIG_IN_BUFF(x)       FIELD_PREP(AD7124_CONFIG_IN_BUFF_MSK, x)
 
 /* AD7124_FILTER_X */
 #define AD7124_FILTER_FS_MSK           GENMASK(10, 0)
@@ -108,6 +110,8 @@ struct ad7124_chip_info {
 struct ad7124_channel_config {
        enum ad7124_ref_sel refsel;
        bool bipolar;
+       bool buf_positive;
+       bool buf_negative;
        unsigned int ain;
        unsigned int vref_mv;
        unsigned int pga_bits;
@@ -117,7 +121,7 @@ struct ad7124_channel_config {
 struct ad7124_state {
        const struct ad7124_chip_info *chip_info;
        struct ad_sigma_delta sd;
-       struct ad7124_channel_config channel_config[4];
+       struct ad7124_channel_config *channel_config;
        struct regulator *vref[4];
        struct clk *mclk;
        unsigned int adc_control;
@@ -435,6 +439,7 @@ static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev,
        struct ad7124_state *st = iio_priv(indio_dev);
        struct device_node *child;
        struct iio_chan_spec *chan;
+       struct ad7124_channel_config *chan_config;
        unsigned int ain[2], channel = 0, tmp;
        int ret;
 
@@ -449,8 +454,14 @@ static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev,
        if (!chan)
                return -ENOMEM;
 
+       chan_config = devm_kcalloc(indio_dev->dev.parent, st->num_channels,
+                                  sizeof(*chan_config), GFP_KERNEL);
+       if (!chan_config)
+               return -ENOMEM;
+
        indio_dev->channels = chan;
        indio_dev->num_channels = st->num_channels;
+       st->channel_config = chan_config;
 
        for_each_available_child_of_node(np, child) {
                ret = of_property_read_u32(child, "reg", &channel);
@@ -462,13 +473,6 @@ static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev,
                if (ret)
                        goto err;
 
-               if (ain[0] >= st->chip_info->num_inputs ||
-                   ain[1] >= st->chip_info->num_inputs) {
-                       dev_err(indio_dev->dev.parent,
-                               "Input pin number out of range.\n");
-                       ret = -EINVAL;
-                       goto err;
-               }
                st->channel_config[channel].ain = AD7124_CHANNEL_AINP(ain[0]) |
                                                  AD7124_CHANNEL_AINM(ain[1]);
                st->channel_config[channel].bipolar =
@@ -480,6 +484,11 @@ static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev,
                else
                        st->channel_config[channel].refsel = tmp;
 
+               st->channel_config[channel].buf_positive =
+                       of_property_read_bool(child, "adi,buffered-positive");
+               st->channel_config[channel].buf_negative =
+                       of_property_read_bool(child, "adi,buffered-negative");
+
                *chan = ad7124_channel_template;
                chan->address = channel;
                chan->scan_index = channel;
@@ -499,7 +508,7 @@ err:
 static int ad7124_setup(struct ad7124_state *st)
 {
        unsigned int val, fclk, power_mode;
-       int i, ret;
+       int i, ret, tmp;
 
        fclk = clk_get_rate(st->mclk);
        if (!fclk)
@@ -532,8 +541,12 @@ static int ad7124_setup(struct ad7124_state *st)
                if (ret < 0)
                        return ret;
 
+               tmp = (st->channel_config[i].buf_positive << 1)  +
+                       st->channel_config[i].buf_negative;
+
                val = AD7124_CONFIG_BIPOLAR(st->channel_config[i].bipolar) |
-                     AD7124_CONFIG_REF_SEL(st->channel_config[i].refsel);
+                     AD7124_CONFIG_REF_SEL(st->channel_config[i].refsel) |
+                     AD7124_CONFIG_IN_BUFF(tmp);
                ret = ad_sd_write_reg(&st->sd, AD7124_CONFIG(i), 2, val);
                if (ret < 0)
                        return ret;
index 24c70c3..aba0fd1 100644 (file)
@@ -140,7 +140,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
                           int *val2,
                           long m)
 {
-       int ret;
+       int ret, ch = 0;
        struct ad7606_state *st = iio_priv(indio_dev);
 
        switch (m) {
@@ -157,8 +157,10 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
                *val = (short)ret;
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_SCALE:
+               if (st->sw_mode_en)
+                       ch = chan->address;
                *val = 0;
-               *val2 = st->scale_avail[st->range];
+               *val2 = st->scale_avail[st->range[ch]];
                return IIO_VAL_INT_PLUS_MICRO;
        case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
                *val = st->oversampling;
@@ -194,6 +196,32 @@ static ssize_t in_voltage_scale_available_show(struct device *dev,
 
 static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0);
 
+static int ad7606_write_scale_hw(struct iio_dev *indio_dev, int ch, int val)
+{
+       struct ad7606_state *st = iio_priv(indio_dev);
+
+       gpiod_set_value(st->gpio_range, val);
+
+       return 0;
+}
+
+static int ad7606_write_os_hw(struct iio_dev *indio_dev, int val)
+{
+       struct ad7606_state *st = iio_priv(indio_dev);
+       DECLARE_BITMAP(values, 3);
+
+       values[0] = val;
+
+       gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc,
+                             st->gpio_os->info, values);
+
+       /* AD7616 requires a reset to update value */
+       if (st->chip_info->os_req_reset)
+               ad7606_reset(st);
+
+       return 0;
+}
+
 static int ad7606_write_raw(struct iio_dev *indio_dev,
                            struct iio_chan_spec const *chan,
                            int val,
@@ -201,15 +229,20 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
                            long mask)
 {
        struct ad7606_state *st = iio_priv(indio_dev);
-       DECLARE_BITMAP(values, 3);
-       int i;
+       int i, ret, ch = 0;
 
        switch (mask) {
        case IIO_CHAN_INFO_SCALE:
                mutex_lock(&st->lock);
                i = find_closest(val2, st->scale_avail, st->num_scales);
-               gpiod_set_value(st->gpio_range, i);
-               st->range = i;
+               if (st->sw_mode_en)
+                       ch = chan->address;
+               ret = st->write_scale(indio_dev, ch, i);
+               if (ret < 0) {
+                       mutex_unlock(&st->lock);
+                       return ret;
+               }
+               st->range[ch] = i;
                mutex_unlock(&st->lock);
 
                return 0;
@@ -218,17 +251,12 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
                        return -EINVAL;
                i = find_closest(val, st->oversampling_avail,
                                 st->num_os_ratios);
-
-               values[0] = i;
-
                mutex_lock(&st->lock);
-               gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc,
-                                     st->gpio_os->info, values);
-
-               /* AD7616 requires a reset to update value */
-               if (st->chip_info->os_req_reset)
-                       ad7606_reset(st);
-
+               ret = st->write_os(indio_dev, i);
+               if (ret < 0) {
+                       mutex_unlock(&st->lock);
+                       return ret;
+               }
                st->oversampling = st->oversampling_avail[i];
                mutex_unlock(&st->lock);
 
@@ -536,7 +564,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
        st->bops = bops;
        st->base_address = base_address;
        /* tied to logic low, analog input range is +/- 5V */
-       st->range = 0;
+       st->range[0] = 0;
        st->oversampling = 1;
        st->scale_avail = ad7606_scale_avail;
        st->num_scales = ARRAY_SIZE(ad7606_scale_avail);
@@ -589,6 +617,39 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
        if (ret)
                dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n");
 
+       st->write_scale = ad7606_write_scale_hw;
+       st->write_os = ad7606_write_os_hw;
+
+       if (st->chip_info->sw_mode_config)
+               st->sw_mode_en = device_property_present(st->dev,
+                                                        "adi,sw-mode");
+
+       if (st->sw_mode_en) {
+               /* After reset, in software mode, ±10 V is set by default */
+               memset32(st->range, 2, ARRAY_SIZE(st->range));
+               indio_dev->info = &ad7606_info_os_and_range;
+
+               /*
+                * In software mode, the range gpio has no longer its function.
+                * Instead, the scale can be configured individually for each
+                * channel from the range registers.
+                */
+               if (st->chip_info->write_scale_sw)
+                       st->write_scale = st->chip_info->write_scale_sw;
+
+               /*
+                * In software mode, the oversampling is no longer configured
+                * with GPIO pins. Instead, the oversampling can be configured
+                * in configuratiion register.
+                */
+               if (st->chip_info->write_os_sw)
+                       st->write_os = st->chip_info->write_os_sw;
+
+               ret = st->chip_info->sw_mode_config(indio_dev);
+               if (ret < 0)
+                       return ret;
+       }
+
        st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
                                          indio_dev->name, indio_dev->id);
        if (!st->trig)
@@ -643,7 +704,7 @@ static int ad7606_resume(struct device *dev)
        struct ad7606_state *st = iio_priv(indio_dev);
 
        if (st->gpio_standby) {
-               gpiod_set_value(st->gpio_range, st->range);
+               gpiod_set_value(st->gpio_range, st->range[0]);
                gpiod_set_value(st->gpio_standby, 1);
                ad7606_reset(st);
        }
index f9ef521..d8a509c 100644 (file)
  *                     oversampling ratios.
  * @oversampling_num   number of elements stored in oversampling_avail array
  * @os_req_reset       some devices require a reset to update oversampling
+ * @write_scale_sw     pointer to the function which writes the scale via spi
+                       in software mode
+ * @write_os_sw                pointer to the function which writes the os via spi
+                       in software mode
+ * @sw_mode_config:    pointer to a function which configured the device
+ *                     for software mode
  */
 struct ad7606_chip_info {
        const struct iio_chan_spec      *channels;
@@ -23,6 +29,9 @@ struct ad7606_chip_info {
        const unsigned int              *oversampling_avail;
        unsigned int                    oversampling_num;
        bool                            os_req_reset;
+       int (*write_scale_sw)(struct iio_dev *indio_dev, int ch, int val);
+       int (*write_os_sw)(struct iio_dev *indio_dev, int val);
+       int (*sw_mode_config)(struct iio_dev *indio_dev);
 };
 
 /**
@@ -34,11 +43,14 @@ struct ad7606_chip_info {
  * @range              voltage range selection, selects which scale to apply
  * @oversampling       oversampling selection
  * @base_address       address from where to read data in parallel operation
+ * @sw_mode_en         software mode enabled
  * @scale_avail                pointer to the array which stores the available scales
  * @num_scales         number of elements stored in the scale_avail array
  * @oversampling_avail pointer to the array which stores the available
  *                     oversampling ratios.
  * @num_os_ratios      number of elements stored in oversampling_avail array
+ * @write_scale                pointer to the function which writes the scale
+ * @write_os           pointer to the function which writes the os
  * @lock               protect sensor state from concurrent accesses to GPIOs
  * @gpio_convst        GPIO descriptor for conversion start signal (CONVST)
  * @gpio_reset         GPIO descriptor for device hard-reset
@@ -57,13 +69,16 @@ struct ad7606_state {
        const struct ad7606_chip_info   *chip_info;
        struct regulator                *reg;
        const struct ad7606_bus_ops     *bops;
-       unsigned int                    range;
+       unsigned int                    range[16];
        unsigned int                    oversampling;
        void __iomem                    *base_address;
+       bool                            sw_mode_en;
        const unsigned int              *scale_avail;
        unsigned int                    num_scales;
        const unsigned int              *oversampling_avail;
        unsigned int                    num_os_ratios;
+       int (*write_scale)(struct iio_dev *indio_dev, int ch, int val);
+       int (*write_os)(struct iio_dev *indio_dev, int val);
 
        struct mutex                    lock; /* protect sensor state */
        struct gpio_desc                *gpio_convst;
index 1423221..2640b75 100644 (file)
@@ -357,7 +357,7 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
        ret = ad_sigma_delta_set_channel(sigma_delta,
                indio_dev->channels[channel].address);
        if (ret)
-               goto err_predisable;
+               return ret;
 
        spi_bus_lock(sigma_delta->spi->master);
        sigma_delta->bus_locked = true;
@@ -374,7 +374,6 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
 
 err_unlock:
        spi_bus_unlock(sigma_delta->spi->master);
-err_predisable:
 
        return ret;
 }
index d384cf0..a2837a0 100644 (file)
@@ -1578,8 +1578,7 @@ static void at91_adc_hw_init(struct at91_adc_state *st)
 static ssize_t at91_adc_get_fifo_state(struct device *dev,
                                       struct device_attribute *attr, char *buf)
 {
-       struct iio_dev *indio_dev =
-                       platform_get_drvdata(to_platform_device(dev));
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct at91_adc_state *st = iio_priv(indio_dev);
 
        return scnprintf(buf, PAGE_SIZE, "%d\n", !!st->dma_st.dma_chan);
@@ -1588,8 +1587,7 @@ static ssize_t at91_adc_get_fifo_state(struct device *dev,
 static ssize_t at91_adc_get_watermark(struct device *dev,
                                      struct device_attribute *attr, char *buf)
 {
-       struct iio_dev *indio_dev =
-                       platform_get_drvdata(to_platform_device(dev));
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct at91_adc_state *st = iio_priv(indio_dev);
 
        return scnprintf(buf, PAGE_SIZE, "%d\n", st->dma_st.watermark);
@@ -1841,8 +1839,7 @@ static int at91_adc_remove(struct platform_device *pdev)
 
 static __maybe_unused int at91_adc_suspend(struct device *dev)
 {
-       struct iio_dev *indio_dev =
-                       platform_get_drvdata(to_platform_device(dev));
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct at91_adc_state *st = iio_priv(indio_dev);
 
        /*
@@ -1862,8 +1859,7 @@ static __maybe_unused int at91_adc_suspend(struct device *dev)
 
 static __maybe_unused int at91_adc_resume(struct device *dev)
 {
-       struct iio_dev *indio_dev =
-                       platform_get_drvdata(to_platform_device(dev));
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct at91_adc_state *st = iio_priv(indio_dev);
        int ret;
 
index d23709e..32f1c4a 100644 (file)
@@ -1359,7 +1359,7 @@ static int at91_adc_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM_SLEEP
 static int at91_adc_suspend(struct device *dev)
 {
-       struct iio_dev *idev = platform_get_drvdata(to_platform_device(dev));
+       struct iio_dev *idev = dev_get_drvdata(dev);
        struct at91_adc_state *st = iio_priv(idev);
 
        pinctrl_pm_select_sleep_state(dev);
@@ -1370,7 +1370,7 @@ static int at91_adc_suspend(struct device *dev)
 
 static int at91_adc_resume(struct device *dev)
 {
-       struct iio_dev *idev = platform_get_drvdata(to_platform_device(dev));
+       struct iio_dev *idev = dev_get_drvdata(dev);
        struct at91_adc_state *st = iio_priv(idev);
 
        clk_prepare_enable(st->clk);
index 4fe97c2..26a7bbe 100644 (file)
@@ -78,6 +78,7 @@
 #define IMX7D_REG_ADC_INT_STATUS_CHANNEL_CONV_TIME_OUT         0xf0000
 
 #define IMX7D_ADC_TIMEOUT              msecs_to_jiffies(100)
+#define IMX7D_ADC_INPUT_CLK            24000000
 
 enum imx7d_adc_clk_pre_div {
        IMX7D_ADC_ANALOG_CLK_PRE_DIV_4,
@@ -100,8 +101,6 @@ struct imx7d_adc_feature {
        enum imx7d_adc_average_num avg_num;
 
        u32 core_time_unit;     /* impact the sample rate */
-
-       bool average_en;
 };
 
 struct imx7d_adc {
@@ -179,7 +178,6 @@ static void imx7d_adc_feature_config(struct imx7d_adc *info)
        info->adc_feature.clk_pre_div = IMX7D_ADC_ANALOG_CLK_PRE_DIV_4;
        info->adc_feature.avg_num = IMX7D_ADC_AVERAGE_NUM_32;
        info->adc_feature.core_time_unit = 1;
-       info->adc_feature.average_en = true;
 }
 
 static void imx7d_adc_sample_rate_set(struct imx7d_adc *info)
@@ -240,9 +238,8 @@ static void imx7d_adc_channel_set(struct imx7d_adc *info)
 
        /* the channel choose single conversion, and enable average mode */
        cfg1 |= (IMX7D_REG_ADC_CH_CFG1_CHANNEL_EN |
-                IMX7D_REG_ADC_CH_CFG1_CHANNEL_SINGLE);
-       if (info->adc_feature.average_en)
-               cfg1 |= IMX7D_REG_ADC_CH_CFG1_CHANNEL_AVG_EN;
+                IMX7D_REG_ADC_CH_CFG1_CHANNEL_SINGLE |
+                IMX7D_REG_ADC_CH_CFG1_CHANNEL_AVG_EN);
 
        /*
         * physical channel 0 chose logical channel A
@@ -272,13 +269,11 @@ static void imx7d_adc_channel_set(struct imx7d_adc *info)
 
 static u32 imx7d_adc_get_sample_rate(struct imx7d_adc *info)
 {
-       /* input clock is always 24MHz */
-       u32 input_clk = 24000000;
        u32 analogue_core_clk;
        u32 core_time_unit = info->adc_feature.core_time_unit;
        u32 tmp;
 
-       analogue_core_clk = input_clk / info->pre_div_num;
+       analogue_core_clk = IMX7D_ADC_INPUT_CLK / info->pre_div_num;
        tmp = (core_time_unit + 1) * 6;
 
        return analogue_core_clk / tmp;
@@ -493,11 +488,8 @@ static int imx7d_adc_probe(struct platform_device *pdev)
        info->dev = dev;
 
        info->regs = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(info->regs)) {
-               ret = PTR_ERR(info->regs);
-               dev_err(dev, "Failed to remap adc memory, err = %d\n", ret);
-               return ret;
-       }
+       if (IS_ERR(info->regs))
+               return PTR_ERR(info->regs);
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
@@ -531,9 +523,7 @@ static int imx7d_adc_probe(struct platform_device *pdev)
        indio_dev->channels = imx7d_adc_iio_channels;
        indio_dev->num_channels = ARRAY_SIZE(imx7d_adc_iio_channels);
 
-       ret = devm_request_irq(dev, irq,
-                              imx7d_adc_isr, 0,
-                              dev_name(dev), info);
+       ret = devm_request_irq(dev, irq, imx7d_adc_isr, 0, dev_name(dev), info);
        if (ret < 0) {
                dev_err(dev, "Failed requesting irq, irq = %d\n", irq);
                return ret;
index 70bbcf2..7b28d04 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Amlogic Meson Successive Approximation Register (SAR) A/D Converter
  *
index d1759c8..7bbb64c 100644 (file)
 #define MT6577_AUXADC_POWER_READY_MS          1
 #define MT6577_AUXADC_SAMPLE_READY_US         25
 
+struct mtk_auxadc_compatible {
+       bool sample_data_cali;
+       bool check_global_idle;
+};
+
 struct mt6577_auxadc_device {
        void __iomem *reg_base;
        struct clk *adc_clk;
        struct mutex lock;
+       const struct mtk_auxadc_compatible *dev_comp;
+};
+
+static const struct mtk_auxadc_compatible mt8173_compat = {
+       .sample_data_cali = false,
+       .check_global_idle = true,
+};
+
+static const struct mtk_auxadc_compatible mt6765_compat = {
+       .sample_data_cali = true,
+       .check_global_idle = false,
 };
 
 #define MT6577_AUXADC_CHANNEL(idx) {                               \
@@ -66,6 +82,11 @@ static const struct iio_chan_spec mt6577_auxadc_iio_channels[] = {
        MT6577_AUXADC_CHANNEL(15),
 };
 
+static int mt_auxadc_get_cali_data(int rawdata, bool enable_cali)
+{
+       return rawdata;
+}
+
 static inline void mt6577_auxadc_mod_reg(void __iomem *reg,
                                         u32 or_mask, u32 and_mask)
 {
@@ -112,15 +133,17 @@ static int mt6577_auxadc_read(struct iio_dev *indio_dev,
        /* we must delay here for hardware sample channel data */
        udelay(MT6577_AUXADC_SAMPLE_READY_US);
 
-       /* check MTK_AUXADC_CON2 if auxadc is idle */
-       ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2, val,
-                                ((val & MT6577_AUXADC_STA) == 0),
-                                MT6577_AUXADC_SLEEP_US,
-                                MT6577_AUXADC_TIMEOUT_US);
-       if (ret < 0) {
-               dev_err(indio_dev->dev.parent,
-                       "wait for auxadc idle time out\n");
-               goto err_timeout;
+       if (adc_dev->dev_comp->check_global_idle) {
+               /* check MTK_AUXADC_CON2 if auxadc is idle */
+               ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2,
+                                        val, ((val & MT6577_AUXADC_STA) == 0),
+                                        MT6577_AUXADC_SLEEP_US,
+                                        MT6577_AUXADC_TIMEOUT_US);
+               if (ret < 0) {
+                       dev_err(indio_dev->dev.parent,
+                               "wait for auxadc idle time out\n");
+                       goto err_timeout;
+               }
        }
 
        /* read channel and make sure ready bit == 1 */
@@ -155,6 +178,8 @@ static int mt6577_auxadc_read_raw(struct iio_dev *indio_dev,
                                  int *val2,
                                  long info)
 {
+       struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
+
        switch (info) {
        case IIO_CHAN_INFO_PROCESSED:
                *val = mt6577_auxadc_read(indio_dev, chan);
@@ -164,6 +189,8 @@ static int mt6577_auxadc_read_raw(struct iio_dev *indio_dev,
                                chan->channel);
                        return *val;
                }
+               if (adc_dev->dev_comp->sample_data_cali)
+                       *val = mt_auxadc_get_cali_data(*val, true);
                return IIO_VAL_INT;
 
        default:
@@ -296,10 +323,11 @@ static SIMPLE_DEV_PM_OPS(mt6577_auxadc_pm_ops,
                         mt6577_auxadc_resume);
 
 static const struct of_device_id mt6577_auxadc_of_match[] = {
-       { .compatible = "mediatek,mt2701-auxadc", },
-       { .compatible = "mediatek,mt2712-auxadc", },
-       { .compatible = "mediatek,mt7622-auxadc", },
-       { .compatible = "mediatek,mt8173-auxadc", },
+       { .compatible = "mediatek,mt2701-auxadc", .data = &mt8173_compat},
+       { .compatible = "mediatek,mt2712-auxadc", .data = &mt8173_compat},
+       { .compatible = "mediatek,mt7622-auxadc", .data = &mt8173_compat},
+       { .compatible = "mediatek,mt8173-auxadc", .data = &mt8173_compat},
+       { .compatible = "mediatek,mt6765-auxadc", .data = &mt6765_compat},
        { }
 };
 MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match);
index 2c0d031..2d68573 100644 (file)
@@ -485,10 +485,8 @@ static int rcar_gyroadc_probe(struct platform_device *pdev)
        int ret;
 
        indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
-       if (!indio_dev) {
-               dev_err(dev, "Failed to allocate IIO device.\n");
+       if (!indio_dev)
                return -ENOMEM;
-       }
 
        priv = iio_priv(indio_dev);
        priv->dev = dev;
index 2327ec1..1f7ce51 100644 (file)
@@ -87,6 +87,7 @@ struct stm32_adc_priv_cfg {
  * @domain:            irq domain reference
  * @aclk:              clock reference for the analog circuitry
  * @bclk:              bus clock common for all ADCs, depends on part used
+ * @vdda:              vdda analog supply reference
  * @vref:              regulator reference
  * @cfg:               compatible configuration data
  * @common:            common data for all ADC instances
@@ -97,6 +98,7 @@ struct stm32_adc_priv {
        struct irq_domain               *domain;
        struct clk                      *aclk;
        struct clk                      *bclk;
+       struct regulator                *vdda;
        struct regulator                *vref;
        const struct stm32_adc_priv_cfg *cfg;
        struct stm32_adc_common         common;
@@ -394,10 +396,16 @@ static int stm32_adc_core_hw_start(struct device *dev)
        struct stm32_adc_priv *priv = to_stm32_adc_priv(common);
        int ret;
 
+       ret = regulator_enable(priv->vdda);
+       if (ret < 0) {
+               dev_err(dev, "vdda enable failed %d\n", ret);
+               return ret;
+       }
+
        ret = regulator_enable(priv->vref);
        if (ret < 0) {
                dev_err(dev, "vref enable failed\n");
-               return ret;
+               goto err_vdda_disable;
        }
 
        if (priv->bclk) {
@@ -425,6 +433,8 @@ err_bclk_disable:
                clk_disable_unprepare(priv->bclk);
 err_regulator_disable:
        regulator_disable(priv->vref);
+err_vdda_disable:
+       regulator_disable(priv->vdda);
 
        return ret;
 }
@@ -441,6 +451,7 @@ static void stm32_adc_core_hw_stop(struct device *dev)
        if (priv->bclk)
                clk_disable_unprepare(priv->bclk);
        regulator_disable(priv->vref);
+       regulator_disable(priv->vdda);
 }
 
 static int stm32_adc_probe(struct platform_device *pdev)
@@ -468,6 +479,14 @@ static int stm32_adc_probe(struct platform_device *pdev)
                return PTR_ERR(priv->common.base);
        priv->common.phys_base = res->start;
 
+       priv->vdda = devm_regulator_get(&pdev->dev, "vdda");
+       if (IS_ERR(priv->vdda)) {
+               ret = PTR_ERR(priv->vdda);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "vdda get failed, %d\n", ret);
+               return ret;
+       }
+
        priv->vref = devm_regulator_get(&pdev->dev, "vref");
        if (IS_ERR(priv->vref)) {
                ret = PTR_ERR(priv->vref);
index 19adc2b..ee1e056 100644 (file)
 #define DFSDM_MAX_INT_OVERSAMPLING 256
 #define DFSDM_MAX_FL_OVERSAMPLING 1024
 
-/* Max sample resolutions */
-#define DFSDM_MAX_RES BIT(31)
-#define DFSDM_DATA_RES BIT(23)
+/* Limit filter output resolution to 31 bits. (i.e. sample range is +/-2^30) */
+#define DFSDM_DATA_MAX BIT(30)
+/*
+ * Data are output as two's complement data in a 24 bit field.
+ * Data from filters are in the range +/-2^(n-1)
+ * 2^(n-1) maximum positive value cannot be coded in 2's complement n bits
+ * An extra bit is required to avoid wrap-around of the binary code for 2^(n-1)
+ * So, the resolution of samples from filter is actually limited to 23 bits
+ */
+#define DFSDM_DATA_RES 24
 
 /* Filter configuration */
 #define DFSDM_CR1_CFG_MASK (DFSDM_CR1_RCH_MASK | DFSDM_CR1_RCONT_MASK | \
@@ -181,14 +188,15 @@ static int stm32_dfsdm_get_jextsel(struct iio_dev *indio_dev,
        return -EINVAL;
 }
 
-static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl,
-                               unsigned int fast, unsigned int oversamp)
+static int stm32_dfsdm_compute_osrs(struct stm32_dfsdm_filter *fl,
+                                   unsigned int fast, unsigned int oversamp)
 {
        unsigned int i, d, fosr, iosr;
-       u64 res;
-       s64 delta;
+       u64 res, max;
+       int bits, shift;
        unsigned int m = 1;     /* multiplication factor */
        unsigned int p = fl->ford;      /* filter order (ford) */
+       struct stm32_dfsdm_filter_osr *flo = &fl->flo[fast];
 
        pr_debug("%s: Requested oversampling: %d\n",  __func__, oversamp);
        /*
@@ -207,11 +215,8 @@ static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl,
 
        /*
         * Look for filter and integrator oversampling ratios which allows
-        * to reach 24 bits data output resolution.
-        * Leave as soon as if exact resolution if reached.
-        * Otherwise the higher resolution below 32 bits is kept.
+        * to maximize data output resolution.
         */
-       fl->res = 0;
        for (fosr = 1; fosr <= DFSDM_MAX_FL_OVERSAMPLING; fosr++) {
                for (iosr = 1; iosr <= DFSDM_MAX_INT_OVERSAMPLING; iosr++) {
                        if (fast)
@@ -236,33 +241,91 @@ static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl,
                        res = fosr;
                        for (i = p - 1; i > 0; i--) {
                                res = res * (u64)fosr;
-                               if (res > DFSDM_MAX_RES)
+                               if (res > DFSDM_DATA_MAX)
                                        break;
                        }
-                       if (res > DFSDM_MAX_RES)
+                       if (res > DFSDM_DATA_MAX)
                                continue;
+
                        res = res * (u64)m * (u64)iosr;
-                       if (res > DFSDM_MAX_RES)
+                       if (res > DFSDM_DATA_MAX)
                                continue;
 
-                       delta = res - DFSDM_DATA_RES;
-
-                       if (res >= fl->res) {
-                               fl->res = res;
-                               fl->fosr = fosr;
-                               fl->iosr = iosr;
-                               fl->fast = fast;
-                               pr_debug("%s: fosr = %d, iosr = %d\n",
-                                        __func__, fl->fosr, fl->iosr);
+                       if (res >= flo->res) {
+                               flo->res = res;
+                               flo->fosr = fosr;
+                               flo->iosr = iosr;
+
+                               bits = fls(flo->res);
+                               /* 8 LBSs in data register contain chan info */
+                               max = flo->res << 8;
+
+                               /* if resolution is not a power of two */
+                               if (flo->res > BIT(bits - 1))
+                                       bits++;
+                               else
+                                       max--;
+
+                               shift = DFSDM_DATA_RES - bits;
+                               /*
+                                * Compute right/left shift
+                                * Right shift is performed by hardware
+                                * when transferring samples to data register.
+                                * Left shift is done by software on buffer
+                                */
+                               if (shift > 0) {
+                                       /* Resolution is lower than 24 bits */
+                                       flo->rshift = 0;
+                                       flo->lshift = shift;
+                               } else {
+                                       /*
+                                        * If resolution is 24 bits or more,
+                                        * max positive value may be ambiguous
+                                        * (equal to max negative value as sign
+                                        * bit is dropped).
+                                        * Reduce resolution to 23 bits (rshift)
+                                        * to keep the sign on bit 23 and treat
+                                        * saturation before rescaling on 24
+                                        * bits (lshift).
+                                        */
+                                       flo->rshift = 1 - shift;
+                                       flo->lshift = 1;
+                                       max >>= flo->rshift;
+                               }
+                               flo->max = (s32)max;
+
+                               pr_debug("%s: fast %d, fosr %d, iosr %d, res 0x%llx/%d bits, rshift %d, lshift %d\n",
+                                        __func__, fast, flo->fosr, flo->iosr,
+                                        flo->res, bits, flo->rshift,
+                                        flo->lshift);
                        }
-
-                       if (!delta)
-                               return 0;
                }
        }
 
-       if (!fl->res)
+       if (!flo->res)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int stm32_dfsdm_compute_all_osrs(struct iio_dev *indio_dev,
+                                       unsigned int oversamp)
+{
+       struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
+       struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
+       int ret0, ret1;
+
+       memset(&fl->flo[0], 0, sizeof(fl->flo[0]));
+       memset(&fl->flo[1], 0, sizeof(fl->flo[1]));
+
+       ret0 = stm32_dfsdm_compute_osrs(fl, 0, oversamp);
+       ret1 = stm32_dfsdm_compute_osrs(fl, 1, oversamp);
+       if (ret0 < 0 && ret1 < 0) {
+               dev_err(&indio_dev->dev,
+                       "Filter parameters not found: errors %d/%d\n",
+                       ret0, ret1);
                return -EINVAL;
+       }
 
        return 0;
 }
@@ -384,6 +447,50 @@ static int stm32_dfsdm_filter_set_trig(struct stm32_dfsdm_adc *adc,
        return 0;
 }
 
+static int stm32_dfsdm_channels_configure(struct stm32_dfsdm_adc *adc,
+                                         unsigned int fl_id,
+                                         struct iio_trigger *trig)
+{
+       struct iio_dev *indio_dev = iio_priv_to_dev(adc);
+       struct regmap *regmap = adc->dfsdm->regmap;
+       struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[fl_id];
+       struct stm32_dfsdm_filter_osr *flo = &fl->flo[0];
+       const struct iio_chan_spec *chan;
+       unsigned int bit;
+       int ret;
+
+       fl->fast = 0;
+
+       /*
+        * In continuous mode, use fast mode configuration,
+        * if it provides a better resolution.
+        */
+       if (adc->nconv == 1 && !trig &&
+           (indio_dev->currentmode & INDIO_BUFFER_SOFTWARE)) {
+               if (fl->flo[1].res >= fl->flo[0].res) {
+                       fl->fast = 1;
+                       flo = &fl->flo[1];
+               }
+       }
+
+       if (!flo->res)
+               return -EINVAL;
+
+       for_each_set_bit(bit, &adc->smask,
+                        sizeof(adc->smask) * BITS_PER_BYTE) {
+               chan = indio_dev->channels + bit;
+
+               ret = regmap_update_bits(regmap,
+                                        DFSDM_CHCFGR2(chan->channel),
+                                        DFSDM_CHCFGR2_DTRBS_MASK,
+                                        DFSDM_CHCFGR2_DTRBS(flo->rshift));
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static int stm32_dfsdm_filter_configure(struct stm32_dfsdm_adc *adc,
                                        unsigned int fl_id,
                                        struct iio_trigger *trig)
@@ -391,6 +498,7 @@ static int stm32_dfsdm_filter_configure(struct stm32_dfsdm_adc *adc,
        struct iio_dev *indio_dev = iio_priv_to_dev(adc);
        struct regmap *regmap = adc->dfsdm->regmap;
        struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[fl_id];
+       struct stm32_dfsdm_filter_osr *flo = &fl->flo[fl->fast];
        u32 cr1;
        const struct iio_chan_spec *chan;
        unsigned int bit, jchg = 0;
@@ -398,13 +506,13 @@ static int stm32_dfsdm_filter_configure(struct stm32_dfsdm_adc *adc,
 
        /* Average integrator oversampling */
        ret = regmap_update_bits(regmap, DFSDM_FCR(fl_id), DFSDM_FCR_IOSR_MASK,
-                                DFSDM_FCR_IOSR(fl->iosr - 1));
+                                DFSDM_FCR_IOSR(flo->iosr - 1));
        if (ret)
                return ret;
 
        /* Filter order and Oversampling */
        ret = regmap_update_bits(regmap, DFSDM_FCR(fl_id), DFSDM_FCR_FOSR_MASK,
-                                DFSDM_FCR_FOSR(fl->fosr - 1));
+                                DFSDM_FCR_FOSR(flo->fosr - 1));
        if (ret)
                return ret;
 
@@ -417,6 +525,12 @@ static int stm32_dfsdm_filter_configure(struct stm32_dfsdm_adc *adc,
        if (ret)
                return ret;
 
+       ret = regmap_update_bits(regmap, DFSDM_CR1(fl_id),
+                                DFSDM_CR1_FAST_MASK,
+                                DFSDM_CR1_FAST(fl->fast));
+       if (ret)
+               return ret;
+
        /*
         * DFSDM modes configuration W.R.T audio/iio type modes
         * ----------------------------------------------------------------
@@ -563,7 +677,6 @@ static int dfsdm_adc_set_samp_freq(struct iio_dev *indio_dev,
                                   unsigned int spi_freq)
 {
        struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
-       struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
        unsigned int oversamp;
        int ret;
 
@@ -573,11 +686,10 @@ static int dfsdm_adc_set_samp_freq(struct iio_dev *indio_dev,
                        "Rate not accurate. requested (%u), actual (%u)\n",
                        sample_freq, spi_freq / oversamp);
 
-       ret = stm32_dfsdm_set_osrs(fl, 0, oversamp);
-       if (ret < 0) {
-               dev_err(&indio_dev->dev, "No filter parameters that match!\n");
+       ret = stm32_dfsdm_compute_all_osrs(indio_dev, oversamp);
+       if (ret < 0)
                return ret;
-       }
+
        adc->sample_freq = spi_freq / oversamp;
        adc->oversamp = oversamp;
 
@@ -623,6 +735,10 @@ static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc,
        struct regmap *regmap = adc->dfsdm->regmap;
        int ret;
 
+       ret = stm32_dfsdm_channels_configure(adc, adc->fl_id, trig);
+       if (ret < 0)
+               return ret;
+
        ret = stm32_dfsdm_start_channel(adc);
        if (ret < 0)
                return ret;
@@ -702,6 +818,30 @@ static unsigned int stm32_dfsdm_adc_dma_residue(struct stm32_dfsdm_adc *adc)
        return 0;
 }
 
+static inline void stm32_dfsdm_process_data(struct stm32_dfsdm_adc *adc,
+                                           s32 *buffer)
+{
+       struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
+       struct stm32_dfsdm_filter_osr *flo = &fl->flo[fl->fast];
+       unsigned int i = adc->nconv;
+       s32 *ptr = buffer;
+
+       while (i--) {
+               /* Mask 8 LSB that contains the channel ID */
+               *ptr &= 0xFFFFFF00;
+               /* Convert 2^(n-1) sample to 2^(n-1)-1 to avoid wrap-around */
+               if (*ptr > flo->max)
+                       *ptr -= 1;
+               /*
+                * Samples from filter are retrieved with 23 bits resolution
+                * or less. Shift left to align MSB on 24 bits.
+                */
+               *ptr <<= flo->lshift;
+
+               ptr++;
+       }
+}
+
 static irqreturn_t stm32_dfsdm_adc_trigger_handler(int irq, void *p)
 {
        struct iio_poll_func *pf = p;
@@ -710,7 +850,9 @@ static irqreturn_t stm32_dfsdm_adc_trigger_handler(int irq, void *p)
        int available = stm32_dfsdm_adc_dma_residue(adc);
 
        while (available >= indio_dev->scan_bytes) {
-               u32 *buffer = (u32 *)&adc->rx_buf[adc->bufi];
+               s32 *buffer = (s32 *)&adc->rx_buf[adc->bufi];
+
+               stm32_dfsdm_process_data(adc, buffer);
 
                iio_push_to_buffers_with_timestamp(indio_dev, buffer,
                                                   pf->timestamp);
@@ -751,10 +893,10 @@ static void stm32_dfsdm_dma_buffer_done(void *data)
        old_pos = adc->bufi;
 
        while (available >= indio_dev->scan_bytes) {
-               u32 *buffer = (u32 *)&adc->rx_buf[adc->bufi];
+               s32 *buffer = (s32 *)&adc->rx_buf[adc->bufi];
+
+               stm32_dfsdm_process_data(adc, buffer);
 
-               /* Mask 8 LSB that contains the channel ID */
-               *buffer = (*buffer & 0xFFFFFF00) << 8;
                available -= indio_dev->scan_bytes;
                adc->bufi += indio_dev->scan_bytes;
                if (adc->bufi >= adc->buf_sz) {
@@ -776,6 +918,11 @@ static void stm32_dfsdm_dma_buffer_done(void *data)
 static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev)
 {
        struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
+       /*
+        * The DFSDM supports half-word transfers. However, for 16 bits record,
+        * 4 bytes buswidth is kept, to avoid losing samples LSBs when left
+        * shift is required.
+        */
        struct dma_slave_config config = {
                .src_addr = (dma_addr_t)adc->dfsdm->phys_base,
                .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
@@ -1068,7 +1215,6 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev,
                                 int val, int val2, long mask)
 {
        struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
-       struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
        struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[chan->channel];
        unsigned int spi_freq;
        int ret = -EINVAL;
@@ -1078,7 +1224,7 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev,
                ret = iio_device_claim_direct_mode(indio_dev);
                if (ret)
                        return ret;
-               ret = stm32_dfsdm_set_osrs(fl, 0, val);
+               ret = stm32_dfsdm_compute_all_osrs(indio_dev, val);
                if (!ret)
                        adc->oversamp = val;
                iio_device_release_direct_mode(indio_dev);
@@ -1277,11 +1423,11 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev,
                                        BIT(IIO_CHAN_INFO_SAMP_FREQ);
 
        if (adc->dev_data->type == DFSDM_AUDIO) {
-               ch->scan_type.sign = 's';
                ch->ext_info = dfsdm_adc_audio_ext_info;
        } else {
-               ch->scan_type.sign = 'u';
+               ch->scan_type.shift = 8;
        }
+       ch->scan_type.sign = 's';
        ch->scan_type.realbits = 24;
        ch->scan_type.storagebits = 32;
 
@@ -1327,8 +1473,7 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev)
        int ret, chan_idx;
 
        adc->oversamp = DFSDM_DEFAULT_OVERSAMPLING;
-       ret = stm32_dfsdm_set_osrs(&adc->dfsdm->fl_list[adc->fl_id], 0,
-                                  adc->oversamp);
+       ret = stm32_dfsdm_compute_all_osrs(indio_dev, adc->oversamp);
        if (ret < 0)
                return ret;
 
@@ -1456,6 +1601,12 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev)
         * So IRQ associated to filter instance 0 is dedicated to the Filter 0.
         */
        irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               if (irq != -EPROBE_DEFER)
+                       dev_err(dev, "Failed to get IRQ: %d\n", irq);
+               return irq;
+       }
+
        ret = devm_request_irq(dev, irq, stm32_dfsdm_irq,
                               0, pdev->name, adc);
        if (ret < 0) {
index 0a4d374..26e2011 100644 (file)
@@ -233,6 +233,8 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev,
        }
        priv->dfsdm.phys_base = res->start;
        priv->dfsdm.base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(priv->dfsdm.base))
+               return PTR_ERR(priv->dfsdm.base);
 
        /*
         * "dfsdm" clock is mandatory for DFSDM peripheral clocking.
@@ -242,8 +244,10 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev,
         */
        priv->clk = devm_clk_get(&pdev->dev, "dfsdm");
        if (IS_ERR(priv->clk)) {
-               dev_err(&pdev->dev, "No stm32_dfsdm_clk clock found\n");
-               return -EINVAL;
+               ret = PTR_ERR(priv->clk);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "Failed to get clock (%d)\n", ret);
+               return ret;
        }
 
        priv->aclk = devm_clk_get(&pdev->dev, "audio");
index 8708394..5dbdae4 100644 (file)
@@ -243,19 +243,33 @@ enum stm32_dfsdm_sinc_order {
 };
 
 /**
- * struct stm32_dfsdm_filter - structure relative to stm32 FDSDM filter
+ * struct stm32_dfsdm_filter_osr - DFSDM filter settings linked to oversampling
  * @iosr: integrator oversampling
  * @fosr: filter oversampling
- * @ford: filter order
+ * @rshift: output sample right shift (hardware shift)
+ * @lshift: output sample left shift (software shift)
  * @res: output sample resolution
+ * @max: output sample maximum positive value
+ */
+struct stm32_dfsdm_filter_osr {
+       unsigned int iosr;
+       unsigned int fosr;
+       unsigned int rshift;
+       unsigned int lshift;
+       u64 res;
+       s32 max;
+};
+
+/**
+ * struct stm32_dfsdm_filter - structure relative to stm32 FDSDM filter
+ * @ford: filter order
+ * @flo: filter oversampling data table indexed by fast mode flag
  * @sync_mode: filter synchronized with filter 0
  * @fast: filter fast mode
  */
 struct stm32_dfsdm_filter {
-       unsigned int iosr;
-       unsigned int fosr;
        enum stm32_dfsdm_sinc_order ford;
-       u64 res;
+       struct stm32_dfsdm_filter_osr flo[2];
        unsigned int sync_mode;
        unsigned int fast;
 };
index 7921f82..bd72727 100644 (file)
@@ -65,6 +65,8 @@ static int stmpe_read_voltage(struct stmpe_adc *info,
 
        mutex_lock(&info->lock);
 
+       reinit_completion(&info->completion);
+
        info->channel = (u8)chan->channel;
 
        if (info->channel > STMPE_ADC_LAST_NR) {
@@ -72,23 +74,16 @@ static int stmpe_read_voltage(struct stmpe_adc *info,
                return -EINVAL;
        }
 
-       stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_EN,
-                       STMPE_ADC_CH(info->channel));
-
        stmpe_reg_write(info->stmpe, STMPE_REG_ADC_CAPT,
                        STMPE_ADC_CH(info->channel));
 
-       *val = info->value;
-
-       ret = wait_for_completion_interruptible_timeout
-               (&info->completion, STMPE_ADC_TIMEOUT);
+       ret = wait_for_completion_timeout(&info->completion, STMPE_ADC_TIMEOUT);
 
        if (ret <= 0) {
+               stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_STA,
+                               STMPE_ADC_CH(info->channel));
                mutex_unlock(&info->lock);
-               if (ret == 0)
-                       return -ETIMEDOUT;
-               else
-                       return ret;
+               return -ETIMEDOUT;
        }
 
        *val = info->value;
@@ -105,6 +100,8 @@ static int stmpe_read_temp(struct stmpe_adc *info,
 
        mutex_lock(&info->lock);
 
+       reinit_completion(&info->completion);
+
        info->channel = (u8)chan->channel;
 
        if (info->channel != STMPE_TEMP_CHANNEL) {
@@ -115,15 +112,11 @@ static int stmpe_read_temp(struct stmpe_adc *info,
        stmpe_reg_write(info->stmpe, STMPE_REG_TEMP_CTRL,
                        STMPE_START_ONE_TEMP_CONV);
 
-       ret = wait_for_completion_interruptible_timeout
-               (&info->completion, STMPE_ADC_TIMEOUT);
+       ret = wait_for_completion_timeout(&info->completion, STMPE_ADC_TIMEOUT);
 
        if (ret <= 0) {
                mutex_unlock(&info->lock);
-               if (ret == 0)
-                       return -ETIMEDOUT;
-               else
-                       return ret;
+               return -ETIMEDOUT;
        }
 
        /*
@@ -331,6 +324,12 @@ static int stmpe_adc_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_EN,
+                       ~(norequest_mask & 0xFF));
+
+       stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_STA,
+                       ~(norequest_mask & 0xFF));
+
        return devm_iio_device_register(&pdev->dev, indio_dev);
 }
 
@@ -353,9 +352,14 @@ static struct platform_driver stmpe_adc_driver = {
                .pm     = &stmpe_adc_pm_ops,
        },
 };
-
 module_platform_driver(stmpe_adc_driver);
 
+static const struct of_device_id stmpe_adc_ids[] = {
+       { .compatible = "st,stmpe-adc", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, stmpe_adc_ids);
+
 MODULE_AUTHOR("Stefan Agner <stefan.agner@toradex.com>");
 MODULE_DESCRIPTION("STMPEXXX ADC driver");
 MODULE_LICENSE("GPL v2");
index a09e7f5..f13c624 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
 /* ADC driver for sunxi platforms' (A10, A13 and A31) GPADC
  *
  * Copyright (c) 2016 Quentin Schulz <quentin.schulz@free-electrons.com>
index 863d735..da7f126 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0-only
+# SPDX-License-Identifier: GPL-2.0
 #
 # Gain Amplifiers, etc.
 #
@@ -7,12 +7,17 @@
 menu "Amplifiers"
 
 config AD8366
-       tristate "Analog Devices AD8366 VGA"
+       tristate "Analog Devices AD8366 and similar Gain Amplifiers"
        depends on SPI
+       depends on GPIOLIB
        select BITREVERSE
        help
-         Say yes here to build support for Analog Devices AD8366
-         SPI Dual-Digital Variable Gain Amplifier (VGA).
+         Say yes here to build support for Analog Devices AD8366 and similar
+         gain amplifiers. This driver supports the following gain amplifiers
+         from Analog Devices:
+           AD8366 Dual-Digital Variable Gain Amplifier (VGA)
+           ADA4961 BiCMOS RF Digital Gain Amplifier (DGA)
+           ADL5240 Digitally controlled variable gain amplifier (VGA)
 
          To compile this driver as a module, choose M here: the
          module will be called ad8366.
index 3d6246f..0176d3d 100644 (file)
@@ -1,8 +1,12 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
 /*
- * AD8366 SPI Dual-Digital Variable Gain Amplifier (VGA)
+ * AD8366 and similar Gain Amplifiers
+ * This driver supports the following gain amplifiers:
+ *   AD8366 Dual-Digital Variable Gain Amplifier (VGA)
+ *   ADA4961 BiCMOS RF Digital Gain Amplifier (DGA)
+ *   ADL5240 Digitally controlled variable gain amplifier (VGA)
  *
- * Copyright 2012 Analog Devices Inc.
+ * Copyright 2012-2019 Analog Devices Inc.
  */
 
 #include <linux/device.h>
@@ -11,6 +15,7 @@
 #include <linux/sysfs.h>
 #include <linux/spi/spi.h>
 #include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/bitrev.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 
+enum ad8366_type {
+       ID_AD8366,
+       ID_ADA4961,
+       ID_ADL5240,
+};
+
+struct ad8366_info {
+       int gain_min;
+       int gain_max;
+};
+
 struct ad8366_state {
        struct spi_device       *spi;
        struct regulator        *reg;
+       struct mutex            lock; /* protect sensor state */
+       struct gpio_desc        *reset_gpio;
        unsigned char           ch[2];
+       enum ad8366_type        type;
+       struct ad8366_info      *info;
        /*
         * DMA (thus cache coherency maintenance) requires the
         * transfer buffers to live in their own cache lines.
@@ -29,19 +49,44 @@ struct ad8366_state {
        unsigned char           data[2] ____cacheline_aligned;
 };
 
+static struct ad8366_info ad8366_infos[] = {
+       [ID_AD8366] = {
+               .gain_min = 4500,
+               .gain_max = 20500,
+       },
+       [ID_ADA4961] = {
+               .gain_min = -6000,
+               .gain_max = 15000,
+       },
+       [ID_ADL5240] = {
+               .gain_min = -11500,
+               .gain_max = 20000,
+       },
+};
+
 static int ad8366_write(struct iio_dev *indio_dev,
                        unsigned char ch_a, unsigned char ch_b)
 {
        struct ad8366_state *st = iio_priv(indio_dev);
        int ret;
 
-       ch_a = bitrev8(ch_a & 0x3F);
-       ch_b = bitrev8(ch_b & 0x3F);
+       switch (st->type) {
+       case ID_AD8366:
+               ch_a = bitrev8(ch_a & 0x3F);
+               ch_b = bitrev8(ch_b & 0x3F);
 
-       st->data[0] = ch_b >> 4;
-       st->data[1] = (ch_b << 4) | (ch_a >> 2);
+               st->data[0] = ch_b >> 4;
+               st->data[1] = (ch_b << 4) | (ch_a >> 2);
+               break;
+       case ID_ADA4961:
+               st->data[0] = ch_a & 0x1F;
+               break;
+       case ID_ADL5240:
+               st->data[0] = (ch_a & 0x3F);
+               break;
+       }
 
-       ret = spi_write(st->spi, st->data, ARRAY_SIZE(st->data));
+       ret = spi_write(st->spi, st->data, indio_dev->num_channels);
        if (ret < 0)
                dev_err(&indio_dev->dev, "write failed (%d)", ret);
 
@@ -56,24 +101,35 @@ static int ad8366_read_raw(struct iio_dev *indio_dev,
 {
        struct ad8366_state *st = iio_priv(indio_dev);
        int ret;
-       unsigned code;
+       int code, gain = 0;
 
-       mutex_lock(&indio_dev->mlock);
+       mutex_lock(&st->lock);
        switch (m) {
        case IIO_CHAN_INFO_HARDWAREGAIN:
                code = st->ch[chan->channel];
 
+               switch (st->type) {
+               case ID_AD8366:
+                       gain = code * 253 + 4500;
+                       break;
+               case ID_ADA4961:
+                       gain = 15000 - code * 1000;
+                       break;
+               case ID_ADL5240:
+                       gain = 20000 - 31500 + code * 500;
+                       break;
+               }
+
                /* Values in dB */
-               code = code * 253 + 4500;
-               *val = code / 1000;
-               *val2 = (code % 1000) * 1000;
+               *val = gain / 1000;
+               *val2 = (gain % 1000) * 1000;
 
                ret = IIO_VAL_INT_PLUS_MICRO_DB;
                break;
        default:
                ret = -EINVAL;
        }
-       mutex_unlock(&indio_dev->mlock);
+       mutex_unlock(&st->lock);
 
        return ret;
 };
@@ -85,21 +141,32 @@ static int ad8366_write_raw(struct iio_dev *indio_dev,
                            long mask)
 {
        struct ad8366_state *st = iio_priv(indio_dev);
-       unsigned code;
+       struct ad8366_info *inf = st->info;
+       int code = 0, gain;
        int ret;
 
-       if (val < 0 || val2 < 0)
-               return -EINVAL;
-
        /* Values in dB */
-       code = (((u8)val * 1000) + ((u32)val2 / 1000));
+       if (val < 0)
+               gain = (val * 1000) - (val2 / 1000);
+       else
+               gain = (val * 1000) + (val2 / 1000);
 
-       if (code > 20500 || code < 4500)
+       if (gain > inf->gain_max || gain < inf->gain_min)
                return -EINVAL;
 
-       code = (code - 4500) / 253;
+       switch (st->type) {
+       case ID_AD8366:
+               code = (gain - 4500) / 253;
+               break;
+       case ID_ADA4961:
+               code = (15000 - gain) / 1000;
+               break;
+       case ID_ADL5240:
+               code = ((gain - 500 - 20000) / 500) & 0x3F;
+               break;
+       }
 
-       mutex_lock(&indio_dev->mlock);
+       mutex_lock(&st->lock);
        switch (mask) {
        case IIO_CHAN_INFO_HARDWAREGAIN:
                st->ch[chan->channel] = code;
@@ -108,7 +175,7 @@ static int ad8366_write_raw(struct iio_dev *indio_dev,
        default:
                ret = -EINVAL;
        }
-       mutex_unlock(&indio_dev->mlock);
+       mutex_unlock(&st->lock);
 
        return ret;
 }
@@ -131,6 +198,10 @@ static const struct iio_chan_spec ad8366_channels[] = {
        AD8366_CHAN(1),
 };
 
+static const struct iio_chan_spec ada4961_channels[] = {
+       AD8366_CHAN(0),
+};
+
 static int ad8366_probe(struct spi_device *spi)
 {
        struct iio_dev *indio_dev;
@@ -151,14 +222,33 @@ static int ad8366_probe(struct spi_device *spi)
        }
 
        spi_set_drvdata(spi, indio_dev);
+       mutex_init(&st->lock);
        st->spi = spi;
+       st->type = spi_get_device_id(spi)->driver_data;
+
+       switch (st->type) {
+       case ID_AD8366:
+               indio_dev->channels = ad8366_channels;
+               indio_dev->num_channels = ARRAY_SIZE(ad8366_channels);
+               break;
+       case ID_ADA4961:
+       case ID_ADL5240:
+               st->reset_gpio = devm_gpiod_get(&spi->dev, "reset",
+                       GPIOD_OUT_HIGH);
+               indio_dev->channels = ada4961_channels;
+               indio_dev->num_channels = ARRAY_SIZE(ada4961_channels);
+               break;
+       default:
+               dev_err(&spi->dev, "Invalid device ID\n");
+               ret = -EINVAL;
+               goto error_disable_reg;
+       }
 
+       st->info = &ad8366_infos[st->type];
        indio_dev->dev.parent = &spi->dev;
        indio_dev->name = spi_get_device_id(spi)->name;
        indio_dev->info = &ad8366_info;
        indio_dev->modes = INDIO_DIRECT_MODE;
-       indio_dev->channels = ad8366_channels;
-       indio_dev->num_channels = ARRAY_SIZE(ad8366_channels);
 
        ret = ad8366_write(indio_dev, 0 , 0);
        if (ret < 0)
@@ -192,7 +282,9 @@ static int ad8366_remove(struct spi_device *spi)
 }
 
 static const struct spi_device_id ad8366_id[] = {
-       {"ad8366", 0},
+       {"ad8366",  ID_AD8366},
+       {"ada4961", ID_ADA4961},
+       {"adl5240", ID_ADL5240},
        {}
 };
 MODULE_DEVICE_TABLE(spi, ad8366_id);
@@ -209,5 +301,5 @@ static struct spi_driver ad8366_driver = {
 module_spi_driver(ad8366_driver);
 
 MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
-MODULE_DESCRIPTION("Analog Devices AD8366 VGA");
+MODULE_DESCRIPTION("Analog Devices AD8366 and similar Gain Amplifiers");
 MODULE_LICENSE("GPL v2");
index f9bf7ff..bcb58fb 100644 (file)
@@ -21,3 +21,12 @@ config IIO_CROS_EC_SENSORS
          Accelerometers, Gyroscope and Magnetometer that are
          presented by the ChromeOS EC Sensor hub.
          Creates an IIO device for each functions.
+
+config IIO_CROS_EC_SENSORS_LID_ANGLE
+       tristate "ChromeOS EC Sensor for lid angle"
+       depends on IIO_CROS_EC_SENSORS_CORE
+       help
+         Module to report the angle between lid and base for some
+         convertible devices.
+         This module is loaded when the EC can calculate the angle between the base
+         and the lid.
index 7c2d6a9..e0a33ab 100644 (file)
@@ -5,3 +5,4 @@
 
 obj-$(CONFIG_IIO_CROS_EC_SENSORS_CORE) += cros_ec_sensors_core.o
 obj-$(CONFIG_IIO_CROS_EC_SENSORS) += cros_ec_sensors.o
+obj-$(CONFIG_IIO_CROS_EC_SENSORS_LID_ANGLE) += cros_ec_lid_angle.o
diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c
new file mode 100644 (file)
index 0000000..876dfd1
--- /dev/null
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * cros_ec_lid_angle - Driver for CrOS EC lid angle sensor.
+ *
+ * Copyright 2018 Google, Inc
+ *
+ * This driver uses the cros-ec interface to communicate with the Chrome OS
+ * EC about counter sensors. Counters are presented through
+ * iio sysfs.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/common/cros_ec_sensors_core.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/kernel.h>
+#include <linux/mfd/cros_ec.h>
+#include <linux/mfd/cros_ec_commands.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define DRV_NAME "cros-ec-lid-angle"
+
+/*
+ * One channel for the lid angle, the other for timestamp.
+ */
+static const struct iio_chan_spec cros_ec_lid_angle_channels[] = {
+       {
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+               .scan_type.realbits = CROS_EC_SENSOR_BITS,
+               .scan_type.storagebits = CROS_EC_SENSOR_BITS,
+               .scan_type.sign = 'u',
+               .type = IIO_ANGL
+       },
+       IIO_CHAN_SOFT_TIMESTAMP(1)
+};
+
+/* State data for ec_sensors iio driver. */
+struct cros_ec_lid_angle_state {
+       /* Shared by all sensors */
+       struct cros_ec_sensors_core_state core;
+};
+
+static int cros_ec_sensors_read_lid_angle(struct iio_dev *indio_dev,
+                                         unsigned long scan_mask, s16 *data)
+{
+       struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
+       int ret;
+
+       st->param.cmd = MOTIONSENSE_CMD_LID_ANGLE;
+       ret = cros_ec_motion_send_host_cmd(st, sizeof(st->resp->lid_angle));
+       if (ret) {
+               dev_warn(&indio_dev->dev, "Unable to read lid angle\n");
+               return ret;
+       }
+
+       *data = st->resp->lid_angle.value;
+       return 0;
+}
+
+static int cros_ec_lid_angle_read(struct iio_dev *indio_dev,
+                                   struct iio_chan_spec const *chan,
+                                   int *val, int *val2, long mask)
+{
+       struct cros_ec_lid_angle_state *st = iio_priv(indio_dev);
+       s16 data;
+       int ret;
+
+       mutex_lock(&st->core.cmd_lock);
+       ret = cros_ec_sensors_read_lid_angle(indio_dev, 1, &data);
+       if (ret == 0) {
+               *val = data;
+               ret = IIO_VAL_INT;
+       }
+       mutex_unlock(&st->core.cmd_lock);
+       return ret;
+}
+
+static const struct iio_info cros_ec_lid_angle_info = {
+       .read_raw = &cros_ec_lid_angle_read,
+};
+
+static int cros_ec_lid_angle_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct iio_dev *indio_dev;
+       struct cros_ec_lid_angle_state *state;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*state));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       ret = cros_ec_sensors_core_init(pdev, indio_dev, false);
+       if (ret)
+               return ret;
+
+       indio_dev->info = &cros_ec_lid_angle_info;
+       state = iio_priv(indio_dev);
+       indio_dev->channels = cros_ec_lid_angle_channels;
+       indio_dev->num_channels = ARRAY_SIZE(cros_ec_lid_angle_channels);
+
+       state->core.read_ec_sensors_data = cros_ec_sensors_read_lid_angle;
+
+       ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+                       cros_ec_sensors_capture, NULL);
+       if (ret)
+               return ret;
+
+       return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct platform_device_id cros_ec_lid_angle_ids[] = {
+       {
+               .name = DRV_NAME,
+       },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, cros_ec_lid_angle_ids);
+
+static struct platform_driver cros_ec_lid_angle_platform_driver = {
+       .driver = {
+               .name   = DRV_NAME,
+               .pm     = &cros_ec_sensors_pm_ops,
+       },
+       .probe          = cros_ec_lid_angle_probe,
+       .id_table       = cros_ec_lid_angle_ids,
+};
+module_platform_driver(cros_ec_lid_angle_platform_driver);
+
+MODULE_DESCRIPTION("ChromeOS EC driver for reporting convertible lid angle.");
+MODULE_LICENSE("GPL v2");
index 719a0df..130362c 100644 (file)
@@ -125,6 +125,15 @@ static ssize_t cros_ec_sensors_calibrate(struct iio_dev *indio_dev,
        return ret ? ret : len;
 }
 
+static ssize_t cros_ec_sensors_id(struct iio_dev *indio_dev,
+                                 uintptr_t private,
+                                 const struct iio_chan_spec *chan, char *buf)
+{
+       struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", st->param.info.sensor_num);
+}
+
 static ssize_t cros_ec_sensors_loc(struct iio_dev *indio_dev,
                uintptr_t private, const struct iio_chan_spec *chan,
                char *buf)
@@ -140,6 +149,11 @@ const struct iio_chan_spec_ext_info cros_ec_sensors_ext_info[] = {
                .shared = IIO_SHARED_BY_ALL,
                .write = cros_ec_sensors_calibrate
        },
+       {
+               .name = "id",
+               .shared = IIO_SHARED_BY_ALL,
+               .read = cros_ec_sensors_id
+       },
        {
                .name = "location",
                .shared = IIO_SHARED_BY_ALL,
index a513c70..475646c 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/property.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/spi/spi.h>
 #include <linux/gpio/consumer.h>
 
@@ -582,7 +584,7 @@ static ssize_t ad5758_write_powerdown(struct iio_dev *indio_dev,
 {
        struct ad5758_state *st = iio_priv(indio_dev);
        bool pwr_down;
-       unsigned int dc_dc_mode, dac_config_mode, val;
+       unsigned int dac_config_mode, val;
        unsigned long int dac_config_msk;
        int ret;
 
@@ -591,13 +593,10 @@ static ssize_t ad5758_write_powerdown(struct iio_dev *indio_dev,
                return ret;
 
        mutex_lock(&st->lock);
-       if (pwr_down) {
-               dc_dc_mode = AD5758_DCDC_MODE_POWER_OFF;
+       if (pwr_down)
                val = 0;
-       } else {
-               dc_dc_mode = st->dc_dc_mode;
+       else
                val = 1;
-       }
 
        dac_config_mode = AD5758_DAC_CONFIG_OUT_EN_MODE(val) |
                          AD5758_DAC_CONFIG_INT_EN_MODE(val);
@@ -885,9 +884,16 @@ static const struct spi_device_id ad5758_id[] = {
 };
 MODULE_DEVICE_TABLE(spi, ad5758_id);
 
+static const struct of_device_id ad5758_of_match[] = {
+        { .compatible = "adi,ad5758" },
+        { },
+};
+MODULE_DEVICE_TABLE(of, ad5758_of_match);
+
 static struct spi_driver ad5758_driver = {
        .driver = {
                .name = KBUILD_MODNAME,
+               .of_match_table = ad5758_of_match,
        },
        .probe = ad5758_probe,
        .id_table = ad5758_id,
index 030c513..26d2066 100644 (file)
@@ -233,12 +233,6 @@ static int ds4424_probe(struct i2c_client *client,
        indio_dev->dev.of_node = client->dev.of_node;
        indio_dev->dev.parent = &client->dev;
 
-       if (!client->dev.of_node) {
-               dev_err(&client->dev,
-                               "Not found DT.\n");
-               return -ENODEV;
-       }
-
        data->vcc_reg = devm_regulator_get(&client->dev, "vcc");
        if (IS_ERR(data->vcc_reg)) {
                dev_err(&client->dev,
index c86db8b..240b815 100644 (file)
@@ -39,5 +39,15 @@ config ADF4350
          To compile this driver as a module, choose M here: the
          module will be called adf4350.
 
+config ADF4371
+       tristate "Analog Devices ADF4371/ADF4372 Wideband Synthesizers"
+       depends on SPI
+       select REGMAP_SPI
+       help
+         Say yes here to build support for Analog Devices ADF4371 and ADF4372
+         Wideband Synthesizers. The driver provides direct access via sysfs.
+
+         To compile this driver as a module, choose M here: the
+         module will be called adf4371.
 endmenu
 endmenu
index f2e396d..518b1e5 100644 (file)
@@ -6,3 +6,4 @@
 # When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_AD9523) += ad9523.o
 obj-$(CONFIG_ADF4350) += adf4350.o
+obj-$(CONFIG_ADF4371) += adf4371.o
index 9691524..a732218 100644 (file)
@@ -861,9 +861,11 @@ static int ad9523_setup(struct iio_dev *indio_dev)
        if (ret < 0)
                return ret;
 
-       st->vco_freq = (pdata->vcxo_freq * (pdata->pll2_freq_doubler_en ? 2 : 1)
-                       / pdata->pll2_r2_div) * AD9523_PLL2_FB_NDIV(pdata->
-                       pll2_ndiv_a_cnt, pdata->pll2_ndiv_b_cnt);
+       st->vco_freq = div_u64((unsigned long long)pdata->vcxo_freq *
+                              (pdata->pll2_freq_doubler_en ? 2 : 1) *
+                              AD9523_PLL2_FB_NDIV(pdata->pll2_ndiv_a_cnt,
+                                                  pdata->pll2_ndiv_b_cnt),
+                              pdata->pll2_r2_div);
 
        ret = ad9523_write(indio_dev, AD9523_PLL2_VCO_CTRL,
                AD9523_PLL2_VCO_CALIBRATE);
diff --git a/drivers/iio/frequency/adf4371.c b/drivers/iio/frequency/adf4371.c
new file mode 100644 (file)
index 0000000..e48f15c
--- /dev/null
@@ -0,0 +1,632 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Analog Devices ADF4371 SPI Wideband Synthesizer driver
+ *
+ * Copyright 2019 Analog Devices Inc.
+ */
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gcd.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/iio.h>
+
+/* Registers address macro */
+#define ADF4371_REG(x)                 (x)
+
+/* ADF4371_REG0 */
+#define ADF4371_ADDR_ASC_MSK           BIT(2)
+#define ADF4371_ADDR_ASC(x)            FIELD_PREP(ADF4371_ADDR_ASC_MSK, x)
+#define ADF4371_ADDR_ASC_R_MSK         BIT(5)
+#define ADF4371_ADDR_ASC_R(x)          FIELD_PREP(ADF4371_ADDR_ASC_R_MSK, x)
+#define ADF4371_RESET_CMD              0x81
+
+/* ADF4371_REG17 */
+#define ADF4371_FRAC2WORD_L_MSK                GENMASK(7, 1)
+#define ADF4371_FRAC2WORD_L(x)         FIELD_PREP(ADF4371_FRAC2WORD_L_MSK, x)
+#define ADF4371_FRAC1WORD_MSK          BIT(0)
+#define ADF4371_FRAC1WORD(x)           FIELD_PREP(ADF4371_FRAC1WORD_MSK, x)
+
+/* ADF4371_REG18 */
+#define ADF4371_FRAC2WORD_H_MSK                GENMASK(6, 0)
+#define ADF4371_FRAC2WORD_H(x)         FIELD_PREP(ADF4371_FRAC2WORD_H_MSK, x)
+
+/* ADF4371_REG1A */
+#define ADF4371_MOD2WORD_MSK           GENMASK(5, 0)
+#define ADF4371_MOD2WORD(x)            FIELD_PREP(ADF4371_MOD2WORD_MSK, x)
+
+/* ADF4371_REG24 */
+#define ADF4371_RF_DIV_SEL_MSK         GENMASK(6, 4)
+#define ADF4371_RF_DIV_SEL(x)          FIELD_PREP(ADF4371_RF_DIV_SEL_MSK, x)
+
+/* ADF4371_REG25 */
+#define ADF4371_MUTE_LD_MSK            BIT(7)
+#define ADF4371_MUTE_LD(x)             FIELD_PREP(ADF4371_MUTE_LD_MSK, x)
+
+/* ADF4371_REG32 */
+#define ADF4371_TIMEOUT_MSK            GENMASK(1, 0)
+#define ADF4371_TIMEOUT(x)             FIELD_PREP(ADF4371_TIMEOUT_MSK, x)
+
+/* ADF4371_REG34 */
+#define ADF4371_VCO_ALC_TOUT_MSK       GENMASK(4, 0)
+#define ADF4371_VCO_ALC_TOUT(x)                FIELD_PREP(ADF4371_VCO_ALC_TOUT_MSK, x)
+
+/* Specifications */
+#define ADF4371_MIN_VCO_FREQ           4000000000ULL /* 4000 MHz */
+#define ADF4371_MAX_VCO_FREQ           8000000000ULL /* 8000 MHz */
+#define ADF4371_MAX_OUT_RF8_FREQ       ADF4371_MAX_VCO_FREQ /* Hz */
+#define ADF4371_MIN_OUT_RF8_FREQ       (ADF4371_MIN_VCO_FREQ / 64) /* Hz */
+#define ADF4371_MAX_OUT_RF16_FREQ      (ADF4371_MAX_VCO_FREQ * 2) /* Hz */
+#define ADF4371_MIN_OUT_RF16_FREQ      (ADF4371_MIN_VCO_FREQ * 2) /* Hz */
+#define ADF4371_MAX_OUT_RF32_FREQ      (ADF4371_MAX_VCO_FREQ * 4) /* Hz */
+#define ADF4371_MIN_OUT_RF32_FREQ      (ADF4371_MIN_VCO_FREQ * 4) /* Hz */
+
+#define ADF4371_MAX_FREQ_PFD           250000000UL /* Hz */
+#define ADF4371_MAX_FREQ_REFIN         600000000UL /* Hz */
+
+/* MOD1 is a 24-bit primary modulus with fixed value of 2^25 */
+#define ADF4371_MODULUS1               33554432ULL
+/* MOD2 is the programmable, 14-bit auxiliary fractional modulus */
+#define ADF4371_MAX_MODULUS2           BIT(14)
+
+#define ADF4371_CHECK_RANGE(freq, range) \
+       ((freq > ADF4371_MAX_ ## range) || (freq < ADF4371_MIN_ ## range))
+
+enum {
+       ADF4371_FREQ,
+       ADF4371_POWER_DOWN,
+       ADF4371_CHANNEL_NAME
+};
+
+enum {
+       ADF4371_CH_RF8,
+       ADF4371_CH_RFAUX8,
+       ADF4371_CH_RF16,
+       ADF4371_CH_RF32
+};
+
+enum adf4371_variant {
+       ADF4371,
+       ADF4372
+};
+
+struct adf4371_pwrdown {
+       unsigned int reg;
+       unsigned int bit;
+};
+
+static const char * const adf4371_ch_names[] = {
+       "RF8x", "RFAUX8x", "RF16x", "RF32x"
+};
+
+static const struct adf4371_pwrdown adf4371_pwrdown_ch[4] = {
+       [ADF4371_CH_RF8] = { ADF4371_REG(0x25), 2 },
+       [ADF4371_CH_RFAUX8] = { ADF4371_REG(0x72), 3 },
+       [ADF4371_CH_RF16] = { ADF4371_REG(0x25), 3 },
+       [ADF4371_CH_RF32] = { ADF4371_REG(0x25), 4 },
+};
+
+static const struct reg_sequence adf4371_reg_defaults[] = {
+       { ADF4371_REG(0x0),  0x18 },
+       { ADF4371_REG(0x12), 0x40 },
+       { ADF4371_REG(0x1E), 0x48 },
+       { ADF4371_REG(0x20), 0x14 },
+       { ADF4371_REG(0x22), 0x00 },
+       { ADF4371_REG(0x23), 0x00 },
+       { ADF4371_REG(0x24), 0x80 },
+       { ADF4371_REG(0x25), 0x07 },
+       { ADF4371_REG(0x27), 0xC5 },
+       { ADF4371_REG(0x28), 0x83 },
+       { ADF4371_REG(0x2C), 0x44 },
+       { ADF4371_REG(0x2D), 0x11 },
+       { ADF4371_REG(0x2E), 0x12 },
+       { ADF4371_REG(0x2F), 0x94 },
+       { ADF4371_REG(0x32), 0x04 },
+       { ADF4371_REG(0x35), 0xFA },
+       { ADF4371_REG(0x36), 0x30 },
+       { ADF4371_REG(0x39), 0x07 },
+       { ADF4371_REG(0x3A), 0x55 },
+       { ADF4371_REG(0x3E), 0x0C },
+       { ADF4371_REG(0x3F), 0x80 },
+       { ADF4371_REG(0x40), 0x50 },
+       { ADF4371_REG(0x41), 0x28 },
+       { ADF4371_REG(0x47), 0xC0 },
+       { ADF4371_REG(0x52), 0xF4 },
+       { ADF4371_REG(0x70), 0x03 },
+       { ADF4371_REG(0x71), 0x60 },
+       { ADF4371_REG(0x72), 0x32 },
+};
+
+static const struct regmap_config adf4371_regmap_config = {
+       .reg_bits = 16,
+       .val_bits = 8,
+       .read_flag_mask = BIT(7),
+};
+
+struct adf4371_chip_info {
+       unsigned int num_channels;
+       const struct iio_chan_spec *channels;
+};
+
+struct adf4371_state {
+       struct spi_device *spi;
+       struct regmap *regmap;
+       struct clk *clkin;
+       /*
+        * Lock for accessing device registers. Some operations require
+        * multiple consecutive R/W operations, during which the device
+        * shouldn't be interrupted. The buffers are also shared across
+        * all operations so need to be protected on stand alone reads and
+        * writes.
+        */
+       struct mutex lock;
+       const struct adf4371_chip_info *chip_info;
+       unsigned long clkin_freq;
+       unsigned long fpfd;
+       unsigned int integer;
+       unsigned int fract1;
+       unsigned int fract2;
+       unsigned int mod2;
+       unsigned int rf_div_sel;
+       unsigned int ref_div_factor;
+       u8 buf[10] ____cacheline_aligned;
+};
+
+static unsigned long long adf4371_pll_fract_n_get_rate(struct adf4371_state *st,
+                                                      u32 channel)
+{
+       unsigned long long val, tmp;
+       unsigned int ref_div_sel;
+
+       val = (((u64)st->integer * ADF4371_MODULUS1) + st->fract1) * st->fpfd;
+       tmp = (u64)st->fract2 * st->fpfd;
+       do_div(tmp, st->mod2);
+       val += tmp + ADF4371_MODULUS1 / 2;
+
+       if (channel == ADF4371_CH_RF8 || channel == ADF4371_CH_RFAUX8)
+               ref_div_sel = st->rf_div_sel;
+       else
+               ref_div_sel = 0;
+
+       do_div(val, ADF4371_MODULUS1 * (1 << ref_div_sel));
+
+       if (channel == ADF4371_CH_RF16)
+               val <<= 1;
+       else if (channel == ADF4371_CH_RF32)
+               val <<= 2;
+
+       return val;
+}
+
+static void adf4371_pll_fract_n_compute(unsigned long long vco,
+                                      unsigned long long pfd,
+                                      unsigned int *integer,
+                                      unsigned int *fract1,
+                                      unsigned int *fract2,
+                                      unsigned int *mod2)
+{
+       unsigned long long tmp;
+       u32 gcd_div;
+
+       tmp = do_div(vco, pfd);
+       tmp = tmp * ADF4371_MODULUS1;
+       *fract2 = do_div(tmp, pfd);
+
+       *integer = vco;
+       *fract1 = tmp;
+
+       *mod2 = pfd;
+
+       while (*mod2 > ADF4371_MAX_MODULUS2) {
+               *mod2 >>= 1;
+               *fract2 >>= 1;
+       }
+
+       gcd_div = gcd(*fract2, *mod2);
+       *mod2 /= gcd_div;
+       *fract2 /= gcd_div;
+}
+
+static int adf4371_set_freq(struct adf4371_state *st, unsigned long long freq,
+                           unsigned int channel)
+{
+       u32 cp_bleed;
+       u8 int_mode = 0;
+       int ret;
+
+       switch (channel) {
+       case ADF4371_CH_RF8:
+       case ADF4371_CH_RFAUX8:
+               if (ADF4371_CHECK_RANGE(freq, OUT_RF8_FREQ))
+                       return -EINVAL;
+
+               st->rf_div_sel = 0;
+
+               while (freq < ADF4371_MIN_VCO_FREQ) {
+                       freq <<= 1;
+                       st->rf_div_sel++;
+               }
+               break;
+       case ADF4371_CH_RF16:
+               /* ADF4371 RF16 8000...16000 MHz */
+               if (ADF4371_CHECK_RANGE(freq, OUT_RF16_FREQ))
+                       return -EINVAL;
+
+               freq >>= 1;
+               break;
+       case ADF4371_CH_RF32:
+               /* ADF4371 RF32 16000...32000 MHz */
+               if (ADF4371_CHECK_RANGE(freq, OUT_RF32_FREQ))
+                       return -EINVAL;
+
+               freq >>= 2;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       adf4371_pll_fract_n_compute(freq, st->fpfd, &st->integer, &st->fract1,
+                                   &st->fract2, &st->mod2);
+       st->buf[0] = st->integer >> 8;
+       st->buf[1] = 0x40; /* REG12 default */
+       st->buf[2] = 0x00;
+       st->buf[3] = st->fract2 & 0xFF;
+       st->buf[4] = st->fract2 >> 7;
+       st->buf[5] = st->fract2 >> 15;
+       st->buf[6] = ADF4371_FRAC2WORD_L(st->fract2 & 0x7F) |
+                    ADF4371_FRAC1WORD(st->fract1 >> 23);
+       st->buf[7] = ADF4371_FRAC2WORD_H(st->fract2 >> 7);
+       st->buf[8] = st->mod2 & 0xFF;
+       st->buf[9] = ADF4371_MOD2WORD(st->mod2 >> 8);
+
+       ret = regmap_bulk_write(st->regmap, ADF4371_REG(0x11), st->buf, 10);
+       if (ret < 0)
+               return ret;
+       /*
+        * The R counter allows the input reference frequency to be
+        * divided down to produce the reference clock to the PFD
+        */
+       ret = regmap_write(st->regmap, ADF4371_REG(0x1F), st->ref_div_factor);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_update_bits(st->regmap, ADF4371_REG(0x24),
+                                ADF4371_RF_DIV_SEL_MSK,
+                                ADF4371_RF_DIV_SEL(st->rf_div_sel));
+       if (ret < 0)
+               return ret;
+
+       cp_bleed = DIV_ROUND_UP(400 * 1750, st->integer * 375);
+       cp_bleed = clamp(cp_bleed, 1U, 255U);
+       ret = regmap_write(st->regmap, ADF4371_REG(0x26), cp_bleed);
+       if (ret < 0)
+               return ret;
+       /*
+        * Set to 1 when in INT mode (when FRAC1 = FRAC2 = 0),
+        * and set to 0 when in FRAC mode.
+        */
+       if (st->fract1 == 0 && st->fract2 == 0)
+               int_mode = 0x01;
+
+       ret = regmap_write(st->regmap, ADF4371_REG(0x2B), int_mode);
+       if (ret < 0)
+               return ret;
+
+       return regmap_write(st->regmap, ADF4371_REG(0x10), st->integer & 0xFF);
+}
+
+static ssize_t adf4371_read(struct iio_dev *indio_dev,
+                           uintptr_t private,
+                           const struct iio_chan_spec *chan,
+                           char *buf)
+{
+       struct adf4371_state *st = iio_priv(indio_dev);
+       unsigned long long val = 0;
+       unsigned int readval, reg, bit;
+       int ret;
+
+       switch ((u32)private) {
+       case ADF4371_FREQ:
+               val = adf4371_pll_fract_n_get_rate(st, chan->channel);
+               ret = regmap_read(st->regmap, ADF4371_REG(0x7C), &readval);
+               if (ret < 0)
+                       break;
+
+               if (readval == 0x00) {
+                       dev_dbg(&st->spi->dev, "PLL un-locked\n");
+                       ret = -EBUSY;
+               }
+               break;
+       case ADF4371_POWER_DOWN:
+               reg = adf4371_pwrdown_ch[chan->channel].reg;
+               bit = adf4371_pwrdown_ch[chan->channel].bit;
+
+               ret = regmap_read(st->regmap, reg, &readval);
+               if (ret < 0)
+                       break;
+
+               val = !(readval & BIT(bit));
+               break;
+       case ADF4371_CHANNEL_NAME:
+               return sprintf(buf, "%s\n", adf4371_ch_names[chan->channel]);
+       default:
+               ret = -EINVAL;
+               val = 0;
+               break;
+       }
+
+       return ret < 0 ? ret : sprintf(buf, "%llu\n", val);
+}
+
+static ssize_t adf4371_write(struct iio_dev *indio_dev,
+                            uintptr_t private,
+                            const struct iio_chan_spec *chan,
+                            const char *buf, size_t len)
+{
+       struct adf4371_state *st = iio_priv(indio_dev);
+       unsigned long long freq;
+       bool power_down;
+       unsigned int bit, readval, reg;
+       int ret;
+
+       mutex_lock(&st->lock);
+       switch ((u32)private) {
+       case ADF4371_FREQ:
+               ret = kstrtoull(buf, 10, &freq);
+               if (ret)
+                       break;
+
+               ret = adf4371_set_freq(st, freq, chan->channel);
+               break;
+       case ADF4371_POWER_DOWN:
+               ret = kstrtobool(buf, &power_down);
+               if (ret)
+                       break;
+
+               reg = adf4371_pwrdown_ch[chan->channel].reg;
+               bit = adf4371_pwrdown_ch[chan->channel].bit;
+               ret = regmap_read(st->regmap, reg, &readval);
+               if (ret < 0)
+                       break;
+
+               readval &= ~BIT(bit);
+               readval |= (!power_down << bit);
+
+               ret = regmap_write(st->regmap, reg, readval);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       mutex_unlock(&st->lock);
+
+       return ret ? ret : len;
+}
+
+#define _ADF4371_EXT_INFO(_name, _ident) { \
+               .name = _name, \
+               .read = adf4371_read, \
+               .write = adf4371_write, \
+               .private = _ident, \
+               .shared = IIO_SEPARATE, \
+}
+
+static const struct iio_chan_spec_ext_info adf4371_ext_info[] = {
+       /*
+        * Ideally we use IIO_CHAN_INFO_FREQUENCY, but there are
+        * values > 2^32 in order to support the entire frequency range
+        * in Hz. Using scale is a bit ugly.
+        */
+       _ADF4371_EXT_INFO("frequency", ADF4371_FREQ),
+       _ADF4371_EXT_INFO("powerdown", ADF4371_POWER_DOWN),
+       _ADF4371_EXT_INFO("name", ADF4371_CHANNEL_NAME),
+       { },
+};
+
+#define ADF4371_CHANNEL(index) { \
+               .type = IIO_ALTVOLTAGE, \
+               .output = 1, \
+               .channel = index, \
+               .ext_info = adf4371_ext_info, \
+               .indexed = 1, \
+       }
+
+static const struct iio_chan_spec adf4371_chan[] = {
+       ADF4371_CHANNEL(ADF4371_CH_RF8),
+       ADF4371_CHANNEL(ADF4371_CH_RFAUX8),
+       ADF4371_CHANNEL(ADF4371_CH_RF16),
+       ADF4371_CHANNEL(ADF4371_CH_RF32),
+};
+
+static const struct adf4371_chip_info adf4371_chip_info[] = {
+       [ADF4371] = {
+               .channels = adf4371_chan,
+               .num_channels = 4,
+       },
+       [ADF4372] = {
+               .channels = adf4371_chan,
+               .num_channels = 3,
+       }
+};
+
+static int adf4371_reg_access(struct iio_dev *indio_dev,
+                             unsigned int reg,
+                             unsigned int writeval,
+                             unsigned int *readval)
+{
+       struct adf4371_state *st = iio_priv(indio_dev);
+
+       if (readval)
+               return regmap_read(st->regmap, reg, readval);
+       else
+               return regmap_write(st->regmap, reg, writeval);
+}
+
+static const struct iio_info adf4371_info = {
+       .debugfs_reg_access = &adf4371_reg_access,
+};
+
+static int adf4371_setup(struct adf4371_state *st)
+{
+       unsigned int synth_timeout = 2, timeout = 1, vco_alc_timeout = 1;
+       unsigned int vco_band_div, tmp;
+       int ret;
+
+       /* Perform a software reset */
+       ret = regmap_write(st->regmap, ADF4371_REG(0x0), ADF4371_RESET_CMD);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_multi_reg_write(st->regmap, adf4371_reg_defaults,
+                                    ARRAY_SIZE(adf4371_reg_defaults));
+       if (ret < 0)
+               return ret;
+
+       /* Mute to Lock Detect */
+       if (device_property_read_bool(&st->spi->dev, "adi,mute-till-lock-en")) {
+               ret = regmap_update_bits(st->regmap, ADF4371_REG(0x25),
+                                        ADF4371_MUTE_LD_MSK,
+                                        ADF4371_MUTE_LD(1));
+               if (ret < 0)
+                       return ret;
+       }
+
+       /* Set address in ascending order, so the bulk_write() will work */
+       ret = regmap_update_bits(st->regmap, ADF4371_REG(0x0),
+                                ADF4371_ADDR_ASC_MSK | ADF4371_ADDR_ASC_R_MSK,
+                                ADF4371_ADDR_ASC(1) | ADF4371_ADDR_ASC_R(1));
+       if (ret < 0)
+               return ret;
+       /*
+        * Calculate and maximize PFD frequency
+        * fPFD = REFIN × ((1 + D)/(R × (1 + T)))
+        * Where D is the REFIN doubler bit, T is the reference divide by 2,
+        * R is the reference division factor
+        * TODO: it is assumed D and T equal 0.
+        */
+       do {
+               st->ref_div_factor++;
+               st->fpfd = st->clkin_freq / st->ref_div_factor;
+       } while (st->fpfd > ADF4371_MAX_FREQ_PFD);
+
+       /* Calculate Timeouts */
+       vco_band_div = DIV_ROUND_UP(st->fpfd, 2400000U);
+
+       tmp = DIV_ROUND_CLOSEST(st->fpfd, 1000000U);
+       do {
+               timeout++;
+               if (timeout > 1023) {
+                       timeout = 2;
+                       synth_timeout++;
+               }
+       } while (synth_timeout * 1024 + timeout <= 20 * tmp);
+
+       do {
+               vco_alc_timeout++;
+       } while (vco_alc_timeout * 1024 - timeout <= 50 * tmp);
+
+       st->buf[0] = vco_band_div;
+       st->buf[1] = timeout & 0xFF;
+       st->buf[2] = ADF4371_TIMEOUT(timeout >> 8) | 0x04;
+       st->buf[3] = synth_timeout;
+       st->buf[4] = ADF4371_VCO_ALC_TOUT(vco_alc_timeout);
+
+       return regmap_bulk_write(st->regmap, ADF4371_REG(0x30), st->buf, 5);
+}
+
+static void adf4371_clk_disable(void *data)
+{
+       struct adf4371_state *st = data;
+
+       clk_disable_unprepare(st->clkin);
+}
+
+static int adf4371_probe(struct spi_device *spi)
+{
+       const struct spi_device_id *id = spi_get_device_id(spi);
+       struct iio_dev *indio_dev;
+       struct adf4371_state *st;
+       struct regmap *regmap;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       regmap = devm_regmap_init_spi(spi, &adf4371_regmap_config);
+       if (IS_ERR(regmap)) {
+               dev_err(&spi->dev, "Error initializing spi regmap: %ld\n",
+                       PTR_ERR(regmap));
+               return PTR_ERR(regmap);
+       }
+
+       st = iio_priv(indio_dev);
+       spi_set_drvdata(spi, indio_dev);
+       st->spi = spi;
+       st->regmap = regmap;
+       mutex_init(&st->lock);
+
+       st->chip_info = &adf4371_chip_info[id->driver_data];
+       indio_dev->dev.parent = &spi->dev;
+       indio_dev->name = id->name;
+       indio_dev->info = &adf4371_info;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->channels = st->chip_info->channels;
+       indio_dev->num_channels = st->chip_info->num_channels;
+
+       st->clkin = devm_clk_get(&spi->dev, "clkin");
+       if (IS_ERR(st->clkin))
+               return PTR_ERR(st->clkin);
+
+       ret = clk_prepare_enable(st->clkin);
+       if (ret < 0)
+               return ret;
+
+       ret = devm_add_action_or_reset(&spi->dev, adf4371_clk_disable, st);
+       if (ret)
+               return ret;
+
+       st->clkin_freq = clk_get_rate(st->clkin);
+
+       ret = adf4371_setup(st);
+       if (ret < 0) {
+               dev_err(&spi->dev, "ADF4371 setup failed\n");
+               return ret;
+       }
+
+       return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct spi_device_id adf4371_id_table[] = {
+       { "adf4371", ADF4371 },
+       { "adf4372", ADF4372 },
+       {}
+};
+MODULE_DEVICE_TABLE(spi, adf4371_id_table);
+
+static const struct of_device_id adf4371_of_match[] = {
+       { .compatible = "adi,adf4371" },
+       { .compatible = "adi,adf4372" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, adf4371_of_match);
+
+static struct spi_driver adf4371_driver = {
+       .driver = {
+               .name = "adf4371",
+               .of_match_table = adf4371_of_match,
+       },
+       .probe = adf4371_probe,
+       .id_table = adf4371_id_table,
+};
+module_spi_driver(adf4371_driver);
+
+MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADF4371 SPI PLL");
+MODULE_LICENSE("GPL");
index 4e22b3c..b459600 100644 (file)
@@ -22,8 +22,7 @@
 #include <linux/completion.h>
 #include <linux/mutex.h>
 #include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/timekeeping.h>
 
 #include <linux/iio/iio.h>
@@ -72,7 +71,7 @@
 struct dht11 {
        struct device                   *dev;
 
-       int                             gpio;
+       struct gpio_desc                *gpiod;
        int                             irq;
 
        struct completion               completion;
@@ -179,7 +178,7 @@ static irqreturn_t dht11_handle_irq(int irq, void *data)
        if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) {
                dht11->edges[dht11->num_edges].ts = ktime_get_boottime_ns();
                dht11->edges[dht11->num_edges++].value =
-                                               gpio_get_value(dht11->gpio);
+                                               gpiod_get_value(dht11->gpiod);
 
                if (dht11->num_edges >= DHT11_EDGES_PER_READ)
                        complete(&dht11->completion);
@@ -217,12 +216,12 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
                reinit_completion(&dht11->completion);
 
                dht11->num_edges = 0;
-               ret = gpio_direction_output(dht11->gpio, 0);
+               ret = gpiod_direction_output(dht11->gpiod, 0);
                if (ret)
                        goto err;
                usleep_range(DHT11_START_TRANSMISSION_MIN,
                             DHT11_START_TRANSMISSION_MAX);
-               ret = gpio_direction_input(dht11->gpio);
+               ret = gpiod_direction_input(dht11->gpiod);
                if (ret)
                        goto err;
 
@@ -294,10 +293,8 @@ MODULE_DEVICE_TABLE(of, dht11_dt_ids);
 static int dht11_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct device_node *node = dev->of_node;
        struct dht11 *dht11;
        struct iio_dev *iio;
-       int ret;
 
        iio = devm_iio_device_alloc(dev, sizeof(*dht11));
        if (!iio) {
@@ -307,18 +304,13 @@ static int dht11_probe(struct platform_device *pdev)
 
        dht11 = iio_priv(iio);
        dht11->dev = dev;
+       dht11->gpiod = devm_gpiod_get(dev, NULL, GPIOD_IN);
+       if (IS_ERR(dht11->gpiod))
+               return PTR_ERR(dht11->gpiod);
 
-       ret = of_get_gpio(node, 0);
-       if (ret < 0)
-               return ret;
-       dht11->gpio = ret;
-       ret = devm_gpio_request_one(dev, dht11->gpio, GPIOF_IN, pdev->name);
-       if (ret)
-               return ret;
-
-       dht11->irq = gpio_to_irq(dht11->gpio);
+       dht11->irq = gpiod_to_irq(dht11->gpiod);
        if (dht11->irq < 0) {
-               dev_err(dev, "GPIO %d has no interrupt\n", dht11->gpio);
+               dev_err(dev, "GPIO %d has no interrupt\n", desc_to_gpio(dht11->gpiod));
                return -EINVAL;
        }
 
index 5e461f0..c14bf53 100644 (file)
@@ -197,7 +197,7 @@ struct st_lsm6dsx_ext_dev_settings {
  * struct st_lsm6dsx_settings - ST IMU sensor settings
  * @wai: Sensor WhoAmI default value.
  * @max_fifo_size: Sensor max fifo length in FIFO words.
- * @id: List of hw id supported by the driver configuration.
+ * @id: List of hw id/device name supported by the driver configuration.
  * @decimator: List of decimator register info (addr + mask).
  * @batch: List of FIFO batching register info (addr + mask).
  * @fifo_ops: Sensor hw FIFO parameters.
@@ -207,7 +207,10 @@ struct st_lsm6dsx_ext_dev_settings {
 struct st_lsm6dsx_settings {
        u8 wai;
        u16 max_fifo_size;
-       enum st_lsm6dsx_hw_id id[ST_LSM6DSX_MAX_ID];
+       struct {
+               enum st_lsm6dsx_hw_id hw_id;
+               const char *name;
+       } id[ST_LSM6DSX_MAX_ID];
        struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID];
        struct st_lsm6dsx_reg batch[ST_LSM6DSX_MAX_ID];
        struct st_lsm6dsx_fifo_ops fifo_ops;
@@ -303,7 +306,7 @@ struct st_lsm6dsx_hw {
 static const unsigned long st_lsm6dsx_available_scan_masks[] = {0x7, 0x0};
 extern const struct dev_pm_ops st_lsm6dsx_pm_ops;
 
-int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
+int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
                     struct regmap *regmap);
 int st_lsm6dsx_sensor_set_enable(struct st_lsm6dsx_sensor *sensor,
                                 bool enable);
index fd95d92..a6702a7 100644 (file)
@@ -124,7 +124,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
                .wai = 0x69,
                .max_fifo_size = 1365,
                .id = {
-                       [0] = ST_LSM6DS3_ID,
+                       {
+                               .hw_id = ST_LSM6DS3_ID,
+                               .name = ST_LSM6DS3_DEV_NAME,
+                       },
                },
                .decimator = {
                        [ST_LSM6DSX_ID_ACC] = {
@@ -171,7 +174,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
                .wai = 0x69,
                .max_fifo_size = 682,
                .id = {
-                       [0] = ST_LSM6DS3H_ID,
+                       {
+                               .hw_id = ST_LSM6DS3H_ID,
+                               .name = ST_LSM6DS3H_DEV_NAME,
+                       },
                },
                .decimator = {
                        [ST_LSM6DSX_ID_ACC] = {
@@ -218,9 +224,16 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
                .wai = 0x6a,
                .max_fifo_size = 682,
                .id = {
-                       [0] = ST_LSM6DSL_ID,
-                       [1] = ST_LSM6DSM_ID,
-                       [2] = ST_ISM330DLC_ID,
+                       {
+                               .hw_id = ST_LSM6DSL_ID,
+                               .name = ST_LSM6DSL_DEV_NAME,
+                       }, {
+                               .hw_id = ST_LSM6DSM_ID,
+                               .name = ST_LSM6DSM_DEV_NAME,
+                       }, {
+                               .hw_id = ST_ISM330DLC_ID,
+                               .name = ST_ISM330DLC_DEV_NAME,
+                       },
                },
                .decimator = {
                        [ST_LSM6DSX_ID_ACC] = {
@@ -267,8 +280,13 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
                .wai = 0x6c,
                .max_fifo_size = 512,
                .id = {
-                       [0] = ST_LSM6DSO_ID,
-                       [1] = ST_LSM6DSOX_ID,
+                       {
+                               .hw_id = ST_LSM6DSO_ID,
+                               .name = ST_LSM6DSO_DEV_NAME,
+                       }, {
+                               .hw_id = ST_LSM6DSOX_ID,
+                               .name = ST_LSM6DSOX_DEV_NAME,
+                       },
                },
                .batch = {
                        [ST_LSM6DSX_ID_ACC] = {
@@ -333,7 +351,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
                .wai = 0x6b,
                .max_fifo_size = 512,
                .id = {
-                       [0] = ST_ASM330LHH_ID,
+                       {
+                               .hw_id = ST_ASM330LHH_ID,
+                               .name = ST_ASM330LHH_DEV_NAME,
+                       },
                },
                .batch = {
                        [ST_LSM6DSX_ID_ACC] = {
@@ -372,7 +393,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
                .wai = 0x6b,
                .max_fifo_size = 512,
                .id = {
-                       [0] = ST_LSM6DSR_ID,
+                       {
+                               .hw_id = ST_LSM6DSR_ID,
+                               .name = ST_LSM6DSR_DEV_NAME,
+                       },
                },
                .batch = {
                        [ST_LSM6DSX_ID_ACC] = {
@@ -470,13 +494,14 @@ int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable)
        return err;
 }
 
-static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id)
+static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id,
+                                  const char **name)
 {
        int err, i, j, data;
 
        for (i = 0; i < ARRAY_SIZE(st_lsm6dsx_sensor_settings); i++) {
                for (j = 0; j < ST_LSM6DSX_MAX_ID; j++) {
-                       if (id == st_lsm6dsx_sensor_settings[i].id[j])
+                       if (id == st_lsm6dsx_sensor_settings[i].id[j].hw_id)
                                break;
                }
                if (j < ST_LSM6DSX_MAX_ID)
@@ -499,6 +524,7 @@ static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id)
                return -ENODEV;
        }
 
+       *name = st_lsm6dsx_sensor_settings[i].id[j].name;
        hw->settings = &st_lsm6dsx_sensor_settings[i];
 
        return 0;
@@ -1040,11 +1066,12 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
        return iio_dev;
 }
 
-int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
+int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
                     struct regmap *regmap)
 {
        const struct st_lsm6dsx_shub_settings *hub_settings;
        struct st_lsm6dsx_hw *hw;
+       const char *name = NULL;
        int i, err;
 
        hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
@@ -1065,7 +1092,7 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
        hw->irq = irq;
        hw->regmap = regmap;
 
-       err = st_lsm6dsx_check_whoami(hw, hw_id);
+       err = st_lsm6dsx_check_whoami(hw, hw_id, &name);
        if (err < 0)
                return err;
 
index 966d52a..b3211e0 100644 (file)
@@ -35,8 +35,7 @@ static int st_lsm6dsx_i2c_probe(struct i2c_client *client,
                return PTR_ERR(regmap);
        }
 
-       return st_lsm6dsx_probe(&client->dev, client->irq,
-                               hw_id, id->name, regmap);
+       return st_lsm6dsx_probe(&client->dev, client->irq, hw_id, regmap);
 }
 
 static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
index 24e4e50..c9d3c47 100644 (file)
@@ -35,8 +35,7 @@ static int st_lsm6dsx_spi_probe(struct spi_device *spi)
                return PTR_ERR(regmap);
        }
 
-       return st_lsm6dsx_probe(&spi->dev, spi->irq,
-                               hw_id, id->name, regmap);
+       return st_lsm6dsx_probe(&spi->dev, spi->irq, hw_id, regmap);
 }
 
 static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
index 401d7ff..524a686 100644 (file)
@@ -366,39 +366,25 @@ static void iio_device_unregister_debugfs(struct iio_dev *indio_dev)
        debugfs_remove_recursive(indio_dev->debugfs_dentry);
 }
 
-static int iio_device_register_debugfs(struct iio_dev *indio_dev)
+static void iio_device_register_debugfs(struct iio_dev *indio_dev)
 {
-       struct dentry *d;
-
        if (indio_dev->info->debugfs_reg_access == NULL)
-               return 0;
+               return;
 
        if (!iio_debugfs_dentry)
-               return 0;
+               return;
 
        indio_dev->debugfs_dentry =
                debugfs_create_dir(dev_name(&indio_dev->dev),
                                   iio_debugfs_dentry);
-       if (indio_dev->debugfs_dentry == NULL) {
-               dev_warn(indio_dev->dev.parent,
-                        "Failed to create debugfs directory\n");
-               return -EFAULT;
-       }
-
-       d = debugfs_create_file("direct_reg_access", 0644,
-                               indio_dev->debugfs_dentry,
-                               indio_dev, &iio_debugfs_reg_fops);
-       if (!d) {
-               iio_device_unregister_debugfs(indio_dev);
-               return -ENOMEM;
-       }
 
-       return 0;
+       debugfs_create_file("direct_reg_access", 0644,
+                           indio_dev->debugfs_dentry, indio_dev,
+                           &iio_debugfs_reg_fops);
 }
 #else
-static int iio_device_register_debugfs(struct iio_dev *indio_dev)
+static void iio_device_register_debugfs(struct iio_dev *indio_dev)
 {
-       return 0;
 }
 
 static void iio_device_unregister_debugfs(struct iio_dev *indio_dev)
@@ -1104,6 +1090,8 @@ static int iio_device_add_info_mask_type_avail(struct iio_dev *indio_dev,
        char *avail_postfix;
 
        for_each_set_bit(i, infomask, sizeof(*infomask) * 8) {
+               if (i >= ARRAY_SIZE(iio_chan_info_postfix))
+                       return -EINVAL;
                avail_postfix = kasprintf(GFP_KERNEL,
                                          "%s_available",
                                          iio_chan_info_postfix[i]);
@@ -1669,12 +1657,7 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
        /* configure elements for the chrdev */
        indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id);
 
-       ret = iio_device_register_debugfs(indio_dev);
-       if (ret) {
-               dev_err(indio_dev->dev.parent,
-                       "Failed to register debugfs interfaces\n");
-               return ret;
-       }
+       iio_device_register_debugfs(indio_dev);
 
        ret = iio_buffer_alloc_sysfs_and_mask(indio_dev);
        if (ret) {
index 2fb2314..5a8351c 100644 (file)
@@ -90,7 +90,7 @@ static const struct iio_chan_spec
 
 #ifdef CONFIG_OF
 
-static int iio_dev_node_match(struct device *dev, void *data)
+static int iio_dev_node_match(struct device *dev, const void *data)
 {
        return dev->of_node == data && dev->type == &iio_device_type;
 }
index 340d64d..a836100 100644 (file)
@@ -146,7 +146,7 @@ static int bh1780_probe(struct i2c_client *client,
 {
        int ret;
        struct bh1780_data *bh1780;
-       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct i2c_adapter *adapter = client->adapter;
        struct iio_dev *indio_dev;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
index eff7ac9..b955183 100644 (file)
@@ -37,6 +37,7 @@
 
 #define STK3310_CHIP_ID_VAL                    0x13
 #define STK3311_CHIP_ID_VAL                    0x1D
+#define STK3335_CHIP_ID_VAL                    0x51
 #define STK3310_PSINT_EN                       0x01
 #define STK3310_PS_MAX_VAL                     0xFFFF
 
@@ -451,7 +452,8 @@ static int stk3310_init(struct iio_dev *indio_dev)
                return ret;
 
        if (chipid != STK3310_CHIP_ID_VAL &&
-           chipid != STK3311_CHIP_ID_VAL) {
+           chipid != STK3311_CHIP_ID_VAL &&
+           chipid != STK3335_CHIP_ID_VAL) {
                dev_err(&client->dev, "invalid chip id: 0x%x\n", chipid);
                return -ENODEV;
        }
@@ -663,6 +665,7 @@ static SIMPLE_DEV_PM_OPS(stk3310_pm_ops, stk3310_suspend, stk3310_resume);
 static const struct i2c_device_id stk3310_i2c_id[] = {
        {"STK3310", 0},
        {"STK3311", 0},
+       {"STK3335", 0},
        {}
 };
 MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id);
@@ -670,6 +673,7 @@ MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id);
 static const struct acpi_device_id stk3310_acpi_id[] = {
        {"STK3310", 0},
        {"STK3311", 0},
+       {"STK3335", 0},
        {}
 };
 
index b191811..ba420e4 100644 (file)
@@ -53,6 +53,17 @@ config IIO_CROS_EC_BARO
          To compile this driver as a module, choose M here: the module
          will be called cros_ec_baro.
 
+config DPS310
+       tristate "Infineon DPS310 pressure and temperature sensor"
+       depends on I2C
+       select REGMAP_I2C
+       help
+         Support for the Infineon DPS310 digital barometric pressure sensor.
+         It can be accessed over I2C bus.
+
+         This driver can also be built as a module.  If so, the module will be
+         called dps310.
+
 config HID_SENSOR_PRESS
        depends on HID_SENSOR_HUB
        select IIO_BUFFER
index c2058d7..d8f5ace 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_BMP280) += bmp280.o
 bmp280-objs := bmp280-core.o bmp280-regmap.o
 obj-$(CONFIG_BMP280_I2C) += bmp280-i2c.o
 obj-$(CONFIG_BMP280_SPI) += bmp280-spi.o
+obj-$(CONFIG_DPS310) += dps310.o
 obj-$(CONFIG_IIO_CROS_EC_BARO) += cros_ec_baro.o
 obj-$(CONFIG_HID_SENSOR_PRESS)   += hid-sensor-press.o
 obj-$(CONFIG_HP03) += hp03.o
diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c
new file mode 100644 (file)
index 0000000..2c1943b
--- /dev/null
@@ -0,0 +1,827 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright IBM Corp 2019
+/*
+ * The DPS310 is a barometric pressure and temperature sensor.
+ * Currently only reading a single temperature is supported by
+ * this driver.
+ *
+ * https://www.infineon.com/dgdl/?fileId=5546d462576f34750157750826c42242
+ *
+ * Temperature calculation:
+ *   c0 * 0.5 + c1 * T_raw / kT °C
+ *
+ * TODO:
+ *  - Optionally support the FIFO
+ */
+
+#include <linux/i2c.h>
+#include <linux/limits.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define DPS310_DEV_NAME                "dps310"
+
+#define DPS310_PRS_B0          0x00
+#define DPS310_PRS_B1          0x01
+#define DPS310_PRS_B2          0x02
+#define DPS310_TMP_B0          0x03
+#define DPS310_TMP_B1          0x04
+#define DPS310_TMP_B2          0x05
+#define DPS310_PRS_CFG         0x06
+#define  DPS310_PRS_RATE_BITS  GENMASK(6, 4)
+#define  DPS310_PRS_PRC_BITS   GENMASK(3, 0)
+#define DPS310_TMP_CFG         0x07
+#define  DPS310_TMP_RATE_BITS  GENMASK(6, 4)
+#define  DPS310_TMP_PRC_BITS   GENMASK(3, 0)
+#define  DPS310_TMP_EXT                BIT(7)
+#define DPS310_MEAS_CFG                0x08
+#define  DPS310_MEAS_CTRL_BITS GENMASK(2, 0)
+#define   DPS310_PRS_EN                BIT(0)
+#define   DPS310_TEMP_EN       BIT(1)
+#define   DPS310_BACKGROUND    BIT(2)
+#define  DPS310_PRS_RDY                BIT(4)
+#define  DPS310_TMP_RDY                BIT(5)
+#define  DPS310_SENSOR_RDY     BIT(6)
+#define  DPS310_COEF_RDY       BIT(7)
+#define DPS310_CFG_REG         0x09
+#define  DPS310_INT_HL         BIT(7)
+#define  DPS310_TMP_SHIFT_EN   BIT(3)
+#define  DPS310_PRS_SHIFT_EN   BIT(4)
+#define  DPS310_FIFO_EN                BIT(5)
+#define  DPS310_SPI_EN         BIT(6)
+#define DPS310_RESET           0x0c
+#define  DPS310_RESET_MAGIC    0x09
+#define DPS310_COEF_BASE       0x10
+
+/* Make sure sleep time is <= 20ms for usleep_range */
+#define DPS310_POLL_SLEEP_US(t)                min(20000, (t) / 8)
+/* Silently handle error in rate value here */
+#define DPS310_POLL_TIMEOUT_US(rc)     ((rc) <= 0 ? 1000000 : 1000000 / (rc))
+
+#define DPS310_PRS_BASE                DPS310_PRS_B0
+#define DPS310_TMP_BASE                DPS310_TMP_B0
+
+/*
+ * These values (defined in the spec) indicate how to scale the raw register
+ * values for each level of precision available.
+ */
+static const int scale_factors[] = {
+        524288,
+       1572864,
+       3670016,
+       7864320,
+        253952,
+        516096,
+       1040384,
+       2088960,
+};
+
+struct dps310_data {
+       struct i2c_client *client;
+       struct regmap *regmap;
+       struct mutex lock;      /* Lock for sequential HW access functions */
+
+       s32 c0, c1;
+       s32 c00, c10, c20, c30, c01, c11, c21;
+       s32 pressure_raw;
+       s32 temp_raw;
+};
+
+static const struct iio_chan_spec dps310_channels[] = {
+       {
+               .type = IIO_TEMP,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
+                       BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+                       BIT(IIO_CHAN_INFO_PROCESSED),
+       },
+       {
+               .type = IIO_PRESSURE,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
+                       BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+                       BIT(IIO_CHAN_INFO_PROCESSED),
+       },
+};
+
+/* To be called after checking the COEF_RDY bit in MEAS_CFG */
+static int dps310_get_coefs(struct dps310_data *data)
+{
+       int rc;
+       u8 coef[18];
+       u32 c0, c1;
+       u32 c00, c10, c20, c30, c01, c11, c21;
+
+       /* Read all sensor calibration coefficients from the COEF registers. */
+       rc = regmap_bulk_read(data->regmap, DPS310_COEF_BASE, coef,
+                             sizeof(coef));
+       if (rc < 0)
+               return rc;
+
+       /*
+        * Calculate temperature calibration coefficients c0 and c1. The
+        * numbers are 12-bit 2's complement numbers.
+        */
+       c0 = (coef[0] << 4) | (coef[1] >> 4);
+       data->c0 = sign_extend32(c0, 11);
+
+       c1 = ((coef[1] & GENMASK(3, 0)) << 8) | coef[2];
+       data->c1 = sign_extend32(c1, 11);
+
+       /*
+        * Calculate pressure calibration coefficients. c00 and c10 are 20 bit
+        * 2's complement numbers, while the rest are 16 bit 2's complement
+        * numbers.
+        */
+       c00 = (coef[3] << 12) | (coef[4] << 4) | (coef[5] >> 4);
+       data->c00 = sign_extend32(c00, 19);
+
+       c10 = ((coef[5] & GENMASK(3, 0)) << 16) | (coef[6] << 8) | coef[7];
+       data->c10 = sign_extend32(c10, 19);
+
+       c01 = (coef[8] << 8) | coef[9];
+       data->c01 = sign_extend32(c01, 15);
+
+       c11 = (coef[10] << 8) | coef[11];
+       data->c11 = sign_extend32(c11, 15);
+
+       c20 = (coef[12] << 8) | coef[13];
+       data->c20 = sign_extend32(c20, 15);
+
+       c21 = (coef[14] << 8) | coef[15];
+       data->c21 = sign_extend32(c21, 15);
+
+       c30 = (coef[16] << 8) | coef[17];
+       data->c30 = sign_extend32(c30, 15);
+
+       return 0;
+}
+
+static int dps310_get_pres_precision(struct dps310_data *data)
+{
+       int rc;
+       int val;
+
+       rc = regmap_read(data->regmap, DPS310_PRS_CFG, &val);
+       if (rc < 0)
+               return rc;
+
+       return BIT(val & GENMASK(2, 0));
+}
+
+static int dps310_get_temp_precision(struct dps310_data *data)
+{
+       int rc;
+       int val;
+
+       rc = regmap_read(data->regmap, DPS310_TMP_CFG, &val);
+       if (rc < 0)
+               return rc;
+
+       /*
+        * Scale factor is bottom 4 bits of the register, but 1111 is
+        * reserved so just grab bottom three
+        */
+       return BIT(val & GENMASK(2, 0));
+}
+
+/* Called with lock held */
+static int dps310_set_pres_precision(struct dps310_data *data, int val)
+{
+       int rc;
+       u8 shift_en;
+
+       if (val < 0 || val > 128)
+               return -EINVAL;
+
+       shift_en = val >= 16 ? DPS310_PRS_SHIFT_EN : 0;
+       rc = regmap_write_bits(data->regmap, DPS310_CFG_REG,
+                              DPS310_PRS_SHIFT_EN, shift_en);
+       if (rc)
+               return rc;
+
+       return regmap_update_bits(data->regmap, DPS310_PRS_CFG,
+                                 DPS310_PRS_PRC_BITS, ilog2(val));
+}
+
+/* Called with lock held */
+static int dps310_set_temp_precision(struct dps310_data *data, int val)
+{
+       int rc;
+       u8 shift_en;
+
+       if (val < 0 || val > 128)
+               return -EINVAL;
+
+       shift_en = val >= 16 ? DPS310_TMP_SHIFT_EN : 0;
+       rc = regmap_write_bits(data->regmap, DPS310_CFG_REG,
+                              DPS310_TMP_SHIFT_EN, shift_en);
+       if (rc)
+               return rc;
+
+       return regmap_update_bits(data->regmap, DPS310_TMP_CFG,
+                                 DPS310_TMP_PRC_BITS, ilog2(val));
+}
+
+/* Called with lock held */
+static int dps310_set_pres_samp_freq(struct dps310_data *data, int freq)
+{
+       u8 val;
+
+       if (freq < 0 || freq > 128)
+               return -EINVAL;
+
+       val = ilog2(freq) << 4;
+
+       return regmap_update_bits(data->regmap, DPS310_PRS_CFG,
+                                 DPS310_PRS_RATE_BITS, val);
+}
+
+/* Called with lock held */
+static int dps310_set_temp_samp_freq(struct dps310_data *data, int freq)
+{
+       u8 val;
+
+       if (freq < 0 || freq > 128)
+               return -EINVAL;
+
+       val = ilog2(freq) << 4;
+
+       return regmap_update_bits(data->regmap, DPS310_TMP_CFG,
+                                 DPS310_TMP_RATE_BITS, val);
+}
+
+static int dps310_get_pres_samp_freq(struct dps310_data *data)
+{
+       int rc;
+       int val;
+
+       rc = regmap_read(data->regmap, DPS310_PRS_CFG, &val);
+       if (rc < 0)
+               return rc;
+
+       return BIT((val & DPS310_PRS_RATE_BITS) >> 4);
+}
+
+static int dps310_get_temp_samp_freq(struct dps310_data *data)
+{
+       int rc;
+       int val;
+
+       rc = regmap_read(data->regmap, DPS310_TMP_CFG, &val);
+       if (rc < 0)
+               return rc;
+
+       return BIT((val & DPS310_TMP_RATE_BITS) >> 4);
+}
+
+static int dps310_get_pres_k(struct dps310_data *data)
+{
+       int rc = dps310_get_pres_precision(data);
+
+       if (rc < 0)
+               return rc;
+
+       return scale_factors[ilog2(rc)];
+}
+
+static int dps310_get_temp_k(struct dps310_data *data)
+{
+       int rc = dps310_get_temp_precision(data);
+
+       if (rc < 0)
+               return rc;
+
+       return scale_factors[ilog2(rc)];
+}
+
+static int dps310_read_pres_raw(struct dps310_data *data)
+{
+       int rc;
+       int rate;
+       int ready;
+       int timeout;
+       s32 raw;
+       u8 val[3];
+
+       if (mutex_lock_interruptible(&data->lock))
+               return -EINTR;
+
+       rate = dps310_get_pres_samp_freq(data);
+       timeout = DPS310_POLL_TIMEOUT_US(rate);
+
+       /* Poll for sensor readiness; base the timeout upon the sample rate. */
+       rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready,
+                                     ready & DPS310_PRS_RDY,
+                                     DPS310_POLL_SLEEP_US(timeout), timeout);
+       if (rc)
+               goto done;
+
+       rc = regmap_bulk_read(data->regmap, DPS310_PRS_BASE, val, sizeof(val));
+       if (rc < 0)
+               goto done;
+
+       raw = (val[0] << 16) | (val[1] << 8) | val[2];
+       data->pressure_raw = sign_extend32(raw, 23);
+
+done:
+       mutex_unlock(&data->lock);
+       return rc;
+}
+
+/* Called with lock held */
+static int dps310_read_temp_ready(struct dps310_data *data)
+{
+       int rc;
+       u8 val[3];
+       s32 raw;
+
+       rc = regmap_bulk_read(data->regmap, DPS310_TMP_BASE, val, sizeof(val));
+       if (rc < 0)
+               return rc;
+
+       raw = (val[0] << 16) | (val[1] << 8) | val[2];
+       data->temp_raw = sign_extend32(raw, 23);
+
+       return 0;
+}
+
+static int dps310_read_temp_raw(struct dps310_data *data)
+{
+       int rc;
+       int rate;
+       int ready;
+       int timeout;
+
+       if (mutex_lock_interruptible(&data->lock))
+               return -EINTR;
+
+       rate = dps310_get_temp_samp_freq(data);
+       timeout = DPS310_POLL_TIMEOUT_US(rate);
+
+       /* Poll for sensor readiness; base the timeout upon the sample rate. */
+       rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready,
+                                     ready & DPS310_TMP_RDY,
+                                     DPS310_POLL_SLEEP_US(timeout), timeout);
+       if (rc < 0)
+               goto done;
+
+       rc = dps310_read_temp_ready(data);
+
+done:
+       mutex_unlock(&data->lock);
+       return rc;
+}
+
+static bool dps310_is_writeable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case DPS310_PRS_CFG:
+       case DPS310_TMP_CFG:
+       case DPS310_MEAS_CFG:
+       case DPS310_CFG_REG:
+       case DPS310_RESET:
+       /* No documentation available on the registers below */
+       case 0x0e:
+       case 0x0f:
+       case 0x62:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool dps310_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case DPS310_PRS_B0:
+       case DPS310_PRS_B1:
+       case DPS310_PRS_B2:
+       case DPS310_TMP_B0:
+       case DPS310_TMP_B1:
+       case DPS310_TMP_B2:
+       case DPS310_MEAS_CFG:
+       case 0x32:      /* No documentation available on this register */
+               return true;
+       default:
+               return false;
+       }
+}
+
+static int dps310_write_raw(struct iio_dev *iio,
+                           struct iio_chan_spec const *chan, int val,
+                           int val2, long mask)
+{
+       int rc;
+       struct dps310_data *data = iio_priv(iio);
+
+       if (mutex_lock_interruptible(&data->lock))
+               return -EINTR;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               switch (chan->type) {
+               case IIO_PRESSURE:
+                       rc = dps310_set_pres_samp_freq(data, val);
+                       break;
+
+               case IIO_TEMP:
+                       rc = dps310_set_temp_samp_freq(data, val);
+                       break;
+
+               default:
+                       rc = -EINVAL;
+                       break;
+               }
+               break;
+
+       case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+               switch (chan->type) {
+               case IIO_PRESSURE:
+                       rc = dps310_set_pres_precision(data, val);
+                       break;
+
+               case IIO_TEMP:
+                       rc = dps310_set_temp_precision(data, val);
+                       break;
+
+               default:
+                       rc = -EINVAL;
+                       break;
+               }
+               break;
+
+       default:
+               rc = -EINVAL;
+               break;
+       }
+
+       mutex_unlock(&data->lock);
+       return rc;
+}
+
+static int dps310_calculate_pressure(struct dps310_data *data)
+{
+       int i;
+       int rc;
+       int t_ready;
+       int kpi = dps310_get_pres_k(data);
+       int kti = dps310_get_temp_k(data);
+       s64 rem = 0ULL;
+       s64 pressure = 0ULL;
+       s64 p;
+       s64 t;
+       s64 denoms[7];
+       s64 nums[7];
+       s64 rems[7];
+       s64 kp;
+       s64 kt;
+
+       if (kpi < 0)
+               return kpi;
+
+       if (kti < 0)
+               return kti;
+
+       kp = (s64)kpi;
+       kt = (s64)kti;
+
+       /* Refresh temp if it's ready, otherwise just use the latest value */
+       if (mutex_trylock(&data->lock)) {
+               rc = regmap_read(data->regmap, DPS310_MEAS_CFG, &t_ready);
+               if (rc >= 0 && t_ready & DPS310_TMP_RDY)
+                       dps310_read_temp_ready(data);
+
+               mutex_unlock(&data->lock);
+       }
+
+       p = (s64)data->pressure_raw;
+       t = (s64)data->temp_raw;
+
+       /* Section 4.9.1 of the DPS310 spec; algebra'd to avoid underflow */
+       nums[0] = (s64)data->c00;
+       denoms[0] = 1LL;
+       nums[1] = p * (s64)data->c10;
+       denoms[1] = kp;
+       nums[2] = p * p * (s64)data->c20;
+       denoms[2] = kp * kp;
+       nums[3] = p * p * p * (s64)data->c30;
+       denoms[3] = kp * kp * kp;
+       nums[4] = t * (s64)data->c01;
+       denoms[4] = kt;
+       nums[5] = t * p * (s64)data->c11;
+       denoms[5] = kp * kt;
+       nums[6] = t * p * p * (s64)data->c21;
+       denoms[6] = kp * kp * kt;
+
+       /* Kernel lacks a div64_s64_rem function; denoms are all positive */
+       for (i = 0; i < 7; ++i) {
+               u64 irem;
+
+               if (nums[i] < 0LL) {
+                       pressure -= div64_u64_rem(-nums[i], denoms[i], &irem);
+                       rems[i] = -irem;
+               } else {
+                       pressure += div64_u64_rem(nums[i], denoms[i], &irem);
+                       rems[i] = (s64)irem;
+               }
+       }
+
+       /* Increase precision and calculate the remainder sum */
+       for (i = 0; i < 7; ++i)
+               rem += div64_s64((s64)rems[i] * 1000000000LL, denoms[i]);
+
+       pressure += div_s64(rem, 1000000000LL);
+       if (pressure < 0LL)
+               return -ERANGE;
+
+       return (int)min_t(s64, pressure, INT_MAX);
+}
+
+static int dps310_read_pressure(struct dps310_data *data, int *val, int *val2,
+                               long mask)
+{
+       int rc;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               rc = dps310_get_pres_samp_freq(data);
+               if (rc < 0)
+                       return rc;
+
+               *val = rc;
+               return IIO_VAL_INT;
+
+       case IIO_CHAN_INFO_PROCESSED:
+               rc = dps310_read_pres_raw(data);
+               if (rc)
+                       return rc;
+
+               rc = dps310_calculate_pressure(data);
+               if (rc < 0)
+                       return rc;
+
+               *val = rc;
+               *val2 = 1000; /* Convert Pa to KPa per IIO ABI */
+               return IIO_VAL_FRACTIONAL;
+
+       case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+               rc = dps310_get_pres_precision(data);
+               if (rc < 0)
+                       return rc;
+
+               *val = rc;
+               return IIO_VAL_INT;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static int dps310_calculate_temp(struct dps310_data *data)
+{
+       s64 c0;
+       s64 t;
+       int kt = dps310_get_temp_k(data);
+
+       if (kt < 0)
+               return kt;
+
+       /* Obtain inverse-scaled offset */
+       c0 = div_s64((s64)kt * (s64)data->c0, 2);
+
+       /* Add the offset to the unscaled temperature */
+       t = c0 + ((s64)data->temp_raw * (s64)data->c1);
+
+       /* Convert to milliCelsius and scale the temperature */
+       return (int)div_s64(t * 1000LL, kt);
+}
+
+static int dps310_read_temp(struct dps310_data *data, int *val, int *val2,
+                           long mask)
+{
+       int rc;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               rc = dps310_get_temp_samp_freq(data);
+               if (rc < 0)
+                       return rc;
+
+               *val = rc;
+               return IIO_VAL_INT;
+
+       case IIO_CHAN_INFO_PROCESSED:
+               rc = dps310_read_temp_raw(data);
+               if (rc)
+                       return rc;
+
+               rc = dps310_calculate_temp(data);
+               if (rc < 0)
+                       return rc;
+
+               *val = rc;
+               return IIO_VAL_INT;
+
+       case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+               rc = dps310_get_temp_precision(data);
+               if (rc < 0)
+                       return rc;
+
+               *val = rc;
+               return IIO_VAL_INT;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static int dps310_read_raw(struct iio_dev *iio,
+                          struct iio_chan_spec const *chan,
+                          int *val, int *val2, long mask)
+{
+       struct dps310_data *data = iio_priv(iio);
+
+       switch (chan->type) {
+       case IIO_PRESSURE:
+               return dps310_read_pressure(data, val, val2, mask);
+
+       case IIO_TEMP:
+               return dps310_read_temp(data, val, val2, mask);
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static void dps310_reset(void *action_data)
+{
+       struct dps310_data *data = action_data;
+
+       regmap_write(data->regmap, DPS310_RESET, DPS310_RESET_MAGIC);
+}
+
+static const struct regmap_config dps310_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .writeable_reg = dps310_is_writeable_reg,
+       .volatile_reg = dps310_is_volatile_reg,
+       .cache_type = REGCACHE_RBTREE,
+       .max_register = 0x62, /* No documentation available on this register */
+};
+
+static const struct iio_info dps310_info = {
+       .read_raw = dps310_read_raw,
+       .write_raw = dps310_write_raw,
+};
+
+/*
+ * Some verions of chip will read temperatures in the ~60C range when
+ * its actually ~20C. This is the manufacturer recommended workaround
+ * to correct the issue. The registers used below are undocumented.
+ */
+static int dps310_temp_workaround(struct dps310_data *data)
+{
+       int rc;
+       int reg;
+
+       rc = regmap_read(data->regmap, 0x32, &reg);
+       if (rc < 0)
+               return rc;
+
+       /*
+        * If bit 1 is set then the device is okay, and the workaround does not
+        * need to be applied
+        */
+       if (reg & BIT(1))
+               return 0;
+
+       rc = regmap_write(data->regmap, 0x0e, 0xA5);
+       if (rc < 0)
+               return rc;
+
+       rc = regmap_write(data->regmap, 0x0f, 0x96);
+       if (rc < 0)
+               return rc;
+
+       rc = regmap_write(data->regmap, 0x62, 0x02);
+       if (rc < 0)
+               return rc;
+
+       rc = regmap_write(data->regmap, 0x0e, 0x00);
+       if (rc < 0)
+               return rc;
+
+       return regmap_write(data->regmap, 0x0f, 0x00);
+}
+
+static int dps310_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct dps310_data *data;
+       struct iio_dev *iio;
+       int rc, ready;
+
+       iio = devm_iio_device_alloc(&client->dev,  sizeof(*data));
+       if (!iio)
+               return -ENOMEM;
+
+       data = iio_priv(iio);
+       data->client = client;
+       mutex_init(&data->lock);
+
+       iio->dev.parent = &client->dev;
+       iio->name = id->name;
+       iio->channels = dps310_channels;
+       iio->num_channels = ARRAY_SIZE(dps310_channels);
+       iio->info = &dps310_info;
+       iio->modes = INDIO_DIRECT_MODE;
+
+       data->regmap = devm_regmap_init_i2c(client, &dps310_regmap_config);
+       if (IS_ERR(data->regmap))
+               return PTR_ERR(data->regmap);
+
+       /* Register to run the device reset when the device is removed */
+       rc = devm_add_action_or_reset(&client->dev, dps310_reset, data);
+       if (rc)
+               return rc;
+
+       /*
+        * Set up pressure sensor in single sample, one measurement per second
+        * mode
+        */
+       rc = regmap_write(data->regmap, DPS310_PRS_CFG, 0);
+
+       /*
+        * Set up external (MEMS) temperature sensor in single sample, one
+        * measurement per second mode
+        */
+       rc = regmap_write(data->regmap, DPS310_TMP_CFG, DPS310_TMP_EXT);
+       if (rc < 0)
+               return rc;
+
+       /* Temp and pressure shifts are disabled when PRC <= 8 */
+       rc = regmap_write_bits(data->regmap, DPS310_CFG_REG,
+                              DPS310_PRS_SHIFT_EN | DPS310_TMP_SHIFT_EN, 0);
+       if (rc < 0)
+               return rc;
+
+       /* MEAS_CFG doesn't update correctly unless first written with 0 */
+       rc = regmap_write_bits(data->regmap, DPS310_MEAS_CFG,
+                              DPS310_MEAS_CTRL_BITS, 0);
+       if (rc < 0)
+               return rc;
+
+       /* Turn on temperature and pressure measurement in the background */
+       rc = regmap_write_bits(data->regmap, DPS310_MEAS_CFG,
+                              DPS310_MEAS_CTRL_BITS, DPS310_PRS_EN |
+                              DPS310_TEMP_EN | DPS310_BACKGROUND);
+       if (rc < 0)
+               return rc;
+
+       /*
+        * Calibration coefficients required for reporting temperature.
+        * They are available 40ms after the device has started
+        */
+       rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready,
+                                     ready & DPS310_COEF_RDY, 10000, 40000);
+       if (rc < 0)
+               return rc;
+
+       rc = dps310_get_coefs(data);
+       if (rc < 0)
+               return rc;
+
+       rc = dps310_temp_workaround(data);
+       if (rc < 0)
+               return rc;
+
+       rc = devm_iio_device_register(&client->dev, iio);
+       if (rc)
+               return rc;
+
+       i2c_set_clientdata(client, iio);
+
+       return 0;
+}
+
+static const struct i2c_device_id dps310_id[] = {
+       { DPS310_DEV_NAME, 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, dps310_id);
+
+static struct i2c_driver dps310_driver = {
+       .driver = {
+               .name = DPS310_DEV_NAME,
+       },
+       .probe = dps310_probe,
+       .id_table = dps310_id,
+};
+module_i2c_driver(dps310_driver);
+
+MODULE_AUTHOR("Joel Stanley <joel@jms.id.au>");
+MODULE_DESCRIPTION("Infineon DPS310 pressure and temperature sensor");
+MODULE_LICENSE("GPL v2");
index c31b963..c613a64 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/init.h>
 #include <linux/mutex.h>
 #include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/spi/spi.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/trigger.h>
@@ -262,9 +264,17 @@ static const struct spi_device_id maxim_thermocouple_id[] = {
 };
 MODULE_DEVICE_TABLE(spi, maxim_thermocouple_id);
 
+static const struct of_device_id maxim_thermocouple_of_match[] = {
+        { .compatible = "maxim,max6675" },
+        { .compatible = "maxim,max31855" },
+        { },
+};
+MODULE_DEVICE_TABLE(of, maxim_thermocouple_of_match);
+
 static struct spi_driver maxim_thermocouple_driver = {
        .driver = {
                .name   = MAXIM_THERMOCOUPLE_DRV_NAME,
+               .of_match_table = maxim_thermocouple_of_match,
        },
        .probe          = maxim_thermocouple_probe,
        .remove         = maxim_thermocouple_remove,
index 829b0c6..6175820 100644 (file)
@@ -127,7 +127,7 @@ __malloc void *_uverbs_alloc(struct uverbs_attr_bundle *bundle, size_t size,
        res = (void *)pbundle->internal_buffer + pbundle->internal_used;
        pbundle->internal_used =
                ALIGN(new_used, sizeof(*pbundle->internal_buffer));
-       if (flags & __GFP_ZERO)
+       if (want_init_on_alloc(flags))
                memset(res, 0, size);
        return res;
 }
index e068a02..3afd3e9 100644 (file)
@@ -4498,7 +4498,7 @@ static const struct acpi_device_id hns_roce_acpi_match[] = {
 };
 MODULE_DEVICE_TABLE(acpi, hns_roce_acpi_match);
 
-static int hns_roce_node_match(struct device *dev, void *fwnode)
+static int hns_roce_node_match(struct device *dev, const void *fwnode)
 {
        return dev->fwnode == fwnode;
 }
index 4305da2..d5cbad2 100644 (file)
@@ -2340,7 +2340,6 @@ static void srp_handle_qp_err(struct ib_cq *cq, struct ib_wc *wc,
 static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
 {
        struct srp_target_port *target = host_to_target(shost);
-       struct srp_rport *rport = target->rport;
        struct srp_rdma_ch *ch;
        struct srp_request *req;
        struct srp_iu *iu;
@@ -2350,16 +2349,6 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
        u32 tag;
        u16 idx;
        int len, ret;
-       const bool in_scsi_eh = !in_interrupt() && current == shost->ehandler;
-
-       /*
-        * The SCSI EH thread is the only context from which srp_queuecommand()
-        * can get invoked for blocked devices (SDEV_BLOCK /
-        * SDEV_CREATED_BLOCK). Avoid racing with srp_reconnect_rport() by
-        * locking the rport mutex if invoked from inside the SCSI EH.
-        */
-       if (in_scsi_eh)
-               mutex_lock(&rport->mutex);
 
        scmnd->result = srp_chkready(target->rport);
        if (unlikely(scmnd->result))
@@ -2428,13 +2417,7 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
                goto err_unmap;
        }
 
-       ret = 0;
-
-unlock_rport:
-       if (in_scsi_eh)
-               mutex_unlock(&rport->mutex);
-
-       return ret;
+       return 0;
 
 err_unmap:
        srp_unmap_data(scmnd, ch, req);
@@ -2456,7 +2439,7 @@ err:
                ret = SCSI_MLQUEUE_HOST_BUSY;
        }
 
-       goto unlock_rport;
+       return ret;
 }
 
 /*
index ac21c05..a2b5fbb 100644 (file)
@@ -808,6 +808,7 @@ static bool joydev_dev_is_blacklisted(struct input_dev *dev)
 static bool joydev_dev_is_absolute_mouse(struct input_dev *dev)
 {
        DECLARE_BITMAP(jd_scratch, KEY_CNT);
+       bool ev_match = false;
 
        BUILD_BUG_ON(ABS_CNT > KEY_CNT || EV_CNT > KEY_CNT);
 
@@ -826,17 +827,36 @@ static bool joydev_dev_is_absolute_mouse(struct input_dev *dev)
         * considered to be an absolute mouse if the following is
         * true:
         *
-        * 1) Event types are exactly EV_ABS, EV_KEY and EV_SYN.
+        * 1) Event types are exactly
+        *      EV_ABS, EV_KEY and EV_SYN
+        *    or
+        *      EV_ABS, EV_KEY, EV_SYN and EV_MSC
+        *    or
+        *      EV_ABS, EV_KEY, EV_SYN, EV_MSC and EV_REL.
         * 2) Absolute events are exactly ABS_X and ABS_Y.
         * 3) Keys are exactly BTN_LEFT, BTN_RIGHT and BTN_MIDDLE.
         * 4) Device is not on "Amiga" bus.
         */
 
        bitmap_zero(jd_scratch, EV_CNT);
+       /* VMware VMMouse, HP ILO2 */
        __set_bit(EV_ABS, jd_scratch);
        __set_bit(EV_KEY, jd_scratch);
        __set_bit(EV_SYN, jd_scratch);
-       if (!bitmap_equal(jd_scratch, dev->evbit, EV_CNT))
+       if (bitmap_equal(jd_scratch, dev->evbit, EV_CNT))
+               ev_match = true;
+
+       /* HP ILO2, AMI BMC firmware */
+       __set_bit(EV_MSC, jd_scratch);
+       if (bitmap_equal(jd_scratch, dev->evbit, EV_CNT))
+               ev_match = true;
+
+       /* VMware Virtual USB Mouse, QEMU USB Tablet, ATEN BMC firmware */
+       __set_bit(EV_REL, jd_scratch);
+       if (bitmap_equal(jd_scratch, dev->evbit, EV_CNT))
+               ev_match = true;
+
+       if (!ev_match)
                return false;
 
        bitmap_zero(jd_scratch, ABS_CNT);
index 62dcc5b..f002fb8 100644 (file)
@@ -14,15 +14,15 @@ config JOYSTICK_IFORCE
          module will be called iforce.
 
 config JOYSTICK_IFORCE_USB
-       bool "I-Force USB joysticks and wheels"
-       depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || USB=y) && USB
+       tristate "I-Force USB joysticks and wheels"
+       depends on JOYSTICK_IFORCE && USB
        help
          Say Y here if you have an I-Force joystick or steering wheel
          connected to your USB port.
 
 config JOYSTICK_IFORCE_232
-       bool "I-Force Serial joysticks and wheels"
-       depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || SERIO=y) && SERIO
+       tristate "I-Force Serial joysticks and wheels"
+       depends on JOYSTICK_IFORCE && SERIO
        help
          Say Y here if you have an I-Force joystick or steering wheel
          connected to your serial (COM) port.
index fa79a49..dbbe7c0 100644 (file)
@@ -5,8 +5,7 @@
 # By Johann Deneux <johann.deneux@gmail.com>
 #
 
-obj-$(CONFIG_JOYSTICK_IFORCE)  += iforce.o
-
+obj-$(CONFIG_JOYSTICK_IFORCE)          += iforce.o
 iforce-y := iforce-ff.o iforce-main.o iforce-packets.o
-iforce-$(CONFIG_JOYSTICK_IFORCE_232)   += iforce-serio.o
-iforce-$(CONFIG_JOYSTICK_IFORCE_USB)   += iforce-usb.o
+obj-$(CONFIG_JOYSTICK_IFORCE_232)      += iforce-serio.o
+obj-$(CONFIG_JOYSTICK_IFORCE_USB)      += iforce-usb.o
index 2ed7da7..4cadebd 100644 (file)
@@ -372,12 +372,12 @@ int iforce_upload_periodic(struct iforce *iforce, struct ff_effect *effect, stru
        }
 
        switch (effect->u.periodic.waveform) {
-               case FF_SQUARE:         wave_code = 0x20; break;
-               case FF_TRIANGLE:       wave_code = 0x21; break;
-               case FF_SINE:           wave_code = 0x22; break;
-               case FF_SAW_UP:         wave_code = 0x23; break;
-               case FF_SAW_DOWN:       wave_code = 0x24; break;
-               default:                wave_code = 0x20; break;
+       case FF_SQUARE:         wave_code = 0x20; break;
+       case FF_TRIANGLE:       wave_code = 0x21; break;
+       case FF_SINE:           wave_code = 0x22; break;
+       case FF_SAW_UP:         wave_code = 0x23; break;
+       case FF_SAW_DOWN:       wave_code = 0x24; break;
+       default:                wave_code = 0x20; break;
        }
 
        if (!old || need_core(old, effect)) {
@@ -476,9 +476,9 @@ int iforce_upload_condition(struct iforce *iforce, struct ff_effect *effect, str
        int core_err = 0;
 
        switch (effect->type) {
-               case FF_SPRING: type = 0x40; break;
-               case FF_DAMPER: type = 0x41; break;
-               default: return -1;
+       case FF_SPRING: type = 0x40; break;
+       case FF_DAMPER: type = 0x41; break;
+       default: return -1;
        }
 
        if (!old || need_condition_modifier(iforce, old, effect)) {
index 55f5b7b..9a5f90d 100644 (file)
@@ -9,10 +9,11 @@
 /*
  */
 
+#include <asm/unaligned.h>
 #include "iforce.h"
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>");
-MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");
+MODULE_DESCRIPTION("Core I-Force joysticks and wheels driver");
 MODULE_LICENSE("GPL");
 
 static signed short btn_joystick[] =
@@ -55,6 +56,7 @@ static struct iforce_device iforce_device[] = {
        { 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel",   btn_wheel, abs_wheel, ff_iforce }, //?
        { 0x061c, 0xc0a4, "ACT LABS Force RS",                          btn_wheel, abs_wheel, ff_iforce }, //?
        { 0x061c, 0xc084, "ACT LABS Force RS",                          btn_wheel, abs_wheel, ff_iforce },
+       { 0x06a3, 0xff04, "Saitek R440 Force Wheel",                    btn_wheel, abs_wheel, ff_iforce }, //?
        { 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback",       btn_wheel, abs_wheel, ff_iforce }, //?
        { 0x06f8, 0x0001, "Guillemot Jet Leader Force Feedback",        btn_joystick, abs_joystick_rudder, ff_iforce },
        { 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel",      btn_wheel, abs_wheel, ff_iforce }, //?
@@ -120,22 +122,21 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect,
  * Upload the effect
  */
        switch (effect->type) {
+       case FF_PERIODIC:
+               ret = iforce_upload_periodic(iforce, effect, old);
+               break;
 
-               case FF_PERIODIC:
-                       ret = iforce_upload_periodic(iforce, effect, old);
-                       break;
-
-               case FF_CONSTANT:
-                       ret = iforce_upload_constant(iforce, effect, old);
-                       break;
+       case FF_CONSTANT:
+               ret = iforce_upload_constant(iforce, effect, old);
+               break;
 
-               case FF_SPRING:
-               case FF_DAMPER:
-                       ret = iforce_upload_condition(iforce, effect, old);
-                       break;
+       case FF_SPRING:
+       case FF_DAMPER:
+               ret = iforce_upload_condition(iforce, effect, old);
+               break;
 
-               default:
-                       return -EINVAL;
+       default:
+               return -EINVAL;
        }
 
        if (ret == 0) {
@@ -173,15 +174,7 @@ static int iforce_open(struct input_dev *dev)
 {
        struct iforce *iforce = input_get_drvdata(dev);
 
-       switch (iforce->bus) {
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
-               case IFORCE_USB:
-                       iforce->irq->dev = iforce->usbdev;
-                       if (usb_submit_urb(iforce->irq, GFP_KERNEL))
-                               return -EIO;
-                       break;
-#endif
-       }
+       iforce->xport_ops->start_io(iforce);
 
        if (test_bit(EV_FF, dev->evbit)) {
                /* Enable force feedback */
@@ -214,27 +207,17 @@ static void iforce_close(struct input_dev *dev)
                        !test_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags));
        }
 
-       switch (iforce->bus) {
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
-       case IFORCE_USB:
-               usb_kill_urb(iforce->irq);
-               usb_kill_urb(iforce->out);
-               usb_kill_urb(iforce->ctrl);
-               break;
-#endif
-#ifdef CONFIG_JOYSTICK_IFORCE_232
-       case IFORCE_232:
-               //TODO: Wait for the last packets to be sent
-               break;
-#endif
-       }
+       iforce->xport_ops->stop_io(iforce);
 }
 
-int iforce_init_device(struct iforce *iforce)
+int iforce_init_device(struct device *parent, u16 bustype,
+                      struct iforce *iforce)
 {
        struct input_dev *input_dev;
        struct ff_device *ff;
-       unsigned char c[] = "CEOV";
+       u8 c[] = "CEOV";
+       u8 buf[IFORCE_MAX_LENGTH];
+       size_t len;
        int i, error;
        int ff_effects = 0;
 
@@ -252,20 +235,8 @@ int iforce_init_device(struct iforce *iforce)
  * Input device fields.
  */
 
-       switch (iforce->bus) {
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
-       case IFORCE_USB:
-               input_dev->id.bustype = BUS_USB;
-               input_dev->dev.parent = &iforce->usbdev->dev;
-               break;
-#endif
-#ifdef CONFIG_JOYSTICK_IFORCE_232
-       case IFORCE_232:
-               input_dev->id.bustype = BUS_RS232;
-               input_dev->dev.parent = &iforce->serio->dev;
-               break;
-#endif
-       }
+       input_dev->id.bustype = bustype;
+       input_dev->dev.parent = parent;
 
        input_set_drvdata(input_dev, iforce);
 
@@ -290,7 +261,7 @@ int iforce_init_device(struct iforce *iforce)
  */
 
        for (i = 0; i < 20; i++)
-               if (!iforce_get_id_packet(iforce, "O"))
+               if (!iforce_get_id_packet(iforce, 'O', buf, &len))
                        break;
 
        if (i == 20) { /* 5 seconds */
@@ -304,23 +275,23 @@ int iforce_init_device(struct iforce *iforce)
  * Get device info.
  */
 
-       if (!iforce_get_id_packet(iforce, "M"))
-               input_dev->id.vendor = (iforce->edata[2] << 8) | iforce->edata[1];
+       if (!iforce_get_id_packet(iforce, 'M', buf, &len) || len < 3)
+               input_dev->id.vendor = get_unaligned_le16(buf + 1);
        else
                dev_warn(&iforce->dev->dev, "Device does not respond to id packet M\n");
 
-       if (!iforce_get_id_packet(iforce, "P"))
-               input_dev->id.product = (iforce->edata[2] << 8) | iforce->edata[1];
+       if (!iforce_get_id_packet(iforce, 'P', buf, &len) || len < 3)
+               input_dev->id.product = get_unaligned_le16(buf + 1);
        else
                dev_warn(&iforce->dev->dev, "Device does not respond to id packet P\n");
 
-       if (!iforce_get_id_packet(iforce, "B"))
-               iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1];
+       if (!iforce_get_id_packet(iforce, 'B', buf, &len) || len < 3)
+               iforce->device_memory.end = get_unaligned_le16(buf + 1);
        else
                dev_warn(&iforce->dev->dev, "Device does not respond to id packet B\n");
 
-       if (!iforce_get_id_packet(iforce, "N"))
-               ff_effects = iforce->edata[1];
+       if (!iforce_get_id_packet(iforce, 'N', buf, &len) || len < 2)
+               ff_effects = buf[1];
        else
                dev_warn(&iforce->dev->dev, "Device does not respond to id packet N\n");
 
@@ -336,8 +307,9 @@ int iforce_init_device(struct iforce *iforce)
  */
 
        for (i = 0; c[i]; i++)
-               if (!iforce_get_id_packet(iforce, c + i))
-                       iforce_dump_packet(iforce, "info", iforce->ecmd, iforce->edata);
+               if (!iforce_get_id_packet(iforce, c[i], buf, &len))
+                       iforce_dump_packet(iforce, "info",
+                                          (FF_CMD_QUERY & 0xff00) | len, buf);
 
 /*
  * Disable spring, enable force feedback.
@@ -371,34 +343,29 @@ int iforce_init_device(struct iforce *iforce)
                signed short t = iforce->type->abs[i];
 
                switch (t) {
+               case ABS_X:
+               case ABS_Y:
+               case ABS_WHEEL:
+                       input_set_abs_params(input_dev, t, -1920, 1920, 16, 128);
+                       set_bit(t, input_dev->ffbit);
+                       break;
 
-                       case ABS_X:
-                       case ABS_Y:
-                       case ABS_WHEEL:
-
-                               input_set_abs_params(input_dev, t, -1920, 1920, 16, 128);
-                               set_bit(t, input_dev->ffbit);
-                               break;
-
-                       case ABS_THROTTLE:
-                       case ABS_GAS:
-                       case ABS_BRAKE:
-
-                               input_set_abs_params(input_dev, t, 0, 255, 0, 0);
-                               break;
-
-                       case ABS_RUDDER:
-
-                               input_set_abs_params(input_dev, t, -128, 127, 0, 0);
-                               break;
+               case ABS_THROTTLE:
+               case ABS_GAS:
+               case ABS_BRAKE:
+                       input_set_abs_params(input_dev, t, 0, 255, 0, 0);
+                       break;
 
-                       case ABS_HAT0X:
-                       case ABS_HAT0Y:
-                       case ABS_HAT1X:
-                       case ABS_HAT1Y:
+               case ABS_RUDDER:
+                       input_set_abs_params(input_dev, t, -128, 127, 0, 0);
+                       break;
 
-                               input_set_abs_params(input_dev, t, -1, 1, 0, 0);
-                               break;
+               case ABS_HAT0X:
+               case ABS_HAT0Y:
+               case ABS_HAT1X:
+               case ABS_HAT1Y:
+                       input_set_abs_params(input_dev, t, -1, 1, 0, 0);
+                       break;
                }
        }
 
@@ -431,35 +398,4 @@ int iforce_init_device(struct iforce *iforce)
  fail: input_free_device(input_dev);
        return error;
 }
-
-static int __init iforce_init(void)
-{
-       int err = 0;
-
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
-       err = usb_register(&iforce_usb_driver);
-       if (err)
-               return err;
-#endif
-#ifdef CONFIG_JOYSTICK_IFORCE_232
-       err = serio_register_driver(&iforce_serio_drv);
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
-       if (err)
-               usb_deregister(&iforce_usb_driver);
-#endif
-#endif
-       return err;
-}
-
-static void __exit iforce_exit(void)
-{
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
-       usb_deregister(&iforce_usb_driver);
-#endif
-#ifdef CONFIG_JOYSTICK_IFORCE_232
-       serio_unregister_driver(&iforce_serio_drv);
-#endif
-}
-
-module_init(iforce_init);
-module_exit(iforce_exit);
+EXPORT_SYMBOL(iforce_init_device);
index 42cd973..b313e38 100644 (file)
@@ -9,6 +9,7 @@
 /*
  */
 
+#include <asm/unaligned.h>
 #include "iforce.h"
 
 static struct {
@@ -79,27 +80,12 @@ int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data)
 /*
  * If necessary, start the transmission
  */
-       switch (iforce->bus) {
+       if (empty)
+               iforce->xport_ops->xmit(iforce);
 
-#ifdef CONFIG_JOYSTICK_IFORCE_232
-               case IFORCE_232:
-               if (empty)
-                       iforce_serial_xmit(iforce);
-               break;
-#endif
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
-               case IFORCE_USB:
-
-               if (iforce->usbdev && empty &&
-                       !test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) {
-
-                       iforce_usb_xmit(iforce);
-               }
-               break;
-#endif
-       }
        return 0;
 }
+EXPORT_SYMBOL(iforce_send_packet);
 
 /* Start or stop an effect */
 int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value)
@@ -133,157 +119,96 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr)
        return -1;
 }
 
-void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
+static void iforce_report_hats_buttons(struct iforce *iforce, u8 *data)
 {
        struct input_dev *dev = iforce->dev;
        int i;
-       static int being_used = 0;
 
-       if (being_used)
-               dev_warn(&iforce->dev->dev,
-                        "re-entrant call to iforce_process %d\n", being_used);
-       being_used++;
-
-#ifdef CONFIG_JOYSTICK_IFORCE_232
-       if (HI(iforce->expect_packet) == HI(cmd)) {
-               iforce->expect_packet = 0;
-               iforce->ecmd = cmd;
-               memcpy(iforce->edata, data, IFORCE_MAX_LENGTH);
-       }
-#endif
-       wake_up(&iforce->wait);
+       input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x);
+       input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y);
 
-       if (!iforce->type) {
-               being_used--;
-               return;
-       }
-
-       switch (HI(cmd)) {
-
-               case 0x01:      /* joystick position data */
-               case 0x03:      /* wheel position data */
-                       if (HI(cmd) == 1) {
-                               input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0]));
-                               input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2]));
-                               input_report_abs(dev, ABS_THROTTLE, 255 - data[4]);
-                               if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit))
-                                       input_report_abs(dev, ABS_RUDDER, (__s8)data[7]);
-                       } else {
-                               input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0]));
-                               input_report_abs(dev, ABS_GAS,   255 - data[2]);
-                               input_report_abs(dev, ABS_BRAKE, 255 - data[3]);
-                       }
+       for (i = 0; iforce->type->btn[i] >= 0; i++)
+               input_report_key(dev, iforce->type->btn[i],
+                                data[(i >> 3) + 5] & (1 << (i & 7)));
 
-                       input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x);
-                       input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y);
-
-                       for (i = 0; iforce->type->btn[i] >= 0; i++)
-                               input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7)));
-
-                       /* If there are untouched bits left, interpret them as the second hat */
-                       if (i <= 8) {
-                               int btns = data[6];
-                               if (test_bit(ABS_HAT1X, dev->absbit)) {
-                                       if (btns & 8) input_report_abs(dev, ABS_HAT1X, -1);
-                                       else if (btns & 2) input_report_abs(dev, ABS_HAT1X, 1);
-                                       else input_report_abs(dev, ABS_HAT1X, 0);
-                               }
-                               if (test_bit(ABS_HAT1Y, dev->absbit)) {
-                                       if (btns & 1) input_report_abs(dev, ABS_HAT1Y, -1);
-                                       else if (btns & 4) input_report_abs(dev, ABS_HAT1Y, 1);
-                                       else input_report_abs(dev, ABS_HAT1Y, 0);
-                               }
-                       }
+       /* If there are untouched bits left, interpret them as the second hat */
+       if (i <= 8) {
+               u8 btns = data[6];
 
-                       input_sync(dev);
-
-                       break;
-
-               case 0x02:      /* status report */
-                       input_report_key(dev, BTN_DEAD, data[0] & 0x02);
-                       input_sync(dev);
+               if (test_bit(ABS_HAT1X, dev->absbit)) {
+                       if (btns & BIT(3))
+                               input_report_abs(dev, ABS_HAT1X, -1);
+                       else if (btns & BIT(1))
+                               input_report_abs(dev, ABS_HAT1X, 1);
+                       else
+                               input_report_abs(dev, ABS_HAT1X, 0);
+               }
 
-                       /* Check if an effect was just started or stopped */
-                       i = data[1] & 0x7f;
-                       if (data[1] & 0x80) {
-                               if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
-                                       /* Report play event */
-                                       input_report_ff_status(dev, i, FF_STATUS_PLAYING);
-                               }
-                       } else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
-                               /* Report stop event */
-                               input_report_ff_status(dev, i, FF_STATUS_STOPPED);
-                       }
-                       if (LO(cmd) > 3) {
-                               int j;
-                               for (j = 3; j < LO(cmd); j += 2)
-                                       mark_core_as_ready(iforce, data[j] | (data[j+1]<<8));
-                       }
-                       break;
+               if (test_bit(ABS_HAT1Y, dev->absbit)) {
+                       if (btns & BIT(0))
+                               input_report_abs(dev, ABS_HAT1Y, -1);
+                       else if (btns & BIT(2))
+                               input_report_abs(dev, ABS_HAT1Y, 1);
+                       else
+                               input_report_abs(dev, ABS_HAT1Y, 0);
+               }
        }
-       being_used--;
 }
 
-int iforce_get_id_packet(struct iforce *iforce, char *packet)
+void iforce_process_packet(struct iforce *iforce,
+                          u8 packet_id, u8 *data, size_t len)
 {
-       switch (iforce->bus) {
+       struct input_dev *dev = iforce->dev;
+       int i, j;
 
-       case IFORCE_USB: {
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
-               int status;
+       switch (packet_id) {
 
-               iforce->cr.bRequest = packet[0];
-               iforce->ctrl->dev = iforce->usbdev;
+       case 0x01:      /* joystick position data */
+               input_report_abs(dev, ABS_X,
+                                (__s16) get_unaligned_le16(data));
+               input_report_abs(dev, ABS_Y,
+                                (__s16) get_unaligned_le16(data + 2));
+               input_report_abs(dev, ABS_THROTTLE, 255 - data[4]);
 
-               status = usb_submit_urb(iforce->ctrl, GFP_KERNEL);
-               if (status) {
-                       dev_err(&iforce->intf->dev,
-                               "usb_submit_urb failed %d\n", status);
-                       return -1;
-               }
+               if (len >= 8 && test_bit(ABS_RUDDER ,dev->absbit))
+                       input_report_abs(dev, ABS_RUDDER, (__s8)data[7]);
 
-               wait_event_interruptible_timeout(iforce->wait,
-                       iforce->ctrl->status != -EINPROGRESS, HZ);
+               iforce_report_hats_buttons(iforce, data);
 
-               if (iforce->ctrl->status) {
-                       dev_dbg(&iforce->intf->dev,
-                               "iforce->ctrl->status = %d\n",
-                               iforce->ctrl->status);
-                       usb_unlink_urb(iforce->ctrl);
-                       return -1;
-               }
-#else
-               printk(KERN_DEBUG "iforce_get_id_packet: iforce->bus = USB!\n");
-#endif
-               }
+               input_sync(dev);
                break;
 
-       case IFORCE_232:
+       case 0x03:      /* wheel position data */
+               input_report_abs(dev, ABS_WHEEL,
+                                (__s16) get_unaligned_le16(data));
+               input_report_abs(dev, ABS_GAS,   255 - data[2]);
+               input_report_abs(dev, ABS_BRAKE, 255 - data[3]);
 
-#ifdef CONFIG_JOYSTICK_IFORCE_232
-               iforce->expect_packet = FF_CMD_QUERY;
-               iforce_send_packet(iforce, FF_CMD_QUERY, packet);
+               iforce_report_hats_buttons(iforce, data);
 
-               wait_event_interruptible_timeout(iforce->wait,
-                       !iforce->expect_packet, HZ);
+               input_sync(dev);
+               break;
+
+       case 0x02:      /* status report */
+               input_report_key(dev, BTN_DEAD, data[0] & 0x02);
+               input_sync(dev);
 
-               if (iforce->expect_packet) {
-                       iforce->expect_packet = 0;
-                       return -1;
+               /* Check if an effect was just started or stopped */
+               i = data[1] & 0x7f;
+               if (data[1] & 0x80) {
+                       if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
+                               /* Report play event */
+                               input_report_ff_status(dev, i, FF_STATUS_PLAYING);
+                       }
+               } else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
+                       /* Report stop event */
+                       input_report_ff_status(dev, i, FF_STATUS_STOPPED);
                }
-#else
-               dev_err(&iforce->dev->dev,
-                       "iforce_get_id_packet: iforce->bus = SERIO!\n");
-#endif
-               break;
 
-       default:
-               dev_err(&iforce->dev->dev,
-                       "iforce_get_id_packet: iforce->bus = %d\n",
-                       iforce->bus);
+               for (j = 3; j < len; j += 2)
+                       mark_core_as_ready(iforce, get_unaligned_le16(data + j));
+
                break;
        }
-
-       return -(iforce->edata[0] != packet[0]);
 }
-
+EXPORT_SYMBOL(iforce_process_packet);
index 65a4fe2..bbe31e0 100644 (file)
@@ -9,10 +9,26 @@
 /*
  */
 
+#include <linux/serio.h>
 #include "iforce.h"
 
-void iforce_serial_xmit(struct iforce *iforce)
+struct iforce_serio {
+       struct iforce iforce;
+
+       struct serio *serio;
+       int idx, pkt, len, id;
+       u8 csum;
+       u8 expect_packet;
+       u8 cmd_response[IFORCE_MAX_LENGTH];
+       u8 cmd_response_len;
+       u8 data_in[IFORCE_MAX_LENGTH];
+};
+
+static void iforce_serio_xmit(struct iforce *iforce)
 {
+       struct iforce_serio *iforce_serio = container_of(iforce,
+                                                        struct iforce_serio,
+                                                        iforce);
        unsigned char cs;
        int i;
        unsigned long flags;
@@ -33,19 +49,20 @@ again:
 
        cs = 0x2b;
 
-       serio_write(iforce->serio, 0x2b);
+       serio_write(iforce_serio->serio, 0x2b);
 
-       serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]);
+       serio_write(iforce_serio->serio, iforce->xmit.buf[iforce->xmit.tail]);
        cs ^= iforce->xmit.buf[iforce->xmit.tail];
        XMIT_INC(iforce->xmit.tail, 1);
 
        for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) {
-               serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]);
+               serio_write(iforce_serio->serio,
+                           iforce->xmit.buf[iforce->xmit.tail]);
                cs ^= iforce->xmit.buf[iforce->xmit.tail];
                XMIT_INC(iforce->xmit.tail, 1);
        }
 
-       serio_write(iforce->serio, cs);
+       serio_write(iforce_serio->serio, cs);
 
        if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags))
                goto again;
@@ -55,54 +72,118 @@ again:
        spin_unlock_irqrestore(&iforce->xmit_lock, flags);
 }
 
+static int iforce_serio_get_id(struct iforce *iforce, u8 id,
+                              u8 *response_data, size_t *response_len)
+{
+       struct iforce_serio *iforce_serio = container_of(iforce,
+                                                        struct iforce_serio,
+                                                        iforce);
+
+       iforce_serio->expect_packet = HI(FF_CMD_QUERY);
+       iforce_serio->cmd_response_len = 0;
+
+       iforce_send_packet(iforce, FF_CMD_QUERY, &id);
+
+       wait_event_interruptible_timeout(iforce->wait,
+                                        !iforce_serio->expect_packet, HZ);
+
+       if (iforce_serio->expect_packet) {
+               iforce_serio->expect_packet = 0;
+               return -ETIMEDOUT;
+       }
+
+       if (iforce_serio->cmd_response[0] != id)
+               return -EIO;
+
+       memcpy(response_data, iforce_serio->cmd_response,
+              iforce_serio->cmd_response_len);
+       *response_len = iforce_serio->cmd_response_len;
+
+       return 0;
+}
+
+static int iforce_serio_start_io(struct iforce *iforce)
+{
+       /* No special handling required */
+       return 0;
+}
+
+static void iforce_serio_stop_io(struct iforce *iforce)
+{
+       //TODO: Wait for the last packets to be sent
+}
+
+static const struct iforce_xport_ops iforce_serio_xport_ops = {
+       .xmit           = iforce_serio_xmit,
+       .get_id         = iforce_serio_get_id,
+       .start_io       = iforce_serio_start_io,
+       .stop_io        = iforce_serio_stop_io,
+};
+
 static void iforce_serio_write_wakeup(struct serio *serio)
 {
        struct iforce *iforce = serio_get_drvdata(serio);
 
-       iforce_serial_xmit(iforce);
+       iforce_serio_xmit(iforce);
 }
 
 static irqreturn_t iforce_serio_irq(struct serio *serio,
-               unsigned char data, unsigned int flags)
+                                   unsigned char data, unsigned int flags)
 {
-       struct iforce *iforce = serio_get_drvdata(serio);
+       struct iforce_serio *iforce_serio = serio_get_drvdata(serio);
+       struct iforce *iforce = &iforce_serio->iforce;
 
-       if (!iforce->pkt) {
+       if (!iforce_serio->pkt) {
                if (data == 0x2b)
-                       iforce->pkt = 1;
+                       iforce_serio->pkt = 1;
                goto out;
        }
 
-       if (!iforce->id) {
+       if (!iforce_serio->id) {
                if (data > 3 && data != 0xff)
-                       iforce->pkt = 0;
+                       iforce_serio->pkt = 0;
                else
-                       iforce->id = data;
+                       iforce_serio->id = data;
                goto out;
        }
 
-       if (!iforce->len) {
+       if (!iforce_serio->len) {
                if (data > IFORCE_MAX_LENGTH) {
-                       iforce->pkt = 0;
-                       iforce->id = 0;
+                       iforce_serio->pkt = 0;
+                       iforce_serio->id = 0;
                } else {
-                       iforce->len = data;
+                       iforce_serio->len = data;
                }
                goto out;
        }
 
-       if (iforce->idx < iforce->len) {
-               iforce->csum += iforce->data[iforce->idx++] = data;
+       if (iforce_serio->idx < iforce_serio->len) {
+               iforce_serio->data_in[iforce_serio->idx++] = data;
+               iforce_serio->csum += data;
                goto out;
        }
 
-       if (iforce->idx == iforce->len) {
-               iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data);
-               iforce->pkt = 0;
-               iforce->id  = 0;
-               iforce->len = 0;
-               iforce->idx = 0;
-               iforce->csum = 0;
+       if (iforce_serio->idx == iforce_serio->len) {
+               /* Handle command completion */
+               if (iforce_serio->expect_packet == iforce_serio->id) {
+                       iforce_serio->expect_packet = 0;
+                       memcpy(iforce_serio->cmd_response,
+                              iforce_serio->data_in, IFORCE_MAX_LENGTH);
+                       iforce_serio->cmd_response_len = iforce_serio->len;
+
+                       /* Signal that command is done */
+                       wake_up(&iforce->wait);
+               } else if (likely(iforce->type)) {
+                       iforce_process_packet(iforce, iforce_serio->id,
+                                             iforce_serio->data_in,
+                                             iforce_serio->len);
+               }
+
+               iforce_serio->pkt = 0;
+               iforce_serio->id  = 0;
+               iforce_serio->len = 0;
+               iforce_serio->idx = 0;
+               iforce_serio->csum = 0;
        }
 out:
        return IRQ_HANDLED;
@@ -110,23 +191,23 @@ out:
 
 static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv)
 {
-       struct iforce *iforce;
+       struct iforce_serio *iforce_serio;
        int err;
 
-       iforce = kzalloc(sizeof(struct iforce), GFP_KERNEL);
-       if (!iforce)
+       iforce_serio = kzalloc(sizeof(*iforce_serio), GFP_KERNEL);
+       if (!iforce_serio)
                return -ENOMEM;
 
-       iforce->bus = IFORCE_232;
-       iforce->serio = serio;
+       iforce_serio->iforce.xport_ops = &iforce_serio_xport_ops;
 
-       serio_set_drvdata(serio, iforce);
+       iforce_serio->serio = serio;
+       serio_set_drvdata(serio, iforce_serio);
 
        err = serio_open(serio, drv);
        if (err)
                goto fail1;
 
-       err = iforce_init_device(iforce);
+       err = iforce_init_device(&serio->dev, BUS_RS232, &iforce_serio->iforce);
        if (err)
                goto fail2;
 
@@ -134,18 +215,18 @@ static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv)
 
  fail2:        serio_close(serio);
  fail1:        serio_set_drvdata(serio, NULL);
-       kfree(iforce);
+       kfree(iforce_serio);
        return err;
 }
 
 static void iforce_serio_disconnect(struct serio *serio)
 {
-       struct iforce *iforce = serio_get_drvdata(serio);
+       struct iforce_serio *iforce_serio = serio_get_drvdata(serio);
 
-       input_unregister_device(iforce->dev);
+       input_unregister_device(iforce_serio->iforce.dev);
        serio_close(serio);
        serio_set_drvdata(serio, NULL);
-       kfree(iforce);
+       kfree(iforce_serio);
 }
 
 static const struct serio_device_id iforce_serio_ids[] = {
@@ -171,3 +252,9 @@ struct serio_driver iforce_serio_drv = {
        .connect        = iforce_serio_connect,
        .disconnect     = iforce_serio_disconnect,
 };
+
+module_serio_driver(iforce_serio_drv);
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>");
+MODULE_DESCRIPTION("RS232 I-Force joysticks and wheels driver");
+MODULE_LICENSE("GPL");
index f1569ae..ade376b 100644 (file)
@@ -9,10 +9,24 @@
 /*
  */
 
+#include <linux/usb.h>
 #include "iforce.h"
 
-void iforce_usb_xmit(struct iforce *iforce)
+struct iforce_usb {
+       struct iforce iforce;
+
+       struct usb_device *usbdev;
+       struct usb_interface *intf;
+       struct urb *irq, *out;
+
+       u8 data_in[IFORCE_MAX_LENGTH] ____cacheline_aligned;
+       u8 data_out[IFORCE_MAX_LENGTH] ____cacheline_aligned;
+};
+
+static void __iforce_usb_xmit(struct iforce *iforce)
 {
+       struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb,
+                                                    iforce);
        int n, c;
        unsigned long flags;
 
@@ -24,31 +38,32 @@ void iforce_usb_xmit(struct iforce *iforce)
                return;
        }
 
-       ((char *)iforce->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail];
+       ((char *)iforce_usb->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail];
        XMIT_INC(iforce->xmit.tail, 1);
        n = iforce->xmit.buf[iforce->xmit.tail];
        XMIT_INC(iforce->xmit.tail, 1);
 
-       iforce->out->transfer_buffer_length = n + 1;
-       iforce->out->dev = iforce->usbdev;
+       iforce_usb->out->transfer_buffer_length = n + 1;
+       iforce_usb->out->dev = iforce_usb->usbdev;
 
        /* Copy rest of data then */
        c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE);
        if (n < c) c=n;
 
-       memcpy(iforce->out->transfer_buffer + 1,
+       memcpy(iforce_usb->out->transfer_buffer + 1,
               &iforce->xmit.buf[iforce->xmit.tail],
               c);
        if (n != c) {
-               memcpy(iforce->out->transfer_buffer + 1 + c,
+               memcpy(iforce_usb->out->transfer_buffer + 1 + c,
                       &iforce->xmit.buf[0],
                       n-c);
        }
        XMIT_INC(iforce->xmit.tail, n);
 
-       if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) {
+       if ( (n=usb_submit_urb(iforce_usb->out, GFP_ATOMIC)) ) {
                clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
-               dev_warn(&iforce->intf->dev, "usb_submit_urb failed %d\n", n);
+               dev_warn(&iforce_usb->intf->dev,
+                        "usb_submit_urb failed %d\n", n);
        }
 
        /* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
@@ -57,10 +72,77 @@ void iforce_usb_xmit(struct iforce *iforce)
        spin_unlock_irqrestore(&iforce->xmit_lock, flags);
 }
 
+static void iforce_usb_xmit(struct iforce *iforce)
+{
+       if (!test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags))
+               __iforce_usb_xmit(iforce);
+}
+
+static int iforce_usb_get_id(struct iforce *iforce, u8 id,
+                            u8 *response_data, size_t *response_len)
+{
+       struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb,
+                                                    iforce);
+       u8 *buf;
+       int status;
+
+       buf = kmalloc(IFORCE_MAX_LENGTH, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       status = usb_control_msg(iforce_usb->usbdev,
+                                usb_rcvctrlpipe(iforce_usb->usbdev, 0),
+                                id,
+                                USB_TYPE_VENDOR | USB_DIR_IN |
+                                       USB_RECIP_INTERFACE,
+                                0, 0, buf, IFORCE_MAX_LENGTH, HZ);
+       if (status < 0) {
+               dev_err(&iforce_usb->intf->dev,
+                       "usb_submit_urb failed: %d\n", status);
+       } else if (buf[0] != id) {
+               status = -EIO;
+       } else {
+               memcpy(response_data, buf, status);
+               *response_len = status;
+               status = 0;
+       }
+
+       kfree(buf);
+       return status;
+}
+
+static int iforce_usb_start_io(struct iforce *iforce)
+{
+       struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb,
+                                                    iforce);
+
+       if (usb_submit_urb(iforce_usb->irq, GFP_KERNEL))
+               return -EIO;
+
+       return 0;
+}
+
+static void iforce_usb_stop_io(struct iforce *iforce)
+{
+       struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb,
+                                                    iforce);
+
+       usb_kill_urb(iforce_usb->irq);
+       usb_kill_urb(iforce_usb->out);
+}
+
+static const struct iforce_xport_ops iforce_usb_xport_ops = {
+       .xmit           = iforce_usb_xmit,
+       .get_id         = iforce_usb_get_id,
+       .start_io       = iforce_usb_start_io,
+       .stop_io        = iforce_usb_stop_io,
+};
+
 static void iforce_usb_irq(struct urb *urb)
 {
-       struct iforce *iforce = urb->context;
-       struct device *dev = &iforce->intf->dev;
+       struct iforce_usb *iforce_usb = urb->context;
+       struct iforce *iforce = &iforce_usb->iforce;
+       struct device *dev = &iforce_usb->intf->dev;
        int status;
 
        switch (urb->status) {
@@ -80,11 +162,11 @@ static void iforce_usb_irq(struct urb *urb)
                goto exit;
        }
 
-       iforce_process_packet(iforce,
-               (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1);
+       iforce_process_packet(iforce, iforce_usb->data_in[0],
+                             iforce_usb->data_in + 1, urb->actual_length - 1);
 
 exit:
-       status = usb_submit_urb (urb, GFP_ATOMIC);
+       status = usb_submit_urb(urb, GFP_ATOMIC);
        if (status)
                dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
                        __func__, status);
@@ -92,35 +174,28 @@ exit:
 
 static void iforce_usb_out(struct urb *urb)
 {
-       struct iforce *iforce = urb->context;
+       struct iforce_usb *iforce_usb = urb->context;
+       struct iforce *iforce = &iforce_usb->iforce;
 
        if (urb->status) {
                clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
-               dev_dbg(&iforce->intf->dev, "urb->status %d, exiting\n",
+               dev_dbg(&iforce_usb->intf->dev, "urb->status %d, exiting\n",
                        urb->status);
                return;
        }
 
-       iforce_usb_xmit(iforce);
+       __iforce_usb_xmit(iforce);
 
        wake_up(&iforce->wait);
 }
 
-static void iforce_usb_ctrl(struct urb *urb)
-{
-       struct iforce *iforce = urb->context;
-       if (urb->status) return;
-       iforce->ecmd = 0xff00 | urb->actual_length;
-       wake_up(&iforce->wait);
-}
-
 static int iforce_usb_probe(struct usb_interface *intf,
                                const struct usb_device_id *id)
 {
        struct usb_device *dev = interface_to_usbdev(intf);
        struct usb_host_interface *interface;
        struct usb_endpoint_descriptor *epirq, *epout;
-       struct iforce *iforce;
+       struct iforce_usb *iforce_usb;
        int err = -ENOMEM;
 
        interface = intf->cur_altsetting;
@@ -131,48 +206,45 @@ static int iforce_usb_probe(struct usb_interface *intf,
        epirq = &interface->endpoint[0].desc;
        epout = &interface->endpoint[1].desc;
 
-       if (!(iforce = kzalloc(sizeof(struct iforce) + 32, GFP_KERNEL)))
-               goto fail;
-
-       if (!(iforce->irq = usb_alloc_urb(0, GFP_KERNEL)))
+       iforce_usb = kzalloc(sizeof(*iforce_usb), GFP_KERNEL);
+       if (!iforce_usb)
                goto fail;
 
-       if (!(iforce->out = usb_alloc_urb(0, GFP_KERNEL)))
+       iforce_usb->irq = usb_alloc_urb(0, GFP_KERNEL);
+       if (!iforce_usb->irq)
                goto fail;
 
-       if (!(iforce->ctrl = usb_alloc_urb(0, GFP_KERNEL)))
+       iforce_usb->out = usb_alloc_urb(0, GFP_KERNEL);
+       if (!iforce_usb->out)
                goto fail;
 
-       iforce->bus = IFORCE_USB;
-       iforce->usbdev = dev;
-       iforce->intf = intf;
-
-       iforce->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE;
-       iforce->cr.wIndex = 0;
-       iforce->cr.wLength = cpu_to_le16(16);
+       iforce_usb->iforce.xport_ops = &iforce_usb_xport_ops;
 
-       usb_fill_int_urb(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
-                       iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval);
+       iforce_usb->usbdev = dev;
+       iforce_usb->intf = intf;
 
-       usb_fill_int_urb(iforce->out, dev, usb_sndintpipe(dev, epout->bEndpointAddress),
-                       iforce + 1, 32, iforce_usb_out, iforce, epout->bInterval);
+       usb_fill_int_urb(iforce_usb->irq, dev,
+                        usb_rcvintpipe(dev, epirq->bEndpointAddress),
+                        iforce_usb->data_in, sizeof(iforce_usb->data_in),
+                        iforce_usb_irq, iforce_usb, epirq->bInterval);
 
-       usb_fill_control_urb(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0),
-                       (void*) &iforce->cr, iforce->edata, 16, iforce_usb_ctrl, iforce);
+       usb_fill_int_urb(iforce_usb->out, dev,
+                        usb_sndintpipe(dev, epout->bEndpointAddress),
+                        iforce_usb->data_out, sizeof(iforce_usb->data_out),
+                        iforce_usb_out, iforce_usb, epout->bInterval);
 
-       err = iforce_init_device(iforce);
+       err = iforce_init_device(&intf->dev, BUS_USB, &iforce_usb->iforce);
        if (err)
                goto fail;
 
-       usb_set_intfdata(intf, iforce);
+       usb_set_intfdata(intf, iforce_usb);
        return 0;
 
 fail:
-       if (iforce) {
-               usb_free_urb(iforce->irq);
-               usb_free_urb(iforce->out);
-               usb_free_urb(iforce->ctrl);
-               kfree(iforce);
+       if (iforce_usb) {
+               usb_free_urb(iforce_usb->irq);
+               usb_free_urb(iforce_usb->out);
+               kfree(iforce_usb);
        }
 
        return err;
@@ -180,17 +252,16 @@ fail:
 
 static void iforce_usb_disconnect(struct usb_interface *intf)
 {
-       struct iforce *iforce = usb_get_intfdata(intf);
+       struct iforce_usb *iforce_usb = usb_get_intfdata(intf);
 
        usb_set_intfdata(intf, NULL);
 
-       input_unregister_device(iforce->dev);
+       input_unregister_device(iforce_usb->iforce.dev);
 
-       usb_free_urb(iforce->irq);
-       usb_free_urb(iforce->out);
-       usb_free_urb(iforce->ctrl);
+       usb_free_urb(iforce_usb->irq);
+       usb_free_urb(iforce_usb->out);
 
-       kfree(iforce);
+       kfree(iforce_usb);
 }
 
 static const struct usb_device_id iforce_usb_ids[] = {
@@ -202,6 +273,7 @@ static const struct usb_device_id iforce_usb_ids[] = {
        { USB_DEVICE(0x05ef, 0x8888) },         /* AVB Top Shot FFB Racing Wheel */
        { USB_DEVICE(0x061c, 0xc0a4) },         /* ACT LABS Force RS */
        { USB_DEVICE(0x061c, 0xc084) },         /* ACT LABS Force RS */
+       { USB_DEVICE(0x06a3, 0xff04) },         /* Saitek R440 Force Wheel */
        { USB_DEVICE(0x06f8, 0x0001) },         /* Guillemot Race Leader Force Feedback */
        { USB_DEVICE(0x06f8, 0x0003) },         /* Guillemot Jet Leader Force Feedback */
        { USB_DEVICE(0x06f8, 0x0004) },         /* Guillemot Force Feedback Racing Wheel */
@@ -217,3 +289,9 @@ struct usb_driver iforce_usb_driver = {
        .disconnect =   iforce_usb_disconnect,
        .id_table =     iforce_usb_ids,
 };
+
+module_usb_driver(iforce_usb_driver);
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>");
+MODULE_DESCRIPTION("USB I-Force joysticks and wheels driver");
+MODULE_LICENSE("GPL");
index f168170..9cfa460 100644 (file)
@@ -14,8 +14,6 @@
 #include <linux/input.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
-#include <linux/usb.h>
-#include <linux/serio.h>
 #include <linux/circ_buf.h>
 #include <linux/mutex.h>
 
 
 #define IFORCE_MAX_LENGTH      16
 
-/* iforce::bus */
-#define IFORCE_232     1
-#define IFORCE_USB     2
-
 #define IFORCE_EFFECTS_MAX     32
 
 /* Each force feedback effect is made of one core effect, which can be
@@ -81,27 +75,21 @@ struct iforce_device {
        signed short *ff;
 };
 
+struct iforce;
+
+struct iforce_xport_ops {
+       void (*xmit)(struct iforce *iforce);
+       int (*get_id)(struct iforce *iforce, u8 id,
+                     u8 *response_data, size_t *response_len);
+       int (*start_io)(struct iforce *iforce);
+       void (*stop_io)(struct iforce *iforce);
+};
+
 struct iforce {
        struct input_dev *dev;          /* Input device interface */
        struct iforce_device *type;
-       int bus;
-
-       unsigned char data[IFORCE_MAX_LENGTH];
-       unsigned char edata[IFORCE_MAX_LENGTH];
-       u16 ecmd;
-       u16 expect_packet;
-
-#ifdef CONFIG_JOYSTICK_IFORCE_232
-       struct serio *serio;            /* RS232 transfer */
-       int idx, pkt, len, id;
-       unsigned char csum;
-#endif
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
-       struct usb_device *usbdev;      /* USB transfer */
-       struct usb_interface *intf;
-       struct urb *irq, *out, *ctrl;
-       struct usb_ctrlrequest cr;
-#endif
+       const struct iforce_xport_ops *xport_ops;
+
        spinlock_t xmit_lock;
        /* Buffer used for asynchronous sending of bytes to the device */
        struct circ_buf xmit;
@@ -127,23 +115,24 @@ struct iforce {
 /* Encode a time value */
 #define TIME_SCALE(a)  (a)
 
+static inline int iforce_get_id_packet(struct iforce *iforce, u8 id,
+                                      u8 *response_data, size_t *response_len)
+{
+       return iforce->xport_ops->get_id(iforce, id,
+                                        response_data, response_len);
+}
 
 /* Public functions */
-/* iforce-serio.c */
-void iforce_serial_xmit(struct iforce *iforce);
-
-/* iforce-usb.c */
-void iforce_usb_xmit(struct iforce *iforce);
-
 /* iforce-main.c */
-int iforce_init_device(struct iforce *iforce);
+int iforce_init_device(struct device *parent, u16 bustype,
+                      struct iforce *iforce);
 
 /* iforce-packets.c */
 int iforce_control_playback(struct iforce*, u16 id, unsigned int);
-void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data);
+void iforce_process_packet(struct iforce *iforce,
+                          u8 packet_id, u8 *data, size_t len);
 int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data);
 void iforce_dump_packet(struct iforce *iforce, char *msg, u16 cmd, unsigned char *data);
-int iforce_get_id_packet(struct iforce *iforce, char *packet);
 
 /* iforce-ff.c */
 int iforce_upload_periodic(struct iforce *, struct ff_effect *, struct ff_effect *);
index d560011..38cb6d8 100644 (file)
@@ -237,7 +237,7 @@ static int cros_ec_keyb_work(struct notifier_block *nb,
        if (queued_during_suspend && !device_may_wakeup(ckdev->dev))
                return NOTIFY_OK;
 
-       switch (ckdev->ec->event_data.event_type) {
+       switch (ckdev->ec->event_data.event_type & EC_MKBP_EVENT_TYPE_MASK) {
        case EC_MKBP_EVENT_KEY_MATRIX:
                pm_wakeup_event(ckdev->dev, 0);
 
index a23c239..03f4d15 100644 (file)
@@ -771,7 +771,6 @@ static int gpio_keys_probe(struct platform_device *pdev)
        struct fwnode_handle *child = NULL;
        struct gpio_keys_drvdata *ddata;
        struct input_dev *input;
-       size_t size;
        int i, error;
        int wakeup = 0;
 
@@ -781,9 +780,8 @@ static int gpio_keys_probe(struct platform_device *pdev)
                        return PTR_ERR(pdata);
        }
 
-       size = sizeof(struct gpio_keys_drvdata) +
-                       pdata->nbuttons * sizeof(struct gpio_button_data);
-       ddata = devm_kzalloc(dev, size, GFP_KERNEL);
+       ddata = devm_kzalloc(dev, struct_size(ddata, data, pdata->nbuttons),
+                            GFP_KERNEL);
        if (!ddata) {
                dev_err(dev, "failed to allocate state\n");
                return -ENOMEM;
index 1eafe6b..465eecf 100644 (file)
@@ -165,6 +165,8 @@ gpio_keys_polled_get_devtree_pdata(struct device *dev)
        pdata->rep = device_property_present(dev, "autorepeat");
        device_property_read_u32(dev, "poll-interval", &pdata->poll_interval);
 
+       device_property_read_string(dev, "label", &pdata->name);
+
        device_for_each_child_node(dev, child) {
                if (fwnode_property_read_u32(child, "linux,code",
                                             &button->code)) {
@@ -232,7 +234,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
        struct gpio_keys_polled_dev *bdev;
        struct input_polled_dev *poll_dev;
        struct input_dev *input;
-       size_t size;
        int error;
        int i;
 
@@ -247,9 +248,8 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       size = sizeof(struct gpio_keys_polled_dev) +
-                       pdata->nbuttons * sizeof(struct gpio_keys_button_data);
-       bdev = devm_kzalloc(dev, size, GFP_KERNEL);
+       bdev = devm_kzalloc(dev, struct_size(bdev, data, pdata->nbuttons),
+                           GFP_KERNEL);
        if (!bdev) {
                dev_err(dev, "no memory for private data\n");
                return -ENOMEM;
@@ -269,7 +269,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
 
        input = poll_dev->input;
 
-       input->name = pdev->name;
+       input->name = pdata->name ?: pdev->name;
        input->phys = DRV_NAME"/input0";
 
        input->id.bustype = BUS_HOST;
index ae9c51c..97500a2 100644 (file)
@@ -422,7 +422,6 @@ static int imx_keypad_probe(struct platform_device *pdev)
                        dev_get_platdata(&pdev->dev);
        struct imx_keypad *keypad;
        struct input_dev *input_dev;
-       struct resource *res;
        int irq, error, i, row, col;
 
        if (!keymap_data && !pdev->dev.of_node) {
@@ -455,8 +454,7 @@ static int imx_keypad_probe(struct platform_device *pdev)
        timer_setup(&keypad->check_matrix_timer,
                    imx_keypad_check_for_events, 0);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       keypad->mmio_base = devm_ioremap_resource(&pdev->dev, res);
+       keypad->mmio_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(keypad->mmio_base))
                return PTR_ERR(keypad->mmio_base);
 
index 6da607d..3bbd7e6 100644 (file)
@@ -266,7 +266,7 @@ static int tca8418_keypad_probe(struct i2c_client *client,
        struct tca8418_keypad *keypad_data;
        struct input_dev *input;
        u32 rows = 0, cols = 0;
-       int error, row_shift, max_keys;
+       int error, row_shift;
        u8 reg;
 
        /* Check i2c driver capabilities */
@@ -291,7 +291,6 @@ static int tca8418_keypad_probe(struct i2c_client *client,
        }
 
        row_shift = get_count_order(cols);
-       max_keys = rows << row_shift;
 
        /* Allocate memory for keypad_data and input device */
        keypad_data = devm_kzalloc(dev, sizeof(*keypad_data), GFP_KERNEL);
index 9d39679..fd355cf 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/regmap.h>
 #include <linux/of.h>
 #include <linux/mfd/da9063/core.h>
-#include <linux/mfd/da9063/pdata.h>
 #include <linux/mfd/da9063/registers.h>
 #include <linux/mfd/da9062/core.h>
 #include <linux/mfd/da9062/registers.h>
@@ -192,8 +191,6 @@ static void da9063_cancel_poll(void *data)
 
 static int da9063_onkey_probe(struct platform_device *pdev)
 {
-       struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent);
-       struct da9063_pdata *pdata = dev_get_platdata(da9063->dev);
        struct da9063_onkey *onkey;
        const struct of_device_id *match;
        int irq;
@@ -220,12 +217,8 @@ static int da9063_onkey_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
-       if (pdata)
-               onkey->key_power = pdata->key_power;
-       else
-               onkey->key_power =
-                       !of_property_read_bool(pdev->dev.of_node,
-                                              "dlg,disable-key-power");
+       onkey->key_power = !of_property_read_bool(pdev->dev.of_node,
+                                                 "dlg,disable-key-power");
 
        onkey->input = devm_input_allocate_device(&pdev->dev);
        if (!onkey->input) {
index fbf6caa..4d875f2 100644 (file)
@@ -119,3 +119,4 @@ module_platform_driver(max77650_onkey_driver);
 MODULE_DESCRIPTION("MAXIM 77650/77651 ONKEY driver");
 MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:max77650-onkey");
index 420efaa..d9b103a 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/completion.h>
 #include <linux/of.h>
 #include <linux/property.h>
+#include <linux/input/elan-i2c-ids.h>
 #include <linux/regulator/consumer.h>
 #include <asm/unaligned.h>
 
@@ -96,6 +97,7 @@ struct elan_tp_data {
        u8                      max_baseline;
        bool                    baseline_ready;
        u8                      clickpad;
+       bool                    middle_button;
 };
 
 static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count,
@@ -363,27 +365,62 @@ static unsigned int elan_convert_resolution(u8 val)
 
 static int elan_query_device_parameters(struct elan_tp_data *data)
 {
+       struct i2c_client *client = data->client;
        unsigned int x_traces, y_traces;
+       u32 x_mm, y_mm;
        u8 hw_x_res, hw_y_res;
        int error;
 
-       error = data->ops->get_max(data->client, &data->max_x, &data->max_y);
-       if (error)
-               return error;
-
-       error = data->ops->get_num_traces(data->client, &x_traces, &y_traces);
-       if (error)
-               return error;
+       if (device_property_read_u32(&client->dev,
+                                    "touchscreen-size-x", &data->max_x) ||
+           device_property_read_u32(&client->dev,
+                                    "touchscreen-size-y", &data->max_y)) {
+               error = data->ops->get_max(data->client,
+                                          &data->max_x,
+                                          &data->max_y);
+               if (error)
+                       return error;
+       } else {
+               /* size is the maximum + 1 */
+               --data->max_x;
+               --data->max_y;
+       }
 
+       if (device_property_read_u32(&client->dev,
+                                    "elan,x_traces",
+                                    &x_traces) ||
+           device_property_read_u32(&client->dev,
+                                    "elan,y_traces",
+                                    &y_traces)) {
+               error = data->ops->get_num_traces(data->client,
+                                                 &x_traces, &y_traces);
+               if (error)
+                       return error;
+       }
        data->width_x = data->max_x / x_traces;
        data->width_y = data->max_y / y_traces;
 
-       error = data->ops->get_resolution(data->client, &hw_x_res, &hw_y_res);
-       if (error)
-               return error;
+       if (device_property_read_u32(&client->dev,
+                                    "touchscreen-x-mm", &x_mm) ||
+           device_property_read_u32(&client->dev,
+                                    "touchscreen-y-mm", &y_mm)) {
+               error = data->ops->get_resolution(data->client,
+                                                 &hw_x_res, &hw_y_res);
+               if (error)
+                       return error;
+
+               data->x_res = elan_convert_resolution(hw_x_res);
+               data->y_res = elan_convert_resolution(hw_y_res);
+       } else {
+               data->x_res = (data->max_x + 1) / x_mm;
+               data->y_res = (data->max_y + 1) / y_mm;
+       }
+
+       if (device_property_read_bool(&client->dev, "elan,clickpad"))
+               data->clickpad = 1;
 
-       data->x_res = elan_convert_resolution(hw_x_res);
-       data->y_res = elan_convert_resolution(hw_y_res);
+       if (device_property_read_bool(&client->dev, "elan,middle-button"))
+               data->middle_button = true;
 
        return 0;
 }
@@ -923,8 +960,9 @@ static void elan_report_absolute(struct elan_tp_data *data, u8 *packet)
                        finger_data += ETP_FINGER_DATA_LEN;
        }
 
-       input_report_key(input, BTN_LEFT, tp_info & 0x01);
-       input_report_key(input, BTN_RIGHT, tp_info & 0x02);
+       input_report_key(input, BTN_LEFT,   tp_info & BIT(0));
+       input_report_key(input, BTN_MIDDLE, tp_info & BIT(2));
+       input_report_key(input, BTN_RIGHT,  tp_info & BIT(1));
        input_report_abs(input, ABS_DISTANCE, hover_event != 0);
        input_mt_report_pointer_emulation(input, true);
        input_sync(input);
@@ -1058,10 +1096,13 @@ static int elan_setup_input_device(struct elan_tp_data *data)
 
        __set_bit(EV_ABS, input->evbit);
        __set_bit(INPUT_PROP_POINTER, input->propbit);
-       if (data->clickpad)
+       if (data->clickpad) {
                __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
-       else
+       } else {
                __set_bit(BTN_RIGHT, input->keybit);
+               if (data->middle_button)
+                       __set_bit(BTN_MIDDLE, input->keybit);
+       }
        __set_bit(BTN_LEFT, input->keybit);
 
        /* Set up ST parameters */
@@ -1332,55 +1373,6 @@ static const struct i2c_device_id elan_id[] = {
 MODULE_DEVICE_TABLE(i2c, elan_id);
 
 #ifdef CONFIG_ACPI
-static const struct acpi_device_id elan_acpi_id[] = {
-       { "ELAN0000", 0 },
-       { "ELAN0100", 0 },
-       { "ELAN0600", 0 },
-       { "ELAN0601", 0 },
-       { "ELAN0602", 0 },
-       { "ELAN0603", 0 },
-       { "ELAN0604", 0 },
-       { "ELAN0605", 0 },
-       { "ELAN0606", 0 },
-       { "ELAN0607", 0 },
-       { "ELAN0608", 0 },
-       { "ELAN0609", 0 },
-       { "ELAN060B", 0 },
-       { "ELAN060C", 0 },
-       { "ELAN060F", 0 },
-       { "ELAN0610", 0 },
-       { "ELAN0611", 0 },
-       { "ELAN0612", 0 },
-       { "ELAN0615", 0 },
-       { "ELAN0616", 0 },
-       { "ELAN0617", 0 },
-       { "ELAN0618", 0 },
-       { "ELAN0619", 0 },
-       { "ELAN061A", 0 },
-       { "ELAN061B", 0 },
-       { "ELAN061C", 0 },
-       { "ELAN061D", 0 },
-       { "ELAN061E", 0 },
-       { "ELAN061F", 0 },
-       { "ELAN0620", 0 },
-       { "ELAN0621", 0 },
-       { "ELAN0622", 0 },
-       { "ELAN0623", 0 },
-       { "ELAN0624", 0 },
-       { "ELAN0625", 0 },
-       { "ELAN0626", 0 },
-       { "ELAN0627", 0 },
-       { "ELAN0628", 0 },
-       { "ELAN0629", 0 },
-       { "ELAN062A", 0 },
-       { "ELAN062B", 0 },
-       { "ELAN062C", 0 },
-       { "ELAN062D", 0 },
-       { "ELAN0631", 0 },
-       { "ELAN0632", 0 },
-       { "ELAN1000", 0 },
-       { }
-};
 MODULE_DEVICE_TABLE(acpi, elan_acpi_id);
 #endif
 
index a434505..2d8434b 100644 (file)
@@ -226,6 +226,52 @@ static void elantech_packet_dump(struct psmouse *psmouse)
                       psmouse->pktsize, psmouse->packet);
 }
 
+/*
+ * Advertise INPUT_PROP_BUTTONPAD for clickpads. The testing of bit 12 in
+ * fw_version for this is based on the following fw_version & caps table:
+ *
+ * Laptop-model:           fw_version:     caps:           buttons:
+ * Acer S3                 0x461f00        10, 13, 0e      clickpad
+ * Acer S7-392             0x581f01        50, 17, 0d      clickpad
+ * Acer V5-131             0x461f02        01, 16, 0c      clickpad
+ * Acer V5-551             0x461f00        ?               clickpad
+ * Asus K53SV              0x450f01        78, 15, 0c      2 hw buttons
+ * Asus G46VW              0x460f02        00, 18, 0c      2 hw buttons
+ * Asus G750JX             0x360f00        00, 16, 0c      2 hw buttons
+ * Asus TP500LN            0x381f17        10, 14, 0e      clickpad
+ * Asus X750JN             0x381f17        10, 14, 0e      clickpad
+ * Asus UX31               0x361f00        20, 15, 0e      clickpad
+ * Asus UX32VD             0x361f02        00, 15, 0e      clickpad
+ * Avatar AVIU-145A2       0x361f00        ?               clickpad
+ * Fujitsu CELSIUS H760    0x570f02        40, 14, 0c      3 hw buttons (**)
+ * Fujitsu CELSIUS H780    0x5d0f02        41, 16, 0d      3 hw buttons (**)
+ * Fujitsu LIFEBOOK E544   0x470f00        d0, 12, 09      2 hw buttons
+ * Fujitsu LIFEBOOK E546   0x470f00        50, 12, 09      2 hw buttons
+ * Fujitsu LIFEBOOK E547   0x470f00        50, 12, 09      2 hw buttons
+ * Fujitsu LIFEBOOK E554   0x570f01        40, 14, 0c      2 hw buttons
+ * Fujitsu LIFEBOOK E557   0x570f01        40, 14, 0c      2 hw buttons
+ * Fujitsu T725            0x470f01        05, 12, 09      2 hw buttons
+ * Fujitsu H730            0x570f00        c0, 14, 0c      3 hw buttons (**)
+ * Gigabyte U2442          0x450f01        58, 17, 0c      2 hw buttons
+ * Lenovo L430             0x350f02        b9, 15, 0c      2 hw buttons (*)
+ * Lenovo L530             0x350f02        b9, 15, 0c      2 hw buttons (*)
+ * Samsung NF210           0x150b00        78, 14, 0a      2 hw buttons
+ * Samsung NP770Z5E        0x575f01        10, 15, 0f      clickpad
+ * Samsung NP700Z5B        0x361f06        21, 15, 0f      clickpad
+ * Samsung NP900X3E-A02    0x575f03        ?               clickpad
+ * Samsung NP-QX410        0x851b00        19, 14, 0c      clickpad
+ * Samsung RC512           0x450f00        08, 15, 0c      2 hw buttons
+ * Samsung RF710           0x450f00        ?               2 hw buttons
+ * System76 Pangolin       0x250f01        ?               2 hw buttons
+ * (*) + 3 trackpoint buttons
+ * (**) + 0 trackpoint buttons
+ * Note: Lenovo L430 and Lenovo L530 have the same fw_version/caps
+ */
+static inline int elantech_is_buttonpad(struct elantech_device_info *info)
+{
+       return info->fw_version & 0x001000;
+}
+
 /*
  * Interpret complete data packets and report absolute mode input events for
  * hardware version 1. (4 byte packets)
@@ -523,7 +569,7 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
        input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
 
        /* For clickpads map both buttons to BTN_LEFT */
-       if (etd->info.fw_version & 0x001000)
+       if (elantech_is_buttonpad(&etd->info))
                input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
        else
                psmouse_report_standard_buttons(dev, packet[0]);
@@ -541,7 +587,7 @@ static void elantech_input_sync_v4(struct psmouse *psmouse)
        unsigned char *packet = psmouse->packet;
 
        /* For clickpads map both buttons to BTN_LEFT */
-       if (etd->info.fw_version & 0x001000)
+       if (elantech_is_buttonpad(&etd->info))
                input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
        else
                psmouse_report_standard_buttons(dev, packet[0]);
@@ -991,88 +1037,6 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
        return rc;
 }
 
-static int elantech_set_range(struct psmouse *psmouse,
-                             unsigned int *x_min, unsigned int *y_min,
-                             unsigned int *x_max, unsigned int *y_max,
-                             unsigned int *width)
-{
-       struct elantech_data *etd = psmouse->private;
-       struct elantech_device_info *info = &etd->info;
-       unsigned char param[3];
-       unsigned char traces;
-
-       switch (info->hw_version) {
-       case 1:
-               *x_min = ETP_XMIN_V1;
-               *y_min = ETP_YMIN_V1;
-               *x_max = ETP_XMAX_V1;
-               *y_max = ETP_YMAX_V1;
-               break;
-
-       case 2:
-               if (info->fw_version == 0x020800 ||
-                   info->fw_version == 0x020b00 ||
-                   info->fw_version == 0x020030) {
-                       *x_min = ETP_XMIN_V2;
-                       *y_min = ETP_YMIN_V2;
-                       *x_max = ETP_XMAX_V2;
-                       *y_max = ETP_YMAX_V2;
-               } else {
-                       int i;
-                       int fixed_dpi;
-
-                       i = (info->fw_version > 0x020800 &&
-                            info->fw_version < 0x020900) ? 1 : 2;
-
-                       if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
-                               return -1;
-
-                       fixed_dpi = param[1] & 0x10;
-
-                       if (((info->fw_version >> 16) == 0x14) && fixed_dpi) {
-                               if (info->send_cmd(psmouse, ETP_SAMPLE_QUERY, param))
-                                       return -1;
-
-                               *x_max = (info->capabilities[1] - i) * param[1] / 2;
-                               *y_max = (info->capabilities[2] - i) * param[2] / 2;
-                       } else if (info->fw_version == 0x040216) {
-                               *x_max = 819;
-                               *y_max = 405;
-                       } else if (info->fw_version == 0x040219 || info->fw_version == 0x040215) {
-                               *x_max = 900;
-                               *y_max = 500;
-                       } else {
-                               *x_max = (info->capabilities[1] - i) * 64;
-                               *y_max = (info->capabilities[2] - i) * 64;
-                       }
-               }
-               break;
-
-       case 3:
-               if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
-                       return -1;
-
-               *x_max = (0x0f & param[0]) << 8 | param[1];
-               *y_max = (0xf0 & param[0]) << 4 | param[2];
-               break;
-
-       case 4:
-               if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
-                       return -1;
-
-               *x_max = (0x0f & param[0]) << 8 | param[1];
-               *y_max = (0xf0 & param[0]) << 4 | param[2];
-               traces = info->capabilities[1];
-               if ((traces < 2) || (traces > *x_max))
-                       return -1;
-
-               *width = *x_max / (traces - 1);
-               break;
-       }
-
-       return 0;
-}
-
 /*
  * (value from firmware) * 10 + 790 = dpi
  * we also have to convert dpi to dots/mm (*10/254 to avoid floating point)
@@ -1099,53 +1063,12 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
        return 0;
 }
 
-/*
- * Advertise INPUT_PROP_BUTTONPAD for clickpads. The testing of bit 12 in
- * fw_version for this is based on the following fw_version & caps table:
- *
- * Laptop-model:           fw_version:     caps:           buttons:
- * Acer S3                 0x461f00        10, 13, 0e      clickpad
- * Acer S7-392             0x581f01        50, 17, 0d      clickpad
- * Acer V5-131             0x461f02        01, 16, 0c      clickpad
- * Acer V5-551             0x461f00        ?               clickpad
- * Asus K53SV              0x450f01        78, 15, 0c      2 hw buttons
- * Asus G46VW              0x460f02        00, 18, 0c      2 hw buttons
- * Asus G750JX             0x360f00        00, 16, 0c      2 hw buttons
- * Asus TP500LN            0x381f17        10, 14, 0e      clickpad
- * Asus X750JN             0x381f17        10, 14, 0e      clickpad
- * Asus UX31               0x361f00        20, 15, 0e      clickpad
- * Asus UX32VD             0x361f02        00, 15, 0e      clickpad
- * Avatar AVIU-145A2       0x361f00        ?               clickpad
- * Fujitsu CELSIUS H760    0x570f02        40, 14, 0c      3 hw buttons (**)
- * Fujitsu CELSIUS H780    0x5d0f02        41, 16, 0d      3 hw buttons (**)
- * Fujitsu LIFEBOOK E544   0x470f00        d0, 12, 09      2 hw buttons
- * Fujitsu LIFEBOOK E546   0x470f00        50, 12, 09      2 hw buttons
- * Fujitsu LIFEBOOK E547   0x470f00        50, 12, 09      2 hw buttons
- * Fujitsu LIFEBOOK E554   0x570f01        40, 14, 0c      2 hw buttons
- * Fujitsu LIFEBOOK E557   0x570f01        40, 14, 0c      2 hw buttons
- * Fujitsu T725            0x470f01        05, 12, 09      2 hw buttons
- * Fujitsu H730            0x570f00        c0, 14, 0c      3 hw buttons (**)
- * Gigabyte U2442          0x450f01        58, 17, 0c      2 hw buttons
- * Lenovo L430             0x350f02        b9, 15, 0c      2 hw buttons (*)
- * Lenovo L530             0x350f02        b9, 15, 0c      2 hw buttons (*)
- * Samsung NF210           0x150b00        78, 14, 0a      2 hw buttons
- * Samsung NP770Z5E        0x575f01        10, 15, 0f      clickpad
- * Samsung NP700Z5B        0x361f06        21, 15, 0f      clickpad
- * Samsung NP900X3E-A02    0x575f03        ?               clickpad
- * Samsung NP-QX410        0x851b00        19, 14, 0c      clickpad
- * Samsung RC512           0x450f00        08, 15, 0c      2 hw buttons
- * Samsung RF710           0x450f00        ?               2 hw buttons
- * System76 Pangolin       0x250f01        ?               2 hw buttons
- * (*) + 3 trackpoint buttons
- * (**) + 0 trackpoint buttons
- * Note: Lenovo L430 and Lenovo L530 have the same fw_version/caps
- */
 static void elantech_set_buttonpad_prop(struct psmouse *psmouse)
 {
        struct input_dev *dev = psmouse->dev;
        struct elantech_data *etd = psmouse->private;
 
-       if (etd->info.fw_version & 0x001000) {
+       if (elantech_is_buttonpad(&etd->info)) {
                __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
                __clear_bit(BTN_RIGHT, dev->keybit);
        }
@@ -1181,16 +1104,6 @@ static const struct dmi_system_id elantech_dmi_has_middle_button[] = {
        { }
 };
 
-static const char * const middle_button_pnp_ids[] = {
-       "LEN2131", /* ThinkPad P52 w/ NFC */
-       "LEN2132", /* ThinkPad P52 */
-       "LEN2133", /* ThinkPad P72 w/ NFC */
-       "LEN2134", /* ThinkPad P72 */
-       "LEN0407",
-       "LEN0408",
-       NULL
-};
-
 /*
  * Set the appropriate event bits for the input subsystem
  */
@@ -1199,10 +1112,9 @@ static int elantech_set_input_params(struct psmouse *psmouse)
        struct input_dev *dev = psmouse->dev;
        struct elantech_data *etd = psmouse->private;
        struct elantech_device_info *info = &etd->info;
-       unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, width = 0;
-
-       if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &width))
-               return -1;
+       unsigned int x_min = info->x_min, y_min = info->y_min,
+                    x_max = info->x_max, y_max = info->y_max,
+                    width = info->width;
 
        __set_bit(INPUT_PROP_POINTER, dev->propbit);
        __set_bit(EV_KEY, dev->evbit);
@@ -1210,8 +1122,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
        __clear_bit(EV_REL, dev->evbit);
 
        __set_bit(BTN_LEFT, dev->keybit);
-       if (dmi_check_system(elantech_dmi_has_middle_button) ||
-                       psmouse_matches_pnp_id(psmouse, middle_button_pnp_ids))
+       if (info->has_middle_button)
                __set_bit(BTN_MIDDLE, dev->keybit);
        __set_bit(BTN_RIGHT, dev->keybit);
 
@@ -1686,6 +1597,7 @@ static int elantech_query_info(struct psmouse *psmouse,
                               struct elantech_device_info *info)
 {
        unsigned char param[3];
+       unsigned char traces;
 
        memset(info, 0, sizeof(*info));
 
@@ -1754,6 +1666,90 @@ static int elantech_query_info(struct psmouse *psmouse,
                }
        }
 
+       /* query range information */
+       switch (info->hw_version) {
+       case 1:
+               info->x_min = ETP_XMIN_V1;
+               info->y_min = ETP_YMIN_V1;
+               info->x_max = ETP_XMAX_V1;
+               info->y_max = ETP_YMAX_V1;
+               break;
+
+       case 2:
+               if (info->fw_version == 0x020800 ||
+                   info->fw_version == 0x020b00 ||
+                   info->fw_version == 0x020030) {
+                       info->x_min = ETP_XMIN_V2;
+                       info->y_min = ETP_YMIN_V2;
+                       info->x_max = ETP_XMAX_V2;
+                       info->y_max = ETP_YMAX_V2;
+               } else {
+                       int i;
+                       int fixed_dpi;
+
+                       i = (info->fw_version > 0x020800 &&
+                            info->fw_version < 0x020900) ? 1 : 2;
+
+                       if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
+                               return -EINVAL;
+
+                       fixed_dpi = param[1] & 0x10;
+
+                       if (((info->fw_version >> 16) == 0x14) && fixed_dpi) {
+                               if (info->send_cmd(psmouse, ETP_SAMPLE_QUERY, param))
+                                       return -EINVAL;
+
+                               info->x_max = (info->capabilities[1] - i) * param[1] / 2;
+                               info->y_max = (info->capabilities[2] - i) * param[2] / 2;
+                       } else if (info->fw_version == 0x040216) {
+                               info->x_max = 819;
+                               info->y_max = 405;
+                       } else if (info->fw_version == 0x040219 || info->fw_version == 0x040215) {
+                               info->x_max = 900;
+                               info->y_max = 500;
+                       } else {
+                               info->x_max = (info->capabilities[1] - i) * 64;
+                               info->y_max = (info->capabilities[2] - i) * 64;
+                       }
+               }
+               break;
+
+       case 3:
+               if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
+                       return -EINVAL;
+
+               info->x_max = (0x0f & param[0]) << 8 | param[1];
+               info->y_max = (0xf0 & param[0]) << 4 | param[2];
+               break;
+
+       case 4:
+               if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
+                       return -EINVAL;
+
+               info->x_max = (0x0f & param[0]) << 8 | param[1];
+               info->y_max = (0xf0 & param[0]) << 4 | param[2];
+               traces = info->capabilities[1];
+               if ((traces < 2) || (traces > info->x_max))
+                       return -EINVAL;
+
+               info->width = info->x_max / (traces - 1);
+
+               /* column number of traces */
+               info->x_traces = traces;
+
+               /* row number of traces */
+               traces = info->capabilities[2];
+               if ((traces >= 2) && (traces <= info->y_max))
+                       info->y_traces = traces;
+
+               break;
+       }
+
+       /* check for the middle button: DMI matching or new v4 firmwares */
+       info->has_middle_button = dmi_check_system(elantech_dmi_has_middle_button) ||
+                                 (ETP_NEW_IC_SMBUS_HOST_NOTIFY(info->fw_version) &&
+                                  !elantech_is_buttonpad(info));
+
        return 0;
 }
 
@@ -1780,10 +1776,6 @@ static const char * const i2c_blacklist_pnp_ids[] = {
         * These are known to not be working properly as bits are missing
         * in elan_i2c.
         */
-       "LEN2131", /* ThinkPad P52 w/ NFC */
-       "LEN2132", /* ThinkPad P52 */
-       "LEN2133", /* ThinkPad P72 w/ NFC */
-       "LEN2134", /* ThinkPad P72 */
        NULL
 };
 
@@ -1791,17 +1783,45 @@ static int elantech_create_smbus(struct psmouse *psmouse,
                                 struct elantech_device_info *info,
                                 bool leave_breadcrumbs)
 {
-       const struct property_entry i2c_properties[] = {
-               PROPERTY_ENTRY_BOOL("elan,trackpoint"),
-               { },
-       };
+       struct property_entry i2c_props[11] = {};
        struct i2c_board_info smbus_board = {
                I2C_BOARD_INFO("elan_i2c", 0x15),
                .flags = I2C_CLIENT_HOST_NOTIFY,
        };
+       unsigned int idx = 0;
+
+       smbus_board.properties = i2c_props;
+
+       i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-size-x",
+                                                  info->x_max + 1);
+       i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-size-y",
+                                                  info->y_max + 1);
+       i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-min-x",
+                                                  info->x_min);
+       i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-min-y",
+                                                  info->y_min);
+       if (info->x_res)
+               i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-x-mm",
+                                                     (info->x_max + 1) / info->x_res);
+       if (info->y_res)
+               i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-y-mm",
+                                                     (info->y_max + 1) / info->y_res);
 
        if (info->has_trackpoint)
-               smbus_board.properties = i2c_properties;
+               i2c_props[idx++] = PROPERTY_ENTRY_BOOL("elan,trackpoint");
+
+       if (info->has_middle_button)
+               i2c_props[idx++] = PROPERTY_ENTRY_BOOL("elan,middle-button");
+
+       if (info->x_traces)
+               i2c_props[idx++] = PROPERTY_ENTRY_U32("elan,x_traces",
+                                                     info->x_traces);
+       if (info->y_traces)
+               i2c_props[idx++] = PROPERTY_ENTRY_U32("elan,y_traces",
+                                                     info->y_traces);
+
+       if (elantech_is_buttonpad(info))
+               i2c_props[idx++] = PROPERTY_ENTRY_BOOL("elan,clickpad");
 
        return psmouse_smbus_init(psmouse, &smbus_board, NULL, 0, false,
                                  leave_breadcrumbs);
index 12ba5af..4634399 100644 (file)
@@ -141,8 +141,15 @@ struct elantech_device_info {
        unsigned char debug;
        unsigned char hw_version;
        unsigned int fw_version;
+       unsigned int x_min;
+       unsigned int y_min;
+       unsigned int x_max;
+       unsigned int y_max;
        unsigned int x_res;
        unsigned int y_res;
+       unsigned int x_traces;
+       unsigned int y_traces;
+       unsigned int width;
        unsigned int bus;
        bool paritycheck;
        bool jumpy_cursor;
@@ -150,6 +157,7 @@ struct elantech_device_info {
        bool crc_enabled;
        bool set_hw_resolution;
        bool has_trackpoint;
+       bool has_middle_button;
        int (*send_cmd)(struct psmouse *psmouse, unsigned char c,
                        unsigned char *param);
 };
index b8ec301..1080c0c 100644 (file)
@@ -173,6 +173,7 @@ static const char * const smbus_pnp_ids[] = {
        "LEN0072", /* X1 Carbon Gen 5 (2017) - Elan/ALPS trackpoint */
        "LEN0073", /* X1 Carbon G5 (Elantech) */
        "LEN0092", /* X1 Carbon 6 */
+       "LEN0093", /* T480 */
        "LEN0096", /* X280 */
        "LEN0097", /* X280 -> ALPS trackpoint */
        "LEN200f", /* T450s */
index bb14369..d20a5d6 100644 (file)
@@ -70,7 +70,6 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
        int pitch_y = 0;
        int rx_receivers = 0;
        int tx_receivers = 0;
-       int sensor_flags = 0;
 
        item = rmi_get_register_desc_item(&f12->control_reg_desc, 8);
        if (!item) {
@@ -126,10 +125,9 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
                offset += 2;
        }
 
-       if (rmi_register_desc_has_subpacket(item, 4)) {
-               sensor_flags = buf[offset];
+       /* Skip over sensor flags */
+       if (rmi_register_desc_has_subpacket(item, 4))
                offset += 1;
-       }
 
        sensor->x_mm = (pitch_x * rx_receivers) >> 12;
        sensor->y_mm = (pitch_y * tx_receivers) >> 12;
index 19378f2..4a5f482 100644 (file)
@@ -256,16 +256,6 @@ enum v4l_dbg_inputs {
        MXT_V4L_INPUT_MAX,
 };
 
-static const struct v4l2_file_operations mxt_video_fops = {
-       .owner = THIS_MODULE,
-       .open = v4l2_fh_open,
-       .release = vb2_fop_release,
-       .unlocked_ioctl = video_ioctl2,
-       .read = vb2_fop_read,
-       .mmap = vb2_fop_mmap,
-       .poll = vb2_fop_poll,
-};
-
 enum mxt_suspend_mode {
        MXT_SUSPEND_DEEP_SLEEP  = 0,
        MXT_SUSPEND_T9_CTRL     = 1,
@@ -1521,7 +1511,8 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw)
                } else if (config_crc == data->config_crc) {
                        dev_dbg(dev, "Config CRC 0x%06X: OK\n",
                                 data->config_crc);
-                       return 0;
+                       ret = 0;
+                       goto release_raw;
                } else {
                        dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n",
                                 data->config_crc, config_crc);
@@ -2218,6 +2209,16 @@ recheck:
 }
 
 #ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37
+static const struct v4l2_file_operations mxt_video_fops = {
+       .owner = THIS_MODULE,
+       .open = v4l2_fh_open,
+       .release = vb2_fop_release,
+       .unlocked_ioctl = video_ioctl2,
+       .read = vb2_fop_read,
+       .mmap = vb2_fop_mmap,
+       .poll = vb2_fop_poll,
+};
+
 static u16 mxt_get_debug_value(struct mxt_data *data, unsigned int x,
                               unsigned int y)
 {
index c639ebc..3cc4341 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/gpio/consumer.h>
 #include <linux/input/mt.h>
 #include <linux/input/touchscreen.h>
+#include <asm/unaligned.h>
 
 #define WORK_REGISTER_THRESHOLD                0x00
 #define WORK_REGISTER_REPORT_RATE      0x08
@@ -228,7 +229,6 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
 
        for (i = 0; i < tsdata->max_support_points; i++) {
                u8 *buf = &rdbuf[i * tplen + offset];
-               bool down;
 
                type = buf[0] >> 6;
                /* ignore Reserved events */
@@ -239,23 +239,19 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
                if (tsdata->version == EDT_M06 && type == TOUCH_EVENT_DOWN)
                        continue;
 
-               x = ((buf[0] << 8) | buf[1]) & 0x0fff;
-               y = ((buf[2] << 8) | buf[3]) & 0x0fff;
+               x = get_unaligned_be16(buf) & 0x0fff;
+               y = get_unaligned_be16(buf + 2) & 0x0fff;
                /* The FT5x26 send the y coordinate first */
                if (tsdata->version == EV_FT)
                        swap(x, y);
 
                id = (buf[2] >> 4) & 0x0f;
-               down = type != TOUCH_EVENT_UP;
 
                input_mt_slot(tsdata->input, id);
-               input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, down);
-
-               if (!down)
-                       continue;
-
-               touchscreen_report_pos(tsdata->input, &tsdata->prop, x, y,
-                                      true);
+               if (input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER,
+                                              type != TOUCH_EVENT_UP))
+                       touchscreen_report_pos(tsdata->input, &tsdata->prop,
+                                              x, y, true);
        }
 
        input_mt_report_pointer_emulation(tsdata->input, true);
index c6b85ba..2e1404c 100644 (file)
@@ -28,6 +28,7 @@ struct eeti_ts {
        struct input_dev *input;
        struct gpio_desc *attn_gpio;
        struct touchscreen_properties props;
+       struct mutex mutex;
        bool running;
 };
 
@@ -62,42 +63,80 @@ static void eeti_ts_report_event(struct eeti_ts *eeti, u8 *buf)
        input_sync(eeti->input);
 }
 
+static int eeti_ts_read(struct eeti_ts *eeti)
+{
+       int len, error;
+       char buf[6];
+
+       len = i2c_master_recv(eeti->client, buf, sizeof(buf));
+       if (len != sizeof(buf)) {
+               error = len < 0 ? len : -EIO;
+               dev_err(&eeti->client->dev,
+                       "failed to read touchscreen data: %d\n",
+                       error);
+               return error;
+       }
+
+       /* Motion packet */
+       if (buf[0] & 0x80)
+               eeti_ts_report_event(eeti, buf);
+
+       return 0;
+}
+
 static irqreturn_t eeti_ts_isr(int irq, void *dev_id)
 {
        struct eeti_ts *eeti = dev_id;
-       int len;
        int error;
-       char buf[6];
+
+       mutex_lock(&eeti->mutex);
 
        do {
-               len = i2c_master_recv(eeti->client, buf, sizeof(buf));
-               if (len != sizeof(buf)) {
-                       error = len < 0 ? len : -EIO;
-                       dev_err(&eeti->client->dev,
-                               "failed to read touchscreen data: %d\n",
-                               error);
+               /*
+                * If we have attention GPIO, trust it. Otherwise we'll read
+                * once and exit. We assume that in this case we are using
+                * level triggered interrupt and it will get raised again
+                * if/when there is more data.
+                */
+               if (eeti->attn_gpio &&
+                   !gpiod_get_value_cansleep(eeti->attn_gpio)) {
                        break;
                }
 
-               if (buf[0] & 0x80) {
-                       /* Motion packet */
-                       eeti_ts_report_event(eeti, buf);
-               }
-       } while (eeti->running &&
-                eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio));
+               error = eeti_ts_read(eeti);
+               if (error)
+                       break;
+
+       } while (eeti->running && eeti->attn_gpio);
 
+       mutex_unlock(&eeti->mutex);
        return IRQ_HANDLED;
 }
 
 static void eeti_ts_start(struct eeti_ts *eeti)
 {
+       mutex_lock(&eeti->mutex);
+
        eeti->running = true;
-       wmb();
        enable_irq(eeti->client->irq);
+
+       /*
+        * Kick the controller in case we are using edge interrupt and
+        * we missed our edge while interrupt was disabled. We expect
+        * the attention GPIO to be wired in this case.
+        */
+       if (eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio))
+               eeti_ts_read(eeti);
+
+       mutex_unlock(&eeti->mutex);
 }
 
 static void eeti_ts_stop(struct eeti_ts *eeti)
 {
+       /*
+        * Not locking here, just setting a flag and expect that the
+        * interrupt thread will notice the flag eventually.
+        */
        eeti->running = false;
        wmb();
        disable_irq(eeti->client->irq);
@@ -140,6 +179,8 @@ static int eeti_ts_probe(struct i2c_client *client,
                return -ENOMEM;
        }
 
+       mutex_init(&eeti->mutex);
+
        input = devm_input_allocate_device(dev);
        if (!input) {
                dev_err(dev, "Failed to allocate input device.\n");
index c10fc59..e04eecd 100644 (file)
@@ -364,8 +364,6 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        struct imx6ul_tsc *tsc;
        struct input_dev *input_dev;
-       struct resource *tsc_mem;
-       struct resource *adc_mem;
        int err;
        int tsc_irq;
        int adc_irq;
@@ -403,16 +401,14 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
                return err;
        }
 
-       tsc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       tsc->tsc_regs = devm_ioremap_resource(&pdev->dev, tsc_mem);
+       tsc->tsc_regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(tsc->tsc_regs)) {
                err = PTR_ERR(tsc->tsc_regs);
                dev_err(&pdev->dev, "failed to remap tsc memory: %d\n", err);
                return err;
        }
 
-       adc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       tsc->adc_regs = devm_ioremap_resource(&pdev->dev, adc_mem);
+       tsc->adc_regs = devm_platform_ioremap_resource(pdev, 1);
        if (IS_ERR(tsc->adc_regs)) {
                err = PTR_ERR(tsc->adc_regs);
                dev_err(&pdev->dev, "failed to remap adc memory: %d\n", err);
index 4f6fe8c..5875bb1 100644 (file)
@@ -1056,8 +1056,6 @@ static int iqs5xx_probe(struct i2c_client *client,
        if (!iqs5xx)
                return -ENOMEM;
 
-       dev_set_drvdata(&client->dev, iqs5xx);
-
        i2c_set_clientdata(client, iqs5xx);
        iqs5xx->client = client;
 
index 2d96cf0..a9a9fab 100644 (file)
@@ -2034,7 +2034,7 @@ arm_smmu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova)
 
 static struct platform_driver arm_smmu_driver;
 
-static int arm_smmu_match_node(struct device *dev, void *data)
+static int arm_smmu_match_node(struct device *dev, const void *data)
 {
        return dev->fwnode == data;
 }
index 653b6b3..64977c1 100644 (file)
@@ -1426,7 +1426,7 @@ static bool arm_smmu_capable(enum iommu_cap cap)
        }
 }
 
-static int arm_smmu_match_node(struct device *dev, void *data)
+static int arm_smmu_match_node(struct device *dev, const void *data)
 {
        return dev->fwnode == data;
 }
index f802255..a7f9c3e 100644 (file)
@@ -951,8 +951,8 @@ static void __iommu_dma_free(struct device *dev, size_t size, void *cpu_addr)
 
        if (pages)
                __iommu_dma_free_pages(pages, count);
-       if (page && !dma_release_from_contiguous(dev, page, count))
-               __free_pages(page, get_order(alloc_size));
+       if (page)
+               dma_free_contiguous(dev, page, alloc_size);
 }
 
 static void iommu_dma_free(struct device *dev, size_t size, void *cpu_addr,
@@ -970,12 +970,7 @@ static void *iommu_dma_alloc_pages(struct device *dev, size_t size,
        struct page *page = NULL;
        void *cpu_addr;
 
-       if (gfpflags_allow_blocking(gfp))
-               page = dma_alloc_from_contiguous(dev, alloc_size >> PAGE_SHIFT,
-                                                get_order(alloc_size),
-                                                gfp & __GFP_NOWARN);
-       if (!page)
-               page = alloc_pages(gfp, get_order(alloc_size));
+       page = dma_alloc_contiguous(dev, alloc_size, gfp);
        if (!page)
                return NULL;
 
@@ -997,8 +992,7 @@ static void *iommu_dma_alloc_pages(struct device *dev, size_t size,
        memset(cpu_addr, 0, alloc_size);
        return cpu_addr;
 out_free_pages:
-       if (!dma_release_from_contiguous(dev, page, alloc_size >> PAGE_SHIFT))
-               __free_pages(page, get_order(alloc_size));
+       dma_free_contiguous(dev, page, alloc_size);
        return NULL;
 }
 
index 9205378..75f83ba 100644 (file)
@@ -15,7 +15,6 @@
 #define NR_CHANNELS            8
 #define IPOCTAL_MAX_BOARDS     16
 #define MAX_DEVICES            (NR_CHANNELS * IPOCTAL_MAX_BOARDS)
-#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
 
 /**
  * struct ipoctal_stats -- Stats since last reset
index 3550080..730fbe0 100644 (file)
@@ -185,7 +185,7 @@ static struct its_collection *dev_event_to_col(struct its_device *its_dev,
 
 static struct its_collection *valid_col(struct its_collection *col)
 {
-       if (WARN_ON_ONCE(col->target_address & GENMASK_ULL(0, 15)))
+       if (WARN_ON_ONCE(col->target_address & GENMASK_ULL(15, 0)))
                return NULL;
 
        return col;
index b1f19b2..b0d46ac 100644 (file)
@@ -208,20 +208,19 @@ static int rza1_irqc_probe(struct platform_device *pdev)
                return PTR_ERR(priv->base);
 
        gic_node = of_irq_find_parent(np);
-       if (gic_node) {
+       if (gic_node)
                parent = irq_find_host(gic_node);
-               of_node_put(gic_node);
-       }
 
        if (!parent) {
                dev_err(dev, "cannot find parent domain\n");
-               return -ENODEV;
+               ret = -ENODEV;
+               goto out_put_node;
        }
 
        ret = rza1_irqc_parse_map(priv, gic_node);
        if (ret) {
                dev_err(dev, "cannot parse %s: %d\n", "interrupt-map", ret);
-               return ret;
+               goto out_put_node;
        }
 
        priv->chip.name = "rza1-irqc",
@@ -237,10 +236,12 @@ static int rza1_irqc_probe(struct platform_device *pdev)
                                                    priv);
        if (!priv->irq_domain) {
                dev_err(dev, "cannot initialize irq domain\n");
-               return -ENOMEM;
+               ret = -ENOMEM;
        }
 
-       return 0;
+out_put_node:
+       of_node_put(gic_node);
+       return ret;
 }
 
 static int rza1_irqc_remove(struct platform_device *pdev)
index a641165..43b3363 100644 (file)
@@ -296,8 +296,6 @@ struct flexrm_mbox {
        struct dma_pool *bd_pool;
        struct dma_pool *cmpl_pool;
        struct dentry *root;
-       struct dentry *config;
-       struct dentry *stats;
        struct mbox_controller controller;
 };
 
@@ -1603,7 +1601,6 @@ static int flexrm_mbox_probe(struct platform_device *pdev)
                                          1 << RING_CMPL_ALIGN_ORDER, 0);
        if (!mbox->cmpl_pool) {
                ret = -ENOMEM;
-               goto fail_destroy_bd_pool;
        }
 
        /* Allocate platform MSIs for each ring */
@@ -1624,28 +1621,15 @@ static int flexrm_mbox_probe(struct platform_device *pdev)
 
        /* Create debugfs root entry */
        mbox->root = debugfs_create_dir(dev_name(mbox->dev), NULL);
-       if (IS_ERR_OR_NULL(mbox->root)) {
-               ret = PTR_ERR_OR_ZERO(mbox->root);
-               goto fail_free_msis;
-       }
 
        /* Create debugfs config entry */
-       mbox->config = debugfs_create_devm_seqfile(mbox->dev,
-                                                  "config", mbox->root,
-                                                  flexrm_debugfs_conf_show);
-       if (IS_ERR_OR_NULL(mbox->config)) {
-               ret = PTR_ERR_OR_ZERO(mbox->config);
-               goto fail_free_debugfs_root;
-       }
+       debugfs_create_devm_seqfile(mbox->dev, "config", mbox->root,
+                                   flexrm_debugfs_conf_show);
 
        /* Create debugfs stats entry */
-       mbox->stats = debugfs_create_devm_seqfile(mbox->dev,
-                                                 "stats", mbox->root,
-                                                 flexrm_debugfs_stats_show);
-       if (IS_ERR_OR_NULL(mbox->stats)) {
-               ret = PTR_ERR_OR_ZERO(mbox->stats);
-               goto fail_free_debugfs_root;
-       }
+       debugfs_create_devm_seqfile(mbox->dev, "stats", mbox->root,
+                                   flexrm_debugfs_stats_show);
+
 skip_debugfs:
 
        /* Initialize mailbox controller */
@@ -1676,11 +1660,9 @@ skip_debugfs:
 
 fail_free_debugfs_root:
        debugfs_remove_recursive(mbox->root);
-fail_free_msis:
        platform_msi_domain_free_irqs(dev);
 fail_destroy_cmpl_pool:
        dma_pool_destroy(mbox->cmpl_pool);
-fail_destroy_bd_pool:
        dma_pool_destroy(mbox->bd_pool);
 fail:
        return ret;
index 8513c42..fcb3b18 100644 (file)
@@ -395,8 +395,6 @@ struct pdc_state {
         */
        struct scatterlist *src_sg[PDC_RING_ENTRIES];
 
-       struct dentry *debugfs_stats;  /* debug FS stats file for this PDC */
-
        /* counters */
        u32  pdc_requests;     /* number of request messages submitted */
        u32  pdc_replies;      /* number of reply messages received */
@@ -501,9 +499,8 @@ static void pdc_setup_debugfs(struct pdc_state *pdcs)
                debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
 
        /* S_IRUSR == 0400 */
-       pdcs->debugfs_stats = debugfs_create_file(spu_stats_name, 0400,
-                                                 debugfs_dir, pdcs,
-                                                 &pdc_debugfs_stats);
+       debugfs_create_file(spu_stats_name, 0400, debugfs_dir, pdcs,
+                           &pdc_debugfs_stats);
 }
 
 static void pdc_free_debugfs(void)
@@ -1603,7 +1600,6 @@ static int pdc_probe(struct platform_device *pdev)
        if (err)
                goto cleanup_buf_pool;
 
-       pdcs->debugfs_stats = NULL;
        pdc_setup_debugfs(pdcs);
 
        dev_dbg(dev, "pdc_probe() successful");
index 2a48ea3..b6b5acc 100644 (file)
@@ -1599,9 +1599,7 @@ dm_bufio_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
        unsigned long freed;
 
        c = container_of(shrink, struct dm_bufio_client, shrinker);
-       if (sc->gfp_mask & __GFP_FS)
-               dm_bufio_lock(c);
-       else if (!dm_bufio_trylock(c))
+       if (!dm_bufio_trylock(c))
                return SHRINK_STOP;
 
        freed  = __scan(c, sc->nr_to_scan, sc->gfp_mask);
index 1b16d34..d5216bc 100644 (file)
@@ -120,6 +120,10 @@ struct iv_tcw_private {
        u8 *whitening;
 };
 
+struct iv_eboiv_private {
+       struct crypto_cipher *tfm;
+};
+
 /*
  * Crypt: maps a linear range of a block device
  * and encrypts / decrypts at the same time.
@@ -159,6 +163,7 @@ struct crypt_config {
                struct iv_benbi_private benbi;
                struct iv_lmk_private lmk;
                struct iv_tcw_private tcw;
+               struct iv_eboiv_private eboiv;
        } iv_gen_private;
        u64 iv_offset;
        unsigned int iv_size;
@@ -291,8 +296,9 @@ static struct crypto_aead *any_tfm_aead(struct crypt_config *cc)
  *       Note that this encryption scheme is vulnerable to watermarking attacks
  *       and should be used for old compatible containers access only.
  *
- * plumb: unimplemented, see:
- * http://article.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt/454
+ * eboiv: Encrypted byte-offset IV (used in Bitlocker in CBC mode)
+ *        The IV is encrypted little-endian byte-offset (with the same key
+ *        and cipher as the volume).
  */
 
 static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv,
@@ -841,6 +847,67 @@ static int crypt_iv_random_gen(struct crypt_config *cc, u8 *iv,
        return 0;
 }
 
+static void crypt_iv_eboiv_dtr(struct crypt_config *cc)
+{
+       struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
+
+       crypto_free_cipher(eboiv->tfm);
+       eboiv->tfm = NULL;
+}
+
+static int crypt_iv_eboiv_ctr(struct crypt_config *cc, struct dm_target *ti,
+                           const char *opts)
+{
+       struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
+       struct crypto_cipher *tfm;
+
+       tfm = crypto_alloc_cipher(cc->cipher, 0, 0);
+       if (IS_ERR(tfm)) {
+               ti->error = "Error allocating crypto tfm for EBOIV";
+               return PTR_ERR(tfm);
+       }
+
+       if (crypto_cipher_blocksize(tfm) != cc->iv_size) {
+               ti->error = "Block size of EBOIV cipher does "
+                           "not match IV size of block cipher";
+               crypto_free_cipher(tfm);
+               return -EINVAL;
+       }
+
+       eboiv->tfm = tfm;
+       return 0;
+}
+
+static int crypt_iv_eboiv_init(struct crypt_config *cc)
+{
+       struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
+       int err;
+
+       err = crypto_cipher_setkey(eboiv->tfm, cc->key, cc->key_size);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static int crypt_iv_eboiv_wipe(struct crypt_config *cc)
+{
+       /* Called after cc->key is set to random key in crypt_wipe() */
+       return crypt_iv_eboiv_init(cc);
+}
+
+static int crypt_iv_eboiv_gen(struct crypt_config *cc, u8 *iv,
+                           struct dm_crypt_request *dmreq)
+{
+       struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
+
+       memset(iv, 0, cc->iv_size);
+       *(__le64 *)iv = cpu_to_le64(dmreq->iv_sector * cc->sector_size);
+       crypto_cipher_encrypt_one(eboiv->tfm, iv, iv);
+
+       return 0;
+}
+
 static const struct crypt_iv_operations crypt_iv_plain_ops = {
        .generator = crypt_iv_plain_gen
 };
@@ -893,6 +960,14 @@ static struct crypt_iv_operations crypt_iv_random_ops = {
        .generator = crypt_iv_random_gen
 };
 
+static struct crypt_iv_operations crypt_iv_eboiv_ops = {
+       .ctr       = crypt_iv_eboiv_ctr,
+       .dtr       = crypt_iv_eboiv_dtr,
+       .init      = crypt_iv_eboiv_init,
+       .wipe      = crypt_iv_eboiv_wipe,
+       .generator = crypt_iv_eboiv_gen
+};
+
 /*
  * Integrity extensions
  */
@@ -2158,6 +2233,14 @@ static int crypt_wipe_key(struct crypt_config *cc)
 
        clear_bit(DM_CRYPT_KEY_VALID, &cc->flags);
        get_random_bytes(&cc->key, cc->key_size);
+
+       /* Wipe IV private keys */
+       if (cc->iv_gen_ops && cc->iv_gen_ops->wipe) {
+               r = cc->iv_gen_ops->wipe(cc);
+               if (r)
+                       return r;
+       }
+
        kzfree(cc->key_string);
        cc->key_string = NULL;
        r = crypt_setkey(cc);
@@ -2288,6 +2371,8 @@ static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode)
                cc->iv_gen_ops = &crypt_iv_benbi_ops;
        else if (strcmp(ivmode, "null") == 0)
                cc->iv_gen_ops = &crypt_iv_null_ops;
+       else if (strcmp(ivmode, "eboiv") == 0)
+               cc->iv_gen_ops = &crypt_iv_eboiv_ops;
        else if (strcmp(ivmode, "lmk") == 0) {
                cc->iv_gen_ops = &crypt_iv_lmk_ops;
                /*
@@ -2699,7 +2784,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                return -EINVAL;
        }
 
-       cc = kzalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
+       cc = kzalloc(struct_size(cc, key, key_size), GFP_KERNEL);
        if (!cc) {
                ti->error = "Cannot allocate encryption context";
                return -ENOMEM;
@@ -3050,14 +3135,8 @@ static int crypt_message(struct dm_target *ti, unsigned argc, char **argv,
                                memset(cc->key, 0, cc->key_size * sizeof(u8));
                        return ret;
                }
-               if (argc == 2 && !strcasecmp(argv[1], "wipe")) {
-                       if (cc->iv_gen_ops && cc->iv_gen_ops->wipe) {
-                               ret = cc->iv_gen_ops->wipe(cc);
-                               if (ret)
-                                       return ret;
-                       }
+               if (argc == 2 && !strcasecmp(argv[1], "wipe"))
                        return crypt_wipe_key(cc);
-               }
        }
 
 error:
@@ -3094,7 +3173,7 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
 
 static struct target_type crypt_target = {
        .name   = "crypt",
-       .version = {1, 18, 1},
+       .version = {1, 19, 0},
        .module = THIS_MODULE,
        .ctr    = crypt_ctr,
        .dtr    = crypt_dtr,
index 44e76cd..b1b0de4 100644 (file)
@@ -476,6 +476,9 @@ static int sync_rw_sb(struct dm_integrity_c *ic, int op, int op_flags)
        io_loc.sector = ic->start;
        io_loc.count = SB_SECTORS;
 
+       if (op == REQ_OP_WRITE)
+               sb_set_version(ic);
+
        return dm_io(&io_req, 1, &io_loc, NULL);
 }
 
@@ -2317,7 +2320,6 @@ static void recalc_write_super(struct dm_integrity_c *ic)
        if (dm_integrity_failed(ic))
                return;
 
-       sb_set_version(ic);
        r = sync_rw_sb(ic, REQ_OP_WRITE, 0);
        if (unlikely(r))
                dm_integrity_io_error(ic, "writing superblock", r);
@@ -3358,7 +3360,7 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
                                goto bad;
                        }
 
-                       crypt_iv = kmalloc(ivsize, GFP_KERNEL);
+                       crypt_iv = kzalloc(ivsize, GFP_KERNEL);
                        if (!crypt_iv) {
                                *error = "Could not allocate iv";
                                r = -ENOMEM;
@@ -3387,7 +3389,6 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
                                sg_set_buf(&sg[i], va, PAGE_SIZE);
                        }
                        sg_set_buf(&sg[i], &ic->commit_ids, sizeof ic->commit_ids);
-                       memset(crypt_iv, 0x00, ivsize);
 
                        skcipher_request_set_crypt(req, sg, sg,
                                                   PAGE_SIZE * ic->journal_pages + sizeof ic->commit_ids, crypt_iv);
index e549392..99721c7 100644 (file)
@@ -40,7 +40,7 @@
  *
  * Would result in the log looking like this:
  *
- * c,a,flush,fuad,b,<other writes>,<next flush>
+ * c,a,b,flush,fuad,<other writes>,<next flush>
  *
  * This is meant to help expose problems where file systems do not properly wait
  * on data being written before invoking a FLUSH.  FUA bypasses cache so once it
@@ -699,7 +699,7 @@ static int log_writes_map(struct dm_target *ti, struct bio *bio)
        if (discard_bio)
                alloc_size = sizeof(struct pending_block);
        else
-               alloc_size = sizeof(struct pending_block) + sizeof(struct bio_vec) * bio_segments(bio);
+               alloc_size = struct_size(block, vecs, bio_segments(bio));
 
        block = kzalloc(alloc_size, GFP_NOIO);
        if (!block) {
index 5f7063f..c9e44ac 100644 (file)
@@ -115,7 +115,7 @@ static void end_clone_bio(struct bio *clone)
 
        /*
         * Update the original request.
-        * Do not use blk_end_request() here, because it may complete
+        * Do not use blk_mq_end_request() here, because it may complete
         * the original request before the clone, and break the ordering.
         */
        if (is_last)
index 3107f2b..63916e1 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * dm-snapshot.c
- *
  * Copyright (C) 2001-2002 Sistina Software (UK) Limited.
  *
  * This file is released under the GPL.
@@ -134,7 +132,10 @@ struct dm_snapshot {
         * - I/O error while merging
         *      => stop merging; set merge_failed; process I/O normally.
         */
-       int merge_failed;
+       bool merge_failed:1;
+
+       bool discard_zeroes_cow:1;
+       bool discard_passdown_origin:1;
 
        /*
         * Incoming bios that overlap with chunks being merged must wait
@@ -1173,12 +1174,64 @@ static void stop_merge(struct dm_snapshot *s)
        clear_bit(SHUTDOWN_MERGE, &s->state_bits);
 }
 
+static int parse_snapshot_features(struct dm_arg_set *as, struct dm_snapshot *s,
+                                  struct dm_target *ti)
+{
+       int r;
+       unsigned argc;
+       const char *arg_name;
+
+       static const struct dm_arg _args[] = {
+               {0, 2, "Invalid number of feature arguments"},
+       };
+
+       /*
+        * No feature arguments supplied.
+        */
+       if (!as->argc)
+               return 0;
+
+       r = dm_read_arg_group(_args, as, &argc, &ti->error);
+       if (r)
+               return -EINVAL;
+
+       while (argc && !r) {
+               arg_name = dm_shift_arg(as);
+               argc--;
+
+               if (!strcasecmp(arg_name, "discard_zeroes_cow"))
+                       s->discard_zeroes_cow = true;
+
+               else if (!strcasecmp(arg_name, "discard_passdown_origin"))
+                       s->discard_passdown_origin = true;
+
+               else {
+                       ti->error = "Unrecognised feature requested";
+                       r = -EINVAL;
+                       break;
+               }
+       }
+
+       if (!s->discard_zeroes_cow && s->discard_passdown_origin) {
+               /*
+                * TODO: really these are disjoint.. but ti->num_discard_bios
+                * and dm_bio_get_target_bio_nr() require rigid constraints.
+                */
+               ti->error = "discard_passdown_origin feature depends on discard_zeroes_cow";
+               r = -EINVAL;
+       }
+
+       return r;
+}
+
 /*
- * Construct a snapshot mapping: <origin_dev> <COW-dev> <p|po|n> <chunk-size>
+ * Construct a snapshot mapping:
+ * <origin_dev> <COW-dev> <p|po|n> <chunk-size> [<# feature args> [<arg>]*]
  */
 static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 {
        struct dm_snapshot *s;
+       struct dm_arg_set as;
        int i;
        int r = -EINVAL;
        char *origin_path, *cow_path;
@@ -1186,8 +1239,8 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        unsigned args_used, num_flush_bios = 1;
        fmode_t origin_mode = FMODE_READ;
 
-       if (argc != 4) {
-               ti->error = "requires exactly 4 arguments";
+       if (argc < 4) {
+               ti->error = "requires 4 or more arguments";
                r = -EINVAL;
                goto bad;
        }
@@ -1204,6 +1257,13 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto bad;
        }
 
+       as.argc = argc;
+       as.argv = argv;
+       dm_consume_args(&as, 4);
+       r = parse_snapshot_features(&as, s, ti);
+       if (r)
+               goto bad_features;
+
        origin_path = argv[0];
        argv++;
        argc--;
@@ -1289,6 +1349,8 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
        ti->private = s;
        ti->num_flush_bios = num_flush_bios;
+       if (s->discard_zeroes_cow)
+               ti->num_discard_bios = (s->discard_passdown_origin ? 2 : 1);
        ti->per_io_data_size = sizeof(struct dm_snap_tracked_chunk);
 
        /* Add snapshot to the list of snapshots for this origin */
@@ -1336,29 +1398,22 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
 bad_read_metadata:
        unregister_snapshot(s);
-
 bad_load_and_register:
        mempool_exit(&s->pending_pool);
-
 bad_pending_pool:
        dm_kcopyd_client_destroy(s->kcopyd_client);
-
 bad_kcopyd:
        dm_exception_table_exit(&s->pending, pending_cache);
        dm_exception_table_exit(&s->complete, exception_cache);
-
 bad_hash_tables:
        dm_exception_store_destroy(s->store);
-
 bad_store:
        dm_put_device(ti, s->cow);
-
 bad_cow:
        dm_put_device(ti, s->origin);
-
 bad_origin:
+bad_features:
        kfree(s);
-
 bad:
        return r;
 }
@@ -1806,6 +1861,37 @@ static void remap_exception(struct dm_snapshot *s, struct dm_exception *e,
                (bio->bi_iter.bi_sector & s->store->chunk_mask);
 }
 
+static void zero_callback(int read_err, unsigned long write_err, void *context)
+{
+       struct bio *bio = context;
+       struct dm_snapshot *s = bio->bi_private;
+
+       up(&s->cow_count);
+       bio->bi_status = write_err ? BLK_STS_IOERR : 0;
+       bio_endio(bio);
+}
+
+static void zero_exception(struct dm_snapshot *s, struct dm_exception *e,
+                          struct bio *bio, chunk_t chunk)
+{
+       struct dm_io_region dest;
+
+       dest.bdev = s->cow->bdev;
+       dest.sector = bio->bi_iter.bi_sector;
+       dest.count = s->store->chunk_size;
+
+       down(&s->cow_count);
+       WARN_ON_ONCE(bio->bi_private);
+       bio->bi_private = s;
+       dm_kcopyd_zero(s->kcopyd_client, 1, &dest, 0, zero_callback, bio);
+}
+
+static bool io_overlaps_chunk(struct dm_snapshot *s, struct bio *bio)
+{
+       return bio->bi_iter.bi_size ==
+               (s->store->chunk_size << SECTOR_SHIFT);
+}
+
 static int snapshot_map(struct dm_target *ti, struct bio *bio)
 {
        struct dm_exception *e;
@@ -1839,10 +1925,43 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
                goto out_unlock;
        }
 
+       if (unlikely(bio_op(bio) == REQ_OP_DISCARD)) {
+               if (s->discard_passdown_origin && dm_bio_get_target_bio_nr(bio)) {
+                       /*
+                        * passdown discard to origin (without triggering
+                        * snapshot exceptions via do_origin; doing so would
+                        * defeat the goal of freeing space in origin that is
+                        * implied by the "discard_passdown_origin" feature)
+                        */
+                       bio_set_dev(bio, s->origin->bdev);
+                       track_chunk(s, bio, chunk);
+                       goto out_unlock;
+               }
+               /* discard to snapshot (target_bio_nr == 0) zeroes exceptions */
+       }
+
        /* If the block is already remapped - use that, else remap it */
        e = dm_lookup_exception(&s->complete, chunk);
        if (e) {
                remap_exception(s, e, bio, chunk);
+               if (unlikely(bio_op(bio) == REQ_OP_DISCARD) &&
+                   io_overlaps_chunk(s, bio)) {
+                       dm_exception_table_unlock(&lock);
+                       up_read(&s->lock);
+                       zero_exception(s, e, bio, chunk);
+                       r = DM_MAPIO_SUBMITTED; /* discard is not issued */
+                       goto out;
+               }
+               goto out_unlock;
+       }
+
+       if (unlikely(bio_op(bio) == REQ_OP_DISCARD)) {
+               /*
+                * If no exception exists, complete discard immediately
+                * otherwise it'll trigger copy-out.
+                */
+               bio_endio(bio);
+               r = DM_MAPIO_SUBMITTED;
                goto out_unlock;
        }
 
@@ -1890,9 +2009,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
 
                r = DM_MAPIO_SUBMITTED;
 
-               if (!pe->started &&
-                   bio->bi_iter.bi_size ==
-                   (s->store->chunk_size << SECTOR_SHIFT)) {
+               if (!pe->started && io_overlaps_chunk(s, bio)) {
                        pe->started = 1;
 
                        dm_exception_table_unlock(&lock);
@@ -2138,6 +2255,7 @@ static void snapshot_status(struct dm_target *ti, status_type_t type,
 {
        unsigned sz = 0;
        struct dm_snapshot *snap = ti->private;
+       unsigned num_features;
 
        switch (type) {
        case STATUSTYPE_INFO:
@@ -2178,8 +2296,16 @@ static void snapshot_status(struct dm_target *ti, status_type_t type,
                 * make sense.
                 */
                DMEMIT("%s %s", snap->origin->name, snap->cow->name);
-               snap->store->type->status(snap->store, type, result + sz,
-                                         maxlen - sz);
+               sz += snap->store->type->status(snap->store, type, result + sz,
+                                               maxlen - sz);
+               num_features = snap->discard_zeroes_cow + snap->discard_passdown_origin;
+               if (num_features) {
+                       DMEMIT(" %u", num_features);
+                       if (snap->discard_zeroes_cow)
+                               DMEMIT(" discard_zeroes_cow");
+                       if (snap->discard_passdown_origin)
+                               DMEMIT(" discard_passdown_origin");
+               }
                break;
        }
 }
@@ -2198,6 +2324,22 @@ static int snapshot_iterate_devices(struct dm_target *ti,
        return r;
 }
 
+static void snapshot_io_hints(struct dm_target *ti, struct queue_limits *limits)
+{
+       struct dm_snapshot *snap = ti->private;
+
+       if (snap->discard_zeroes_cow) {
+               struct dm_snapshot *snap_src = NULL, *snap_dest = NULL;
+
+               (void) __find_snapshots_sharing_cow(snap, &snap_src, &snap_dest, NULL);
+               if (snap_src && snap_dest)
+                       snap = snap_src;
+
+               /* All discards are split on chunk_size boundary */
+               limits->discard_granularity = snap->store->chunk_size;
+               limits->max_discard_sectors = snap->store->chunk_size;
+       }
+}
 
 /*-----------------------------------------------------------------
  * Origin methods
@@ -2522,7 +2664,7 @@ static struct target_type origin_target = {
 
 static struct target_type snapshot_target = {
        .name    = "snapshot",
-       .version = {1, 15, 0},
+       .version = {1, 16, 0},
        .module  = THIS_MODULE,
        .ctr     = snapshot_ctr,
        .dtr     = snapshot_dtr,
@@ -2532,11 +2674,12 @@ static struct target_type snapshot_target = {
        .resume  = snapshot_resume,
        .status  = snapshot_status,
        .iterate_devices = snapshot_iterate_devices,
+       .io_hints = snapshot_io_hints,
 };
 
 static struct target_type merge_target = {
        .name    = dm_snapshot_merge_target_name,
-       .version = {1, 4, 0},
+       .version = {1, 5, 0},
        .module  = THIS_MODULE,
        .ctr     = snapshot_ctr,
        .dtr     = snapshot_dtr,
@@ -2547,6 +2690,7 @@ static struct target_type merge_target = {
        .resume  = snapshot_merge_resume,
        .status  = snapshot_status,
        .iterate_devices = snapshot_iterate_devices,
+       .io_hints = snapshot_io_hints,
 };
 
 static int __init dm_snapshot_init(void)
index 7f08406..4c68a7b 100644 (file)
@@ -2046,16 +2046,19 @@ int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
 
 int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd)
 {
-       int r;
+       int r = -EINVAL;
        struct dm_block *sblock;
        struct thin_disk_superblock *disk_super;
 
        pmd_write_lock(pmd);
+       if (pmd->fail_io)
+               goto out;
+
        pmd->flags |= THIN_METADATA_NEEDS_CHECK_FLAG;
 
        r = superblock_lock(pmd, &sblock);
        if (r) {
-               DMERR("couldn't read superblock");
+               DMERR("couldn't lock superblock");
                goto out;
        }
 
index 392ad4f..dbdee02 100644 (file)
@@ -123,7 +123,7 @@ config FSL_IFC
 config JZ4780_NEMC
        bool "Ingenic JZ4780 SoC NEMC driver"
        default y
-       depends on MACH_JZ4780 || COMPILE_TEST
+       depends on MIPS || COMPILE_TEST
        depends on HAS_IOMEM && OF
        help
          This driver is for the NAND/External Memory Controller (NEMC) in
index 698da97..2a3f7ef 100644 (file)
 #define NEMC_NFCSR_NFCEn(n)    BIT((((n) - 1) << 1) + 1)
 #define NEMC_NFCSR_TNFEn(n)    BIT(16 + (n) - 1)
 
+struct jz_soc_info {
+       u8 tas_tah_cycles_max;
+};
+
 struct jz4780_nemc {
        spinlock_t lock;
        struct device *dev;
+       const struct jz_soc_info *soc_info;
        void __iomem *base;
        struct clk *clk;
        uint32_t clk_period;
@@ -158,7 +163,7 @@ static bool jz4780_nemc_configure_bank(struct jz4780_nemc *nemc,
         * Conversion of tBP and tAW cycle counts to values supported by the
         * hardware (round up to the next supported value).
         */
-       static const uint32_t convert_tBP_tAW[] = {
+       static const u8 convert_tBP_tAW[] = {
                0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
 
                /* 11 - 12 -> 12 cycles */
@@ -199,7 +204,7 @@ static bool jz4780_nemc_configure_bank(struct jz4780_nemc *nemc,
        if (of_property_read_u32(node, "ingenic,nemc-tAS", &val) == 0) {
                smcr &= ~NEMC_SMCR_TAS_MASK;
                cycles = jz4780_nemc_ns_to_cycles(nemc, val);
-               if (cycles > 15) {
+               if (cycles > nemc->soc_info->tas_tah_cycles_max) {
                        dev_err(nemc->dev, "tAS %u is too high (%u cycles)\n",
                                val, cycles);
                        return false;
@@ -211,7 +216,7 @@ static bool jz4780_nemc_configure_bank(struct jz4780_nemc *nemc,
        if (of_property_read_u32(node, "ingenic,nemc-tAH", &val) == 0) {
                smcr &= ~NEMC_SMCR_TAH_MASK;
                cycles = jz4780_nemc_ns_to_cycles(nemc, val);
-               if (cycles > 15) {
+               if (cycles > nemc->soc_info->tas_tah_cycles_max) {
                        dev_err(nemc->dev, "tAH %u is too high (%u cycles)\n",
                                val, cycles);
                        return false;
@@ -275,6 +280,10 @@ static int jz4780_nemc_probe(struct platform_device *pdev)
        if (!nemc)
                return -ENOMEM;
 
+       nemc->soc_info = device_get_match_data(dev);
+       if (!nemc->soc_info)
+               return -EINVAL;
+
        spin_lock_init(&nemc->lock);
        nemc->dev = dev;
 
@@ -367,8 +376,17 @@ static int jz4780_nemc_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct jz_soc_info jz4740_soc_info = {
+       .tas_tah_cycles_max = 7,
+};
+
+static const struct jz_soc_info jz4780_soc_info = {
+       .tas_tah_cycles_max = 15,
+};
+
 static const struct of_device_id jz4780_nemc_dt_match[] = {
-       { .compatible = "ingenic,jz4780-nemc" },
+       { .compatible = "ingenic,jz4740-nemc", .data = &jz4740_soc_info, },
+       { .compatible = "ingenic,jz4780-nemc", .data = &jz4780_soc_info, },
        {},
 };
 
index 6cfb293..693ee73 100644 (file)
@@ -625,13 +625,18 @@ static int __init memstick_init(void)
                return -ENOMEM;
 
        rc = bus_register(&memstick_bus_type);
-       if (!rc)
-               rc = class_register(&memstick_host_class);
+       if (rc)
+               goto error_destroy_workqueue;
 
-       if (!rc)
-               return 0;
+       rc = class_register(&memstick_host_class);
+       if (rc)
+               goto error_bus_unregister;
+
+       return 0;
 
+error_bus_unregister:
        bus_unregister(&memstick_bus_type);
+error_destroy_workqueue:
        destroy_workqueue(workqueue);
 
        return rc;
index d8882b0..c2dd322 100644 (file)
@@ -6001,13 +6001,12 @@ mpt_findImVolumes(MPT_ADAPTER *ioc)
        if (mpt_config(ioc, &cfg) != 0)
                goto out;
 
-       mem = kmalloc(iocpage2sz, GFP_KERNEL);
+       mem = kmemdup(pIoc2, iocpage2sz, GFP_KERNEL);
        if (!mem) {
                rc = -ENOMEM;
                goto out;
        }
 
-       memcpy(mem, (u8 *)pIoc2, iocpage2sz);
        ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
 
        mpt_read_ioc_pg_3(ioc);
index 8976f82..2ee14d8 100644 (file)
@@ -92,9 +92,9 @@ static struct regmap_config altr_sysmgr_regmap_cfg = {
  * Matching function used by driver_find_device().
  * Return: True if match is found, otherwise false.
  */
-static int sysmgr_match_phandle(struct device *dev, void *data)
+static int sysmgr_match_phandle(struct device *dev, const void *data)
 {
-       return dev->of_node == (struct device_node *)data;
+       return dev->of_node == (const struct device_node *)data;
 }
 
 /**
index 5d5c41a..2a9ac52 100644 (file)
@@ -102,12 +102,16 @@ static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event)
 
        /* For now, report failure to transition to S0ix with a warning. */
        if (ret >= 0 && ec_dev->host_sleep_v1 &&
-           (sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME))
+           (sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME)) {
+               ec_dev->last_resume_result =
+                       buf.u.resp1.resume_response.sleep_transitions;
+
                WARN_ONCE(buf.u.resp1.resume_response.sleep_transitions &
                          EC_HOST_RESUME_SLEEP_TIMEOUT,
                          "EC detected sleep transition timeout. Total slp_s0 transitions: %d",
                          buf.u.resp1.resume_response.sleep_transitions &
                          EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK);
+       }
 
        return ret;
 }
index 8ce1e41..b65e585 100644 (file)
@@ -190,27 +190,6 @@ struct regmap *syscon_regmap_lookup_by_compatible(const char *s)
 }
 EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible);
 
-static int syscon_match_pdevname(struct device *dev, void *data)
-{
-       return !strcmp(dev_name(dev), (const char *)data);
-}
-
-struct regmap *syscon_regmap_lookup_by_pdevname(const char *s)
-{
-       struct device *dev;
-       struct syscon *syscon;
-
-       dev = driver_find_device(&syscon_driver.driver, NULL, (void *)s,
-                                syscon_match_pdevname);
-       if (!dev)
-               return ERR_PTR(-EPROBE_DEFER);
-
-       syscon = dev_get_drvdata(dev);
-
-       return syscon->regmap;
-}
-EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_pdevname);
-
 struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
                                        const char *property)
 {
index 85fc771..6abfc8e 100644 (file)
@@ -9,7 +9,6 @@ config SENSORS_LIS3LV02D
        tristate
        depends on INPUT
        select INPUT_POLLDEV
-       default n
 
 config AD525X_DPOT
        tristate "Analog Devices Digital Potentiometers"
@@ -62,7 +61,6 @@ config ATMEL_TCLIB
 
 config DUMMY_IRQ
        tristate "Dummy IRQ handler"
-       default n
        ---help---
          This module accepts a single 'irq' parameter, which it should register for.
          The sole purpose of this module is to help with debugging of systems on
@@ -118,7 +116,6 @@ config PHANTOM
 config INTEL_MID_PTI
        tristate "Parallel Trace Interface for MIPI P1149.7 cJTAG standard"
        depends on PCI && TTY && (X86_INTEL_MID || COMPILE_TEST)
-       default n
        help
          The PTI (Parallel Trace Interface) driver directs
          trace data routed from various parts in the system out
@@ -194,7 +191,6 @@ config ATMEL_SSC
 
 config ENCLOSURE_SERVICES
        tristate "Enclosure Services"
-       default n
        help
          Provides support for intelligent enclosures (bays which
          contain storage devices).  You also need either a host
@@ -218,7 +214,6 @@ config SGI_XP
 config CS5535_MFGPT
        tristate "CS5535/CS5536 Geode Multi-Function General Purpose Timer (MFGPT) support"
        depends on MFD_CS5535
-       default n
        help
          This driver provides access to MFGPT functionality for other
          drivers that need timers.  MFGPTs are available in the CS5535 and
@@ -251,7 +246,6 @@ config CS5535_CLOCK_EVENT_SRC
 config HP_ILO
        tristate "Channel interface driver for the HP iLO processor"
        depends on PCI
-       default n
        help
          The channel interface driver allows applications to communicate
          with iLO management processors present on HP ProLiant servers.
@@ -286,7 +280,6 @@ config QCOM_FASTRPC
 config SGI_GRU
        tristate "SGI GRU driver"
        depends on X86_UV && SMP
-       default n
        select MMU_NOTIFIER
        ---help---
        The GRU is a hardware resource located in the system chipset. The GRU
@@ -301,7 +294,6 @@ config SGI_GRU
 config SGI_GRU_DEBUG
        bool  "SGI GRU driver debug"
        depends on SGI_GRU
-       default n
        ---help---
        This option enables additional debugging code for the SGI GRU driver.
        If you are unsure, say N.
@@ -359,7 +351,6 @@ config SENSORS_BH1770
 config SENSORS_APDS990X
         tristate "APDS990X combined als and proximity sensors"
         depends on I2C
-        default n
         ---help---
           Say Y here if you want to build a driver for Avago APDS990x
           combined ambient light and proximity sensor chip.
@@ -387,7 +378,6 @@ config DS1682
 config SPEAR13XX_PCIE_GADGET
        bool "PCIe gadget support for SPEAr13XX platform"
        depends on ARCH_SPEAR13XX && BROKEN
-       default n
        help
         This option enables gadget support for PCIe controller. If
         board file defines any controller as PCIe endpoint then a sysfs
@@ -397,6 +387,7 @@ config SPEAR13XX_PCIE_GADGET
 config VMWARE_BALLOON
        tristate "VMware Balloon Driver"
        depends on VMWARE_VMCI && X86 && HYPERVISOR_GUEST
+       select MEMORY_BALLOON
        help
          This is VMware physical memory management driver which acts
          like a "balloon" that can be inflated to reclaim physical pages
@@ -431,15 +422,6 @@ config PCH_PHUB
          To compile this driver as a module, choose M here: the module will
          be called pch_phub.
 
-config USB_SWITCH_FSA9480
-       tristate "FSA9480 USB Switch"
-       depends on I2C
-       help
-         The FSA9480 is a USB port accessory detector and switch.
-         The FSA9480 is fully controlled using I2C and enables USB data,
-         stereo and mono audio, video, microphone and UART data to use
-         a common connector port.
-
 config LATTICE_ECP3_CONFIG
        tristate "Lattice ECP3 FPGA bitstream configuration via SPI"
        depends on SPI && SYSFS
@@ -481,6 +463,18 @@ config PCI_ENDPOINT_TEST
            Enable this configuration option to enable the host side test driver
            for PCI Endpoint.
 
+config XILINX_SDFEC
+       tristate "Xilinx SDFEC 16"
+       help
+         This option enables support for the Xilinx SDFEC (Soft Decision
+         Forward Error Correction) driver. This enables a char driver
+         for the SDFEC.
+
+         You may select this driver if your design instantiates the
+         SDFEC(16nm) hardened block. To compile this as a module choose M.
+
+         If unsure, say N.
+
 config MISC_RTSX
        tristate
        default MISC_RTSX_PCI || MISC_RTSX_USB
index b9affcd..abd8ae2 100644 (file)
@@ -42,7 +42,6 @@ obj-$(CONFIG_VMWARE_BALLOON)  += vmw_balloon.o
 obj-$(CONFIG_PCH_PHUB)         += pch_phub.o
 obj-y                          += ti-st/
 obj-y                          += lis3lv02d/
-obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
 obj-$(CONFIG_ALTERA_STAPL)     +=altera-stapl/
 obj-$(CONFIG_INTEL_MEI)                += mei/
 obj-$(CONFIG_VMWARE_VMCI)      += vmw_vmci/
@@ -59,3 +58,4 @@ obj-$(CONFIG_OCXL)            += ocxl/
 obj-y                          += cardreader/
 obj-$(CONFIG_PVPANIC)          += pvpanic.o
 obj-$(CONFIG_HABANA_AI)                += habanalabs/
+obj-$(CONFIG_XILINX_SDFEC)     += xilinx_sdfec.o
index b348635..6c4c657 100644 (file)
@@ -5,6 +5,5 @@ comment "Altera FPGA firmware download module (requires I2C)"
 config ALTERA_STAPL
        tristate "Altera FPGA firmware download module"
        depends on I2C
-       default n
        help
          An Altera FPGA module. Say Y when you want to support this tool.
index 192e250..e20516f 100644 (file)
@@ -5,7 +5,6 @@
 
 menuconfig C2PORT
        tristate "Silicon Labs C2 port support"
-       default n
        help
          This option enables support for Silicon Labs C2 port used to
          program Silicon micro controller chips (and other 8051 compatible).
@@ -24,7 +23,6 @@ if C2PORT
 config C2PORT_DURAMAR_2150
        tristate "C2 port support for Eurotech's Duramar 2150"
        depends on X86
-       default n
        help
          This option enables C2 support for the Eurotech's Duramar 2150
          on board micro controller.
index 3c7356d..a696d75 100644 (file)
@@ -15,7 +15,6 @@ config CB710_CORE
 config CB710_DEBUG
        bool "Enable driver debugging"
        depends on CB710_CORE != n
-       default n
        help
          This is an option for use by developers; most people should
          say N here.  This adds a lot of debugging output to dmesg.
index f1d9a84..39eec90 100644 (file)
@@ -5,16 +5,13 @@
 
 config CXL_BASE
        bool
-       default n
        select PPC_COPRO_BASE
 
 config CXL_AFU_DRIVER_OPS
        bool
-       default n
 
 config CXL_LIB
        bool
-       default n
 
 config CXL
        tristate "Support for IBM Coherent Accelerators (CXL)"
index a73c9e6..5dc0f60 100644 (file)
@@ -908,11 +908,11 @@ void cxl_update_dedicated_ivtes_psl8(struct cxl_context *ctx);
 
 #ifdef CONFIG_DEBUG_FS
 
-int cxl_debugfs_init(void);
+void cxl_debugfs_init(void);
 void cxl_debugfs_exit(void);
-int cxl_debugfs_adapter_add(struct cxl *adapter);
+void cxl_debugfs_adapter_add(struct cxl *adapter);
 void cxl_debugfs_adapter_remove(struct cxl *adapter);
-int cxl_debugfs_afu_add(struct cxl_afu *afu);
+void cxl_debugfs_afu_add(struct cxl_afu *afu);
 void cxl_debugfs_afu_remove(struct cxl_afu *afu);
 void cxl_debugfs_add_adapter_regs_psl9(struct cxl *adapter, struct dentry *dir);
 void cxl_debugfs_add_adapter_regs_psl8(struct cxl *adapter, struct dentry *dir);
@@ -921,27 +921,24 @@ void cxl_debugfs_add_afu_regs_psl8(struct cxl_afu *afu, struct dentry *dir);
 
 #else /* CONFIG_DEBUG_FS */
 
-static inline int __init cxl_debugfs_init(void)
+static inline void __init cxl_debugfs_init(void)
 {
-       return 0;
 }
 
 static inline void cxl_debugfs_exit(void)
 {
 }
 
-static inline int cxl_debugfs_adapter_add(struct cxl *adapter)
+static inline void cxl_debugfs_adapter_add(struct cxl *adapter)
 {
-       return 0;
 }
 
 static inline void cxl_debugfs_adapter_remove(struct cxl *adapter)
 {
 }
 
-static inline int cxl_debugfs_afu_add(struct cxl_afu *afu)
+static inline void cxl_debugfs_afu_add(struct cxl_afu *afu)
 {
-       return 0;
 }
 
 static inline void cxl_debugfs_afu_remove(struct cxl_afu *afu)
index 1fda22c..7b987bf 100644 (file)
@@ -26,11 +26,11 @@ static int debugfs_io_u64_set(void *data, u64 val)
 DEFINE_DEBUGFS_ATTRIBUTE(fops_io_x64, debugfs_io_u64_get, debugfs_io_u64_set,
                         "0x%016llx\n");
 
-static struct dentry *debugfs_create_io_x64(const char *name, umode_t mode,
-                                           struct dentry *parent, u64 __iomem *value)
+static void debugfs_create_io_x64(const char *name, umode_t mode,
+                                 struct dentry *parent, u64 __iomem *value)
 {
-       return debugfs_create_file_unsafe(name, mode, parent,
-                                         (void __force *)value, &fops_io_x64);
+       debugfs_create_file_unsafe(name, mode, parent, (void __force *)value,
+                                  &fops_io_x64);
 }
 
 void cxl_debugfs_add_adapter_regs_psl9(struct cxl *adapter, struct dentry *dir)
@@ -54,25 +54,22 @@ void cxl_debugfs_add_adapter_regs_psl8(struct cxl *adapter, struct dentry *dir)
        debugfs_create_io_x64("trace", S_IRUSR | S_IWUSR, dir, _cxl_p1_addr(adapter, CXL_PSL_TRACE));
 }
 
-int cxl_debugfs_adapter_add(struct cxl *adapter)
+void cxl_debugfs_adapter_add(struct cxl *adapter)
 {
        struct dentry *dir;
        char buf[32];
 
        if (!cxl_debugfs)
-               return -ENODEV;
+               return;
 
        snprintf(buf, 32, "card%i", adapter->adapter_num);
        dir = debugfs_create_dir(buf, cxl_debugfs);
-       if (IS_ERR(dir))
-               return PTR_ERR(dir);
        adapter->debugfs = dir;
 
        debugfs_create_io_x64("err_ivte", S_IRUSR, dir, _cxl_p1_addr(adapter, CXL_PSL_ErrIVTE));
 
        if (adapter->native->sl_ops->debugfs_add_adapter_regs)
                adapter->native->sl_ops->debugfs_add_adapter_regs(adapter, dir);
-       return 0;
 }
 
 void cxl_debugfs_adapter_remove(struct cxl *adapter)
@@ -96,18 +93,16 @@ void cxl_debugfs_add_afu_regs_psl8(struct cxl_afu *afu, struct dentry *dir)
        debugfs_create_io_x64("trace", S_IRUSR | S_IWUSR, dir, _cxl_p1n_addr(afu, CXL_PSL_SLICE_TRACE));
 }
 
-int cxl_debugfs_afu_add(struct cxl_afu *afu)
+void cxl_debugfs_afu_add(struct cxl_afu *afu)
 {
        struct dentry *dir;
        char buf[32];
 
        if (!afu->adapter->debugfs)
-               return -ENODEV;
+               return;
 
        snprintf(buf, 32, "psl%i.%i", afu->adapter->adapter_num, afu->slice);
        dir = debugfs_create_dir(buf, afu->adapter->debugfs);
-       if (IS_ERR(dir))
-               return PTR_ERR(dir);
        afu->debugfs = dir;
 
        debugfs_create_io_x64("sr",         S_IRUSR, dir, _cxl_p1n_addr(afu, CXL_PSL_SR_An));
@@ -118,8 +113,6 @@ int cxl_debugfs_afu_add(struct cxl_afu *afu)
 
        if (afu->adapter->native->sl_ops->debugfs_add_afu_regs)
                afu->adapter->native->sl_ops->debugfs_add_afu_regs(afu, dir);
-
-       return 0;
 }
 
 void cxl_debugfs_afu_remove(struct cxl_afu *afu)
@@ -127,19 +120,12 @@ void cxl_debugfs_afu_remove(struct cxl_afu *afu)
        debugfs_remove_recursive(afu->debugfs);
 }
 
-int __init cxl_debugfs_init(void)
+void __init cxl_debugfs_init(void)
 {
-       struct dentry *ent;
-
        if (!cpu_has_feature(CPU_FTR_HVMODE))
-               return 0;
-
-       ent = debugfs_create_dir("cxl", NULL);
-       if (IS_ERR(ent))
-               return PTR_ERR(ent);
-       cxl_debugfs = ent;
+               return;
 
-       return 0;
+       cxl_debugfs = debugfs_create_dir("cxl", NULL);
 }
 
 void cxl_debugfs_exit(void)
index 3965641..be70b26 100644 (file)
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 config ECHO
        tristate "Line Echo Canceller support"
-       default n
        ---help---
          This driver provides line echo cancelling support for mISDN and
          Zaptel drivers.
index be3263d..6f00c33 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * ee1004 - driver for DDR4 SPD EEPROMs
  *
- * Copyright (C) 2017 Jean Delvare
+ * Copyright (C) 2017-2019 Jean Delvare
  *
  * Based on the at24 driver:
  * Copyright (C) 2005-2007 David Brownell
@@ -53,6 +53,24 @@ MODULE_DEVICE_TABLE(i2c, ee1004_ids);
 
 /*-------------------------------------------------------------------------*/
 
+static int ee1004_get_current_page(void)
+{
+       int err;
+
+       err = i2c_smbus_read_byte(ee1004_set_page[0]);
+       if (err == -ENXIO) {
+               /* Nack means page 1 is selected */
+               return 1;
+       }
+       if (err < 0) {
+               /* Anything else is a real error, bail out */
+               return err;
+       }
+
+       /* Ack means page 0 is selected, returned value meaningless */
+       return 0;
+}
+
 static ssize_t ee1004_eeprom_read(struct i2c_client *client, char *buf,
                                  unsigned int offset, size_t count)
 {
@@ -102,6 +120,16 @@ static ssize_t ee1004_read(struct file *filp, struct kobject *kobj,
                        /* Data is ignored */
                        status = i2c_smbus_write_byte(ee1004_set_page[page],
                                                      0x00);
+                       if (status == -ENXIO) {
+                               /*
+                                * Don't give up just yet. Some memory
+                                * modules will select the page but not
+                                * ack the command. Check which page is
+                                * selected now.
+                                */
+                               if (ee1004_get_current_page() == page)
+                                       status = 0;
+                       }
                        if (status < 0) {
                                dev_err(dev, "Failed to select page %d (%d)\n",
                                        page, status);
@@ -186,17 +214,10 @@ static int ee1004_probe(struct i2c_client *client,
        }
 
        /* Remember current page to avoid unneeded page select */
-       err = i2c_smbus_read_byte(ee1004_set_page[0]);
-       if (err == -ENXIO) {
-               /* Nack means page 1 is selected */
-               ee1004_current_page = 1;
-       } else if (err < 0) {
-               /* Anything else is a real error, bail out */
+       err = ee1004_get_current_page();
+       if (err < 0)
                goto err_clients;
-       } else {
-               /* Ack means page 0 is selected, returned value meaningless */
-               ee1004_current_page = 0;
-       }
+       ee1004_current_page = err;
        dev_dbg(&client->dev, "Currently selected page: %d\n",
                ee1004_current_page);
        mutex_unlock(&ee1004_bus_lock);
index 8a46595..81c70e5 100644 (file)
@@ -115,7 +115,6 @@ static struct dentry *csr_dbgdir;
  * @client:    i2c client used to perform IO operations
  *
  * @ee_file:   EEPROM read/write sysfs-file
- * @csr_file:  CSR read/write debugfs-node
  */
 struct idt_smb_seq;
 struct idt_89hpesx_dev {
@@ -137,7 +136,6 @@ struct idt_89hpesx_dev {
 
        struct bin_attribute *ee_file;
        struct dentry *csr_dir;
-       struct dentry *csr_file;
 };
 
 /*
@@ -1378,8 +1376,8 @@ static void idt_create_dbgfs_files(struct idt_89hpesx_dev *pdev)
        pdev->csr_dir = debugfs_create_dir(fname, csr_dbgdir);
 
        /* Create Debugfs file for CSR read/write operations */
-       pdev->csr_file = debugfs_create_file(cli->name, 0600,
-               pdev->csr_dir, pdev, &csr_dbgfs_ops);
+       debugfs_create_file(cli->name, 0600, pdev->csr_dir, pdev,
+                           &csr_dbgfs_ops);
 }
 
 /*
diff --git a/drivers/misc/fsa9480.c b/drivers/misc/fsa9480.c
deleted file mode 100644 (file)
index fab02f2..0000000
+++ /dev/null
@@ -1,547 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * fsa9480.c - FSA9480 micro USB switch device driver
- *
- * Copyright (C) 2010 Samsung Electronics
- * Minkyu Kang <mk7.kang@samsung.com>
- * Wonguk Jeong <wonguk.jeong@samsung.com>
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include <linux/platform_data/fsa9480.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
-
-/* FSA9480 I2C registers */
-#define FSA9480_REG_DEVID              0x01
-#define FSA9480_REG_CTRL               0x02
-#define FSA9480_REG_INT1               0x03
-#define FSA9480_REG_INT2               0x04
-#define FSA9480_REG_INT1_MASK          0x05
-#define FSA9480_REG_INT2_MASK          0x06
-#define FSA9480_REG_ADC                        0x07
-#define FSA9480_REG_TIMING1            0x08
-#define FSA9480_REG_TIMING2            0x09
-#define FSA9480_REG_DEV_T1             0x0a
-#define FSA9480_REG_DEV_T2             0x0b
-#define FSA9480_REG_BTN1               0x0c
-#define FSA9480_REG_BTN2               0x0d
-#define FSA9480_REG_CK                 0x0e
-#define FSA9480_REG_CK_INT1            0x0f
-#define FSA9480_REG_CK_INT2            0x10
-#define FSA9480_REG_CK_INTMASK1                0x11
-#define FSA9480_REG_CK_INTMASK2                0x12
-#define FSA9480_REG_MANSW1             0x13
-#define FSA9480_REG_MANSW2             0x14
-
-/* Control */
-#define CON_SWITCH_OPEN                (1 << 4)
-#define CON_RAW_DATA           (1 << 3)
-#define CON_MANUAL_SW          (1 << 2)
-#define CON_WAIT               (1 << 1)
-#define CON_INT_MASK           (1 << 0)
-#define CON_MASK               (CON_SWITCH_OPEN | CON_RAW_DATA | \
-                               CON_MANUAL_SW | CON_WAIT)
-
-/* Device Type 1 */
-#define DEV_USB_OTG            (1 << 7)
-#define DEV_DEDICATED_CHG      (1 << 6)
-#define DEV_USB_CHG            (1 << 5)
-#define DEV_CAR_KIT            (1 << 4)
-#define DEV_UART               (1 << 3)
-#define DEV_USB                        (1 << 2)
-#define DEV_AUDIO_2            (1 << 1)
-#define DEV_AUDIO_1            (1 << 0)
-
-#define DEV_T1_USB_MASK                (DEV_USB_OTG | DEV_USB)
-#define DEV_T1_UART_MASK       (DEV_UART)
-#define DEV_T1_CHARGER_MASK    (DEV_DEDICATED_CHG | DEV_USB_CHG)
-
-/* Device Type 2 */
-#define DEV_AV                 (1 << 6)
-#define DEV_TTY                        (1 << 5)
-#define DEV_PPD                        (1 << 4)
-#define DEV_JIG_UART_OFF       (1 << 3)
-#define DEV_JIG_UART_ON                (1 << 2)
-#define DEV_JIG_USB_OFF                (1 << 1)
-#define DEV_JIG_USB_ON         (1 << 0)
-
-#define DEV_T2_USB_MASK                (DEV_JIG_USB_OFF | DEV_JIG_USB_ON)
-#define DEV_T2_UART_MASK       (DEV_JIG_UART_OFF | DEV_JIG_UART_ON)
-#define DEV_T2_JIG_MASK                (DEV_JIG_USB_OFF | DEV_JIG_USB_ON | \
-                               DEV_JIG_UART_OFF | DEV_JIG_UART_ON)
-
-/*
- * Manual Switch
- * D- [7:5] / D+ [4:2]
- * 000: Open all / 001: USB / 010: AUDIO / 011: UART / 100: V_AUDIO
- */
-#define SW_VAUDIO              ((4 << 5) | (4 << 2))
-#define SW_UART                        ((3 << 5) | (3 << 2))
-#define SW_AUDIO               ((2 << 5) | (2 << 2))
-#define SW_DHOST               ((1 << 5) | (1 << 2))
-#define SW_AUTO                        ((0 << 5) | (0 << 2))
-
-/* Interrupt 1 */
-#define INT_DETACH             (1 << 1)
-#define INT_ATTACH             (1 << 0)
-
-struct fsa9480_usbsw {
-       struct i2c_client               *client;
-       struct fsa9480_platform_data    *pdata;
-       int                             dev1;
-       int                             dev2;
-       int                             mansw;
-};
-
-static struct fsa9480_usbsw *chip;
-
-static int fsa9480_write_reg(struct i2c_client *client,
-               int reg, int value)
-{
-       int ret;
-
-       ret = i2c_smbus_write_byte_data(client, reg, value);
-
-       if (ret < 0)
-               dev_err(&client->dev, "%s: err %d\n", __func__, ret);
-
-       return ret;
-}
-
-static int fsa9480_read_reg(struct i2c_client *client, int reg)
-{
-       int ret;
-
-       ret = i2c_smbus_read_byte_data(client, reg);
-
-       if (ret < 0)
-               dev_err(&client->dev, "%s: err %d\n", __func__, ret);
-
-       return ret;
-}
-
-static int fsa9480_read_irq(struct i2c_client *client, int *value)
-{
-       int ret;
-
-       ret = i2c_smbus_read_i2c_block_data(client,
-                       FSA9480_REG_INT1, 2, (u8 *)value);
-       *value &= 0xffff;
-
-       if (ret < 0)
-               dev_err(&client->dev, "%s: err %d\n", __func__, ret);
-
-       return ret;
-}
-
-static void fsa9480_set_switch(const char *buf)
-{
-       struct fsa9480_usbsw *usbsw = chip;
-       struct i2c_client *client = usbsw->client;
-       unsigned int value;
-       unsigned int path = 0;
-
-       value = fsa9480_read_reg(client, FSA9480_REG_CTRL);
-
-       if (!strncmp(buf, "VAUDIO", 6)) {
-               path = SW_VAUDIO;
-               value &= ~CON_MANUAL_SW;
-       } else if (!strncmp(buf, "UART", 4)) {
-               path = SW_UART;
-               value &= ~CON_MANUAL_SW;
-       } else if (!strncmp(buf, "AUDIO", 5)) {
-               path = SW_AUDIO;
-               value &= ~CON_MANUAL_SW;
-       } else if (!strncmp(buf, "DHOST", 5)) {
-               path = SW_DHOST;
-               value &= ~CON_MANUAL_SW;
-       } else if (!strncmp(buf, "AUTO", 4)) {
-               path = SW_AUTO;
-               value |= CON_MANUAL_SW;
-       } else {
-               printk(KERN_ERR "Wrong command\n");
-               return;
-       }
-
-       usbsw->mansw = path;
-       fsa9480_write_reg(client, FSA9480_REG_MANSW1, path);
-       fsa9480_write_reg(client, FSA9480_REG_CTRL, value);
-}
-
-static ssize_t fsa9480_get_switch(char *buf)
-{
-       struct fsa9480_usbsw *usbsw = chip;
-       struct i2c_client *client = usbsw->client;
-       unsigned int value;
-
-       value = fsa9480_read_reg(client, FSA9480_REG_MANSW1);
-
-       if (value == SW_VAUDIO)
-               return sprintf(buf, "VAUDIO\n");
-       else if (value == SW_UART)
-               return sprintf(buf, "UART\n");
-       else if (value == SW_AUDIO)
-               return sprintf(buf, "AUDIO\n");
-       else if (value == SW_DHOST)
-               return sprintf(buf, "DHOST\n");
-       else if (value == SW_AUTO)
-               return sprintf(buf, "AUTO\n");
-       else
-               return sprintf(buf, "%x", value);
-}
-
-static ssize_t fsa9480_show_device(struct device *dev,
-                                  struct device_attribute *attr,
-                                  char *buf)
-{
-       struct fsa9480_usbsw *usbsw = dev_get_drvdata(dev);
-       struct i2c_client *client = usbsw->client;
-       int dev1, dev2;
-
-       dev1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1);
-       dev2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2);
-
-       if (!dev1 && !dev2)
-               return sprintf(buf, "NONE\n");
-
-       /* USB */
-       if (dev1 & DEV_T1_USB_MASK || dev2 & DEV_T2_USB_MASK)
-               return sprintf(buf, "USB\n");
-
-       /* UART */
-       if (dev1 & DEV_T1_UART_MASK || dev2 & DEV_T2_UART_MASK)
-               return sprintf(buf, "UART\n");
-
-       /* CHARGER */
-       if (dev1 & DEV_T1_CHARGER_MASK)
-               return sprintf(buf, "CHARGER\n");
-
-       /* JIG */
-       if (dev2 & DEV_T2_JIG_MASK)
-               return sprintf(buf, "JIG\n");
-
-       return sprintf(buf, "UNKNOWN\n");
-}
-
-static ssize_t fsa9480_show_manualsw(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       return fsa9480_get_switch(buf);
-
-}
-
-static ssize_t fsa9480_set_manualsw(struct device *dev,
-                                   struct device_attribute *attr,
-                                   const char *buf, size_t count)
-{
-       fsa9480_set_switch(buf);
-
-       return count;
-}
-
-static DEVICE_ATTR(device, S_IRUGO, fsa9480_show_device, NULL);
-static DEVICE_ATTR(switch, S_IRUGO | S_IWUSR,
-               fsa9480_show_manualsw, fsa9480_set_manualsw);
-
-static struct attribute *fsa9480_attributes[] = {
-       &dev_attr_device.attr,
-       &dev_attr_switch.attr,
-       NULL
-};
-
-static const struct attribute_group fsa9480_group = {
-       .attrs = fsa9480_attributes,
-};
-
-static void fsa9480_detect_dev(struct fsa9480_usbsw *usbsw, int intr)
-{
-       int val1, val2, ctrl;
-       struct fsa9480_platform_data *pdata = usbsw->pdata;
-       struct i2c_client *client = usbsw->client;
-
-       val1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1);
-       val2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2);
-       ctrl = fsa9480_read_reg(client, FSA9480_REG_CTRL);
-
-       dev_info(&client->dev, "intr: 0x%x, dev1: 0x%x, dev2: 0x%x\n",
-                       intr, val1, val2);
-
-       if (!intr)
-               goto out;
-
-       if (intr & INT_ATTACH) {        /* Attached */
-               /* USB */
-               if (val1 & DEV_T1_USB_MASK || val2 & DEV_T2_USB_MASK) {
-                       if (pdata->usb_cb)
-                               pdata->usb_cb(FSA9480_ATTACHED);
-
-                       if (usbsw->mansw) {
-                               fsa9480_write_reg(client,
-                                       FSA9480_REG_MANSW1, usbsw->mansw);
-                       }
-               }
-
-               /* UART */
-               if (val1 & DEV_T1_UART_MASK || val2 & DEV_T2_UART_MASK) {
-                       if (pdata->uart_cb)
-                               pdata->uart_cb(FSA9480_ATTACHED);
-
-                       if (!(ctrl & CON_MANUAL_SW)) {
-                               fsa9480_write_reg(client,
-                                       FSA9480_REG_MANSW1, SW_UART);
-                       }
-               }
-
-               /* CHARGER */
-               if (val1 & DEV_T1_CHARGER_MASK) {
-                       if (pdata->charger_cb)
-                               pdata->charger_cb(FSA9480_ATTACHED);
-               }
-
-               /* JIG */
-               if (val2 & DEV_T2_JIG_MASK) {
-                       if (pdata->jig_cb)
-                               pdata->jig_cb(FSA9480_ATTACHED);
-               }
-       } else if (intr & INT_DETACH) { /* Detached */
-               /* USB */
-               if (usbsw->dev1 & DEV_T1_USB_MASK ||
-                       usbsw->dev2 & DEV_T2_USB_MASK) {
-                       if (pdata->usb_cb)
-                               pdata->usb_cb(FSA9480_DETACHED);
-               }
-
-               /* UART */
-               if (usbsw->dev1 & DEV_T1_UART_MASK ||
-                       usbsw->dev2 & DEV_T2_UART_MASK) {
-                       if (pdata->uart_cb)
-                               pdata->uart_cb(FSA9480_DETACHED);
-               }
-
-               /* CHARGER */
-               if (usbsw->dev1 & DEV_T1_CHARGER_MASK) {
-                       if (pdata->charger_cb)
-                               pdata->charger_cb(FSA9480_DETACHED);
-               }
-
-               /* JIG */
-               if (usbsw->dev2 & DEV_T2_JIG_MASK) {
-                       if (pdata->jig_cb)
-                               pdata->jig_cb(FSA9480_DETACHED);
-               }
-       }
-
-       usbsw->dev1 = val1;
-       usbsw->dev2 = val2;
-
-out:
-       ctrl &= ~CON_INT_MASK;
-       fsa9480_write_reg(client, FSA9480_REG_CTRL, ctrl);
-}
-
-static irqreturn_t fsa9480_irq_handler(int irq, void *data)
-{
-       struct fsa9480_usbsw *usbsw = data;
-       struct i2c_client *client = usbsw->client;
-       int intr;
-
-       /* clear interrupt */
-       fsa9480_read_irq(client, &intr);
-
-       /* device detection */
-       fsa9480_detect_dev(usbsw, intr);
-
-       return IRQ_HANDLED;
-}
-
-static int fsa9480_irq_init(struct fsa9480_usbsw *usbsw)
-{
-       struct fsa9480_platform_data *pdata = usbsw->pdata;
-       struct i2c_client *client = usbsw->client;
-       int ret;
-       int intr;
-       unsigned int ctrl = CON_MASK;
-
-       /* clear interrupt */
-       fsa9480_read_irq(client, &intr);
-
-       /* unmask interrupt (attach/detach only) */
-       fsa9480_write_reg(client, FSA9480_REG_INT1_MASK, 0xfc);
-       fsa9480_write_reg(client, FSA9480_REG_INT2_MASK, 0x1f);
-
-       usbsw->mansw = fsa9480_read_reg(client, FSA9480_REG_MANSW1);
-
-       if (usbsw->mansw)
-               ctrl &= ~CON_MANUAL_SW; /* Manual Switching Mode */
-
-       fsa9480_write_reg(client, FSA9480_REG_CTRL, ctrl);
-
-       if (pdata && pdata->cfg_gpio)
-               pdata->cfg_gpio();
-
-       if (client->irq) {
-               ret = request_threaded_irq(client->irq, NULL,
-                               fsa9480_irq_handler,
-                               IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-                               "fsa9480 micro USB", usbsw);
-               if (ret) {
-                       dev_err(&client->dev, "failed to request IRQ\n");
-                       return ret;
-               }
-
-               if (pdata)
-                       device_init_wakeup(&client->dev, pdata->wakeup);
-       }
-
-       return 0;
-}
-
-static int fsa9480_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
-{
-       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
-       struct fsa9480_usbsw *usbsw;
-       int ret = 0;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return -EIO;
-
-       usbsw = kzalloc(sizeof(struct fsa9480_usbsw), GFP_KERNEL);
-       if (!usbsw) {
-               dev_err(&client->dev, "failed to allocate driver data\n");
-               return -ENOMEM;
-       }
-
-       usbsw->client = client;
-       usbsw->pdata = client->dev.platform_data;
-
-       chip = usbsw;
-
-       i2c_set_clientdata(client, usbsw);
-
-       ret = fsa9480_irq_init(usbsw);
-       if (ret)
-               goto fail1;
-
-       ret = sysfs_create_group(&client->dev.kobj, &fsa9480_group);
-       if (ret) {
-               dev_err(&client->dev,
-                               "failed to create fsa9480 attribute group\n");
-               goto fail2;
-       }
-
-       /* ADC Detect Time: 500ms */
-       fsa9480_write_reg(client, FSA9480_REG_TIMING1, 0x6);
-
-       if (chip->pdata->reset_cb)
-               chip->pdata->reset_cb();
-
-       /* device detection */
-       fsa9480_detect_dev(usbsw, INT_ATTACH);
-
-       pm_runtime_set_active(&client->dev);
-
-       return 0;
-
-fail2:
-       if (client->irq)
-               free_irq(client->irq, usbsw);
-fail1:
-       kfree(usbsw);
-       return ret;
-}
-
-static int fsa9480_remove(struct i2c_client *client)
-{
-       struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client);
-
-       if (client->irq)
-               free_irq(client->irq, usbsw);
-
-       sysfs_remove_group(&client->dev.kobj, &fsa9480_group);
-       device_init_wakeup(&client->dev, 0);
-       kfree(usbsw);
-       return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-
-static int fsa9480_suspend(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client);
-       struct fsa9480_platform_data *pdata = usbsw->pdata;
-
-       if (device_may_wakeup(&client->dev) && client->irq)
-               enable_irq_wake(client->irq);
-
-       if (pdata->usb_power)
-               pdata->usb_power(0);
-
-       return 0;
-}
-
-static int fsa9480_resume(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client);
-       int dev1, dev2;
-
-       if (device_may_wakeup(&client->dev) && client->irq)
-               disable_irq_wake(client->irq);
-
-       /*
-        * Clear Pending interrupt. Note that detect_dev does what
-        * the interrupt handler does. So, we don't miss pending and
-        * we reenable interrupt if there is one.
-        */
-       fsa9480_read_reg(client, FSA9480_REG_INT1);
-       fsa9480_read_reg(client, FSA9480_REG_INT2);
-
-       dev1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1);
-       dev2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2);
-
-       /* device detection */
-       fsa9480_detect_dev(usbsw, (dev1 || dev2) ? INT_ATTACH : INT_DETACH);
-
-       return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(fsa9480_pm_ops, fsa9480_suspend, fsa9480_resume);
-#define FSA9480_PM_OPS (&fsa9480_pm_ops)
-
-#else
-
-#define FSA9480_PM_OPS NULL
-
-#endif /* CONFIG_PM_SLEEP */
-
-static const struct i2c_device_id fsa9480_id[] = {
-       {"fsa9480", 0},
-       {}
-};
-MODULE_DEVICE_TABLE(i2c, fsa9480_id);
-
-static struct i2c_driver fsa9480_i2c_driver = {
-       .driver = {
-               .name = "fsa9480",
-               .pm = FSA9480_PM_OPS,
-       },
-       .probe = fsa9480_probe,
-       .remove = fsa9480_remove,
-       .id_table = fsa9480_id,
-};
-
-module_i2c_driver(fsa9480_i2c_driver);
-
-MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>");
-MODULE_DESCRIPTION("FSA9480 USB Switch driver");
-MODULE_LICENSE("GPL");
index a8a6087..97f64bc 100644 (file)
@@ -7,7 +7,6 @@ menuconfig GENWQE
        tristate "GenWQE PCIe Accelerator"
        depends on PCI && 64BIT
        select CRC_ITU_T
-       default n
        help
          Enables PCIe card driver for IBM GenWQE accelerators.
          The user-space interface is described in
index ab7f2cd..1dc6c7c 100644 (file)
@@ -1369,10 +1369,6 @@ static int __init genwqe_init_module(void)
        class_genwqe->devnode = genwqe_devnode;
 
        debugfs_genwqe = debugfs_create_dir(GENWQE_DEVNAME, NULL);
-       if (!debugfs_genwqe) {
-               rc = -ENOMEM;
-               goto err_out;
-       }
 
        rc = pci_register_driver(&genwqe_driver);
        if (rc != 0) {
@@ -1384,7 +1380,6 @@ static int __init genwqe_init_module(void)
 
  err_out0:
        debugfs_remove(debugfs_genwqe);
- err_out:
        class_destroy(class_genwqe);
        return rc;
 }
index 2f6dd2f..0e90297 100644 (file)
@@ -437,7 +437,7 @@ int  genwqe_device_create(struct genwqe_dev *cd);
 int  genwqe_device_remove(struct genwqe_dev *cd);
 
 /* debugfs */
-int  genwqe_init_debugfs(struct genwqe_dev *cd);
+void genwqe_init_debugfs(struct genwqe_dev *cd);
 void genqwe_exit_debugfs(struct genwqe_dev *cd);
 
 int  genwqe_read_softreset(struct genwqe_dev *cd);
index 49c945d..1b5b82e 100644 (file)
@@ -316,11 +316,9 @@ static int info_show(struct seq_file *s, void *unused)
 
 DEFINE_SHOW_ATTRIBUTE(info);
 
-int genwqe_init_debugfs(struct genwqe_dev *cd)
+void genwqe_init_debugfs(struct genwqe_dev *cd)
 {
        struct dentry *root;
-       struct dentry *file;
-       int ret;
        char card_name[64];
        char name[64];
        unsigned int i;
@@ -328,153 +326,50 @@ int genwqe_init_debugfs(struct genwqe_dev *cd)
        sprintf(card_name, "%s%d_card", GENWQE_DEVNAME, cd->card_idx);
 
        root = debugfs_create_dir(card_name, cd->debugfs_genwqe);
-       if (!root) {
-               ret = -ENOMEM;
-               goto err0;
-       }
 
        /* non privileged interfaces are done here */
-       file = debugfs_create_file("ddcb_info", S_IRUGO, root, cd,
-                                  &ddcb_info_fops);
-       if (!file) {
-               ret = -ENOMEM;
-               goto err1;
-       }
-
-       file = debugfs_create_file("info", S_IRUGO, root, cd,
-                                  &info_fops);
-       if (!file) {
-               ret = -ENOMEM;
-               goto err1;
-       }
-
-       file = debugfs_create_x64("err_inject", 0666, root, &cd->err_inject);
-       if (!file) {
-               ret = -ENOMEM;
-               goto err1;
-       }
-
-       file = debugfs_create_u32("ddcb_software_timeout", 0666, root,
-                                 &cd->ddcb_software_timeout);
-       if (!file) {
-               ret = -ENOMEM;
-               goto err1;
-       }
-
-       file = debugfs_create_u32("kill_timeout", 0666, root,
-                                 &cd->kill_timeout);
-       if (!file) {
-               ret = -ENOMEM;
-               goto err1;
-       }
+       debugfs_create_file("ddcb_info", S_IRUGO, root, cd, &ddcb_info_fops);
+       debugfs_create_file("info", S_IRUGO, root, cd, &info_fops);
+       debugfs_create_x64("err_inject", 0666, root, &cd->err_inject);
+       debugfs_create_u32("ddcb_software_timeout", 0666, root,
+                          &cd->ddcb_software_timeout);
+       debugfs_create_u32("kill_timeout", 0666, root, &cd->kill_timeout);
 
        /* privileged interfaces follow here */
        if (!genwqe_is_privileged(cd)) {
                cd->debugfs_root = root;
-               return 0;
+               return;
        }
 
-       file = debugfs_create_file("curr_regs", S_IRUGO, root, cd,
-                                  &curr_regs_fops);
-       if (!file) {
-               ret = -ENOMEM;
-               goto err1;
-       }
-
-       file = debugfs_create_file("curr_dbg_uid0", S_IRUGO, root, cd,
-                                  &curr_dbg_uid0_fops);
-       if (!file) {
-               ret = -ENOMEM;
-               goto err1;
-       }
-
-       file = debugfs_create_file("curr_dbg_uid1", S_IRUGO, root, cd,
-                                  &curr_dbg_uid1_fops);
-       if (!file) {
-               ret = -ENOMEM;
-               goto err1;
-       }
-
-       file = debugfs_create_file("curr_dbg_uid2", S_IRUGO, root, cd,
-                                  &curr_dbg_uid2_fops);
-       if (!file) {
-               ret = -ENOMEM;
-               goto err1;
-       }
-
-       file = debugfs_create_file("prev_regs", S_IRUGO, root, cd,
-                                  &prev_regs_fops);
-       if (!file) {
-               ret = -ENOMEM;
-               goto err1;
-       }
-
-       file = debugfs_create_file("prev_dbg_uid0", S_IRUGO, root, cd,
-                                  &prev_dbg_uid0_fops);
-       if (!file) {
-               ret = -ENOMEM;
-               goto err1;
-       }
-
-       file = debugfs_create_file("prev_dbg_uid1", S_IRUGO, root, cd,
-                                  &prev_dbg_uid1_fops);
-       if (!file) {
-               ret = -ENOMEM;
-               goto err1;
-       }
-
-       file = debugfs_create_file("prev_dbg_uid2", S_IRUGO, root, cd,
-                                  &prev_dbg_uid2_fops);
-       if (!file) {
-               ret = -ENOMEM;
-               goto err1;
-       }
+       debugfs_create_file("curr_regs", S_IRUGO, root, cd, &curr_regs_fops);
+       debugfs_create_file("curr_dbg_uid0", S_IRUGO, root, cd,
+                           &curr_dbg_uid0_fops);
+       debugfs_create_file("curr_dbg_uid1", S_IRUGO, root, cd,
+                           &curr_dbg_uid1_fops);
+       debugfs_create_file("curr_dbg_uid2", S_IRUGO, root, cd,
+                           &curr_dbg_uid2_fops);
+       debugfs_create_file("prev_regs", S_IRUGO, root, cd, &prev_regs_fops);
+       debugfs_create_file("prev_dbg_uid0", S_IRUGO, root, cd,
+                           &prev_dbg_uid0_fops);
+       debugfs_create_file("prev_dbg_uid1", S_IRUGO, root, cd,
+                           &prev_dbg_uid1_fops);
+       debugfs_create_file("prev_dbg_uid2", S_IRUGO, root, cd,
+                           &prev_dbg_uid2_fops);
 
        for (i = 0; i <  GENWQE_MAX_VFS; i++) {
                sprintf(name, "vf%u_jobtimeout_msec", i);
-
-               file = debugfs_create_u32(name, 0666, root,
-                                         &cd->vf_jobtimeout_msec[i]);
-               if (!file) {
-                       ret = -ENOMEM;
-                       goto err1;
-               }
+               debugfs_create_u32(name, 0666, root,
+                                  &cd->vf_jobtimeout_msec[i]);
        }
 
-       file = debugfs_create_file("jobtimer", S_IRUGO, root, cd,
-                                  &jtimer_fops);
-       if (!file) {
-               ret = -ENOMEM;
-               goto err1;
-       }
-
-       file = debugfs_create_file("queue_working_time", S_IRUGO, root, cd,
-                                  &queue_working_time_fops);
-       if (!file) {
-               ret = -ENOMEM;
-               goto err1;
-       }
-
-       file = debugfs_create_u32("skip_recovery", 0666, root,
-                                 &cd->skip_recovery);
-       if (!file) {
-               ret = -ENOMEM;
-               goto err1;
-       }
-
-       file = debugfs_create_u32("use_platform_recovery", 0666, root,
-                                 &cd->use_platform_recovery);
-       if (!file) {
-               ret = -ENOMEM;
-               goto err1;
-       }
+       debugfs_create_file("jobtimer", S_IRUGO, root, cd, &jtimer_fops);
+       debugfs_create_file("queue_working_time", S_IRUGO, root, cd,
+                           &queue_working_time_fops);
+       debugfs_create_u32("skip_recovery", 0666, root, &cd->skip_recovery);
+       debugfs_create_u32("use_platform_recovery", 0666, root,
+                          &cd->use_platform_recovery);
 
        cd->debugfs_root = root;
-       return 0;
-err1:
-       debugfs_remove_recursive(root);
-err0:
-       return ret;
 }
 
 void genqwe_exit_debugfs(struct genwqe_dev *cd)
index 3bc51f1..0e34c05 100644 (file)
@@ -1301,14 +1301,10 @@ int genwqe_device_create(struct genwqe_dev *cd)
                goto err_cdev;
        }
 
-       rc = genwqe_init_debugfs(cd);
-       if (rc != 0)
-               goto err_debugfs;
+       genwqe_init_debugfs(cd);
 
        return 0;
 
- err_debugfs:
-       device_destroy(cd->class_genwqe, cd->devnum_genwqe);
  err_cdev:
        cdev_del(&cd->cdev_genwqe);
  err_add:
index f54e797..2c01461 100644 (file)
@@ -18,7 +18,7 @@ int hl_asid_init(struct hl_device *hdev)
 
        mutex_init(&hdev->asid_mutex);
 
-       /* ASID 0 is reserved for KMD */
+       /* ASID 0 is reserved for KMD and device CPU */
        set_bit(0, hdev->asid_bitmap);
 
        return 0;
index 6fe785e..6ad83d5 100644 (file)
@@ -682,14 +682,12 @@ int hl_cs_ioctl(struct hl_fpriv *hpriv, void *data)
                u32 tmp;
 
                rc = hl_poll_timeout_memory(hdev,
-                       (u64) (uintptr_t) &ctx->thread_ctx_switch_wait_token,
-                       jiffies_to_usecs(hdev->timeout_jiffies),
-                       &tmp);
+                       &ctx->thread_ctx_switch_wait_token, tmp, (tmp == 1),
+                       100, jiffies_to_usecs(hdev->timeout_jiffies));
 
-               if (rc || !tmp) {
+               if (rc == -ETIMEDOUT) {
                        dev_err(hdev->dev,
-                               "context switch phase didn't finish in time\n");
-                       rc = -ETIMEDOUT;
+                               "context switch phase timeout (%d)\n", tmp);
                        goto out;
                }
        }
index f4c92f1..8682590 100644 (file)
@@ -31,9 +31,13 @@ static void hl_ctx_fini(struct hl_ctx *ctx)
                 * Coresight might be still working by accessing addresses
                 * related to the stopped engines. Hence stop it explicitly.
                 */
-               hdev->asic_funcs->halt_coresight(hdev);
+               if (hdev->in_debug)
+                       hl_device_set_debug_mode(hdev, false);
+
                hl_vm_ctx_fini(ctx);
                hl_asid_free(hdev, ctx->asid);
+       } else {
+               hl_mmu_ctx_fini(ctx);
        }
 }
 
@@ -117,6 +121,11 @@ int hl_ctx_init(struct hl_device *hdev, struct hl_ctx *ctx, bool is_kernel_ctx)
 
        if (is_kernel_ctx) {
                ctx->asid = HL_KERNEL_ASID_ID; /* KMD gets ASID 0 */
+               rc = hl_mmu_ctx_init(ctx);
+               if (rc) {
+                       dev_err(hdev->dev, "Failed to init mmu ctx module\n");
+                       goto mem_ctx_err;
+               }
        } else {
                ctx->asid = hl_asid_alloc(hdev);
                if (!ctx->asid) {
index ba418aa..18e499c 100644 (file)
@@ -355,7 +355,7 @@ static int mmu_show(struct seq_file *s, void *data)
        struct hl_debugfs_entry *entry = s->private;
        struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
        struct hl_device *hdev = dev_entry->hdev;
-       struct hl_ctx *ctx = hdev->user_ctx;
+       struct hl_ctx *ctx;
 
        u64 hop0_addr = 0, hop0_pte_addr = 0, hop0_pte = 0,
                hop1_addr = 0, hop1_pte_addr = 0, hop1_pte = 0,
@@ -367,6 +367,11 @@ static int mmu_show(struct seq_file *s, void *data)
        if (!hdev->mmu_enable)
                return 0;
 
+       if (dev_entry->mmu_asid == HL_KERNEL_ASID_ID)
+               ctx = hdev->kernel_ctx;
+       else
+               ctx = hdev->user_ctx;
+
        if (!ctx) {
                dev_err(hdev->dev, "no ctx available\n");
                return 0;
@@ -495,6 +500,36 @@ err:
        return -EINVAL;
 }
 
+static int engines_show(struct seq_file *s, void *data)
+{
+       struct hl_debugfs_entry *entry = s->private;
+       struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
+       struct hl_device *hdev = dev_entry->hdev;
+
+       hdev->asic_funcs->is_device_idle(hdev, NULL, s);
+
+       return 0;
+}
+
+static bool hl_is_device_va(struct hl_device *hdev, u64 addr)
+{
+       struct asic_fixed_properties *prop = &hdev->asic_prop;
+
+       if (!hdev->mmu_enable)
+               goto out;
+
+       if (hdev->dram_supports_virtual_memory &&
+                       addr >= prop->va_space_dram_start_address &&
+                       addr < prop->va_space_dram_end_address)
+               return true;
+
+       if (addr >= prop->va_space_host_start_address &&
+                       addr < prop->va_space_host_end_address)
+               return true;
+out:
+       return false;
+}
+
 static int device_va_to_pa(struct hl_device *hdev, u64 virt_addr,
                                u64 *phys_addr)
 {
@@ -568,7 +603,6 @@ static ssize_t hl_data_read32(struct file *f, char __user *buf,
 {
        struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
        struct hl_device *hdev = entry->hdev;
-       struct asic_fixed_properties *prop = &hdev->asic_prop;
        char tmp_buf[32];
        u64 addr = entry->addr;
        u32 val;
@@ -577,11 +611,8 @@ static ssize_t hl_data_read32(struct file *f, char __user *buf,
        if (*ppos)
                return 0;
 
-       if (addr >= prop->va_space_dram_start_address &&
-                       addr < prop->va_space_dram_end_address &&
-                       hdev->mmu_enable &&
-                       hdev->dram_supports_virtual_memory) {
-               rc = device_va_to_pa(hdev, entry->addr, &addr);
+       if (hl_is_device_va(hdev, addr)) {
+               rc = device_va_to_pa(hdev, addr, &addr);
                if (rc)
                        return rc;
        }
@@ -602,7 +633,6 @@ static ssize_t hl_data_write32(struct file *f, const char __user *buf,
 {
        struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
        struct hl_device *hdev = entry->hdev;
-       struct asic_fixed_properties *prop = &hdev->asic_prop;
        u64 addr = entry->addr;
        u32 value;
        ssize_t rc;
@@ -611,11 +641,8 @@ static ssize_t hl_data_write32(struct file *f, const char __user *buf,
        if (rc)
                return rc;
 
-       if (addr >= prop->va_space_dram_start_address &&
-                       addr < prop->va_space_dram_end_address &&
-                       hdev->mmu_enable &&
-                       hdev->dram_supports_virtual_memory) {
-               rc = device_va_to_pa(hdev, entry->addr, &addr);
+       if (hl_is_device_va(hdev, addr)) {
+               rc = device_va_to_pa(hdev, addr, &addr);
                if (rc)
                        return rc;
        }
@@ -877,6 +904,7 @@ static const struct hl_info_list hl_debugfs_list[] = {
        {"userptr", userptr_show, NULL},
        {"vm", vm_show, NULL},
        {"mmu", mmu_show, mmu_write},
+       {"engines", engines_show, NULL}
 };
 
 static int hl_debugfs_open(struct inode *inode, struct file *file)
index 0b19d3e..0c4894d 100644 (file)
@@ -231,6 +231,7 @@ static int device_early_init(struct hl_device *hdev)
 
        mutex_init(&hdev->fd_open_cnt_lock);
        mutex_init(&hdev->send_cpu_message_lock);
+       mutex_init(&hdev->debug_lock);
        mutex_init(&hdev->mmu_cache_lock);
        INIT_LIST_HEAD(&hdev->hw_queues_mirror_list);
        spin_lock_init(&hdev->hw_queues_mirror_lock);
@@ -262,6 +263,7 @@ early_fini:
 static void device_early_fini(struct hl_device *hdev)
 {
        mutex_destroy(&hdev->mmu_cache_lock);
+       mutex_destroy(&hdev->debug_lock);
        mutex_destroy(&hdev->send_cpu_message_lock);
 
        hl_cb_mgr_fini(hdev, &hdev->kernel_cb_mgr);
@@ -324,7 +326,15 @@ static int device_late_init(struct hl_device *hdev)
 {
        int rc;
 
-       INIT_DELAYED_WORK(&hdev->work_freq, set_freq_to_low_job);
+       if (hdev->asic_funcs->late_init) {
+               rc = hdev->asic_funcs->late_init(hdev);
+               if (rc) {
+                       dev_err(hdev->dev,
+                               "failed late initialization for the H/W\n");
+                       return rc;
+               }
+       }
+
        hdev->high_pll = hdev->asic_prop.high_pll;
 
        /* force setting to low frequency */
@@ -335,17 +345,9 @@ static int device_late_init(struct hl_device *hdev)
        else
                hdev->asic_funcs->set_pll_profile(hdev, PLL_LAST);
 
-       if (hdev->asic_funcs->late_init) {
-               rc = hdev->asic_funcs->late_init(hdev);
-               if (rc) {
-                       dev_err(hdev->dev,
-                               "failed late initialization for the H/W\n");
-                       return rc;
-               }
-       }
-
+       INIT_DELAYED_WORK(&hdev->work_freq, set_freq_to_low_job);
        schedule_delayed_work(&hdev->work_freq,
-                       usecs_to_jiffies(HL_PLL_LOW_JOB_FREQ_USEC));
+       usecs_to_jiffies(HL_PLL_LOW_JOB_FREQ_USEC));
 
        if (hdev->heartbeat) {
                INIT_DELAYED_WORK(&hdev->work_heartbeat, hl_device_heartbeat);
@@ -420,6 +422,52 @@ int hl_device_set_frequency(struct hl_device *hdev, enum hl_pll_frequency freq)
        return 1;
 }
 
+int hl_device_set_debug_mode(struct hl_device *hdev, bool enable)
+{
+       int rc = 0;
+
+       mutex_lock(&hdev->debug_lock);
+
+       if (!enable) {
+               if (!hdev->in_debug) {
+                       dev_err(hdev->dev,
+                               "Failed to disable debug mode because device was not in debug mode\n");
+                       rc = -EFAULT;
+                       goto out;
+               }
+
+               hdev->asic_funcs->halt_coresight(hdev);
+               hdev->in_debug = 0;
+
+               goto out;
+       }
+
+       if (hdev->in_debug) {
+               dev_err(hdev->dev,
+                       "Failed to enable debug mode because device is already in debug mode\n");
+               rc = -EFAULT;
+               goto out;
+       }
+
+       mutex_lock(&hdev->fd_open_cnt_lock);
+
+       if (atomic_read(&hdev->fd_open_cnt) > 1) {
+               dev_err(hdev->dev,
+                       "Failed to enable debug mode. More then a single user is using the device\n");
+               rc = -EPERM;
+               goto unlock_fd_open_lock;
+       }
+
+       hdev->in_debug = 1;
+
+unlock_fd_open_lock:
+       mutex_unlock(&hdev->fd_open_cnt_lock);
+out:
+       mutex_unlock(&hdev->debug_lock);
+
+       return rc;
+}
+
 /*
  * hl_device_suspend - initiate device suspend
  *
@@ -647,13 +695,6 @@ again:
 
                hdev->hard_reset_pending = true;
 
-               if (!hdev->pdev) {
-                       dev_err(hdev->dev,
-                               "Reset action is NOT supported in simulator\n");
-                       rc = -EINVAL;
-                       goto out_err;
-               }
-
                device_reset_work = kzalloc(sizeof(*device_reset_work),
                                                GFP_ATOMIC);
                if (!device_reset_work) {
@@ -704,6 +745,7 @@ again:
 
        if (hard_reset) {
                hl_vm_fini(hdev);
+               hl_mmu_fini(hdev);
                hl_eq_reset(hdev, &hdev->event_queue);
        }
 
@@ -731,6 +773,13 @@ again:
                        goto out_err;
                }
 
+               rc = hl_mmu_init(hdev);
+               if (rc) {
+                       dev_err(hdev->dev,
+                               "Failed to initialize MMU S/W after hard reset\n");
+                       goto out_err;
+               }
+
                /* Allocate the kernel context */
                hdev->kernel_ctx = kzalloc(sizeof(*hdev->kernel_ctx),
                                                GFP_KERNEL);
@@ -902,11 +951,18 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass)
                goto cq_fini;
        }
 
+       /* MMU S/W must be initialized before kernel context is created */
+       rc = hl_mmu_init(hdev);
+       if (rc) {
+               dev_err(hdev->dev, "Failed to initialize MMU S/W structures\n");
+               goto eq_fini;
+       }
+
        /* Allocate the kernel context */
        hdev->kernel_ctx = kzalloc(sizeof(*hdev->kernel_ctx), GFP_KERNEL);
        if (!hdev->kernel_ctx) {
                rc = -ENOMEM;
-               goto eq_fini;
+               goto mmu_fini;
        }
 
        hdev->user_ctx = NULL;
@@ -954,8 +1010,6 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass)
                goto out_disabled;
        }
 
-       /* After test_queues, KMD can start sending messages to device CPU */
-
        rc = device_late_init(hdev);
        if (rc) {
                dev_err(hdev->dev, "Failed late initialization\n");
@@ -1001,6 +1055,8 @@ release_ctx:
                        "kernel ctx is still alive on initialization failure\n");
 free_ctx:
        kfree(hdev->kernel_ctx);
+mmu_fini:
+       hl_mmu_fini(hdev);
 eq_fini:
        hl_eq_fini(hdev, &hdev->event_queue);
 cq_fini:
@@ -1105,6 +1161,8 @@ void hl_device_fini(struct hl_device *hdev)
 
        hl_vm_fini(hdev);
 
+       hl_mmu_fini(hdev);
+
        hl_eq_fini(hdev, &hdev->event_queue);
 
        for (i = 0 ; i < hdev->asic_prop.completion_queues_count ; i++)
@@ -1125,95 +1183,6 @@ void hl_device_fini(struct hl_device *hdev)
        pr_info("removed device successfully\n");
 }
 
-/*
- * hl_poll_timeout_memory - Periodically poll a host memory address
- *                              until it is not zero or a timeout occurs
- * @hdev: pointer to habanalabs device structure
- * @addr: Address to poll
- * @timeout_us: timeout in us
- * @val: Variable to read the value into
- *
- * Returns 0 on success and -ETIMEDOUT upon a timeout. In either
- * case, the last read value at @addr is stored in @val. Must not
- * be called from atomic context if sleep_us or timeout_us are used.
- *
- * The function sleeps for 100us with timeout value of
- * timeout_us
- */
-int hl_poll_timeout_memory(struct hl_device *hdev, u64 addr,
-                               u32 timeout_us, u32 *val)
-{
-       /*
-        * address in this function points always to a memory location in the
-        * host's (server's) memory. That location is updated asynchronously
-        * either by the direct access of the device or by another core
-        */
-       u32 *paddr = (u32 *) (uintptr_t) addr;
-       ktime_t timeout;
-
-       /* timeout should be longer when working with simulator */
-       if (!hdev->pdev)
-               timeout_us *= 10;
-
-       timeout = ktime_add_us(ktime_get(), timeout_us);
-
-       might_sleep();
-
-       for (;;) {
-               /*
-                * Flush CPU read/write buffers to make sure we read updates
-                * done by other cores or by the device
-                */
-               mb();
-               *val = *paddr;
-               if (*val)
-                       break;
-               if (ktime_compare(ktime_get(), timeout) > 0) {
-                       *val = *paddr;
-                       break;
-               }
-               usleep_range((100 >> 2) + 1, 100);
-       }
-
-       return *val ? 0 : -ETIMEDOUT;
-}
-
-/*
- * hl_poll_timeout_devicememory - Periodically poll a device memory address
- *                                until it is not zero or a timeout occurs
- * @hdev: pointer to habanalabs device structure
- * @addr: Device address to poll
- * @timeout_us: timeout in us
- * @val: Variable to read the value into
- *
- * Returns 0 on success and -ETIMEDOUT upon a timeout. In either
- * case, the last read value at @addr is stored in @val. Must not
- * be called from atomic context if sleep_us or timeout_us are used.
- *
- * The function sleeps for 100us with timeout value of
- * timeout_us
- */
-int hl_poll_timeout_device_memory(struct hl_device *hdev, void __iomem *addr,
-                               u32 timeout_us, u32 *val)
-{
-       ktime_t timeout = ktime_add_us(ktime_get(), timeout_us);
-
-       might_sleep();
-
-       for (;;) {
-               *val = readl(addr);
-               if (*val)
-                       break;
-               if (ktime_compare(ktime_get(), timeout) > 0) {
-                       *val = readl(addr);
-                       break;
-               }
-               usleep_range((100 >> 2) + 1, 100);
-       }
-
-       return *val ? 0 : -ETIMEDOUT;
-}
-
 /*
  * MMIO register access helper functions.
  */
index eda5d7f..cc8168b 100644 (file)
@@ -29,13 +29,13 @@ int hl_fw_push_fw_to_device(struct hl_device *hdev, const char *fw_name,
 
        rc = request_firmware(&fw, fw_name, hdev->dev);
        if (rc) {
-               dev_err(hdev->dev, "Failed to request %s\n", fw_name);
+               dev_err(hdev->dev, "Firmware file %s is not found!\n", fw_name);
                goto out;
        }
 
        fw_size = fw->size;
        if ((fw_size % 4) != 0) {
-               dev_err(hdev->dev, "illegal %s firmware size %zu\n",
+               dev_err(hdev->dev, "Illegal %s firmware size %zu\n",
                        fw_name, fw_size);
                rc = -EINVAL;
                goto out;
@@ -85,12 +85,6 @@ int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg,
        u32 tmp;
        int rc = 0;
 
-       if (len > HL_CPU_CB_SIZE) {
-               dev_err(hdev->dev, "Invalid CPU message size of %d bytes\n",
-                       len);
-               return -ENOMEM;
-       }
-
        pkt = hdev->asic_funcs->cpu_accessible_dma_pool_alloc(hdev, len,
                                                                &pkt_dma_addr);
        if (!pkt) {
@@ -117,33 +111,28 @@ int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg,
                goto out;
        }
 
-       rc = hl_poll_timeout_memory(hdev, (u64) (uintptr_t) &pkt->fence,
-                                       timeout, &tmp);
+       rc = hl_poll_timeout_memory(hdev, &pkt->fence, tmp,
+                               (tmp == ARMCP_PACKET_FENCE_VAL), 1000, timeout);
 
        hl_hw_queue_inc_ci_kernel(hdev, hw_queue_id);
 
        if (rc == -ETIMEDOUT) {
-               dev_err(hdev->dev, "Timeout while waiting for device CPU\n");
+               dev_err(hdev->dev, "Device CPU packet timeout (0x%x)\n", tmp);
                hdev->device_cpu_disabled = true;
                goto out;
        }
 
-       if (tmp == ARMCP_PACKET_FENCE_VAL) {
-               u32 ctl = le32_to_cpu(pkt->ctl);
+       tmp = le32_to_cpu(pkt->ctl);
 
-               rc = (ctl & ARMCP_PKT_CTL_RC_MASK) >> ARMCP_PKT_CTL_RC_SHIFT;
-               if (rc) {
-                       dev_err(hdev->dev,
-                               "F/W ERROR %d for CPU packet %d\n",
-                               rc, (ctl & ARMCP_PKT_CTL_OPCODE_MASK)
+       rc = (tmp & ARMCP_PKT_CTL_RC_MASK) >> ARMCP_PKT_CTL_RC_SHIFT;
+       if (rc) {
+               dev_err(hdev->dev, "F/W ERROR %d for CPU packet %d\n",
+                       rc,
+                       (tmp & ARMCP_PKT_CTL_OPCODE_MASK)
                                                >> ARMCP_PKT_CTL_OPCODE_SHIFT);
-                       rc = -EINVAL;
-               } else if (result) {
-                       *result = (long) le64_to_cpu(pkt->result);
-               }
-       } else {
-               dev_err(hdev->dev, "CPU packet wrong fence value\n");
-               rc = -EINVAL;
+               rc = -EIO;
+       } else if (result) {
+               *result = (long) le64_to_cpu(pkt->result);
        }
 
 out:
@@ -186,9 +175,6 @@ void *hl_fw_cpu_accessible_dma_pool_alloc(struct hl_device *hdev, size_t size,
 {
        u64 kernel_addr;
 
-       /* roundup to HL_CPU_PKT_SIZE */
-       size = (size + (HL_CPU_PKT_SIZE - 1)) & HL_CPU_PKT_MASK;
-
        kernel_addr = gen_pool_alloc(hdev->cpu_accessible_dma_pool, size);
 
        *dma_handle = hdev->cpu_accessible_dma_address +
@@ -200,9 +186,6 @@ void *hl_fw_cpu_accessible_dma_pool_alloc(struct hl_device *hdev, size_t size,
 void hl_fw_cpu_accessible_dma_pool_free(struct hl_device *hdev, size_t size,
                                        void *vaddr)
 {
-       /* roundup to HL_CPU_PKT_SIZE */
-       size = (size + (HL_CPU_PKT_SIZE - 1)) & HL_CPU_PKT_MASK;
-
        gen_pool_free(hdev->cpu_accessible_dma_pool, (u64) (uintptr_t) vaddr,
                        size);
 }
@@ -256,7 +239,7 @@ int hl_fw_armcp_info_get(struct hl_device *hdev)
                                        HL_ARMCP_INFO_TIMEOUT_USEC, &result);
        if (rc) {
                dev_err(hdev->dev,
-                       "Failed to send armcp info pkt, error %d\n", rc);
+                       "Failed to send ArmCP info pkt, error %d\n", rc);
                goto out;
        }
 
@@ -291,7 +274,7 @@ int hl_fw_get_eeprom_data(struct hl_device *hdev, void *data, size_t max_size)
                                        max_size, &eeprom_info_dma_addr);
        if (!eeprom_info_cpu_addr) {
                dev_err(hdev->dev,
-                       "Failed to allocate DMA memory for EEPROM info packet\n");
+                       "Failed to allocate DMA memory for ArmCP EEPROM packet\n");
                return -ENOMEM;
        }
 
@@ -307,7 +290,7 @@ int hl_fw_get_eeprom_data(struct hl_device *hdev, void *data, size_t max_size)
 
        if (rc) {
                dev_err(hdev->dev,
-                       "Failed to send armcp EEPROM pkt, error %d\n", rc);
+                       "Failed to send ArmCP EEPROM packet, error %d\n", rc);
                goto out;
        }
 
index 02d116b..75294ec 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/genalloc.h>
 #include <linux/hwmon.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/iommu.h>
+#include <linux/seq_file.h>
 
 /*
  * GOYA security scheme:
 #define GOYA_CB_POOL_CB_CNT            512
 #define GOYA_CB_POOL_CB_SIZE           0x20000         /* 128KB */
 
+#define IS_QM_IDLE(engine, qm_glbl_sts0) \
+       (((qm_glbl_sts0) & engine##_QM_IDLE_MASK) == engine##_QM_IDLE_MASK)
+#define IS_DMA_QM_IDLE(qm_glbl_sts0)   IS_QM_IDLE(DMA, qm_glbl_sts0)
+#define IS_TPC_QM_IDLE(qm_glbl_sts0)   IS_QM_IDLE(TPC, qm_glbl_sts0)
+#define IS_MME_QM_IDLE(qm_glbl_sts0)   IS_QM_IDLE(MME, qm_glbl_sts0)
+
+#define IS_CMDQ_IDLE(engine, cmdq_glbl_sts0) \
+       (((cmdq_glbl_sts0) & engine##_CMDQ_IDLE_MASK) == \
+                       engine##_CMDQ_IDLE_MASK)
+#define IS_TPC_CMDQ_IDLE(cmdq_glbl_sts0) \
+       IS_CMDQ_IDLE(TPC, cmdq_glbl_sts0)
+#define IS_MME_CMDQ_IDLE(cmdq_glbl_sts0) \
+       IS_CMDQ_IDLE(MME, cmdq_glbl_sts0)
+
+#define IS_DMA_IDLE(dma_core_sts0) \
+       !((dma_core_sts0) & DMA_CH_0_STS0_DMA_BUSY_MASK)
+
+#define IS_TPC_IDLE(tpc_cfg_sts) \
+       (((tpc_cfg_sts) & TPC_CFG_IDLE_MASK) == TPC_CFG_IDLE_MASK)
+
+#define IS_MME_IDLE(mme_arch_sts) \
+       (((mme_arch_sts) & MME_ARCH_IDLE_MASK) == MME_ARCH_IDLE_MASK)
+
+
 static const char goya_irq_name[GOYA_MSIX_ENTRIES][GOYA_MAX_STRING_LEN] = {
                "goya cq 0", "goya cq 1", "goya cq 2", "goya cq 3",
                "goya cq 4", "goya cpu eq"
@@ -297,6 +323,11 @@ static u32 goya_all_events[] = {
        GOYA_ASYNC_EVENT_ID_DMA_BM_CH4
 };
 
+static int goya_mmu_clear_pgt_range(struct hl_device *hdev);
+static int goya_mmu_set_dram_default_page(struct hl_device *hdev);
+static int goya_mmu_add_mappings_for_device_cpu(struct hl_device *hdev);
+static void goya_mmu_prepare(struct hl_device *hdev, u32 asid);
+
 void goya_get_fixed_properties(struct hl_device *hdev)
 {
        struct asic_fixed_properties *prop = &hdev->asic_prop;
@@ -467,7 +498,7 @@ static int goya_early_init(struct hl_device *hdev)
 
        prop->dram_pci_bar_size = pci_resource_len(pdev, DDR_BAR_ID);
 
-       rc = hl_pci_init(hdev, 39);
+       rc = hl_pci_init(hdev, 48);
        if (rc)
                return rc;
 
@@ -539,9 +570,36 @@ int goya_late_init(struct hl_device *hdev)
        struct asic_fixed_properties *prop = &hdev->asic_prop;
        int rc;
 
+       goya_fetch_psoc_frequency(hdev);
+
+       rc = goya_mmu_clear_pgt_range(hdev);
+       if (rc) {
+               dev_err(hdev->dev,
+                       "Failed to clear MMU page tables range %d\n", rc);
+               return rc;
+       }
+
+       rc = goya_mmu_set_dram_default_page(hdev);
+       if (rc) {
+               dev_err(hdev->dev, "Failed to set DRAM default page %d\n", rc);
+               return rc;
+       }
+
+       rc = goya_mmu_add_mappings_for_device_cpu(hdev);
+       if (rc)
+               return rc;
+
+       rc = goya_init_cpu_queues(hdev);
+       if (rc)
+               return rc;
+
+       rc = goya_test_cpu_queue(hdev);
+       if (rc)
+               return rc;
+
        rc = goya_armcp_info_get(hdev);
        if (rc) {
-               dev_err(hdev->dev, "Failed to get armcp info\n");
+               dev_err(hdev->dev, "Failed to get armcp info %d\n", rc);
                return rc;
        }
 
@@ -553,33 +611,15 @@ int goya_late_init(struct hl_device *hdev)
 
        rc = hl_fw_send_pci_access_msg(hdev, ARMCP_PACKET_ENABLE_PCI_ACCESS);
        if (rc) {
-               dev_err(hdev->dev, "Failed to enable PCI access from CPU\n");
+               dev_err(hdev->dev,
+                       "Failed to enable PCI access from CPU %d\n", rc);
                return rc;
        }
 
        WREG32(mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR,
                        GOYA_ASYNC_EVENT_ID_INTS_REGISTER);
 
-       goya_fetch_psoc_frequency(hdev);
-
-       rc = goya_mmu_clear_pgt_range(hdev);
-       if (rc) {
-               dev_err(hdev->dev, "Failed to clear MMU page tables range\n");
-               goto disable_pci_access;
-       }
-
-       rc = goya_mmu_set_dram_default_page(hdev);
-       if (rc) {
-               dev_err(hdev->dev, "Failed to set DRAM default page\n");
-               goto disable_pci_access;
-       }
-
        return 0;
-
-disable_pci_access:
-       hl_fw_send_pci_access_msg(hdev, ARMCP_PACKET_DISABLE_PCI_ACCESS);
-
-       return rc;
 }
 
 /*
@@ -655,7 +695,10 @@ static int goya_sw_init(struct hl_device *hdev)
                goto free_dma_pool;
        }
 
-       hdev->cpu_accessible_dma_pool = gen_pool_create(HL_CPU_PKT_SHIFT, -1);
+       dev_dbg(hdev->dev, "cpu accessible memory at bus address 0x%llx\n",
+               hdev->cpu_accessible_dma_address);
+
+       hdev->cpu_accessible_dma_pool = gen_pool_create(ilog2(32), -1);
        if (!hdev->cpu_accessible_dma_pool) {
                dev_err(hdev->dev,
                        "Failed to create CPU accessible DMA pool\n");
@@ -786,7 +829,6 @@ static void goya_init_dma_ch(struct hl_device *hdev, int dma_id)
        else
                sob_addr = CFG_BASE + mmSYNC_MNGR_SOB_OBJ_1007;
 
-       WREG32(mmDMA_CH_0_WR_COMP_ADDR_LO + reg_off, lower_32_bits(sob_addr));
        WREG32(mmDMA_CH_0_WR_COMP_ADDR_HI + reg_off, upper_32_bits(sob_addr));
        WREG32(mmDMA_CH_0_WR_COMP_WDATA + reg_off, 0x80000001);
 }
@@ -973,9 +1015,9 @@ int goya_init_cpu_queues(struct hl_device *hdev)
        WREG32(mmPSOC_GLOBAL_CONF_SCRATCHPAD_3, upper_32_bits(eq->bus_address));
 
        WREG32(mmPSOC_GLOBAL_CONF_SCRATCHPAD_8,
-                       lower_32_bits(hdev->cpu_accessible_dma_address));
+                       lower_32_bits(VA_CPU_ACCESSIBLE_MEM_ADDR));
        WREG32(mmPSOC_GLOBAL_CONF_SCRATCHPAD_9,
-                       upper_32_bits(hdev->cpu_accessible_dma_address));
+                       upper_32_bits(VA_CPU_ACCESSIBLE_MEM_ADDR));
 
        WREG32(mmPSOC_GLOBAL_CONF_SCRATCHPAD_5, HL_QUEUE_SIZE_IN_BYTES);
        WREG32(mmPSOC_GLOBAL_CONF_SCRATCHPAD_4, HL_EQ_SIZE_IN_BYTES);
@@ -1001,7 +1043,7 @@ int goya_init_cpu_queues(struct hl_device *hdev)
 
        if (err) {
                dev_err(hdev->dev,
-                       "Failed to communicate with ARM CPU (ArmCP timeout)\n");
+                       "Failed to setup communication with device CPU\n");
                return -EIO;
        }
 
@@ -2061,10 +2103,12 @@ static void goya_halt_engines(struct hl_device *hdev, bool hard_reset)
        goya_disable_external_queues(hdev);
        goya_disable_internal_queues(hdev);
 
-       if (hard_reset)
+       if (hard_reset) {
                goya_disable_msix(hdev);
-       else
+               goya_mmu_remove_device_cpu_mappings(hdev);
+       } else {
                goya_sync_irqs(hdev);
+       }
 }
 
 /*
@@ -2277,14 +2321,14 @@ static int goya_init_cpu(struct hl_device *hdev, u32 cpu_timeout)
        goya_read_device_fw_version(hdev, FW_COMP_UBOOT);
        goya_read_device_fw_version(hdev, FW_COMP_PREBOOT);
 
-       if (status == CPU_BOOT_STATUS_SRAM_AVAIL)
-               goto out;
-
        if (!hdev->fw_loading) {
                dev_info(hdev->dev, "Skip loading FW\n");
                goto out;
        }
 
+       if (status == CPU_BOOT_STATUS_SRAM_AVAIL)
+               goto out;
+
        rc = goya_push_linux_to_device(hdev);
        if (rc)
                return rc;
@@ -2466,34 +2510,11 @@ static int goya_hw_init(struct hl_device *hdev)
        if (rc)
                goto disable_queues;
 
-       rc = goya_init_cpu_queues(hdev);
-       if (rc) {
-               dev_err(hdev->dev, "failed to initialize CPU H/W queues %d\n",
-                       rc);
-               goto disable_msix;
-       }
-
-       /*
-        * Check if we managed to set the DMA mask to more then 32 bits. If so,
-        * let's try to increase it again because in Goya we set the initial
-        * dma mask to less then 39 bits so that the allocation of the memory
-        * area for the device's cpu will be under 39 bits
-        */
-       if (hdev->dma_mask > 32) {
-               rc = hl_pci_set_dma_mask(hdev, 48);
-               if (rc)
-                       goto disable_pci_access;
-       }
-
        /* Perform read from the device to flush all MSI-X configuration */
        val = RREG32(mmPCIE_DBI_DEVICE_ID_VENDOR_ID_REG);
 
        return 0;
 
-disable_pci_access:
-       hl_fw_send_pci_access_msg(hdev, ARMCP_PACKET_DISABLE_PCI_ACCESS);
-disable_msix:
-       goya_disable_msix(hdev);
 disable_queues:
        goya_disable_internal_queues(hdev);
        goya_disable_external_queues(hdev);
@@ -2629,7 +2650,6 @@ static int goya_cb_mmap(struct hl_device *hdev, struct vm_area_struct *vma,
 void goya_ring_doorbell(struct hl_device *hdev, u32 hw_queue_id, u32 pi)
 {
        u32 db_reg_offset, db_value;
-       bool invalid_queue = false;
 
        switch (hw_queue_id) {
        case GOYA_QUEUE_ID_DMA_0:
@@ -2653,10 +2673,7 @@ void goya_ring_doorbell(struct hl_device *hdev, u32 hw_queue_id, u32 pi)
                break;
 
        case GOYA_QUEUE_ID_CPU_PQ:
-               if (hdev->cpu_queues_enable)
-                       db_reg_offset = mmCPU_IF_PF_PQ_PI;
-               else
-                       invalid_queue = true;
+               db_reg_offset = mmCPU_IF_PF_PQ_PI;
                break;
 
        case GOYA_QUEUE_ID_MME:
@@ -2696,12 +2713,8 @@ void goya_ring_doorbell(struct hl_device *hdev, u32 hw_queue_id, u32 pi)
                break;
 
        default:
-               invalid_queue = true;
-       }
-
-       if (invalid_queue) {
                /* Should never get here */
-               dev_err(hdev->dev, "h/w queue %d is invalid. Can't set pi\n",
+               dev_err(hdev->dev, "H/W queue %d is invalid. Can't set pi\n",
                        hw_queue_id);
                return;
        }
@@ -2808,7 +2821,6 @@ static int goya_send_job_on_qman0(struct hl_device *hdev, struct hl_cs_job *job)
        dma_addr_t fence_dma_addr;
        struct hl_cb *cb;
        u32 tmp, timeout;
-       char buf[16] = {};
        int rc;
 
        if (hdev->pldm)
@@ -2816,10 +2828,9 @@ static int goya_send_job_on_qman0(struct hl_device *hdev, struct hl_cs_job *job)
        else
                timeout = HL_DEVICE_TIMEOUT_USEC;
 
-       if (!hdev->asic_funcs->is_device_idle(hdev, buf, sizeof(buf))) {
+       if (!hdev->asic_funcs->is_device_idle(hdev, NULL, NULL)) {
                dev_err_ratelimited(hdev->dev,
-                       "Can't send KMD job on QMAN0 because %s is busy\n",
-                       buf);
+                       "Can't send KMD job on QMAN0 because the device is not idle\n");
                return -EBUSY;
        }
 
@@ -2831,16 +2842,8 @@ static int goya_send_job_on_qman0(struct hl_device *hdev, struct hl_cs_job *job)
                return -ENOMEM;
        }
 
-       *fence_ptr = 0;
-
        goya_qman0_set_security(hdev, true);
 
-       /*
-        * goya cs parser saves space for 2xpacket_msg_prot at end of CB. For
-        * synchronized kernel jobs we only need space for 1 packet_msg_prot
-        */
-       job->job_cb_size -= sizeof(struct packet_msg_prot);
-
        cb = job->patched_cb;
 
        fence_pkt = (struct packet_msg_prot *) (uintptr_t) (cb->kernel_address +
@@ -2860,14 +2863,14 @@ static int goya_send_job_on_qman0(struct hl_device *hdev, struct hl_cs_job *job)
                goto free_fence_ptr;
        }
 
-       rc = hl_poll_timeout_memory(hdev, (u64) (uintptr_t) fence_ptr, timeout,
-                                       &tmp);
+       rc = hl_poll_timeout_memory(hdev, fence_ptr, tmp,
+                               (tmp == GOYA_QMAN0_FENCE_VAL), 1000, timeout);
 
        hl_hw_queue_inc_ci_kernel(hdev, GOYA_QUEUE_ID_DMA_0);
 
-       if ((rc) || (tmp != GOYA_QMAN0_FENCE_VAL)) {
-               dev_err(hdev->dev, "QMAN0 Job hasn't finished in time\n");
-               rc = -ETIMEDOUT;
+       if (rc == -ETIMEDOUT) {
+               dev_err(hdev->dev, "QMAN0 Job timeout (0x%x)\n", tmp);
+               goto free_fence_ptr;
        }
 
 free_fence_ptr:
@@ -2941,20 +2944,19 @@ int goya_test_queue(struct hl_device *hdev, u32 hw_queue_id)
                goto free_pkt;
        }
 
-       rc = hl_poll_timeout_memory(hdev, (u64) (uintptr_t) fence_ptr,
-                                       GOYA_TEST_QUEUE_WAIT_USEC, &tmp);
+       rc = hl_poll_timeout_memory(hdev, fence_ptr, tmp, (tmp == fence_val),
+                                       1000, GOYA_TEST_QUEUE_WAIT_USEC);
 
        hl_hw_queue_inc_ci_kernel(hdev, hw_queue_id);
 
-       if ((!rc) && (tmp == fence_val)) {
-               dev_info(hdev->dev,
-                       "queue test on H/W queue %d succeeded\n",
-                       hw_queue_id);
-       } else {
+       if (rc == -ETIMEDOUT) {
                dev_err(hdev->dev,
                        "H/W queue %d test failed (scratch(0x%08llX) == 0x%08X)\n",
                        hw_queue_id, (unsigned long long) fence_dma_addr, tmp);
-               rc = -EINVAL;
+               rc = -EIO;
+       } else {
+               dev_info(hdev->dev, "queue test on H/W queue %d succeeded\n",
+                       hw_queue_id);
        }
 
 free_pkt:
@@ -2990,12 +2992,6 @@ int goya_test_queues(struct hl_device *hdev)
                        ret_val = -EINVAL;
        }
 
-       if (hdev->cpu_queues_enable) {
-               rc = goya_test_cpu_queue(hdev);
-               if (rc)
-                       ret_val = -EINVAL;
-       }
-
        return ret_val;
 }
 
@@ -3028,7 +3024,13 @@ static void goya_dma_pool_free(struct hl_device *hdev, void *vaddr,
 void *goya_cpu_accessible_dma_pool_alloc(struct hl_device *hdev, size_t size,
                                        dma_addr_t *dma_handle)
 {
-       return hl_fw_cpu_accessible_dma_pool_alloc(hdev, size, dma_handle);
+       void *vaddr;
+
+       vaddr = hl_fw_cpu_accessible_dma_pool_alloc(hdev, size, dma_handle);
+       *dma_handle = (*dma_handle) - hdev->cpu_accessible_dma_address +
+                       VA_CPU_ACCESSIBLE_MEM_ADDR;
+
+       return vaddr;
 }
 
 void goya_cpu_accessible_dma_pool_free(struct hl_device *hdev, size_t size,
@@ -3907,8 +3909,8 @@ int goya_cs_parser(struct hl_device *hdev, struct hl_cs_parser *parser)
                return goya_parse_cb_no_mmu(hdev, parser);
 }
 
-void goya_add_end_of_cb_packets(u64 kernel_address, u32 len, u64 cq_addr,
-                               u32 cq_val, u32 msix_vec)
+void goya_add_end_of_cb_packets(struct hl_device *hdev, u64 kernel_address,
+                               u32 len, u64 cq_addr, u32 cq_val, u32 msix_vec)
 {
        struct packet_msg_prot *cq_pkt;
        u32 tmp;
@@ -3938,6 +3940,11 @@ void goya_update_eq_ci(struct hl_device *hdev, u32 val)
 }
 
 void goya_restore_phase_topology(struct hl_device *hdev)
+{
+
+}
+
+static void goya_clear_sm_regs(struct hl_device *hdev)
 {
        int i, num_of_sob_in_longs, num_of_mon_in_longs;
 
@@ -3958,10 +3965,11 @@ void goya_restore_phase_topology(struct hl_device *hdev)
 }
 
 /*
- * goya_debugfs_read32 - read a 32bit value from a given device address
+ * goya_debugfs_read32 - read a 32bit value from a given device or a host mapped
+ *                       address.
  *
  * @hdev:      pointer to hl_device structure
- * @addr:      address in device
+ * @addr:      device or host mapped address
  * @val:       returned value
  *
  * In case of DDR address that is not mapped into the default aperture that
@@ -4002,6 +4010,10 @@ static int goya_debugfs_read32(struct hl_device *hdev, u64 addr, u32 *val)
                }
                if (ddr_bar_addr == U64_MAX)
                        rc = -EIO;
+
+       } else if (addr >= HOST_PHYS_BASE && !iommu_present(&pci_bus_type)) {
+               *val = *(u32 *) phys_to_virt(addr - HOST_PHYS_BASE);
+
        } else {
                rc = -EFAULT;
        }
@@ -4010,10 +4022,11 @@ static int goya_debugfs_read32(struct hl_device *hdev, u64 addr, u32 *val)
 }
 
 /*
- * goya_debugfs_write32 - write a 32bit value to a given device address
+ * goya_debugfs_write32 - write a 32bit value to a given device or a host mapped
+ *                        address.
  *
  * @hdev:      pointer to hl_device structure
- * @addr:      address in device
+ * @addr:      device or host mapped address
  * @val:       returned value
  *
  * In case of DDR address that is not mapped into the default aperture that
@@ -4054,6 +4067,10 @@ static int goya_debugfs_write32(struct hl_device *hdev, u64 addr, u32 val)
                }
                if (ddr_bar_addr == U64_MAX)
                        rc = -EIO;
+
+       } else if (addr >= HOST_PHYS_BASE && !iommu_present(&pci_bus_type)) {
+               *(u32 *) phys_to_virt(addr - HOST_PHYS_BASE) = val;
+
        } else {
                rc = -EFAULT;
        }
@@ -4086,6 +4103,47 @@ static void goya_write_pte(struct hl_device *hdev, u64 addr, u64 val)
 static const char *_goya_get_event_desc(u16 event_type)
 {
        switch (event_type) {
+       case GOYA_ASYNC_EVENT_ID_PCIE_IF:
+               return "PCIe_if";
+       case GOYA_ASYNC_EVENT_ID_TPC0_ECC:
+       case GOYA_ASYNC_EVENT_ID_TPC1_ECC:
+       case GOYA_ASYNC_EVENT_ID_TPC2_ECC:
+       case GOYA_ASYNC_EVENT_ID_TPC3_ECC:
+       case GOYA_ASYNC_EVENT_ID_TPC4_ECC:
+       case GOYA_ASYNC_EVENT_ID_TPC5_ECC:
+       case GOYA_ASYNC_EVENT_ID_TPC6_ECC:
+       case GOYA_ASYNC_EVENT_ID_TPC7_ECC:
+               return "TPC%d_ecc";
+       case GOYA_ASYNC_EVENT_ID_MME_ECC:
+               return "MME_ecc";
+       case GOYA_ASYNC_EVENT_ID_MME_ECC_EXT:
+               return "MME_ecc_ext";
+       case GOYA_ASYNC_EVENT_ID_MMU_ECC:
+               return "MMU_ecc";
+       case GOYA_ASYNC_EVENT_ID_DMA_MACRO:
+               return "DMA_macro";
+       case GOYA_ASYNC_EVENT_ID_DMA_ECC:
+               return "DMA_ecc";
+       case GOYA_ASYNC_EVENT_ID_CPU_IF_ECC:
+               return "CPU_if_ecc";
+       case GOYA_ASYNC_EVENT_ID_PSOC_MEM:
+               return "PSOC_mem";
+       case GOYA_ASYNC_EVENT_ID_PSOC_CORESIGHT:
+               return "PSOC_coresight";
+       case GOYA_ASYNC_EVENT_ID_SRAM0 ... GOYA_ASYNC_EVENT_ID_SRAM29:
+               return "SRAM%d";
+       case GOYA_ASYNC_EVENT_ID_GIC500:
+               return "GIC500";
+       case GOYA_ASYNC_EVENT_ID_PLL0 ... GOYA_ASYNC_EVENT_ID_PLL6:
+               return "PLL%d";
+       case GOYA_ASYNC_EVENT_ID_AXI_ECC:
+               return "AXI_ecc";
+       case GOYA_ASYNC_EVENT_ID_L2_RAM_ECC:
+               return "L2_ram_ecc";
+       case GOYA_ASYNC_EVENT_ID_PSOC_GPIO_05_SW_RESET:
+               return "PSOC_gpio_05_sw_reset";
+       case GOYA_ASYNC_EVENT_ID_PSOC_GPIO_10_VRHOT_ICRIT:
+               return "PSOC_gpio_10_vrhot_icrit";
        case GOYA_ASYNC_EVENT_ID_PCIE_DEC:
                return "PCIe_dec";
        case GOYA_ASYNC_EVENT_ID_TPC0_DEC:
@@ -4128,6 +4186,17 @@ static const char *_goya_get_event_desc(u16 event_type)
                return "DMA%d_qm";
        case GOYA_ASYNC_EVENT_ID_DMA0_CH ... GOYA_ASYNC_EVENT_ID_DMA4_CH:
                return "DMA%d_ch";
+       case GOYA_ASYNC_EVENT_ID_TPC0_BMON_SPMU:
+       case GOYA_ASYNC_EVENT_ID_TPC1_BMON_SPMU:
+       case GOYA_ASYNC_EVENT_ID_TPC2_BMON_SPMU:
+       case GOYA_ASYNC_EVENT_ID_TPC3_BMON_SPMU:
+       case GOYA_ASYNC_EVENT_ID_TPC4_BMON_SPMU:
+       case GOYA_ASYNC_EVENT_ID_TPC5_BMON_SPMU:
+       case GOYA_ASYNC_EVENT_ID_TPC6_BMON_SPMU:
+       case GOYA_ASYNC_EVENT_ID_TPC7_BMON_SPMU:
+               return "TPC%d_bmon_spmu";
+       case GOYA_ASYNC_EVENT_ID_DMA_BM_CH0 ... GOYA_ASYNC_EVENT_ID_DMA_BM_CH4:
+               return "DMA_bm_ch%d";
        default:
                return "N/A";
        }
@@ -4138,6 +4207,25 @@ static void goya_get_event_desc(u16 event_type, char *desc, size_t size)
        u8 index;
 
        switch (event_type) {
+       case GOYA_ASYNC_EVENT_ID_TPC0_ECC:
+       case GOYA_ASYNC_EVENT_ID_TPC1_ECC:
+       case GOYA_ASYNC_EVENT_ID_TPC2_ECC:
+       case GOYA_ASYNC_EVENT_ID_TPC3_ECC:
+       case GOYA_ASYNC_EVENT_ID_TPC4_ECC:
+       case GOYA_ASYNC_EVENT_ID_TPC5_ECC:
+       case GOYA_ASYNC_EVENT_ID_TPC6_ECC:
+       case GOYA_ASYNC_EVENT_ID_TPC7_ECC:
+               index = (event_type - GOYA_ASYNC_EVENT_ID_TPC0_ECC) / 3;
+               snprintf(desc, size, _goya_get_event_desc(event_type), index);
+               break;
+       case GOYA_ASYNC_EVENT_ID_SRAM0 ... GOYA_ASYNC_EVENT_ID_SRAM29:
+               index = event_type - GOYA_ASYNC_EVENT_ID_SRAM0;
+               snprintf(desc, size, _goya_get_event_desc(event_type), index);
+               break;
+       case GOYA_ASYNC_EVENT_ID_PLL0 ... GOYA_ASYNC_EVENT_ID_PLL6:
+               index = event_type - GOYA_ASYNC_EVENT_ID_PLL0;
+               snprintf(desc, size, _goya_get_event_desc(event_type), index);
+               break;
        case GOYA_ASYNC_EVENT_ID_TPC0_DEC:
        case GOYA_ASYNC_EVENT_ID_TPC1_DEC:
        case GOYA_ASYNC_EVENT_ID_TPC2_DEC:
@@ -4176,6 +4264,21 @@ static void goya_get_event_desc(u16 event_type, char *desc, size_t size)
                index = event_type - GOYA_ASYNC_EVENT_ID_DMA0_CH;
                snprintf(desc, size, _goya_get_event_desc(event_type), index);
                break;
+       case GOYA_ASYNC_EVENT_ID_TPC0_BMON_SPMU:
+       case GOYA_ASYNC_EVENT_ID_TPC1_BMON_SPMU:
+       case GOYA_ASYNC_EVENT_ID_TPC2_BMON_SPMU:
+       case GOYA_ASYNC_EVENT_ID_TPC3_BMON_SPMU:
+       case GOYA_ASYNC_EVENT_ID_TPC4_BMON_SPMU:
+       case GOYA_ASYNC_EVENT_ID_TPC5_BMON_SPMU:
+       case GOYA_ASYNC_EVENT_ID_TPC6_BMON_SPMU:
+       case GOYA_ASYNC_EVENT_ID_TPC7_BMON_SPMU:
+               index = (event_type - GOYA_ASYNC_EVENT_ID_TPC0_BMON_SPMU) / 10;
+               snprintf(desc, size, _goya_get_event_desc(event_type), index);
+               break;
+       case GOYA_ASYNC_EVENT_ID_DMA_BM_CH0 ... GOYA_ASYNC_EVENT_ID_DMA_BM_CH4:
+               index = event_type - GOYA_ASYNC_EVENT_ID_DMA_BM_CH0;
+               snprintf(desc, size, _goya_get_event_desc(event_type), index);
+               break;
        default:
                snprintf(desc, size, _goya_get_event_desc(event_type));
                break;
@@ -4226,7 +4329,8 @@ static void goya_print_mmu_error_info(struct hl_device *hdev)
        }
 }
 
-static void goya_print_irq_info(struct hl_device *hdev, u16 event_type)
+static void goya_print_irq_info(struct hl_device *hdev, u16 event_type,
+                               bool razwi)
 {
        char desc[20] = "";
 
@@ -4234,8 +4338,10 @@ static void goya_print_irq_info(struct hl_device *hdev, u16 event_type)
        dev_err(hdev->dev, "Received H/W interrupt %d [\"%s\"]\n",
                event_type, desc);
 
-       goya_print_razwi_info(hdev);
-       goya_print_mmu_error_info(hdev);
+       if (razwi) {
+               goya_print_razwi_info(hdev);
+               goya_print_mmu_error_info(hdev);
+       }
 }
 
 static int goya_unmask_irq_arr(struct hl_device *hdev, u32 *irq_arr,
@@ -4339,19 +4445,12 @@ void goya_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entry)
        case GOYA_ASYNC_EVENT_ID_PSOC_CORESIGHT:
        case GOYA_ASYNC_EVENT_ID_SRAM0 ... GOYA_ASYNC_EVENT_ID_SRAM29:
        case GOYA_ASYNC_EVENT_ID_GIC500:
-       case GOYA_ASYNC_EVENT_ID_PLL0:
-       case GOYA_ASYNC_EVENT_ID_PLL1:
-       case GOYA_ASYNC_EVENT_ID_PLL3:
-       case GOYA_ASYNC_EVENT_ID_PLL4:
-       case GOYA_ASYNC_EVENT_ID_PLL5:
-       case GOYA_ASYNC_EVENT_ID_PLL6:
+       case GOYA_ASYNC_EVENT_ID_PLL0 ... GOYA_ASYNC_EVENT_ID_PLL6:
        case GOYA_ASYNC_EVENT_ID_AXI_ECC:
        case GOYA_ASYNC_EVENT_ID_L2_RAM_ECC:
        case GOYA_ASYNC_EVENT_ID_PSOC_GPIO_05_SW_RESET:
        case GOYA_ASYNC_EVENT_ID_PSOC_GPIO_10_VRHOT_ICRIT:
-               dev_err(hdev->dev,
-                       "Received H/W interrupt %d, reset the chip\n",
-                       event_type);
+               goya_print_irq_info(hdev, event_type, false);
                hl_device_reset(hdev, true, false);
                break;
 
@@ -4382,7 +4481,7 @@ void goya_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entry)
        case GOYA_ASYNC_EVENT_ID_MME_CMDQ:
        case GOYA_ASYNC_EVENT_ID_DMA0_QM ... GOYA_ASYNC_EVENT_ID_DMA4_QM:
        case GOYA_ASYNC_EVENT_ID_DMA0_CH ... GOYA_ASYNC_EVENT_ID_DMA4_CH:
-               goya_print_irq_info(hdev, event_type);
+               goya_print_irq_info(hdev, event_type, true);
                goya_unmask_irq(hdev, event_type);
                break;
 
@@ -4394,12 +4493,9 @@ void goya_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entry)
        case GOYA_ASYNC_EVENT_ID_TPC5_BMON_SPMU:
        case GOYA_ASYNC_EVENT_ID_TPC6_BMON_SPMU:
        case GOYA_ASYNC_EVENT_ID_TPC7_BMON_SPMU:
-       case GOYA_ASYNC_EVENT_ID_DMA_BM_CH0:
-       case GOYA_ASYNC_EVENT_ID_DMA_BM_CH1:
-       case GOYA_ASYNC_EVENT_ID_DMA_BM_CH2:
-       case GOYA_ASYNC_EVENT_ID_DMA_BM_CH3:
-       case GOYA_ASYNC_EVENT_ID_DMA_BM_CH4:
-               dev_info(hdev->dev, "Received H/W interrupt %d\n", event_type);
+       case GOYA_ASYNC_EVENT_ID_DMA_BM_CH0 ... GOYA_ASYNC_EVENT_ID_DMA_BM_CH4:
+               goya_print_irq_info(hdev, event_type, false);
+               goya_unmask_irq(hdev, event_type);
                break;
 
        default:
@@ -4418,36 +4514,47 @@ void *goya_get_events_stat(struct hl_device *hdev, u32 *size)
        return goya->events_stat;
 }
 
-static int goya_memset_device_memory(struct hl_device *hdev, u64 addr, u32 size,
+static int goya_memset_device_memory(struct hl_device *hdev, u64 addr, u64 size,
                                u64 val, bool is_dram)
 {
        struct packet_lin_dma *lin_dma_pkt;
        struct hl_cs_job *job;
        u32 cb_size, ctl;
        struct hl_cb *cb;
-       int rc;
+       int rc, lin_dma_pkts_cnt;
 
-       cb = hl_cb_kernel_create(hdev, PAGE_SIZE);
+       lin_dma_pkts_cnt = DIV_ROUND_UP_ULL(size, SZ_2G);
+       cb_size = lin_dma_pkts_cnt * sizeof(struct packet_lin_dma) +
+                                               sizeof(struct packet_msg_prot);
+       cb = hl_cb_kernel_create(hdev, cb_size);
        if (!cb)
-               return -EFAULT;
+               return -ENOMEM;
 
        lin_dma_pkt = (struct packet_lin_dma *) (uintptr_t) cb->kernel_address;
 
-       memset(lin_dma_pkt, 0, sizeof(*lin_dma_pkt));
-       cb_size = sizeof(*lin_dma_pkt);
-
-       ctl = ((PACKET_LIN_DMA << GOYA_PKT_CTL_OPCODE_SHIFT) |
-                       (1 << GOYA_PKT_LIN_DMA_CTL_MEMSET_SHIFT) |
-                       (1 << GOYA_PKT_LIN_DMA_CTL_WO_SHIFT) |
-                       (1 << GOYA_PKT_CTL_RB_SHIFT) |
-                       (1 << GOYA_PKT_CTL_MB_SHIFT));
-       ctl |= (is_dram ? DMA_HOST_TO_DRAM : DMA_HOST_TO_SRAM) <<
-                       GOYA_PKT_LIN_DMA_CTL_DMA_DIR_SHIFT;
-       lin_dma_pkt->ctl = cpu_to_le32(ctl);
+       do {
+               memset(lin_dma_pkt, 0, sizeof(*lin_dma_pkt));
+
+               ctl = ((PACKET_LIN_DMA << GOYA_PKT_CTL_OPCODE_SHIFT) |
+                               (1 << GOYA_PKT_LIN_DMA_CTL_MEMSET_SHIFT) |
+                               (1 << GOYA_PKT_LIN_DMA_CTL_WO_SHIFT) |
+                               (1 << GOYA_PKT_CTL_RB_SHIFT) |
+                               (1 << GOYA_PKT_CTL_MB_SHIFT));
+               ctl |= (is_dram ? DMA_HOST_TO_DRAM : DMA_HOST_TO_SRAM) <<
+                               GOYA_PKT_LIN_DMA_CTL_DMA_DIR_SHIFT;
+               lin_dma_pkt->ctl = cpu_to_le32(ctl);
+
+               lin_dma_pkt->src_addr = cpu_to_le64(val);
+               lin_dma_pkt->dst_addr = cpu_to_le64(addr);
+               if (lin_dma_pkts_cnt > 1)
+                       lin_dma_pkt->tsize = cpu_to_le32(SZ_2G);
+               else
+                       lin_dma_pkt->tsize = cpu_to_le32(size);
 
-       lin_dma_pkt->src_addr = cpu_to_le64(val);
-       lin_dma_pkt->dst_addr = cpu_to_le64(addr);
-       lin_dma_pkt->tsize = cpu_to_le32(size);
+               size -= SZ_2G;
+               addr += SZ_2G;
+               lin_dma_pkt++;
+       } while (--lin_dma_pkts_cnt);
 
        job = hl_cs_allocate_job(hdev, true);
        if (!job) {
@@ -4462,8 +4569,7 @@ static int goya_memset_device_memory(struct hl_device *hdev, u64 addr, u32 size,
        job->user_cb_size = cb_size;
        job->hw_queue_id = GOYA_QUEUE_ID_DMA_0;
        job->patched_cb = job->user_cb;
-       job->job_cb_size = job->user_cb_size +
-                       sizeof(struct packet_msg_prot) * 2;
+       job->job_cb_size = job->user_cb_size;
 
        hl_debugfs_add_job(hdev, job);
 
@@ -4485,10 +4591,12 @@ release_cb:
 int goya_context_switch(struct hl_device *hdev, u32 asid)
 {
        struct asic_fixed_properties *prop = &hdev->asic_prop;
-       u64 addr = prop->sram_base_address;
+       u64 addr = prop->sram_base_address, sob_addr;
        u32 size = hdev->pldm ? 0x10000 : prop->sram_size;
        u64 val = 0x7777777777777777ull;
-       int rc;
+       int rc, dma_id;
+       u32 channel_off = mmDMA_CH_1_WR_COMP_ADDR_LO -
+                                       mmDMA_CH_0_WR_COMP_ADDR_LO;
 
        rc = goya_memset_device_memory(hdev, addr, size, val, false);
        if (rc) {
@@ -4496,13 +4604,27 @@ int goya_context_switch(struct hl_device *hdev, u32 asid)
                return rc;
        }
 
+       /* we need to reset registers that the user is allowed to change */
+       sob_addr = CFG_BASE + mmSYNC_MNGR_SOB_OBJ_1007;
+       WREG32(mmDMA_CH_0_WR_COMP_ADDR_LO, lower_32_bits(sob_addr));
+
+       for (dma_id = 1 ; dma_id < NUMBER_OF_EXT_HW_QUEUES ; dma_id++) {
+               sob_addr = CFG_BASE + mmSYNC_MNGR_SOB_OBJ_1000 +
+                                                       (dma_id - 1) * 4;
+               WREG32(mmDMA_CH_0_WR_COMP_ADDR_LO + channel_off * dma_id,
+                                               lower_32_bits(sob_addr));
+       }
+
        WREG32(mmTPC_PLL_CLK_RLX_0, 0x200020);
+
        goya_mmu_prepare(hdev, asid);
 
+       goya_clear_sm_regs(hdev);
+
        return 0;
 }
 
-int goya_mmu_clear_pgt_range(struct hl_device *hdev)
+static int goya_mmu_clear_pgt_range(struct hl_device *hdev)
 {
        struct asic_fixed_properties *prop = &hdev->asic_prop;
        struct goya_device *goya = hdev->asic_specific;
@@ -4516,7 +4638,7 @@ int goya_mmu_clear_pgt_range(struct hl_device *hdev)
        return goya_memset_device_memory(hdev, addr, size, 0, true);
 }
 
-int goya_mmu_set_dram_default_page(struct hl_device *hdev)
+static int goya_mmu_set_dram_default_page(struct hl_device *hdev)
 {
        struct goya_device *goya = hdev->asic_specific;
        u64 addr = hdev->asic_prop.mmu_dram_default_page_addr;
@@ -4529,7 +4651,123 @@ int goya_mmu_set_dram_default_page(struct hl_device *hdev)
        return goya_memset_device_memory(hdev, addr, size, val, true);
 }
 
-void goya_mmu_prepare(struct hl_device *hdev, u32 asid)
+static int goya_mmu_add_mappings_for_device_cpu(struct hl_device *hdev)
+{
+       struct asic_fixed_properties *prop = &hdev->asic_prop;
+       struct goya_device *goya = hdev->asic_specific;
+       s64 off, cpu_off;
+       int rc;
+
+       if (!(goya->hw_cap_initialized & HW_CAP_MMU))
+               return 0;
+
+       for (off = 0 ; off < CPU_FW_IMAGE_SIZE ; off += PAGE_SIZE_2MB) {
+               rc = hl_mmu_map(hdev->kernel_ctx, prop->dram_base_address + off,
+                               prop->dram_base_address + off, PAGE_SIZE_2MB);
+               if (rc) {
+                       dev_err(hdev->dev, "Map failed for address 0x%llx\n",
+                               prop->dram_base_address + off);
+                       goto unmap;
+               }
+       }
+
+       if (!(hdev->cpu_accessible_dma_address & (PAGE_SIZE_2MB - 1))) {
+               rc = hl_mmu_map(hdev->kernel_ctx, VA_CPU_ACCESSIBLE_MEM_ADDR,
+                       hdev->cpu_accessible_dma_address, PAGE_SIZE_2MB);
+
+               if (rc) {
+                       dev_err(hdev->dev,
+                               "Map failed for CPU accessible memory\n");
+                       off -= PAGE_SIZE_2MB;
+                       goto unmap;
+               }
+       } else {
+               for (cpu_off = 0 ; cpu_off < SZ_2M ; cpu_off += PAGE_SIZE_4KB) {
+                       rc = hl_mmu_map(hdev->kernel_ctx,
+                               VA_CPU_ACCESSIBLE_MEM_ADDR + cpu_off,
+                               hdev->cpu_accessible_dma_address + cpu_off,
+                               PAGE_SIZE_4KB);
+                       if (rc) {
+                               dev_err(hdev->dev,
+                                       "Map failed for CPU accessible memory\n");
+                               cpu_off -= PAGE_SIZE_4KB;
+                               goto unmap_cpu;
+                       }
+               }
+       }
+
+       goya_mmu_prepare_reg(hdev, mmCPU_IF_ARUSER_OVR, HL_KERNEL_ASID_ID);
+       goya_mmu_prepare_reg(hdev, mmCPU_IF_AWUSER_OVR, HL_KERNEL_ASID_ID);
+       WREG32(mmCPU_IF_ARUSER_OVR_EN, 0x7FF);
+       WREG32(mmCPU_IF_AWUSER_OVR_EN, 0x7FF);
+
+       /* Make sure configuration is flushed to device */
+       RREG32(mmCPU_IF_AWUSER_OVR_EN);
+
+       goya->device_cpu_mmu_mappings_done = true;
+
+       return 0;
+
+unmap_cpu:
+       for (; cpu_off >= 0 ; cpu_off -= PAGE_SIZE_4KB)
+               if (hl_mmu_unmap(hdev->kernel_ctx,
+                               VA_CPU_ACCESSIBLE_MEM_ADDR + cpu_off,
+                               PAGE_SIZE_4KB))
+                       dev_warn_ratelimited(hdev->dev,
+                               "failed to unmap address 0x%llx\n",
+                               VA_CPU_ACCESSIBLE_MEM_ADDR + cpu_off);
+unmap:
+       for (; off >= 0 ; off -= PAGE_SIZE_2MB)
+               if (hl_mmu_unmap(hdev->kernel_ctx,
+                               prop->dram_base_address + off, PAGE_SIZE_2MB))
+                       dev_warn_ratelimited(hdev->dev,
+                               "failed to unmap address 0x%llx\n",
+                               prop->dram_base_address + off);
+
+       return rc;
+}
+
+void goya_mmu_remove_device_cpu_mappings(struct hl_device *hdev)
+{
+       struct asic_fixed_properties *prop = &hdev->asic_prop;
+       struct goya_device *goya = hdev->asic_specific;
+       u32 off, cpu_off;
+
+       if (!(goya->hw_cap_initialized & HW_CAP_MMU))
+               return;
+
+       if (!goya->device_cpu_mmu_mappings_done)
+               return;
+
+       WREG32(mmCPU_IF_ARUSER_OVR_EN, 0);
+       WREG32(mmCPU_IF_AWUSER_OVR_EN, 0);
+
+       if (!(hdev->cpu_accessible_dma_address & (PAGE_SIZE_2MB - 1))) {
+               if (hl_mmu_unmap(hdev->kernel_ctx, VA_CPU_ACCESSIBLE_MEM_ADDR,
+                               PAGE_SIZE_2MB))
+                       dev_warn(hdev->dev,
+                               "Failed to unmap CPU accessible memory\n");
+       } else {
+               for (cpu_off = 0 ; cpu_off < SZ_2M ; cpu_off += PAGE_SIZE_4KB)
+                       if (hl_mmu_unmap(hdev->kernel_ctx,
+                                       VA_CPU_ACCESSIBLE_MEM_ADDR + cpu_off,
+                                       PAGE_SIZE_4KB))
+                               dev_warn_ratelimited(hdev->dev,
+                                       "failed to unmap address 0x%llx\n",
+                                       VA_CPU_ACCESSIBLE_MEM_ADDR + cpu_off);
+       }
+
+       for (off = 0 ; off < CPU_FW_IMAGE_SIZE ; off += PAGE_SIZE_2MB)
+               if (hl_mmu_unmap(hdev->kernel_ctx,
+                               prop->dram_base_address + off, PAGE_SIZE_2MB))
+                       dev_warn_ratelimited(hdev->dev,
+                                       "Failed to unmap address 0x%llx\n",
+                                       prop->dram_base_address + off);
+
+       goya->device_cpu_mmu_mappings_done = false;
+}
+
+static void goya_mmu_prepare(struct hl_device *hdev, u32 asid)
 {
        struct goya_device *goya = hdev->asic_specific;
        int i;
@@ -4676,57 +4914,82 @@ int goya_armcp_info_get(struct hl_device *hdev)
        return 0;
 }
 
-static bool goya_is_device_idle(struct hl_device *hdev, char *buf, size_t size)
+static bool goya_is_device_idle(struct hl_device *hdev, u32 *mask,
+                               struct seq_file *s)
 {
-       u64 offset, dma_qm_reg, tpc_qm_reg, tpc_cmdq_reg, tpc_cfg_reg;
+       const char *fmt = "%-5d%-9s%#-14x%#-16x%#x\n";
+       const char *dma_fmt = "%-5d%-9s%#-14x%#x\n";
+       u32 qm_glbl_sts0, cmdq_glbl_sts0, dma_core_sts0, tpc_cfg_sts,
+               mme_arch_sts;
+       bool is_idle = true, is_eng_idle;
+       u64 offset;
        int i;
 
+       if (s)
+               seq_puts(s, "\nDMA  is_idle  QM_GLBL_STS0  DMA_CORE_STS0\n"
+                               "---  -------  ------------  -------------\n");
+
        offset = mmDMA_QM_1_GLBL_STS0 - mmDMA_QM_0_GLBL_STS0;
 
        for (i = 0 ; i < DMA_MAX_NUM ; i++) {
-               dma_qm_reg = mmDMA_QM_0_GLBL_STS0 + i * offset;
+               qm_glbl_sts0 = RREG32(mmDMA_QM_0_GLBL_STS0 + i * offset);
+               dma_core_sts0 = RREG32(mmDMA_CH_0_STS0 + i * offset);
+               is_eng_idle = IS_DMA_QM_IDLE(qm_glbl_sts0) &&
+                               IS_DMA_IDLE(dma_core_sts0);
+               is_idle &= is_eng_idle;
 
-               if ((RREG32(dma_qm_reg) & DMA_QM_IDLE_MASK) !=
-                               DMA_QM_IDLE_MASK)
-                       return HL_ENG_BUSY(buf, size, "DMA%d_QM", i);
+               if (mask)
+                       *mask |= !is_eng_idle << (GOYA_ENGINE_ID_DMA_0 + i);
+               if (s)
+                       seq_printf(s, dma_fmt, i, is_eng_idle ? "Y" : "N",
+                                       qm_glbl_sts0, dma_core_sts0);
        }
 
+       if (s)
+               seq_puts(s,
+                       "\nTPC  is_idle  QM_GLBL_STS0  CMDQ_GLBL_STS0  CFG_STATUS\n"
+                       "---  -------  ------------  --------------  ----------\n");
+
        offset = mmTPC1_QM_GLBL_STS0 - mmTPC0_QM_GLBL_STS0;
 
        for (i = 0 ; i < TPC_MAX_NUM ; i++) {
-               tpc_qm_reg = mmTPC0_QM_GLBL_STS0 + i * offset;
-               tpc_cmdq_reg = mmTPC0_CMDQ_GLBL_STS0 + i * offset;
-               tpc_cfg_reg = mmTPC0_CFG_STATUS + i * offset;
-
-               if ((RREG32(tpc_qm_reg) & TPC_QM_IDLE_MASK) !=
-                               TPC_QM_IDLE_MASK)
-                       return HL_ENG_BUSY(buf, size, "TPC%d_QM", i);
-
-               if ((RREG32(tpc_cmdq_reg) & TPC_CMDQ_IDLE_MASK) !=
-                               TPC_CMDQ_IDLE_MASK)
-                       return HL_ENG_BUSY(buf, size, "TPC%d_CMDQ", i);
-
-               if ((RREG32(tpc_cfg_reg) & TPC_CFG_IDLE_MASK) !=
-                               TPC_CFG_IDLE_MASK)
-                       return HL_ENG_BUSY(buf, size, "TPC%d_CFG", i);
-       }
-
-       if ((RREG32(mmMME_QM_GLBL_STS0) & MME_QM_IDLE_MASK) !=
-                       MME_QM_IDLE_MASK)
-               return HL_ENG_BUSY(buf, size, "MME_QM");
-
-       if ((RREG32(mmMME_CMDQ_GLBL_STS0) & MME_CMDQ_IDLE_MASK) !=
-                       MME_CMDQ_IDLE_MASK)
-               return HL_ENG_BUSY(buf, size, "MME_CMDQ");
-
-       if ((RREG32(mmMME_ARCH_STATUS) & MME_ARCH_IDLE_MASK) !=
-                       MME_ARCH_IDLE_MASK)
-               return HL_ENG_BUSY(buf, size, "MME_ARCH");
-
-       if (RREG32(mmMME_SHADOW_0_STATUS) & MME_SHADOW_IDLE_MASK)
-               return HL_ENG_BUSY(buf, size, "MME");
-
-       return true;
+               qm_glbl_sts0 = RREG32(mmTPC0_QM_GLBL_STS0 + i * offset);
+               cmdq_glbl_sts0 = RREG32(mmTPC0_CMDQ_GLBL_STS0 + i * offset);
+               tpc_cfg_sts = RREG32(mmTPC0_CFG_STATUS + i * offset);
+               is_eng_idle = IS_TPC_QM_IDLE(qm_glbl_sts0) &&
+                               IS_TPC_CMDQ_IDLE(cmdq_glbl_sts0) &&
+                               IS_TPC_IDLE(tpc_cfg_sts);
+               is_idle &= is_eng_idle;
+
+               if (mask)
+                       *mask |= !is_eng_idle << (GOYA_ENGINE_ID_TPC_0 + i);
+               if (s)
+                       seq_printf(s, fmt, i, is_eng_idle ? "Y" : "N",
+                               qm_glbl_sts0, cmdq_glbl_sts0, tpc_cfg_sts);
+       }
+
+       if (s)
+               seq_puts(s,
+                       "\nMME  is_idle  QM_GLBL_STS0  CMDQ_GLBL_STS0  ARCH_STATUS\n"
+                       "---  -------  ------------  --------------  -----------\n");
+
+       qm_glbl_sts0 = RREG32(mmMME_QM_GLBL_STS0);
+       cmdq_glbl_sts0 = RREG32(mmMME_CMDQ_GLBL_STS0);
+       mme_arch_sts = RREG32(mmMME_ARCH_STATUS);
+       is_eng_idle = IS_MME_QM_IDLE(qm_glbl_sts0) &&
+                       IS_MME_CMDQ_IDLE(cmdq_glbl_sts0) &&
+                       IS_MME_IDLE(mme_arch_sts);
+       is_idle &= is_eng_idle;
+
+       if (mask)
+               *mask |= !is_eng_idle << GOYA_ENGINE_ID_MME_0;
+       if (s) {
+               seq_printf(s, fmt, 0, is_eng_idle ? "Y" : "N", qm_glbl_sts0,
+                               cmdq_glbl_sts0, mme_arch_sts);
+               seq_puts(s, "\n");
+       }
+
+       return is_idle;
 }
 
 static void goya_hw_queues_lock(struct hl_device *hdev)
index c83cab0..f8c6118 100644 (file)
 #define VA_DDR_SPACE_SIZE      (VA_DDR_SPACE_END - \
                                        VA_DDR_SPACE_START)     /* 128GB */
 
+#if (HL_CPU_ACCESSIBLE_MEM_SIZE != SZ_2M)
+#error "HL_CPU_ACCESSIBLE_MEM_SIZE must be exactly 2MB to enable MMU mapping"
+#endif
+
+#define VA_CPU_ACCESSIBLE_MEM_ADDR     0x8000000000ull
+
 #define DMA_MAX_TRANSFER_SIZE  U32_MAX
 
 #define HW_CAP_PLL             0x00000001
@@ -157,6 +163,7 @@ struct goya_device {
        u64             ddr_bar_cur_addr;
        u32             events_stat[GOYA_ASYNC_EVENT_ID_SIZE];
        u32             hw_cap_initialized;
+       u8              device_cpu_mmu_mappings_done;
 };
 
 void goya_get_fixed_properties(struct hl_device *hdev);
@@ -204,18 +211,14 @@ int goya_armcp_info_get(struct hl_device *hdev);
 int goya_debug_coresight(struct hl_device *hdev, void *data);
 void goya_halt_coresight(struct hl_device *hdev);
 
-void goya_mmu_prepare(struct hl_device *hdev, u32 asid);
-int goya_mmu_clear_pgt_range(struct hl_device *hdev);
-int goya_mmu_set_dram_default_page(struct hl_device *hdev);
-
 int goya_suspend(struct hl_device *hdev);
 int goya_resume(struct hl_device *hdev);
 
 void goya_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entry);
 void *goya_get_events_stat(struct hl_device *hdev, u32 *size);
 
-void goya_add_end_of_cb_packets(u64 kernel_address, u32 len, u64 cq_addr,
-                               u32 cq_val, u32 msix_vec);
+void goya_add_end_of_cb_packets(struct hl_device *hdev, u64 kernel_address,
+                               u32 len, u64 cq_addr, u32 cq_val, u32 msix_vec);
 int goya_cs_parser(struct hl_device *hdev, struct hl_cs_parser *parser);
 void *goya_get_int_queue_base(struct hl_device *hdev, u32 queue_id,
                                dma_addr_t *dma_handle, u16 *queue_len);
@@ -225,5 +228,6 @@ void *goya_cpu_accessible_dma_pool_alloc(struct hl_device *hdev, size_t size,
                                        dma_addr_t *dma_handle);
 void goya_cpu_accessible_dma_pool_free(struct hl_device *hdev, size_t size,
                                        void *vaddr);
+void goya_mmu_remove_device_cpu_mappings(struct hl_device *hdev);
 
 #endif /* GOYAP_H_ */
index d95d1b2..d6ec12b 100644 (file)
@@ -677,6 +677,17 @@ static void goya_init_tpc_protection_bits(struct hl_device *hdev)
        goya_pb_set_block(hdev, mmTPC0_RD_REGULATOR_BASE);
        goya_pb_set_block(hdev, mmTPC0_WR_REGULATOR_BASE);
 
+       pb_addr = (mmTPC0_CFG_SEMAPHORE & ~0xFFF) + PROT_BITS_OFFS;
+       word_offset = ((mmTPC0_CFG_SEMAPHORE & PROT_BITS_OFFS) >> 7) << 2;
+
+       mask = 1 << ((mmTPC0_CFG_SEMAPHORE & 0x7F) >> 2);
+       mask |= 1 << ((mmTPC0_CFG_VFLAGS & 0x7F) >> 2);
+       mask |= 1 << ((mmTPC0_CFG_SFLAGS & 0x7F) >> 2);
+       mask |= 1 << ((mmTPC0_CFG_LFSR_POLYNOM & 0x7F) >> 2);
+       mask |= 1 << ((mmTPC0_CFG_STATUS & 0x7F) >> 2);
+
+       WREG32(pb_addr + word_offset, ~mask);
+
        pb_addr = (mmTPC0_CFG_CFG_BASE_ADDRESS_HIGH & ~0xFFF) + PROT_BITS_OFFS;
        word_offset = ((mmTPC0_CFG_CFG_BASE_ADDRESS_HIGH &
                        PROT_BITS_OFFS) >> 7) << 2;
@@ -684,6 +695,11 @@ static void goya_init_tpc_protection_bits(struct hl_device *hdev)
        mask |= 1 << ((mmTPC0_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2);
        mask |= 1 << ((mmTPC0_CFG_SM_BASE_ADDRESS_LOW & 0x7F) >> 2);
        mask |= 1 << ((mmTPC0_CFG_SM_BASE_ADDRESS_HIGH & 0x7F) >> 2);
+       mask |= 1 << ((mmTPC0_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2);
+       mask |= 1 << ((mmTPC0_CFG_TPC_STALL & 0x7F) >> 2);
+       mask |= 1 << ((mmTPC0_CFG_MSS_CONFIG & 0x7F) >> 2);
+       mask |= 1 << ((mmTPC0_CFG_TPC_INTR_CAUSE & 0x7F) >> 2);
+       mask |= 1 << ((mmTPC0_CFG_TPC_INTR_MASK & 0x7F) >> 2);
 
        WREG32(pb_addr + word_offset, ~mask);
 
index adef7d9..10da994 100644 (file)
@@ -34,6 +34,8 @@
 #define HL_ARMCP_INFO_TIMEOUT_USEC     10000000 /* 10s */
 #define HL_ARMCP_EEPROM_TIMEOUT_USEC   10000000 /* 10s */
 
+#define HL_PCI_ELBI_TIMEOUT_MSEC       10 /* 10ms */
+
 #define HL_MAX_QUEUES                  128
 
 #define HL_MAX_JOBS_PER_CS             64
@@ -123,7 +125,7 @@ enum hl_device_hw_state {
 /**
  * struct asic_fixed_properties - ASIC specific immutable properties.
  * @hw_queues_props: H/W queues properties.
- * @armcp_info: received various information from ArmCP regarding the H/W. e.g.
+ * @armcp_info: received various information from ArmCP regarding the H/W, e.g.
  *             available sensors.
  * @uboot_ver: F/W U-boot version.
  * @preboot_ver: F/W Preboot version.
@@ -318,18 +320,8 @@ struct hl_cs_job;
 #define HL_EQ_LENGTH                   64
 #define HL_EQ_SIZE_IN_BYTES            (HL_EQ_LENGTH * HL_EQ_ENTRY_SIZE)
 
-#define HL_CPU_PKT_SHIFT               5
-#define HL_CPU_PKT_SIZE                        (1 << HL_CPU_PKT_SHIFT)
-#define HL_CPU_PKT_MASK                        (~((1 << HL_CPU_PKT_SHIFT) - 1))
-#define HL_CPU_MAX_PKTS_IN_CB          32
-#define HL_CPU_CB_SIZE                 (HL_CPU_PKT_SIZE * \
-                                        HL_CPU_MAX_PKTS_IN_CB)
-#define HL_CPU_CB_QUEUE_SIZE           (HL_QUEUE_LENGTH * HL_CPU_CB_SIZE)
-
-/* KMD <-> ArmCP shared memory size (EQ + PQ + CPU CB queue) */
-#define HL_CPU_ACCESSIBLE_MEM_SIZE     (HL_EQ_SIZE_IN_BYTES + \
-                                        HL_QUEUE_SIZE_IN_BYTES + \
-                                        HL_CPU_CB_QUEUE_SIZE)
+/* KMD <-> ArmCP shared memory size */
+#define HL_CPU_ACCESSIBLE_MEM_SIZE     SZ_2M
 
 /**
  * struct hl_hw_queue - describes a H/W transport queue.
@@ -543,8 +535,9 @@ struct hl_asic_funcs {
                                enum dma_data_direction dir);
        u32 (*get_dma_desc_list_size)(struct hl_device *hdev,
                                        struct sg_table *sgt);
-       void (*add_end_of_cb_packets)(u64 kernel_address, u32 len, u64 cq_addr,
-                                       u32 cq_val, u32 msix_num);
+       void (*add_end_of_cb_packets)(struct hl_device *hdev,
+                                       u64 kernel_address, u32 len,
+                                       u64 cq_addr, u32 cq_val, u32 msix_num);
        void (*update_eq_ci)(struct hl_device *hdev, u32 val);
        int (*context_switch)(struct hl_device *hdev, u32 asid);
        void (*restore_phase_topology)(struct hl_device *hdev);
@@ -564,7 +557,8 @@ struct hl_asic_funcs {
                        u32 asid, u64 va, u64 size);
        int (*send_heartbeat)(struct hl_device *hdev);
        int (*debug_coresight)(struct hl_device *hdev, void *data);
-       bool (*is_device_idle)(struct hl_device *hdev, char *buf, size_t size);
+       bool (*is_device_idle)(struct hl_device *hdev, u32 *mask,
+                               struct seq_file *s);
        int (*soft_reset_late_init)(struct hl_device *hdev);
        void (*hw_queues_lock)(struct hl_device *hdev);
        void (*hw_queues_unlock)(struct hl_device *hdev);
@@ -1065,12 +1059,59 @@ void hl_wreg(struct hl_device *hdev, u32 reg, u32 val);
        (cond) ? 0 : -ETIMEDOUT; \
 })
 
+/*
+ * address in this macro points always to a memory location in the
+ * host's (server's) memory. That location is updated asynchronously
+ * either by the direct access of the device or by another core
+ */
+#define hl_poll_timeout_memory(hdev, addr, val, cond, sleep_us, timeout_us) \
+({ \
+       ktime_t __timeout; \
+       /* timeout should be longer when working with simulator */ \
+       if (hdev->pdev) \
+               __timeout = ktime_add_us(ktime_get(), timeout_us); \
+       else \
+               __timeout = ktime_add_us(ktime_get(), (timeout_us * 10)); \
+       might_sleep_if(sleep_us); \
+       for (;;) { \
+               /* Verify we read updates done by other cores or by device */ \
+               mb(); \
+               (val) = *((u32 *) (uintptr_t) (addr)); \
+               if (cond) \
+                       break; \
+               if (timeout_us && ktime_compare(ktime_get(), __timeout) > 0) { \
+                       (val) = *((u32 *) (uintptr_t) (addr)); \
+                       break; \
+               } \
+               if (sleep_us) \
+                       usleep_range((sleep_us >> 2) + 1, sleep_us); \
+       } \
+       (cond) ? 0 : -ETIMEDOUT; \
+})
 
-#define HL_ENG_BUSY(buf, size, fmt, ...) ({ \
-               if (buf) \
-                       snprintf(buf, size, fmt, ##__VA_ARGS__); \
-               false; \
-       })
+#define hl_poll_timeout_device_memory(hdev, addr, val, cond, sleep_us, \
+                                       timeout_us) \
+({ \
+       ktime_t __timeout; \
+       /* timeout should be longer when working with simulator */ \
+       if (hdev->pdev) \
+               __timeout = ktime_add_us(ktime_get(), timeout_us); \
+       else \
+               __timeout = ktime_add_us(ktime_get(), (timeout_us * 10)); \
+       might_sleep_if(sleep_us); \
+       for (;;) { \
+               (val) = readl(addr); \
+               if (cond) \
+                       break; \
+               if (timeout_us && ktime_compare(ktime_get(), __timeout) > 0) { \
+                       (val) = readl(addr); \
+                       break; \
+               } \
+               if (sleep_us) \
+                       usleep_range((sleep_us >> 2) + 1, sleep_us); \
+       } \
+       (cond) ? 0 : -ETIMEDOUT; \
+})
 
 struct hwmon_chip_info;
 
@@ -1117,6 +1158,7 @@ struct hl_device_reset_work {
  *                    lock here so we can flush user processes which are opening
  *                    the device while we are trying to hard reset it
  * @send_cpu_message_lock: enforces only one message in KMD <-> ArmCP queue.
+ * @debug_lock: protects critical section of setting debug mode for device
  * @asic_prop: ASIC specific immutable properties.
  * @asic_funcs: ASIC specific functions.
  * @asic_specific: ASIC specific information to use only from ASIC files.
@@ -1159,6 +1201,8 @@ struct hl_device_reset_work {
  * @mmu_enable: is MMU enabled.
  * @device_cpu_disabled: is the device CPU disabled (due to timeouts)
  * @dma_mask: the dma mask that was set for this device
+ * @in_debug: is device under debug. This, together with fd_open_cnt, enforces
+ *            that only a single user is configuring the debug infrastructure.
  */
 struct hl_device {
        struct pci_dev                  *pdev;
@@ -1188,6 +1232,7 @@ struct hl_device {
        /* TODO: remove fd_open_cnt_lock for multiple process support */
        struct mutex                    fd_open_cnt_lock;
        struct mutex                    send_cpu_message_lock;
+       struct mutex                    debug_lock;
        struct asic_fixed_properties    asic_prop;
        const struct hl_asic_funcs      *asic_funcs;
        void                            *asic_specific;
@@ -1230,6 +1275,7 @@ struct hl_device {
        u8                              init_done;
        u8                              device_cpu_disabled;
        u8                              dma_mask;
+       u8                              in_debug;
 
        /* Parameters for bring-up */
        u8                              mmu_enable;
@@ -1325,13 +1371,10 @@ static inline bool hl_mem_area_crosses_range(u64 address, u32 size,
 int hl_device_open(struct inode *inode, struct file *filp);
 bool hl_device_disabled_or_in_reset(struct hl_device *hdev);
 enum hl_device_status hl_device_status(struct hl_device *hdev);
+int hl_device_set_debug_mode(struct hl_device *hdev, bool enable);
 int create_hdev(struct hl_device **dev, struct pci_dev *pdev,
                enum hl_asic_type asic_type, int minor);
 void destroy_hdev(struct hl_device *hdev);
-int hl_poll_timeout_memory(struct hl_device *hdev, u64 addr, u32 timeout_us,
-                               u32 *val);
-int hl_poll_timeout_device_memory(struct hl_device *hdev, void __iomem *addr,
-                               u32 timeout_us, u32 *val);
 int hl_hw_queues_create(struct hl_device *hdev);
 void hl_hw_queues_destroy(struct hl_device *hdev);
 int hl_hw_queue_send_cb_no_cmpl(struct hl_device *hdev, u32 hw_queue_id,
index 5f4d155..6f6dbe9 100644 (file)
@@ -105,9 +105,17 @@ int hl_device_open(struct inode *inode, struct file *filp)
                return -EPERM;
        }
 
+       if (hdev->in_debug) {
+               dev_err_ratelimited(hdev->dev,
+                       "Can't open %s because it is being debugged by another user\n",
+                       dev_name(hdev->dev));
+               mutex_unlock(&hdev->fd_open_cnt_lock);
+               return -EPERM;
+       }
+
        if (atomic_read(&hdev->fd_open_cnt)) {
                dev_info_ratelimited(hdev->dev,
-                       "Device %s is already attached to application\n",
+                       "Can't open %s because another user is working on it\n",
                        dev_name(hdev->dev));
                mutex_unlock(&hdev->fd_open_cnt_lock);
                return -EBUSY;
@@ -164,6 +172,17 @@ close_device:
        return rc;
 }
 
+static void set_driver_behavior_per_device(struct hl_device *hdev)
+{
+       hdev->mmu_enable = 1;
+       hdev->cpu_enable = 1;
+       hdev->fw_loading = 1;
+       hdev->cpu_queues_enable = 1;
+       hdev->heartbeat = 1;
+
+       hdev->reset_pcilink = 0;
+}
+
 /*
  * create_hdev - create habanalabs device instance
  *
@@ -188,29 +207,25 @@ int create_hdev(struct hl_device **dev, struct pci_dev *pdev,
        if (!hdev)
                return -ENOMEM;
 
+       /* First, we must find out which ASIC are we handling. This is needed
+        * to configure the behavior of the driver (kernel parameters)
+        */
+       if (pdev) {
+               hdev->asic_type = get_asic_type(pdev->device);
+               if (hdev->asic_type == ASIC_INVALID) {
+                       dev_err(&pdev->dev, "Unsupported ASIC\n");
+                       rc = -ENODEV;
+                       goto free_hdev;
+               }
+       } else {
+               hdev->asic_type = asic_type;
+       }
+
        hdev->major = hl_major;
        hdev->reset_on_lockup = reset_on_lockup;
-
-       /* Parameters for bring-up - set them to defaults */
-       hdev->mmu_enable = 1;
-       hdev->cpu_enable = 1;
-       hdev->reset_pcilink = 0;
-       hdev->cpu_queues_enable = 1;
-       hdev->fw_loading = 1;
        hdev->pldm = 0;
-       hdev->heartbeat = 1;
-
-       /* If CPU is disabled, no point in loading FW */
-       if (!hdev->cpu_enable)
-               hdev->fw_loading = 0;
 
-       /* If we don't load FW, no need to initialize CPU queues */
-       if (!hdev->fw_loading)
-               hdev->cpu_queues_enable = 0;
-
-       /* If CPU queues not enabled, no way to do heartbeat */
-       if (!hdev->cpu_queues_enable)
-               hdev->heartbeat = 0;
+       set_driver_behavior_per_device(hdev);
 
        if (timeout_locked)
                hdev->timeout_jiffies = msecs_to_jiffies(timeout_locked * 1000);
@@ -220,17 +235,6 @@ int create_hdev(struct hl_device **dev, struct pci_dev *pdev,
        hdev->disabled = true;
        hdev->pdev = pdev; /* can be NULL in case of simulator device */
 
-       if (pdev) {
-               hdev->asic_type = get_asic_type(pdev->device);
-               if (hdev->asic_type == ASIC_INVALID) {
-                       dev_err(&pdev->dev, "Unsupported ASIC\n");
-                       rc = -ENODEV;
-                       goto free_hdev;
-               }
-       } else {
-               hdev->asic_type = asic_type;
-       }
-
        /* Set default DMA mask to 32 bits */
        hdev->dma_mask = 32;
 
index b7a0eec..0712757 100644 (file)
@@ -119,7 +119,8 @@ static int hw_idle(struct hl_device *hdev, struct hl_info_args *args)
        if ((!max_size) || (!out))
                return -EINVAL;
 
-       hw_idle.is_idle = hdev->asic_funcs->is_device_idle(hdev, NULL, 0);
+       hw_idle.is_idle = hdev->asic_funcs->is_device_idle(hdev,
+                                       &hw_idle.busy_engines_mask, NULL);
 
        return copy_to_user(out, &hw_idle,
                min((size_t) max_size, sizeof(hw_idle))) ? -EFAULT : 0;
@@ -254,10 +255,18 @@ static int hl_debug_ioctl(struct hl_fpriv *hpriv, void *data)
        case HL_DEBUG_OP_BMON:
        case HL_DEBUG_OP_SPMU:
        case HL_DEBUG_OP_TIMESTAMP:
+               if (!hdev->in_debug) {
+                       dev_err_ratelimited(hdev->dev,
+                               "Rejecting debug configuration request because device not in debug mode\n");
+                       return -EFAULT;
+               }
                args->input_size =
                        min(args->input_size, hl_debug_struct_size[args->op]);
                rc = debug_coresight(hdev, args);
                break;
+       case HL_DEBUG_OP_SET_MODE:
+               rc = hl_device_set_debug_mode(hdev, (bool) args->enable);
+               break;
        default:
                dev_err(hdev->dev, "Invalid request %d\n", args->op);
                rc = -ENOTTY;
index 2894d89..e3b5517 100644 (file)
@@ -265,7 +265,7 @@ static void ext_hw_queue_schedule_job(struct hl_cs_job *job)
        cq = &hdev->completion_queue[q->hw_queue_id];
        cq_addr = cq->bus_address + cq->pi * sizeof(struct hl_cq_entry);
 
-       hdev->asic_funcs->add_end_of_cb_packets(cb->kernel_address, len,
+       hdev->asic_funcs->add_end_of_cb_packets(hdev, cb->kernel_address, len,
                                                cq_addr,
                                                __le32_to_cpu(cq_pkt.data),
                                                q->hw_queue_id);
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_0_masks.h b/drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_0_masks.h
new file mode 100644 (file)
index 0000000..0281434
--- /dev/null
@@ -0,0 +1,418 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright 2016-2018 HabanaLabs, Ltd.
+ * All Rights Reserved.
+ *
+ */
+
+/************************************
+ ** This is an auto-generated file **
+ **       DO NOT EDIT BELOW        **
+ ************************************/
+
+#ifndef ASIC_REG_DMA_CH_0_MASKS_H_
+#define ASIC_REG_DMA_CH_0_MASKS_H_
+
+/*
+ *****************************************
+ *   DMA_CH_0 (Prototype: DMA_CH)
+ *****************************************
+ */
+
+/* DMA_CH_0_CFG0 */
+#define DMA_CH_0_CFG0_RD_MAX_OUTSTAND_SHIFT                          0
+#define DMA_CH_0_CFG0_RD_MAX_OUTSTAND_MASK                           0x3FF
+#define DMA_CH_0_CFG0_WR_MAX_OUTSTAND_SHIFT                          16
+#define DMA_CH_0_CFG0_WR_MAX_OUTSTAND_MASK                           0xFFF0000
+
+/* DMA_CH_0_CFG1 */
+#define DMA_CH_0_CFG1_RD_BUF_MAX_SIZE_SHIFT                          0
+#define DMA_CH_0_CFG1_RD_BUF_MAX_SIZE_MASK                           0x3FF
+
+/* DMA_CH_0_ERRMSG_ADDR_LO */
+#define DMA_CH_0_ERRMSG_ADDR_LO_VAL_SHIFT                            0
+#define DMA_CH_0_ERRMSG_ADDR_LO_VAL_MASK                             0xFFFFFFFF
+
+/* DMA_CH_0_ERRMSG_ADDR_HI */
+#define DMA_CH_0_ERRMSG_ADDR_HI_VAL_SHIFT                            0
+#define DMA_CH_0_ERRMSG_ADDR_HI_VAL_MASK                             0xFFFFFFFF
+
+/* DMA_CH_0_ERRMSG_WDATA */
+#define DMA_CH_0_ERRMSG_WDATA_VAL_SHIFT                              0
+#define DMA_CH_0_ERRMSG_WDATA_VAL_MASK                               0xFFFFFFFF
+
+/* DMA_CH_0_RD_COMP_ADDR_LO */
+#define DMA_CH_0_RD_COMP_ADDR_LO_VAL_SHIFT                           0
+#define DMA_CH_0_RD_COMP_ADDR_LO_VAL_MASK                            0xFFFFFFFF
+
+/* DMA_CH_0_RD_COMP_ADDR_HI */
+#define DMA_CH_0_RD_COMP_ADDR_HI_VAL_SHIFT                           0
+#define DMA_CH_0_RD_COMP_ADDR_HI_VAL_MASK                            0xFFFFFFFF
+
+/* DMA_CH_0_RD_COMP_WDATA */
+#define DMA_CH_0_RD_COMP_WDATA_VAL_SHIFT                             0
+#define DMA_CH_0_RD_COMP_WDATA_VAL_MASK                              0xFFFFFFFF
+
+/* DMA_CH_0_WR_COMP_ADDR_LO */
+#define DMA_CH_0_WR_COMP_ADDR_LO_VAL_SHIFT                           0
+#define DMA_CH_0_WR_COMP_ADDR_LO_VAL_MASK                            0xFFFFFFFF
+
+/* DMA_CH_0_WR_COMP_ADDR_HI */
+#define DMA_CH_0_WR_COMP_ADDR_HI_VAL_SHIFT                           0
+#define DMA_CH_0_WR_COMP_ADDR_HI_VAL_MASK                            0xFFFFFFFF
+
+/* DMA_CH_0_WR_COMP_WDATA */
+#define DMA_CH_0_WR_COMP_WDATA_VAL_SHIFT                             0
+#define DMA_CH_0_WR_COMP_WDATA_VAL_MASK                              0xFFFFFFFF
+
+/* DMA_CH_0_LDMA_SRC_ADDR_LO */
+#define DMA_CH_0_LDMA_SRC_ADDR_LO_VAL_SHIFT                          0
+#define DMA_CH_0_LDMA_SRC_ADDR_LO_VAL_MASK                           0xFFFFFFFF
+
+/* DMA_CH_0_LDMA_SRC_ADDR_HI */
+#define DMA_CH_0_LDMA_SRC_ADDR_HI_VAL_SHIFT                          0
+#define DMA_CH_0_LDMA_SRC_ADDR_HI_VAL_MASK                           0xFFFFFFFF
+
+/* DMA_CH_0_LDMA_DST_ADDR_LO */
+#define DMA_CH_0_LDMA_DST_ADDR_LO_VAL_SHIFT                          0
+#define DMA_CH_0_LDMA_DST_ADDR_LO_VAL_MASK                           0xFFFFFFFF
+
+/* DMA_CH_0_LDMA_DST_ADDR_HI */
+#define DMA_CH_0_LDMA_DST_ADDR_HI_VAL_SHIFT                          0
+#define DMA_CH_0_LDMA_DST_ADDR_HI_VAL_MASK                           0xFFFFFFFF
+
+/* DMA_CH_0_LDMA_TSIZE */
+#define DMA_CH_0_LDMA_TSIZE_VAL_SHIFT                                0
+#define DMA_CH_0_LDMA_TSIZE_VAL_MASK                                 0xFFFFFFFF
+
+/* DMA_CH_0_COMIT_TRANSFER */
+#define DMA_CH_0_COMIT_TRANSFER_PCI_UPS_WKORDR_SHIFT                 0
+#define DMA_CH_0_COMIT_TRANSFER_PCI_UPS_WKORDR_MASK                  0x1
+#define DMA_CH_0_COMIT_TRANSFER_RD_COMP_EN_SHIFT                     1
+#define DMA_CH_0_COMIT_TRANSFER_RD_COMP_EN_MASK                      0x2
+#define DMA_CH_0_COMIT_TRANSFER_WR_COMP_EN_SHIFT                     2
+#define DMA_CH_0_COMIT_TRANSFER_WR_COMP_EN_MASK                      0x4
+#define DMA_CH_0_COMIT_TRANSFER_NOSNOOP_SHIFT                        3
+#define DMA_CH_0_COMIT_TRANSFER_NOSNOOP_MASK                         0x8
+#define DMA_CH_0_COMIT_TRANSFER_SRC_ADDR_INC_DIS_SHIFT               4
+#define DMA_CH_0_COMIT_TRANSFER_SRC_ADDR_INC_DIS_MASK                0x10
+#define DMA_CH_0_COMIT_TRANSFER_DST_ADDR_INC_DIS_SHIFT               5
+#define DMA_CH_0_COMIT_TRANSFER_DST_ADDR_INC_DIS_MASK                0x20
+#define DMA_CH_0_COMIT_TRANSFER_MEM_SET_SHIFT                        6
+#define DMA_CH_0_COMIT_TRANSFER_MEM_SET_MASK                         0x40
+#define DMA_CH_0_COMIT_TRANSFER_MOD_TENSOR_SHIFT                     15
+#define DMA_CH_0_COMIT_TRANSFER_MOD_TENSOR_MASK                      0x8000
+#define DMA_CH_0_COMIT_TRANSFER_CTL_SHIFT                            16
+#define DMA_CH_0_COMIT_TRANSFER_CTL_MASK                             0xFFFF0000
+
+/* DMA_CH_0_STS0 */
+#define DMA_CH_0_STS0_DMA_BUSY_SHIFT                                 0
+#define DMA_CH_0_STS0_DMA_BUSY_MASK                                  0x1
+#define DMA_CH_0_STS0_RD_STS_CTX_FULL_SHIFT                          1
+#define DMA_CH_0_STS0_RD_STS_CTX_FULL_MASK                           0x2
+#define DMA_CH_0_STS0_WR_STS_CTX_FULL_SHIFT                          2
+#define DMA_CH_0_STS0_WR_STS_CTX_FULL_MASK                           0x4
+
+/* DMA_CH_0_STS1 */
+#define DMA_CH_0_STS1_RD_STS_CTX_CNT_SHIFT                           0
+#define DMA_CH_0_STS1_RD_STS_CTX_CNT_MASK                            0xFFFFFFFF
+
+/* DMA_CH_0_STS2 */
+#define DMA_CH_0_STS2_WR_STS_CTX_CNT_SHIFT                           0
+#define DMA_CH_0_STS2_WR_STS_CTX_CNT_MASK                            0xFFFFFFFF
+
+/* DMA_CH_0_STS3 */
+#define DMA_CH_0_STS3_RD_STS_TRN_CNT_SHIFT                           0
+#define DMA_CH_0_STS3_RD_STS_TRN_CNT_MASK                            0xFFFFFFFF
+
+/* DMA_CH_0_STS4 */
+#define DMA_CH_0_STS4_WR_STS_TRN_CNT_SHIFT                           0
+#define DMA_CH_0_STS4_WR_STS_TRN_CNT_MASK                            0xFFFFFFFF
+
+/* DMA_CH_0_SRC_ADDR_LO_STS */
+#define DMA_CH_0_SRC_ADDR_LO_STS_VAL_SHIFT                           0
+#define DMA_CH_0_SRC_ADDR_LO_STS_VAL_MASK                            0xFFFFFFFF
+
+/* DMA_CH_0_SRC_ADDR_HI_STS */
+#define DMA_CH_0_SRC_ADDR_HI_STS_VAL_SHIFT                           0
+#define DMA_CH_0_SRC_ADDR_HI_STS_VAL_MASK                            0xFFFFFFFF
+
+/* DMA_CH_0_SRC_TSIZE_STS */
+#define DMA_CH_0_SRC_TSIZE_STS_VAL_SHIFT                             0
+#define DMA_CH_0_SRC_TSIZE_STS_VAL_MASK                              0xFFFFFFFF
+
+/* DMA_CH_0_DST_ADDR_LO_STS */
+#define DMA_CH_0_DST_ADDR_LO_STS_VAL_SHIFT                           0
+#define DMA_CH_0_DST_ADDR_LO_STS_VAL_MASK                            0xFFFFFFFF
+
+/* DMA_CH_0_DST_ADDR_HI_STS */
+#define DMA_CH_0_DST_ADDR_HI_STS_VAL_SHIFT                           0
+#define DMA_CH_0_DST_ADDR_HI_STS_VAL_MASK                            0xFFFFFFFF
+
+/* DMA_CH_0_DST_TSIZE_STS */
+#define DMA_CH_0_DST_TSIZE_STS_VAL_SHIFT                             0
+#define DMA_CH_0_DST_TSIZE_STS_VAL_MASK                              0xFFFFFFFF
+
+/* DMA_CH_0_RD_RATE_LIM_EN */
+#define DMA_CH_0_RD_RATE_LIM_EN_VAL_SHIFT                            0
+#define DMA_CH_0_RD_RATE_LIM_EN_VAL_MASK                             0x1
+
+/* DMA_CH_0_RD_RATE_LIM_RST_TOKEN */
+#define DMA_CH_0_RD_RATE_LIM_RST_TOKEN_VAL_SHIFT                     0
+#define DMA_CH_0_RD_RATE_LIM_RST_TOKEN_VAL_MASK                      0xFFFF
+
+/* DMA_CH_0_RD_RATE_LIM_SAT */
+#define DMA_CH_0_RD_RATE_LIM_SAT_VAL_SHIFT                           0
+#define DMA_CH_0_RD_RATE_LIM_SAT_VAL_MASK                            0xFFFF
+
+/* DMA_CH_0_RD_RATE_LIM_TOUT */
+#define DMA_CH_0_RD_RATE_LIM_TOUT_VAL_SHIFT                          0
+#define DMA_CH_0_RD_RATE_LIM_TOUT_VAL_MASK                           0x7FFFFFFF
+
+/* DMA_CH_0_WR_RATE_LIM_EN */
+#define DMA_CH_0_WR_RATE_LIM_EN_VAL_SHIFT                            0
+#define DMA_CH_0_WR_RATE_LIM_EN_VAL_MASK                             0x1
+
+/* DMA_CH_0_WR_RATE_LIM_RST_TOKEN */
+#define DMA_CH_0_WR_RATE_LIM_RST_TOKEN_VAL_SHIFT                     0
+#define DMA_CH_0_WR_RATE_LIM_RST_TOKEN_VAL_MASK                      0xFFFF
+
+/* DMA_CH_0_WR_RATE_LIM_SAT */
+#define DMA_CH_0_WR_RATE_LIM_SAT_VAL_SHIFT                           0
+#define DMA_CH_0_WR_RATE_LIM_SAT_VAL_MASK                            0xFFFF
+
+/* DMA_CH_0_WR_RATE_LIM_TOUT */
+#define DMA_CH_0_WR_RATE_LIM_TOUT_VAL_SHIFT                          0
+#define DMA_CH_0_WR_RATE_LIM_TOUT_VAL_MASK                           0x7FFFFFFF
+
+/* DMA_CH_0_CFG2 */
+#define DMA_CH_0_CFG2_FORCE_WORD_SHIFT                               0
+#define DMA_CH_0_CFG2_FORCE_WORD_MASK                                0x1
+
+/* DMA_CH_0_TDMA_CTL */
+#define DMA_CH_0_TDMA_CTL_DTYPE_SHIFT                                0
+#define DMA_CH_0_TDMA_CTL_DTYPE_MASK                                 0x7
+
+/* DMA_CH_0_TDMA_SRC_BASE_ADDR_LO */
+#define DMA_CH_0_TDMA_SRC_BASE_ADDR_LO_VAL_SHIFT                     0
+#define DMA_CH_0_TDMA_SRC_BASE_ADDR_LO_VAL_MASK                      0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_BASE_ADDR_HI */
+#define DMA_CH_0_TDMA_SRC_BASE_ADDR_HI_VAL_SHIFT                     0
+#define DMA_CH_0_TDMA_SRC_BASE_ADDR_HI_VAL_MASK                      0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_ROI_BASE_0 */
+#define DMA_CH_0_TDMA_SRC_ROI_BASE_0_VAL_SHIFT                       0
+#define DMA_CH_0_TDMA_SRC_ROI_BASE_0_VAL_MASK                        0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_ROI_SIZE_0 */
+#define DMA_CH_0_TDMA_SRC_ROI_SIZE_0_VAL_SHIFT                       0
+#define DMA_CH_0_TDMA_SRC_ROI_SIZE_0_VAL_MASK                        0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_0 */
+#define DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_0_VAL_SHIFT                 0
+#define DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_0_VAL_MASK                  0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_START_OFFSET_0 */
+#define DMA_CH_0_TDMA_SRC_START_OFFSET_0_VAL_SHIFT                   0
+#define DMA_CH_0_TDMA_SRC_START_OFFSET_0_VAL_MASK                    0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_STRIDE_0 */
+#define DMA_CH_0_TDMA_SRC_STRIDE_0_VAL_SHIFT                         0
+#define DMA_CH_0_TDMA_SRC_STRIDE_0_VAL_MASK                          0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_ROI_BASE_1 */
+#define DMA_CH_0_TDMA_SRC_ROI_BASE_1_VAL_SHIFT                       0
+#define DMA_CH_0_TDMA_SRC_ROI_BASE_1_VAL_MASK                        0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_ROI_SIZE_1 */
+#define DMA_CH_0_TDMA_SRC_ROI_SIZE_1_VAL_SHIFT                       0
+#define DMA_CH_0_TDMA_SRC_ROI_SIZE_1_VAL_MASK                        0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_1 */
+#define DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_1_VAL_SHIFT                 0
+#define DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_1_VAL_MASK                  0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_START_OFFSET_1 */
+#define DMA_CH_0_TDMA_SRC_START_OFFSET_1_VAL_SHIFT                   0
+#define DMA_CH_0_TDMA_SRC_START_OFFSET_1_VAL_MASK                    0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_STRIDE_1 */
+#define DMA_CH_0_TDMA_SRC_STRIDE_1_VAL_SHIFT                         0
+#define DMA_CH_0_TDMA_SRC_STRIDE_1_VAL_MASK                          0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_ROI_BASE_2 */
+#define DMA_CH_0_TDMA_SRC_ROI_BASE_2_VAL_SHIFT                       0
+#define DMA_CH_0_TDMA_SRC_ROI_BASE_2_VAL_MASK                        0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_ROI_SIZE_2 */
+#define DMA_CH_0_TDMA_SRC_ROI_SIZE_2_VAL_SHIFT                       0
+#define DMA_CH_0_TDMA_SRC_ROI_SIZE_2_VAL_MASK                        0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_2 */
+#define DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_2_VAL_SHIFT                 0
+#define DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_2_VAL_MASK                  0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_START_OFFSET_2 */
+#define DMA_CH_0_TDMA_SRC_START_OFFSET_2_VAL_SHIFT                   0
+#define DMA_CH_0_TDMA_SRC_START_OFFSET_2_VAL_MASK                    0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_STRIDE_2 */
+#define DMA_CH_0_TDMA_SRC_STRIDE_2_VAL_SHIFT                         0
+#define DMA_CH_0_TDMA_SRC_STRIDE_2_VAL_MASK                          0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_ROI_BASE_3 */
+#define DMA_CH_0_TDMA_SRC_ROI_BASE_3_VAL_SHIFT                       0
+#define DMA_CH_0_TDMA_SRC_ROI_BASE_3_VAL_MASK                        0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_ROI_SIZE_3 */
+#define DMA_CH_0_TDMA_SRC_ROI_SIZE_3_VAL_SHIFT                       0
+#define DMA_CH_0_TDMA_SRC_ROI_SIZE_3_VAL_MASK                        0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_3 */
+#define DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_3_VAL_SHIFT                 0
+#define DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_3_VAL_MASK                  0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_START_OFFSET_3 */
+#define DMA_CH_0_TDMA_SRC_START_OFFSET_3_VAL_SHIFT                   0
+#define DMA_CH_0_TDMA_SRC_START_OFFSET_3_VAL_MASK                    0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_STRIDE_3 */
+#define DMA_CH_0_TDMA_SRC_STRIDE_3_VAL_SHIFT                         0
+#define DMA_CH_0_TDMA_SRC_STRIDE_3_VAL_MASK                          0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_ROI_BASE_4 */
+#define DMA_CH_0_TDMA_SRC_ROI_BASE_4_VAL_SHIFT                       0
+#define DMA_CH_0_TDMA_SRC_ROI_BASE_4_VAL_MASK                        0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_ROI_SIZE_4 */
+#define DMA_CH_0_TDMA_SRC_ROI_SIZE_4_VAL_SHIFT                       0
+#define DMA_CH_0_TDMA_SRC_ROI_SIZE_4_VAL_MASK                        0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_4 */
+#define DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_4_VAL_SHIFT                 0
+#define DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_4_VAL_MASK                  0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_START_OFFSET_4 */
+#define DMA_CH_0_TDMA_SRC_START_OFFSET_4_VAL_SHIFT                   0
+#define DMA_CH_0_TDMA_SRC_START_OFFSET_4_VAL_MASK                    0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_STRIDE_4 */
+#define DMA_CH_0_TDMA_SRC_STRIDE_4_VAL_SHIFT                         0
+#define DMA_CH_0_TDMA_SRC_STRIDE_4_VAL_MASK                          0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_BASE_ADDR_LO */
+#define DMA_CH_0_TDMA_DST_BASE_ADDR_LO_VAL_SHIFT                     0
+#define DMA_CH_0_TDMA_DST_BASE_ADDR_LO_VAL_MASK                      0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_BASE_ADDR_HI */
+#define DMA_CH_0_TDMA_DST_BASE_ADDR_HI_VAL_SHIFT                     0
+#define DMA_CH_0_TDMA_DST_BASE_ADDR_HI_VAL_MASK                      0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_ROI_BASE_0 */
+#define DMA_CH_0_TDMA_DST_ROI_BASE_0_VAL_SHIFT                       0
+#define DMA_CH_0_TDMA_DST_ROI_BASE_0_VAL_MASK                        0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_ROI_SIZE_0 */
+#define DMA_CH_0_TDMA_DST_ROI_SIZE_0_VAL_SHIFT                       0
+#define DMA_CH_0_TDMA_DST_ROI_SIZE_0_VAL_MASK                        0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_VALID_ELEMENTS_0 */
+#define DMA_CH_0_TDMA_DST_VALID_ELEMENTS_0_VAL_SHIFT                 0
+#define DMA_CH_0_TDMA_DST_VALID_ELEMENTS_0_VAL_MASK                  0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_START_OFFSET_0 */
+#define DMA_CH_0_TDMA_DST_START_OFFSET_0_VAL_SHIFT                   0
+#define DMA_CH_0_TDMA_DST_START_OFFSET_0_VAL_MASK                    0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_STRIDE_0 */
+#define DMA_CH_0_TDMA_DST_STRIDE_0_VAL_SHIFT                         0
+#define DMA_CH_0_TDMA_DST_STRIDE_0_VAL_MASK                          0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_ROI_BASE_1 */
+#define DMA_CH_0_TDMA_DST_ROI_BASE_1_VAL_SHIFT                       0
+#define DMA_CH_0_TDMA_DST_ROI_BASE_1_VAL_MASK                        0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_ROI_SIZE_1 */
+#define DMA_CH_0_TDMA_DST_ROI_SIZE_1_VAL_SHIFT                       0
+#define DMA_CH_0_TDMA_DST_ROI_SIZE_1_VAL_MASK                        0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_VALID_ELEMENTS_1 */
+#define DMA_CH_0_TDMA_DST_VALID_ELEMENTS_1_VAL_SHIFT                 0
+#define DMA_CH_0_TDMA_DST_VALID_ELEMENTS_1_VAL_MASK                  0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_START_OFFSET_1 */
+#define DMA_CH_0_TDMA_DST_START_OFFSET_1_VAL_SHIFT                   0
+#define DMA_CH_0_TDMA_DST_START_OFFSET_1_VAL_MASK                    0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_STRIDE_1 */
+#define DMA_CH_0_TDMA_DST_STRIDE_1_VAL_SHIFT                         0
+#define DMA_CH_0_TDMA_DST_STRIDE_1_VAL_MASK                          0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_ROI_BASE_2 */
+#define DMA_CH_0_TDMA_DST_ROI_BASE_2_VAL_SHIFT                       0
+#define DMA_CH_0_TDMA_DST_ROI_BASE_2_VAL_MASK                        0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_ROI_SIZE_2 */
+#define DMA_CH_0_TDMA_DST_ROI_SIZE_2_VAL_SHIFT                       0
+#define DMA_CH_0_TDMA_DST_ROI_SIZE_2_VAL_MASK                        0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_VALID_ELEMENTS_2 */
+#define DMA_CH_0_TDMA_DST_VALID_ELEMENTS_2_VAL_SHIFT                 0
+#define DMA_CH_0_TDMA_DST_VALID_ELEMENTS_2_VAL_MASK                  0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_START_OFFSET_2 */
+#define DMA_CH_0_TDMA_DST_START_OFFSET_2_VAL_SHIFT                   0
+#define DMA_CH_0_TDMA_DST_START_OFFSET_2_VAL_MASK                    0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_STRIDE_2 */
+#define DMA_CH_0_TDMA_DST_STRIDE_2_VAL_SHIFT                         0
+#define DMA_CH_0_TDMA_DST_STRIDE_2_VAL_MASK                          0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_ROI_BASE_3 */
+#define DMA_CH_0_TDMA_DST_ROI_BASE_3_VAL_SHIFT                       0
+#define DMA_CH_0_TDMA_DST_ROI_BASE_3_VAL_MASK                        0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_ROI_SIZE_3 */
+#define DMA_CH_0_TDMA_DST_ROI_SIZE_3_VAL_SHIFT                       0
+#define DMA_CH_0_TDMA_DST_ROI_SIZE_3_VAL_MASK                        0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_VALID_ELEMENTS_3 */
+#define DMA_CH_0_TDMA_DST_VALID_ELEMENTS_3_VAL_SHIFT                 0
+#define DMA_CH_0_TDMA_DST_VALID_ELEMENTS_3_VAL_MASK                  0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_START_OFFSET_3 */
+#define DMA_CH_0_TDMA_DST_START_OFFSET_3_VAL_SHIFT                   0
+#define DMA_CH_0_TDMA_DST_START_OFFSET_3_VAL_MASK                    0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_STRIDE_3 */
+#define DMA_CH_0_TDMA_DST_STRIDE_3_VAL_SHIFT                         0
+#define DMA_CH_0_TDMA_DST_STRIDE_3_VAL_MASK                          0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_ROI_BASE_4 */
+#define DMA_CH_0_TDMA_DST_ROI_BASE_4_VAL_SHIFT                       0
+#define DMA_CH_0_TDMA_DST_ROI_BASE_4_VAL_MASK                        0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_ROI_SIZE_4 */
+#define DMA_CH_0_TDMA_DST_ROI_SIZE_4_VAL_SHIFT                       0
+#define DMA_CH_0_TDMA_DST_ROI_SIZE_4_VAL_MASK                        0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_VALID_ELEMENTS_4 */
+#define DMA_CH_0_TDMA_DST_VALID_ELEMENTS_4_VAL_SHIFT                 0
+#define DMA_CH_0_TDMA_DST_VALID_ELEMENTS_4_VAL_MASK                  0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_START_OFFSET_4 */
+#define DMA_CH_0_TDMA_DST_START_OFFSET_4_VAL_SHIFT                   0
+#define DMA_CH_0_TDMA_DST_START_OFFSET_4_VAL_MASK                    0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_STRIDE_4 */
+#define DMA_CH_0_TDMA_DST_STRIDE_4_VAL_SHIFT                         0
+#define DMA_CH_0_TDMA_DST_STRIDE_4_VAL_MASK                          0xFFFFFFFF
+
+/* DMA_CH_0_MEM_INIT_BUSY */
+#define DMA_CH_0_MEM_INIT_BUSY_SBC_DATA_SHIFT                        0
+#define DMA_CH_0_MEM_INIT_BUSY_SBC_DATA_MASK                         0xFF
+#define DMA_CH_0_MEM_INIT_BUSY_SBC_MD_SHIFT                          8
+#define DMA_CH_0_MEM_INIT_BUSY_SBC_MD_MASK                           0x100
+
+#endif /* ASIC_REG_DMA_CH_0_MASKS_H_ */
index 506e71e..19b0f0e 100644 (file)
@@ -88,6 +88,7 @@
 #include "psoc_global_conf_masks.h"
 #include "dma_macro_masks.h"
 #include "dma_qm_0_masks.h"
+#include "dma_ch_0_masks.h"
 #include "tpc0_qm_masks.h"
 #include "tpc0_cmdq_masks.h"
 #include "mme_qm_masks.h"
index 693877e..42d237c 100644 (file)
@@ -1657,17 +1657,10 @@ int hl_vm_init(struct hl_device *hdev)
        struct hl_vm *vm = &hdev->vm;
        int rc;
 
-       rc = hl_mmu_init(hdev);
-       if (rc) {
-               dev_err(hdev->dev, "Failed to init MMU\n");
-               return rc;
-       }
-
        vm->dram_pg_pool = gen_pool_create(__ffs(prop->dram_page_size), -1);
        if (!vm->dram_pg_pool) {
                dev_err(hdev->dev, "Failed to create dram page pool\n");
-               rc = -ENOMEM;
-               goto pool_create_err;
+               return -ENOMEM;
        }
 
        kref_init(&vm->dram_pg_pool_refcount);
@@ -1693,8 +1686,6 @@ int hl_vm_init(struct hl_device *hdev)
 
 pool_add_err:
        gen_pool_destroy(vm->dram_pg_pool);
-pool_create_err:
-       hl_mmu_fini(hdev);
 
        return rc;
 }
@@ -1724,7 +1715,5 @@ void hl_vm_fini(struct hl_device *hdev)
                dev_warn(hdev->dev, "dram_pg_pool was not destroyed on %s\n",
                                __func__);
 
-       hl_mmu_fini(hdev);
-
        vm->init_done = false;
 }
index 10aee31..176c315 100644 (file)
@@ -241,8 +241,9 @@ static int dram_default_mapping_init(struct hl_ctx *ctx)
                hop2_pte_addr, hop3_pte_addr, pte_val;
        int rc, i, j, hop3_allocated = 0;
 
-       if (!hdev->dram_supports_virtual_memory ||
-                       !hdev->dram_default_page_mapping)
+       if ((!hdev->dram_supports_virtual_memory) ||
+                       (!hdev->dram_default_page_mapping) ||
+                       (ctx->asid == HL_KERNEL_ASID_ID))
                return 0;
 
        num_of_hop3 = prop->dram_size_for_default_page_mapping;
@@ -340,8 +341,9 @@ static void dram_default_mapping_fini(struct hl_ctx *ctx)
                hop2_pte_addr, hop3_pte_addr;
        int i, j;
 
-       if (!hdev->dram_supports_virtual_memory ||
-                       !hdev->dram_default_page_mapping)
+       if ((!hdev->dram_supports_virtual_memory) ||
+                       (!hdev->dram_default_page_mapping) ||
+                       (ctx->asid == HL_KERNEL_ASID_ID))
                return;
 
        num_of_hop3 = prop->dram_size_for_default_page_mapping;
@@ -385,12 +387,8 @@ static void dram_default_mapping_fini(struct hl_ctx *ctx)
  * @hdev: habanalabs device structure.
  *
  * This function does the following:
- * - Allocate max_asid zeroed hop0 pgts so no mapping is available.
- * - Enable MMU in H/W.
- * - Invalidate the MMU cache.
  * - Create a pool of pages for pgt_infos.
- *
- * This function depends on DMA QMAN to be working!
+ * - Create a shadow table for pgt
  *
  * Return: 0 for success, non-zero for failure.
  */
@@ -915,6 +913,10 @@ int hl_mmu_map(struct hl_ctx *ctx, u64 virt_addr, u64 phys_addr, u32 page_size)
                return -EFAULT;
        }
 
+       WARN_ONCE((phys_addr & (real_page_size - 1)),
+               "Mapping 0x%llx with page size of 0x%x is erroneous! Address must be divisible by page size",
+               phys_addr, real_page_size);
+
        npages = page_size / real_page_size;
        real_virt_addr = virt_addr;
        real_phys_addr = phys_addr;
index 0e78a04..c98d88c 100644 (file)
@@ -10,6 +10,8 @@
 
 #include <linux/pci.h>
 
+#define HL_PLDM_PCI_ELBI_TIMEOUT_MSEC  (HL_PCI_ELBI_TIMEOUT_MSEC * 10)
+
 /**
  * hl_pci_bars_map() - Map PCI BARs.
  * @hdev: Pointer to hl_device structure.
@@ -88,8 +90,14 @@ static int hl_pci_elbi_write(struct hl_device *hdev, u64 addr, u32 data)
 {
        struct pci_dev *pdev = hdev->pdev;
        ktime_t timeout;
+       u64 msec;
        u32 val;
 
+       if (hdev->pldm)
+               msec = HL_PLDM_PCI_ELBI_TIMEOUT_MSEC;
+       else
+               msec = HL_PCI_ELBI_TIMEOUT_MSEC;
+
        /* Clear previous status */
        pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_STS, 0);
 
@@ -98,7 +106,7 @@ static int hl_pci_elbi_write(struct hl_device *hdev, u64 addr, u32 data)
        pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_CTRL,
                                PCI_CONFIG_ELBI_CTRL_WRITE);
 
-       timeout = ktime_add_ms(ktime_get(), 10);
+       timeout = ktime_add_ms(ktime_get(), msec);
        for (;;) {
                pci_read_config_dword(pdev, mmPCI_CONFIG_ELBI_STS, &val);
                if (val & PCI_CONFIG_ELBI_STS_MASK)
index c900ab1..25eb46d 100644 (file)
@@ -328,10 +328,6 @@ static ssize_t pci_addr_show(struct device *dev, struct device_attribute *attr,
 {
        struct hl_device *hdev = dev_get_drvdata(dev);
 
-       /* Use dummy, fixed address for simulator */
-       if (!hdev->pdev)
-               return sprintf(buf, "0000:%02d:00.0\n", hdev->id);
-
        return sprintf(buf, "%04x:%02x:%02x.%x\n",
                        pci_domain_nr(hdev->pdev->bus),
                        hdev->pdev->bus->number,
index 3431a82..c12406f 100644 (file)
@@ -3,7 +3,7 @@
  *  isl29003.c - Linux kernel module for
  *     Intersil ISL29003 ambient light sensor
  *
- *  See file:Documentation/misc-devices/isl29003
+ *  See file:Documentation/misc-devices/isl29003.rst
  *
  *  Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
  *
@@ -377,7 +377,7 @@ static int isl29003_init_client(struct i2c_client *client)
 static int isl29003_probe(struct i2c_client *client,
                                    const struct i2c_device_id *id)
 {
-       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct i2c_adapter *adapter = client->adapter;
        struct isl29003_data *data;
        int err = 0;
 
index 4cfad45..bb2fec4 100644 (file)
@@ -7,7 +7,6 @@ config SENSORS_LIS3_SPI
        tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)"
        depends on !ACPI && SPI_MASTER && INPUT
        select SENSORS_LIS3LV02D
-       default n
        help
          This driver provides support for the LIS3LV02Dx accelerometer connected
          via SPI. The accelerometer data is readable via
@@ -24,7 +23,6 @@ config SENSORS_LIS3_I2C
        tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (I2C)"
        depends on I2C && INPUT
        select SENSORS_LIS3LV02D
-       default n
        help
          This driver provides support for the LIS3LV02Dx accelerometer connected
          via I2C. The accelerometer data is readable via
index 951c984..fb10eaf 100644 (file)
@@ -15,8 +15,7 @@ KCOV_INSTRUMENT_rodata.o      := n
 
 OBJCOPYFLAGS :=
 OBJCOPYFLAGS_rodata_objcopy.o  := \
-                       --set-section-flags .text=alloc,readonly \
-                       --rename-section .text=.rodata
+                       --rename-section .text=.rodata,alloc,readonly,load
 targets += rodata.o rodata_objcopy.o
 $(obj)/rodata_objcopy.o: $(obj)/rodata.o FORCE
        $(call if_changed,objcopy)
index d9fcfd3..1606658 100644 (file)
@@ -266,3 +266,69 @@ void lkdtm_STACK_GUARD_PAGE_TRAILING(void)
 
        pr_err("FAIL: accessed page after stack!\n");
 }
+
+void lkdtm_UNSET_SMEP(void)
+{
+#ifdef CONFIG_X86_64
+#define MOV_CR4_DEPTH  64
+       void (*direct_write_cr4)(unsigned long val);
+       unsigned char *insn;
+       unsigned long cr4;
+       int i;
+
+       cr4 = native_read_cr4();
+
+       if ((cr4 & X86_CR4_SMEP) != X86_CR4_SMEP) {
+               pr_err("FAIL: SMEP not in use\n");
+               return;
+       }
+       cr4 &= ~(X86_CR4_SMEP);
+
+       pr_info("trying to clear SMEP normally\n");
+       native_write_cr4(cr4);
+       if (cr4 == native_read_cr4()) {
+               pr_err("FAIL: pinning SMEP failed!\n");
+               cr4 |= X86_CR4_SMEP;
+               pr_info("restoring SMEP\n");
+               native_write_cr4(cr4);
+               return;
+       }
+       pr_info("ok: SMEP did not get cleared\n");
+
+       /*
+        * To test the post-write pinning verification we need to call
+        * directly into the middle of native_write_cr4() where the
+        * cr4 write happens, skipping any pinning. This searches for
+        * the cr4 writing instruction.
+        */
+       insn = (unsigned char *)native_write_cr4;
+       for (i = 0; i < MOV_CR4_DEPTH; i++) {
+               /* mov %rdi, %cr4 */
+               if (insn[i] == 0x0f && insn[i+1] == 0x22 && insn[i+2] == 0xe7)
+                       break;
+               /* mov %rdi,%rax; mov %rax, %cr4 */
+               if (insn[i]   == 0x48 && insn[i+1] == 0x89 &&
+                   insn[i+2] == 0xf8 && insn[i+3] == 0x0f &&
+                   insn[i+4] == 0x22 && insn[i+5] == 0xe0)
+                       break;
+       }
+       if (i >= MOV_CR4_DEPTH) {
+               pr_info("ok: cannot locate cr4 writing call gadget\n");
+               return;
+       }
+       direct_write_cr4 = (void *)(insn + i);
+
+       pr_info("trying to clear SMEP with call gadget\n");
+       direct_write_cr4(cr4);
+       if (native_read_cr4() & X86_CR4_SMEP) {
+               pr_info("ok: SMEP removal was reverted\n");
+       } else {
+               pr_err("FAIL: cleared SMEP not detected!\n");
+               cr4 |= X86_CR4_SMEP;
+               pr_info("restoring SMEP\n");
+               native_write_cr4(cr4);
+       }
+#else
+       pr_err("FAIL: this test is x86_64-only\n");
+#endif
+}
index bba49ab..66ae6b2 100644 (file)
@@ -114,12 +114,16 @@ static const struct crashtype crashtypes[] = {
        CRASHTYPE(CORRUPT_USER_DS),
        CRASHTYPE(STACK_GUARD_PAGE_LEADING),
        CRASHTYPE(STACK_GUARD_PAGE_TRAILING),
+       CRASHTYPE(UNSET_SMEP),
        CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE),
        CRASHTYPE(OVERWRITE_ALLOCATION),
        CRASHTYPE(WRITE_AFTER_FREE),
        CRASHTYPE(READ_AFTER_FREE),
        CRASHTYPE(WRITE_BUDDY_AFTER_FREE),
        CRASHTYPE(READ_BUDDY_AFTER_FREE),
+       CRASHTYPE(SLAB_FREE_DOUBLE),
+       CRASHTYPE(SLAB_FREE_CROSS),
+       CRASHTYPE(SLAB_FREE_PAGE),
        CRASHTYPE(SOFTLOCKUP),
        CRASHTYPE(HARDLOCKUP),
        CRASHTYPE(SPINLOCKUP),
@@ -387,7 +391,7 @@ static int __init lkdtm_module_init(void)
 {
        struct crashpoint *crashpoint = NULL;
        const struct crashtype *crashtype = NULL;
-       int ret = -EINVAL;
+       int ret;
        int i;
 
        /* Neither or both of these need to be set */
@@ -426,25 +430,17 @@ static int __init lkdtm_module_init(void)
        lkdtm_bugs_init(&recur_count);
        lkdtm_perms_init();
        lkdtm_usercopy_init();
+       lkdtm_heap_init();
 
        /* Register debugfs interface */
        lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL);
-       if (!lkdtm_debugfs_root) {
-               pr_err("creating root dir failed\n");
-               return -ENODEV;
-       }
 
        /* Install debugfs trigger files. */
        for (i = 0; i < ARRAY_SIZE(crashpoints); i++) {
                struct crashpoint *cur = &crashpoints[i];
-               struct dentry *de;
 
-               de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root,
-                                        cur, &cur->fops);
-               if (de == NULL) {
-                       pr_err("could not create crashpoint %s\n", cur->name);
-                       goto out_err;
-               }
+               debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root, cur,
+                                   &cur->fops);
        }
 
        /* Install crashpoint if one was selected. */
@@ -472,6 +468,7 @@ static void __exit lkdtm_module_exit(void)
        debugfs_remove_recursive(lkdtm_debugfs_root);
 
        /* Handle test-specific clean-up. */
+       lkdtm_heap_exit();
        lkdtm_usercopy_exit();
 
        if (lkdtm_kprobe != NULL)
index 65026d7..3c5cec8 100644 (file)
@@ -7,6 +7,10 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 
+static struct kmem_cache *double_free_cache;
+static struct kmem_cache *a_cache;
+static struct kmem_cache *b_cache;
+
 /*
  * This tries to stay within the next largest power-of-2 kmalloc cache
  * to avoid actually overwriting anything important if it's not detected
@@ -146,3 +150,71 @@ void lkdtm_READ_BUDDY_AFTER_FREE(void)
 
        kfree(val);
 }
+
+void lkdtm_SLAB_FREE_DOUBLE(void)
+{
+       int *val;
+
+       val = kmem_cache_alloc(double_free_cache, GFP_KERNEL);
+       if (!val) {
+               pr_info("Unable to allocate double_free_cache memory.\n");
+               return;
+       }
+
+       /* Just make sure we got real memory. */
+       *val = 0x12345678;
+       pr_info("Attempting double slab free ...\n");
+       kmem_cache_free(double_free_cache, val);
+       kmem_cache_free(double_free_cache, val);
+}
+
+void lkdtm_SLAB_FREE_CROSS(void)
+{
+       int *val;
+
+       val = kmem_cache_alloc(a_cache, GFP_KERNEL);
+       if (!val) {
+               pr_info("Unable to allocate a_cache memory.\n");
+               return;
+       }
+
+       /* Just make sure we got real memory. */
+       *val = 0x12345679;
+       pr_info("Attempting cross-cache slab free ...\n");
+       kmem_cache_free(b_cache, val);
+}
+
+void lkdtm_SLAB_FREE_PAGE(void)
+{
+       unsigned long p = __get_free_page(GFP_KERNEL);
+
+       pr_info("Attempting non-Slab slab free ...\n");
+       kmem_cache_free(NULL, (void *)p);
+       free_page(p);
+}
+
+/*
+ * We have constructors to keep the caches distinctly separated without
+ * needing to boot with "slab_nomerge".
+ */
+static void ctor_double_free(void *region)
+{ }
+static void ctor_a(void *region)
+{ }
+static void ctor_b(void *region)
+{ }
+
+void __init lkdtm_heap_init(void)
+{
+       double_free_cache = kmem_cache_create("lkdtm-heap-double_free",
+                                             64, 0, 0, ctor_double_free);
+       a_cache = kmem_cache_create("lkdtm-heap-a", 64, 0, 0, ctor_a);
+       b_cache = kmem_cache_create("lkdtm-heap-b", 64, 0, 0, ctor_b);
+}
+
+void __exit lkdtm_heap_exit(void)
+{
+       kmem_cache_destroy(double_free_cache);
+       kmem_cache_destroy(a_cache);
+       kmem_cache_destroy(b_cache);
+}
index 23dc565..6a284a8 100644 (file)
@@ -26,13 +26,19 @@ void lkdtm_CORRUPT_LIST_DEL(void);
 void lkdtm_CORRUPT_USER_DS(void);
 void lkdtm_STACK_GUARD_PAGE_LEADING(void);
 void lkdtm_STACK_GUARD_PAGE_TRAILING(void);
+void lkdtm_UNSET_SMEP(void);
 
 /* lkdtm_heap.c */
+void __init lkdtm_heap_init(void);
+void __exit lkdtm_heap_exit(void);
 void lkdtm_OVERWRITE_ALLOCATION(void);
 void lkdtm_WRITE_AFTER_FREE(void);
 void lkdtm_READ_AFTER_FREE(void);
 void lkdtm_WRITE_BUDDY_AFTER_FREE(void);
 void lkdtm_READ_BUDDY_AFTER_FREE(void);
+void lkdtm_SLAB_FREE_DOUBLE(void);
+void lkdtm_SLAB_FREE_CROSS(void);
+void lkdtm_SLAB_FREE_PAGE(void);
 
 /* lkdtm_perms.c */
 void __init lkdtm_perms_init(void);
index 0970142..a26c716 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/kernel.h>
 #include <linux/device.h>
 #include <linux/debugfs.h>
+#include <linux/seq_file.h>
 
 #include <linux/mei.h>
 
 #include "client.h"
 #include "hw.h"
 
-static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf,
-                                       size_t cnt, loff_t *ppos)
+static int mei_dbgfs_meclients_show(struct seq_file *m, void *unused)
 {
-       struct mei_device *dev = fp->private_data;
+       struct mei_device *dev = m->private;
        struct mei_me_client *me_cl;
-       size_t bufsz = 1;
-       char *buf;
        int i = 0;
-       int pos = 0;
-       int ret;
 
-#define HDR \
-"  |id|fix|         UUID                       |con|msg len|sb|refc|\n"
+       if (!dev)
+               return -ENODEV;
 
        down_read(&dev->me_clients_rwsem);
-       list_for_each_entry(me_cl, &dev->me_clients, list)
-               bufsz++;
-
-       bufsz *= sizeof(HDR) + 1;
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf) {
-               up_read(&dev->me_clients_rwsem);
-               return -ENOMEM;
-       }
 
-       pos += scnprintf(buf + pos, bufsz - pos, HDR);
-#undef HDR
+       seq_puts(m, "  |id|fix|         UUID                       |con|msg len|sb|refc|\n");
 
        /*  if the driver is not enabled the list won't be consistent */
        if (dev->dev_state != MEI_DEV_ENABLED)
                goto out;
 
        list_for_each_entry(me_cl, &dev->me_clients, list) {
-
-               if (mei_me_cl_get(me_cl)) {
-                       pos += scnprintf(buf + pos, bufsz - pos,
-                               "%2d|%2d|%3d|%pUl|%3d|%7d|%2d|%4d|\n",
-                               i++, me_cl->client_id,
-                               me_cl->props.fixed_address,
-                               &me_cl->props.protocol_name,
-                               me_cl->props.max_number_of_connections,
-                               me_cl->props.max_msg_length,
-                               me_cl->props.single_recv_buf,
-                               kref_read(&me_cl->refcnt));
-
-                       mei_me_cl_put(me_cl);
-               }
+               if (!mei_me_cl_get(me_cl))
+                       continue;
+
+               seq_printf(m, "%2d|%2d|%3d|%pUl|%3d|%7d|%2d|%4d|\n",
+                          i++, me_cl->client_id,
+                          me_cl->props.fixed_address,
+                          &me_cl->props.protocol_name,
+                          me_cl->props.max_number_of_connections,
+                          me_cl->props.max_msg_length,
+                          me_cl->props.single_recv_buf,
+                          kref_read(&me_cl->refcnt));
+               mei_me_cl_put(me_cl);
        }
 
 out:
        up_read(&dev->me_clients_rwsem);
-       ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
-       kfree(buf);
-       return ret;
+       return 0;
 }
+DEFINE_SHOW_ATTRIBUTE(mei_dbgfs_meclients);
 
-static const struct file_operations mei_dbgfs_fops_meclients = {
-       .open = simple_open,
-       .read = mei_dbgfs_read_meclients,
-       .llseek = generic_file_llseek,
-};
-
-static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf,
-                                       size_t cnt, loff_t *ppos)
+static int mei_dbgfs_active_show(struct seq_file *m, void *unused)
 {
-       struct mei_device *dev = fp->private_data;
+       struct mei_device *dev = m->private;
        struct mei_cl *cl;
-       size_t bufsz = 1;
-       char *buf;
        int i = 0;
-       int pos = 0;
-       int ret;
-
-#define HDR "   |me|host|state|rd|wr|wrq\n"
 
        if (!dev)
                return -ENODEV;
 
        mutex_lock(&dev->device_lock);
 
-       /*
-        * if the driver is not enabled the list won't be consistent,
-        * we output empty table
-        */
-       if (dev->dev_state == MEI_DEV_ENABLED)
-               list_for_each_entry(cl, &dev->file_list, link)
-                       bufsz++;
-
-       bufsz *= sizeof(HDR) + 1;
-
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if  (!buf) {
-               mutex_unlock(&dev->device_lock);
-               return -ENOMEM;
-       }
-
-       pos += scnprintf(buf + pos, bufsz - pos, HDR);
-#undef HDR
+       seq_puts(m, "   |me|host|state|rd|wr|wrq\n");
 
        /*  if the driver is not enabled the list won't be consistent */
        if (dev->dev_state != MEI_DEV_ENABLED)
@@ -120,76 +73,44 @@ static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf,
 
        list_for_each_entry(cl, &dev->file_list, link) {
 
-               pos += scnprintf(buf + pos, bufsz - pos,
-                       "%3d|%2d|%4d|%5d|%2d|%2d|%3u\n",
-                       i, mei_cl_me_id(cl), cl->host_client_id, cl->state,
-                       !list_empty(&cl->rd_completed), cl->writing_state,
-                       cl->tx_cb_queued);
+               seq_printf(m, "%3d|%2d|%4d|%5d|%2d|%2d|%3u\n",
+                          i, mei_cl_me_id(cl), cl->host_client_id, cl->state,
+                          !list_empty(&cl->rd_completed), cl->writing_state,
+                          cl->tx_cb_queued);
                i++;
        }
 out:
        mutex_unlock(&dev->device_lock);
-       ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
-       kfree(buf);
-       return ret;
+       return 0;
 }
+DEFINE_SHOW_ATTRIBUTE(mei_dbgfs_active);
 
-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)
+static int mei_dbgfs_devstate_show(struct seq_file *m, void *unused)
 {
-       struct mei_device *dev = fp->private_data;
-       const size_t bufsz = 1024;
-       char *buf = kzalloc(bufsz, GFP_KERNEL);
-       int pos = 0;
-       int ret;
-
-       if  (!buf)
-               return -ENOMEM;
+       struct mei_device *dev = m->private;
 
-       pos += scnprintf(buf + pos, bufsz - pos, "dev: %s\n",
-                       mei_dev_state_str(dev->dev_state));
-       pos += scnprintf(buf + pos, bufsz - pos, "hbm: %s\n",
-                       mei_hbm_state_str(dev->hbm_state));
+       seq_printf(m, "dev: %s\n", mei_dev_state_str(dev->dev_state));
+       seq_printf(m, "hbm: %s\n", mei_hbm_state_str(dev->hbm_state));
 
        if (dev->hbm_state >= MEI_HBM_ENUM_CLIENTS &&
            dev->hbm_state <= MEI_HBM_STARTED) {
-               pos += scnprintf(buf + pos, bufsz - pos, "hbm features:\n");
-               pos += scnprintf(buf + pos, bufsz - pos, "\tPG: %01d\n",
-                                dev->hbm_f_pg_supported);
-               pos += scnprintf(buf + pos, bufsz - pos, "\tDC: %01d\n",
-                                dev->hbm_f_dc_supported);
-               pos += scnprintf(buf + pos, bufsz - pos, "\tIE: %01d\n",
-                                dev->hbm_f_ie_supported);
-               pos += scnprintf(buf + pos, bufsz - pos, "\tDOT: %01d\n",
-                                dev->hbm_f_dot_supported);
-               pos += scnprintf(buf + pos, bufsz - pos, "\tEV: %01d\n",
-                                dev->hbm_f_ev_supported);
-               pos += scnprintf(buf + pos, bufsz - pos, "\tFA: %01d\n",
-                                dev->hbm_f_fa_supported);
-               pos += scnprintf(buf + pos, bufsz - pos, "\tOS: %01d\n",
-                                dev->hbm_f_os_supported);
-               pos += scnprintf(buf + pos, bufsz - pos, "\tDR: %01d\n",
-                                dev->hbm_f_dr_supported);
+               seq_puts(m, "hbm features:\n");
+               seq_printf(m, "\tPG: %01d\n", dev->hbm_f_pg_supported);
+               seq_printf(m, "\tDC: %01d\n", dev->hbm_f_dc_supported);
+               seq_printf(m, "\tIE: %01d\n", dev->hbm_f_ie_supported);
+               seq_printf(m, "\tDOT: %01d\n", dev->hbm_f_dot_supported);
+               seq_printf(m, "\tEV: %01d\n", dev->hbm_f_ev_supported);
+               seq_printf(m, "\tFA: %01d\n", dev->hbm_f_fa_supported);
+               seq_printf(m, "\tOS: %01d\n", dev->hbm_f_os_supported);
+               seq_printf(m, "\tDR: %01d\n", dev->hbm_f_dr_supported);
        }
 
-       pos += scnprintf(buf + pos, bufsz - pos, "pg:  %s, %s\n",
-                       mei_pg_is_enabled(dev) ? "ENABLED" : "DISABLED",
-                       mei_pg_state_str(mei_pg_state(dev)));
-       ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
-       kfree(buf);
-       return ret;
+       seq_printf(m, "pg:  %s, %s\n",
+                  mei_pg_is_enabled(dev) ? "ENABLED" : "DISABLED",
+                  mei_pg_state_str(mei_pg_state(dev)));
+       return 0;
 }
-static const struct file_operations mei_dbgfs_fops_devstate = {
-       .open = simple_open,
-       .read = mei_dbgfs_read_devstate,
-       .llseek = generic_file_llseek,
-};
+DEFINE_SHOW_ATTRIBUTE(mei_dbgfs_devstate);
 
 static ssize_t mei_dbgfs_write_allow_fa(struct file *file,
                                        const char __user *user_buf,
@@ -208,7 +129,7 @@ static ssize_t mei_dbgfs_write_allow_fa(struct file *file,
        return ret;
 }
 
-static const struct file_operations mei_dbgfs_fops_allow_fa = {
+static const struct file_operations mei_dbgfs_allow_fa_fops = {
        .open = simple_open,
        .read = debugfs_read_file_bool,
        .write = mei_dbgfs_write_allow_fa,
@@ -233,47 +154,21 @@ void mei_dbgfs_deregister(struct mei_device *dev)
  *
  * @dev: the mei device structure
  * @name: the mei device name
- *
- * Return: 0 on success, <0 on failure.
  */
-int mei_dbgfs_register(struct mei_device *dev, const char *name)
+void mei_dbgfs_register(struct mei_device *dev, const char *name)
 {
-       struct dentry *dir, *f;
+       struct dentry *dir;
 
        dir = debugfs_create_dir(name, NULL);
-       if (!dir)
-               return -ENOMEM;
-
        dev->dbgfs_dir = dir;
 
-       f = debugfs_create_file("meclients", S_IRUSR, dir,
-                               dev, &mei_dbgfs_fops_meclients);
-       if (!f) {
-               dev_err(dev->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->dev, "active: registration failed\n");
-               goto err;
-       }
-       f = debugfs_create_file("devstate", S_IRUSR, dir,
-                               dev, &mei_dbgfs_fops_devstate);
-       if (!f) {
-               dev_err(dev->dev, "devstate: registration failed\n");
-               goto err;
-       }
-       f = debugfs_create_file("allow_fixed_address", S_IRUSR | S_IWUSR, dir,
-                               &dev->allow_fixed_address,
-                               &mei_dbgfs_fops_allow_fa);
-       if (!f) {
-               dev_err(dev->dev, "allow_fixed_address: registration failed\n");
-               goto err;
-       }
-       return 0;
-err:
-       mei_dbgfs_deregister(dev);
-       return -ENODEV;
+       debugfs_create_file("meclients", S_IRUSR, dir, dev,
+                           &mei_dbgfs_meclients_fops);
+       debugfs_create_file("active", S_IRUSR, dir, dev,
+                           &mei_dbgfs_active_fops);
+       debugfs_create_file("devstate", S_IRUSR, dir, dev,
+                           &mei_dbgfs_devstate_fops);
+       debugfs_create_file("allow_fixed_address", S_IRUSR | S_IWUSR, dir,
+                           &dev->allow_fixed_address,
+                           &mei_dbgfs_allow_fa_fops);
 }
-
index b070002..ed81693 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Copyright © 2019 Intel Corporation
  *
- * Mei_hdcp.c: HDCP client driver for mei bus
+ * mei_hdcp.c: HDCP client driver for mei bus
  *
  * Author:
  * Ramalingam C <ramalingam.c@intel.com>
 /**
  * DOC: MEI_HDCP Client Driver
  *
- * This is a client driver to the mei_bus to make the HDCP2.2 services of
- * ME FW available for the interested consumers like I915.
- *
- * This module will act as a translation layer between HDCP protocol
- * implementor(I915) and ME FW by translating HDCP2.2 authentication
- * messages to ME FW command payloads and vice versa.
+ * The mei_hdcp driver acts as a translation layer between HDCP 2.2
+ * protocol  implementer (I915) and ME FW by translating HDCP2.2
+ * negotiation messages to ME FW command payloads and vice versa.
  */
 
 #include <linux/module.h>
index ad02097..f894d1f 100644 (file)
@@ -984,16 +984,10 @@ int mei_register(struct mei_device *dev, struct device *parent)
                goto err_dev_create;
        }
 
-       ret = mei_dbgfs_register(dev, dev_name(clsdev));
-       if (ret) {
-               dev_err(clsdev, "cannot register debugfs ret = %d\n", ret);
-               goto err_dev_dbgfs;
-       }
+       mei_dbgfs_register(dev, dev_name(clsdev));
 
        return 0;
 
-err_dev_dbgfs:
-       device_destroy(mei_class, devno);
 err_dev_create:
        cdev_del(&dev->cdev);
 err_dev_add:
index fca832f..f71a023 100644 (file)
@@ -718,13 +718,10 @@ bool mei_hbuf_acquire(struct mei_device *dev);
 bool mei_write_is_idle(struct mei_device *dev);
 
 #if IS_ENABLED(CONFIG_DEBUG_FS)
-int mei_dbgfs_register(struct mei_device *dev, const char *name);
+void mei_dbgfs_register(struct mei_device *dev, const char *name);
 void mei_dbgfs_deregister(struct mei_device *dev);
 #else
-static inline int mei_dbgfs_register(struct mei_device *dev, const char *name)
-{
-       return 0;
-}
+static inline void mei_dbgfs_register(struct mei_device *dev, const char *name) {}
 static inline void mei_dbgfs_deregister(struct mei_device *dev) {}
 #endif /* CONFIG_DEBUG_FS */
 
index bf7a60c..3ee3d24 100644 (file)
@@ -51,25 +51,13 @@ DEFINE_SHOW_ATTRIBUTE(mic_intr);
  */
 void __init mic_create_card_debug_dir(struct mic_driver *mdrv)
 {
-       struct dentry *d;
-
        if (!mic_dbg)
                return;
 
        mdrv->dbg_dir = debugfs_create_dir(mdrv->name, mic_dbg);
-       if (!mdrv->dbg_dir) {
-               dev_err(mdrv->dev, "Cant create dbg_dir %s\n", mdrv->name);
-               return;
-       }
-
-       d = debugfs_create_file("intr_test", 0444, mdrv->dbg_dir,
-               mdrv, &mic_intr_fops);
 
-       if (!d) {
-               dev_err(mdrv->dev,
-                       "Cant create dbg intr_test %s\n", mdrv->name);
-               return;
-       }
+       debugfs_create_file("intr_test", 0444, mdrv->dbg_dir, mdrv,
+                           &mic_intr_fops);
 }
 
 /**
@@ -89,8 +77,6 @@ void mic_delete_card_debug_dir(struct mic_driver *mdrv)
 void __init mic_init_card_debugfs(void)
 {
        mic_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL);
-       if (!mic_dbg)
-               pr_err("can't create debugfs dir\n");
 }
 
 /**
index 8e3f458..2fc9f4b 100644 (file)
@@ -93,8 +93,6 @@ void cosm_create_debug_dir(struct cosm_device *cdev)
 
        scnprintf(name, sizeof(name), "mic%d", cdev->index);
        cdev->dbg_dir = debugfs_create_dir(name, cosm_dbg);
-       if (!cdev->dbg_dir)
-               return;
 
        debugfs_create_file("log_buf", 0444, cdev->dbg_dir, cdev,
                            &log_buf_fops);
@@ -113,8 +111,6 @@ void cosm_delete_debug_dir(struct cosm_device *cdev)
 void cosm_init_debugfs(void)
 {
        cosm_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL);
-       if (!cosm_dbg)
-               pr_err("can't create debugfs dir\n");
 }
 
 void cosm_exit_debugfs(void)
index 7ef8efe..8a8e416 100644 (file)
@@ -113,8 +113,6 @@ void mic_create_debug_dir(struct mic_device *mdev)
 
        scnprintf(name, sizeof(name), "mic%d", mdev->id);
        mdev->dbg_dir = debugfs_create_dir(name, mic_dbg);
-       if (!mdev->dbg_dir)
-               return;
 
        debugfs_create_file("smpt", 0444, mdev->dbg_dir, mdev,
                            &mic_smpt_fops);
@@ -143,8 +141,6 @@ void mic_delete_debug_dir(struct mic_device *mdev)
 void __init mic_init_debugfs(void)
 {
        mic_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL);
-       if (!mic_dbg)
-               pr_err("can't create debugfs dir\n");
 }
 
 /**
index a682048..8fe38e7 100644 (file)
@@ -103,11 +103,6 @@ DEFINE_SHOW_ATTRIBUTE(scif_rma);
 void __init scif_init_debugfs(void)
 {
        scif_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL);
-       if (!scif_dbg) {
-               dev_err(scif_info.mdev.this_device,
-                       "can't create debugfs dir scif\n");
-               return;
-       }
 
        debugfs_create_file("scif_dev", 0444, scif_dbg, NULL, &scif_dev_fops);
        debugfs_create_file("scif_rma", 0444, scif_dbg, NULL, &scif_rma_fops);
index 490e3bd..e2278bf 100644 (file)
@@ -133,6 +133,7 @@ static int scif_setup_scifdev(void)
 static void scif_destroy_scifdev(void)
 {
        kfree(scif_dev);
+       scif_dev = NULL;
 }
 
 static int scif_probe(struct scif_hw_dev *sdev)
index ed59cd7..9d4f175 100644 (file)
@@ -174,10 +174,6 @@ void vop_init_debugfs(struct vop_info *vi)
 
        snprintf(name, sizeof(name), "%s%d", KBUILD_MODNAME, vi->vpdev->dnode);
        vi->dbg = debugfs_create_dir(name, NULL);
-       if (!vi->dbg) {
-               pr_err("can't create debugfs dir vop\n");
-               return;
-       }
        debugfs_create_file("dp", 0444, vi->dbg, vi, &vop_dp_fops);
        debugfs_create_file("vdev_info", 0444, vi->dbg, vi, &vop_vdev_info_fops);
 }
index 7fb6d39..1916fa6 100644 (file)
@@ -5,7 +5,6 @@
 
 config OCXL_BASE
        bool
-       default n
        select PPC_COPRO_BASE
 
 config OCXL
index bab9c93..994563a 100644 (file)
@@ -69,6 +69,7 @@ static void xsl_fault_error(void *data, u64 addr, u64 dsisr)
 int ocxl_context_attach(struct ocxl_context *ctx, u64 amr, struct mm_struct *mm)
 {
        int rc;
+       unsigned long pidr = 0;
 
        // Locks both status & tidr
        mutex_lock(&ctx->status_mutex);
@@ -77,9 +78,11 @@ int ocxl_context_attach(struct ocxl_context *ctx, u64 amr, struct mm_struct *mm)
                goto out;
        }
 
-       rc = ocxl_link_add_pe(ctx->afu->fn->link, ctx->pasid,
-                       mm->context.id, ctx->tidr, amr, mm,
-                       xsl_fault_error, ctx);
+       if (mm)
+               pidr = mm->context.id;
+
+       rc = ocxl_link_add_pe(ctx->afu->fn->link, ctx->pasid, pidr, ctx->tidr,
+                             amr, mm, xsl_fault_error, ctx);
        if (rc)
                goto out;
 
index cce5b0d..58d111a 100644 (file)
@@ -224,6 +224,17 @@ static irqreturn_t xsl_fault_handler(int irq, void *data)
                ack_irq(spa, ADDRESS_ERROR);
                return IRQ_HANDLED;
        }
+
+       if (!pe_data->mm) {
+               /*
+                * translation fault from a kernel context - an OpenCAPI
+                * device tried to access a bad kernel address
+                */
+               rcu_read_unlock();
+               pr_warn("Unresolved OpenCAPI xsl fault in kernel context\n");
+               ack_irq(spa, ADDRESS_ERROR);
+               return IRQ_HANDLED;
+       }
        WARN_ON(pe_data->mm->context.id != pid);
 
        if (mmget_not_zero(pe_data->mm)) {
@@ -523,7 +534,13 @@ int ocxl_link_add_pe(void *link_handle, int pasid, u32 pidr, u32 tidr,
        pe->amr = cpu_to_be64(amr);
        pe->software_state = cpu_to_be32(SPA_PE_VALID);
 
-       mm_context_add_copro(mm);
+       /*
+        * For user contexts, register a copro so that TLBIs are seen
+        * by the nest MMU. If we have a kernel context, TLBIs are
+        * already global.
+        */
+       if (mm)
+               mm_context_add_copro(mm);
        /*
         * Barrier is to make sure PE is visible in the SPA before it
         * is used by the device. It also helps with the global TLBI
@@ -546,7 +563,8 @@ int ocxl_link_add_pe(void *link_handle, int pasid, u32 pidr, u32 tidr,
         * have a reference on mm_users. Incrementing mm_count solves
         * the problem.
         */
-       mmgrab(mm);
+       if (mm)
+               mmgrab(mm);
        trace_ocxl_context_add(current->pid, spa->spa_mem, pasid, pidr, tidr);
 unlock:
        mutex_unlock(&spa->spa_lock);
@@ -652,8 +670,10 @@ int ocxl_link_remove_pe(void *link_handle, int pasid)
        if (!pe_data) {
                WARN(1, "Couldn't find pe data when removing PE\n");
        } else {
-               mm_context_remove_copro(pe_data->mm);
-               mmdrop(pe_data->mm);
+               if (pe_data->mm) {
+                       mm_context_remove_copro(pe_data->mm);
+                       mmdrop(pe_data->mm);
+               }
                kfree_rcu(pe_data, rcu);
        }
 unlock:
index 3eba1c4..782ce95 100644 (file)
@@ -70,7 +70,7 @@ xpc_get_rsvd_page_pa(int nasid)
        unsigned long rp_pa = nasid;    /* seed with nasid */
        size_t len = 0;
        size_t buf_len = 0;
-       void *buf = buf;
+       void *buf = NULL;
        void *buf_base = NULL;
        enum xp_retval (*get_partition_rsvd_page_pa)
                (void *, u64 *, unsigned long *, size_t *) =
index 18ca938..a36ed1f 100644 (file)
@@ -748,10 +748,6 @@ static int kim_probe(struct platform_device *pdev)
        pr_info("sysfs entries created\n");
 
        kim_debugfs_dir = debugfs_create_dir("ti-st", NULL);
-       if (!kim_debugfs_dir) {
-               pr_err(" debugfs entries creation failed ");
-               return 0;
-       }
 
        debugfs_create_file("version", S_IRUGO, kim_debugfs_dir,
                                kim_gdata, &version_fops);
index 5b7afd6..09db397 100644 (file)
@@ -336,7 +336,7 @@ static struct i2c_driver tsl2550_driver;
 static int tsl2550_probe(struct i2c_client *client,
                                   const struct i2c_device_id *id)
 {
-       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct i2c_adapter *adapter = client->adapter;
        struct tsl2550_data *data;
        int *opmode, err = 0;
 
index ad807d5..97b58e7 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/rwsem.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/mount.h>
+#include <linux/balloon_compaction.h>
 #include <linux/vmw_vmci_defs.h>
 #include <linux/vmw_vmci_api.h>
 #include <asm/hypervisor.h>
@@ -38,25 +40,20 @@ MODULE_ALIAS("dmi:*:svnVMware*:*");
 MODULE_ALIAS("vmware_vmmemctl");
 MODULE_LICENSE("GPL");
 
-/*
- * Use __GFP_HIGHMEM to allow pages from HIGHMEM zone. We don't allow wait
- * (__GFP_RECLAIM) for huge page allocations. Use __GFP_NOWARN, to suppress page
- * allocation failure warnings. Disallow access to emergency low-memory pools.
- */
-#define VMW_HUGE_PAGE_ALLOC_FLAGS      (__GFP_HIGHMEM|__GFP_NOWARN|    \
-                                        __GFP_NOMEMALLOC)
+static bool __read_mostly vmwballoon_shrinker_enable;
+module_param(vmwballoon_shrinker_enable, bool, 0444);
+MODULE_PARM_DESC(vmwballoon_shrinker_enable,
+       "Enable non-cooperative out-of-memory protection. Disabled by default as it may degrade performance.");
 
-/*
- * Use __GFP_HIGHMEM to allow pages from HIGHMEM zone. We allow lightweight
- * reclamation (__GFP_NORETRY). Use __GFP_NOWARN, to suppress page allocation
- * failure warnings. Disallow access to emergency low-memory pools.
- */
-#define VMW_PAGE_ALLOC_FLAGS           (__GFP_HIGHMEM|__GFP_NOWARN|    \
-                                        __GFP_NOMEMALLOC|__GFP_NORETRY)
+/* Delay in seconds after shrink before inflation. */
+#define VMBALLOON_SHRINK_DELAY         (5)
 
 /* Maximum number of refused pages we accumulate during inflation cycle */
 #define VMW_BALLOON_MAX_REFUSED                16
 
+/* Magic number for the balloon mount-point */
+#define BALLOON_VMW_MAGIC              0x0ba11007
+
 /*
  * Hypervisor communication port definitions.
  */
@@ -229,29 +226,26 @@ enum vmballoon_stat_general {
        VMW_BALLOON_STAT_TIMER,
        VMW_BALLOON_STAT_DOORBELL,
        VMW_BALLOON_STAT_RESET,
-       VMW_BALLOON_STAT_LAST = VMW_BALLOON_STAT_RESET
+       VMW_BALLOON_STAT_SHRINK,
+       VMW_BALLOON_STAT_SHRINK_FREE,
+       VMW_BALLOON_STAT_LAST = VMW_BALLOON_STAT_SHRINK_FREE
 };
 
 #define VMW_BALLOON_STAT_NUM           (VMW_BALLOON_STAT_LAST + 1)
 
-
 static DEFINE_STATIC_KEY_TRUE(vmw_balloon_batching);
 static DEFINE_STATIC_KEY_FALSE(balloon_stat_enabled);
 
 struct vmballoon_ctl {
        struct list_head pages;
        struct list_head refused_pages;
+       struct list_head prealloc_pages;
        unsigned int n_refused_pages;
        unsigned int n_pages;
        enum vmballoon_page_size_type page_size;
        enum vmballoon_op op;
 };
 
-struct vmballoon_page_size {
-       /* list of reserved physical pages */
-       struct list_head pages;
-};
-
 /**
  * struct vmballoon_batch_entry - a batch entry for lock or unlock.
  *
@@ -266,8 +260,6 @@ struct vmballoon_batch_entry {
 } __packed;
 
 struct vmballoon {
-       struct vmballoon_page_size page_sizes[VMW_BALLOON_NUM_PAGE_SIZES];
-
        /**
         * @max_page_size: maximum supported page size for ballooning.
         *
@@ -340,6 +332,15 @@ struct vmballoon {
         */
        struct page *page;
 
+       /**
+        * @shrink_timeout: timeout until the next inflation.
+        *
+        * After an shrink event, indicates the time in jiffies after which
+        * inflation is allowed again. Can be written concurrently with reads,
+        * so must use READ_ONCE/WRITE_ONCE when accessing.
+        */
+       unsigned long shrink_timeout;
+
        /* statistics */
        struct vmballoon_stats *stats;
 
@@ -348,8 +349,20 @@ struct vmballoon {
        struct dentry *dbg_entry;
 #endif
 
+       /**
+        * @b_dev_info: balloon device information descriptor.
+        */
+       struct balloon_dev_info b_dev_info;
+
        struct delayed_work dwork;
 
+       /**
+        * @huge_pages - list of the inflated 2MB pages.
+        *
+        * Protected by @b_dev_info.pages_lock .
+        */
+       struct list_head huge_pages;
+
        /**
         * @vmci_doorbell.
         *
@@ -368,6 +381,20 @@ struct vmballoon {
         * Lock ordering: @conf_sem -> @comm_lock .
         */
        spinlock_t comm_lock;
+
+       /**
+        * @shrinker: shrinker interface that is used to avoid over-inflation.
+        */
+       struct shrinker shrinker;
+
+       /**
+        * @shrinker_registered: whether the shrinker was registered.
+        *
+        * The shrinker interface does not handle gracefully the removal of
+        * shrinker that was not registered before. This indication allows to
+        * simplify the unregistration process.
+        */
+       bool shrinker_registered;
 };
 
 static struct vmballoon balloon;
@@ -642,15 +669,25 @@ static int vmballoon_alloc_page_list(struct vmballoon *b,
        unsigned int i;
 
        for (i = 0; i < req_n_pages; i++) {
-               if (ctl->page_size == VMW_BALLOON_2M_PAGE)
-                       page = alloc_pages(VMW_HUGE_PAGE_ALLOC_FLAGS,
-                                          VMW_BALLOON_2M_ORDER);
-               else
-                       page = alloc_page(VMW_PAGE_ALLOC_FLAGS);
-
-               /* Update statistics */
-               vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_ALLOC,
-                                        ctl->page_size);
+               /*
+                * First check if we happen to have pages that were allocated
+                * before. This happens when 2MB page rejected during inflation
+                * by the hypervisor, and then split into 4KB pages.
+                */
+               if (!list_empty(&ctl->prealloc_pages)) {
+                       page = list_first_entry(&ctl->prealloc_pages,
+                                               struct page, lru);
+                       list_del(&page->lru);
+               } else {
+                       if (ctl->page_size == VMW_BALLOON_2M_PAGE)
+                               page = alloc_pages(__GFP_HIGHMEM|__GFP_NOWARN|
+                                       __GFP_NOMEMALLOC, VMW_BALLOON_2M_ORDER);
+                       else
+                               page = balloon_page_alloc();
+
+                       vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_ALLOC,
+                                                ctl->page_size);
+               }
 
                if (page) {
                        vmballoon_mark_page_offline(page, ctl->page_size);
@@ -896,7 +933,8 @@ static void vmballoon_release_page_list(struct list_head *page_list,
                __free_pages(page, vmballoon_page_order(page_size));
        }
 
-       *n_pages = 0;
+       if (n_pages)
+               *n_pages = 0;
 }
 
 
@@ -942,6 +980,10 @@ static int64_t vmballoon_change(struct vmballoon *b)
            size - target < vmballoon_page_in_frames(VMW_BALLOON_2M_PAGE))
                return 0;
 
+       /* If an out-of-memory recently occurred, inflation is disallowed. */
+       if (target > size && time_before(jiffies, READ_ONCE(b->shrink_timeout)))
+               return 0;
+
        return target - size;
 }
 
@@ -961,9 +1003,22 @@ static void vmballoon_enqueue_page_list(struct vmballoon *b,
                                        unsigned int *n_pages,
                                        enum vmballoon_page_size_type page_size)
 {
-       struct vmballoon_page_size *page_size_info = &b->page_sizes[page_size];
+       unsigned long flags;
+
+       if (page_size == VMW_BALLOON_4K_PAGE) {
+               balloon_page_list_enqueue(&b->b_dev_info, pages);
+       } else {
+               /*
+                * Keep the huge pages in a local list which is not available
+                * for the balloon compaction mechanism.
+                */
+               spin_lock_irqsave(&b->b_dev_info.pages_lock, flags);
+               list_splice_init(pages, &b->huge_pages);
+               __count_vm_events(BALLOON_INFLATE, *n_pages *
+                                 vmballoon_page_in_frames(VMW_BALLOON_2M_PAGE));
+               spin_unlock_irqrestore(&b->b_dev_info.pages_lock, flags);
+       }
 
-       list_splice_init(pages, &page_size_info->pages);
        *n_pages = 0;
 }
 
@@ -986,18 +1041,57 @@ static void vmballoon_dequeue_page_list(struct vmballoon *b,
                                        enum vmballoon_page_size_type page_size,
                                        unsigned int n_req_pages)
 {
-       struct vmballoon_page_size *page_size_info = &b->page_sizes[page_size];
        struct page *page, *tmp;
        unsigned int i = 0;
+       unsigned long flags;
 
-       list_for_each_entry_safe(page, tmp, &page_size_info->pages, lru) {
+       /* In the case of 4k pages, use the compaction infrastructure */
+       if (page_size == VMW_BALLOON_4K_PAGE) {
+               *n_pages = balloon_page_list_dequeue(&b->b_dev_info, pages,
+                                                    n_req_pages);
+               return;
+       }
+
+       /* 2MB pages */
+       spin_lock_irqsave(&b->b_dev_info.pages_lock, flags);
+       list_for_each_entry_safe(page, tmp, &b->huge_pages, lru) {
                list_move(&page->lru, pages);
                if (++i == n_req_pages)
                        break;
        }
+
+       __count_vm_events(BALLOON_DEFLATE,
+                         i * vmballoon_page_in_frames(VMW_BALLOON_2M_PAGE));
+       spin_unlock_irqrestore(&b->b_dev_info.pages_lock, flags);
        *n_pages = i;
 }
 
+/**
+ * vmballoon_split_refused_pages() - Split the 2MB refused pages to 4k.
+ *
+ * If inflation of 2MB pages was denied by the hypervisor, it is likely to be
+ * due to one or few 4KB pages. These 2MB pages may keep being allocated and
+ * then being refused. To prevent this case, this function splits the refused
+ * pages into 4KB pages and adds them into @prealloc_pages list.
+ *
+ * @ctl: pointer for the %struct vmballoon_ctl, which defines the operation.
+ */
+static void vmballoon_split_refused_pages(struct vmballoon_ctl *ctl)
+{
+       struct page *page, *tmp;
+       unsigned int i, order;
+
+       order = vmballoon_page_order(ctl->page_size);
+
+       list_for_each_entry_safe(page, tmp, &ctl->refused_pages, lru) {
+               list_del(&page->lru);
+               split_page(page, order);
+               for (i = 0; i < (1 << order); i++)
+                       list_add(&page[i].lru, &ctl->prealloc_pages);
+       }
+       ctl->n_refused_pages = 0;
+}
+
 /**
  * vmballoon_inflate() - Inflate the balloon towards its target size.
  *
@@ -1009,6 +1103,7 @@ static void vmballoon_inflate(struct vmballoon *b)
        struct vmballoon_ctl ctl = {
                .pages = LIST_HEAD_INIT(ctl.pages),
                .refused_pages = LIST_HEAD_INIT(ctl.refused_pages),
+               .prealloc_pages = LIST_HEAD_INIT(ctl.prealloc_pages),
                .page_size = b->max_page_size,
                .op = VMW_BALLOON_INFLATE
        };
@@ -1056,10 +1151,10 @@ static void vmballoon_inflate(struct vmballoon *b)
                                break;
 
                        /*
-                        * Ignore errors from locking as we now switch to 4k
-                        * pages and we might get different errors.
+                        * Split the refused pages to 4k. This will also empty
+                        * the refused pages list.
                         */
-                       vmballoon_release_refused_pages(b, &ctl);
+                       vmballoon_split_refused_pages(&ctl);
                        ctl.page_size--;
                }
 
@@ -1073,6 +1168,8 @@ static void vmballoon_inflate(struct vmballoon *b)
         */
        if (ctl.n_refused_pages != 0)
                vmballoon_release_refused_pages(b, &ctl);
+
+       vmballoon_release_page_list(&ctl.prealloc_pages, NULL, ctl.page_size);
 }
 
 /**
@@ -1411,6 +1508,90 @@ static void vmballoon_work(struct work_struct *work)
 
 }
 
+/**
+ * vmballoon_shrinker_scan() - deflate the balloon due to memory pressure.
+ * @shrinker: pointer to the balloon shrinker.
+ * @sc: page reclaim information.
+ *
+ * Returns: number of pages that were freed during deflation.
+ */
+static unsigned long vmballoon_shrinker_scan(struct shrinker *shrinker,
+                                            struct shrink_control *sc)
+{
+       struct vmballoon *b = &balloon;
+       unsigned long deflated_frames;
+
+       pr_debug("%s - size: %llu", __func__, atomic64_read(&b->size));
+
+       vmballoon_stats_gen_inc(b, VMW_BALLOON_STAT_SHRINK);
+
+       /*
+        * If the lock is also contended for read, we cannot easily reclaim and
+        * we bail out.
+        */
+       if (!down_read_trylock(&b->conf_sem))
+               return 0;
+
+       deflated_frames = vmballoon_deflate(b, sc->nr_to_scan, true);
+
+       vmballoon_stats_gen_add(b, VMW_BALLOON_STAT_SHRINK_FREE,
+                               deflated_frames);
+
+       /*
+        * Delay future inflation for some time to mitigate the situations in
+        * which balloon continuously grows and shrinks. Use WRITE_ONCE() since
+        * the access is asynchronous.
+        */
+       WRITE_ONCE(b->shrink_timeout, jiffies + HZ * VMBALLOON_SHRINK_DELAY);
+
+       up_read(&b->conf_sem);
+
+       return deflated_frames;
+}
+
+/**
+ * vmballoon_shrinker_count() - return the number of ballooned pages.
+ * @shrinker: pointer to the balloon shrinker.
+ * @sc: page reclaim information.
+ *
+ * Returns: number of 4k pages that are allocated for the balloon and can
+ *         therefore be reclaimed under pressure.
+ */
+static unsigned long vmballoon_shrinker_count(struct shrinker *shrinker,
+                                             struct shrink_control *sc)
+{
+       struct vmballoon *b = &balloon;
+
+       return atomic64_read(&b->size);
+}
+
+static void vmballoon_unregister_shrinker(struct vmballoon *b)
+{
+       if (b->shrinker_registered)
+               unregister_shrinker(&b->shrinker);
+       b->shrinker_registered = false;
+}
+
+static int vmballoon_register_shrinker(struct vmballoon *b)
+{
+       int r;
+
+       /* Do nothing if the shrinker is not enabled */
+       if (!vmwballoon_shrinker_enable)
+               return 0;
+
+       b->shrinker.scan_objects = vmballoon_shrinker_scan;
+       b->shrinker.count_objects = vmballoon_shrinker_count;
+       b->shrinker.seeks = DEFAULT_SEEKS;
+
+       r = register_shrinker(&b->shrinker);
+
+       if (r == 0)
+               b->shrinker_registered = true;
+
+       return r;
+}
+
 /*
  * DEBUGFS Interface
  */
@@ -1428,6 +1609,8 @@ static const char * const vmballoon_stat_names[] = {
        [VMW_BALLOON_STAT_TIMER]                = "timer",
        [VMW_BALLOON_STAT_DOORBELL]             = "doorbell",
        [VMW_BALLOON_STAT_RESET]                = "reset",
+       [VMW_BALLOON_STAT_SHRINK]               = "shrink",
+       [VMW_BALLOON_STAT_SHRINK_FREE]          = "shrinkFree"
 };
 
 static int vmballoon_enable_stats(struct vmballoon *b)
@@ -1516,19 +1699,10 @@ static int vmballoon_debug_show(struct seq_file *f, void *offset)
 
 DEFINE_SHOW_ATTRIBUTE(vmballoon_debug);
 
-static int __init vmballoon_debugfs_init(struct vmballoon *b)
+static void __init vmballoon_debugfs_init(struct vmballoon *b)
 {
-       int error;
-
        b->dbg_entry = debugfs_create_file("vmmemctl", S_IRUGO, NULL, b,
                                           &vmballoon_debug_fops);
-       if (IS_ERR(b->dbg_entry)) {
-               error = PTR_ERR(b->dbg_entry);
-               pr_err("failed to create debugfs entry, error: %d\n", error);
-               return error;
-       }
-
-       return 0;
 }
 
 static void __exit vmballoon_debugfs_exit(struct vmballoon *b)
@@ -1541,9 +1715,8 @@ static void __exit vmballoon_debugfs_exit(struct vmballoon *b)
 
 #else
 
-static inline int vmballoon_debugfs_init(struct vmballoon *b)
+static inline void vmballoon_debugfs_init(struct vmballoon *b)
 {
-       return 0;
 }
 
 static inline void vmballoon_debugfs_exit(struct vmballoon *b)
@@ -1552,9 +1725,204 @@ static inline void vmballoon_debugfs_exit(struct vmballoon *b)
 
 #endif /* CONFIG_DEBUG_FS */
 
+
+#ifdef CONFIG_BALLOON_COMPACTION
+
+static struct dentry *vmballoon_mount(struct file_system_type *fs_type,
+                                     int flags, const char *dev_name,
+                                     void *data)
+{
+       static const struct dentry_operations ops = {
+               .d_dname = simple_dname,
+       };
+
+       return mount_pseudo(fs_type, "balloon-vmware:", NULL, &ops,
+                           BALLOON_VMW_MAGIC);
+}
+
+static struct file_system_type vmballoon_fs = {
+       .name           = "balloon-vmware",
+       .mount          = vmballoon_mount,
+       .kill_sb        = kill_anon_super,
+};
+
+static struct vfsmount *vmballoon_mnt;
+
+/**
+ * vmballoon_migratepage() - migrates a balloon page.
+ * @b_dev_info: balloon device information descriptor.
+ * @newpage: the page to which @page should be migrated.
+ * @page: a ballooned page that should be migrated.
+ * @mode: migration mode, ignored.
+ *
+ * This function is really open-coded, but that is according to the interface
+ * that balloon_compaction provides.
+ *
+ * Return: zero on success, -EAGAIN when migration cannot be performed
+ *        momentarily, and -EBUSY if migration failed and should be retried
+ *        with that specific page.
+ */
+static int vmballoon_migratepage(struct balloon_dev_info *b_dev_info,
+                                struct page *newpage, struct page *page,
+                                enum migrate_mode mode)
+{
+       unsigned long status, flags;
+       struct vmballoon *b;
+       int ret;
+
+       b = container_of(b_dev_info, struct vmballoon, b_dev_info);
+
+       /*
+        * If the semaphore is taken, there is ongoing configuration change
+        * (i.e., balloon reset), so try again.
+        */
+       if (!down_read_trylock(&b->conf_sem))
+               return -EAGAIN;
+
+       spin_lock(&b->comm_lock);
+       /*
+        * We must start by deflating and not inflating, as otherwise the
+        * hypervisor may tell us that it has enough memory and the new page is
+        * not needed. Since the old page is isolated, we cannot use the list
+        * interface to unlock it, as the LRU field is used for isolation.
+        * Instead, we use the native interface directly.
+        */
+       vmballoon_add_page(b, 0, page);
+       status = vmballoon_lock_op(b, 1, VMW_BALLOON_4K_PAGE,
+                                  VMW_BALLOON_DEFLATE);
+
+       if (status == VMW_BALLOON_SUCCESS)
+               status = vmballoon_status_page(b, 0, &page);
+
+       /*
+        * If a failure happened, let the migration mechanism know that it
+        * should not retry.
+        */
+       if (status != VMW_BALLOON_SUCCESS) {
+               spin_unlock(&b->comm_lock);
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+
+       /*
+        * The page is isolated, so it is safe to delete it without holding
+        * @pages_lock . We keep holding @comm_lock since we will need it in a
+        * second.
+        */
+       balloon_page_delete(page);
+
+       put_page(page);
+
+       /* Inflate */
+       vmballoon_add_page(b, 0, newpage);
+       status = vmballoon_lock_op(b, 1, VMW_BALLOON_4K_PAGE,
+                                  VMW_BALLOON_INFLATE);
+
+       if (status == VMW_BALLOON_SUCCESS)
+               status = vmballoon_status_page(b, 0, &newpage);
+
+       spin_unlock(&b->comm_lock);
+
+       if (status != VMW_BALLOON_SUCCESS) {
+               /*
+                * A failure happened. While we can deflate the page we just
+                * inflated, this deflation can also encounter an error. Instead
+                * we will decrease the size of the balloon to reflect the
+                * change and report failure.
+                */
+               atomic64_dec(&b->size);
+               ret = -EBUSY;
+       } else {
+               /*
+                * Success. Take a reference for the page, and we will add it to
+                * the list after acquiring the lock.
+                */
+               get_page(newpage);
+               ret = MIGRATEPAGE_SUCCESS;
+       }
+
+       /* Update the balloon list under the @pages_lock */
+       spin_lock_irqsave(&b->b_dev_info.pages_lock, flags);
+
+       /*
+        * On inflation success, we already took a reference for the @newpage.
+        * If we succeed just insert it to the list and update the statistics
+        * under the lock.
+        */
+       if (ret == MIGRATEPAGE_SUCCESS) {
+               balloon_page_insert(&b->b_dev_info, newpage);
+               __count_vm_event(BALLOON_MIGRATE);
+       }
+
+       /*
+        * We deflated successfully, so regardless to the inflation success, we
+        * need to reduce the number of isolated_pages.
+        */
+       b->b_dev_info.isolated_pages--;
+       spin_unlock_irqrestore(&b->b_dev_info.pages_lock, flags);
+
+out_unlock:
+       up_read(&b->conf_sem);
+       return ret;
+}
+
+/**
+ * vmballoon_compaction_deinit() - removes compaction related data.
+ *
+ * @b: pointer to the balloon.
+ */
+static void vmballoon_compaction_deinit(struct vmballoon *b)
+{
+       if (!IS_ERR(b->b_dev_info.inode))
+               iput(b->b_dev_info.inode);
+
+       b->b_dev_info.inode = NULL;
+       kern_unmount(vmballoon_mnt);
+       vmballoon_mnt = NULL;
+}
+
+/**
+ * vmballoon_compaction_init() - initialized compaction for the balloon.
+ *
+ * @b: pointer to the balloon.
+ *
+ * If during the initialization a failure occurred, this function does not
+ * perform cleanup. The caller must call vmballoon_compaction_deinit() in this
+ * case.
+ *
+ * Return: zero on success or error code on failure.
+ */
+static __init int vmballoon_compaction_init(struct vmballoon *b)
+{
+       vmballoon_mnt = kern_mount(&vmballoon_fs);
+       if (IS_ERR(vmballoon_mnt))
+               return PTR_ERR(vmballoon_mnt);
+
+       b->b_dev_info.migratepage = vmballoon_migratepage;
+       b->b_dev_info.inode = alloc_anon_inode(vmballoon_mnt->mnt_sb);
+
+       if (IS_ERR(b->b_dev_info.inode))
+               return PTR_ERR(b->b_dev_info.inode);
+
+       b->b_dev_info.inode->i_mapping->a_ops = &balloon_aops;
+       return 0;
+}
+
+#else /* CONFIG_BALLOON_COMPACTION */
+
+static void vmballoon_compaction_deinit(struct vmballoon *b)
+{
+}
+
+static int vmballoon_compaction_init(struct vmballoon *b)
+{
+       return 0;
+}
+
+#endif /* CONFIG_BALLOON_COMPACTION */
+
 static int __init vmballoon_init(void)
 {
-       enum vmballoon_page_size_type page_size;
        int error;
 
        /*
@@ -1564,17 +1932,22 @@ static int __init vmballoon_init(void)
        if (x86_hyper_type != X86_HYPER_VMWARE)
                return -ENODEV;
 
-       for (page_size = VMW_BALLOON_4K_PAGE;
-            page_size <= VMW_BALLOON_LAST_SIZE; page_size++)
-               INIT_LIST_HEAD(&balloon.page_sizes[page_size].pages);
-
-
        INIT_DELAYED_WORK(&balloon.dwork, vmballoon_work);
 
-       error = vmballoon_debugfs_init(&balloon);
+       error = vmballoon_register_shrinker(&balloon);
+       if (error)
+               goto fail;
+
+       /*
+        * Initialization of compaction must be done after the call to
+        * balloon_devinfo_init() .
+        */
+       balloon_devinfo_init(&balloon.b_dev_info);
+       error = vmballoon_compaction_init(&balloon);
        if (error)
-               return error;
+               goto fail;
 
+       INIT_LIST_HEAD(&balloon.huge_pages);
        spin_lock_init(&balloon.comm_lock);
        init_rwsem(&balloon.conf_sem);
        balloon.vmci_doorbell = VMCI_INVALID_HANDLE;
@@ -1584,7 +1957,13 @@ static int __init vmballoon_init(void)
 
        queue_delayed_work(system_freezable_wq, &balloon.dwork, 0);
 
+       vmballoon_debugfs_init(&balloon);
+
        return 0;
+fail:
+       vmballoon_unregister_shrinker(&balloon);
+       vmballoon_compaction_deinit(&balloon);
+       return error;
 }
 
 /*
@@ -1597,6 +1976,7 @@ late_initcall(vmballoon_init);
 
 static void __exit vmballoon_exit(void)
 {
+       vmballoon_unregister_shrinker(&balloon);
        vmballoon_vmci_cleanup(&balloon);
        cancel_delayed_work_sync(&balloon.dwork);
 
@@ -1609,5 +1989,8 @@ static void __exit vmballoon_exit(void)
         */
        vmballoon_send_start(&balloon, 0);
        vmballoon_pop(&balloon);
+
+       /* Only once we popped the balloon, compaction can be deinit */
+       vmballoon_compaction_deinit(&balloon);
 }
 module_exit(vmballoon_exit);
index 300ed69..1669536 100644 (file)
@@ -21,6 +21,9 @@
 #include "vmci_driver.h"
 #include "vmci_event.h"
 
+/* Use a wide upper bound for the maximum contexts. */
+#define VMCI_MAX_CONTEXTS 2000
+
 /*
  * List of current VMCI contexts.  Contexts can be added by
  * vmci_ctx_create() and removed via vmci_ctx_destroy().
@@ -117,19 +120,22 @@ struct vmci_ctx *vmci_ctx_create(u32 cid, u32 priv_flags,
        /* Initialize host-specific VMCI context. */
        init_waitqueue_head(&context->host_context.wait_queue);
 
-       context->queue_pair_array = vmci_handle_arr_create(0);
+       context->queue_pair_array =
+               vmci_handle_arr_create(0, VMCI_MAX_GUEST_QP_COUNT);
        if (!context->queue_pair_array) {
                error = -ENOMEM;
                goto err_free_ctx;
        }
 
-       context->doorbell_array = vmci_handle_arr_create(0);
+       context->doorbell_array =
+               vmci_handle_arr_create(0, VMCI_MAX_GUEST_DOORBELL_COUNT);
        if (!context->doorbell_array) {
                error = -ENOMEM;
                goto err_free_qp_array;
        }
 
-       context->pending_doorbell_array = vmci_handle_arr_create(0);
+       context->pending_doorbell_array =
+               vmci_handle_arr_create(0, VMCI_MAX_GUEST_DOORBELL_COUNT);
        if (!context->pending_doorbell_array) {
                error = -ENOMEM;
                goto err_free_db_array;
@@ -204,7 +210,7 @@ static int ctx_fire_notification(u32 context_id, u32 priv_flags)
         * We create an array to hold the subscribers we find when
         * scanning through all contexts.
         */
-       subscriber_array = vmci_handle_arr_create(0);
+       subscriber_array = vmci_handle_arr_create(0, VMCI_MAX_CONTEXTS);
        if (subscriber_array == NULL)
                return VMCI_ERROR_NO_MEM;
 
@@ -623,20 +629,26 @@ int vmci_ctx_add_notification(u32 context_id, u32 remote_cid)
 
        spin_lock(&context->lock);
 
-       list_for_each_entry(n, &context->notifier_list, node) {
-               if (vmci_handle_is_equal(n->handle, notifier->handle)) {
-                       exists = true;
-                       break;
+       if (context->n_notifiers < VMCI_MAX_CONTEXTS) {
+               list_for_each_entry(n, &context->notifier_list, node) {
+                       if (vmci_handle_is_equal(n->handle, notifier->handle)) {
+                               exists = true;
+                               break;
+                       }
                }
-       }
 
-       if (exists) {
-               kfree(notifier);
-               result = VMCI_ERROR_ALREADY_EXISTS;
+               if (exists) {
+                       kfree(notifier);
+                       result = VMCI_ERROR_ALREADY_EXISTS;
+               } else {
+                       list_add_tail_rcu(&notifier->node,
+                                         &context->notifier_list);
+                       context->n_notifiers++;
+                       result = VMCI_SUCCESS;
+               }
        } else {
-               list_add_tail_rcu(&notifier->node, &context->notifier_list);
-               context->n_notifiers++;
-               result = VMCI_SUCCESS;
+               kfree(notifier);
+               result = VMCI_ERROR_NO_MEM;
        }
 
        spin_unlock(&context->lock);
@@ -721,8 +733,7 @@ static int vmci_ctx_get_chkpt_doorbells(struct vmci_ctx *context,
                                        u32 *buf_size, void **pbuf)
 {
        struct dbell_cpt_state *dbells;
-       size_t n_doorbells;
-       int i;
+       u32 i, n_doorbells;
 
        n_doorbells = vmci_handle_arr_get_size(context->doorbell_array);
        if (n_doorbells > 0) {
@@ -860,7 +871,8 @@ int vmci_ctx_rcv_notifications_get(u32 context_id,
        spin_lock(&context->lock);
 
        *db_handle_array = context->pending_doorbell_array;
-       context->pending_doorbell_array = vmci_handle_arr_create(0);
+       context->pending_doorbell_array =
+               vmci_handle_arr_create(0, VMCI_MAX_GUEST_DOORBELL_COUNT);
        if (!context->pending_doorbell_array) {
                context->pending_doorbell_array = *db_handle_array;
                *db_handle_array = NULL;
@@ -942,12 +954,11 @@ int vmci_ctx_dbell_create(u32 context_id, struct vmci_handle handle)
                return VMCI_ERROR_NOT_FOUND;
 
        spin_lock(&context->lock);
-       if (!vmci_handle_arr_has_entry(context->doorbell_array, handle)) {
-               vmci_handle_arr_append_entry(&context->doorbell_array, handle);
-               result = VMCI_SUCCESS;
-       } else {
+       if (!vmci_handle_arr_has_entry(context->doorbell_array, handle))
+               result = vmci_handle_arr_append_entry(&context->doorbell_array,
+                                                     handle);
+       else
                result = VMCI_ERROR_DUPLICATE_ENTRY;
-       }
 
        spin_unlock(&context->lock);
        vmci_ctx_put(context);
@@ -1083,15 +1094,16 @@ int vmci_ctx_notify_dbell(u32 src_cid,
                        if (!vmci_handle_arr_has_entry(
                                        dst_context->pending_doorbell_array,
                                        handle)) {
-                               vmci_handle_arr_append_entry(
+                               result = vmci_handle_arr_append_entry(
                                        &dst_context->pending_doorbell_array,
                                        handle);
-
-                               ctx_signal_notify(dst_context);
-                               wake_up(&dst_context->host_context.wait_queue);
-
+                               if (result == VMCI_SUCCESS) {
+                                       ctx_signal_notify(dst_context);
+                                       wake_up(&dst_context->host_context.wait_queue);
+                               }
+                       } else {
+                               result = VMCI_SUCCESS;
                        }
-                       result = VMCI_SUCCESS;
                }
                spin_unlock(&dst_context->lock);
        }
@@ -1118,13 +1130,11 @@ int vmci_ctx_qp_create(struct vmci_ctx *context, struct vmci_handle handle)
        if (context == NULL || vmci_handle_is_invalid(handle))
                return VMCI_ERROR_INVALID_ARGS;
 
-       if (!vmci_handle_arr_has_entry(context->queue_pair_array, handle)) {
-               vmci_handle_arr_append_entry(&context->queue_pair_array,
-                                            handle);
-               result = VMCI_SUCCESS;
-       } else {
+       if (!vmci_handle_arr_has_entry(context->queue_pair_array, handle))
+               result = vmci_handle_arr_append_entry(
+                       &context->queue_pair_array, handle);
+       else
                result = VMCI_ERROR_DUPLICATE_ENTRY;
-       }
 
        return result;
 }
index c527388..de7fee7 100644 (file)
@@ -8,24 +8,29 @@
 #include <linux/slab.h>
 #include "vmci_handle_array.h"
 
-static size_t handle_arr_calc_size(size_t capacity)
+static size_t handle_arr_calc_size(u32 capacity)
 {
-       return sizeof(struct vmci_handle_arr) +
+       return VMCI_HANDLE_ARRAY_HEADER_SIZE +
            capacity * sizeof(struct vmci_handle);
 }
 
-struct vmci_handle_arr *vmci_handle_arr_create(size_t capacity)
+struct vmci_handle_arr *vmci_handle_arr_create(u32 capacity, u32 max_capacity)
 {
        struct vmci_handle_arr *array;
 
+       if (max_capacity == 0 || capacity > max_capacity)
+               return NULL;
+
        if (capacity == 0)
-               capacity = VMCI_HANDLE_ARRAY_DEFAULT_SIZE;
+               capacity = min((u32)VMCI_HANDLE_ARRAY_DEFAULT_CAPACITY,
+                              max_capacity);
 
        array = kmalloc(handle_arr_calc_size(capacity), GFP_ATOMIC);
        if (!array)
                return NULL;
 
        array->capacity = capacity;
+       array->max_capacity = max_capacity;
        array->size = 0;
 
        return array;
@@ -36,27 +41,34 @@ void vmci_handle_arr_destroy(struct vmci_handle_arr *array)
        kfree(array);
 }
 
-void vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
-                                 struct vmci_handle handle)
+int vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
+                                struct vmci_handle handle)
 {
        struct vmci_handle_arr *array = *array_ptr;
 
        if (unlikely(array->size >= array->capacity)) {
                /* reallocate. */
                struct vmci_handle_arr *new_array;
-               size_t new_capacity = array->capacity * VMCI_ARR_CAP_MULT;
-               size_t new_size = handle_arr_calc_size(new_capacity);
+               u32 capacity_bump = min(array->max_capacity - array->capacity,
+                                       array->capacity);
+               size_t new_size = handle_arr_calc_size(array->capacity +
+                                                      capacity_bump);
+
+               if (array->size >= array->max_capacity)
+                       return VMCI_ERROR_NO_MEM;
 
                new_array = krealloc(array, new_size, GFP_ATOMIC);
                if (!new_array)
-                       return;
+                       return VMCI_ERROR_NO_MEM;
 
-               new_array->capacity = new_capacity;
+               new_array->capacity += capacity_bump;
                *array_ptr = array = new_array;
        }
 
        array->entries[array->size] = handle;
        array->size++;
+
+       return VMCI_SUCCESS;
 }
 
 /*
@@ -66,7 +78,7 @@ struct vmci_handle vmci_handle_arr_remove_entry(struct vmci_handle_arr *array,
                                                struct vmci_handle entry_handle)
 {
        struct vmci_handle handle = VMCI_INVALID_HANDLE;
-       size_t i;
+       u32 i;
 
        for (i = 0; i < array->size; i++) {
                if (vmci_handle_is_equal(array->entries[i], entry_handle)) {
@@ -101,7 +113,7 @@ struct vmci_handle vmci_handle_arr_remove_tail(struct vmci_handle_arr *array)
  * Handle at given index, VMCI_INVALID_HANDLE if invalid index.
  */
 struct vmci_handle
-vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, size_t index)
+vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, u32 index)
 {
        if (unlikely(index >= array->size))
                return VMCI_INVALID_HANDLE;
@@ -112,7 +124,7 @@ vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, size_t index)
 bool vmci_handle_arr_has_entry(const struct vmci_handle_arr *array,
                               struct vmci_handle entry_handle)
 {
-       size_t i;
+       u32 i;
 
        for (i = 0; i < array->size; i++)
                if (vmci_handle_is_equal(array->entries[i], entry_handle))
index bd1559a..96193f8 100644 (file)
@@ -9,32 +9,41 @@
 #define _VMCI_HANDLE_ARRAY_H_
 
 #include <linux/vmw_vmci_defs.h>
+#include <linux/limits.h>
 #include <linux/types.h>
 
-#define VMCI_HANDLE_ARRAY_DEFAULT_SIZE 4
-#define VMCI_ARR_CAP_MULT 2    /* Array capacity multiplier */
-
 struct vmci_handle_arr {
-       size_t capacity;
-       size_t size;
+       u32 capacity;
+       u32 max_capacity;
+       u32 size;
+       u32 pad;
        struct vmci_handle entries[];
 };
 
-struct vmci_handle_arr *vmci_handle_arr_create(size_t capacity);
+#define VMCI_HANDLE_ARRAY_HEADER_SIZE                          \
+       offsetof(struct vmci_handle_arr, entries)
+/* Select a default capacity that results in a 64 byte sized array */
+#define VMCI_HANDLE_ARRAY_DEFAULT_CAPACITY                     6
+/* Make sure that the max array size can be expressed by a u32 */
+#define VMCI_HANDLE_ARRAY_MAX_CAPACITY                         \
+       ((U32_MAX - VMCI_HANDLE_ARRAY_HEADER_SIZE - 1) /        \
+       sizeof(struct vmci_handle))
+
+struct vmci_handle_arr *vmci_handle_arr_create(u32 capacity, u32 max_capacity);
 void vmci_handle_arr_destroy(struct vmci_handle_arr *array);
-void vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
-                                 struct vmci_handle handle);
+int vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
+                                struct vmci_handle handle);
 struct vmci_handle vmci_handle_arr_remove_entry(struct vmci_handle_arr *array,
                                                struct vmci_handle
                                                entry_handle);
 struct vmci_handle vmci_handle_arr_remove_tail(struct vmci_handle_arr *array);
 struct vmci_handle
-vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, size_t index);
+vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, u32 index);
 bool vmci_handle_arr_has_entry(const struct vmci_handle_arr *array,
                               struct vmci_handle entry_handle);
 struct vmci_handle *vmci_handle_arr_get_handles(struct vmci_handle_arr *array);
 
-static inline size_t vmci_handle_arr_get_size(
+static inline u32 vmci_handle_arr_get_size(
        const struct vmci_handle_arr *array)
 {
        return array->size;
diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
new file mode 100644 (file)
index 0000000..f257d38
--- /dev/null
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx SDFEC
+ *
+ * Copyright (C) 2019 Xilinx, Inc.
+ *
+ * Description:
+ * This driver is developed for SDFEC16 (Soft Decision FEC 16nm)
+ * IP. It exposes a char device which supports file operations
+ * like  open(), close() and ioctl().
+ */
+
+#include <linux/miscdevice.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+
+#define DEV_NAME_LEN 12
+
+static struct idr dev_idr;
+static struct mutex dev_idr_lock;
+
+/**
+ * struct xsdfec_clks - For managing SD-FEC clocks
+ * @core_clk: Main processing clock for core
+ * @axi_clk: AXI4-Lite memory-mapped clock
+ * @din_words_clk: DIN Words AXI4-Stream Slave clock
+ * @din_clk: DIN AXI4-Stream Slave clock
+ * @dout_clk: DOUT Words AXI4-Stream Slave clock
+ * @dout_words_clk: DOUT AXI4-Stream Slave clock
+ * @ctrl_clk: Control AXI4-Stream Slave clock
+ * @status_clk: Status AXI4-Stream Slave clock
+ */
+struct xsdfec_clks {
+       struct clk *core_clk;
+       struct clk *axi_clk;
+       struct clk *din_words_clk;
+       struct clk *din_clk;
+       struct clk *dout_clk;
+       struct clk *dout_words_clk;
+       struct clk *ctrl_clk;
+       struct clk *status_clk;
+};
+
+/**
+ * struct xsdfec_dev - Driver data for SDFEC
+ * @regs: device physical base address
+ * @dev: pointer to device struct
+ * @miscdev: Misc device handle
+ * @error_data_lock: Error counter and states spinlock
+ * @clks: Clocks managed by the SDFEC driver
+ * @dev_name: Device name
+ * @dev_id: Device ID
+ *
+ * This structure contains necessary state for SDFEC driver to operate
+ */
+struct xsdfec_dev {
+       void __iomem *regs;
+       struct device *dev;
+       struct miscdevice miscdev;
+       /* Spinlock to protect state_updated and stats_updated */
+       spinlock_t error_data_lock;
+       struct xsdfec_clks clks;
+       char dev_name[DEV_NAME_LEN];
+       int dev_id;
+};
+
+static const struct file_operations xsdfec_fops = {
+       .owner = THIS_MODULE,
+};
+
+static int xsdfec_clk_init(struct platform_device *pdev,
+                          struct xsdfec_clks *clks)
+{
+       int err;
+
+       clks->core_clk = devm_clk_get(&pdev->dev, "core_clk");
+       if (IS_ERR(clks->core_clk)) {
+               dev_err(&pdev->dev, "failed to get core_clk");
+               return PTR_ERR(clks->core_clk);
+       }
+
+       clks->axi_clk = devm_clk_get(&pdev->dev, "s_axi_aclk");
+       if (IS_ERR(clks->axi_clk)) {
+               dev_err(&pdev->dev, "failed to get axi_clk");
+               return PTR_ERR(clks->axi_clk);
+       }
+
+       clks->din_words_clk = devm_clk_get(&pdev->dev, "s_axis_din_words_aclk");
+       if (IS_ERR(clks->din_words_clk)) {
+               if (PTR_ERR(clks->din_words_clk) != -ENOENT) {
+                       err = PTR_ERR(clks->din_words_clk);
+                       return err;
+               }
+               clks->din_words_clk = NULL;
+       }
+
+       clks->din_clk = devm_clk_get(&pdev->dev, "s_axis_din_aclk");
+       if (IS_ERR(clks->din_clk)) {
+               if (PTR_ERR(clks->din_clk) != -ENOENT) {
+                       err = PTR_ERR(clks->din_clk);
+                       return err;
+               }
+               clks->din_clk = NULL;
+       }
+
+       clks->dout_clk = devm_clk_get(&pdev->dev, "m_axis_dout_aclk");
+       if (IS_ERR(clks->dout_clk)) {
+               if (PTR_ERR(clks->dout_clk) != -ENOENT) {
+                       err = PTR_ERR(clks->dout_clk);
+                       return err;
+               }
+               clks->dout_clk = NULL;
+       }
+
+       clks->dout_words_clk =
+               devm_clk_get(&pdev->dev, "s_axis_dout_words_aclk");
+       if (IS_ERR(clks->dout_words_clk)) {
+               if (PTR_ERR(clks->dout_words_clk) != -ENOENT) {
+                       err = PTR_ERR(clks->dout_words_clk);
+                       return err;
+               }
+               clks->dout_words_clk = NULL;
+       }
+
+       clks->ctrl_clk = devm_clk_get(&pdev->dev, "s_axis_ctrl_aclk");
+       if (IS_ERR(clks->ctrl_clk)) {
+               if (PTR_ERR(clks->ctrl_clk) != -ENOENT) {
+                       err = PTR_ERR(clks->ctrl_clk);
+                       return err;
+               }
+               clks->ctrl_clk = NULL;
+       }
+
+       clks->status_clk = devm_clk_get(&pdev->dev, "m_axis_status_aclk");
+       if (IS_ERR(clks->status_clk)) {
+               if (PTR_ERR(clks->status_clk) != -ENOENT) {
+                       err = PTR_ERR(clks->status_clk);
+                       return err;
+               }
+               clks->status_clk = NULL;
+       }
+
+       err = clk_prepare_enable(clks->core_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable core_clk (%d)", err);
+               return err;
+       }
+
+       err = clk_prepare_enable(clks->axi_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable axi_clk (%d)", err);
+               goto err_disable_core_clk;
+       }
+
+       err = clk_prepare_enable(clks->din_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable din_clk (%d)", err);
+               goto err_disable_axi_clk;
+       }
+
+       err = clk_prepare_enable(clks->din_words_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable din_words_clk (%d)", err);
+               goto err_disable_din_clk;
+       }
+
+       err = clk_prepare_enable(clks->dout_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable dout_clk (%d)", err);
+               goto err_disable_din_words_clk;
+       }
+
+       err = clk_prepare_enable(clks->dout_words_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable dout_words_clk (%d)",
+                       err);
+               goto err_disable_dout_clk;
+       }
+
+       err = clk_prepare_enable(clks->ctrl_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable ctrl_clk (%d)", err);
+               goto err_disable_dout_words_clk;
+       }
+
+       err = clk_prepare_enable(clks->status_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable status_clk (%d)\n", err);
+               goto err_disable_ctrl_clk;
+       }
+
+       return err;
+
+err_disable_ctrl_clk:
+       clk_disable_unprepare(clks->ctrl_clk);
+err_disable_dout_words_clk:
+       clk_disable_unprepare(clks->dout_words_clk);
+err_disable_dout_clk:
+       clk_disable_unprepare(clks->dout_clk);
+err_disable_din_words_clk:
+       clk_disable_unprepare(clks->din_words_clk);
+err_disable_din_clk:
+       clk_disable_unprepare(clks->din_clk);
+err_disable_axi_clk:
+       clk_disable_unprepare(clks->axi_clk);
+err_disable_core_clk:
+       clk_disable_unprepare(clks->core_clk);
+
+       return err;
+}
+
+static void xsdfec_disable_all_clks(struct xsdfec_clks *clks)
+{
+       clk_disable_unprepare(clks->status_clk);
+       clk_disable_unprepare(clks->ctrl_clk);
+       clk_disable_unprepare(clks->dout_words_clk);
+       clk_disable_unprepare(clks->dout_clk);
+       clk_disable_unprepare(clks->din_words_clk);
+       clk_disable_unprepare(clks->din_clk);
+       clk_disable_unprepare(clks->core_clk);
+       clk_disable_unprepare(clks->axi_clk);
+}
+
+static void xsdfec_idr_remove(struct xsdfec_dev *xsdfec)
+{
+       mutex_lock(&dev_idr_lock);
+       idr_remove(&dev_idr, xsdfec->dev_id);
+       mutex_unlock(&dev_idr_lock);
+}
+
+static int xsdfec_probe(struct platform_device *pdev)
+{
+       struct xsdfec_dev *xsdfec;
+       struct device *dev;
+       struct resource *res;
+       int err;
+
+       xsdfec = devm_kzalloc(&pdev->dev, sizeof(*xsdfec), GFP_KERNEL);
+       if (!xsdfec)
+               return -ENOMEM;
+
+       xsdfec->dev = &pdev->dev;
+       spin_lock_init(&xsdfec->error_data_lock);
+
+       err = xsdfec_clk_init(pdev, &xsdfec->clks);
+       if (err)
+               return err;
+
+       dev = xsdfec->dev;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       xsdfec->regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(xsdfec->regs)) {
+               err = PTR_ERR(xsdfec->regs);
+               goto err_xsdfec_dev;
+       }
+
+       /* Save driver private data */
+       platform_set_drvdata(pdev, xsdfec);
+
+       mutex_lock(&dev_idr_lock);
+       err = idr_alloc(&dev_idr, xsdfec->dev_name, 0, 0, GFP_KERNEL);
+       mutex_unlock(&dev_idr_lock);
+       if (err < 0)
+               goto err_xsdfec_dev;
+       xsdfec->dev_id = err;
+
+       snprintf(xsdfec->dev_name, DEV_NAME_LEN, "xsdfec%d", xsdfec->dev_id);
+       xsdfec->miscdev.minor = MISC_DYNAMIC_MINOR;
+       xsdfec->miscdev.name = xsdfec->dev_name;
+       xsdfec->miscdev.fops = &xsdfec_fops;
+       xsdfec->miscdev.parent = dev;
+       err = misc_register(&xsdfec->miscdev);
+       if (err) {
+               dev_err(dev, "error:%d. Unable to register device", err);
+               goto err_xsdfec_idr;
+       }
+       return 0;
+
+err_xsdfec_idr:
+       xsdfec_idr_remove(xsdfec);
+err_xsdfec_dev:
+       xsdfec_disable_all_clks(&xsdfec->clks);
+       return err;
+}
+
+static int xsdfec_remove(struct platform_device *pdev)
+{
+       struct xsdfec_dev *xsdfec;
+
+       xsdfec = platform_get_drvdata(pdev);
+       misc_deregister(&xsdfec->miscdev);
+       xsdfec_idr_remove(xsdfec);
+       xsdfec_disable_all_clks(&xsdfec->clks);
+       return 0;
+}
+
+static const struct of_device_id xsdfec_of_match[] = {
+       {
+               .compatible = "xlnx,sd-fec-1.1",
+       },
+       { /* end of table */ }
+};
+MODULE_DEVICE_TABLE(of, xsdfec_of_match);
+
+static struct platform_driver xsdfec_driver = {
+       .driver = {
+               .name = "xilinx-sdfec",
+               .of_match_table = xsdfec_of_match,
+       },
+       .probe = xsdfec_probe,
+       .remove =  xsdfec_remove,
+};
+
+static int __init xsdfec_init(void)
+{
+       int err;
+
+       mutex_init(&dev_idr_lock);
+       idr_init(&dev_idr);
+       err = platform_driver_register(&xsdfec_driver);
+       if (err < 0) {
+               pr_err("%s Unabled to register SDFEC driver", __func__);
+               return err;
+       }
+       return 0;
+}
+
+static void __exit xsdfec_exit(void)
+{
+       platform_driver_unregister(&xsdfec_driver);
+       idr_destroy(&dev_idr);
+}
+
+module_init(xsdfec_init);
+module_exit(xsdfec_exit);
+
+MODULE_AUTHOR("Xilinx, Inc");
+MODULE_DESCRIPTION("Xilinx SD-FEC16 Driver");
+MODULE_LICENSE("GPL");
index 2797771..09e0c76 100644 (file)
@@ -227,45 +227,21 @@ void mmc_add_host_debugfs(struct mmc_host *host)
        struct dentry *root;
 
        root = debugfs_create_dir(mmc_hostname(host), NULL);
-       if (IS_ERR(root))
-               /* Don't complain -- debugfs just isn't enabled */
-               return;
-       if (!root)
-               /* Complain -- debugfs is enabled, but it failed to
-                * create the directory. */
-               goto err_root;
-
        host->debugfs_root = root;
 
-       if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops))
-               goto err_node;
-
-       if (!debugfs_create_x32("caps", S_IRUSR, root, &host->caps))
-               goto err_node;
-
-       if (!debugfs_create_x32("caps2", S_IRUSR, root, &host->caps2))
-               goto err_node;
-
-       if (!debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host,
-                       &mmc_clock_fops))
-               goto err_node;
+       debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops);
+       debugfs_create_x32("caps", S_IRUSR, root, &host->caps);
+       debugfs_create_x32("caps2", S_IRUSR, root, &host->caps2);
+       debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host,
+                           &mmc_clock_fops);
 
 #ifdef CONFIG_FAIL_MMC_REQUEST
        if (fail_request)
                setup_fault_attr(&fail_default_attr, fail_request);
        host->fail_mmc_request = fail_default_attr;
-       if (IS_ERR(fault_create_debugfs_attr("fail_mmc_request",
-                                            root,
-                                            &host->fail_mmc_request)))
-               goto err_node;
+       fault_create_debugfs_attr("fail_mmc_request", root,
+                                 &host->fail_mmc_request);
 #endif
-       return;
-
-err_node:
-       debugfs_remove_recursive(root);
-       host->debugfs_root = NULL;
-err_root:
-       dev_err(&host->class_dev, "failed to initialize debugfs\n");
 }
 
 void mmc_remove_host_debugfs(struct mmc_host *host)
@@ -282,25 +258,9 @@ void mmc_add_card_debugfs(struct mmc_card *card)
                return;
 
        root = debugfs_create_dir(mmc_card_id(card), host->debugfs_root);
-       if (IS_ERR(root))
-               /* Don't complain -- debugfs just isn't enabled */
-               return;
-       if (!root)
-               /* Complain -- debugfs is enabled, but it failed to
-                * create the directory. */
-               goto err;
-
        card->debugfs_root = root;
 
-       if (!debugfs_create_x32("state", S_IRUSR, root, &card->state))
-               goto err;
-
-       return;
-
-err:
-       debugfs_remove_recursive(root);
-       card->debugfs_root = NULL;
-       dev_err(&card->dev, "failed to initialize debugfs\n");
+       debugfs_create_x32("state", S_IRUSR, root, &card->state);
 }
 
 void mmc_remove_card_debugfs(struct mmc_card *card)
index b27df2d..492dd45 100644 (file)
@@ -3167,15 +3167,7 @@ static int __mmc_test_register_dbgfs_file(struct mmc_card *card,
        struct mmc_test_dbgfs_file *df;
 
        if (card->debugfs_root)
-               file = debugfs_create_file(name, mode, card->debugfs_root,
-                       card, fops);
-
-       if (IS_ERR_OR_NULL(file)) {
-               dev_err(&card->dev,
-                       "Can't create %s. Perhaps debugfs is disabled.\n",
-                       name);
-               return -ENODEV;
-       }
+               debugfs_create_file(name, mode, card->debugfs_root, card, fops);
 
        df = kmalloc(sizeof(*df), GFP_KERNEL);
        if (!df) {
index 3557d5c..e327f80 100644 (file)
@@ -350,18 +350,15 @@ static const struct blk_mq_ops mmc_mq_ops = {
 static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card)
 {
        struct mmc_host *host = card->host;
-       u64 limit = BLK_BOUNCE_HIGH;
        unsigned block_size = 512;
 
-       if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
-               limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
-
        blk_queue_flag_set(QUEUE_FLAG_NONROT, mq->queue);
        blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, mq->queue);
        if (mmc_can_erase(card))
                mmc_queue_setup_discard(mq->queue, card);
 
-       blk_queue_bounce_limit(mq->queue, limit);
+       if (!mmc_dev(host)->dma_mask || !*mmc_dev(host)->dma_mask)
+               blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_HIGH);
        blk_queue_max_hw_sectors(mq->queue,
                min(host->max_blk_count, host->max_req_size / 512));
        blk_queue_max_segments(mq->queue, host->max_segs);
index 712a774..8dd8fc3 100644 (file)
@@ -559,7 +559,7 @@ static void mmc_sdio_resend_if_cond(struct mmc_host *host,
  * we're trying to reinitialise.
  */
 static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
-                             struct mmc_card *oldcard, int powered_resume)
+                             struct mmc_card *oldcard)
 {
        struct mmc_card *card;
        int err;
@@ -582,11 +582,9 @@ try_again:
        /*
         * Inform the card of the voltage
         */
-       if (!powered_resume) {
-               err = mmc_send_io_op_cond(host, ocr, &rocr);
-               if (err)
-                       goto err;
-       }
+       err = mmc_send_io_op_cond(host, ocr, &rocr);
+       if (err)
+               goto err;
 
        /*
         * For SPI, enable CRC as appropriate.
@@ -645,7 +643,7 @@ try_again:
         * try to init uhs card. sdio_read_cccr will take over this task
         * to make sure which speed mode should work.
         */
-       if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) {
+       if (rocr & ocr & R4_18V_PRESENT) {
                err = mmc_set_uhs_voltage(host, ocr_card);
                if (err == -EAGAIN) {
                        mmc_sdio_resend_if_cond(host, card);
@@ -659,7 +657,7 @@ try_again:
        /*
         * For native busses:  set card RCA and quit open drain mode.
         */
-       if (!powered_resume && !mmc_host_is_spi(host)) {
+       if (!mmc_host_is_spi(host)) {
                err = mmc_send_relative_addr(host, &card->rca);
                if (err)
                        goto remove;
@@ -687,7 +685,7 @@ try_again:
        /*
         * Select card, as all following commands rely on that.
         */
-       if (!powered_resume && !mmc_host_is_spi(host)) {
+       if (!mmc_host_is_spi(host)) {
                err = mmc_select_card(card);
                if (err)
                        goto remove;
@@ -816,10 +814,27 @@ err:
        return err;
 }
 
-static int mmc_sdio_reinit_card(struct mmc_host *host, bool powered_resume)
+static int mmc_sdio_reinit_card(struct mmc_host *host)
 {
        int ret;
 
+       /*
+        * Reset the card by performing the same steps that are taken by
+        * mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe.
+        *
+        * sdio_reset() is technically not needed. Having just powered up the
+        * hardware, it should already be in reset state. However, some
+        * platforms (such as SD8686 on OLPC) do not instantly cut power,
+        * meaning that a reset is required when restoring power soon after
+        * powering off. It is harmless in other cases.
+        *
+        * The CMD5 reset (mmc_send_io_op_cond()), according to the SDIO spec,
+        * is not necessary for non-removable cards. However, it is required
+        * for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and
+        * harmless in other situations.
+        *
+        */
+
        sdio_reset(host);
        mmc_go_idle(host);
        mmc_send_if_cond(host, host->card->ocr);
@@ -828,8 +843,7 @@ static int mmc_sdio_reinit_card(struct mmc_host *host, bool powered_resume)
        if (ret)
                return ret;
 
-       return mmc_sdio_init_card(host, host->card->ocr, host->card,
-                                 powered_resume);
+       return mmc_sdio_init_card(host, host->card->ocr, host->card);
 }
 
 /*
@@ -965,7 +979,11 @@ static int mmc_sdio_resume(struct mmc_host *host)
        /* Basic card reinitialization. */
        mmc_claim_host(host);
 
-       /* Restore power if needed */
+       /*
+        * Restore power and reinitialize the card when needed. Note that a
+        * removable card is checked from a detect work later on in the resume
+        * process.
+        */
        if (!mmc_card_keep_power(host)) {
                mmc_power_up(host, host->card->ocr);
                /*
@@ -979,12 +997,8 @@ static int mmc_sdio_resume(struct mmc_host *host)
                        pm_runtime_set_active(&host->card->dev);
                        pm_runtime_enable(&host->card->dev);
                }
-       }
-
-       /* No need to reinitialize powered-resumed nonremovable cards */
-       if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
-               err = mmc_sdio_reinit_card(host, mmc_card_keep_power(host));
-       } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
+               err = mmc_sdio_reinit_card(host);
+       } else if (mmc_card_wake_sdio_irq(host)) {
                /* We may have switched to 1-bit mode during suspend */
                err = sdio_enable_4bit_bus(host->card);
        }
@@ -1009,38 +1023,6 @@ out:
        return err;
 }
 
-static int mmc_sdio_power_restore(struct mmc_host *host)
-{
-       int ret;
-
-       /*
-        * Reset the card by performing the same steps that are taken by
-        * mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe.
-        *
-        * sdio_reset() is technically not needed. Having just powered up the
-        * hardware, it should already be in reset state. However, some
-        * platforms (such as SD8686 on OLPC) do not instantly cut power,
-        * meaning that a reset is required when restoring power soon after
-        * powering off. It is harmless in other cases.
-        *
-        * The CMD5 reset (mmc_send_io_op_cond()), according to the SDIO spec,
-        * is not necessary for non-removable cards. However, it is required
-        * for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and
-        * harmless in other situations.
-        *
-        */
-
-       mmc_claim_host(host);
-
-       ret = mmc_sdio_reinit_card(host, mmc_card_keep_power(host));
-       if (!ret && host->sdio_irqs)
-               mmc_signal_sdio_irq(host);
-
-       mmc_release_host(host);
-
-       return ret;
-}
-
 static int mmc_sdio_runtime_suspend(struct mmc_host *host)
 {
        /* No references to the card, cut the power to it. */
@@ -1058,7 +1040,7 @@ static int mmc_sdio_runtime_resume(struct mmc_host *host)
        /* Restore power and re-initialize. */
        mmc_claim_host(host);
        mmc_power_up(host, host->card->ocr);
-       ret = mmc_sdio_power_restore(host);
+       ret = mmc_sdio_reinit_card(host);
        mmc_release_host(host);
 
        return ret;
@@ -1067,7 +1049,7 @@ static int mmc_sdio_runtime_resume(struct mmc_host *host)
 static int mmc_sdio_hw_reset(struct mmc_host *host)
 {
        mmc_power_cycle(host, host->card->ocr);
-       return mmc_sdio_power_restore(host);
+       return mmc_sdio_reinit_card(host);
 }
 
 static int mmc_sdio_sw_reset(struct mmc_host *host)
@@ -1079,7 +1061,7 @@ static int mmc_sdio_sw_reset(struct mmc_host *host)
        mmc_set_initial_state(host);
        mmc_set_initial_signal_voltage(host);
 
-       return mmc_sdio_reinit_card(host, 0);
+       return mmc_sdio_reinit_card(host);
 }
 
 static const struct mmc_bus_ops mmc_sdio_ops = {
@@ -1129,7 +1111,7 @@ int mmc_attach_sdio(struct mmc_host *host)
        /*
         * Detect and init the card.
         */
-       err = mmc_sdio_init_card(host, rocr, NULL, 0);
+       err = mmc_sdio_init_card(host, rocr, NULL);
        if (err)
                goto err;
 
index 9f54a25..0bcc5e8 100644 (file)
@@ -92,7 +92,7 @@ static int process_sdio_pending_irqs(struct mmc_host *host)
        return ret;
 }
 
-void sdio_run_irqs(struct mmc_host *host)
+static void sdio_run_irqs(struct mmc_host *host)
 {
        mmc_claim_host(host);
        if (host->sdio_irqs) {
@@ -103,7 +103,6 @@ void sdio_run_irqs(struct mmc_host *host)
        }
        mmc_release_host(host);
 }
-EXPORT_SYMBOL_GPL(sdio_run_irqs);
 
 void sdio_irq_work(struct work_struct *work)
 {
index 931770f..14d89a1 100644 (file)
@@ -996,7 +996,7 @@ config MMC_SDHCI_OMAP
 
 config MMC_SDHCI_AM654
        tristate "Support for the SDHCI Controller in TI's AM654 SOCs"
-       depends on MMC_SDHCI_PLTFM && OF
+       depends on MMC_SDHCI_PLTFM && OF && REGMAP_MMIO
        select MMC_SDHCI_IO_ACCESSORS
        help
          This selects the Secure Digital Host Controller Interface (SDHCI)
index e481535..1aee485 100644 (file)
@@ -672,7 +672,7 @@ static void alcor_set_clock(struct alcor_sdmmc_host *host, unsigned int clock)
                tmp_clock = DIV_ROUND_UP(cfg->clk_src_freq, tmp_div);
                tmp_diff = abs(clock - tmp_clock);
 
-               if (tmp_diff >= 0 && tmp_diff < diff) {
+               if (tmp_diff < diff) {
                        diff = tmp_diff;
                        clk_src = cfg->clk_src_reg;
                        clk_div = tmp_div;
index 11a208c..914e17b 100644 (file)
@@ -110,7 +110,6 @@ struct goldfish_mmc_host {
        struct mmc_request      *mrq;
        struct mmc_command      *cmd;
        struct mmc_data         *data;
-       struct mmc_host         *mmc;
        struct device           *dev;
        unsigned char           id; /* 16xx chips have 2 MMC blocks */
        void                    *virt_base;
@@ -172,7 +171,7 @@ goldfish_mmc_start_command(struct goldfish_mmc_host *host, struct mmc_command *c
                resptype = 3;
                break;
        default:
-               dev_err(mmc_dev(host->mmc),
+               dev_err(mmc_dev(mmc_from_priv(host)),
                        "Invalid response type: %04x\n", mmc_resp_type(cmd));
                break;
        }
@@ -218,8 +217,8 @@ static void goldfish_mmc_xfer_done(struct goldfish_mmc_host *host,
                                        data->sg->length);
                }
                host->data->bytes_xfered += data->sg->length;
-               dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
-                            dma_data_dir);
+               dma_unmap_sg(mmc_dev(mmc_from_priv(host)), data->sg,
+                            host->sg_len, dma_data_dir);
        }
 
        host->data = NULL;
@@ -233,7 +232,7 @@ static void goldfish_mmc_xfer_done(struct goldfish_mmc_host *host,
 
        if (!data->stop) {
                host->mrq = NULL;
-               mmc_request_done(host->mmc, data->mrq);
+               mmc_request_done(mmc_from_priv(host), data->mrq);
                return;
        }
 
@@ -275,7 +274,7 @@ static void goldfish_mmc_cmd_done(struct goldfish_mmc_host *host,
 
        if (host->data == NULL || cmd->error) {
                host->mrq = NULL;
-               mmc_request_done(host->mmc, cmd->mrq);
+               mmc_request_done(mmc_from_priv(host), cmd->mrq);
        }
 }
 
@@ -310,7 +309,7 @@ static irqreturn_t goldfish_mmc_irq(int irq, void *dev_id)
                struct mmc_request *mrq = host->mrq;
                mrq->cmd->error = -ETIMEDOUT;
                host->mrq = NULL;
-               mmc_request_done(host->mmc, mrq);
+               mmc_request_done(mmc_from_priv(host), mrq);
        }
 
        if (end_command)
@@ -336,12 +335,13 @@ static irqreturn_t goldfish_mmc_irq(int irq, void *dev_id)
                u32 state = GOLDFISH_MMC_READ(host, MMC_STATE);
                pr_info("%s: Card detect now %d\n", __func__,
                        (state & MMC_STATE_INSERTED));
-               mmc_detect_change(host->mmc, 0);
+               mmc_detect_change(mmc_from_priv(host), 0);
        }
 
        if (!end_command && !end_transfer && !state_changed && !cmd_timeout) {
                status = GOLDFISH_MMC_READ(host, MMC_INT_STATUS);
-               dev_info(mmc_dev(host->mmc),"spurious irq 0x%04x\n", status);
+               dev_info(mmc_dev(mmc_from_priv(host)), "spurious irq 0x%04x\n",
+                        status);
                if (status != 0) {
                        GOLDFISH_MMC_WRITE(host, MMC_INT_STATUS, status);
                        GOLDFISH_MMC_WRITE(host, MMC_INT_ENABLE, 0);
@@ -380,7 +380,7 @@ static void goldfish_mmc_prepare_data(struct goldfish_mmc_host *host,
 
        dma_data_dir = mmc_get_dma_dir(data);
 
-       host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
+       host->sg_len = dma_map_sg(mmc_dev(mmc_from_priv(host)), data->sg,
                                  sg_len, dma_data_dir);
        host->dma_done = 0;
        host->dma_in_use = 1;
@@ -458,7 +458,6 @@ static int goldfish_mmc_probe(struct platform_device *pdev)
        }
 
        host = mmc_priv(mmc);
-       host->mmc = mmc;
 
        pr_err("mmc: Mapping %lX to %lX\n", (long)res->start, (long)res->end);
        host->reg_base = ioremap(res->start, resource_size(res));
@@ -505,8 +504,7 @@ static int goldfish_mmc_probe(struct platform_device *pdev)
 
        ret = device_create_file(&pdev->dev, &dev_attr_cover_switch);
        if (ret)
-               dev_warn(mmc_dev(host->mmc),
-                        "Unable to create sysfs attributes\n");
+               dev_warn(mmc_dev(mmc), "Unable to create sysfs attributes\n");
 
        GOLDFISH_MMC_WRITE(host, MMC_SET_BUFFER, host->phys_base);
        GOLDFISH_MMC_WRITE(host, MMC_INT_ENABLE,
@@ -522,7 +520,7 @@ err_request_irq_failed:
 dma_alloc_failed:
        iounmap(host->reg_base);
 ioremap_failed:
-       mmc_free_host(host->mmc);
+       mmc_free_host(mmc);
 err_alloc_host_failed:
        return ret;
 }
@@ -530,14 +528,15 @@ err_alloc_host_failed:
 static int goldfish_mmc_remove(struct platform_device *pdev)
 {
        struct goldfish_mmc_host *host = platform_get_drvdata(pdev);
+       struct mmc_host *mmc = mmc_from_priv(host);
 
        BUG_ON(host == NULL);
 
-       mmc_remove_host(host->mmc);
+       mmc_remove_host(mmc);
        free_irq(host->irq, host);
        dma_free_coherent(&pdev->dev, BUFFER_SIZE, host->virt_base, host->phys_base);
        iounmap(host->reg_base);
-       mmc_free_host(host->mmc);
+       mmc_free_host(mmc);
        return 0;
 }
 
index 392a1f8..9ee0bc0 100644 (file)
@@ -576,42 +576,18 @@ static void atmci_init_debugfs(struct atmel_mci_slot *slot)
        struct mmc_host         *mmc = slot->mmc;
        struct atmel_mci        *host = slot->host;
        struct dentry           *root;
-       struct dentry           *node;
 
        root = mmc->debugfs_root;
        if (!root)
                return;
 
-       node = debugfs_create_file("regs", S_IRUSR, root, host,
-                                  &atmci_regs_fops);
-       if (IS_ERR(node))
-               return;
-       if (!node)
-               goto err;
-
-       node = debugfs_create_file("req", S_IRUSR, root, slot,
-                                  &atmci_req_fops);
-       if (!node)
-               goto err;
-
-       node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
-       if (!node)
-               goto err;
-
-       node = debugfs_create_x32("pending_events", S_IRUSR, root,
-                                    (u32 *)&host->pending_events);
-       if (!node)
-               goto err;
-
-       node = debugfs_create_x32("completed_events", S_IRUSR, root,
-                                    (u32 *)&host->completed_events);
-       if (!node)
-               goto err;
-
-       return;
-
-err:
-       dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
+       debugfs_create_file("regs", S_IRUSR, root, host, &atmci_regs_fops);
+       debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops);
+       debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
+       debugfs_create_x32("pending_events", S_IRUSR, root,
+                          (u32 *)&host->pending_events);
+       debugfs_create_x32("completed_events", S_IRUSR, root,
+                          (u32 *)&host->completed_events);
 }
 
 #if defined(CONFIG_OF)
index b53b6b7..faaaf52 100644 (file)
@@ -169,40 +169,18 @@ static void dw_mci_init_debugfs(struct dw_mci_slot *slot)
        struct mmc_host *mmc = slot->mmc;
        struct dw_mci *host = slot->host;
        struct dentry *root;
-       struct dentry *node;
 
        root = mmc->debugfs_root;
        if (!root)
                return;
 
-       node = debugfs_create_file("regs", S_IRUSR, root, host,
-                                  &dw_mci_regs_fops);
-       if (!node)
-               goto err;
-
-       node = debugfs_create_file("req", S_IRUSR, root, slot,
-                                  &dw_mci_req_fops);
-       if (!node)
-               goto err;
-
-       node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
-       if (!node)
-               goto err;
-
-       node = debugfs_create_x32("pending_events", S_IRUSR, root,
-                                 (u32 *)&host->pending_events);
-       if (!node)
-               goto err;
-
-       node = debugfs_create_x32("completed_events", S_IRUSR, root,
-                                 (u32 *)&host->completed_events);
-       if (!node)
-               goto err;
-
-       return;
-
-err:
-       dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
+       debugfs_create_file("regs", S_IRUSR, root, host, &dw_mci_regs_fops);
+       debugfs_create_file("req", S_IRUSR, root, slot, &dw_mci_req_fops);
+       debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
+       debugfs_create_x32("pending_events", S_IRUSR, root,
+                          (u32 *)&host->pending_events);
+       debugfs_create_x32("completed_events", S_IRUSR, root,
+                          (u32 *)&host->completed_events);
 }
 #endif /* defined(CONFIG_DEBUG_FS) */
 
index fb84225..037311d 100644 (file)
 #define SD_EMMC_TXD 0x94
 #define SD_EMMC_LAST_REG SD_EMMC_TXD
 
+#define SD_EMMC_SRAM_DATA_BUF_LEN 1536
+#define SD_EMMC_SRAM_DATA_BUF_OFF 0x200
+
 #define SD_EMMC_CFG_BLK_SIZE 512 /* internal buffer max: 512 bytes */
 #define SD_EMMC_CFG_RESP_TIMEOUT 256 /* in clock cycles */
 #define SD_EMMC_CMD_TIMEOUT 1024 /* in ms */
@@ -155,6 +158,8 @@ struct meson_host {
        unsigned long req_rate;
        bool ddr;
 
+       bool dram_access_quirk;
+
        struct pinctrl *pinctrl;
        struct pinctrl_state *pins_default;
        struct pinctrl_state *pins_clk_gate;
@@ -219,11 +224,20 @@ static struct mmc_command *meson_mmc_get_next_command(struct mmc_command *cmd)
 static void meson_mmc_get_transfer_mode(struct mmc_host *mmc,
                                        struct mmc_request *mrq)
 {
+       struct meson_host *host = mmc_priv(mmc);
        struct mmc_data *data = mrq->data;
        struct scatterlist *sg;
        int i;
        bool use_desc_chain_mode = true;
 
+       /*
+        * When Controller DMA cannot directly access DDR memory, disable
+        * support for Chain Mode to directly use the internal SRAM using
+        * the bounce buffer mode.
+        */
+       if (host->dram_access_quirk)
+               return;
+
        /*
         * Broken SDIO with AP6255-based WiFi on Khadas VIM Pro has been
         * reported. For some strange reason this occurs in descriptor
@@ -1036,6 +1050,10 @@ static int meson_mmc_probe(struct platform_device *pdev)
        host->dev = &pdev->dev;
        dev_set_drvdata(&pdev->dev, host);
 
+       /* The G12A SDIO Controller needs an SRAM bounce buffer */
+       host->dram_access_quirk = device_property_read_bool(&pdev->dev,
+                                       "amlogic,dram-access-quirk");
+
        /* Get regulators and the supported OCR mask */
        host->vqmmc_enabled = false;
        ret = mmc_regulator_get_supply(mmc);
@@ -1133,9 +1151,16 @@ static int meson_mmc_probe(struct platform_device *pdev)
                goto err_init_clk;
 
        mmc->caps |= MMC_CAP_CMD23;
-       mmc->max_blk_count = CMD_CFG_LENGTH_MASK;
+       if (host->dram_access_quirk) {
+               /* Limit to the available sram memory */
+               mmc->max_segs = SD_EMMC_SRAM_DATA_BUF_LEN / mmc->max_blk_size;
+               mmc->max_blk_count = mmc->max_segs;
+       } else {
+               mmc->max_blk_count = CMD_CFG_LENGTH_MASK;
+               mmc->max_segs = SD_EMMC_DESC_BUF_LEN /
+                               sizeof(struct sd_emmc_desc);
+       }
        mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size;
-       mmc->max_segs = SD_EMMC_DESC_BUF_LEN / sizeof(struct sd_emmc_desc);
        mmc->max_seg_size = mmc->max_req_size;
 
        /*
@@ -1145,15 +1170,27 @@ static int meson_mmc_probe(struct platform_device *pdev)
         */
        mmc->caps2 &= ~MMC_CAP2_HS400;
 
-       /* data bounce buffer */
-       host->bounce_buf_size = mmc->max_req_size;
-       host->bounce_buf =
-               dma_alloc_coherent(host->dev, host->bounce_buf_size,
-                                  &host->bounce_dma_addr, GFP_KERNEL);
-       if (host->bounce_buf == NULL) {
-               dev_err(host->dev, "Unable to map allocate DMA bounce buffer.\n");
-               ret = -ENOMEM;
-               goto err_free_irq;
+       if (host->dram_access_quirk) {
+               /*
+                * The MMC Controller embeds 1,5KiB of internal SRAM
+                * that can be used to be used as bounce buffer.
+                * In the case of the G12A SDIO controller, use these
+                * instead of the DDR memory
+                */
+               host->bounce_buf_size = SD_EMMC_SRAM_DATA_BUF_LEN;
+               host->bounce_buf = host->regs + SD_EMMC_SRAM_DATA_BUF_OFF;
+               host->bounce_dma_addr = res->start + SD_EMMC_SRAM_DATA_BUF_OFF;
+       } else {
+               /* data bounce buffer */
+               host->bounce_buf_size = mmc->max_req_size;
+               host->bounce_buf =
+                       dma_alloc_coherent(host->dev, host->bounce_buf_size,
+                                          &host->bounce_dma_addr, GFP_KERNEL);
+               if (host->bounce_buf == NULL) {
+                       dev_err(host->dev, "Unable to map allocate DMA bounce buffer.\n");
+                       ret = -ENOMEM;
+                       goto err_free_irq;
+               }
        }
 
        host->descs = dma_alloc_coherent(host->dev, SD_EMMC_DESC_BUF_LEN,
@@ -1170,8 +1207,9 @@ static int meson_mmc_probe(struct platform_device *pdev)
        return 0;
 
 err_bounce_buf:
-       dma_free_coherent(host->dev, host->bounce_buf_size,
-                         host->bounce_buf, host->bounce_dma_addr);
+       if (!host->dram_access_quirk)
+               dma_free_coherent(host->dev, host->bounce_buf_size,
+                                 host->bounce_buf, host->bounce_dma_addr);
 err_free_irq:
        free_irq(host->irq, host);
 err_init_clk:
@@ -1195,8 +1233,10 @@ static int meson_mmc_remove(struct platform_device *pdev)
 
        dma_free_coherent(host->dev, SD_EMMC_DESC_BUF_LEN,
                          host->descs, host->descs_dma_addr);
-       dma_free_coherent(host->dev, host->bounce_buf_size,
-                         host->bounce_buf, host->bounce_dma_addr);
+
+       if (!host->dram_access_quirk)
+               dma_free_coherent(host->dev, host->bounce_buf_size,
+                                 host->bounce_buf, host->bounce_dma_addr);
 
        clk_disable_unprepare(host->mmc_clk);
        clk_disable_unprepare(host->core_clk);
index 5f8d57a..64d3b5f 100644 (file)
@@ -610,13 +610,12 @@ static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
        renesas_sdhi_sdbuf_width(host, enable ? width : 16);
 }
 
-static const struct renesas_sdhi_quirks sdhi_quirks_h3_m3w_es1 = {
+static const struct renesas_sdhi_quirks sdhi_quirks_4tap_nohs400 = {
        .hs400_disabled = true,
        .hs400_4taps = true,
 };
 
-static const struct renesas_sdhi_quirks sdhi_quirks_h3_es2 = {
-       .hs400_disabled = false,
+static const struct renesas_sdhi_quirks sdhi_quirks_4tap = {
        .hs400_4taps = true,
 };
 
@@ -625,10 +624,10 @@ static const struct renesas_sdhi_quirks sdhi_quirks_nohs400 = {
 };
 
 static const struct soc_device_attribute sdhi_quirks_match[]  = {
-       { .soc_id = "r8a7795", .revision = "ES1.*", .data = &sdhi_quirks_h3_m3w_es1 },
-       { .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_h3_es2 },
-       { .soc_id = "r8a7796", .revision = "ES1.[012]", .data = &sdhi_quirks_h3_m3w_es1 },
-       { .soc_id = "r8a774a1", .revision = "ES1.[012]", .data = &sdhi_quirks_h3_m3w_es1 },
+       { .soc_id = "r8a7795", .revision = "ES1.*", .data = &sdhi_quirks_4tap_nohs400 },
+       { .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_4tap },
+       { .soc_id = "r8a7796", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 },
+       { .soc_id = "r8a774a1", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 },
        { .soc_id = "r8a77980", .data = &sdhi_quirks_nohs400 },
        { /* Sentinel. */ },
 };
@@ -775,6 +774,8 @@ int renesas_sdhi_probe(struct platform_device *pdev,
        /* All SDHI have SDIO status bits which must be 1 */
        mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS;
 
+       pm_runtime_enable(&pdev->dev);
+
        ret = renesas_sdhi_clk_enable(host);
        if (ret)
                goto efree;
@@ -855,6 +856,8 @@ edisclk:
 efree:
        tmio_mmc_host_free(host);
 
+       pm_runtime_disable(&pdev->dev);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(renesas_sdhi_probe);
@@ -866,6 +869,8 @@ int renesas_sdhi_remove(struct platform_device *pdev)
        tmio_mmc_host_remove(host);
        renesas_sdhi_clk_disable(host);
 
+       pm_runtime_disable(&pdev->dev);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(renesas_sdhi_remove);
index b1d3f82..ccc5f09 100644 (file)
@@ -1449,33 +1449,18 @@ DEFINE_SHOW_ATTRIBUTE(s3cmci_regs);
 static void s3cmci_debugfs_attach(struct s3cmci_host *host)
 {
        struct device *dev = &host->pdev->dev;
+       struct dentry *root;
 
-       host->debug_root = debugfs_create_dir(dev_name(dev), NULL);
-       if (IS_ERR(host->debug_root)) {
-               dev_err(dev, "failed to create debugfs root\n");
-               return;
-       }
-
-       host->debug_state = debugfs_create_file("state", 0444,
-                                               host->debug_root, host,
-                                               &s3cmci_state_fops);
-
-       if (IS_ERR(host->debug_state))
-               dev_err(dev, "failed to create debug state file\n");
-
-       host->debug_regs = debugfs_create_file("regs", 0444,
-                                              host->debug_root, host,
-                                              &s3cmci_regs_fops);
+       root = debugfs_create_dir(dev_name(dev), NULL);
+       host->debug_root = root;
 
-       if (IS_ERR(host->debug_regs))
-               dev_err(dev, "failed to create debug regs file\n");
+       debugfs_create_file("state", 0444, root, host, &s3cmci_state_fops);
+       debugfs_create_file("regs", 0444, root, host, &s3cmci_regs_fops);
 }
 
 static void s3cmci_debugfs_remove(struct s3cmci_host *host)
 {
-       debugfs_remove(host->debug_regs);
-       debugfs_remove(host->debug_state);
-       debugfs_remove(host->debug_root);
+       debugfs_remove_recursive(host->debug_root);
 }
 
 #else
index 7ca1d9d..8b65d7a 100644 (file)
@@ -67,8 +67,6 @@ struct s3cmci_host {
 
 #ifdef CONFIG_DEBUG_FS
        struct dentry           *debug_root;
-       struct dentry           *debug_state;
-       struct dentry           *debug_regs;
 #endif
 
 #ifdef CONFIG_ARM_S3C24XX_CPUFREQ
index 5fc76a1..9cf14b3 100644 (file)
@@ -575,11 +575,14 @@ static int msm_init_cm_dll(struct sdhci_host *host)
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
        int wait_cnt = 50;
-       unsigned long flags;
+       unsigned long flags, xo_clk = 0;
        u32 config;
        const struct sdhci_msm_offset *msm_offset =
                                        msm_host->offset;
 
+       if (msm_host->use_14lpp_dll_reset && !IS_ERR_OR_NULL(msm_host->xo_clk))
+               xo_clk = clk_get_rate(msm_host->xo_clk);
+
        spin_lock_irqsave(&host->lock, flags);
 
        /*
@@ -627,10 +630,10 @@ static int msm_init_cm_dll(struct sdhci_host *host)
                config &= CORE_FLL_CYCLE_CNT;
                if (config)
                        mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 8),
-                                       clk_get_rate(msm_host->xo_clk));
+                                       xo_clk);
                else
                        mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 4),
-                                       clk_get_rate(msm_host->xo_clk));
+                                       xo_clk);
 
                config = readl_relaxed(host->ioaddr +
                                msm_offset->core_dll_config_2);
index 68c5866..4dd43b1 100644 (file)
@@ -830,9 +830,17 @@ static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
        bool hs400_tuning;
+       unsigned int clk;
        u32 val;
        int ret;
 
+       /* For tuning mode, the sd clock divisor value
+        * must be larger than 3 according to reference manual.
+        */
+       clk = esdhc->peripheral_clock / 3;
+       if (host->clock > clk)
+               esdhc_of_set_clock(host, clk);
+
        if (esdhc->quirk_limited_clk_division &&
            host->flags & SDHCI_HS400_TUNING)
                esdhc_of_set_clock(host, host->clock);
@@ -1040,11 +1048,12 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
                /*
                 * esdhc->peripheral_clock would be assigned with a value
                 * which is eSDHC base clock when use periperal clock.
-                * For ls1046a, the clock value got by common clk API is
-                * peripheral clock while the eSDHC base clock is 1/2
-                * peripheral clock.
+                * For some platforms, the clock value got by common clk
+                * API is peripheral clock while the eSDHC base clock is
+                * 1/2 peripheral clock.
                 */
-               if (of_device_is_compatible(np, "fsl,ls1046a-esdhc"))
+               if (of_device_is_compatible(np, "fsl,ls1046a-esdhc") ||
+                   of_device_is_compatible(np, "fsl,ls1028a-esdhc"))
                        esdhc->peripheral_clock = clk_get_rate(clk) / 2;
                else
                        esdhc->peripheral_clock = clk_get_rate(clk);
index 4154ee1..4041878 100644 (file)
@@ -1668,6 +1668,8 @@ static const struct pci_device_id pci_ids[] = {
        SDHCI_PCI_DEVICE(INTEL, CNPH_SD,   intel_byt_sd),
        SDHCI_PCI_DEVICE(INTEL, ICP_EMMC,  intel_glk_emmc),
        SDHCI_PCI_DEVICE(INTEL, ICP_SD,    intel_byt_sd),
+       SDHCI_PCI_DEVICE(INTEL, EHL_EMMC,  intel_glk_emmc),
+       SDHCI_PCI_DEVICE(INTEL, EHL_SD,    intel_byt_sd),
        SDHCI_PCI_DEVICE(INTEL, CML_EMMC,  intel_glk_emmc),
        SDHCI_PCI_DEVICE(INTEL, CML_SD,    intel_byt_sd),
        SDHCI_PCI_DEVICE(O2, 8120,     o2),
@@ -2040,8 +2042,6 @@ static int sdhci_pci_probe(struct pci_dev *pdev,
 
        slots = PCI_SLOT_INFO_SLOTS(slots) + 1;
        dev_dbg(&pdev->dev, "found %d slot(s)\n", slots);
-       if (slots == 0)
-               return -ENODEV;
 
        BUG_ON(slots > MAX_SLOTS);
 
index dd21315..9dc4548 100644 (file)
@@ -395,11 +395,21 @@ int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
 {
        struct sdhci_pci_chip *chip;
        struct sdhci_host *host;
-       u32 reg;
+       u32 reg, caps;
        int ret;
 
        chip = slot->chip;
        host = slot->host;
+
+       caps = sdhci_readl(host, SDHCI_CAPABILITIES);
+
+       /*
+        * mmc_select_bus_width() will test the bus to determine the actual bus
+        * width.
+        */
+       if (caps & SDHCI_CAN_DO_8BIT)
+               host->mmc->caps |= MMC_CAP_8_BIT_DATA;
+
        switch (chip->pdev->device) {
        case PCI_DEVICE_ID_O2_SDS0:
        case PCI_DEVICE_ID_O2_SEABIRD0:
index e5dc6e4..cdd15f3 100644 (file)
@@ -50,6 +50,8 @@
 #define PCI_DEVICE_ID_INTEL_CNPH_SD    0xa375
 #define PCI_DEVICE_ID_INTEL_ICP_EMMC   0x34c4
 #define PCI_DEVICE_ID_INTEL_ICP_SD     0x34f8
+#define PCI_DEVICE_ID_INTEL_EHL_EMMC   0x4b47
+#define PCI_DEVICE_ID_INTEL_EHL_SD     0x4b48
 #define PCI_DEVICE_ID_INTEL_CML_EMMC   0x02c4
 #define PCI_DEVICE_ID_INTEL_CML_SD     0x02f5
 
index 9a822e2..6ee340a 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 /* SDHCI_ARGUMENT2 register high 16bit */
 #define SDHCI_SPRD_ARG2_STUFF          GENMASK(31, 16)
 
+#define SDHCI_SPRD_REG_32_DLL_CFG      0x200
+#define  SDHCI_SPRD_DLL_ALL_CPST_EN    (BIT(18) | BIT(24) | BIT(25) | BIT(26) | BIT(27))
+#define  SDHCI_SPRD_DLL_EN             BIT(21)
+#define  SDHCI_SPRD_DLL_SEARCH_MODE    BIT(16)
+#define  SDHCI_SPRD_DLL_INIT_COUNT     0xc00
+#define  SDHCI_SPRD_DLL_PHASE_INTERNAL 0x3
+
+#define SDHCI_SPRD_REG_32_DLL_DLY      0x204
+
 #define SDHCI_SPRD_REG_32_DLL_DLY_OFFSET       0x208
 #define  SDHCIBSPRD_IT_WR_DLY_INV              BIT(5)
 #define  SDHCI_SPRD_BIT_CMD_DLY_INV            BIT(13)
@@ -41,6 +51,7 @@
 /* SDHCI_HOST_CONTROL2 */
 #define  SDHCI_SPRD_CTRL_HS200         0x0005
 #define  SDHCI_SPRD_CTRL_HS400         0x0006
+#define  SDHCI_SPRD_CTRL_HS400ES       0x0007
 
 /*
  * According to the standard specification, BIT(3) of SDHCI_SOFTWARE_RESET is
 #define SDHCI_SPRD_CLK_MAX_DIV         1023
 
 #define SDHCI_SPRD_CLK_DEF_RATE                26000000
+#define SDHCI_SPRD_PHY_DLL_CLK         52000000
 
 struct sdhci_sprd_host {
        u32 version;
        struct clk *clk_sdio;
        struct clk *clk_enable;
+       struct clk *clk_2x_enable;
+       struct pinctrl *pinctrl;
+       struct pinctrl_state *pins_uhs;
+       struct pinctrl_state *pins_default;
        u32 base_rate;
        int flags; /* backup of host attribute */
+       u32 phy_delay[MMC_TIMING_MMC_HS400 + 2];
+};
+
+struct sdhci_sprd_phy_cfg {
+       const char *property;
+       u8 timing;
+};
+
+static const struct sdhci_sprd_phy_cfg sdhci_sprd_phy_cfgs[] = {
+       { "sprd,phy-delay-legacy", MMC_TIMING_LEGACY, },
+       { "sprd,phy-delay-sd-highspeed", MMC_TIMING_SD_HS, },
+       { "sprd,phy-delay-sd-uhs-sdr50", MMC_TIMING_UHS_SDR50, },
+       { "sprd,phy-delay-sd-uhs-sdr104", MMC_TIMING_UHS_SDR104, },
+       { "sprd,phy-delay-mmc-highspeed", MMC_TIMING_MMC_HS, },
+       { "sprd,phy-delay-mmc-ddr52", MMC_TIMING_MMC_DDR52, },
+       { "sprd,phy-delay-mmc-hs200", MMC_TIMING_MMC_HS200, },
+       { "sprd,phy-delay-mmc-hs400", MMC_TIMING_MMC_HS400, },
+       { "sprd,phy-delay-mmc-hs400es", MMC_TIMING_MMC_HS400 + 1, },
 };
 
 #define TO_SPRD_HOST(host) sdhci_pltfm_priv(sdhci_priv(host))
@@ -131,6 +165,15 @@ static inline void sdhci_sprd_sd_clk_off(struct sdhci_host *host)
        sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL);
 }
 
+static inline void sdhci_sprd_sd_clk_on(struct sdhci_host *host)
+{
+       u16 ctrl;
+
+       ctrl = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+       ctrl |= SDHCI_CLOCK_CARD_EN;
+       sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL);
+}
+
 static inline void
 sdhci_sprd_set_dll_invert(struct sdhci_host *host, u32 mask, bool en)
 {
@@ -189,9 +232,33 @@ static inline void _sdhci_sprd_set_clock(struct sdhci_host *host,
        }
 }
 
+static void sdhci_sprd_enable_phy_dll(struct sdhci_host *host)
+{
+       u32 tmp;
+
+       tmp = sdhci_readl(host, SDHCI_SPRD_REG_32_DLL_CFG);
+       tmp &= ~(SDHCI_SPRD_DLL_EN | SDHCI_SPRD_DLL_ALL_CPST_EN);
+       sdhci_writel(host, tmp, SDHCI_SPRD_REG_32_DLL_CFG);
+       /* wait 1ms */
+       usleep_range(1000, 1250);
+
+       tmp = sdhci_readl(host, SDHCI_SPRD_REG_32_DLL_CFG);
+       tmp |= SDHCI_SPRD_DLL_ALL_CPST_EN | SDHCI_SPRD_DLL_SEARCH_MODE |
+               SDHCI_SPRD_DLL_INIT_COUNT | SDHCI_SPRD_DLL_PHASE_INTERNAL;
+       sdhci_writel(host, tmp, SDHCI_SPRD_REG_32_DLL_CFG);
+       /* wait 1ms */
+       usleep_range(1000, 1250);
+
+       tmp = sdhci_readl(host, SDHCI_SPRD_REG_32_DLL_CFG);
+       tmp |= SDHCI_SPRD_DLL_EN;
+       sdhci_writel(host, tmp, SDHCI_SPRD_REG_32_DLL_CFG);
+       /* wait 1ms */
+       usleep_range(1000, 1250);
+}
+
 static void sdhci_sprd_set_clock(struct sdhci_host *host, unsigned int clock)
 {
-       bool en = false;
+       bool en = false, clk_changed = false;
 
        if (clock == 0) {
                sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
@@ -203,9 +270,19 @@ static void sdhci_sprd_set_clock(struct sdhci_host *host, unsigned int clock)
                        en = true;
                sdhci_sprd_set_dll_invert(host, SDHCI_SPRD_BIT_CMD_DLY_INV |
                                          SDHCI_SPRD_BIT_POSRD_DLY_INV, en);
+               clk_changed = true;
        } else {
                _sdhci_sprd_set_clock(host, clock);
        }
+
+       /*
+        * According to the Spreadtrum SD host specification, when we changed
+        * the clock to be more than 52M, we should enable the PHY DLL which
+        * is used to track the clock frequency to make the clock work more
+        * stable. Otherwise deviation may occur of the higher clock.
+        */
+       if (clk_changed && clock > SDHCI_SPRD_PHY_DLL_CLK)
+               sdhci_sprd_enable_phy_dll(host);
 }
 
 static unsigned int sdhci_sprd_get_max_clock(struct sdhci_host *host)
@@ -223,6 +300,9 @@ static unsigned int sdhci_sprd_get_min_clock(struct sdhci_host *host)
 static void sdhci_sprd_set_uhs_signaling(struct sdhci_host *host,
                                         unsigned int timing)
 {
+       struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
+       struct mmc_host *mmc = host->mmc;
+       u32 *p = sprd_host->phy_delay;
        u16 ctrl_2;
 
        if (timing == host->timing)
@@ -261,6 +341,9 @@ static void sdhci_sprd_set_uhs_signaling(struct sdhci_host *host,
        }
 
        sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+
+       if (!mmc->ios.enhanced_strobe)
+               sdhci_writel(host, p[timing], SDHCI_SPRD_REG_32_DLL_DLY);
 }
 
 static void sdhci_sprd_hw_reset(struct sdhci_host *host)
@@ -284,6 +367,12 @@ static void sdhci_sprd_hw_reset(struct sdhci_host *host)
        usleep_range(300, 500);
 }
 
+static unsigned int sdhci_sprd_get_max_timeout_count(struct sdhci_host *host)
+{
+       /* The Spredtrum controller actual maximum timeout count is 1 << 31 */
+       return 1 << 31;
+}
+
 static struct sdhci_ops sdhci_sprd_ops = {
        .read_l = sdhci_sprd_readl,
        .write_l = sdhci_sprd_writel,
@@ -295,6 +384,7 @@ static struct sdhci_ops sdhci_sprd_ops = {
        .reset = sdhci_reset,
        .set_uhs_signaling = sdhci_sprd_set_uhs_signaling,
        .hw_reset = sdhci_sprd_hw_reset,
+       .get_max_timeout_count = sdhci_sprd_get_max_timeout_count,
 };
 
 static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq)
@@ -317,6 +407,99 @@ static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq)
        sdhci_request(mmc, mrq);
 }
 
+static int sdhci_sprd_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+       struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
+       int ret;
+
+       if (!IS_ERR(mmc->supply.vqmmc)) {
+               ret = mmc_regulator_set_vqmmc(mmc, ios);
+               if (ret) {
+                       pr_err("%s: Switching signalling voltage failed\n",
+                              mmc_hostname(mmc));
+                       return ret;
+               }
+       }
+
+       if (IS_ERR(sprd_host->pinctrl))
+               return 0;
+
+       switch (ios->signal_voltage) {
+       case MMC_SIGNAL_VOLTAGE_180:
+               ret = pinctrl_select_state(sprd_host->pinctrl,
+                                          sprd_host->pins_uhs);
+               if (ret) {
+                       pr_err("%s: failed to select uhs pin state\n",
+                              mmc_hostname(mmc));
+                       return ret;
+               }
+               break;
+
+       default:
+               /* fall-through */
+       case MMC_SIGNAL_VOLTAGE_330:
+               ret = pinctrl_select_state(sprd_host->pinctrl,
+                                          sprd_host->pins_default);
+               if (ret) {
+                       pr_err("%s: failed to select default pin state\n",
+                              mmc_hostname(mmc));
+                       return ret;
+               }
+               break;
+       }
+
+       /* Wait for 300 ~ 500 us for pin state stable */
+       usleep_range(300, 500);
+       sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+
+       return 0;
+}
+
+static void sdhci_sprd_hs400_enhanced_strobe(struct mmc_host *mmc,
+                                            struct mmc_ios *ios)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+       struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
+       u32 *p = sprd_host->phy_delay;
+       u16 ctrl_2;
+
+       if (!ios->enhanced_strobe)
+               return;
+
+       sdhci_sprd_sd_clk_off(host);
+
+       /* Set HS400 enhanced strobe mode */
+       ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+       ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+       ctrl_2 |= SDHCI_SPRD_CTRL_HS400ES;
+       sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+
+       sdhci_sprd_sd_clk_on(host);
+
+       /* Set the PHY DLL delay value for HS400 enhanced strobe mode */
+       sdhci_writel(host, p[MMC_TIMING_MMC_HS400 + 1],
+                    SDHCI_SPRD_REG_32_DLL_DLY);
+}
+
+static void sdhci_sprd_phy_param_parse(struct sdhci_sprd_host *sprd_host,
+                                      struct device_node *np)
+{
+       u32 *p = sprd_host->phy_delay;
+       int ret, i, index;
+       u32 val[4];
+
+       for (i = 0; i < ARRAY_SIZE(sdhci_sprd_phy_cfgs); i++) {
+               ret = of_property_read_u32_array(np,
+                               sdhci_sprd_phy_cfgs[i].property, val, 4);
+               if (ret)
+                       continue;
+
+               index = sdhci_sprd_phy_cfgs[i].timing;
+               p[index] = val[0] | (val[1] << 8) | (val[2] << 16) | (val[3] << 24);
+       }
+}
+
 static const struct sdhci_pltfm_data sdhci_sprd_pdata = {
        .quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,
        .quirks2 = SDHCI_QUIRK2_BROKEN_HS200 |
@@ -338,6 +521,16 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
        host->dma_mask = DMA_BIT_MASK(64);
        pdev->dev.dma_mask = &host->dma_mask;
        host->mmc_host_ops.request = sdhci_sprd_request;
+       host->mmc_host_ops.hs400_enhanced_strobe =
+               sdhci_sprd_hs400_enhanced_strobe;
+       /*
+        * We can not use the standard ops to change and detect the voltage
+        * signal for Spreadtrum SD host controller, since our voltage regulator
+        * for I/O is fixed in hardware, that means we do not need control
+        * the standard SD host controller to change the I/O voltage.
+        */
+       host->mmc_host_ops.start_signal_voltage_switch =
+               sdhci_sprd_voltage_switch;
 
        host->mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
                MMC_CAP_ERASE | MMC_CAP_CMD23;
@@ -346,6 +539,24 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
                goto pltfm_free;
 
        sprd_host = TO_SPRD_HOST(host);
+       sdhci_sprd_phy_param_parse(sprd_host, pdev->dev.of_node);
+
+       sprd_host->pinctrl = devm_pinctrl_get(&pdev->dev);
+       if (!IS_ERR(sprd_host->pinctrl)) {
+               sprd_host->pins_uhs =
+                       pinctrl_lookup_state(sprd_host->pinctrl, "state_uhs");
+               if (IS_ERR(sprd_host->pins_uhs)) {
+                       ret = PTR_ERR(sprd_host->pins_uhs);
+                       goto pltfm_free;
+               }
+
+               sprd_host->pins_default =
+                       pinctrl_lookup_state(sprd_host->pinctrl, "default");
+               if (IS_ERR(sprd_host->pins_default)) {
+                       ret = PTR_ERR(sprd_host->pins_default);
+                       goto pltfm_free;
+               }
+       }
 
        clk = devm_clk_get(&pdev->dev, "sdio");
        if (IS_ERR(clk)) {
@@ -364,14 +575,22 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
        }
        sprd_host->clk_enable = clk;
 
+       clk = devm_clk_get(&pdev->dev, "2x_enable");
+       if (!IS_ERR(clk))
+               sprd_host->clk_2x_enable = clk;
+
        ret = clk_prepare_enable(sprd_host->clk_sdio);
        if (ret)
                goto pltfm_free;
 
-       clk_prepare_enable(sprd_host->clk_enable);
+       ret = clk_prepare_enable(sprd_host->clk_enable);
        if (ret)
                goto clk_disable;
 
+       ret = clk_prepare_enable(sprd_host->clk_2x_enable);
+       if (ret)
+               goto clk_disable2;
+
        sdhci_sprd_init_config(host);
        host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
        sprd_host->version = ((host->version & SDHCI_VENDOR_VER_MASK) >>
@@ -408,6 +627,9 @@ pm_runtime_disable:
        pm_runtime_disable(&pdev->dev);
        pm_runtime_set_suspended(&pdev->dev);
 
+       clk_disable_unprepare(sprd_host->clk_2x_enable);
+
+clk_disable2:
        clk_disable_unprepare(sprd_host->clk_enable);
 
 clk_disable:
@@ -427,6 +649,7 @@ static int sdhci_sprd_remove(struct platform_device *pdev)
        mmc_remove_host(mmc);
        clk_disable_unprepare(sprd_host->clk_sdio);
        clk_disable_unprepare(sprd_host->clk_enable);
+       clk_disable_unprepare(sprd_host->clk_2x_enable);
 
        mmc_free_host(mmc);
 
@@ -449,6 +672,7 @@ static int sdhci_sprd_runtime_suspend(struct device *dev)
 
        clk_disable_unprepare(sprd_host->clk_sdio);
        clk_disable_unprepare(sprd_host->clk_enable);
+       clk_disable_unprepare(sprd_host->clk_2x_enable);
 
        return 0;
 }
@@ -459,19 +683,28 @@ static int sdhci_sprd_runtime_resume(struct device *dev)
        struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
        int ret;
 
-       ret = clk_prepare_enable(sprd_host->clk_enable);
+       ret = clk_prepare_enable(sprd_host->clk_2x_enable);
        if (ret)
                return ret;
 
+       ret = clk_prepare_enable(sprd_host->clk_enable);
+       if (ret)
+               goto clk_2x_disable;
+
        ret = clk_prepare_enable(sprd_host->clk_sdio);
-       if (ret) {
-               clk_disable_unprepare(sprd_host->clk_enable);
-               return ret;
-       }
+       if (ret)
+               goto clk_disable;
 
        sdhci_runtime_resume_host(host);
-
        return 0;
+
+clk_disable:
+       clk_disable_unprepare(sprd_host->clk_enable);
+
+clk_2x_disable:
+       clk_disable_unprepare(sprd_host->clk_2x_enable);
+
+       return ret;
 }
 #endif
 
index 781a3e1..f4d4761 100644 (file)
@@ -1541,8 +1541,11 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
 
        clk = devm_clk_get(mmc_dev(host->mmc), NULL);
        if (IS_ERR(clk)) {
-               dev_err(mmc_dev(host->mmc), "clk err\n");
                rc = PTR_ERR(clk);
+
+               if (rc != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "failed to get clock: %d\n", rc);
+
                goto err_clk_get;
        }
        clk_prepare_enable(clk);
index 199712e..89fd965 100644 (file)
@@ -89,7 +89,7 @@
 #define   SDHCI_CTRL_ADMA32    0x10
 #define   SDHCI_CTRL_ADMA64    0x18
 #define   SDHCI_CTRL_ADMA3     0x18
-#define   SDHCI_CTRL_8BITBUS   0x20
+#define  SDHCI_CTRL_8BITBUS    0x20
 #define  SDHCI_CTRL_CDTEST_INS 0x40
 #define  SDHCI_CTRL_CDTEST_EN  0x80
 
index 3222ea4..bb90757 100644 (file)
@@ -6,6 +6,7 @@
  *
  */
 #include <linux/clk.h>
+#include <linux/of.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
 #include <linux/property.h>
 #define OTAPDLYSEL_SHIFT       12
 #define OTAPDLYSEL_MASK                GENMASK(15, 12)
 #define STRBSEL_SHIFT          24
-#define STRBSEL_MASK           GENMASK(27, 24)
+#define STRBSEL_4BIT_MASK      GENMASK(27, 24)
+#define STRBSEL_8BIT_MASK      GENMASK(31, 24)
 #define SEL50_SHIFT            8
 #define SEL50_MASK             BIT(SEL50_SHIFT)
 #define SEL100_SHIFT           9
 #define SEL100_MASK            BIT(SEL100_SHIFT)
+#define FREQSEL_SHIFT          8
+#define FREQSEL_MASK           GENMASK(10, 8)
 #define DLL_TRIM_ICP_SHIFT     4
 #define DLL_TRIM_ICP_MASK      GENMASK(7, 4)
 #define DR_TY_SHIFT            20
@@ -77,19 +81,29 @@ struct sdhci_am654_data {
        int trm_icp;
        int drv_strength;
        bool dll_on;
+       int strb_sel;
+       u32 flags;
+};
+
+struct sdhci_am654_driver_data {
+       const struct sdhci_pltfm_data *pdata;
+       u32 flags;
+#define IOMUX_PRESENT  (1 << 0)
+#define FREQSEL_2_BIT  (1 << 1)
+#define STRBSEL_4_BIT  (1 << 2)
+#define DLL_PRESENT    (1 << 3)
 };
 
 static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
-       int sel50, sel100;
+       int sel50, sel100, freqsel;
        u32 mask, val;
        int ret;
 
        if (sdhci_am654->dll_on) {
-               regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
-                                  ENDLL_MASK, 0);
+               regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, 0);
 
                sdhci_am654->dll_on = false;
        }
@@ -101,27 +115,53 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
                mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
                val = (1 << OTAPDLYENA_SHIFT) |
                      (sdhci_am654->otap_del_sel << OTAPDLYSEL_SHIFT);
-               regmap_update_bits(sdhci_am654->base, PHY_CTRL4,
-                                  mask, val);
-               switch (clock) {
-               case 200000000:
-                       sel50 = 0;
-                       sel100 = 0;
-                       break;
-               case 100000000:
-                       sel50 = 0;
-                       sel100 = 1;
-                       break;
-               default:
-                       sel50 = 1;
-                       sel100 = 0;
+               regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
+               /* Write to STRBSEL for HS400 speed mode */
+               if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
+                       if (sdhci_am654->flags & STRBSEL_4_BIT)
+                               mask = STRBSEL_4BIT_MASK;
+                       else
+                               mask = STRBSEL_8BIT_MASK;
+
+                       regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask,
+                                          sdhci_am654->strb_sel <<
+                                          STRBSEL_SHIFT);
+               }
+
+               if (sdhci_am654->flags & FREQSEL_2_BIT) {
+                       switch (clock) {
+                       case 200000000:
+                               sel50 = 0;
+                               sel100 = 0;
+                               break;
+                       case 100000000:
+                               sel50 = 0;
+                               sel100 = 1;
+                               break;
+                       default:
+                               sel50 = 1;
+                               sel100 = 0;
+                       }
+
+                       /* Configure PHY DLL frequency */
+                       mask = SEL50_MASK | SEL100_MASK;
+                       val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
+                       regmap_update_bits(sdhci_am654->base, PHY_CTRL5, mask,
+                                          val);
+               } else {
+                       switch (clock) {
+                       case 200000000:
+                               freqsel = 0x0;
+                               break;
+                       default:
+                               freqsel = 0x4;
+                       }
+
+                       regmap_update_bits(sdhci_am654->base, PHY_CTRL5,
+                                          FREQSEL_MASK,
+                                          freqsel << FREQSEL_SHIFT);
                }
 
-               /* Configure PHY DLL frequency */
-               mask = SEL50_MASK | SEL100_MASK;
-               val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
-               regmap_update_bits(sdhci_am654->base, PHY_CTRL5,
-                                  mask, val);
                /* Configure DLL TRIM */
                mask = DLL_TRIM_ICP_MASK;
                val = sdhci_am654->trm_icp << DLL_TRIM_ICP_SHIFT;
@@ -129,24 +169,41 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
                /* Configure DLL driver strength */
                mask |= DR_TY_MASK;
                val |= sdhci_am654->drv_strength << DR_TY_SHIFT;
-               regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
-                                  mask, val);
+               regmap_update_bits(sdhci_am654->base, PHY_CTRL1, mask, val);
                /* Enable DLL */
-               regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
-                                  ENDLL_MASK, 0x1 << ENDLL_SHIFT);
+               regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK,
+                                  0x1 << ENDLL_SHIFT);
                /*
                 * Poll for DLL ready. Use a one second timeout.
                 * Works in all experiments done so far
                 */
-               ret = regmap_read_poll_timeout(sdhci_am654->base,
-                                        PHY_STAT1, val,
-                                        val & DLLRDY_MASK,
-                                        1000, 1000000);
+               ret = regmap_read_poll_timeout(sdhci_am654->base, PHY_STAT1,
+                                              val, val & DLLRDY_MASK, 1000,
+                                              1000000);
+               if (ret) {
+                       dev_err(mmc_dev(host->mmc), "DLL failed to relock\n");
+                       return;
+               }
 
                sdhci_am654->dll_on = true;
        }
 }
 
+static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host,
+                                      unsigned int clock)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
+       int val, mask;
+
+       mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
+       val = (1 << OTAPDLYENA_SHIFT) |
+             (sdhci_am654->otap_del_sel << OTAPDLYSEL_SHIFT);
+       regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
+
+       sdhci_set_clock(host, clock);
+}
+
 static void sdhci_am654_set_power(struct sdhci_host *host, unsigned char mode,
                                  unsigned short vdd)
 {
@@ -197,6 +254,56 @@ static const struct sdhci_pltfm_data sdhci_am654_pdata = {
        .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
 };
 
+static const struct sdhci_am654_driver_data sdhci_am654_drvdata = {
+       .pdata = &sdhci_am654_pdata,
+       .flags = IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT | DLL_PRESENT,
+};
+
+static struct sdhci_ops sdhci_j721e_8bit_ops = {
+       .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+       .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
+       .set_uhs_signaling = sdhci_set_uhs_signaling,
+       .set_bus_width = sdhci_set_bus_width,
+       .set_power = sdhci_am654_set_power,
+       .set_clock = sdhci_am654_set_clock,
+       .write_b = sdhci_am654_write_b,
+       .reset = sdhci_reset,
+};
+
+static const struct sdhci_pltfm_data sdhci_j721e_8bit_pdata = {
+       .ops = &sdhci_j721e_8bit_ops,
+       .quirks = SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
+                 SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
+       .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+};
+
+static const struct sdhci_am654_driver_data sdhci_j721e_8bit_drvdata = {
+       .pdata = &sdhci_j721e_8bit_pdata,
+       .flags = DLL_PRESENT,
+};
+
+static struct sdhci_ops sdhci_j721e_4bit_ops = {
+       .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+       .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
+       .set_uhs_signaling = sdhci_set_uhs_signaling,
+       .set_bus_width = sdhci_set_bus_width,
+       .set_power = sdhci_am654_set_power,
+       .set_clock = sdhci_j721e_4bit_set_clock,
+       .write_b = sdhci_am654_write_b,
+       .reset = sdhci_reset,
+};
+
+static const struct sdhci_pltfm_data sdhci_j721e_4bit_pdata = {
+       .ops = &sdhci_j721e_4bit_ops,
+       .quirks = SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
+                 SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
+       .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+};
+
+static const struct sdhci_am654_driver_data sdhci_j721e_4bit_drvdata = {
+       .pdata = &sdhci_j721e_4bit_pdata,
+       .flags = IOMUX_PRESENT,
+};
 static int sdhci_am654_init(struct sdhci_host *host)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -208,30 +315,34 @@ static int sdhci_am654_init(struct sdhci_host *host)
 
        /* Reset OTAP to default value */
        mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
-       regmap_update_bits(sdhci_am654->base, PHY_CTRL4,
-                                  mask, 0x0);
-
-       regmap_read(sdhci_am654->base, PHY_STAT1, &val);
-       if (~val & CALDONE_MASK) {
-               /* Calibrate IO lines */
-               regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
-                                  PDB_MASK, PDB_MASK);
-               ret = regmap_read_poll_timeout(sdhci_am654->base, PHY_STAT1,
-                                              val, val & CALDONE_MASK, 1, 20);
-               if (ret)
-                       return ret;
+       regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, 0x0);
+
+       if (sdhci_am654->flags & DLL_PRESENT) {
+               regmap_read(sdhci_am654->base, PHY_STAT1, &val);
+               if (~val & CALDONE_MASK) {
+                       /* Calibrate IO lines */
+                       regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
+                                          PDB_MASK, PDB_MASK);
+                       ret = regmap_read_poll_timeout(sdhci_am654->base,
+                                                      PHY_STAT1, val,
+                                                      val & CALDONE_MASK,
+                                                      1, 20);
+                       if (ret)
+                               return ret;
+               }
        }
 
        /* Enable pins by setting IO mux to 0 */
-       regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
-                          IOMUX_ENABLE_MASK, 0);
+       if (sdhci_am654->flags & IOMUX_PRESENT)
+               regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
+                                  IOMUX_ENABLE_MASK, 0);
 
        /* Set slot type based on SD or eMMC */
        if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
                ctl_cfg_2 = SLOTTYPE_EMBEDDED;
 
-       regmap_update_bits(sdhci_am654->base, CTL_CFG_2,
-                          SLOTTYPE_MASK, ctl_cfg_2);
+       regmap_update_bits(sdhci_am654->base, CTL_CFG_2, SLOTTYPE_MASK,
+                          ctl_cfg_2);
 
        return sdhci_add_host(host);
 }
@@ -243,51 +354,73 @@ static int sdhci_am654_get_of_property(struct platform_device *pdev,
        int drv_strength;
        int ret;
 
-       ret = device_property_read_u32(dev, "ti,trm-icp",
-                                      &sdhci_am654->trm_icp);
-       if (ret)
-               return ret;
-
        ret = device_property_read_u32(dev, "ti,otap-del-sel",
                                       &sdhci_am654->otap_del_sel);
        if (ret)
                return ret;
 
-       ret = device_property_read_u32(dev, "ti,driver-strength-ohm",
-                                      &drv_strength);
-       if (ret)
-               return ret;
+       if (sdhci_am654->flags & DLL_PRESENT) {
+               ret = device_property_read_u32(dev, "ti,trm-icp",
+                                              &sdhci_am654->trm_icp);
+               if (ret)
+                       return ret;
 
-       switch (drv_strength) {
-       case 50:
-               sdhci_am654->drv_strength = DRIVER_STRENGTH_50_OHM;
-               break;
-       case 33:
-               sdhci_am654->drv_strength = DRIVER_STRENGTH_33_OHM;
-               break;
-       case 66:
-               sdhci_am654->drv_strength = DRIVER_STRENGTH_66_OHM;
-               break;
-       case 100:
-               sdhci_am654->drv_strength = DRIVER_STRENGTH_100_OHM;
-               break;
-       case 40:
-               sdhci_am654->drv_strength = DRIVER_STRENGTH_40_OHM;
-               break;
-       default:
-               dev_err(dev, "Invalid driver strength\n");
-               return -EINVAL;
+               ret = device_property_read_u32(dev, "ti,driver-strength-ohm",
+                                              &drv_strength);
+               if (ret)
+                       return ret;
+
+               switch (drv_strength) {
+               case 50:
+                       sdhci_am654->drv_strength = DRIVER_STRENGTH_50_OHM;
+                       break;
+               case 33:
+                       sdhci_am654->drv_strength = DRIVER_STRENGTH_33_OHM;
+                       break;
+               case 66:
+                       sdhci_am654->drv_strength = DRIVER_STRENGTH_66_OHM;
+                       break;
+               case 100:
+                       sdhci_am654->drv_strength = DRIVER_STRENGTH_100_OHM;
+                       break;
+               case 40:
+                       sdhci_am654->drv_strength = DRIVER_STRENGTH_40_OHM;
+                       break;
+               default:
+                       dev_err(dev, "Invalid driver strength\n");
+                       return -EINVAL;
+               }
        }
 
+       device_property_read_u32(dev, "ti,strobe-sel", &sdhci_am654->strb_sel);
+
        sdhci_get_of_property(pdev);
 
        return 0;
 }
 
+static const struct of_device_id sdhci_am654_of_match[] = {
+       {
+               .compatible = "ti,am654-sdhci-5.1",
+               .data = &sdhci_am654_drvdata,
+       },
+       {
+               .compatible = "ti,j721e-sdhci-8bit",
+               .data = &sdhci_j721e_8bit_drvdata,
+       },
+       {
+               .compatible = "ti,j721e-sdhci-4bit",
+               .data = &sdhci_j721e_4bit_drvdata,
+       },
+       { /* sentinel */ }
+};
+
 static int sdhci_am654_probe(struct platform_device *pdev)
 {
+       const struct sdhci_am654_driver_data *drvdata;
        struct sdhci_pltfm_host *pltfm_host;
        struct sdhci_am654_data *sdhci_am654;
+       const struct of_device_id *match;
        struct sdhci_host *host;
        struct resource *res;
        struct clk *clk_xin;
@@ -295,12 +428,15 @@ static int sdhci_am654_probe(struct platform_device *pdev)
        void __iomem *base;
        int ret;
 
-       host = sdhci_pltfm_init(pdev, &sdhci_am654_pdata, sizeof(*sdhci_am654));
+       match = of_match_node(sdhci_am654_of_match, pdev->dev.of_node);
+       drvdata = match->data;
+       host = sdhci_pltfm_init(pdev, drvdata->pdata, sizeof(*sdhci_am654));
        if (IS_ERR(host))
                return PTR_ERR(host);
 
        pltfm_host = sdhci_priv(host);
        sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
+       sdhci_am654->flags = drvdata->flags;
 
        clk_xin = devm_clk_get(dev, "clk_xin");
        if (IS_ERR(clk_xin)) {
@@ -375,11 +511,6 @@ static int sdhci_am654_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct of_device_id sdhci_am654_of_match[] = {
-       { .compatible = "ti,am654-sdhci-5.1" },
-       { /* sentinel */ }
-};
-
 static struct platform_driver sdhci_am654_driver = {
        .driver = {
                .name = "sdhci-am654",
index 93e83ad..8539e10 100644 (file)
@@ -172,6 +172,8 @@ static int tmio_mmc_probe(struct platform_device *pdev)
        host->mmc->f_max = pdata->hclk;
        host->mmc->f_min = pdata->hclk / 512;
 
+       pm_runtime_enable(&pdev->dev);
+
        ret = tmio_mmc_host_probe(host);
        if (ret)
                goto host_free;
@@ -191,6 +193,7 @@ host_remove:
        tmio_mmc_host_remove(host);
 host_free:
        tmio_mmc_host_free(host);
+       pm_runtime_disable(&pdev->dev);
 cell_disable:
        if (cell->disable)
                cell->disable(pdev);
@@ -207,6 +210,8 @@ static int tmio_mmc_remove(struct platform_device *pdev)
        if (cell->disable)
                cell->disable(pdev);
 
+       pm_runtime_disable(&pdev->dev);
+
        return 0;
 }
 
index 84cb7d2..2cb3f95 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/dma-mapping.h>
 #include <linux/highmem.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -45,7 +46,6 @@
 #include <linux/scatterlist.h>
 #include <linux/sizes.h>
 #include <linux/spinlock.h>
-#include <linux/swiotlb.h>
 #include <linux/workqueue.h>
 
 #include "tmio_mmc.h"
@@ -1153,6 +1153,15 @@ void tmio_mmc_host_free(struct tmio_mmc_host *host)
 }
 EXPORT_SYMBOL_GPL(tmio_mmc_host_free);
 
+/**
+ * tmio_mmc_host_probe() - Common probe for all implementations
+ * @_host: Host to probe
+ *
+ * Perform tasks common to all implementations probe functions.
+ *
+ * The caller should have called pm_runtime_enable() prior to calling
+ * the common probe function.
+ */
 int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
 {
        struct platform_device *pdev = _host->pdev;
@@ -1190,19 +1199,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
        mmc->max_blk_size = TMIO_MAX_BLK_SIZE;
        mmc->max_blk_count = pdata->max_blk_count ? :
                (PAGE_SIZE / mmc->max_blk_size) * mmc->max_segs;
-       mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
-       /*
-        * Since swiotlb has memory size limitation, this will calculate
-        * the maximum size locally (because we don't have any APIs for it now)
-        * and check the current max_req_size. And then, this will update
-        * the max_req_size if needed as a workaround.
-        */
-       if (swiotlb_max_segment()) {
-               unsigned int max_size = (1 << IO_TLB_SHIFT) * IO_TLB_SEGSIZE;
-
-               if (mmc->max_req_size > max_size)
-                       mmc->max_req_size = max_size;
-       }
+       mmc->max_req_size = min_t(size_t,
+                                 mmc->max_blk_size * mmc->max_blk_count,
+                                 dma_max_mapping_size(&pdev->dev));
        mmc->max_seg_size = mmc->max_req_size;
 
        if (mmc_can_gpio_ro(mmc))
@@ -1261,7 +1260,6 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
        pm_runtime_set_active(&pdev->dev);
        pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
        pm_runtime_use_autosuspend(&pdev->dev);
-       pm_runtime_enable(&pdev->dev);
 
        ret = mmc_add_host(mmc);
        if (ret)
@@ -1297,7 +1295,6 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
 
        pm_runtime_dont_use_autosuspend(&pdev->dev);
        pm_runtime_put_sync(&pdev->dev);
-       pm_runtime_disable(&pdev->dev);
 }
 EXPORT_SYMBOL_GPL(tmio_mmc_host_remove);
 
index 91a2be4..49aad9a 100644 (file)
@@ -631,6 +631,7 @@ static int uniphier_sd_probe(struct platform_device *pdev)
        host->clk_disable = uniphier_sd_clk_disable;
        host->set_clock = uniphier_sd_set_clock;
 
+       pm_runtime_enable(&pdev->dev);
        ret = uniphier_sd_clk_enable(host);
        if (ret)
                goto free_host;
@@ -652,6 +653,7 @@ static int uniphier_sd_probe(struct platform_device *pdev)
 
 free_host:
        tmio_mmc_host_free(host);
+       pm_runtime_disable(&pdev->dev);
 
        return ret;
 }
@@ -662,6 +664,7 @@ static int uniphier_sd_remove(struct platform_device *pdev)
 
        tmio_mmc_host_remove(host);
        uniphier_sd_clk_disable(host);
+       pm_runtime_disable(&pdev->dev);
 
        return 0;
 }
index fb31a7f..80a6e2d 100644 (file)
@@ -274,4 +274,6 @@ source "drivers/mtd/spi-nor/Kconfig"
 
 source "drivers/mtd/ubi/Kconfig"
 
+source "drivers/mtd/hyperbus/Kconfig"
+
 endif # MTD
index 806287e..62d649a 100644 (file)
@@ -34,3 +34,4 @@ obj-y         += chips/ lpddr/ maps/ devices/ nand/ tests/
 
 obj-$(CONFIG_MTD_SPI_NOR)      += spi-nor/
 obj-$(CONFIG_MTD_UBI)          += ubi/
+obj-$(CONFIG_MTD_HYPERBUS)     += hyperbus/
index c8fa590..f4da7bd 100644 (file)
 #define SST49LF008A            0x005a
 #define AT49BV6416             0x00d6
 
+/*
+ * Status Register bit description. Used by flash devices that don't
+ * support DQ polling (e.g. HyperFlash)
+ */
+#define CFI_SR_DRB             BIT(7)
+#define CFI_SR_ESB             BIT(5)
+#define CFI_SR_PSB             BIT(4)
+#define CFI_SR_WBASB           BIT(3)
+#define CFI_SR_SLSB            BIT(1)
+
 static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
@@ -97,6 +107,50 @@ static struct mtd_chip_driver cfi_amdstd_chipdrv = {
        .module         = THIS_MODULE
 };
 
+/*
+ * Use status register to poll for Erase/write completion when DQ is not
+ * supported. This is indicated by Bit[1:0] of SoftwareFeatures field in
+ * CFI Primary Vendor-Specific Extended Query table 1.5
+ */
+static int cfi_use_status_reg(struct cfi_private *cfi)
+{
+       struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
+       u8 poll_mask = CFI_POLL_STATUS_REG | CFI_POLL_DQ;
+
+       return extp->MinorVersion >= '5' &&
+               (extp->SoftwareFeatures & poll_mask) == CFI_POLL_STATUS_REG;
+}
+
+static void cfi_check_err_status(struct map_info *map, struct flchip *chip,
+                                unsigned long adr)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+       map_word status;
+
+       if (!cfi_use_status_reg(cfi))
+               return;
+
+       cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi,
+                        cfi->device_type, NULL);
+       status = map_read(map, adr);
+
+       if (map_word_bitsset(map, status, CMD(0x3a))) {
+               unsigned long chipstatus = MERGESTATUS(status);
+
+               if (chipstatus & CFI_SR_ESB)
+                       pr_err("%s erase operation failed, status %lx\n",
+                              map->name, chipstatus);
+               if (chipstatus & CFI_SR_PSB)
+                       pr_err("%s program operation failed, status %lx\n",
+                              map->name, chipstatus);
+               if (chipstatus & CFI_SR_WBASB)
+                       pr_err("%s buffer program command aborted, status %lx\n",
+                              map->name, chipstatus);
+               if (chipstatus & CFI_SR_SLSB)
+                       pr_err("%s sector write protected, status %lx\n",
+                              map->name, chipstatus);
+       }
+}
 
 /* #define DEBUG_CFI_FEATURES */
 
@@ -742,10 +796,25 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)
  * correctly and is therefore not done (particularly with interleaved chips
  * as each chip must be checked independently of the others).
  */
-static int __xipram chip_ready(struct map_info *map, unsigned long addr)
+static int __xipram chip_ready(struct map_info *map, struct flchip *chip,
+                              unsigned long addr)
 {
+       struct cfi_private *cfi = map->fldrv_priv;
        map_word d, t;
 
+       if (cfi_use_status_reg(cfi)) {
+               map_word ready = CMD(CFI_SR_DRB);
+               /*
+                * For chips that support status register, check device
+                * ready bit
+                */
+               cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi,
+                                cfi->device_type, NULL);
+               d = map_read(map, addr);
+
+               return map_word_andequal(map, d, ready, ready);
+       }
+
        d = map_read(map, addr);
        t = map_read(map, addr);
 
@@ -767,10 +836,30 @@ static int __xipram chip_ready(struct map_info *map, unsigned long addr)
  * as each chip must be checked independently of the others).
  *
  */
-static int __xipram chip_good(struct map_info *map, unsigned long addr, map_word expected)
+static int __xipram chip_good(struct map_info *map, struct flchip *chip,
+                             unsigned long addr, map_word expected)
 {
+       struct cfi_private *cfi = map->fldrv_priv;
        map_word oldd, curd;
 
+       if (cfi_use_status_reg(cfi)) {
+               map_word ready = CMD(CFI_SR_DRB);
+               map_word err = CMD(CFI_SR_PSB | CFI_SR_ESB);
+               /*
+                * For chips that support status register, check device
+                * ready bit and Erase/Program status bit to know if
+                * operation succeeded.
+                */
+               cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi,
+                                cfi->device_type, NULL);
+               curd = map_read(map, addr);
+
+               if (map_word_andequal(map, curd, ready, ready))
+                       return !map_word_bitsset(map, curd, err);
+
+               return 0;
+       }
+
        oldd = map_read(map, addr);
        curd = map_read(map, addr);
 
@@ -792,7 +881,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
 
        case FL_STATUS:
                for (;;) {
-                       if (chip_ready(map, adr))
+                       if (chip_ready(map, chip, adr))
                                break;
 
                        if (time_after(jiffies, timeo)) {
@@ -830,7 +919,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                chip->state = FL_ERASE_SUSPENDING;
                chip->erase_suspended = 1;
                for (;;) {
-                       if (chip_ready(map, adr))
+                       if (chip_ready(map, chip, adr))
                                break;
 
                        if (time_after(jiffies, timeo)) {
@@ -1362,7 +1451,7 @@ static int do_otp_lock(struct map_info *map, struct flchip *chip, loff_t adr,
        /* wait for chip to become ready */
        timeo = jiffies + msecs_to_jiffies(2);
        for (;;) {
-               if (chip_ready(map, adr))
+               if (chip_ready(map, chip, adr))
                        break;
 
                if (time_after(jiffies, timeo)) {
@@ -1628,22 +1717,24 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
                        continue;
                }
 
-               if (time_after(jiffies, timeo) && !chip_ready(map, adr)){
+               if (time_after(jiffies, timeo) &&
+                   !chip_ready(map, chip, adr)) {
                        xip_enable(map, chip, adr);
                        printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
                        xip_disable(map, chip, adr);
                        break;
                }
 
-               if (chip_ready(map, adr))
+               if (chip_ready(map, chip, adr))
                        break;
 
                /* Latency issues. Drop the lock, wait a while and retry */
                UDELAY(map, chip, adr, 1);
        }
        /* Did we succeed? */
-       if (!chip_good(map, adr, datum)) {
+       if (!chip_good(map, chip, adr, datum)) {
                /* reset on all failures. */
+               cfi_check_err_status(map, chip, adr);
                map_write(map, CMD(0xF0), chip->start);
                /* FIXME - should have reset delay before continuing */
 
@@ -1881,10 +1972,11 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
                 * We check "time_after" and "!chip_good" before checking "chip_good" to avoid
                 * the failure due to scheduling.
                 */
-               if (time_after(jiffies, timeo) && !chip_good(map, adr, datum))
+               if (time_after(jiffies, timeo) &&
+                   !chip_good(map, chip, adr, datum))
                        break;
 
-               if (chip_good(map, adr, datum)) {
+               if (chip_good(map, chip, adr, datum)) {
                        xip_enable(map, chip, adr);
                        goto op_done;
                }
@@ -1901,6 +1993,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
         * See e.g.
         * http://www.spansion.com/Support/Application%20Notes/MirrorBit_Write_Buffer_Prog_Page_Buffer_Read_AN.pdf
         */
+       cfi_check_err_status(map, chip, adr);
        cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
                         cfi->device_type, NULL);
        cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
@@ -2018,7 +2111,7 @@ static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip,
         * If the driver thinks the chip is idle, and no toggle bits
         * are changing, then the chip is actually idle for sure.
         */
-       if (chip->state == FL_READY && chip_ready(map, adr))
+       if (chip->state == FL_READY && chip_ready(map, chip, adr))
                return 0;
 
        /*
@@ -2035,7 +2128,7 @@ static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip,
 
                /* wait for the chip to become ready */
                for (i = 0; i < jiffies_to_usecs(timeo); i++) {
-                       if (chip_ready(map, adr))
+                       if (chip_ready(map, chip, adr))
                                return 0;
 
                        udelay(1);
@@ -2099,14 +2192,15 @@ retry:
        map_write(map, datum, adr);
 
        for (i = 0; i < jiffies_to_usecs(uWriteTimeout); i++) {
-               if (chip_ready(map, adr))
+               if (chip_ready(map, chip, adr))
                        break;
 
                udelay(1);
        }
 
-       if (!chip_good(map, adr, datum)) {
+       if (!chip_good(map, chip, adr, datum)) {
                /* reset on all failures. */
+               cfi_check_err_status(map, chip, adr);
                map_write(map, CMD(0xF0), chip->start);
                /* FIXME - should have reset delay before continuing */
 
@@ -2300,7 +2394,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
                        chip->erase_suspended = 0;
                }
 
-               if (chip_good(map, adr, map_word_ff(map)))
+               if (chip_good(map, chip, adr, map_word_ff(map)))
                        break;
 
                if (time_after(jiffies, timeo)) {
@@ -2316,6 +2410,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
        /* Did we succeed? */
        if (ret) {
                /* reset on all failures. */
+               cfi_check_err_status(map, chip, adr);
                map_write(map, CMD(0xF0), chip->start);
                /* FIXME - should have reset delay before continuing */
 
@@ -2396,7 +2491,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
                        chip->erase_suspended = 0;
                }
 
-               if (chip_good(map, adr, map_word_ff(map)))
+               if (chip_good(map, chip, adr, map_word_ff(map)))
                        break;
 
                if (time_after(jiffies, timeo)) {
@@ -2412,6 +2507,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
        /* Did we succeed? */
        if (ret) {
                /* reset on all failures. */
+               cfi_check_err_status(map, chip, adr);
                map_write(map, CMD(0xF0), chip->start);
                /* FIXME - should have reset delay before continuing */
 
@@ -2533,8 +2629,6 @@ struct ppb_lock {
        int locked;
 };
 
-#define MAX_SECTORS                    512
-
 #define DO_XXLOCK_ONEBLOCK_LOCK                ((void *)1)
 #define DO_XXLOCK_ONEBLOCK_UNLOCK      ((void *)2)
 #define DO_XXLOCK_ONEBLOCK_GETLOCK     ((void *)3)
@@ -2589,7 +2683,7 @@ static int __maybe_unused do_ppb_xxlock(struct map_info *map,
         */
        timeo = jiffies + msecs_to_jiffies(2000);       /* 2s max (un)locking */
        for (;;) {
-               if (chip_ready(map, adr))
+               if (chip_ready(map, chip, adr))
                        break;
 
                if (time_after(jiffies, timeo)) {
@@ -2633,6 +2727,7 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs,
        int i;
        int sectors;
        int ret;
+       int max_sectors;
 
        /*
         * PPB unlocking always unlocks all sectors of the flash chip.
@@ -2640,7 +2735,11 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs,
         * first check the locking status of all sectors and save
         * it for future use.
         */
-       sect = kcalloc(MAX_SECTORS, sizeof(struct ppb_lock), GFP_KERNEL);
+       max_sectors = 0;
+       for (i = 0; i < mtd->numeraseregions; i++)
+               max_sectors += regions[i].numblocks;
+
+       sect = kcalloc(max_sectors, sizeof(struct ppb_lock), GFP_KERNEL);
        if (!sect)
                return -ENOMEM;
 
@@ -2689,9 +2788,9 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs,
                }
 
                sectors++;
-               if (sectors >= MAX_SECTORS) {
+               if (sectors >= max_sectors) {
                        printk(KERN_ERR "Only %d sectors for PPB locking supported!\n",
-                              MAX_SECTORS);
+                              max_sectors);
                        kfree(sect);
                        return -EINVAL;
                }
diff --git a/drivers/mtd/hyperbus/Kconfig b/drivers/mtd/hyperbus/Kconfig
new file mode 100644 (file)
index 0000000..cff6bbd
--- /dev/null
@@ -0,0 +1,23 @@
+menuconfig MTD_HYPERBUS
+       tristate "HyperBus support"
+       select MTD_CFI
+       select MTD_MAP_BANK_WIDTH_2
+       select MTD_CFI_AMDSTD
+       select MTD_COMPLEX_MAPPINGS
+       help
+         This is the framework for the HyperBus which can be used by
+         the HyperBus Controller driver to communicate with
+         HyperFlash. See Cypress HyperBus specification for more
+         details
+
+if MTD_HYPERBUS
+
+config HBMC_AM654
+       tristate "HyperBus controller driver for AM65x SoC"
+       select MULTIPLEXER
+       select MUX_MMIO
+       help
+        This is the driver for HyperBus controller on TI's AM65x and
+        other SoCs
+
+endif # MTD_HYPERBUS
diff --git a/drivers/mtd/hyperbus/Makefile b/drivers/mtd/hyperbus/Makefile
new file mode 100644 (file)
index 0000000..8a936e0
--- /dev/null
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_MTD_HYPERBUS)     += hyperbus-core.o
+obj-$(CONFIG_HBMC_AM654)       += hbmc-am654.o
diff --git a/drivers/mtd/hyperbus/hbmc-am654.c b/drivers/mtd/hyperbus/hbmc-am654.c
new file mode 100644 (file)
index 0000000..08d543b
--- /dev/null
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+// Author: Vignesh Raghavendra <vigneshr@ti.com>
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mtd/cfi.h>
+#include <linux/mtd/hyperbus.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mux/consumer.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/types.h>
+
+#define AM654_HBMC_CALIB_COUNT 25
+
+struct am654_hbmc_priv {
+       struct hyperbus_ctlr ctlr;
+       struct hyperbus_device hbdev;
+       struct mux_control *mux_ctrl;
+};
+
+static int am654_hbmc_calibrate(struct hyperbus_device *hbdev)
+{
+       struct map_info *map = &hbdev->map;
+       struct cfi_private cfi;
+       int count = AM654_HBMC_CALIB_COUNT;
+       int pass_count = 0;
+       int ret;
+
+       cfi.interleave = 1;
+       cfi.device_type = CFI_DEVICETYPE_X16;
+       cfi_send_gen_cmd(0xF0, 0, 0, map, &cfi, cfi.device_type, NULL);
+       cfi_send_gen_cmd(0x98, 0x55, 0, map, &cfi, cfi.device_type, NULL);
+
+       while (count--) {
+               ret = cfi_qry_present(map, 0, &cfi);
+               if (ret)
+                       pass_count++;
+               else
+                       pass_count = 0;
+               if (pass_count == 5)
+                       break;
+       }
+
+       cfi_qry_mode_off(0, map, &cfi);
+
+       return ret;
+}
+
+static const struct hyperbus_ops am654_hbmc_ops = {
+       .calibrate = am654_hbmc_calibrate,
+};
+
+static int am654_hbmc_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct am654_hbmc_priv *priv;
+       int ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, priv);
+
+       if (of_property_read_bool(dev->of_node, "mux-controls")) {
+               struct mux_control *control = devm_mux_control_get(dev, NULL);
+
+               if (IS_ERR(control))
+                       return PTR_ERR(control);
+
+               ret = mux_control_select(control, 1);
+               if (ret) {
+                       dev_err(dev, "Failed to select HBMC mux\n");
+                       return ret;
+               }
+               priv->mux_ctrl = control;
+       }
+
+       pm_runtime_enable(dev);
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0) {
+               pm_runtime_put_noidle(dev);
+               goto disable_pm;
+       }
+
+       priv->ctlr.dev = dev;
+       priv->ctlr.ops = &am654_hbmc_ops;
+       priv->hbdev.ctlr = &priv->ctlr;
+       priv->hbdev.np = of_get_next_child(dev->of_node, NULL);
+       ret = hyperbus_register_device(&priv->hbdev);
+       if (ret) {
+               dev_err(dev, "failed to register controller\n");
+               pm_runtime_put_sync(&pdev->dev);
+               goto disable_pm;
+       }
+
+       return 0;
+disable_pm:
+       pm_runtime_disable(dev);
+       if (priv->mux_ctrl)
+               mux_control_deselect(priv->mux_ctrl);
+       return ret;
+}
+
+static int am654_hbmc_remove(struct platform_device *pdev)
+{
+       struct am654_hbmc_priv *priv = platform_get_drvdata(pdev);
+       int ret;
+
+       ret = hyperbus_unregister_device(&priv->hbdev);
+       if (priv->mux_ctrl)
+               mux_control_deselect(priv->mux_ctrl);
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+
+       return ret;
+}
+
+static const struct of_device_id am654_hbmc_dt_ids[] = {
+       {
+               .compatible = "ti,am654-hbmc",
+       },
+       { /* end of table */ }
+};
+
+MODULE_DEVICE_TABLE(of, am654_hbmc_dt_ids);
+
+static struct platform_driver am654_hbmc_platform_driver = {
+       .probe = am654_hbmc_probe,
+       .remove = am654_hbmc_remove,
+       .driver = {
+               .name = "hbmc-am654",
+               .of_match_table = am654_hbmc_dt_ids,
+       },
+};
+
+module_platform_driver(am654_hbmc_platform_driver);
+
+MODULE_DESCRIPTION("HBMC driver for AM654 SoC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:hbmc-am654");
+MODULE_AUTHOR("Vignesh Raghavendra <vigneshr@ti.com>");
diff --git a/drivers/mtd/hyperbus/hyperbus-core.c b/drivers/mtd/hyperbus/hyperbus-core.c
new file mode 100644 (file)
index 0000000..6af9ea3
--- /dev/null
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+// Author: Vignesh Raghavendra <vigneshr@ti.com>
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mtd/hyperbus.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/mtd.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/types.h>
+
+static struct hyperbus_device *map_to_hbdev(struct map_info *map)
+{
+       return container_of(map, struct hyperbus_device, map);
+}
+
+static map_word hyperbus_read16(struct map_info *map, unsigned long addr)
+{
+       struct hyperbus_device *hbdev = map_to_hbdev(map);
+       struct hyperbus_ctlr *ctlr = hbdev->ctlr;
+       map_word read_data;
+
+       read_data.x[0] = ctlr->ops->read16(hbdev, addr);
+
+       return read_data;
+}
+
+static void hyperbus_write16(struct map_info *map, map_word d,
+                            unsigned long addr)
+{
+       struct hyperbus_device *hbdev = map_to_hbdev(map);
+       struct hyperbus_ctlr *ctlr = hbdev->ctlr;
+
+       ctlr->ops->write16(hbdev, addr, d.x[0]);
+}
+
+static void hyperbus_copy_from(struct map_info *map, void *to,
+                              unsigned long from, ssize_t len)
+{
+       struct hyperbus_device *hbdev = map_to_hbdev(map);
+       struct hyperbus_ctlr *ctlr = hbdev->ctlr;
+
+       ctlr->ops->copy_from(hbdev, to, from, len);
+}
+
+static void hyperbus_copy_to(struct map_info *map, unsigned long to,
+                            const void *from, ssize_t len)
+{
+       struct hyperbus_device *hbdev = map_to_hbdev(map);
+       struct hyperbus_ctlr *ctlr = hbdev->ctlr;
+
+       ctlr->ops->copy_to(hbdev, to, from, len);
+}
+
+int hyperbus_register_device(struct hyperbus_device *hbdev)
+{
+       const struct hyperbus_ops *ops;
+       struct hyperbus_ctlr *ctlr;
+       struct device_node *np;
+       struct map_info *map;
+       struct resource res;
+       struct device *dev;
+       int ret;
+
+       if (!hbdev || !hbdev->np || !hbdev->ctlr || !hbdev->ctlr->dev) {
+               pr_err("hyperbus: please fill all the necessary fields!\n");
+               return -EINVAL;
+       }
+
+       np = hbdev->np;
+       ctlr = hbdev->ctlr;
+       if (!of_device_is_compatible(np, "cypress,hyperflash"))
+               return -ENODEV;
+
+       hbdev->memtype = HYPERFLASH;
+
+       ret = of_address_to_resource(np, 0, &res);
+       if (ret)
+               return ret;
+
+       dev = ctlr->dev;
+       map = &hbdev->map;
+       map->size = resource_size(&res);
+       map->virt = devm_ioremap_resource(dev, &res);
+       if (IS_ERR(map->virt))
+               return PTR_ERR(map->virt);
+
+       map->name = dev_name(dev);
+       map->bankwidth = 2;
+       map->device_node = np;
+
+       simple_map_init(map);
+       ops = ctlr->ops;
+       if (ops) {
+               if (ops->read16)
+                       map->read = hyperbus_read16;
+               if (ops->write16)
+                       map->write = hyperbus_write16;
+               if (ops->copy_to)
+                       map->copy_to = hyperbus_copy_to;
+               if (ops->copy_from)
+                       map->copy_from = hyperbus_copy_from;
+
+               if (ops->calibrate && !ctlr->calibrated) {
+                       ret = ops->calibrate(hbdev);
+                       if (!ret) {
+                               dev_err(dev, "Calibration failed\n");
+                               return -ENODEV;
+                       }
+                       ctlr->calibrated = true;
+               }
+       }
+
+       hbdev->mtd = do_map_probe("cfi_probe", map);
+       if (!hbdev->mtd) {
+               dev_err(dev, "probing of hyperbus device failed\n");
+               return -ENODEV;
+       }
+
+       hbdev->mtd->dev.parent = dev;
+       mtd_set_of_node(hbdev->mtd, np);
+
+       ret = mtd_device_register(hbdev->mtd, NULL, 0);
+       if (ret) {
+               dev_err(dev, "failed to register mtd device\n");
+               map_destroy(hbdev->mtd);
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(hyperbus_register_device);
+
+int hyperbus_unregister_device(struct hyperbus_device *hbdev)
+{
+       int ret = 0;
+
+       if (hbdev && hbdev->mtd) {
+               ret = mtd_device_unregister(hbdev->mtd);
+               map_destroy(hbdev->mtd);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(hyperbus_unregister_device);
+
+MODULE_DESCRIPTION("HyperBus Framework");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Vignesh Raghavendra <vigneshr@ti.com>");
index 7324ff8..170a722 100644 (file)
@@ -437,7 +437,8 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
        return err;
 }
 
-static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+static int concat_xxlock(struct mtd_info *mtd, loff_t ofs, uint64_t len,
+                        bool is_lock)
 {
        struct mtd_concat *concat = CONCAT(mtd);
        int i, err = -EINVAL;
@@ -456,7 +457,10 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
                else
                        size = len;
 
-               err = mtd_lock(subdev, ofs, size);
+               if (is_lock)
+                       err = mtd_lock(subdev, ofs, size);
+               else
+                       err = mtd_unlock(subdev, ofs, size);
                if (err)
                        break;
 
@@ -471,35 +475,33 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
        return err;
 }
 
+static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+{
+       return concat_xxlock(mtd, ofs, len, true);
+}
+
 static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+{
+       return concat_xxlock(mtd, ofs, len, false);
+}
+
+static int concat_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 {
        struct mtd_concat *concat = CONCAT(mtd);
-       int i, err = 0;
+       int i, err = -EINVAL;
 
        for (i = 0; i < concat->num_subdev; i++) {
                struct mtd_info *subdev = concat->subdev[i];
-               uint64_t size;
 
                if (ofs >= subdev->size) {
-                       size = 0;
                        ofs -= subdev->size;
                        continue;
                }
-               if (ofs + len > subdev->size)
-                       size = subdev->size - ofs;
-               else
-                       size = len;
-
-               err = mtd_unlock(subdev, ofs, size);
-               if (err)
-                       break;
 
-               len -= size;
-               if (len == 0)
+               if (ofs + len > subdev->size)
                        break;
 
-               err = -EINVAL;
-               ofs = 0;
+               return mtd_is_locked(subdev, ofs, len);
        }
 
        return err;
@@ -704,6 +706,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],       /* subdevices to c
        concat->mtd._sync = concat_sync;
        concat->mtd._lock = concat_lock;
        concat->mtd._unlock = concat_unlock;
+       concat->mtd._is_locked = concat_is_locked;
        concat->mtd._suspend = concat_suspend;
        concat->mtd._resume = concat_resume;
 
index 453242d..408615f 100644 (file)
@@ -1124,6 +1124,9 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
                return -EROFS;
        if (!len)
                return 0;
+       if (!mtd->oops_panic_write)
+               mtd->oops_panic_write = true;
+
        return mtd->_panic_write(mtd, to, len, retlen, buf);
 }
 EXPORT_SYMBOL_GPL(mtd_panic_write);
index d759c02..a1f8fe1 100644 (file)
@@ -3257,6 +3257,8 @@ static void onenand_check_features(struct mtd_info *mtd)
 
        /* Lock scheme */
        switch (density) {
+       case ONENAND_DEVICE_DENSITY_8Gb:
+               this->options |= ONENAND_HAS_NOP_1;
        case ONENAND_DEVICE_DENSITY_4Gb:
                if (ONENAND_IS_DDP(this))
                        this->options |= ONENAND_HAS_2PLANE;
@@ -3277,12 +3279,15 @@ static void onenand_check_features(struct mtd_info *mtd)
                        if ((this->version_id & 0xf) == 0xe)
                                this->options |= ONENAND_HAS_NOP_1;
                }
+               this->options |= ONENAND_HAS_UNLOCK_ALL;
+               break;
 
        case ONENAND_DEVICE_DENSITY_2Gb:
                /* 2Gb DDP does not have 2 plane */
                if (!ONENAND_IS_DDP(this))
                        this->options |= ONENAND_HAS_2PLANE;
                this->options |= ONENAND_HAS_UNLOCK_ALL;
+               break;
 
        case ONENAND_DEVICE_DENSITY_1Gb:
                /* A-Die has all block unlock */
index 8735277..33310b8 100644 (file)
@@ -84,6 +84,12 @@ struct brcm_nand_dma_desc {
 #define FLASH_DMA_ECC_ERROR    (1 << 8)
 #define FLASH_DMA_CORR_ERROR   (1 << 9)
 
+/* Bitfields for DMA_MODE */
+#define FLASH_DMA_MODE_STOP_ON_ERROR   BIT(1) /* stop in Uncorr ECC error */
+#define FLASH_DMA_MODE_MODE            BIT(0) /* link list */
+#define FLASH_DMA_MODE_MASK            (FLASH_DMA_MODE_STOP_ON_ERROR | \
+                                               FLASH_DMA_MODE_MODE)
+
 /* 512B flash cache in the NAND controller HW */
 #define FC_SHIFT               9U
 #define FC_BYTES               512U
@@ -96,6 +102,51 @@ struct brcm_nand_dma_desc {
 #define NAND_CTRL_RDY                  (INTFC_CTLR_READY | INTFC_FLASH_READY)
 #define NAND_POLL_STATUS_TIMEOUT_MS    100
 
+/* flash_dma registers */
+enum flash_dma_reg {
+       FLASH_DMA_REVISION = 0,
+       FLASH_DMA_FIRST_DESC,
+       FLASH_DMA_FIRST_DESC_EXT,
+       FLASH_DMA_CTRL,
+       FLASH_DMA_MODE,
+       FLASH_DMA_STATUS,
+       FLASH_DMA_INTERRUPT_DESC,
+       FLASH_DMA_INTERRUPT_DESC_EXT,
+       FLASH_DMA_ERROR_STATUS,
+       FLASH_DMA_CURRENT_DESC,
+       FLASH_DMA_CURRENT_DESC_EXT,
+};
+
+/* flash_dma registers v1*/
+static const u16 flash_dma_regs_v1[] = {
+       [FLASH_DMA_REVISION]            = 0x00,
+       [FLASH_DMA_FIRST_DESC]          = 0x04,
+       [FLASH_DMA_FIRST_DESC_EXT]      = 0x08,
+       [FLASH_DMA_CTRL]                = 0x0c,
+       [FLASH_DMA_MODE]                = 0x10,
+       [FLASH_DMA_STATUS]              = 0x14,
+       [FLASH_DMA_INTERRUPT_DESC]      = 0x18,
+       [FLASH_DMA_INTERRUPT_DESC_EXT]  = 0x1c,
+       [FLASH_DMA_ERROR_STATUS]        = 0x20,
+       [FLASH_DMA_CURRENT_DESC]        = 0x24,
+       [FLASH_DMA_CURRENT_DESC_EXT]    = 0x28,
+};
+
+/* flash_dma registers v4 */
+static const u16 flash_dma_regs_v4[] = {
+       [FLASH_DMA_REVISION]            = 0x00,
+       [FLASH_DMA_FIRST_DESC]          = 0x08,
+       [FLASH_DMA_FIRST_DESC_EXT]      = 0x0c,
+       [FLASH_DMA_CTRL]                = 0x10,
+       [FLASH_DMA_MODE]                = 0x14,
+       [FLASH_DMA_STATUS]              = 0x18,
+       [FLASH_DMA_INTERRUPT_DESC]      = 0x20,
+       [FLASH_DMA_INTERRUPT_DESC_EXT]  = 0x24,
+       [FLASH_DMA_ERROR_STATUS]        = 0x28,
+       [FLASH_DMA_CURRENT_DESC]        = 0x30,
+       [FLASH_DMA_CURRENT_DESC_EXT]    = 0x34,
+};
+
 /* Controller feature flags */
 enum {
        BRCMNAND_HAS_1K_SECTORS                 = BIT(0),
@@ -128,6 +179,8 @@ struct brcmnand_controller {
        /* List of NAND hosts (one for each chip-select) */
        struct list_head host_list;
 
+       /* flash_dma reg */
+       const u16               *flash_dma_offsets;
        struct brcm_nand_dma_desc *dma_desc;
        dma_addr_t              dma_pa;
 
@@ -151,6 +204,7 @@ struct brcmnand_controller {
        u32                     nand_cs_nand_xor;
        u32                     corr_stat_threshold;
        u32                     flash_dma_mode;
+       bool                    pio_poll_mode;
 };
 
 struct brcmnand_cfg {
@@ -462,7 +516,7 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
        /* Register offsets */
        if (ctrl->nand_version >= 0x0702)
                ctrl->reg_offsets = brcmnand_regs_v72;
-       else if (ctrl->nand_version >= 0x0701)
+       else if (ctrl->nand_version == 0x0701)
                ctrl->reg_offsets = brcmnand_regs_v71;
        else if (ctrl->nand_version >= 0x0600)
                ctrl->reg_offsets = brcmnand_regs_v60;
@@ -507,7 +561,7 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
        }
 
        /* Maximum spare area sector size (per 512B) */
-       if (ctrl->nand_version >= 0x0702)
+       if (ctrl->nand_version == 0x0702)
                ctrl->max_oob = 128;
        else if (ctrl->nand_version >= 0x0600)
                ctrl->max_oob = 64;
@@ -538,6 +592,15 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
        return 0;
 }
 
+static void brcmnand_flash_dma_revision_init(struct brcmnand_controller *ctrl)
+{
+       /* flash_dma register offsets */
+       if (ctrl->nand_version >= 0x0703)
+               ctrl->flash_dma_offsets = flash_dma_regs_v4;
+       else
+               ctrl->flash_dma_offsets = flash_dma_regs_v1;
+}
+
 static inline u32 brcmnand_read_reg(struct brcmnand_controller *ctrl,
                enum brcmnand_reg reg)
 {
@@ -580,6 +643,54 @@ static inline void brcmnand_write_fc(struct brcmnand_controller *ctrl,
        __raw_writel(val, ctrl->nand_fc + word * 4);
 }
 
+static void brcmnand_clear_ecc_addr(struct brcmnand_controller *ctrl)
+{
+
+       /* Clear error addresses */
+       brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_ADDR, 0);
+       brcmnand_write_reg(ctrl, BRCMNAND_CORR_ADDR, 0);
+       brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_EXT_ADDR, 0);
+       brcmnand_write_reg(ctrl, BRCMNAND_CORR_EXT_ADDR, 0);
+}
+
+static u64 brcmnand_get_uncorrecc_addr(struct brcmnand_controller *ctrl)
+{
+       u64 err_addr;
+
+       err_addr = brcmnand_read_reg(ctrl, BRCMNAND_UNCORR_ADDR);
+       err_addr |= ((u64)(brcmnand_read_reg(ctrl,
+                                            BRCMNAND_UNCORR_EXT_ADDR)
+                                            & 0xffff) << 32);
+
+       return err_addr;
+}
+
+static u64 brcmnand_get_correcc_addr(struct brcmnand_controller *ctrl)
+{
+       u64 err_addr;
+
+       err_addr = brcmnand_read_reg(ctrl, BRCMNAND_CORR_ADDR);
+       err_addr |= ((u64)(brcmnand_read_reg(ctrl,
+                                            BRCMNAND_CORR_EXT_ADDR)
+                                            & 0xffff) << 32);
+
+       return err_addr;
+}
+
+static void brcmnand_set_cmd_addr(struct mtd_info *mtd, u64 addr)
+{
+       struct nand_chip *chip =  mtd_to_nand(mtd);
+       struct brcmnand_host *host = nand_get_controller_data(chip);
+       struct brcmnand_controller *ctrl = host->ctrl;
+
+       brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
+                          (host->cs << 16) | ((addr >> 32) & 0xffff));
+       (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
+       brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
+                          lower_32_bits(addr));
+       (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
+}
+
 static inline u16 brcmnand_cs_offset(struct brcmnand_controller *ctrl, int cs,
                                     enum brcmnand_cs_reg reg)
 {
@@ -612,7 +723,7 @@ static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val)
        enum brcmnand_reg reg = BRCMNAND_CORR_THRESHOLD;
        int cs = host->cs;
 
-       if (ctrl->nand_version >= 0x0702)
+       if (ctrl->nand_version == 0x0702)
                bits = 7;
        else if (ctrl->nand_version >= 0x0600)
                bits = 6;
@@ -666,7 +777,7 @@ enum {
 
 static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
 {
-       if (ctrl->nand_version >= 0x0702)
+       if (ctrl->nand_version == 0x0702)
                return GENMASK(7, 0);
        else if (ctrl->nand_version >= 0x0600)
                return GENMASK(6, 0);
@@ -796,39 +907,44 @@ static inline void brcmnand_set_wp(struct brcmnand_controller *ctrl, bool en)
  * Flash DMA
  ***********************************************************************/
 
-enum flash_dma_reg {
-       FLASH_DMA_REVISION              = 0x00,
-       FLASH_DMA_FIRST_DESC            = 0x04,
-       FLASH_DMA_FIRST_DESC_EXT        = 0x08,
-       FLASH_DMA_CTRL                  = 0x0c,
-       FLASH_DMA_MODE                  = 0x10,
-       FLASH_DMA_STATUS                = 0x14,
-       FLASH_DMA_INTERRUPT_DESC        = 0x18,
-       FLASH_DMA_INTERRUPT_DESC_EXT    = 0x1c,
-       FLASH_DMA_ERROR_STATUS          = 0x20,
-       FLASH_DMA_CURRENT_DESC          = 0x24,
-       FLASH_DMA_CURRENT_DESC_EXT      = 0x28,
-};
-
 static inline bool has_flash_dma(struct brcmnand_controller *ctrl)
 {
        return ctrl->flash_dma_base;
 }
 
+static inline void disable_ctrl_irqs(struct brcmnand_controller *ctrl)
+{
+       if (ctrl->pio_poll_mode)
+               return;
+
+       if (has_flash_dma(ctrl)) {
+               ctrl->flash_dma_base = 0;
+               disable_irq(ctrl->dma_irq);
+       }
+
+       disable_irq(ctrl->irq);
+       ctrl->pio_poll_mode = true;
+}
+
 static inline bool flash_dma_buf_ok(const void *buf)
 {
        return buf && !is_vmalloc_addr(buf) &&
                likely(IS_ALIGNED((uintptr_t)buf, 4));
 }
 
-static inline void flash_dma_writel(struct brcmnand_controller *ctrl, u8 offs,
-                                   u32 val)
+static inline void flash_dma_writel(struct brcmnand_controller *ctrl,
+                                   enum flash_dma_reg dma_reg, u32 val)
 {
+       u16 offs = ctrl->flash_dma_offsets[dma_reg];
+
        brcmnand_writel(val, ctrl->flash_dma_base + offs);
 }
 
-static inline u32 flash_dma_readl(struct brcmnand_controller *ctrl, u8 offs)
+static inline u32 flash_dma_readl(struct brcmnand_controller *ctrl,
+                                 enum flash_dma_reg dma_reg)
 {
+       u16 offs = ctrl->flash_dma_offsets[dma_reg];
+
        return brcmnand_readl(ctrl->flash_dma_base + offs);
 }
 
@@ -931,7 +1047,7 @@ static int brcmnand_bch_ooblayout_ecc(struct mtd_info *mtd, int section,
        if (section >= sectors)
                return -ERANGE;
 
-       oobregion->offset = (section * (sas + 1)) - chip->ecc.bytes;
+       oobregion->offset = ((section + 1) * sas) - chip->ecc.bytes;
        oobregion->length = chip->ecc.bytes;
 
        return 0;
@@ -1205,9 +1321,12 @@ static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd)
 {
        struct brcmnand_controller *ctrl = host->ctrl;
        int ret;
+       u64 cmd_addr;
+
+       cmd_addr = brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
+
+       dev_dbg(ctrl->dev, "send native cmd %d addr 0x%llx\n", cmd, cmd_addr);
 
-       dev_dbg(ctrl->dev, "send native cmd %d addr_lo 0x%x\n", cmd,
-               brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS));
        BUG_ON(ctrl->cmd_pending != 0);
        ctrl->cmd_pending = cmd;
 
@@ -1229,15 +1348,42 @@ static void brcmnand_cmd_ctrl(struct nand_chip *chip, int dat,
        /* intentionally left blank */
 }
 
+static bool brcmstb_nand_wait_for_completion(struct nand_chip *chip)
+{
+       struct brcmnand_host *host = nand_get_controller_data(chip);
+       struct brcmnand_controller *ctrl = host->ctrl;
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       bool err = false;
+       int sts;
+
+       if (mtd->oops_panic_write) {
+               /* switch to interrupt polling and PIO mode */
+               disable_ctrl_irqs(ctrl);
+               sts = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY,
+                                              NAND_CTRL_RDY, 0);
+               err = (sts < 0) ? true : false;
+       } else {
+               unsigned long timeo = msecs_to_jiffies(
+                                               NAND_POLL_STATUS_TIMEOUT_MS);
+               /* wait for completion interrupt */
+               sts = wait_for_completion_timeout(&ctrl->done, timeo);
+               err = (sts <= 0) ? true : false;
+       }
+
+       return err;
+}
+
 static int brcmnand_waitfunc(struct nand_chip *chip)
 {
        struct brcmnand_host *host = nand_get_controller_data(chip);
        struct brcmnand_controller *ctrl = host->ctrl;
-       unsigned long timeo = msecs_to_jiffies(100);
+       bool err = false;
 
        dev_dbg(ctrl->dev, "wait on native cmd %d\n", ctrl->cmd_pending);
-       if (ctrl->cmd_pending &&
-                       wait_for_completion_timeout(&ctrl->done, timeo) <= 0) {
+       if (ctrl->cmd_pending)
+               err = brcmstb_nand_wait_for_completion(chip);
+
+       if (err) {
                u32 cmd = brcmnand_read_reg(ctrl, BRCMNAND_CMD_START)
                                        >> brcmnand_cmd_shift(ctrl);
 
@@ -1366,12 +1512,7 @@ static void brcmnand_cmdfunc(struct nand_chip *chip, unsigned command,
        if (!native_cmd)
                return;
 
-       brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
-               (host->cs << 16) | ((addr >> 32) & 0xffff));
-       (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
-       brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS, lower_32_bits(addr));
-       (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
-
+       brcmnand_set_cmd_addr(mtd, addr);
        brcmnand_send_cmd(host, native_cmd);
        brcmnand_waitfunc(chip);
 
@@ -1589,20 +1730,10 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
        struct brcmnand_controller *ctrl = host->ctrl;
        int i, j, ret = 0;
 
-       /* Clear error addresses */
-       brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_ADDR, 0);
-       brcmnand_write_reg(ctrl, BRCMNAND_CORR_ADDR, 0);
-       brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_EXT_ADDR, 0);
-       brcmnand_write_reg(ctrl, BRCMNAND_CORR_EXT_ADDR, 0);
-
-       brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
-                       (host->cs << 16) | ((addr >> 32) & 0xffff));
-       (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
+       brcmnand_clear_ecc_addr(ctrl);
 
        for (i = 0; i < trans; i++, addr += FC_BYTES) {
-               brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
-                                  lower_32_bits(addr));
-               (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
+               brcmnand_set_cmd_addr(mtd, addr);
                /* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */
                brcmnand_send_cmd(host, CMD_PAGE_READ);
                brcmnand_waitfunc(chip);
@@ -1622,21 +1753,15 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
                                        host->hwcfg.sector_size_1k);
 
                if (!ret) {
-                       *err_addr = brcmnand_read_reg(ctrl,
-                                       BRCMNAND_UNCORR_ADDR) |
-                               ((u64)(brcmnand_read_reg(ctrl,
-                                               BRCMNAND_UNCORR_EXT_ADDR)
-                                       & 0xffff) << 32);
+                       *err_addr = brcmnand_get_uncorrecc_addr(ctrl);
+
                        if (*err_addr)
                                ret = -EBADMSG;
                }
 
                if (!ret) {
-                       *err_addr = brcmnand_read_reg(ctrl,
-                                       BRCMNAND_CORR_ADDR) |
-                               ((u64)(brcmnand_read_reg(ctrl,
-                                               BRCMNAND_CORR_EXT_ADDR)
-                                       & 0xffff) << 32);
+                       *err_addr = brcmnand_get_correcc_addr(ctrl);
+
                        if (*err_addr)
                                ret = -EUCLEAN;
                }
@@ -1703,7 +1828,7 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
        dev_dbg(ctrl->dev, "read %llx -> %p\n", (unsigned long long)addr, buf);
 
 try_dmaread:
-       brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_COUNT, 0);
+       brcmnand_clear_ecc_addr(ctrl);
 
        if (has_flash_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) {
                err = brcmnand_dma_trans(host, addr, buf, trans * FC_BYTES,
@@ -1850,15 +1975,9 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
                goto out;
        }
 
-       brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
-                       (host->cs << 16) | ((addr >> 32) & 0xffff));
-       (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
-
        for (i = 0; i < trans; i++, addr += FC_BYTES) {
                /* full address MUST be set before populating FC */
-               brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
-                                  lower_32_bits(addr));
-               (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
+               brcmnand_set_cmd_addr(mtd, addr);
 
                if (buf) {
                        brcmnand_soc_data_bus_prepare(ctrl->soc, false);
@@ -2136,6 +2255,17 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
                return -EINVAL;
        }
 
+       if (chip->ecc.mode != NAND_ECC_NONE &&
+           (!chip->ecc.size || !chip->ecc.strength)) {
+               if (chip->base.eccreq.step_size && chip->base.eccreq.strength) {
+                       /* use detected ECC parameters */
+                       chip->ecc.size = chip->base.eccreq.step_size;
+                       chip->ecc.strength = chip->base.eccreq.strength;
+                       dev_info(ctrl->dev, "Using ECC step-size %d, strength %d\n",
+                               chip->ecc.size, chip->ecc.strength);
+               }
+       }
+
        switch (chip->ecc.size) {
        case 512:
                if (chip->ecc.algo == NAND_ECC_HAMMING)
@@ -2395,6 +2525,7 @@ static const struct of_device_id brcmnand_of_match[] = {
        { .compatible = "brcm,brcmnand-v7.0" },
        { .compatible = "brcm,brcmnand-v7.1" },
        { .compatible = "brcm,brcmnand-v7.2" },
+       { .compatible = "brcm,brcmnand-v7.3" },
        {},
 };
 MODULE_DEVICE_TABLE(of, brcmnand_of_match);
@@ -2481,7 +2612,11 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
                        goto err;
                }
 
-               flash_dma_writel(ctrl, FLASH_DMA_MODE, 1); /* linked-list */
+               /* initialize the dma version */
+               brcmnand_flash_dma_revision_init(ctrl);
+
+               /* linked-list and stop on error */
+               flash_dma_writel(ctrl, FLASH_DMA_MODE, FLASH_DMA_MODE_MASK);
                flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0);
 
                /* Allocate descriptor(s) */
index 6c7ca41..a6964fe 100644 (file)
@@ -613,28 +613,20 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
        for (op_id = 0; op_id < op->ninstrs; op_id++) {
                instr = &op->instrs[op_id];
 
+               nand_op_trace("  ", instr);
+
                switch (instr->type) {
                case NAND_OP_CMD_INSTR:
-                       pr_debug("  ->CMD      [0x%02x]\n",
-                                instr->ctx.cmd.opcode);
-
                        writeb_relaxed(instr->ctx.cmd.opcode, host->cmd_va);
                        break;
 
                case NAND_OP_ADDR_INSTR:
-                       pr_debug("  ->ADDR     [%d cyc]",
-                                instr->ctx.addr.naddrs);
-
                        for (i = 0; i < instr->ctx.addr.naddrs; i++)
                                writeb_relaxed(instr->ctx.addr.addrs[i],
                                               host->addr_va);
                        break;
 
                case NAND_OP_DATA_IN_INSTR:
-                       pr_debug("  ->DATA_IN  [%d B%s]\n", instr->ctx.data.len,
-                                instr->ctx.data.force_8bit ?
-                                ", force 8-bit" : "");
-
                        if (host->mode == USE_DMA_ACCESS)
                                fsmc_read_buf_dma(host, instr->ctx.data.buf.in,
                                                  instr->ctx.data.len);
@@ -644,10 +636,6 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
                        break;
 
                case NAND_OP_DATA_OUT_INSTR:
-                       pr_debug("  ->DATA_OUT [%d B%s]\n", instr->ctx.data.len,
-                                instr->ctx.data.force_8bit ?
-                                ", force 8-bit" : "");
-
                        if (host->mode == USE_DMA_ACCESS)
                                fsmc_write_buf_dma(host,
                                                   instr->ctx.data.buf.out,
@@ -658,9 +646,6 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
                        break;
 
                case NAND_OP_WAITRDY_INSTR:
-                       pr_debug("  ->WAITRDY  [max %d ms]\n",
-                                instr->ctx.waitrdy.timeout_ms);
-
                        ret = nand_soft_waitrdy(chip,
                                                instr->ctx.waitrdy.timeout_ms);
                        break;
index 30ceee9..9bd81a3 100644 (file)
@@ -1,4 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi_nand.o
 gpmi_nand-objs += gpmi-nand.o
-gpmi_nand-objs += gpmi-lib.o
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
deleted file mode 100644 (file)
index a8b26d2..0000000
+++ /dev/null
@@ -1,934 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Freescale GPMI NAND Flash Driver
- *
- * Copyright (C) 2008-2011 Freescale Semiconductor, Inc.
- * Copyright (C) 2008 Embedded Alley Solutions, Inc.
- */
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/slab.h>
-
-#include "gpmi-nand.h"
-#include "gpmi-regs.h"
-#include "bch-regs.h"
-
-/* Converts time to clock cycles */
-#define TO_CYCLES(duration, period) DIV_ROUND_UP_ULL(duration, period)
-
-#define MXS_SET_ADDR           0x4
-#define MXS_CLR_ADDR           0x8
-/*
- * Clear the bit and poll it cleared.  This is usually called with
- * a reset address and mask being either SFTRST(bit 31) or CLKGATE
- * (bit 30).
- */
-static int clear_poll_bit(void __iomem *addr, u32 mask)
-{
-       int timeout = 0x400;
-
-       /* clear the bit */
-       writel(mask, addr + MXS_CLR_ADDR);
-
-       /*
-        * SFTRST needs 3 GPMI clocks to settle, the reference manual
-        * recommends to wait 1us.
-        */
-       udelay(1);
-
-       /* poll the bit becoming clear */
-       while ((readl(addr) & mask) && --timeout)
-               /* nothing */;
-
-       return !timeout;
-}
-
-#define MODULE_CLKGATE         (1 << 30)
-#define MODULE_SFTRST          (1 << 31)
-/*
- * The current mxs_reset_block() will do two things:
- *  [1] enable the module.
- *  [2] reset the module.
- *
- * In most of the cases, it's ok.
- * But in MX23, there is a hardware bug in the BCH block (see erratum #2847).
- * If you try to soft reset the BCH block, it becomes unusable until
- * the next hard reset. This case occurs in the NAND boot mode. When the board
- * boots by NAND, the ROM of the chip will initialize the BCH blocks itself.
- * So If the driver tries to reset the BCH again, the BCH will not work anymore.
- * You will see a DMA timeout in this case. The bug has been fixed
- * in the following chips, such as MX28.
- *
- * To avoid this bug, just add a new parameter `just_enable` for
- * the mxs_reset_block(), and rewrite it here.
- */
-static int gpmi_reset_block(void __iomem *reset_addr, bool just_enable)
-{
-       int ret;
-       int timeout = 0x400;
-
-       /* clear and poll SFTRST */
-       ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
-       if (unlikely(ret))
-               goto error;
-
-       /* clear CLKGATE */
-       writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR);
-
-       if (!just_enable) {
-               /* set SFTRST to reset the block */
-               writel(MODULE_SFTRST, reset_addr + MXS_SET_ADDR);
-               udelay(1);
-
-               /* poll CLKGATE becoming set */
-               while ((!(readl(reset_addr) & MODULE_CLKGATE)) && --timeout)
-                       /* nothing */;
-               if (unlikely(!timeout))
-                       goto error;
-       }
-
-       /* clear and poll SFTRST */
-       ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
-       if (unlikely(ret))
-               goto error;
-
-       /* clear and poll CLKGATE */
-       ret = clear_poll_bit(reset_addr, MODULE_CLKGATE);
-       if (unlikely(ret))
-               goto error;
-
-       return 0;
-
-error:
-       pr_err("%s(%p): module reset timeout\n", __func__, reset_addr);
-       return -ETIMEDOUT;
-}
-
-static int __gpmi_enable_clk(struct gpmi_nand_data *this, bool v)
-{
-       struct clk *clk;
-       int ret;
-       int i;
-
-       for (i = 0; i < GPMI_CLK_MAX; i++) {
-               clk = this->resources.clock[i];
-               if (!clk)
-                       break;
-
-               if (v) {
-                       ret = clk_prepare_enable(clk);
-                       if (ret)
-                               goto err_clk;
-               } else {
-                       clk_disable_unprepare(clk);
-               }
-       }
-       return 0;
-
-err_clk:
-       for (; i > 0; i--)
-               clk_disable_unprepare(this->resources.clock[i - 1]);
-       return ret;
-}
-
-int gpmi_enable_clk(struct gpmi_nand_data *this)
-{
-       return __gpmi_enable_clk(this, true);
-}
-
-int gpmi_disable_clk(struct gpmi_nand_data *this)
-{
-       return __gpmi_enable_clk(this, false);
-}
-
-int gpmi_init(struct gpmi_nand_data *this)
-{
-       struct resources *r = &this->resources;
-       int ret;
-
-       ret = gpmi_enable_clk(this);
-       if (ret)
-               return ret;
-       ret = gpmi_reset_block(r->gpmi_regs, false);
-       if (ret)
-               goto err_out;
-
-       /*
-        * Reset BCH here, too. We got failures otherwise :(
-        * See later BCH reset for explanation of MX23 and MX28 handling
-        */
-       ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MXS(this));
-       if (ret)
-               goto err_out;
-
-       /* Choose NAND mode. */
-       writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR);
-
-       /* Set the IRQ polarity. */
-       writel(BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY,
-                               r->gpmi_regs + HW_GPMI_CTRL1_SET);
-
-       /* Disable Write-Protection. */
-       writel(BM_GPMI_CTRL1_DEV_RESET, r->gpmi_regs + HW_GPMI_CTRL1_SET);
-
-       /* Select BCH ECC. */
-       writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET);
-
-       /*
-        * Decouple the chip select from dma channel. We use dma0 for all
-        * the chips.
-        */
-       writel(BM_GPMI_CTRL1_DECOUPLE_CS, r->gpmi_regs + HW_GPMI_CTRL1_SET);
-
-       gpmi_disable_clk(this);
-       return 0;
-err_out:
-       gpmi_disable_clk(this);
-       return ret;
-}
-
-/* This function is very useful. It is called only when the bug occur. */
-void gpmi_dump_info(struct gpmi_nand_data *this)
-{
-       struct resources *r = &this->resources;
-       struct bch_geometry *geo = &this->bch_geometry;
-       u32 reg;
-       int i;
-
-       dev_err(this->dev, "Show GPMI registers :\n");
-       for (i = 0; i <= HW_GPMI_DEBUG / 0x10 + 1; i++) {
-               reg = readl(r->gpmi_regs + i * 0x10);
-               dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
-       }
-
-       /* start to print out the BCH info */
-       dev_err(this->dev, "Show BCH registers :\n");
-       for (i = 0; i <= HW_BCH_VERSION / 0x10 + 1; i++) {
-               reg = readl(r->bch_regs + i * 0x10);
-               dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
-       }
-       dev_err(this->dev, "BCH Geometry :\n"
-               "GF length              : %u\n"
-               "ECC Strength           : %u\n"
-               "Page Size in Bytes     : %u\n"
-               "Metadata Size in Bytes : %u\n"
-               "ECC Chunk Size in Bytes: %u\n"
-               "ECC Chunk Count        : %u\n"
-               "Payload Size in Bytes  : %u\n"
-               "Auxiliary Size in Bytes: %u\n"
-               "Auxiliary Status Offset: %u\n"
-               "Block Mark Byte Offset : %u\n"
-               "Block Mark Bit Offset  : %u\n",
-               geo->gf_len,
-               geo->ecc_strength,
-               geo->page_size,
-               geo->metadata_size,
-               geo->ecc_chunk_size,
-               geo->ecc_chunk_count,
-               geo->payload_size,
-               geo->auxiliary_size,
-               geo->auxiliary_status_offset,
-               geo->block_mark_byte_offset,
-               geo->block_mark_bit_offset);
-}
-
-/* Configures the geometry for BCH.  */
-int bch_set_geometry(struct gpmi_nand_data *this)
-{
-       struct resources *r = &this->resources;
-       struct bch_geometry *bch_geo = &this->bch_geometry;
-       unsigned int block_count;
-       unsigned int block_size;
-       unsigned int metadata_size;
-       unsigned int ecc_strength;
-       unsigned int page_size;
-       unsigned int gf_len;
-       int ret;
-
-       ret = common_nfc_set_geometry(this);
-       if (ret)
-               return ret;
-
-       block_count   = bch_geo->ecc_chunk_count - 1;
-       block_size    = bch_geo->ecc_chunk_size;
-       metadata_size = bch_geo->metadata_size;
-       ecc_strength  = bch_geo->ecc_strength >> 1;
-       page_size     = bch_geo->page_size;
-       gf_len        = bch_geo->gf_len;
-
-       ret = gpmi_enable_clk(this);
-       if (ret)
-               return ret;
-
-       /*
-       * Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this
-       * chip, otherwise it will lock up. So we skip resetting BCH on the MX23.
-       * and MX28.
-       */
-       ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MXS(this));
-       if (ret)
-               goto err_out;
-
-       /* Configure layout 0. */
-       writel(BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count)
-                       | BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size)
-                       | BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength, this)
-                       | BF_BCH_FLASH0LAYOUT0_GF(gf_len, this)
-                       | BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size, this),
-                       r->bch_regs + HW_BCH_FLASH0LAYOUT0);
-
-       writel(BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size)
-                       | BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength, this)
-                       | BF_BCH_FLASH0LAYOUT1_GF(gf_len, this)
-                       | BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size, this),
-                       r->bch_regs + HW_BCH_FLASH0LAYOUT1);
-
-       /* Set *all* chip selects to use layout 0. */
-       writel(0, r->bch_regs + HW_BCH_LAYOUTSELECT);
-
-       /* Enable interrupts. */
-       writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
-                               r->bch_regs + HW_BCH_CTRL_SET);
-
-       gpmi_disable_clk(this);
-       return 0;
-err_out:
-       gpmi_disable_clk(this);
-       return ret;
-}
-
-/*
- * <1> Firstly, we should know what's the GPMI-clock means.
- *     The GPMI-clock is the internal clock in the gpmi nand controller.
- *     If you set 100MHz to gpmi nand controller, the GPMI-clock's period
- *     is 10ns. Mark the GPMI-clock's period as GPMI-clock-period.
- *
- * <2> Secondly, we should know what's the frequency on the nand chip pins.
- *     The frequency on the nand chip pins is derived from the GPMI-clock.
- *     We can get it from the following equation:
- *
- *         F = G / (DS + DH)
- *
- *         F  : the frequency on the nand chip pins.
- *         G  : the GPMI clock, such as 100MHz.
- *         DS : GPMI_HW_GPMI_TIMING0:DATA_SETUP
- *         DH : GPMI_HW_GPMI_TIMING0:DATA_HOLD
- *
- * <3> Thirdly, when the frequency on the nand chip pins is above 33MHz,
- *     the nand EDO(extended Data Out) timing could be applied.
- *     The GPMI implements a feedback read strobe to sample the read data.
- *     The feedback read strobe can be delayed to support the nand EDO timing
- *     where the read strobe may deasserts before the read data is valid, and
- *     read data is valid for some time after read strobe.
- *
- *     The following figure illustrates some aspects of a NAND Flash read:
- *
- *                   |<---tREA---->|
- *                   |             |
- *                   |         |   |
- *                   |<--tRP-->|   |
- *                   |         |   |
- *                  __          ___|__________________________________
- *     RDN            \________/   |
- *                                 |
- *                                 /---------\
- *     Read Data    --------------<           >---------
- *                                 \---------/
- *                                |     |
- *                                |<-D->|
- *     FeedbackRDN  ________             ____________
- *                          \___________/
- *
- *          D stands for delay, set in the HW_GPMI_CTRL1:RDN_DELAY.
- *
- *
- * <4> Now, we begin to describe how to compute the right RDN_DELAY.
- *
- *  4.1) From the aspect of the nand chip pins:
- *        Delay = (tREA + C - tRP)               {1}
- *
- *        tREA : the maximum read access time.
- *        C    : a constant to adjust the delay. default is 4000ps.
- *        tRP  : the read pulse width, which is exactly:
- *                   tRP = (GPMI-clock-period) * DATA_SETUP
- *
- *  4.2) From the aspect of the GPMI nand controller:
- *         Delay = RDN_DELAY * 0.125 * RP        {2}
- *
- *         RP   : the DLL reference period.
- *            if (GPMI-clock-period > DLL_THRETHOLD)
- *                   RP = GPMI-clock-period / 2;
- *            else
- *                   RP = GPMI-clock-period;
- *
- *            Set the HW_GPMI_CTRL1:HALF_PERIOD if GPMI-clock-period
- *            is greater DLL_THRETHOLD. In other SOCs, the DLL_THRETHOLD
- *            is 16000ps, but in mx6q, we use 12000ps.
- *
- *  4.3) since {1} equals {2}, we get:
- *
- *                     (tREA + 4000 - tRP) * 8
- *         RDN_DELAY = -----------------------     {3}
- *                           RP
- */
-static void gpmi_nfc_compute_timings(struct gpmi_nand_data *this,
-                                    const struct nand_sdr_timings *sdr)
-{
-       struct gpmi_nfc_hardware_timing *hw = &this->hw;
-       unsigned int dll_threshold_ps = this->devdata->max_chain_delay;
-       unsigned int period_ps, reference_period_ps;
-       unsigned int data_setup_cycles, data_hold_cycles, addr_setup_cycles;
-       unsigned int tRP_ps;
-       bool use_half_period;
-       int sample_delay_ps, sample_delay_factor;
-       u16 busy_timeout_cycles;
-       u8 wrn_dly_sel;
-
-       if (sdr->tRC_min >= 30000) {
-               /* ONFI non-EDO modes [0-3] */
-               hw->clk_rate = 22000000;
-               wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS;
-       } else if (sdr->tRC_min >= 25000) {
-               /* ONFI EDO mode 4 */
-               hw->clk_rate = 80000000;
-               wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
-       } else {
-               /* ONFI EDO mode 5 */
-               hw->clk_rate = 100000000;
-               wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
-       }
-
-       /* SDR core timings are given in picoseconds */
-       period_ps = div_u64((u64)NSEC_PER_SEC * 1000, hw->clk_rate);
-
-       addr_setup_cycles = TO_CYCLES(sdr->tALS_min, period_ps);
-       data_setup_cycles = TO_CYCLES(sdr->tDS_min, period_ps);
-       data_hold_cycles = TO_CYCLES(sdr->tDH_min, period_ps);
-       busy_timeout_cycles = TO_CYCLES(sdr->tWB_max + sdr->tR_max, period_ps);
-
-       hw->timing0 = BF_GPMI_TIMING0_ADDRESS_SETUP(addr_setup_cycles) |
-                     BF_GPMI_TIMING0_DATA_HOLD(data_hold_cycles) |
-                     BF_GPMI_TIMING0_DATA_SETUP(data_setup_cycles);
-       hw->timing1 = BF_GPMI_TIMING1_BUSY_TIMEOUT(busy_timeout_cycles * 4096);
-
-       /*
-        * Derive NFC ideal delay from {3}:
-        *
-        *                     (tREA + 4000 - tRP) * 8
-        *         RDN_DELAY = -----------------------
-        *                                RP
-        */
-       if (period_ps > dll_threshold_ps) {
-               use_half_period = true;
-               reference_period_ps = period_ps / 2;
-       } else {
-               use_half_period = false;
-               reference_period_ps = period_ps;
-       }
-
-       tRP_ps = data_setup_cycles * period_ps;
-       sample_delay_ps = (sdr->tREA_max + 4000 - tRP_ps) * 8;
-       if (sample_delay_ps > 0)
-               sample_delay_factor = sample_delay_ps / reference_period_ps;
-       else
-               sample_delay_factor = 0;
-
-       hw->ctrl1n = BF_GPMI_CTRL1_WRN_DLY_SEL(wrn_dly_sel);
-       if (sample_delay_factor)
-               hw->ctrl1n |= BF_GPMI_CTRL1_RDN_DELAY(sample_delay_factor) |
-                             BM_GPMI_CTRL1_DLL_ENABLE |
-                             (use_half_period ? BM_GPMI_CTRL1_HALF_PERIOD : 0);
-}
-
-void gpmi_nfc_apply_timings(struct gpmi_nand_data *this)
-{
-       struct gpmi_nfc_hardware_timing *hw = &this->hw;
-       struct resources *r = &this->resources;
-       void __iomem *gpmi_regs = r->gpmi_regs;
-       unsigned int dll_wait_time_us;
-
-       clk_set_rate(r->clock[0], hw->clk_rate);
-
-       writel(hw->timing0, gpmi_regs + HW_GPMI_TIMING0);
-       writel(hw->timing1, gpmi_regs + HW_GPMI_TIMING1);
-
-       /*
-        * Clear several CTRL1 fields, DLL must be disabled when setting
-        * RDN_DELAY or HALF_PERIOD.
-        */
-       writel(BM_GPMI_CTRL1_CLEAR_MASK, gpmi_regs + HW_GPMI_CTRL1_CLR);
-       writel(hw->ctrl1n, gpmi_regs + HW_GPMI_CTRL1_SET);
-
-       /* Wait 64 clock cycles before using the GPMI after enabling the DLL */
-       dll_wait_time_us = USEC_PER_SEC / hw->clk_rate * 64;
-       if (!dll_wait_time_us)
-               dll_wait_time_us = 1;
-
-       /* Wait for the DLL to settle. */
-       udelay(dll_wait_time_us);
-}
-
-int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr,
-                             const struct nand_data_interface *conf)
-{
-       struct gpmi_nand_data *this = nand_get_controller_data(chip);
-       const struct nand_sdr_timings *sdr;
-
-       /* Retrieve required NAND timings */
-       sdr = nand_get_sdr_timings(conf);
-       if (IS_ERR(sdr))
-               return PTR_ERR(sdr);
-
-       /* Only MX6 GPMI controller can reach EDO timings */
-       if (sdr->tRC_min <= 25000 && !GPMI_IS_MX6(this))
-               return -ENOTSUPP;
-
-       /* Stop here if this call was just a check */
-       if (chipnr < 0)
-               return 0;
-
-       /* Do the actual derivation of the controller timings */
-       gpmi_nfc_compute_timings(this, sdr);
-
-       this->hw.must_apply_timings = true;
-
-       return 0;
-}
-
-/* Clears a BCH interrupt. */
-void gpmi_clear_bch(struct gpmi_nand_data *this)
-{
-       struct resources *r = &this->resources;
-       writel(BM_BCH_CTRL_COMPLETE_IRQ, r->bch_regs + HW_BCH_CTRL_CLR);
-}
-
-/* Returns the Ready/Busy status of the given chip. */
-int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip)
-{
-       struct resources *r = &this->resources;
-       uint32_t mask = 0;
-       uint32_t reg = 0;
-
-       if (GPMI_IS_MX23(this)) {
-               mask = MX23_BM_GPMI_DEBUG_READY0 << chip;
-               reg = readl(r->gpmi_regs + HW_GPMI_DEBUG);
-       } else if (GPMI_IS_MX28(this) || GPMI_IS_MX6(this)) {
-               /*
-                * In the imx6, all the ready/busy pins are bound
-                * together. So we only need to check chip 0.
-                */
-               if (GPMI_IS_MX6(this))
-                       chip = 0;
-
-               /* MX28 shares the same R/B register as MX6Q. */
-               mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip);
-               reg = readl(r->gpmi_regs + HW_GPMI_STAT);
-       } else
-               dev_err(this->dev, "unknown arch.\n");
-       return reg & mask;
-}
-
-int gpmi_send_command(struct gpmi_nand_data *this)
-{
-       struct dma_chan *channel = get_dma_chan(this);
-       struct dma_async_tx_descriptor *desc;
-       struct scatterlist *sgl;
-       int chip = this->current_chip;
-       int ret;
-       u32 pio[3];
-
-       /* [1] send out the PIO words */
-       pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE)
-               | BM_GPMI_CTRL0_WORD_LENGTH
-               | BF_GPMI_CTRL0_CS(chip, this)
-               | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
-               | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_CLE)
-               | BM_GPMI_CTRL0_ADDRESS_INCREMENT
-               | BF_GPMI_CTRL0_XFER_COUNT(this->command_length);
-       pio[1] = pio[2] = 0;
-       desc = dmaengine_prep_slave_sg(channel,
-                                       (struct scatterlist *)pio,
-                                       ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
-       if (!desc)
-               return -EINVAL;
-
-       /* [2] send out the COMMAND + ADDRESS string stored in @buffer */
-       sgl = &this->cmd_sgl;
-
-       sg_init_one(sgl, this->cmd_buffer, this->command_length);
-       dma_map_sg(this->dev, sgl, 1, DMA_TO_DEVICE);
-       desc = dmaengine_prep_slave_sg(channel,
-                               sgl, 1, DMA_MEM_TO_DEV,
-                               DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc)
-               return -EINVAL;
-
-       /* [3] submit the DMA */
-       ret = start_dma_without_bch_irq(this, desc);
-
-       dma_unmap_sg(this->dev, sgl, 1, DMA_TO_DEVICE);
-
-       return ret;
-}
-
-int gpmi_send_data(struct gpmi_nand_data *this, const void *buf, int len)
-{
-       struct dma_async_tx_descriptor *desc;
-       struct dma_chan *channel = get_dma_chan(this);
-       int chip = this->current_chip;
-       int ret;
-       uint32_t command_mode;
-       uint32_t address;
-       u32 pio[2];
-
-       /* [1] PIO */
-       command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
-       address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
-
-       pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
-               | BM_GPMI_CTRL0_WORD_LENGTH
-               | BF_GPMI_CTRL0_CS(chip, this)
-               | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
-               | BF_GPMI_CTRL0_ADDRESS(address)
-               | BF_GPMI_CTRL0_XFER_COUNT(len);
-       pio[1] = 0;
-       desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio,
-                                       ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
-       if (!desc)
-               return -EINVAL;
-
-       /* [2] send DMA request */
-       prepare_data_dma(this, buf, len, DMA_TO_DEVICE);
-       desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
-                                       1, DMA_MEM_TO_DEV,
-                                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc)
-               return -EINVAL;
-
-       /* [3] submit the DMA */
-       ret = start_dma_without_bch_irq(this, desc);
-
-       dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_TO_DEVICE);
-
-       return ret;
-}
-
-int gpmi_read_data(struct gpmi_nand_data *this, void *buf, int len)
-{
-       struct dma_async_tx_descriptor *desc;
-       struct dma_chan *channel = get_dma_chan(this);
-       int chip = this->current_chip;
-       int ret;
-       u32 pio[2];
-       bool direct;
-
-       /* [1] : send PIO */
-       pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__READ)
-               | BM_GPMI_CTRL0_WORD_LENGTH
-               | BF_GPMI_CTRL0_CS(chip, this)
-               | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
-               | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA)
-               | BF_GPMI_CTRL0_XFER_COUNT(len);
-       pio[1] = 0;
-       desc = dmaengine_prep_slave_sg(channel,
-                                       (struct scatterlist *)pio,
-                                       ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
-       if (!desc)
-               return -EINVAL;
-
-       /* [2] : send DMA request */
-       direct = prepare_data_dma(this, buf, len, DMA_FROM_DEVICE);
-       desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
-                                       1, DMA_DEV_TO_MEM,
-                                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc)
-               return -EINVAL;
-
-       /* [3] : submit the DMA */
-
-       ret = start_dma_without_bch_irq(this, desc);
-
-       dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_FROM_DEVICE);
-       if (!direct)
-               memcpy(buf, this->data_buffer_dma, len);
-
-       return ret;
-}
-
-int gpmi_send_page(struct gpmi_nand_data *this,
-                       dma_addr_t payload, dma_addr_t auxiliary)
-{
-       struct bch_geometry *geo = &this->bch_geometry;
-       uint32_t command_mode;
-       uint32_t address;
-       uint32_t ecc_command;
-       uint32_t buffer_mask;
-       struct dma_async_tx_descriptor *desc;
-       struct dma_chan *channel = get_dma_chan(this);
-       int chip = this->current_chip;
-       u32 pio[6];
-
-       /* A DMA descriptor that does an ECC page read. */
-       command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
-       address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
-       ecc_command  = BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE;
-       buffer_mask  = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE |
-                               BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
-
-       pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
-               | BM_GPMI_CTRL0_WORD_LENGTH
-               | BF_GPMI_CTRL0_CS(chip, this)
-               | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
-               | BF_GPMI_CTRL0_ADDRESS(address)
-               | BF_GPMI_CTRL0_XFER_COUNT(0);
-       pio[1] = 0;
-       pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC
-               | BF_GPMI_ECCCTRL_ECC_CMD(ecc_command)
-               | BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask);
-       pio[3] = geo->page_size;
-       pio[4] = payload;
-       pio[5] = auxiliary;
-
-       desc = dmaengine_prep_slave_sg(channel,
-                                       (struct scatterlist *)pio,
-                                       ARRAY_SIZE(pio), DMA_TRANS_NONE,
-                                       DMA_CTRL_ACK);
-       if (!desc)
-               return -EINVAL;
-
-       return start_dma_with_bch_irq(this, desc);
-}
-
-int gpmi_read_page(struct gpmi_nand_data *this,
-                               dma_addr_t payload, dma_addr_t auxiliary)
-{
-       struct bch_geometry *geo = &this->bch_geometry;
-       uint32_t command_mode;
-       uint32_t address;
-       uint32_t ecc_command;
-       uint32_t buffer_mask;
-       struct dma_async_tx_descriptor *desc;
-       struct dma_chan *channel = get_dma_chan(this);
-       int chip = this->current_chip;
-       u32 pio[6];
-
-       /* [1] Wait for the chip to report ready. */
-       command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
-       address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
-
-       pio[0] =  BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
-               | BM_GPMI_CTRL0_WORD_LENGTH
-               | BF_GPMI_CTRL0_CS(chip, this)
-               | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
-               | BF_GPMI_CTRL0_ADDRESS(address)
-               | BF_GPMI_CTRL0_XFER_COUNT(0);
-       pio[1] = 0;
-       desc = dmaengine_prep_slave_sg(channel,
-                               (struct scatterlist *)pio, 2,
-                               DMA_TRANS_NONE, 0);
-       if (!desc)
-               return -EINVAL;
-
-       /* [2] Enable the BCH block and read. */
-       command_mode = BV_GPMI_CTRL0_COMMAND_MODE__READ;
-       address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
-       ecc_command  = BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE;
-       buffer_mask  = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE
-                       | BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
-
-       pio[0] =  BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
-               | BM_GPMI_CTRL0_WORD_LENGTH
-               | BF_GPMI_CTRL0_CS(chip, this)
-               | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
-               | BF_GPMI_CTRL0_ADDRESS(address)
-               | BF_GPMI_CTRL0_XFER_COUNT(geo->page_size);
-
-       pio[1] = 0;
-       pio[2] =  BM_GPMI_ECCCTRL_ENABLE_ECC
-               | BF_GPMI_ECCCTRL_ECC_CMD(ecc_command)
-               | BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask);
-       pio[3] = geo->page_size;
-       pio[4] = payload;
-       pio[5] = auxiliary;
-       desc = dmaengine_prep_slave_sg(channel,
-                                       (struct scatterlist *)pio,
-                                       ARRAY_SIZE(pio), DMA_TRANS_NONE,
-                                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc)
-               return -EINVAL;
-
-       /* [3] Disable the BCH block */
-       command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
-       address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
-
-       pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
-               | BM_GPMI_CTRL0_WORD_LENGTH
-               | BF_GPMI_CTRL0_CS(chip, this)
-               | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
-               | BF_GPMI_CTRL0_ADDRESS(address)
-               | BF_GPMI_CTRL0_XFER_COUNT(geo->page_size);
-       pio[1] = 0;
-       pio[2] = 0; /* clear GPMI_HW_GPMI_ECCCTRL, disable the BCH. */
-       desc = dmaengine_prep_slave_sg(channel,
-                               (struct scatterlist *)pio, 3,
-                               DMA_TRANS_NONE,
-                               DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc)
-               return -EINVAL;
-
-       /* [4] submit the DMA */
-       return start_dma_with_bch_irq(this, desc);
-}
-
-/**
- * gpmi_copy_bits - copy bits from one memory region to another
- * @dst: destination buffer
- * @dst_bit_off: bit offset we're starting to write at
- * @src: source buffer
- * @src_bit_off: bit offset we're starting to read from
- * @nbits: number of bits to copy
- *
- * This functions copies bits from one memory region to another, and is used by
- * the GPMI driver to copy ECC sections which are not guaranteed to be byte
- * aligned.
- *
- * src and dst should not overlap.
- *
- */
-void gpmi_copy_bits(u8 *dst, size_t dst_bit_off,
-                   const u8 *src, size_t src_bit_off,
-                   size_t nbits)
-{
-       size_t i;
-       size_t nbytes;
-       u32 src_buffer = 0;
-       size_t bits_in_src_buffer = 0;
-
-       if (!nbits)
-               return;
-
-       /*
-        * Move src and dst pointers to the closest byte pointer and store bit
-        * offsets within a byte.
-        */
-       src += src_bit_off / 8;
-       src_bit_off %= 8;
-
-       dst += dst_bit_off / 8;
-       dst_bit_off %= 8;
-
-       /*
-        * Initialize the src_buffer value with bits available in the first
-        * byte of data so that we end up with a byte aligned src pointer.
-        */
-       if (src_bit_off) {
-               src_buffer = src[0] >> src_bit_off;
-               if (nbits >= (8 - src_bit_off)) {
-                       bits_in_src_buffer += 8 - src_bit_off;
-               } else {
-                       src_buffer &= GENMASK(nbits - 1, 0);
-                       bits_in_src_buffer += nbits;
-               }
-               nbits -= bits_in_src_buffer;
-               src++;
-       }
-
-       /* Calculate the number of bytes that can be copied from src to dst. */
-       nbytes = nbits / 8;
-
-       /* Try to align dst to a byte boundary. */
-       if (dst_bit_off) {
-               if (bits_in_src_buffer < (8 - dst_bit_off) && nbytes) {
-                       src_buffer |= src[0] << bits_in_src_buffer;
-                       bits_in_src_buffer += 8;
-                       src++;
-                       nbytes--;
-               }
-
-               if (bits_in_src_buffer >= (8 - dst_bit_off)) {
-                       dst[0] &= GENMASK(dst_bit_off - 1, 0);
-                       dst[0] |= src_buffer << dst_bit_off;
-                       src_buffer >>= (8 - dst_bit_off);
-                       bits_in_src_buffer -= (8 - dst_bit_off);
-                       dst_bit_off = 0;
-                       dst++;
-                       if (bits_in_src_buffer > 7) {
-                               bits_in_src_buffer -= 8;
-                               dst[0] = src_buffer;
-                               dst++;
-                               src_buffer >>= 8;
-                       }
-               }
-       }
-
-       if (!bits_in_src_buffer && !dst_bit_off) {
-               /*
-                * Both src and dst pointers are byte aligned, thus we can
-                * just use the optimized memcpy function.
-                */
-               if (nbytes)
-                       memcpy(dst, src, nbytes);
-       } else {
-               /*
-                * src buffer is not byte aligned, hence we have to copy each
-                * src byte to the src_buffer variable before extracting a byte
-                * to store in dst.
-                */
-               for (i = 0; i < nbytes; i++) {
-                       src_buffer |= src[i] << bits_in_src_buffer;
-                       dst[i] = src_buffer;
-                       src_buffer >>= 8;
-               }
-       }
-       /* Update dst and src pointers */
-       dst += nbytes;
-       src += nbytes;
-
-       /*
-        * nbits is the number of remaining bits. It should not exceed 8 as
-        * we've already copied as much bytes as possible.
-        */
-       nbits %= 8;
-
-       /*
-        * If there's no more bits to copy to the destination and src buffer
-        * was already byte aligned, then we're done.
-        */
-       if (!nbits && !bits_in_src_buffer)
-               return;
-
-       /* Copy the remaining bits to src_buffer */
-       if (nbits)
-               src_buffer |= (*src & GENMASK(nbits - 1, 0)) <<
-                             bits_in_src_buffer;
-       bits_in_src_buffer += nbits;
-
-       /*
-        * In case there were not enough bits to get a byte aligned dst buffer
-        * prepare the src_buffer variable to match the dst organization (shift
-        * src_buffer by dst_bit_off and retrieve the least significant bits
-        * from dst).
-        */
-       if (dst_bit_off)
-               src_buffer = (src_buffer << dst_bit_off) |
-                            (*dst & GENMASK(dst_bit_off - 1, 0));
-       bits_in_src_buffer += dst_bit_off;
-
-       /*
-        * Keep most significant bits from dst if we end up with an unaligned
-        * number of bits.
-        */
-       nbytes = bits_in_src_buffer / 8;
-       if (bits_in_src_buffer % 8) {
-               src_buffer |= (dst[nbytes] &
-                              GENMASK(7, bits_in_src_buffer % 8)) <<
-                             (nbytes * 8);
-               nbytes++;
-       }
-
-       /* Copy the remaining bytes to dst */
-       for (i = 0; i < nbytes; i++) {
-               dst[i] = src_buffer;
-               src_buffer >>= 8;
-       }
-}
index 40df20d..334fe31 100644 (file)
@@ -6,6 +6,7 @@
  * Copyright (C) 2008 Embedded Alley Solutions, Inc.
  */
 #include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/sched/task_stack.h>
 #include <linux/interrupt.h>
 #include <linux/mtd/partitions.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/dma/mxs-dma.h>
 #include "gpmi-nand.h"
+#include "gpmi-regs.h"
 #include "bch-regs.h"
 
 /* Resource names for the GPMI NAND driver. */
 #define GPMI_NAND_BCH_REGS_ADDR_RES_NAME   "bch"
 #define GPMI_NAND_BCH_INTERRUPT_RES_NAME   "bch"
 
-/* add our owner bbt descriptor */
-static uint8_t scan_ff_pattern[] = { 0xff };
-static struct nand_bbt_descr gpmi_bbt_descr = {
-       .options        = 0,
-       .offs           = 0,
-       .len            = 1,
-       .pattern        = scan_ff_pattern
-};
+/* Converts time to clock cycles */
+#define TO_CYCLES(duration, period) DIV_ROUND_UP_ULL(duration, period)
 
+#define MXS_SET_ADDR           0x4
+#define MXS_CLR_ADDR           0x8
 /*
- * We may change the layout if we can get the ECC info from the datasheet,
- * else we will use all the (page + OOB).
+ * Clear the bit and poll it cleared.  This is usually called with
+ * a reset address and mask being either SFTRST(bit 31) or CLKGATE
+ * (bit 30).
  */
-static int gpmi_ooblayout_ecc(struct mtd_info *mtd, int section,
-                             struct mtd_oob_region *oobregion)
+static int clear_poll_bit(void __iomem *addr, u32 mask)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       struct gpmi_nand_data *this = nand_get_controller_data(chip);
-       struct bch_geometry *geo = &this->bch_geometry;
+       int timeout = 0x400;
 
-       if (section)
-               return -ERANGE;
+       /* clear the bit */
+       writel(mask, addr + MXS_CLR_ADDR);
 
-       oobregion->offset = 0;
-       oobregion->length = geo->page_size - mtd->writesize;
+       /*
+        * SFTRST needs 3 GPMI clocks to settle, the reference manual
+        * recommends to wait 1us.
+        */
+       udelay(1);
 
-       return 0;
+       /* poll the bit becoming clear */
+       while ((readl(addr) & mask) && --timeout)
+               /* nothing */;
+
+       return !timeout;
 }
 
-static int gpmi_ooblayout_free(struct mtd_info *mtd, int section,
-                              struct mtd_oob_region *oobregion)
+#define MODULE_CLKGATE         (1 << 30)
+#define MODULE_SFTRST          (1 << 31)
+/*
+ * The current mxs_reset_block() will do two things:
+ *  [1] enable the module.
+ *  [2] reset the module.
+ *
+ * In most of the cases, it's ok.
+ * But in MX23, there is a hardware bug in the BCH block (see erratum #2847).
+ * If you try to soft reset the BCH block, it becomes unusable until
+ * the next hard reset. This case occurs in the NAND boot mode. When the board
+ * boots by NAND, the ROM of the chip will initialize the BCH blocks itself.
+ * So If the driver tries to reset the BCH again, the BCH will not work anymore.
+ * You will see a DMA timeout in this case. The bug has been fixed
+ * in the following chips, such as MX28.
+ *
+ * To avoid this bug, just add a new parameter `just_enable` for
+ * the mxs_reset_block(), and rewrite it here.
+ */
+static int gpmi_reset_block(void __iomem *reset_addr, bool just_enable)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       struct gpmi_nand_data *this = nand_get_controller_data(chip);
-       struct bch_geometry *geo = &this->bch_geometry;
+       int ret;
+       int timeout = 0x400;
+
+       /* clear and poll SFTRST */
+       ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
+       if (unlikely(ret))
+               goto error;
+
+       /* clear CLKGATE */
+       writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR);
+
+       if (!just_enable) {
+               /* set SFTRST to reset the block */
+               writel(MODULE_SFTRST, reset_addr + MXS_SET_ADDR);
+               udelay(1);
+
+               /* poll CLKGATE becoming set */
+               while ((!(readl(reset_addr) & MODULE_CLKGATE)) && --timeout)
+                       /* nothing */;
+               if (unlikely(!timeout))
+                       goto error;
+       }
 
-       if (section)
-               return -ERANGE;
+       /* clear and poll SFTRST */
+       ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
+       if (unlikely(ret))
+               goto error;
 
-       /* The available oob size we have. */
-       if (geo->page_size < mtd->writesize + mtd->oobsize) {
-               oobregion->offset = geo->page_size - mtd->writesize;
-               oobregion->length = mtd->oobsize - oobregion->offset;
-       }
+       /* clear and poll CLKGATE */
+       ret = clear_poll_bit(reset_addr, MODULE_CLKGATE);
+       if (unlikely(ret))
+               goto error;
 
        return 0;
+
+error:
+       pr_err("%s(%p): module reset timeout\n", __func__, reset_addr);
+       return -ETIMEDOUT;
 }
 
-static const char * const gpmi_clks_for_mx2x[] = {
-       "gpmi_io",
-};
+static int __gpmi_enable_clk(struct gpmi_nand_data *this, bool v)
+{
+       struct clk *clk;
+       int ret;
+       int i;
 
-static const struct mtd_ooblayout_ops gpmi_ooblayout_ops = {
-       .ecc = gpmi_ooblayout_ecc,
-       .free = gpmi_ooblayout_free,
-};
+       for (i = 0; i < GPMI_CLK_MAX; i++) {
+               clk = this->resources.clock[i];
+               if (!clk)
+                       break;
 
-static const struct gpmi_devdata gpmi_devdata_imx23 = {
-       .type = IS_MX23,
-       .bch_max_ecc_strength = 20,
-       .max_chain_delay = 16000,
-       .clks = gpmi_clks_for_mx2x,
-       .clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
-};
+               if (v) {
+                       ret = clk_prepare_enable(clk);
+                       if (ret)
+                               goto err_clk;
+               } else {
+                       clk_disable_unprepare(clk);
+               }
+       }
+       return 0;
 
-static const struct gpmi_devdata gpmi_devdata_imx28 = {
-       .type = IS_MX28,
-       .bch_max_ecc_strength = 20,
-       .max_chain_delay = 16000,
-       .clks = gpmi_clks_for_mx2x,
-       .clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
-};
+err_clk:
+       for (; i > 0; i--)
+               clk_disable_unprepare(this->resources.clock[i - 1]);
+       return ret;
+}
 
-static const char * const gpmi_clks_for_mx6[] = {
-       "gpmi_io", "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch",
-};
+static int gpmi_init(struct gpmi_nand_data *this)
+{
+       struct resources *r = &this->resources;
+       int ret;
 
-static const struct gpmi_devdata gpmi_devdata_imx6q = {
-       .type = IS_MX6Q,
-       .bch_max_ecc_strength = 40,
-       .max_chain_delay = 12000,
-       .clks = gpmi_clks_for_mx6,
-       .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
-};
+       ret = gpmi_reset_block(r->gpmi_regs, false);
+       if (ret)
+               goto err_out;
 
-static const struct gpmi_devdata gpmi_devdata_imx6sx = {
-       .type = IS_MX6SX,
-       .bch_max_ecc_strength = 62,
-       .max_chain_delay = 12000,
-       .clks = gpmi_clks_for_mx6,
-       .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
-};
+       /*
+        * Reset BCH here, too. We got failures otherwise :(
+        * See later BCH reset for explanation of MX23 and MX28 handling
+        */
+       ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MXS(this));
+       if (ret)
+               goto err_out;
 
-static const char * const gpmi_clks_for_mx7d[] = {
-       "gpmi_io", "gpmi_bch_apb",
-};
+       /* Choose NAND mode. */
+       writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR);
 
-static const struct gpmi_devdata gpmi_devdata_imx7d = {
-       .type = IS_MX7D,
-       .bch_max_ecc_strength = 62,
-       .max_chain_delay = 12000,
-       .clks = gpmi_clks_for_mx7d,
-       .clks_count = ARRAY_SIZE(gpmi_clks_for_mx7d),
-};
+       /* Set the IRQ polarity. */
+       writel(BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY,
+                               r->gpmi_regs + HW_GPMI_CTRL1_SET);
 
-static irqreturn_t bch_irq(int irq, void *cookie)
-{
-       struct gpmi_nand_data *this = cookie;
+       /* Disable Write-Protection. */
+       writel(BM_GPMI_CTRL1_DEV_RESET, r->gpmi_regs + HW_GPMI_CTRL1_SET);
 
-       gpmi_clear_bch(this);
-       complete(&this->bch_done);
-       return IRQ_HANDLED;
+       /* Select BCH ECC. */
+       writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET);
+
+       /*
+        * Decouple the chip select from dma channel. We use dma0 for all
+        * the chips.
+        */
+       writel(BM_GPMI_CTRL1_DECOUPLE_CS, r->gpmi_regs + HW_GPMI_CTRL1_SET);
+
+       return 0;
+err_out:
+       return ret;
 }
 
-/*
- *  Calculate the ECC strength by hand:
- *     E : The ECC strength.
- *     G : the length of Galois Field.
- *     N : The chunk count of per page.
- *     O : the oobsize of the NAND chip.
- *     M : the metasize of per page.
- *
- *     The formula is :
- *             E * G * N
- *           ------------ <= (O - M)
- *                  8
- *
- *      So, we get E by:
- *                    (O - M) * 8
- *              E <= -------------
- *                       G * N
- */
-static inline int get_ecc_strength(struct gpmi_nand_data *this)
+/* This function is very useful. It is called only when the bug occur. */
+static void gpmi_dump_info(struct gpmi_nand_data *this)
 {
+       struct resources *r = &this->resources;
        struct bch_geometry *geo = &this->bch_geometry;
-       struct mtd_info *mtd = nand_to_mtd(&this->nand);
-       int ecc_strength;
+       u32 reg;
+       int i;
 
-       ecc_strength = ((mtd->oobsize - geo->metadata_size) * 8)
-                       / (geo->gf_len * geo->ecc_chunk_count);
+       dev_err(this->dev, "Show GPMI registers :\n");
+       for (i = 0; i <= HW_GPMI_DEBUG / 0x10 + 1; i++) {
+               reg = readl(r->gpmi_regs + i * 0x10);
+               dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
+       }
 
-       /* We need the minor even number. */
-       return round_down(ecc_strength, 2);
+       /* start to print out the BCH info */
+       dev_err(this->dev, "Show BCH registers :\n");
+       for (i = 0; i <= HW_BCH_VERSION / 0x10 + 1; i++) {
+               reg = readl(r->bch_regs + i * 0x10);
+               dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
+       }
+       dev_err(this->dev, "BCH Geometry :\n"
+               "GF length              : %u\n"
+               "ECC Strength           : %u\n"
+               "Page Size in Bytes     : %u\n"
+               "Metadata Size in Bytes : %u\n"
+               "ECC Chunk Size in Bytes: %u\n"
+               "ECC Chunk Count        : %u\n"
+               "Payload Size in Bytes  : %u\n"
+               "Auxiliary Size in Bytes: %u\n"
+               "Auxiliary Status Offset: %u\n"
+               "Block Mark Byte Offset : %u\n"
+               "Block Mark Bit Offset  : %u\n",
+               geo->gf_len,
+               geo->ecc_strength,
+               geo->page_size,
+               geo->metadata_size,
+               geo->ecc_chunk_size,
+               geo->ecc_chunk_count,
+               geo->payload_size,
+               geo->auxiliary_size,
+               geo->auxiliary_status_offset,
+               geo->block_mark_byte_offset,
+               geo->block_mark_bit_offset);
 }
 
 static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
@@ -296,6 +359,37 @@ static int set_geometry_by_ecc_info(struct gpmi_nand_data *this,
        return 0;
 }
 
+/*
+ *  Calculate the ECC strength by hand:
+ *     E : The ECC strength.
+ *     G : the length of Galois Field.
+ *     N : The chunk count of per page.
+ *     O : the oobsize of the NAND chip.
+ *     M : the metasize of per page.
+ *
+ *     The formula is :
+ *             E * G * N
+ *           ------------ <= (O - M)
+ *                  8
+ *
+ *      So, we get E by:
+ *                    (O - M) * 8
+ *              E <= -------------
+ *                       G * N
+ */
+static inline int get_ecc_strength(struct gpmi_nand_data *this)
+{
+       struct bch_geometry *geo = &this->bch_geometry;
+       struct mtd_info *mtd = nand_to_mtd(&this->nand);
+       int ecc_strength;
+
+       ecc_strength = ((mtd->oobsize - geo->metadata_size) * 8)
+                       / (geo->gf_len * geo->ecc_chunk_count);
+
+       /* We need the minor even number. */
+       return round_down(ecc_strength, 2);
+}
+
 static int legacy_set_geometry(struct gpmi_nand_data *this)
 {
        struct bch_geometry *geo = &this->bch_geometry;
@@ -408,7 +502,7 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
        return 0;
 }
 
-int common_nfc_set_geometry(struct gpmi_nand_data *this)
+static int common_nfc_set_geometry(struct gpmi_nand_data *this)
 {
        struct nand_chip *chip = &this->nand;
 
@@ -430,18 +524,288 @@ int common_nfc_set_geometry(struct gpmi_nand_data *this)
        return 0;
 }
 
-struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
+/* Configures the geometry for BCH.  */
+static int bch_set_geometry(struct gpmi_nand_data *this)
+{
+       struct resources *r = &this->resources;
+       int ret;
+
+       ret = common_nfc_set_geometry(this);
+       if (ret)
+               return ret;
+
+       ret = pm_runtime_get_sync(this->dev);
+       if (ret < 0)
+               return ret;
+
+       /*
+       * Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this
+       * chip, otherwise it will lock up. So we skip resetting BCH on the MX23.
+       * and MX28.
+       */
+       ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MXS(this));
+       if (ret)
+               goto err_out;
+
+       /* Set *all* chip selects to use layout 0. */
+       writel(0, r->bch_regs + HW_BCH_LAYOUTSELECT);
+
+       ret = 0;
+err_out:
+       pm_runtime_mark_last_busy(this->dev);
+       pm_runtime_put_autosuspend(this->dev);
+
+       return ret;
+}
+
+/*
+ * <1> Firstly, we should know what's the GPMI-clock means.
+ *     The GPMI-clock is the internal clock in the gpmi nand controller.
+ *     If you set 100MHz to gpmi nand controller, the GPMI-clock's period
+ *     is 10ns. Mark the GPMI-clock's period as GPMI-clock-period.
+ *
+ * <2> Secondly, we should know what's the frequency on the nand chip pins.
+ *     The frequency on the nand chip pins is derived from the GPMI-clock.
+ *     We can get it from the following equation:
+ *
+ *         F = G / (DS + DH)
+ *
+ *         F  : the frequency on the nand chip pins.
+ *         G  : the GPMI clock, such as 100MHz.
+ *         DS : GPMI_HW_GPMI_TIMING0:DATA_SETUP
+ *         DH : GPMI_HW_GPMI_TIMING0:DATA_HOLD
+ *
+ * <3> Thirdly, when the frequency on the nand chip pins is above 33MHz,
+ *     the nand EDO(extended Data Out) timing could be applied.
+ *     The GPMI implements a feedback read strobe to sample the read data.
+ *     The feedback read strobe can be delayed to support the nand EDO timing
+ *     where the read strobe may deasserts before the read data is valid, and
+ *     read data is valid for some time after read strobe.
+ *
+ *     The following figure illustrates some aspects of a NAND Flash read:
+ *
+ *                   |<---tREA---->|
+ *                   |             |
+ *                   |         |   |
+ *                   |<--tRP-->|   |
+ *                   |         |   |
+ *                  __          ___|__________________________________
+ *     RDN            \________/   |
+ *                                 |
+ *                                 /---------\
+ *     Read Data    --------------<           >---------
+ *                                 \---------/
+ *                                |     |
+ *                                |<-D->|
+ *     FeedbackRDN  ________             ____________
+ *                          \___________/
+ *
+ *          D stands for delay, set in the HW_GPMI_CTRL1:RDN_DELAY.
+ *
+ *
+ * <4> Now, we begin to describe how to compute the right RDN_DELAY.
+ *
+ *  4.1) From the aspect of the nand chip pins:
+ *        Delay = (tREA + C - tRP)               {1}
+ *
+ *        tREA : the maximum read access time.
+ *        C    : a constant to adjust the delay. default is 4000ps.
+ *        tRP  : the read pulse width, which is exactly:
+ *                   tRP = (GPMI-clock-period) * DATA_SETUP
+ *
+ *  4.2) From the aspect of the GPMI nand controller:
+ *         Delay = RDN_DELAY * 0.125 * RP        {2}
+ *
+ *         RP   : the DLL reference period.
+ *            if (GPMI-clock-period > DLL_THRETHOLD)
+ *                   RP = GPMI-clock-period / 2;
+ *            else
+ *                   RP = GPMI-clock-period;
+ *
+ *            Set the HW_GPMI_CTRL1:HALF_PERIOD if GPMI-clock-period
+ *            is greater DLL_THRETHOLD. In other SOCs, the DLL_THRETHOLD
+ *            is 16000ps, but in mx6q, we use 12000ps.
+ *
+ *  4.3) since {1} equals {2}, we get:
+ *
+ *                     (tREA + 4000 - tRP) * 8
+ *         RDN_DELAY = -----------------------     {3}
+ *                           RP
+ */
+static void gpmi_nfc_compute_timings(struct gpmi_nand_data *this,
+                                    const struct nand_sdr_timings *sdr)
+{
+       struct gpmi_nfc_hardware_timing *hw = &this->hw;
+       unsigned int dll_threshold_ps = this->devdata->max_chain_delay;
+       unsigned int period_ps, reference_period_ps;
+       unsigned int data_setup_cycles, data_hold_cycles, addr_setup_cycles;
+       unsigned int tRP_ps;
+       bool use_half_period;
+       int sample_delay_ps, sample_delay_factor;
+       u16 busy_timeout_cycles;
+       u8 wrn_dly_sel;
+
+       if (sdr->tRC_min >= 30000) {
+               /* ONFI non-EDO modes [0-3] */
+               hw->clk_rate = 22000000;
+               wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS;
+       } else if (sdr->tRC_min >= 25000) {
+               /* ONFI EDO mode 4 */
+               hw->clk_rate = 80000000;
+               wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
+       } else {
+               /* ONFI EDO mode 5 */
+               hw->clk_rate = 100000000;
+               wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
+       }
+
+       /* SDR core timings are given in picoseconds */
+       period_ps = div_u64((u64)NSEC_PER_SEC * 1000, hw->clk_rate);
+
+       addr_setup_cycles = TO_CYCLES(sdr->tALS_min, period_ps);
+       data_setup_cycles = TO_CYCLES(sdr->tDS_min, period_ps);
+       data_hold_cycles = TO_CYCLES(sdr->tDH_min, period_ps);
+       busy_timeout_cycles = TO_CYCLES(sdr->tWB_max + sdr->tR_max, period_ps);
+
+       hw->timing0 = BF_GPMI_TIMING0_ADDRESS_SETUP(addr_setup_cycles) |
+                     BF_GPMI_TIMING0_DATA_HOLD(data_hold_cycles) |
+                     BF_GPMI_TIMING0_DATA_SETUP(data_setup_cycles);
+       hw->timing1 = BF_GPMI_TIMING1_BUSY_TIMEOUT(busy_timeout_cycles * 4096);
+
+       /*
+        * Derive NFC ideal delay from {3}:
+        *
+        *                     (tREA + 4000 - tRP) * 8
+        *         RDN_DELAY = -----------------------
+        *                                RP
+        */
+       if (period_ps > dll_threshold_ps) {
+               use_half_period = true;
+               reference_period_ps = period_ps / 2;
+       } else {
+               use_half_period = false;
+               reference_period_ps = period_ps;
+       }
+
+       tRP_ps = data_setup_cycles * period_ps;
+       sample_delay_ps = (sdr->tREA_max + 4000 - tRP_ps) * 8;
+       if (sample_delay_ps > 0)
+               sample_delay_factor = sample_delay_ps / reference_period_ps;
+       else
+               sample_delay_factor = 0;
+
+       hw->ctrl1n = BF_GPMI_CTRL1_WRN_DLY_SEL(wrn_dly_sel);
+       if (sample_delay_factor)
+               hw->ctrl1n |= BF_GPMI_CTRL1_RDN_DELAY(sample_delay_factor) |
+                             BM_GPMI_CTRL1_DLL_ENABLE |
+                             (use_half_period ? BM_GPMI_CTRL1_HALF_PERIOD : 0);
+}
+
+static void gpmi_nfc_apply_timings(struct gpmi_nand_data *this)
+{
+       struct gpmi_nfc_hardware_timing *hw = &this->hw;
+       struct resources *r = &this->resources;
+       void __iomem *gpmi_regs = r->gpmi_regs;
+       unsigned int dll_wait_time_us;
+
+       clk_set_rate(r->clock[0], hw->clk_rate);
+
+       writel(hw->timing0, gpmi_regs + HW_GPMI_TIMING0);
+       writel(hw->timing1, gpmi_regs + HW_GPMI_TIMING1);
+
+       /*
+        * Clear several CTRL1 fields, DLL must be disabled when setting
+        * RDN_DELAY or HALF_PERIOD.
+        */
+       writel(BM_GPMI_CTRL1_CLEAR_MASK, gpmi_regs + HW_GPMI_CTRL1_CLR);
+       writel(hw->ctrl1n, gpmi_regs + HW_GPMI_CTRL1_SET);
+
+       /* Wait 64 clock cycles before using the GPMI after enabling the DLL */
+       dll_wait_time_us = USEC_PER_SEC / hw->clk_rate * 64;
+       if (!dll_wait_time_us)
+               dll_wait_time_us = 1;
+
+       /* Wait for the DLL to settle. */
+       udelay(dll_wait_time_us);
+}
+
+static int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr,
+                                    const struct nand_data_interface *conf)
+{
+       struct gpmi_nand_data *this = nand_get_controller_data(chip);
+       const struct nand_sdr_timings *sdr;
+
+       /* Retrieve required NAND timings */
+       sdr = nand_get_sdr_timings(conf);
+       if (IS_ERR(sdr))
+               return PTR_ERR(sdr);
+
+       /* Only MX6 GPMI controller can reach EDO timings */
+       if (sdr->tRC_min <= 25000 && !GPMI_IS_MX6(this))
+               return -ENOTSUPP;
+
+       /* Stop here if this call was just a check */
+       if (chipnr < 0)
+               return 0;
+
+       /* Do the actual derivation of the controller timings */
+       gpmi_nfc_compute_timings(this, sdr);
+
+       this->hw.must_apply_timings = true;
+
+       return 0;
+}
+
+/* Clears a BCH interrupt. */
+static void gpmi_clear_bch(struct gpmi_nand_data *this)
+{
+       struct resources *r = &this->resources;
+       writel(BM_BCH_CTRL_COMPLETE_IRQ, r->bch_regs + HW_BCH_CTRL_CLR);
+}
+
+static struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
 {
        /* We use the DMA channel 0 to access all the nand chips. */
        return this->dma_chans[0];
 }
 
+/* This will be called after the DMA operation is finished. */
+static void dma_irq_callback(void *param)
+{
+       struct gpmi_nand_data *this = param;
+       struct completion *dma_c = &this->dma_done;
+
+       complete(dma_c);
+}
+
+static irqreturn_t bch_irq(int irq, void *cookie)
+{
+       struct gpmi_nand_data *this = cookie;
+
+       gpmi_clear_bch(this);
+       complete(&this->bch_done);
+       return IRQ_HANDLED;
+}
+
+static int gpmi_raw_len_to_len(struct gpmi_nand_data *this, int raw_len)
+{
+       /*
+        * raw_len is the length to read/write including bch data which
+        * we are passed in exec_op. Calculate the data length from it.
+        */
+       if (this->bch)
+               return ALIGN_DOWN(raw_len, this->bch_geometry.ecc_chunk_size);
+       else
+               return raw_len;
+}
+
 /* Can we use the upper's buffer directly for DMA? */
-bool prepare_data_dma(struct gpmi_nand_data *this, const void *buf, int len,
-                     enum dma_data_direction dr)
+static bool prepare_data_dma(struct gpmi_nand_data *this, const void *buf,
+                            int raw_len, struct scatterlist *sgl,
+                            enum dma_data_direction dr)
 {
-       struct scatterlist *sgl = &this->data_sgl;
        int ret;
+       int len = gpmi_raw_len_to_len(this, raw_len);
 
        /* first try to map the upper buffer directly */
        if (virt_addr_valid(buf) && !object_is_on_stack(buf)) {
@@ -457,7 +821,7 @@ map_fail:
        /* We have to use our own DMA buffer. */
        sg_init_one(sgl, this->data_buffer_dma, len);
 
-       if (dr == DMA_TO_DEVICE)
+       if (dr == DMA_TO_DEVICE && buf != this->data_buffer_dma)
                memcpy(this->data_buffer_dma, buf, len);
 
        dma_map_sg(this->dev, sgl, 1, dr);
@@ -465,67 +829,263 @@ map_fail:
        return false;
 }
 
-/* This will be called after the DMA operation is finished. */
-static void dma_irq_callback(void *param)
+/**
+ * gpmi_copy_bits - copy bits from one memory region to another
+ * @dst: destination buffer
+ * @dst_bit_off: bit offset we're starting to write at
+ * @src: source buffer
+ * @src_bit_off: bit offset we're starting to read from
+ * @nbits: number of bits to copy
+ *
+ * This functions copies bits from one memory region to another, and is used by
+ * the GPMI driver to copy ECC sections which are not guaranteed to be byte
+ * aligned.
+ *
+ * src and dst should not overlap.
+ *
+ */
+static void gpmi_copy_bits(u8 *dst, size_t dst_bit_off, const u8 *src,
+                          size_t src_bit_off, size_t nbits)
 {
-       struct gpmi_nand_data *this = param;
-       struct completion *dma_c = &this->dma_done;
+       size_t i;
+       size_t nbytes;
+       u32 src_buffer = 0;
+       size_t bits_in_src_buffer = 0;
 
-       complete(dma_c);
-}
+       if (!nbits)
+               return;
 
-int start_dma_without_bch_irq(struct gpmi_nand_data *this,
-                               struct dma_async_tx_descriptor *desc)
-{
-       struct completion *dma_c = &this->dma_done;
-       unsigned long timeout;
+       /*
+        * Move src and dst pointers to the closest byte pointer and store bit
+        * offsets within a byte.
+        */
+       src += src_bit_off / 8;
+       src_bit_off %= 8;
 
-       init_completion(dma_c);
+       dst += dst_bit_off / 8;
+       dst_bit_off %= 8;
 
-       desc->callback          = dma_irq_callback;
-       desc->callback_param    = this;
-       dmaengine_submit(desc);
-       dma_async_issue_pending(get_dma_chan(this));
+       /*
+        * Initialize the src_buffer value with bits available in the first
+        * byte of data so that we end up with a byte aligned src pointer.
+        */
+       if (src_bit_off) {
+               src_buffer = src[0] >> src_bit_off;
+               if (nbits >= (8 - src_bit_off)) {
+                       bits_in_src_buffer += 8 - src_bit_off;
+               } else {
+                       src_buffer &= GENMASK(nbits - 1, 0);
+                       bits_in_src_buffer += nbits;
+               }
+               nbits -= bits_in_src_buffer;
+               src++;
+       }
 
-       /* Wait for the interrupt from the DMA block. */
-       timeout = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000));
-       if (!timeout) {
-               dev_err(this->dev, "DMA timeout, last DMA\n");
-               gpmi_dump_info(this);
-               return -ETIMEDOUT;
+       /* Calculate the number of bytes that can be copied from src to dst. */
+       nbytes = nbits / 8;
+
+       /* Try to align dst to a byte boundary. */
+       if (dst_bit_off) {
+               if (bits_in_src_buffer < (8 - dst_bit_off) && nbytes) {
+                       src_buffer |= src[0] << bits_in_src_buffer;
+                       bits_in_src_buffer += 8;
+                       src++;
+                       nbytes--;
+               }
+
+               if (bits_in_src_buffer >= (8 - dst_bit_off)) {
+                       dst[0] &= GENMASK(dst_bit_off - 1, 0);
+                       dst[0] |= src_buffer << dst_bit_off;
+                       src_buffer >>= (8 - dst_bit_off);
+                       bits_in_src_buffer -= (8 - dst_bit_off);
+                       dst_bit_off = 0;
+                       dst++;
+                       if (bits_in_src_buffer > 7) {
+                               bits_in_src_buffer -= 8;
+                               dst[0] = src_buffer;
+                               dst++;
+                               src_buffer >>= 8;
+                       }
+               }
+       }
+
+       if (!bits_in_src_buffer && !dst_bit_off) {
+               /*
+                * Both src and dst pointers are byte aligned, thus we can
+                * just use the optimized memcpy function.
+                */
+               if (nbytes)
+                       memcpy(dst, src, nbytes);
+       } else {
+               /*
+                * src buffer is not byte aligned, hence we have to copy each
+                * src byte to the src_buffer variable before extracting a byte
+                * to store in dst.
+                */
+               for (i = 0; i < nbytes; i++) {
+                       src_buffer |= src[i] << bits_in_src_buffer;
+                       dst[i] = src_buffer;
+                       src_buffer >>= 8;
+               }
+       }
+       /* Update dst and src pointers */
+       dst += nbytes;
+       src += nbytes;
+
+       /*
+        * nbits is the number of remaining bits. It should not exceed 8 as
+        * we've already copied as much bytes as possible.
+        */
+       nbits %= 8;
+
+       /*
+        * If there's no more bits to copy to the destination and src buffer
+        * was already byte aligned, then we're done.
+        */
+       if (!nbits && !bits_in_src_buffer)
+               return;
+
+       /* Copy the remaining bits to src_buffer */
+       if (nbits)
+               src_buffer |= (*src & GENMASK(nbits - 1, 0)) <<
+                             bits_in_src_buffer;
+       bits_in_src_buffer += nbits;
+
+       /*
+        * In case there were not enough bits to get a byte aligned dst buffer
+        * prepare the src_buffer variable to match the dst organization (shift
+        * src_buffer by dst_bit_off and retrieve the least significant bits
+        * from dst).
+        */
+       if (dst_bit_off)
+               src_buffer = (src_buffer << dst_bit_off) |
+                            (*dst & GENMASK(dst_bit_off - 1, 0));
+       bits_in_src_buffer += dst_bit_off;
+
+       /*
+        * Keep most significant bits from dst if we end up with an unaligned
+        * number of bits.
+        */
+       nbytes = bits_in_src_buffer / 8;
+       if (bits_in_src_buffer % 8) {
+               src_buffer |= (dst[nbytes] &
+                              GENMASK(7, bits_in_src_buffer % 8)) <<
+                             (nbytes * 8);
+               nbytes++;
+       }
+
+       /* Copy the remaining bytes to dst */
+       for (i = 0; i < nbytes; i++) {
+               dst[i] = src_buffer;
+               src_buffer >>= 8;
        }
-       return 0;
 }
 
+/* add our owner bbt descriptor */
+static uint8_t scan_ff_pattern[] = { 0xff };
+static struct nand_bbt_descr gpmi_bbt_descr = {
+       .options        = 0,
+       .offs           = 0,
+       .len            = 1,
+       .pattern        = scan_ff_pattern
+};
+
 /*
- * This function is used in BCH reading or BCH writing pages.
- * It will wait for the BCH interrupt as long as ONE second.
- * Actually, we must wait for two interrupts :
- *     [1] firstly the DMA interrupt and
- *     [2] secondly the BCH interrupt.
+ * We may change the layout if we can get the ECC info from the datasheet,
+ * else we will use all the (page + OOB).
  */
-int start_dma_with_bch_irq(struct gpmi_nand_data *this,
-                       struct dma_async_tx_descriptor *desc)
+static int gpmi_ooblayout_ecc(struct mtd_info *mtd, int section,
+                             struct mtd_oob_region *oobregion)
 {
-       struct completion *bch_c = &this->bch_done;
-       unsigned long timeout;
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct gpmi_nand_data *this = nand_get_controller_data(chip);
+       struct bch_geometry *geo = &this->bch_geometry;
 
-       /* Prepare to receive an interrupt from the BCH block. */
-       init_completion(bch_c);
+       if (section)
+               return -ERANGE;
 
-       /* start the DMA */
-       start_dma_without_bch_irq(this, desc);
+       oobregion->offset = 0;
+       oobregion->length = geo->page_size - mtd->writesize;
 
-       /* Wait for the interrupt from the BCH block. */
-       timeout = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000));
-       if (!timeout) {
-               dev_err(this->dev, "BCH timeout\n");
-               gpmi_dump_info(this);
-               return -ETIMEDOUT;
+       return 0;
+}
+
+static int gpmi_ooblayout_free(struct mtd_info *mtd, int section,
+                              struct mtd_oob_region *oobregion)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct gpmi_nand_data *this = nand_get_controller_data(chip);
+       struct bch_geometry *geo = &this->bch_geometry;
+
+       if (section)
+               return -ERANGE;
+
+       /* The available oob size we have. */
+       if (geo->page_size < mtd->writesize + mtd->oobsize) {
+               oobregion->offset = geo->page_size - mtd->writesize;
+               oobregion->length = mtd->oobsize - oobregion->offset;
        }
+
        return 0;
 }
 
+static const char * const gpmi_clks_for_mx2x[] = {
+       "gpmi_io",
+};
+
+static const struct mtd_ooblayout_ops gpmi_ooblayout_ops = {
+       .ecc = gpmi_ooblayout_ecc,
+       .free = gpmi_ooblayout_free,
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx23 = {
+       .type = IS_MX23,
+       .bch_max_ecc_strength = 20,
+       .max_chain_delay = 16000,
+       .clks = gpmi_clks_for_mx2x,
+       .clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx28 = {
+       .type = IS_MX28,
+       .bch_max_ecc_strength = 20,
+       .max_chain_delay = 16000,
+       .clks = gpmi_clks_for_mx2x,
+       .clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
+};
+
+static const char * const gpmi_clks_for_mx6[] = {
+       "gpmi_io", "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch",
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx6q = {
+       .type = IS_MX6Q,
+       .bch_max_ecc_strength = 40,
+       .max_chain_delay = 12000,
+       .clks = gpmi_clks_for_mx6,
+       .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx6sx = {
+       .type = IS_MX6SX,
+       .bch_max_ecc_strength = 62,
+       .max_chain_delay = 12000,
+       .clks = gpmi_clks_for_mx6,
+       .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
+};
+
+static const char * const gpmi_clks_for_mx7d[] = {
+       "gpmi_io", "gpmi_bch_apb",
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx7d = {
+       .type = IS_MX7D,
+       .bch_max_ecc_strength = 62,
+       .max_chain_delay = 12000,
+       .clks = gpmi_clks_for_mx7d,
+       .clks_count = ARRAY_SIZE(gpmi_clks_for_mx7d),
+};
+
 static int acquire_register_block(struct gpmi_nand_data *this,
                                  const char *res_name)
 {
@@ -667,68 +1227,20 @@ static void release_resources(struct gpmi_nand_data *this)
        release_dma_channels(this);
 }
 
-static int send_page_prepare(struct gpmi_nand_data *this,
-                       const void *source, unsigned length,
-                       void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
-                       const void **use_virt, dma_addr_t *use_phys)
-{
-       struct device *dev = this->dev;
-
-       if (virt_addr_valid(source)) {
-               dma_addr_t source_phys;
-
-               source_phys = dma_map_single(dev, (void *)source, length,
-                                               DMA_TO_DEVICE);
-               if (dma_mapping_error(dev, source_phys)) {
-                       if (alt_size < length) {
-                               dev_err(dev, "Alternate buffer is too small\n");
-                               return -ENOMEM;
-                       }
-                       goto map_failed;
-               }
-               *use_virt = source;
-               *use_phys = source_phys;
-               return 0;
-       }
-map_failed:
-       /*
-        * Copy the content of the source buffer into the alternate
-        * buffer and set up the return values accordingly.
-        */
-       memcpy(alt_virt, source, length);
-
-       *use_virt = alt_virt;
-       *use_phys = alt_phys;
-       return 0;
-}
-
-static void send_page_end(struct gpmi_nand_data *this,
-                       const void *source, unsigned length,
-                       void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
-                       const void *used_virt, dma_addr_t used_phys)
-{
-       struct device *dev = this->dev;
-       if (used_virt == source)
-               dma_unmap_single(dev, used_phys, length, DMA_TO_DEVICE);
-}
-
 static void gpmi_free_dma_buffer(struct gpmi_nand_data *this)
 {
        struct device *dev = this->dev;
+       struct bch_geometry *geo = &this->bch_geometry;
 
-       if (this->page_buffer_virt && virt_addr_valid(this->page_buffer_virt))
-               dma_free_coherent(dev, this->page_buffer_size,
-                                       this->page_buffer_virt,
-                                       this->page_buffer_phys);
-       kfree(this->cmd_buffer);
+       if (this->auxiliary_virt && virt_addr_valid(this->auxiliary_virt))
+               dma_free_coherent(dev, geo->auxiliary_size,
+                                       this->auxiliary_virt,
+                                       this->auxiliary_phys);
        kfree(this->data_buffer_dma);
        kfree(this->raw_buffer);
 
-       this->cmd_buffer        = NULL;
        this->data_buffer_dma   = NULL;
        this->raw_buffer        = NULL;
-       this->page_buffer_virt  = NULL;
-       this->page_buffer_size  =  0;
 }
 
 /* Allocate the DMA buffers */
@@ -738,11 +1250,6 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
        struct device *dev = this->dev;
        struct mtd_info *mtd = nand_to_mtd(&this->nand);
 
-       /* [1] Allocate a command buffer. PAGE_SIZE is enough. */
-       this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL);
-       if (this->cmd_buffer == NULL)
-               goto error_alloc;
-
        /*
         * [2] Allocate a read/write data buffer.
         *     The gpmi_alloc_dma_buffer can be called twice.
@@ -756,29 +1263,15 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
        if (this->data_buffer_dma == NULL)
                goto error_alloc;
 
-       /*
-        * [3] Allocate the page buffer.
-        *
-        * Both the payload buffer and the auxiliary buffer must appear on
-        * 32-bit boundaries. We presume the size of the payload buffer is a
-        * power of two and is much larger than four, which guarantees the
-        * auxiliary buffer will appear on a 32-bit boundary.
-        */
-       this->page_buffer_size = geo->payload_size + geo->auxiliary_size;
-       this->page_buffer_virt = dma_alloc_coherent(dev, this->page_buffer_size,
-                                       &this->page_buffer_phys, GFP_DMA);
-       if (!this->page_buffer_virt)
+       this->auxiliary_virt = dma_alloc_coherent(dev, geo->auxiliary_size,
+                                       &this->auxiliary_phys, GFP_DMA);
+       if (!this->auxiliary_virt)
                goto error_alloc;
 
-       this->raw_buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
+       this->raw_buffer = kzalloc((mtd->writesize ?: PAGE_SIZE) + mtd->oobsize, GFP_KERNEL);
        if (!this->raw_buffer)
                goto error_alloc;
 
-       /* Slice up the page buffer. */
-       this->payload_virt = this->page_buffer_virt;
-       this->payload_phys = this->page_buffer_phys;
-       this->auxiliary_virt = this->payload_virt + geo->payload_size;
-       this->auxiliary_phys = this->payload_phys + geo->payload_size;
        return 0;
 
 error_alloc:
@@ -786,106 +1279,6 @@ error_alloc:
        return -ENOMEM;
 }
 
-static void gpmi_cmd_ctrl(struct nand_chip *chip, int data, unsigned int ctrl)
-{
-       struct gpmi_nand_data *this = nand_get_controller_data(chip);
-       int ret;
-
-       /*
-        * Every operation begins with a command byte and a series of zero or
-        * more address bytes. These are distinguished by either the Address
-        * Latch Enable (ALE) or Command Latch Enable (CLE) signals being
-        * asserted. When MTD is ready to execute the command, it will deassert
-        * both latch enables.
-        *
-        * Rather than run a separate DMA operation for every single byte, we
-        * queue them up and run a single DMA operation for the entire series
-        * of command and data bytes. NAND_CMD_NONE means the END of the queue.
-        */
-       if ((ctrl & (NAND_ALE | NAND_CLE))) {
-               if (data != NAND_CMD_NONE)
-                       this->cmd_buffer[this->command_length++] = data;
-               return;
-       }
-
-       if (!this->command_length)
-               return;
-
-       ret = gpmi_send_command(this);
-       if (ret)
-               dev_err(this->dev, "Chip: %u, Error %d\n",
-                       this->current_chip, ret);
-
-       this->command_length = 0;
-}
-
-static int gpmi_dev_ready(struct nand_chip *chip)
-{
-       struct gpmi_nand_data *this = nand_get_controller_data(chip);
-
-       return gpmi_is_ready(this, this->current_chip);
-}
-
-static void gpmi_select_chip(struct nand_chip *chip, int chipnr)
-{
-       struct gpmi_nand_data *this = nand_get_controller_data(chip);
-       int ret;
-
-       /*
-        * For power consumption matters, disable/enable the clock each time a
-        * die is selected/unselected.
-        */
-       if (this->current_chip < 0 && chipnr >= 0) {
-               ret = gpmi_enable_clk(this);
-               if (ret)
-                       dev_err(this->dev, "Failed to enable the clock\n");
-       } else if (this->current_chip >= 0 && chipnr < 0) {
-               ret = gpmi_disable_clk(this);
-               if (ret)
-                       dev_err(this->dev, "Failed to disable the clock\n");
-       }
-
-       /*
-        * This driver currently supports only one NAND chip. Plus, dies share
-        * the same configuration. So once timings have been applied on the
-        * controller side, they will not change anymore. When the time will
-        * come, the check on must_apply_timings will have to be dropped.
-        */
-       if (chipnr >= 0 && this->hw.must_apply_timings) {
-               this->hw.must_apply_timings = false;
-               gpmi_nfc_apply_timings(this);
-       }
-
-       this->current_chip = chipnr;
-}
-
-static void gpmi_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
-{
-       struct gpmi_nand_data *this = nand_get_controller_data(chip);
-
-       dev_dbg(this->dev, "len is %d\n", len);
-
-       gpmi_read_data(this, buf, len);
-}
-
-static void gpmi_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
-{
-       struct gpmi_nand_data *this = nand_get_controller_data(chip);
-
-       dev_dbg(this->dev, "len is %d\n", len);
-
-       gpmi_send_data(this, buf, len);
-}
-
-static uint8_t gpmi_read_byte(struct nand_chip *chip)
-{
-       struct gpmi_nand_data *this = nand_get_controller_data(chip);
-       uint8_t *buf = this->data_buffer_dma;
-
-       gpmi_read_buf(chip, buf, 1);
-       return buf[0];
-}
-
 /*
  * Handles block mark swapping.
  * It can be called in swapping the block mark, or swapping it back,
@@ -934,54 +1327,20 @@ static void block_mark_swapping(struct gpmi_nand_data *this,
        p[1] = (p[1] & mask) | (from_oob >> (8 - bit));
 }
 
-static int gpmi_ecc_read_page_data(struct nand_chip *chip,
-                                  uint8_t *buf, int oob_required,
-                                  int page)
+static int gpmi_count_bitflips(struct nand_chip *chip, void *buf, int first,
+                              int last, int meta)
 {
        struct gpmi_nand_data *this = nand_get_controller_data(chip);
        struct bch_geometry *nfc_geo = &this->bch_geometry;
        struct mtd_info *mtd = nand_to_mtd(chip);
-       dma_addr_t    payload_phys;
-       unsigned int  i;
+       int i;
        unsigned char *status;
-       unsigned int  max_bitflips = 0;
-       int           ret;
-       bool          direct = false;
-
-       dev_dbg(this->dev, "page number is : %d\n", page);
-
-       payload_phys = this->payload_phys;
-
-       if (virt_addr_valid(buf)) {
-               dma_addr_t dest_phys;
-
-               dest_phys = dma_map_single(this->dev, buf, nfc_geo->payload_size,
-                                          DMA_FROM_DEVICE);
-               if (!dma_mapping_error(this->dev, dest_phys)) {
-                       payload_phys = dest_phys;
-                       direct = true;
-               }
-       }
-
-       /* go! */
-       ret = gpmi_read_page(this, payload_phys, this->auxiliary_phys);
-
-       if (direct)
-               dma_unmap_single(this->dev, payload_phys, nfc_geo->payload_size,
-                                DMA_FROM_DEVICE);
-
-       if (ret) {
-               dev_err(this->dev, "Error in ECC-based read: %d\n", ret);
-               return ret;
-       }
+       unsigned int max_bitflips = 0;
 
        /* Loop over status bytes, accumulating ECC status. */
-       status = this->auxiliary_virt + nfc_geo->auxiliary_status_offset;
+       status = this->auxiliary_virt + ALIGN(meta, 4);
 
-       if (!direct)
-               memcpy(buf, this->payload_virt, nfc_geo->payload_size);
-
-       for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) {
+       for (i = first; i < last; i++, status++) {
                if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED))
                        continue;
 
@@ -1061,6 +1420,50 @@ static int gpmi_ecc_read_page_data(struct nand_chip *chip,
                max_bitflips = max_t(unsigned int, max_bitflips, *status);
        }
 
+       return max_bitflips;
+}
+
+static void gpmi_bch_layout_std(struct gpmi_nand_data *this)
+{
+       struct bch_geometry *geo = &this->bch_geometry;
+       unsigned int ecc_strength = geo->ecc_strength >> 1;
+       unsigned int gf_len = geo->gf_len;
+       unsigned int block_size = geo->ecc_chunk_size;
+
+       this->bch_flashlayout0 =
+               BF_BCH_FLASH0LAYOUT0_NBLOCKS(geo->ecc_chunk_count - 1) |
+               BF_BCH_FLASH0LAYOUT0_META_SIZE(geo->metadata_size) |
+               BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength, this) |
+               BF_BCH_FLASH0LAYOUT0_GF(gf_len, this) |
+               BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size, this);
+
+       this->bch_flashlayout1 =
+               BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(geo->page_size) |
+               BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength, this) |
+               BF_BCH_FLASH0LAYOUT1_GF(gf_len, this) |
+               BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size, this);
+}
+
+static int gpmi_ecc_read_page(struct nand_chip *chip, uint8_t *buf,
+                             int oob_required, int page)
+{
+       struct gpmi_nand_data *this = nand_get_controller_data(chip);
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct bch_geometry *geo = &this->bch_geometry;
+       unsigned int max_bitflips;
+       int ret;
+
+       gpmi_bch_layout_std(this);
+       this->bch = true;
+
+       ret = nand_read_page_op(chip, page, 0, buf, geo->page_size);
+       if (ret)
+               return ret;
+
+       max_bitflips = gpmi_count_bitflips(chip, buf, 0,
+                                          geo->ecc_chunk_count,
+                                          geo->auxiliary_status_offset);
+
        /* handle the block mark swapping */
        block_mark_swapping(this, buf, this->auxiliary_virt);
 
@@ -1082,30 +1485,20 @@ static int gpmi_ecc_read_page_data(struct nand_chip *chip,
        return max_bitflips;
 }
 
-static int gpmi_ecc_read_page(struct nand_chip *chip, uint8_t *buf,
-                             int oob_required, int page)
-{
-       nand_read_page_op(chip, page, 0, NULL, 0);
-
-       return gpmi_ecc_read_page_data(chip, buf, oob_required, page);
-}
-
 /* Fake a virtual small page for the subpage read */
 static int gpmi_ecc_read_subpage(struct nand_chip *chip, uint32_t offs,
                                 uint32_t len, uint8_t *buf, int page)
 {
        struct gpmi_nand_data *this = nand_get_controller_data(chip);
-       void __iomem *bch_regs = this->resources.bch_regs;
-       struct bch_geometry old_geo = this->bch_geometry;
        struct bch_geometry *geo = &this->bch_geometry;
        int size = chip->ecc.size; /* ECC chunk size */
        int meta, n, page_size;
-       u32 r1_old, r2_old, r1_new, r2_new;
        unsigned int max_bitflips;
+       unsigned int ecc_strength;
        int first, last, marker_pos;
        int ecc_parity_size;
        int col = 0;
-       int old_swap_block_mark = this->swap_block_mark;
+       int ret;
 
        /* The size of ECC parity */
        ecc_parity_size = geo->gf_len * geo->ecc_strength / 8;
@@ -1138,43 +1531,33 @@ static int gpmi_ecc_read_subpage(struct nand_chip *chip, uint32_t offs,
                buf = buf + first * size;
        }
 
-       nand_read_page_op(chip, page, col, NULL, 0);
-
-       /* Save the old environment */
-       r1_old = r1_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT0);
-       r2_old = r2_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT1);
+       ecc_parity_size = geo->gf_len * geo->ecc_strength / 8;
 
-       /* change the BCH registers and bch_geometry{} */
        n = last - first + 1;
        page_size = meta + (size + ecc_parity_size) * n;
+       ecc_strength = geo->ecc_strength >> 1;
+
+       this->bch_flashlayout0 = BF_BCH_FLASH0LAYOUT0_NBLOCKS(n - 1) |
+               BF_BCH_FLASH0LAYOUT0_META_SIZE(meta) |
+               BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength, this) |
+               BF_BCH_FLASH0LAYOUT0_GF(geo->gf_len, this) |
+               BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(geo->ecc_chunk_size, this);
 
-       r1_new &= ~(BM_BCH_FLASH0LAYOUT0_NBLOCKS |
-                       BM_BCH_FLASH0LAYOUT0_META_SIZE);
-       r1_new |= BF_BCH_FLASH0LAYOUT0_NBLOCKS(n - 1)
-                       | BF_BCH_FLASH0LAYOUT0_META_SIZE(meta);
-       writel(r1_new, bch_regs + HW_BCH_FLASH0LAYOUT0);
+       this->bch_flashlayout1 = BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size) |
+               BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength, this) |
+               BF_BCH_FLASH0LAYOUT1_GF(geo->gf_len, this) |
+               BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(geo->ecc_chunk_size, this);
 
-       r2_new &= ~BM_BCH_FLASH0LAYOUT1_PAGE_SIZE;
-       r2_new |= BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size);
-       writel(r2_new, bch_regs + HW_BCH_FLASH0LAYOUT1);
+       this->bch = true;
 
-       geo->ecc_chunk_count = n;
-       geo->payload_size = n * size;
-       geo->page_size = page_size;
-       geo->auxiliary_status_offset = ALIGN(meta, 4);
+       ret = nand_read_page_op(chip, page, col, buf, page_size);
+       if (ret)
+               return ret;
 
        dev_dbg(this->dev, "page:%d(%d:%d)%d, chunk:(%d:%d), BCH PG size:%d\n",
                page, offs, len, col, first, n, page_size);
 
-       /* Read the subpage now */
-       this->swap_block_mark = false;
-       max_bitflips = gpmi_ecc_read_page_data(chip, buf, 0, page);
-
-       /* Restore */
-       writel(r1_old, bch_regs + HW_BCH_FLASH0LAYOUT0);
-       writel(r2_old, bch_regs + HW_BCH_FLASH0LAYOUT1);
-       this->bch_geometry = old_geo;
-       this->swap_block_mark = old_swap_block_mark;
+       max_bitflips = gpmi_count_bitflips(chip, buf, first, last, meta);
 
        return max_bitflips;
 }
@@ -1185,81 +1568,29 @@ static int gpmi_ecc_write_page(struct nand_chip *chip, const uint8_t *buf,
        struct mtd_info *mtd = nand_to_mtd(chip);
        struct gpmi_nand_data *this = nand_get_controller_data(chip);
        struct bch_geometry *nfc_geo = &this->bch_geometry;
-       const void *payload_virt;
-       dma_addr_t payload_phys;
-       const void *auxiliary_virt;
-       dma_addr_t auxiliary_phys;
-       int        ret;
+       int ret;
 
        dev_dbg(this->dev, "ecc write page.\n");
 
-       nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+       gpmi_bch_layout_std(this);
+       this->bch = true;
+
+       memcpy(this->auxiliary_virt, chip->oob_poi, nfc_geo->auxiliary_size);
 
        if (this->swap_block_mark) {
                /*
-                * If control arrives here, we're doing block mark swapping.
-                * Since we can't modify the caller's buffers, we must copy them
-                * into our own.
-                */
-               memcpy(this->payload_virt, buf, mtd->writesize);
-               payload_virt = this->payload_virt;
-               payload_phys = this->payload_phys;
-
-               memcpy(this->auxiliary_virt, chip->oob_poi,
-                               nfc_geo->auxiliary_size);
-               auxiliary_virt = this->auxiliary_virt;
-               auxiliary_phys = this->auxiliary_phys;
-
-               /* Handle block mark swapping. */
-               block_mark_swapping(this,
-                               (void *)payload_virt, (void *)auxiliary_virt);
-       } else {
-               /*
-                * If control arrives here, we're not doing block mark swapping,
-                * so we can to try and use the caller's buffers.
+                * When doing bad block marker swapping we must always copy the
+                * input buffer as we can't modify the const buffer.
                 */
-               ret = send_page_prepare(this,
-                               buf, mtd->writesize,
-                               this->payload_virt, this->payload_phys,
-                               nfc_geo->payload_size,
-                               &payload_virt, &payload_phys);
-               if (ret) {
-                       dev_err(this->dev, "Inadequate payload DMA buffer\n");
-                       return 0;
-               }
-
-               ret = send_page_prepare(this,
-                               chip->oob_poi, mtd->oobsize,
-                               this->auxiliary_virt, this->auxiliary_phys,
-                               nfc_geo->auxiliary_size,
-                               &auxiliary_virt, &auxiliary_phys);
-               if (ret) {
-                       dev_err(this->dev, "Inadequate auxiliary DMA buffer\n");
-                       goto exit_auxiliary;
-               }
-       }
-
-       /* Ask the NFC. */
-       ret = gpmi_send_page(this, payload_phys, auxiliary_phys);
-       if (ret)
-               dev_err(this->dev, "Error in ECC-based write: %d\n", ret);
-
-       if (!this->swap_block_mark) {
-               send_page_end(this, chip->oob_poi, mtd->oobsize,
-                               this->auxiliary_virt, this->auxiliary_phys,
-                               nfc_geo->auxiliary_size,
-                               auxiliary_virt, auxiliary_phys);
-exit_auxiliary:
-               send_page_end(this, buf, mtd->writesize,
-                               this->payload_virt, this->payload_phys,
-                               nfc_geo->payload_size,
-                               payload_virt, payload_phys);
+               memcpy(this->data_buffer_dma, buf, mtd->writesize);
+               buf = this->data_buffer_dma;
+               block_mark_swapping(this, this->data_buffer_dma,
+                                   this->auxiliary_virt);
        }
 
-       if (ret)
-               return ret;
+       ret = nand_prog_page_op(chip, page, 0, buf, nfc_geo->page_size);
 
-       return nand_prog_page_end_op(chip);
+       return ret;
 }
 
 /*
@@ -1326,14 +1657,16 @@ static int gpmi_ecc_read_oob(struct nand_chip *chip, int page)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
        struct gpmi_nand_data *this = nand_get_controller_data(chip);
+       int ret;
 
-       dev_dbg(this->dev, "page number is %d\n", page);
        /* clear the OOB buffer */
        memset(chip->oob_poi, ~0, mtd->oobsize);
 
        /* Read out the conventional OOB. */
-       nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
-       chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
+       ret = nand_read_page_op(chip, page, mtd->writesize, chip->oob_poi,
+                               mtd->oobsize);
+       if (ret)
+               return ret;
 
        /*
         * Now, we want to make sure the block mark is correct. In the
@@ -1342,8 +1675,9 @@ static int gpmi_ecc_read_oob(struct nand_chip *chip, int page)
         */
        if (GPMI_IS_MX23(this)) {
                /* Read the block mark into the first byte of the OOB buffer. */
-               nand_read_page_op(chip, page, 0, NULL, 0);
-               chip->oob_poi[0] = chip->legacy.read_byte(chip);
+               ret = nand_read_page_op(chip, page, 0, chip->oob_poi, 1);
+               if (ret)
+                       return ret;
        }
 
        return 0;
@@ -1392,9 +1726,12 @@ static int gpmi_ecc_read_page_raw(struct nand_chip *chip, uint8_t *buf,
        size_t oob_byte_off;
        uint8_t *oob = chip->oob_poi;
        int step;
+       int ret;
 
-       nand_read_page_op(chip, page, 0, tmp_buf,
-                         mtd->writesize + mtd->oobsize);
+       ret = nand_read_page_op(chip, page, 0, tmp_buf,
+                               mtd->writesize + mtd->oobsize);
+       if (ret)
+               return ret;
 
        /*
         * If required, swap the bad block marker and the data stored in the
@@ -1606,13 +1943,12 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
        unsigned int stride;
        unsigned int page;
        u8 *buffer = nand_get_data_buf(chip);
-       int saved_chip_number;
        int found_an_ncb_fingerprint = false;
+       int ret;
 
        /* Compute the number of strides in a search area. */
        search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent;
 
-       saved_chip_number = this->current_chip;
        nand_select_target(chip, 0);
 
        /*
@@ -1630,8 +1966,10 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
                 * Read the NCB fingerprint. The fingerprint is four bytes long
                 * and starts in the 12th byte of the page.
                 */
-               nand_read_page_op(chip, page, 12, NULL, 0);
-               chip->legacy.read_buf(chip, buffer, strlen(fingerprint));
+               ret = nand_read_page_op(chip, page, 12, buffer,
+                                       strlen(fingerprint));
+               if (ret)
+                       continue;
 
                /* Look for the fingerprint. */
                if (!memcmp(buffer, fingerprint, strlen(fingerprint))) {
@@ -1641,10 +1979,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
 
        }
 
-       if (saved_chip_number >= 0)
-               nand_select_target(chip, saved_chip_number);
-       else
-               nand_deselect_target(chip);
+       nand_deselect_target(chip);
 
        if (found_an_ncb_fingerprint)
                dev_dbg(dev, "\tFound a fingerprint\n");
@@ -1668,7 +2003,6 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
        unsigned int stride;
        unsigned int page;
        u8 *buffer = nand_get_data_buf(chip);
-       int saved_chip_number;
        int status;
 
        /* Compute the search area geometry. */
@@ -1685,8 +2019,6 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
        dev_dbg(dev, "\tin Strides: %u\n", search_area_size_in_strides);
        dev_dbg(dev, "\tin Pages  : %u\n", search_area_size_in_pages);
 
-       /* Select chip 0. */
-       saved_chip_number = this->current_chip;
        nand_select_target(chip, 0);
 
        /* Loop over blocks in the first search area, erasing them. */
@@ -1718,11 +2050,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
                        dev_err(dev, "[%s] Write failed.\n", __func__);
        }
 
-       /* Deselect chip 0. */
-       if (saved_chip_number >= 0)
-               nand_select_target(chip, saved_chip_number);
-       else
-               nand_deselect_target(chip);
+       nand_deselect_target(chip);
 
        return 0;
 }
@@ -1773,10 +2101,13 @@ static int mx23_boot_init(struct gpmi_nand_data  *this)
 
                /* Send the command to read the conventional block mark. */
                nand_select_target(chip, chipnr);
-               nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
-               block_mark = chip->legacy.read_byte(chip);
+               ret = nand_read_page_op(chip, page, mtd->writesize, &block_mark,
+                                       1);
                nand_deselect_target(chip);
 
+               if (ret)
+                       continue;
+
                /*
                 * Check if the block is marked bad. If so, we need to mark it
                 * again, but this time the result will be a mark in the
@@ -1890,9 +2221,330 @@ static int gpmi_nand_attach_chip(struct nand_chip *chip)
        return 0;
 }
 
+static struct gpmi_transfer *get_next_transfer(struct gpmi_nand_data *this)
+{
+       struct gpmi_transfer *transfer = &this->transfers[this->ntransfers];
+
+       this->ntransfers++;
+
+       if (this->ntransfers == GPMI_MAX_TRANSFERS)
+               return NULL;
+
+       return transfer;
+}
+
+static struct dma_async_tx_descriptor *gpmi_chain_command(
+       struct gpmi_nand_data *this, u8 cmd, const u8 *addr, int naddr)
+{
+       struct dma_chan *channel = get_dma_chan(this);
+       struct dma_async_tx_descriptor *desc;
+       struct gpmi_transfer *transfer;
+       int chip = this->nand.cur_cs;
+       u32 pio[3];
+
+       /* [1] send out the PIO words */
+       pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE)
+               | BM_GPMI_CTRL0_WORD_LENGTH
+               | BF_GPMI_CTRL0_CS(chip, this)
+               | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+               | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_CLE)
+               | BM_GPMI_CTRL0_ADDRESS_INCREMENT
+               | BF_GPMI_CTRL0_XFER_COUNT(naddr + 1);
+       pio[1] = 0;
+       pio[2] = 0;
+       desc = mxs_dmaengine_prep_pio(channel, pio, ARRAY_SIZE(pio),
+                                     DMA_TRANS_NONE, 0);
+       if (!desc)
+               return NULL;
+
+       transfer = get_next_transfer(this);
+       if (!transfer)
+               return NULL;
+
+       transfer->cmdbuf[0] = cmd;
+       if (naddr)
+               memcpy(&transfer->cmdbuf[1], addr, naddr);
+
+       sg_init_one(&transfer->sgl, transfer->cmdbuf, naddr + 1);
+       dma_map_sg(this->dev, &transfer->sgl, 1, DMA_TO_DEVICE);
+
+       transfer->direction = DMA_TO_DEVICE;
+
+       desc = dmaengine_prep_slave_sg(channel, &transfer->sgl, 1, DMA_MEM_TO_DEV,
+                                      MXS_DMA_CTRL_WAIT4END);
+       return desc;
+}
+
+static struct dma_async_tx_descriptor *gpmi_chain_wait_ready(
+       struct gpmi_nand_data *this)
+{
+       struct dma_chan *channel = get_dma_chan(this);
+       u32 pio[2];
+
+       pio[0] =  BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY)
+               | BM_GPMI_CTRL0_WORD_LENGTH
+               | BF_GPMI_CTRL0_CS(this->nand.cur_cs, this)
+               | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+               | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA)
+               | BF_GPMI_CTRL0_XFER_COUNT(0);
+       pio[1] = 0;
+
+       return mxs_dmaengine_prep_pio(channel, pio, 2, DMA_TRANS_NONE,
+                               MXS_DMA_CTRL_WAIT4END | MXS_DMA_CTRL_WAIT4RDY);
+}
+
+static struct dma_async_tx_descriptor *gpmi_chain_data_read(
+       struct gpmi_nand_data *this, void *buf, int raw_len, bool *direct)
+{
+       struct dma_async_tx_descriptor *desc;
+       struct dma_chan *channel = get_dma_chan(this);
+       struct gpmi_transfer *transfer;
+       u32 pio[6] = {};
+
+       transfer = get_next_transfer(this);
+       if (!transfer)
+               return NULL;
+
+       transfer->direction = DMA_FROM_DEVICE;
+
+       *direct = prepare_data_dma(this, buf, raw_len, &transfer->sgl,
+                                  DMA_FROM_DEVICE);
+
+       pio[0] =  BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__READ)
+               | BM_GPMI_CTRL0_WORD_LENGTH
+               | BF_GPMI_CTRL0_CS(this->nand.cur_cs, this)
+               | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+               | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA)
+               | BF_GPMI_CTRL0_XFER_COUNT(raw_len);
+
+       if (this->bch) {
+               pio[2] =  BM_GPMI_ECCCTRL_ENABLE_ECC
+                       | BF_GPMI_ECCCTRL_ECC_CMD(BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE)
+                       | BF_GPMI_ECCCTRL_BUFFER_MASK(BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE
+                               | BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY);
+               pio[3] = raw_len;
+               pio[4] = transfer->sgl.dma_address;
+               pio[5] = this->auxiliary_phys;
+       }
+
+       desc = mxs_dmaengine_prep_pio(channel, pio, ARRAY_SIZE(pio),
+                                     DMA_TRANS_NONE, 0);
+       if (!desc)
+               return NULL;
+
+       if (!this->bch)
+               desc = dmaengine_prep_slave_sg(channel, &transfer->sgl, 1,
+                                            DMA_DEV_TO_MEM,
+                                            MXS_DMA_CTRL_WAIT4END);
+
+       return desc;
+}
+
+static struct dma_async_tx_descriptor *gpmi_chain_data_write(
+       struct gpmi_nand_data *this, const void *buf, int raw_len)
+{
+       struct dma_chan *channel = get_dma_chan(this);
+       struct dma_async_tx_descriptor *desc;
+       struct gpmi_transfer *transfer;
+       u32 pio[6] = {};
+
+       transfer = get_next_transfer(this);
+       if (!transfer)
+               return NULL;
+
+       transfer->direction = DMA_TO_DEVICE;
+
+       prepare_data_dma(this, buf, raw_len, &transfer->sgl, DMA_TO_DEVICE);
+
+       pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE)
+               | BM_GPMI_CTRL0_WORD_LENGTH
+               | BF_GPMI_CTRL0_CS(this->nand.cur_cs, this)
+               | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+               | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA)
+               | BF_GPMI_CTRL0_XFER_COUNT(raw_len);
+
+       if (this->bch) {
+               pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC
+                       | BF_GPMI_ECCCTRL_ECC_CMD(BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE)
+                       | BF_GPMI_ECCCTRL_BUFFER_MASK(BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE |
+                                       BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY);
+               pio[3] = raw_len;
+               pio[4] = transfer->sgl.dma_address;
+               pio[5] = this->auxiliary_phys;
+       }
+
+       desc = mxs_dmaengine_prep_pio(channel, pio, ARRAY_SIZE(pio),
+                                     DMA_TRANS_NONE,
+                                     (this->bch ? MXS_DMA_CTRL_WAIT4END : 0));
+       if (!desc)
+               return NULL;
+
+       if (!this->bch)
+               desc = dmaengine_prep_slave_sg(channel, &transfer->sgl, 1,
+                                              DMA_MEM_TO_DEV,
+                                              MXS_DMA_CTRL_WAIT4END);
+
+       return desc;
+}
+
+static int gpmi_nfc_exec_op(struct nand_chip *chip,
+                            const struct nand_operation *op,
+                            bool check_only)
+{
+       const struct nand_op_instr *instr;
+       struct gpmi_nand_data *this = nand_get_controller_data(chip);
+       struct dma_async_tx_descriptor *desc = NULL;
+       int i, ret, buf_len = 0, nbufs = 0;
+       u8 cmd = 0;
+       void *buf_read = NULL;
+       const void *buf_write = NULL;
+       bool direct = false;
+       struct completion *completion;
+       unsigned long to;
+
+       this->ntransfers = 0;
+       for (i = 0; i < GPMI_MAX_TRANSFERS; i++)
+               this->transfers[i].direction = DMA_NONE;
+
+       ret = pm_runtime_get_sync(this->dev);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * This driver currently supports only one NAND chip. Plus, dies share
+        * the same configuration. So once timings have been applied on the
+        * controller side, they will not change anymore. When the time will
+        * come, the check on must_apply_timings will have to be dropped.
+        */
+       if (this->hw.must_apply_timings) {
+               this->hw.must_apply_timings = false;
+               gpmi_nfc_apply_timings(this);
+       }
+
+       dev_dbg(this->dev, "%s: %d instructions\n", __func__, op->ninstrs);
+
+       for (i = 0; i < op->ninstrs; i++) {
+               instr = &op->instrs[i];
+
+               nand_op_trace("  ", instr);
+
+               switch (instr->type) {
+               case NAND_OP_WAITRDY_INSTR:
+                       desc = gpmi_chain_wait_ready(this);
+                       break;
+               case NAND_OP_CMD_INSTR:
+                       cmd = instr->ctx.cmd.opcode;
+
+                       /*
+                        * When this command has an address cycle chain it
+                        * together with the address cycle
+                        */
+                       if (i + 1 != op->ninstrs &&
+                           op->instrs[i + 1].type == NAND_OP_ADDR_INSTR)
+                               continue;
+
+                       desc = gpmi_chain_command(this, cmd, NULL, 0);
+
+                       break;
+               case NAND_OP_ADDR_INSTR:
+                       desc = gpmi_chain_command(this, cmd, instr->ctx.addr.addrs,
+                                                 instr->ctx.addr.naddrs);
+                       break;
+               case NAND_OP_DATA_OUT_INSTR:
+                       buf_write = instr->ctx.data.buf.out;
+                       buf_len = instr->ctx.data.len;
+                       nbufs++;
+
+                       desc = gpmi_chain_data_write(this, buf_write, buf_len);
+
+                       break;
+               case NAND_OP_DATA_IN_INSTR:
+                       if (!instr->ctx.data.len)
+                               break;
+                       buf_read = instr->ctx.data.buf.in;
+                       buf_len = instr->ctx.data.len;
+                       nbufs++;
+
+                       desc = gpmi_chain_data_read(this, buf_read, buf_len,
+                                                  &direct);
+                       break;
+               }
+
+               if (!desc) {
+                       ret = -ENXIO;
+                       goto unmap;
+               }
+       }
+
+       dev_dbg(this->dev, "%s setup done\n", __func__);
+
+       if (nbufs > 1) {
+               dev_err(this->dev, "Multiple data instructions not supported\n");
+               ret = -EINVAL;
+               goto unmap;
+       }
+
+       if (this->bch) {
+               writel(this->bch_flashlayout0,
+                      this->resources.bch_regs + HW_BCH_FLASH0LAYOUT0);
+               writel(this->bch_flashlayout1,
+                      this->resources.bch_regs + HW_BCH_FLASH0LAYOUT1);
+       }
+
+       if (this->bch && buf_read) {
+               writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
+                      this->resources.bch_regs + HW_BCH_CTRL_SET);
+               completion = &this->bch_done;
+       } else {
+               desc->callback = dma_irq_callback;
+               desc->callback_param = this;
+               completion = &this->dma_done;
+       }
+
+       init_completion(completion);
+
+       dmaengine_submit(desc);
+       dma_async_issue_pending(get_dma_chan(this));
+
+       to = wait_for_completion_timeout(completion, msecs_to_jiffies(1000));
+       if (!to) {
+               dev_err(this->dev, "DMA timeout, last DMA\n");
+               gpmi_dump_info(this);
+               ret = -ETIMEDOUT;
+               goto unmap;
+       }
+
+       writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
+              this->resources.bch_regs + HW_BCH_CTRL_CLR);
+       gpmi_clear_bch(this);
+
+       ret = 0;
+
+unmap:
+       for (i = 0; i < this->ntransfers; i++) {
+               struct gpmi_transfer *transfer = &this->transfers[i];
+
+               if (transfer->direction != DMA_NONE)
+                       dma_unmap_sg(this->dev, &transfer->sgl, 1,
+                                    transfer->direction);
+       }
+
+       if (!ret && buf_read && !direct)
+               memcpy(buf_read, this->data_buffer_dma,
+                      gpmi_raw_len_to_len(this, buf_len));
+
+       this->bch = false;
+
+       pm_runtime_mark_last_busy(this->dev);
+       pm_runtime_put_autosuspend(this->dev);
+
+       return ret;
+}
+
 static const struct nand_controller_ops gpmi_nand_controller_ops = {
        .attach_chip = gpmi_nand_attach_chip,
        .setup_data_interface = gpmi_setup_data_interface,
+       .exec_op = gpmi_nfc_exec_op,
 };
 
 static int gpmi_nand_init(struct gpmi_nand_data *this)
@@ -1901,9 +2553,6 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
        struct mtd_info  *mtd = nand_to_mtd(chip);
        int ret;
 
-       /* init current chip */
-       this->current_chip      = -1;
-
        /* init the MTD data structures */
        mtd->name               = "gpmi-nand";
        mtd->dev.parent         = this->dev;
@@ -1911,14 +2560,8 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
        /* init the nand_chip{}, we don't support a 16-bit NAND Flash bus. */
        nand_set_controller_data(chip, this);
        nand_set_flash_node(chip, this->pdev->dev.of_node);
-       chip->legacy.select_chip        = gpmi_select_chip;
-       chip->legacy.cmd_ctrl   = gpmi_cmd_ctrl;
-       chip->legacy.dev_ready  = gpmi_dev_ready;
-       chip->legacy.read_byte  = gpmi_read_byte;
-       chip->legacy.read_buf   = gpmi_read_buf;
-       chip->legacy.write_buf  = gpmi_write_buf;
-       chip->badblock_pattern  = &gpmi_bbt_descr;
        chip->legacy.block_markbad = gpmi_block_markbad;
+       chip->badblock_pattern  = &gpmi_bbt_descr;
        chip->options           |= NAND_NO_SUBPAGE_WRITE;
 
        /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */
@@ -1934,7 +2577,10 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
        if (ret)
                goto err_out;
 
-       chip->legacy.dummy_controller.ops = &gpmi_nand_controller_ops;
+       nand_controller_init(&this->base);
+       this->base.ops = &gpmi_nand_controller_ops;
+       chip->controller = &this->base;
+
        ret = nand_scan(chip, GPMI_IS_MX6(this) ? 2 : 1);
        if (ret)
                goto err_out;
@@ -2004,6 +2650,16 @@ static int gpmi_nand_probe(struct platform_device *pdev)
        if (ret)
                goto exit_acquire_resources;
 
+       ret = __gpmi_enable_clk(this, true);
+       if (ret)
+               goto exit_nfc_init;
+
+       pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
+
        ret = gpmi_init(this);
        if (ret)
                goto exit_nfc_init;
@@ -2012,11 +2668,16 @@ static int gpmi_nand_probe(struct platform_device *pdev)
        if (ret)
                goto exit_nfc_init;
 
+       pm_runtime_mark_last_busy(&pdev->dev);
+       pm_runtime_put_autosuspend(&pdev->dev);
+
        dev_info(this->dev, "driver registered.\n");
 
        return 0;
 
 exit_nfc_init:
+       pm_runtime_put(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
        release_resources(this);
 exit_acquire_resources:
 
@@ -2027,6 +2688,9 @@ static int gpmi_nand_remove(struct platform_device *pdev)
 {
        struct gpmi_nand_data *this = platform_get_drvdata(pdev);
 
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+
        nand_release(&this->nand);
        gpmi_free_dma_buffer(this);
        release_resources(this);
@@ -2069,8 +2733,23 @@ static int gpmi_pm_resume(struct device *dev)
 }
 #endif /* CONFIG_PM_SLEEP */
 
+static int __maybe_unused gpmi_runtime_suspend(struct device *dev)
+{
+       struct gpmi_nand_data *this = dev_get_drvdata(dev);
+
+       return __gpmi_enable_clk(this, false);
+}
+
+static int __maybe_unused gpmi_runtime_resume(struct device *dev)
+{
+       struct gpmi_nand_data *this = dev_get_drvdata(dev);
+
+       return __gpmi_enable_clk(this, true);
+}
+
 static const struct dev_pm_ops gpmi_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(gpmi_pm_suspend, gpmi_pm_resume)
+       SET_RUNTIME_PM_OPS(gpmi_runtime_suspend, gpmi_runtime_resume, NULL)
 };
 
 static struct platform_driver gpmi_nand_driver = {
index a804a4a..fdc5ed7 100644 (file)
@@ -103,6 +103,14 @@ struct gpmi_nfc_hardware_timing {
        u32 ctrl1n;
 };
 
+#define GPMI_MAX_TRANSFERS     8
+
+struct gpmi_transfer {
+       u8 cmdbuf[8];
+       struct scatterlist sgl;
+       enum dma_data_direction direction;
+};
+
 struct gpmi_nand_data {
        /* Devdata */
        const struct gpmi_devdata *devdata;
@@ -126,25 +134,18 @@ struct gpmi_nand_data {
        struct boot_rom_geometry rom_geometry;
 
        /* MTD / NAND */
+       struct nand_controller  base;
        struct nand_chip        nand;
 
-       /* General-use Variables */
-       int                     current_chip;
-       unsigned int            command_length;
+       struct gpmi_transfer    transfers[GPMI_MAX_TRANSFERS];
+       int                     ntransfers;
 
-       struct scatterlist      cmd_sgl;
-       char                    *cmd_buffer;
+       bool                    bch;
+       uint32_t                bch_flashlayout0;
+       uint32_t                bch_flashlayout1;
 
-       struct scatterlist      data_sgl;
        char                    *data_buffer_dma;
 
-       void                    *page_buffer_virt;
-       dma_addr_t              page_buffer_phys;
-       unsigned int            page_buffer_size;
-
-       void                    *payload_virt;
-       dma_addr_t              payload_phys;
-
        void                    *auxiliary_virt;
        dma_addr_t              auxiliary_phys;
 
@@ -154,45 +155,8 @@ struct gpmi_nand_data {
 #define DMA_CHANS              8
        struct dma_chan         *dma_chans[DMA_CHANS];
        struct completion       dma_done;
-
-       /* private */
-       void                    *private;
 };
 
-/* Common Services */
-int common_nfc_set_geometry(struct gpmi_nand_data *);
-struct dma_chan *get_dma_chan(struct gpmi_nand_data *);
-bool prepare_data_dma(struct gpmi_nand_data *, const void *buf, int len,
-                     enum dma_data_direction dr);
-int start_dma_without_bch_irq(struct gpmi_nand_data *,
-                             struct dma_async_tx_descriptor *);
-int start_dma_with_bch_irq(struct gpmi_nand_data *,
-                          struct dma_async_tx_descriptor *);
-
-/* GPMI-NAND helper function library */
-int gpmi_init(struct gpmi_nand_data *);
-void gpmi_clear_bch(struct gpmi_nand_data *);
-void gpmi_dump_info(struct gpmi_nand_data *);
-int bch_set_geometry(struct gpmi_nand_data *);
-int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip);
-int gpmi_send_command(struct gpmi_nand_data *);
-int gpmi_enable_clk(struct gpmi_nand_data *this);
-int gpmi_disable_clk(struct gpmi_nand_data *this);
-int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr,
-                             const struct nand_data_interface *conf);
-void gpmi_nfc_apply_timings(struct gpmi_nand_data *this);
-int gpmi_read_data(struct gpmi_nand_data *, void *buf, int len);
-int gpmi_send_data(struct gpmi_nand_data *, const void *buf, int len);
-
-int gpmi_send_page(struct gpmi_nand_data *,
-                  dma_addr_t payload, dma_addr_t auxiliary);
-int gpmi_read_page(struct gpmi_nand_data *,
-                  dma_addr_t payload, dma_addr_t auxiliary);
-
-void gpmi_copy_bits(u8 *dst, size_t dst_bit_off,
-                   const u8 *src, size_t src_bit_off,
-                   size_t nbits);
-
 /* BCH : Status Block Completion Codes */
 #define STATUS_GOOD            0x00
 #define STATUS_ERASED          0xff
index 0f90e06..74595b6 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0 OR MIT
 /*
  * MTK ECC controller driver.
  * Copyright (C) 2016  MediaTek Inc.
@@ -596,4 +596,4 @@ module_platform_driver(mtk_ecc_driver);
 
 MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>");
 MODULE_DESCRIPTION("MTK Nand ECC Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("Dual MIT/GPL");
index aa52e94..0e48c36 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
 /*
  * MTK SDG1 ECC controller
  *
index dceff28..373d47d 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0 OR MIT
 /*
  * MTK NAND Flash controller driver.
  * Copyright (C) 2016 MediaTek Inc.
 #define NFI_FDMM(x)            (0xA4 + (x) * sizeof(u32) * 2)
 #define NFI_FDM_MAX_SIZE       (8)
 #define NFI_FDM_MIN_SIZE       (1)
+#define NFI_DEBUG_CON1         (0x220)
+#define                STROBE_MASK             GENMASK(4, 3)
+#define                STROBE_SHIFT            (3)
+#define                MAX_STROBE_DLY          (3)
 #define NFI_MASTER_STA         (0x224)
 #define                MASTER_STA_MASK         (0x0FFF)
 #define NFI_EMPTY_THRESH       (0x23C)
@@ -150,6 +154,8 @@ struct mtk_nfc {
        struct list_head chips;
 
        u8 *buffer;
+
+       unsigned long assigned_cs;
 };
 
 /*
@@ -500,7 +506,8 @@ static int mtk_nfc_setup_data_interface(struct nand_chip *chip, int csline,
 {
        struct mtk_nfc *nfc = nand_get_controller_data(chip);
        const struct nand_sdr_timings *timings;
-       u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt;
+       u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst = 0, trlt = 0;
+       u32 temp, tsel = 0;
 
        timings = nand_get_sdr_timings(conf);
        if (IS_ERR(timings))
@@ -536,14 +543,53 @@ static int mtk_nfc_setup_data_interface(struct nand_chip *chip, int csline,
        twh = DIV_ROUND_UP(twh * rate, 1000000) - 1;
        twh &= 0xf;
 
-       twst = timings->tWP_min / 1000;
+       /* Calculate real WE#/RE# hold time in nanosecond */
+       temp = (twh + 1) * 1000000 / rate;
+       /* nanosecond to picosecond */
+       temp *= 1000;
+
+       /*
+        * WE# low level time should be expaned to meet WE# pulse time
+        * and WE# cycle time at the same time.
+        */
+       if (temp < timings->tWC_min)
+               twst = timings->tWC_min - temp;
+       twst = max(timings->tWP_min, twst) / 1000;
        twst = DIV_ROUND_UP(twst * rate, 1000000) - 1;
        twst &= 0xf;
 
-       trlt = max(timings->tREA_max, timings->tRP_min) / 1000;
+       /*
+        * RE# low level time should be expaned to meet RE# pulse time
+        * and RE# cycle time at the same time.
+        */
+       if (temp < timings->tRC_min)
+               trlt = timings->tRC_min - temp;
+       trlt = max(trlt, timings->tRP_min) / 1000;
        trlt = DIV_ROUND_UP(trlt * rate, 1000000) - 1;
        trlt &= 0xf;
 
+       /* Calculate RE# pulse time in nanosecond. */
+       temp = (trlt + 1) * 1000000 / rate;
+       /* nanosecond to picosecond */
+       temp *= 1000;
+       /*
+        * If RE# access time is bigger than RE# pulse time,
+        * delay sampling data timing.
+        */
+       if (temp < timings->tREA_max) {
+               tsel = timings->tREA_max / 1000;
+               tsel = DIV_ROUND_UP(tsel * rate, 1000000);
+               tsel -= (trlt + 1);
+               if (tsel > MAX_STROBE_DLY) {
+                       trlt += tsel - MAX_STROBE_DLY;
+                       tsel = MAX_STROBE_DLY;
+               }
+       }
+       temp = nfi_readl(nfc, NFI_DEBUG_CON1);
+       temp &= ~STROBE_MASK;
+       temp |= tsel << STROBE_SHIFT;
+       nfi_writel(nfc, temp, NFI_DEBUG_CON1);
+
        /*
         * ACCON: access timing control register
         * -------------------------------------
@@ -835,19 +881,21 @@ static int mtk_nfc_write_oob_std(struct nand_chip *chip, int page)
        return mtk_nfc_write_page_raw(chip, NULL, 1, page);
 }
 
-static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 sectors)
+static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 start,
+                                   u32 sectors)
 {
        struct nand_chip *chip = mtd_to_nand(mtd);
        struct mtk_nfc *nfc = nand_get_controller_data(chip);
        struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
        struct mtk_ecc_stats stats;
+       u32 reg_size = mtk_nand->fdm.reg_size;
        int rc, i;
 
        rc = nfi_readl(nfc, NFI_STA) & STA_EMP_PAGE;
        if (rc) {
                memset(buf, 0xff, sectors * chip->ecc.size);
                for (i = 0; i < sectors; i++)
-                       memset(oob_ptr(chip, i), 0xff, mtk_nand->fdm.reg_size);
+                       memset(oob_ptr(chip, start + i), 0xff, reg_size);
                return 0;
        }
 
@@ -867,7 +915,7 @@ static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
        u32 spare = mtk_nand->spare_per_sector;
        u32 column, sectors, start, end, reg;
        dma_addr_t addr;
-       int bitflips;
+       int bitflips = 0;
        size_t len;
        u8 *buf;
        int rc;
@@ -934,14 +982,11 @@ static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
        if (rc < 0) {
                dev_err(nfc->dev, "subpage done timeout\n");
                bitflips = -EIO;
-       } else {
-               bitflips = 0;
-               if (!raw) {
-                       rc = mtk_ecc_wait_done(nfc->ecc, ECC_DECODE);
-                       bitflips = rc < 0 ? -ETIMEDOUT :
-                               mtk_nfc_update_ecc_stats(mtd, buf, sectors);
-                       mtk_nfc_read_fdm(chip, start, sectors);
-               }
+       } else if (!raw) {
+               rc = mtk_ecc_wait_done(nfc->ecc, ECC_DECODE);
+               bitflips = rc < 0 ? -ETIMEDOUT :
+                       mtk_nfc_update_ecc_stats(mtd, buf, start, sectors);
+               mtk_nfc_read_fdm(chip, start, sectors);
        }
 
        dma_unmap_single(nfc->dev, addr, len, DMA_FROM_DEVICE);
@@ -1315,6 +1360,17 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
                        dev_err(dev, "reg property failure : %d\n", ret);
                        return ret;
                }
+
+               if (tmp >= MTK_NAND_MAX_NSELS) {
+                       dev_err(dev, "invalid CS: %u\n", tmp);
+                       return -EINVAL;
+               }
+
+               if (test_and_set_bit(tmp, &nfc->assigned_cs)) {
+                       dev_err(dev, "CS %u already assigned\n", tmp);
+                       return -EINVAL;
+               }
+
                chip->sels[i] = tmp;
        }
 
@@ -1589,6 +1645,6 @@ static struct platform_driver mtk_nfc_driver = {
 
 module_platform_driver(mtk_nfc_driver);
 
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("Dual MIT/GPL");
 MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>");
 MODULE_DESCRIPTION("MTK Nand Flash Controller Driver");
index 6eb1312..91f046d 100644 (file)
@@ -2111,35 +2111,7 @@ static void nand_op_parser_trace(const struct nand_op_parser_ctx *ctx)
                if (instr == &ctx->subop.instrs[0])
                        prefix = "    ->";
 
-               switch (instr->type) {
-               case NAND_OP_CMD_INSTR:
-                       pr_debug("%sCMD      [0x%02x]\n", prefix,
-                                instr->ctx.cmd.opcode);
-                       break;
-               case NAND_OP_ADDR_INSTR:
-                       pr_debug("%sADDR     [%d cyc: %*ph]\n", prefix,
-                                instr->ctx.addr.naddrs,
-                                instr->ctx.addr.naddrs < 64 ?
-                                instr->ctx.addr.naddrs : 64,
-                                instr->ctx.addr.addrs);
-                       break;
-               case NAND_OP_DATA_IN_INSTR:
-                       pr_debug("%sDATA_IN  [%d B%s]\n", prefix,
-                                instr->ctx.data.len,
-                                instr->ctx.data.force_8bit ?
-                                ", force 8-bit" : "");
-                       break;
-               case NAND_OP_DATA_OUT_INSTR:
-                       pr_debug("%sDATA_OUT [%d B%s]\n", prefix,
-                                instr->ctx.data.len,
-                                instr->ctx.data.force_8bit ?
-                                ", force 8-bit" : "");
-                       break;
-               case NAND_OP_WAITRDY_INSTR:
-                       pr_debug("%sWAITRDY  [max %d ms]\n", prefix,
-                                instr->ctx.waitrdy.timeout_ms);
-                       break;
-               }
+               nand_op_trace(prefix, instr);
 
                if (instr == &ctx->subop.instrs[ctx->subop.ninstrs - 1])
                        prefix = "      ";
@@ -2152,6 +2124,22 @@ static void nand_op_parser_trace(const struct nand_op_parser_ctx *ctx)
 }
 #endif
 
+static int nand_op_parser_cmp_ctx(const struct nand_op_parser_ctx *a,
+                                 const struct nand_op_parser_ctx *b)
+{
+       if (a->subop.ninstrs < b->subop.ninstrs)
+               return -1;
+       else if (a->subop.ninstrs > b->subop.ninstrs)
+               return 1;
+
+       if (a->subop.last_instr_end_off < b->subop.last_instr_end_off)
+               return -1;
+       else if (a->subop.last_instr_end_off > b->subop.last_instr_end_off)
+               return 1;
+
+       return 0;
+}
+
 /**
  * nand_op_parser_exec_op - exec_op parser
  * @chip: the NAND chip
@@ -2186,32 +2174,40 @@ int nand_op_parser_exec_op(struct nand_chip *chip,
        unsigned int i;
 
        while (ctx.subop.instrs < op->instrs + op->ninstrs) {
-               int ret;
+               const struct nand_op_parser_pattern *pattern;
+               struct nand_op_parser_ctx best_ctx;
+               int ret, best_pattern = -1;
 
                for (i = 0; i < parser->npatterns; i++) {
-                       const struct nand_op_parser_pattern *pattern;
+                       struct nand_op_parser_ctx test_ctx = ctx;
 
                        pattern = &parser->patterns[i];
-                       if (!nand_op_parser_match_pat(pattern, &ctx))
+                       if (!nand_op_parser_match_pat(pattern, &test_ctx))
                                continue;
 
-                       nand_op_parser_trace(&ctx);
-
-                       if (check_only)
-                               break;
-
-                       ret = pattern->exec(chip, &ctx.subop);
-                       if (ret)
-                               return ret;
+                       if (best_pattern >= 0 &&
+                           nand_op_parser_cmp_ctx(&test_ctx, &best_ctx) <= 0)
+                               continue;
 
-                       break;
+                       best_pattern = i;
+                       best_ctx = test_ctx;
                }
 
-               if (i == parser->npatterns) {
+               if (best_pattern < 0) {
                        pr_debug("->exec_op() parser: pattern not found!\n");
                        return -ENOTSUPP;
                }
 
+               ctx = best_ctx;
+               nand_op_parser_trace(&ctx);
+
+               if (!check_only) {
+                       pattern = &parser->patterns[best_pattern];
+                       ret = pattern->exec(chip, &ctx.subop);
+                       if (ret)
+                               return ret;
+               }
+
                /*
                 * Update the context structure by pointing to the start of the
                 * next subop.
index 55aa4c1..1752731 100644 (file)
@@ -170,7 +170,7 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
                goto fail;
        }
 
-       nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL);
+       nbc->eccmask = kzalloc(eccbytes, GFP_KERNEL);
        nbc->errloc = kmalloc_array(t, sizeof(*nbc->errloc), GFP_KERNEL);
        if (!nbc->eccmask || !nbc->errloc)
                goto fail;
@@ -182,7 +182,6 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
                goto fail;
 
        memset(erased_page, 0xff, eccsize);
-       memset(nbc->eccmask, 0, eccbytes);
        encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask);
        kfree(erased_page);
 
index fad57c3..58511ae 100644 (file)
@@ -8,6 +8,50 @@
 
 #include "internals.h"
 
+#define MACRONIX_READ_RETRY_BIT BIT(0)
+#define MACRONIX_NUM_READ_RETRY_MODES 6
+
+struct nand_onfi_vendor_macronix {
+       u8 reserved;
+       u8 reliability_func;
+} __packed;
+
+static int macronix_nand_setup_read_retry(struct nand_chip *chip, int mode)
+{
+       u8 feature[ONFI_SUBFEATURE_PARAM_LEN];
+
+       if (!chip->parameters.supports_set_get_features ||
+           !test_bit(ONFI_FEATURE_ADDR_READ_RETRY,
+                     chip->parameters.set_feature_list))
+               return -ENOTSUPP;
+
+       feature[0] = mode;
+       return nand_set_features(chip, ONFI_FEATURE_ADDR_READ_RETRY, feature);
+}
+
+static void macronix_nand_onfi_init(struct nand_chip *chip)
+{
+       struct nand_parameters *p = &chip->parameters;
+       struct nand_onfi_vendor_macronix *mxic;
+
+       if (!p->onfi)
+               return;
+
+       mxic = (struct nand_onfi_vendor_macronix *)p->onfi->vendor;
+       if ((mxic->reliability_func & MACRONIX_READ_RETRY_BIT) == 0)
+               return;
+
+       chip->read_retries = MACRONIX_NUM_READ_RETRY_MODES;
+       chip->setup_read_retry = macronix_nand_setup_read_retry;
+
+       if (p->supports_set_get_features) {
+               bitmap_set(p->set_feature_list,
+                          ONFI_FEATURE_ADDR_READ_RETRY, 1);
+               bitmap_set(p->get_feature_list,
+                          ONFI_FEATURE_ADDR_READ_RETRY, 1);
+       }
+}
+
 /*
  * Macronix AC series does not support using SET/GET_FEATURES to change
  * the timings unlike what is declared in the parameter page. Unflag
@@ -56,6 +100,7 @@ static int macronix_nand_init(struct nand_chip *chip)
                chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;
 
        macronix_nand_fix_broken_get_timings(chip);
+       macronix_nand_onfi_init(chip);
 
        return 0;
 }
index 999ca6a..e63acc0 100644 (file)
@@ -37,6 +37,8 @@
 /* Max ECC buffer length */
 #define FMC2_MAX_ECC_BUF_LEN           (FMC2_BCHDSRS_LEN * FMC2_MAX_SG)
 
+#define FMC2_TIMEOUT_MS                        1000
+
 /* Timings */
 #define FMC2_THIZ                      1
 #define FMC2_TIO                       8000
@@ -530,7 +532,8 @@ static int stm32_fmc2_ham_calculate(struct nand_chip *chip, const u8 *data,
        int ret;
 
        ret = readl_relaxed_poll_timeout(fmc2->io_base + FMC2_SR,
-                                        sr, sr & FMC2_SR_NWRF, 10, 1000);
+                                        sr, sr & FMC2_SR_NWRF, 10,
+                                        FMC2_TIMEOUT_MS);
        if (ret) {
                dev_err(fmc2->dev, "ham timeout\n");
                return ret;
@@ -611,7 +614,7 @@ static int stm32_fmc2_bch_calculate(struct nand_chip *chip, const u8 *data,
 
        /* Wait until the BCH code is ready */
        if (!wait_for_completion_timeout(&fmc2->complete,
-                                        msecs_to_jiffies(1000))) {
+                                        msecs_to_jiffies(FMC2_TIMEOUT_MS))) {
                dev_err(fmc2->dev, "bch timeout\n");
                stm32_fmc2_disable_bch_irq(fmc2);
                return -ETIMEDOUT;
@@ -696,7 +699,7 @@ static int stm32_fmc2_bch_correct(struct nand_chip *chip, u8 *dat,
 
        /* Wait until the decoding error is ready */
        if (!wait_for_completion_timeout(&fmc2->complete,
-                                        msecs_to_jiffies(1000))) {
+                                        msecs_to_jiffies(FMC2_TIMEOUT_MS))) {
                dev_err(fmc2->dev, "bch timeout\n");
                stm32_fmc2_disable_bch_irq(fmc2);
                return -ETIMEDOUT;
@@ -969,7 +972,7 @@ static int stm32_fmc2_xfer(struct nand_chip *chip, const u8 *buf,
 
        /* Wait end of sequencer transfer */
        if (!wait_for_completion_timeout(&fmc2->complete,
-                                        msecs_to_jiffies(1000))) {
+                                        msecs_to_jiffies(FMC2_TIMEOUT_MS))) {
                dev_err(fmc2->dev, "seq timeout\n");
                stm32_fmc2_disable_seq_irq(fmc2);
                dmaengine_terminate_all(dma_ch);
@@ -981,7 +984,7 @@ static int stm32_fmc2_xfer(struct nand_chip *chip, const u8 *buf,
 
        /* Wait DMA data transfer completion */
        if (!wait_for_completion_timeout(&fmc2->dma_data_complete,
-                                        msecs_to_jiffies(100))) {
+                                        msecs_to_jiffies(FMC2_TIMEOUT_MS))) {
                dev_err(fmc2->dev, "data DMA timeout\n");
                dmaengine_terminate_all(dma_ch);
                ret = -ETIMEDOUT;
@@ -990,7 +993,7 @@ static int stm32_fmc2_xfer(struct nand_chip *chip, const u8 *buf,
        /* Wait DMA ECC transfer completion */
        if (!write_data && !raw) {
                if (!wait_for_completion_timeout(&fmc2->dma_ecc_complete,
-                                                msecs_to_jiffies(100))) {
+                                       msecs_to_jiffies(FMC2_TIMEOUT_MS))) {
                        dev_err(fmc2->dev, "ECC DMA timeout\n");
                        dmaengine_terminate_all(fmc2->dma_ecc_ch);
                        ret = -ETIMEDOUT;
@@ -1909,6 +1912,12 @@ static int stm32_fmc2_probe(struct platform_device *pdev)
        }
 
        irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               if (irq != -EPROBE_DEFER)
+                       dev_err(dev, "IRQ error missing or invalid\n");
+               return irq;
+       }
+
        ret = devm_request_irq(dev, irq, stm32_fmc2_irq, 0,
                               dev_name(dev), fmc2);
        if (ret) {
index 7531250..9662b9c 100644 (file)
@@ -1,3 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
-spinand-objs := core.o gigadevice.o macronix.o micron.o toshiba.o winbond.o
+spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o
 obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
index 4c15bb5..89f6bee 100644 (file)
@@ -511,12 +511,12 @@ static int spinand_mtd_read(struct mtd_info *mtd, loff_t from,
                if (ret == -EBADMSG) {
                        ecc_failed = true;
                        mtd->ecc_stats.failed++;
-                       ret = 0;
                } else {
                        mtd->ecc_stats.corrected += ret;
                        max_bitflips = max_t(unsigned int, max_bitflips, ret);
                }
 
+               ret = 0;
                ops->retlen += iter.req.datalen;
                ops->oobretlen += iter.req.ooblen;
        }
@@ -757,6 +757,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
        &gigadevice_spinand_manufacturer,
        &macronix_spinand_manufacturer,
        &micron_spinand_manufacturer,
+       &paragon_spinand_manufacturer,
        &toshiba_spinand_manufacturer,
        &winbond_spinand_manufacturer,
 };
@@ -845,7 +846,7 @@ spinand_select_op_variant(struct spinand_device *spinand,
  */
 int spinand_match_and_init(struct spinand_device *spinand,
                           const struct spinand_info *table,
-                          unsigned int table_size, u8 devid)
+                          unsigned int table_size, u16 devid)
 {
        struct nand_device *nand = spinand_to_nand(spinand);
        unsigned int i;
index e6c6460..e99d425 100644 (file)
@@ -9,11 +9,17 @@
 #include <linux/mtd/spinand.h>
 
 #define SPINAND_MFR_GIGADEVICE                 0xC8
+
 #define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS     (1 << 4)
 #define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS       (3 << 4)
 
 #define GD5FXGQ4UEXXG_REG_STATUS2              0xf0
 
+#define GD5FXGQ4UXFXXG_STATUS_ECC_MASK         (7 << 4)
+#define GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS  (0 << 4)
+#define GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS (1 << 4)
+#define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR  (7 << 4)
+
 static SPINAND_OP_VARIANTS(read_cache_variants,
                SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
                SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
@@ -22,6 +28,14 @@ static SPINAND_OP_VARIANTS(read_cache_variants,
                SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
                SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
 
+static SPINAND_OP_VARIANTS(read_cache_variants_f,
+               SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_OP_3A(true, 0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_OP_3A(false, 0, 0, NULL, 0));
+
 static SPINAND_OP_VARIANTS(write_cache_variants,
                SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
                SPINAND_PROG_LOAD(true, 0, NULL, 0));
@@ -59,6 +73,11 @@ static int gd5fxgq4xa_ooblayout_free(struct mtd_info *mtd, int section,
        return 0;
 }
 
+static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
+       .ecc = gd5fxgq4xa_ooblayout_ecc,
+       .free = gd5fxgq4xa_ooblayout_free,
+};
+
 static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
                                         u8 status)
 {
@@ -83,7 +102,7 @@ static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
        return -EINVAL;
 }
 
-static int gd5fxgq4uexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
+static int gd5fxgq4_variant2_ooblayout_ecc(struct mtd_info *mtd, int section,
                                       struct mtd_oob_region *region)
 {
        if (section)
@@ -95,7 +114,7 @@ static int gd5fxgq4uexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
        return 0;
 }
 
-static int gd5fxgq4uexxg_ooblayout_free(struct mtd_info *mtd, int section,
+static int gd5fxgq4_variant2_ooblayout_free(struct mtd_info *mtd, int section,
                                        struct mtd_oob_region *region)
 {
        if (section)
@@ -108,6 +127,11 @@ static int gd5fxgq4uexxg_ooblayout_free(struct mtd_info *mtd, int section,
        return 0;
 }
 
+static const struct mtd_ooblayout_ops gd5fxgq4_variant2_ooblayout = {
+       .ecc = gd5fxgq4_variant2_ooblayout_ecc,
+       .free = gd5fxgq4_variant2_ooblayout_free,
+};
+
 static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
                                        u8 status)
 {
@@ -150,15 +174,25 @@ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
        return -EINVAL;
 }
 
-static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
-       .ecc = gd5fxgq4xa_ooblayout_ecc,
-       .free = gd5fxgq4xa_ooblayout_free,
-};
+static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand,
+                                       u8 status)
+{
+       switch (status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) {
+       case GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS:
+               return 0;
 
-static const struct mtd_ooblayout_ops gd5fxgq4uexxg_ooblayout = {
-       .ecc = gd5fxgq4uexxg_ooblayout_ecc,
-       .free = gd5fxgq4uexxg_ooblayout_free,
-};
+       case GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS:
+               return 3;
+
+       case GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR:
+               return -EBADMSG;
+
+       default: /* (2 << 4) through (6 << 4) are 4-8 corrected errors */
+               return ((status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) >> 4) + 2;
+       }
+
+       return -EINVAL;
+}
 
 static const struct spinand_info gigadevice_spinand_table[] = {
        SPINAND_INFO("GD5F1GQ4xA", 0xF1,
@@ -195,25 +229,40 @@ static const struct spinand_info gigadevice_spinand_table[] = {
                                              &write_cache_variants,
                                              &update_cache_variants),
                     0,
-                    SPINAND_ECCINFO(&gd5fxgq4uexxg_ooblayout,
+                    SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout,
                                     gd5fxgq4uexxg_ecc_get_status)),
+       SPINAND_INFO("GD5F1GQ4UFxxG", 0xb148,
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    0,
+                    SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout,
+                                    gd5fxgq4ufxxg_ecc_get_status)),
 };
 
 static int gigadevice_spinand_detect(struct spinand_device *spinand)
 {
        u8 *id = spinand->id.data;
+       u16 did;
        int ret;
 
        /*
-        * For GD NANDs, There is an address byte needed to shift in before IDs
-        * are read out, so the first byte in raw_id is dummy.
+        * Earlier GDF5-series devices (A,E) return [0][MID][DID]
+        * Later (F) devices return [MID][DID1][DID2]
         */
-       if (id[1] != SPINAND_MFR_GIGADEVICE)
+
+       if (id[0] == SPINAND_MFR_GIGADEVICE)
+               did = (id[1] << 8) + id[2];
+       else if (id[0] == 0 && id[1] == SPINAND_MFR_GIGADEVICE)
+               did = id[2];
+       else
                return 0;
 
        ret = spinand_match_and_init(spinand, gigadevice_spinand_table,
                                     ARRAY_SIZE(gigadevice_spinand_table),
-                                    id[2]);
+                                    did);
        if (ret)
                return ret;
 
diff --git a/drivers/mtd/nand/spi/paragon.c b/drivers/mtd/nand/spi/paragon.c
new file mode 100644 (file)
index 0000000..5230768
--- /dev/null
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Jeff Kletsky
+ *
+ * Author: Jeff Kletsky <git-commits@allycomm.com>
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mtd/spinand.h>
+
+
+#define SPINAND_MFR_PARAGON    0xa1
+
+
+#define PN26G0XA_STATUS_ECC_BITMASK            (3 << 4)
+
+#define PN26G0XA_STATUS_ECC_NONE_DETECTED      (0 << 4)
+#define PN26G0XA_STATUS_ECC_1_7_CORRECTED      (1 << 4)
+#define PN26G0XA_STATUS_ECC_ERRORED            (2 << 4)
+#define PN26G0XA_STATUS_ECC_8_CORRECTED                (3 << 4)
+
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+               SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+               SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
+               SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+               SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
+               SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
+
+static int pn26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
+                                  struct mtd_oob_region *region)
+{
+       if (section > 3)
+               return -ERANGE;
+
+       region->offset = 6 + (15 * section); /* 4 BBM + 2 user bytes */
+       region->length = 13;
+
+       return 0;
+}
+
+static int pn26g0xa_ooblayout_free(struct mtd_info *mtd, int section,
+                                  struct mtd_oob_region *region)
+{
+       if (section > 4)
+               return -ERANGE;
+
+       if (section == 4) {
+               region->offset = 64;
+               region->length = 64;
+       } else {
+               region->offset = 4 + (15 * section);
+               region->length = 2;
+       }
+
+       return 0;
+}
+
+static int pn26g0xa_ecc_get_status(struct spinand_device *spinand,
+                                  u8 status)
+{
+       switch (status & PN26G0XA_STATUS_ECC_BITMASK) {
+       case PN26G0XA_STATUS_ECC_NONE_DETECTED:
+               return 0;
+
+       case PN26G0XA_STATUS_ECC_1_7_CORRECTED:
+               return 7;       /* Return upper limit by convention */
+
+       case PN26G0XA_STATUS_ECC_8_CORRECTED:
+               return 8;
+
+       case PN26G0XA_STATUS_ECC_ERRORED:
+               return -EBADMSG;
+
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+
+static const struct mtd_ooblayout_ops pn26g0xa_ooblayout = {
+       .ecc = pn26g0xa_ooblayout_ecc,
+       .free = pn26g0xa_ooblayout_free,
+};
+
+
+static const struct spinand_info paragon_spinand_table[] = {
+       SPINAND_INFO("PN26G01A", 0xe1,
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 21, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    0,
+                    SPINAND_ECCINFO(&pn26g0xa_ooblayout,
+                                    pn26g0xa_ecc_get_status)),
+       SPINAND_INFO("PN26G02A", 0xe2,
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 41, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    0,
+                    SPINAND_ECCINFO(&pn26g0xa_ooblayout,
+                                    pn26g0xa_ecc_get_status)),
+};
+
+static int paragon_spinand_detect(struct spinand_device *spinand)
+{
+       u8 *id = spinand->id.data;
+       int ret;
+
+       /* Read ID returns [0][MID][DID] */
+
+       if (id[1] != SPINAND_MFR_PARAGON)
+               return 0;
+
+       ret = spinand_match_and_init(spinand, paragon_spinand_table,
+                                    ARRAY_SIZE(paragon_spinand_table),
+                                    id[2]);
+       if (ret)
+               return ret;
+
+       return 1;
+}
+
+static const struct spinand_manufacturer_ops paragon_spinand_manuf_ops = {
+       .detect = paragon_spinand_detect,
+};
+
+const struct spinand_manufacturer paragon_spinand_manufacturer = {
+       .id = SPINAND_MFR_PARAGON,
+       .name = "Paragon",
+       .ops = &paragon_spinand_manuf_ops,
+};
index f24d768..752b6cf 100644 (file)
@@ -371,8 +371,7 @@ static int parse_afs_partitions(struct mtd_info *mtd,
 
 out_free_parts:
        while (i >= 0) {
-               if (parts[i].name)
-                       kfree(parts[i].name);
+               kfree(parts[i].name);
                i--;
        }
        kfree(parts);
index 8e14248..6de8327 100644 (file)
@@ -105,11 +105,4 @@ config SPI_INTEL_SPI_PLATFORM
          To compile this driver as a module, choose M here: the module
          will be called intel-spi-platform.
 
-config SPI_STM32_QUADSPI
-       tristate "STM32 Quad SPI controller"
-       depends on ARCH_STM32 || COMPILE_TEST
-       help
-         This enables support for the STM32 Quad SPI controller.
-         We only connect the NOR to this controller.
-
 endif # MTD_SPI_NOR
index 189a15c..9c5ed03 100644 (file)
@@ -8,4 +8,3 @@ obj-$(CONFIG_SPI_NXP_SPIFI)     += nxp-spifi.o
 obj-$(CONFIG_SPI_INTEL_SPI)    += intel-spi.o
 obj-$(CONFIG_SPI_INTEL_SPI_PCI)        += intel-spi-pci.o
 obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM)   += intel-spi-platform.o
-obj-$(CONFIG_SPI_STM32_QUADSPI)        += stm32-quadspi.o
index 67ade2c..67f15a1 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/reset.h>
 #include <linux/sched.h>
 #include <linux/spi/spi.h>
 #include <linux/timer.h>
@@ -1325,6 +1326,7 @@ static int cqspi_probe(struct platform_device *pdev)
        struct cqspi_st *cqspi;
        struct resource *res;
        struct resource *res_ahb;
+       struct reset_control *rstc, *rstc_ocp;
        const struct cqspi_driver_platdata *ddata;
        int ret;
        int irq;
@@ -1391,6 +1393,25 @@ static int cqspi_probe(struct platform_device *pdev)
                goto probe_clk_failed;
        }
 
+       /* Obtain QSPI reset control */
+       rstc = devm_reset_control_get_optional_exclusive(dev, "qspi");
+       if (IS_ERR(rstc)) {
+               dev_err(dev, "Cannot get QSPI reset.\n");
+               return PTR_ERR(rstc);
+       }
+
+       rstc_ocp = devm_reset_control_get_optional_exclusive(dev, "qspi-ocp");
+       if (IS_ERR(rstc_ocp)) {
+               dev_err(dev, "Cannot get QSPI OCP reset.\n");
+               return PTR_ERR(rstc_ocp);
+       }
+
+       reset_control_assert(rstc);
+       reset_control_deassert(rstc);
+
+       reset_control_assert(rstc_ocp);
+       reset_control_deassert(rstc_ocp);
+
        cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clk);
        ddata  = of_device_get_match_data(dev);
        if (ddata && (ddata->quirks & CQSPI_NEEDS_WR_DELAY))
index 5e23447..b83c4ab 100644 (file)
@@ -64,6 +64,7 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
        { PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info },
        { PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info },
        { PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info },
+       { PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info },
        { PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info },
        { PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info },
        { },
index 0c2ec1c..03cc788 100644 (file)
@@ -200,7 +200,7 @@ struct sfdp_header {
  *         register does not modify status register 2.
  * - 101b: QE is bit 1 of status register 2. Status register 1 is read using
  *         Read Status instruction 05h. Status register2 is read using
- *         instruction 35h. QE is set via Writ Status instruction 01h with
+ *         instruction 35h. QE is set via Write Status instruction 01h with
  *         two data bytes where bit 1 of the second byte is one.
  *         [...]
  */
@@ -1775,6 +1775,28 @@ static int spi_nor_spansion_clear_sr_bp(struct spi_nor *nor)
                .addr_width = 3,                                        \
                .flags = SPI_NOR_NO_FR | SPI_S3AN,
 
+static int
+is25lp256_post_bfpt_fixups(struct spi_nor *nor,
+                          const struct sfdp_parameter_header *bfpt_header,
+                          const struct sfdp_bfpt *bfpt,
+                          struct spi_nor_flash_parameter *params)
+{
+       /*
+        * IS25LP256 supports 4B opcodes, but the BFPT advertises a
+        * BFPT_DWORD1_ADDRESS_BYTES_3_ONLY address width.
+        * Overwrite the address width advertised by the BFPT.
+        */
+       if ((bfpt->dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) ==
+               BFPT_DWORD1_ADDRESS_BYTES_3_ONLY)
+               nor->addr_width = 4;
+
+       return 0;
+}
+
+static struct spi_nor_fixups is25lp256_fixups = {
+       .post_bfpt = is25lp256_post_bfpt_fixups,
+};
+
 static int
 mx25l25635_post_bfpt_fixups(struct spi_nor *nor,
                            const struct sfdp_parameter_header *bfpt_header,
@@ -1916,7 +1938,8 @@ static const struct flash_info spi_nor_ids[] = {
                        SECT_4K | SPI_NOR_DUAL_READ) },
        { "is25lp256",  INFO(0x9d6019, 0, 64 * 1024, 512,
                        SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-                       SPI_NOR_4B_OPCODES) },
+                       SPI_NOR_4B_OPCODES)
+                       .fixups = &is25lp256_fixups },
        { "is25wp032",  INFO(0x9d7016, 0, 64 * 1024,  64,
                        SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
        { "is25wp064",  INFO(0x9d7017, 0, 64 * 1024, 128,
@@ -1969,6 +1992,9 @@ static const struct flash_info spi_nor_ids[] = {
        { "n25q512ax3",  INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
        { "n25q00",      INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
        { "n25q00a",     INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
+       { "mt25ql02g",   INFO(0x20ba22, 0, 64 * 1024, 4096,
+                             SECT_4K | USE_FSR | SPI_NOR_QUAD_READ |
+                             NO_CHIP_ERASE) },
        { "mt25qu02g",   INFO(0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
 
        /* Micron */
@@ -2085,6 +2111,11 @@ static const struct flash_info spi_nor_ids[] = {
                        SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
        },
        { "w25x32", INFO(0xef3016, 0, 64 * 1024,  64, SECT_4K) },
+       {
+               "w25q16jv-im/jm", INFO(0xef7015, 0, 64 * 1024,  32,
+                       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+                       SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+       },
        { "w25q20cl", INFO(0xef4012, 0, 64 * 1024,  4, SECT_4K) },
        { "w25q20bw", INFO(0xef5012, 0, 64 * 1024,  4, SECT_4K) },
        { "w25q20ew", INFO(0xef6012, 0, 64 * 1024,  4, SECT_4K) },
@@ -2151,7 +2182,7 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
 
        tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
        if (tmp < 0) {
-               dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
+               dev_err(nor->dev, "error %d reading JEDEC ID\n", tmp);
                return ERR_PTR(tmp);
        }
 
diff --git a/drivers/mtd/spi-nor/stm32-quadspi.c b/drivers/mtd/spi-nor/stm32-quadspi.c
deleted file mode 100644 (file)
index 33534f9..0000000
+++ /dev/null
@@ -1,707 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Driver for stm32 quadspi controller
- *
- * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
- * Author(s): Ludovic Barre author <ludovic.barre@st.com>.
- */
-#include <linux/clk.h>
-#include <linux/errno.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/spi-nor.h>
-#include <linux/mutex.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/reset.h>
-#include <linux/sizes.h>
-
-#define QUADSPI_CR             0x00
-#define CR_EN                  BIT(0)
-#define CR_ABORT               BIT(1)
-#define CR_DMAEN               BIT(2)
-#define CR_TCEN                        BIT(3)
-#define CR_SSHIFT              BIT(4)
-#define CR_DFM                 BIT(6)
-#define CR_FSEL                        BIT(7)
-#define CR_FTHRES_SHIFT                8
-#define CR_FTHRES_MASK         GENMASK(12, 8)
-#define CR_FTHRES(n)           (((n) << CR_FTHRES_SHIFT) & CR_FTHRES_MASK)
-#define CR_TEIE                        BIT(16)
-#define CR_TCIE                        BIT(17)
-#define CR_FTIE                        BIT(18)
-#define CR_SMIE                        BIT(19)
-#define CR_TOIE                        BIT(20)
-#define CR_PRESC_SHIFT         24
-#define CR_PRESC_MASK          GENMASK(31, 24)
-#define CR_PRESC(n)            (((n) << CR_PRESC_SHIFT) & CR_PRESC_MASK)
-
-#define QUADSPI_DCR            0x04
-#define DCR_CSHT_SHIFT         8
-#define DCR_CSHT_MASK          GENMASK(10, 8)
-#define DCR_CSHT(n)            (((n) << DCR_CSHT_SHIFT) & DCR_CSHT_MASK)
-#define DCR_FSIZE_SHIFT                16
-#define DCR_FSIZE_MASK         GENMASK(20, 16)
-#define DCR_FSIZE(n)           (((n) << DCR_FSIZE_SHIFT) & DCR_FSIZE_MASK)
-
-#define QUADSPI_SR             0x08
-#define SR_TEF                 BIT(0)
-#define SR_TCF                 BIT(1)
-#define SR_FTF                 BIT(2)
-#define SR_SMF                 BIT(3)
-#define SR_TOF                 BIT(4)
-#define SR_BUSY                        BIT(5)
-#define SR_FLEVEL_SHIFT                8
-#define SR_FLEVEL_MASK         GENMASK(13, 8)
-
-#define QUADSPI_FCR            0x0c
-#define FCR_CTCF               BIT(1)
-
-#define QUADSPI_DLR            0x10
-
-#define QUADSPI_CCR            0x14
-#define CCR_INST_SHIFT         0
-#define CCR_INST_MASK          GENMASK(7, 0)
-#define CCR_INST(n)            (((n) << CCR_INST_SHIFT) & CCR_INST_MASK)
-#define CCR_IMODE_NONE         (0U << 8)
-#define CCR_IMODE_1            (1U << 8)
-#define CCR_IMODE_2            (2U << 8)
-#define CCR_IMODE_4            (3U << 8)
-#define CCR_ADMODE_NONE                (0U << 10)
-#define CCR_ADMODE_1           (1U << 10)
-#define CCR_ADMODE_2           (2U << 10)
-#define CCR_ADMODE_4           (3U << 10)
-#define CCR_ADSIZE_SHIFT       12
-#define CCR_ADSIZE_MASK                GENMASK(13, 12)
-#define CCR_ADSIZE(n)          (((n) << CCR_ADSIZE_SHIFT) & CCR_ADSIZE_MASK)
-#define CCR_ABMODE_NONE                (0U << 14)
-#define CCR_ABMODE_1           (1U << 14)
-#define CCR_ABMODE_2           (2U << 14)
-#define CCR_ABMODE_4           (3U << 14)
-#define CCR_ABSIZE_8           (0U << 16)
-#define CCR_ABSIZE_16          (1U << 16)
-#define CCR_ABSIZE_24          (2U << 16)
-#define CCR_ABSIZE_32          (3U << 16)
-#define CCR_DCYC_SHIFT         18
-#define CCR_DCYC_MASK          GENMASK(22, 18)
-#define CCR_DCYC(n)            (((n) << CCR_DCYC_SHIFT) & CCR_DCYC_MASK)
-#define CCR_DMODE_NONE         (0U << 24)
-#define CCR_DMODE_1            (1U << 24)
-#define CCR_DMODE_2            (2U << 24)
-#define CCR_DMODE_4            (3U << 24)
-#define CCR_FMODE_INDW         (0U << 26)
-#define CCR_FMODE_INDR         (1U << 26)
-#define CCR_FMODE_APM          (2U << 26)
-#define CCR_FMODE_MM           (3U << 26)
-
-#define QUADSPI_AR             0x18
-#define QUADSPI_ABR            0x1c
-#define QUADSPI_DR             0x20
-#define QUADSPI_PSMKR          0x24
-#define QUADSPI_PSMAR          0x28
-#define QUADSPI_PIR            0x2c
-#define QUADSPI_LPTR           0x30
-#define LPTR_DFT_TIMEOUT       0x10
-
-#define FSIZE_VAL(size)                (__fls(size) - 1)
-
-#define STM32_MAX_MMAP_SZ      SZ_256M
-#define STM32_MAX_NORCHIP      2
-
-#define STM32_QSPI_FIFO_SZ     32
-#define STM32_QSPI_FIFO_TIMEOUT_US 30000
-#define STM32_QSPI_BUSY_TIMEOUT_US 100000
-
-struct stm32_qspi_flash {
-       struct spi_nor nor;
-       struct stm32_qspi *qspi;
-       u32 cs;
-       u32 fsize;
-       u32 presc;
-       u32 read_mode;
-       bool registered;
-       u32 prefetch_limit;
-};
-
-struct stm32_qspi {
-       struct device *dev;
-       void __iomem *io_base;
-       void __iomem *mm_base;
-       resource_size_t mm_size;
-       u32 nor_num;
-       struct clk *clk;
-       u32 clk_rate;
-       struct stm32_qspi_flash flash[STM32_MAX_NORCHIP];
-       struct completion cmd_completion;
-
-       /*
-        * to protect device configuration, could be different between
-        * 2 flash access (bk1, bk2)
-        */
-       struct mutex lock;
-};
-
-struct stm32_qspi_cmd {
-       u8 addr_width;
-       u8 dummy;
-       bool tx_data;
-       u8 opcode;
-       u32 framemode;
-       u32 qspimode;
-       u32 addr;
-       size_t len;
-       void *buf;
-};
-
-static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi)
-{
-       u32 cr;
-       int err = 0;
-
-       if (readl_relaxed(qspi->io_base + QUADSPI_SR) & SR_TCF)
-               return 0;
-
-       reinit_completion(&qspi->cmd_completion);
-       cr = readl_relaxed(qspi->io_base + QUADSPI_CR);
-       writel_relaxed(cr | CR_TCIE, qspi->io_base + QUADSPI_CR);
-
-       if (!wait_for_completion_interruptible_timeout(&qspi->cmd_completion,
-                                                      msecs_to_jiffies(1000)))
-               err = -ETIMEDOUT;
-
-       writel_relaxed(cr, qspi->io_base + QUADSPI_CR);
-       return err;
-}
-
-static int stm32_qspi_wait_nobusy(struct stm32_qspi *qspi)
-{
-       u32 sr;
-
-       return readl_relaxed_poll_timeout(qspi->io_base + QUADSPI_SR, sr,
-                                         !(sr & SR_BUSY), 10,
-                                         STM32_QSPI_BUSY_TIMEOUT_US);
-}
-
-static void stm32_qspi_set_framemode(struct spi_nor *nor,
-                                    struct stm32_qspi_cmd *cmd, bool read)
-{
-       u32 dmode = CCR_DMODE_1;
-
-       cmd->framemode = CCR_IMODE_1;
-
-       if (read) {
-               switch (nor->read_proto) {
-               default:
-               case SNOR_PROTO_1_1_1:
-                       dmode = CCR_DMODE_1;
-                       break;
-               case SNOR_PROTO_1_1_2:
-                       dmode = CCR_DMODE_2;
-                       break;
-               case SNOR_PROTO_1_1_4:
-                       dmode = CCR_DMODE_4;
-                       break;
-               }
-       }
-
-       cmd->framemode |= cmd->tx_data ? dmode : 0;
-       cmd->framemode |= cmd->addr_width ? CCR_ADMODE_1 : 0;
-}
-
-static void stm32_qspi_read_fifo(u8 *val, void __iomem *addr)
-{
-       *val = readb_relaxed(addr);
-}
-
-static void stm32_qspi_write_fifo(u8 *val, void __iomem *addr)
-{
-       writeb_relaxed(*val, addr);
-}
-
-static int stm32_qspi_tx_poll(struct stm32_qspi *qspi,
-                             const struct stm32_qspi_cmd *cmd)
-{
-       void (*tx_fifo)(u8 *, void __iomem *);
-       u32 len = cmd->len, sr;
-       u8 *buf = cmd->buf;
-       int ret;
-
-       if (cmd->qspimode == CCR_FMODE_INDW)
-               tx_fifo = stm32_qspi_write_fifo;
-       else
-               tx_fifo = stm32_qspi_read_fifo;
-
-       while (len--) {
-               ret = readl_relaxed_poll_timeout(qspi->io_base + QUADSPI_SR,
-                                                sr, (sr & SR_FTF), 10,
-                                                STM32_QSPI_FIFO_TIMEOUT_US);
-               if (ret) {
-                       dev_err(qspi->dev, "fifo timeout (stat:%#x)\n", sr);
-                       return ret;
-               }
-               tx_fifo(buf++, qspi->io_base + QUADSPI_DR);
-       }
-
-       return 0;
-}
-
-static int stm32_qspi_tx_mm(struct stm32_qspi *qspi,
-                           const struct stm32_qspi_cmd *cmd)
-{
-       memcpy_fromio(cmd->buf, qspi->mm_base + cmd->addr, cmd->len);
-       return 0;
-}
-
-static int stm32_qspi_tx(struct stm32_qspi *qspi,
-                        const struct stm32_qspi_cmd *cmd)
-{
-       if (!cmd->tx_data)
-               return 0;
-
-       if (cmd->qspimode == CCR_FMODE_MM)
-               return stm32_qspi_tx_mm(qspi, cmd);
-
-       return stm32_qspi_tx_poll(qspi, cmd);
-}
-
-static int stm32_qspi_send(struct stm32_qspi_flash *flash,
-                          const struct stm32_qspi_cmd *cmd)
-{
-       struct stm32_qspi *qspi = flash->qspi;
-       u32 ccr, dcr, cr;
-       u32 last_byte;
-       int err;
-
-       err = stm32_qspi_wait_nobusy(qspi);
-       if (err)
-               goto abort;
-
-       dcr = readl_relaxed(qspi->io_base + QUADSPI_DCR) & ~DCR_FSIZE_MASK;
-       dcr |= DCR_FSIZE(flash->fsize);
-       writel_relaxed(dcr, qspi->io_base + QUADSPI_DCR);
-
-       cr = readl_relaxed(qspi->io_base + QUADSPI_CR);
-       cr &= ~CR_PRESC_MASK & ~CR_FSEL;
-       cr |= CR_PRESC(flash->presc);
-       cr |= flash->cs ? CR_FSEL : 0;
-       writel_relaxed(cr, qspi->io_base + QUADSPI_CR);
-
-       if (cmd->tx_data)
-               writel_relaxed(cmd->len - 1, qspi->io_base + QUADSPI_DLR);
-
-       ccr = cmd->framemode | cmd->qspimode;
-
-       if (cmd->dummy)
-               ccr |= CCR_DCYC(cmd->dummy);
-
-       if (cmd->addr_width)
-               ccr |= CCR_ADSIZE(cmd->addr_width - 1);
-
-       ccr |= CCR_INST(cmd->opcode);
-       writel_relaxed(ccr, qspi->io_base + QUADSPI_CCR);
-
-       if (cmd->addr_width && cmd->qspimode != CCR_FMODE_MM)
-               writel_relaxed(cmd->addr, qspi->io_base + QUADSPI_AR);
-
-       err = stm32_qspi_tx(qspi, cmd);
-       if (err)
-               goto abort;
-
-       if (cmd->qspimode != CCR_FMODE_MM) {
-               err = stm32_qspi_wait_cmd(qspi);
-               if (err)
-                       goto abort;
-               writel_relaxed(FCR_CTCF, qspi->io_base + QUADSPI_FCR);
-       } else {
-               last_byte = cmd->addr + cmd->len;
-               if (last_byte > flash->prefetch_limit)
-                       goto abort;
-       }
-
-       return err;
-
-abort:
-       cr = readl_relaxed(qspi->io_base + QUADSPI_CR) | CR_ABORT;
-       writel_relaxed(cr, qspi->io_base + QUADSPI_CR);
-
-       if (err)
-               dev_err(qspi->dev, "%s abort err:%d\n", __func__, err);
-
-       return err;
-}
-
-static int stm32_qspi_read_reg(struct spi_nor *nor,
-                              u8 opcode, u8 *buf, int len)
-{
-       struct stm32_qspi_flash *flash = nor->priv;
-       struct device *dev = flash->qspi->dev;
-       struct stm32_qspi_cmd cmd;
-
-       dev_dbg(dev, "read_reg: cmd:%#.2x buf:%pK len:%#x\n", opcode, buf, len);
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.opcode = opcode;
-       cmd.tx_data = true;
-       cmd.len = len;
-       cmd.buf = buf;
-       cmd.qspimode = CCR_FMODE_INDR;
-
-       stm32_qspi_set_framemode(nor, &cmd, false);
-
-       return stm32_qspi_send(flash, &cmd);
-}
-
-static int stm32_qspi_write_reg(struct spi_nor *nor, u8 opcode,
-                               u8 *buf, int len)
-{
-       struct stm32_qspi_flash *flash = nor->priv;
-       struct device *dev = flash->qspi->dev;
-       struct stm32_qspi_cmd cmd;
-
-       dev_dbg(dev, "write_reg: cmd:%#.2x buf:%pK len:%#x\n", opcode, buf, len);
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.opcode = opcode;
-       cmd.tx_data = !!(buf && len > 0);
-       cmd.len = len;
-       cmd.buf = buf;
-       cmd.qspimode = CCR_FMODE_INDW;
-
-       stm32_qspi_set_framemode(nor, &cmd, false);
-
-       return stm32_qspi_send(flash, &cmd);
-}
-
-static ssize_t stm32_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
-                              u_char *buf)
-{
-       struct stm32_qspi_flash *flash = nor->priv;
-       struct stm32_qspi *qspi = flash->qspi;
-       struct stm32_qspi_cmd cmd;
-       int err;
-
-       dev_dbg(qspi->dev, "read(%#.2x): buf:%pK from:%#.8x len:%#zx\n",
-               nor->read_opcode, buf, (u32)from, len);
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.opcode = nor->read_opcode;
-       cmd.addr_width = nor->addr_width;
-       cmd.addr = (u32)from;
-       cmd.tx_data = true;
-       cmd.dummy = nor->read_dummy;
-       cmd.len = len;
-       cmd.buf = buf;
-       cmd.qspimode = flash->read_mode;
-
-       stm32_qspi_set_framemode(nor, &cmd, true);
-       err = stm32_qspi_send(flash, &cmd);
-
-       return err ? err : len;
-}
-
-static ssize_t stm32_qspi_write(struct spi_nor *nor, loff_t to, size_t len,
-                               const u_char *buf)
-{
-       struct stm32_qspi_flash *flash = nor->priv;
-       struct device *dev = flash->qspi->dev;
-       struct stm32_qspi_cmd cmd;
-       int err;
-
-       dev_dbg(dev, "write(%#.2x): buf:%p to:%#.8x len:%#zx\n",
-               nor->program_opcode, buf, (u32)to, len);
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.opcode = nor->program_opcode;
-       cmd.addr_width = nor->addr_width;
-       cmd.addr = (u32)to;
-       cmd.tx_data = true;
-       cmd.len = len;
-       cmd.buf = (void *)buf;
-       cmd.qspimode = CCR_FMODE_INDW;
-
-       stm32_qspi_set_framemode(nor, &cmd, false);
-       err = stm32_qspi_send(flash, &cmd);
-
-       return err ? err : len;
-}
-
-static int stm32_qspi_erase(struct spi_nor *nor, loff_t offs)
-{
-       struct stm32_qspi_flash *flash = nor->priv;
-       struct device *dev = flash->qspi->dev;
-       struct stm32_qspi_cmd cmd;
-
-       dev_dbg(dev, "erase(%#.2x):offs:%#x\n", nor->erase_opcode, (u32)offs);
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.opcode = nor->erase_opcode;
-       cmd.addr_width = nor->addr_width;
-       cmd.addr = (u32)offs;
-       cmd.qspimode = CCR_FMODE_INDW;
-
-       stm32_qspi_set_framemode(nor, &cmd, false);
-
-       return stm32_qspi_send(flash, &cmd);
-}
-
-static irqreturn_t stm32_qspi_irq(int irq, void *dev_id)
-{
-       struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id;
-       u32 cr, sr, fcr = 0;
-
-       cr = readl_relaxed(qspi->io_base + QUADSPI_CR);
-       sr = readl_relaxed(qspi->io_base + QUADSPI_SR);
-
-       if ((cr & CR_TCIE) && (sr & SR_TCF)) {
-               /* tx complete */
-               fcr |= FCR_CTCF;
-               complete(&qspi->cmd_completion);
-       } else {
-               dev_info_ratelimited(qspi->dev, "spurious interrupt\n");
-       }
-
-       writel_relaxed(fcr, qspi->io_base + QUADSPI_FCR);
-
-       return IRQ_HANDLED;
-}
-
-static int stm32_qspi_prep(struct spi_nor *nor, enum spi_nor_ops ops)
-{
-       struct stm32_qspi_flash *flash = nor->priv;
-       struct stm32_qspi *qspi = flash->qspi;
-
-       mutex_lock(&qspi->lock);
-       return 0;
-}
-
-static void stm32_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
-{
-       struct stm32_qspi_flash *flash = nor->priv;
-       struct stm32_qspi *qspi = flash->qspi;
-
-       mutex_unlock(&qspi->lock);
-}
-
-static int stm32_qspi_flash_setup(struct stm32_qspi *qspi,
-                                 struct device_node *np)
-{
-       struct spi_nor_hwcaps hwcaps = {
-               .mask = SNOR_HWCAPS_READ |
-                       SNOR_HWCAPS_READ_FAST |
-                       SNOR_HWCAPS_PP,
-       };
-       u32 width, presc, cs_num, max_rate = 0;
-       struct stm32_qspi_flash *flash;
-       struct mtd_info *mtd;
-       int ret;
-
-       of_property_read_u32(np, "reg", &cs_num);
-       if (cs_num >= STM32_MAX_NORCHIP)
-               return -EINVAL;
-
-       of_property_read_u32(np, "spi-max-frequency", &max_rate);
-       if (!max_rate)
-               return -EINVAL;
-
-       presc = DIV_ROUND_UP(qspi->clk_rate, max_rate) - 1;
-
-       if (of_property_read_u32(np, "spi-rx-bus-width", &width))
-               width = 1;
-
-       if (width == 4)
-               hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
-       else if (width == 2)
-               hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
-       else if (width != 1)
-               return -EINVAL;
-
-       flash = &qspi->flash[cs_num];
-       flash->qspi = qspi;
-       flash->cs = cs_num;
-       flash->presc = presc;
-
-       flash->nor.dev = qspi->dev;
-       spi_nor_set_flash_node(&flash->nor, np);
-       flash->nor.priv = flash;
-       mtd = &flash->nor.mtd;
-
-       flash->nor.read = stm32_qspi_read;
-       flash->nor.write = stm32_qspi_write;
-       flash->nor.erase = stm32_qspi_erase;
-       flash->nor.read_reg = stm32_qspi_read_reg;
-       flash->nor.write_reg = stm32_qspi_write_reg;
-       flash->nor.prepare = stm32_qspi_prep;
-       flash->nor.unprepare = stm32_qspi_unprep;
-
-       writel_relaxed(LPTR_DFT_TIMEOUT, qspi->io_base + QUADSPI_LPTR);
-
-       writel_relaxed(CR_PRESC(presc) | CR_FTHRES(3) | CR_TCEN | CR_SSHIFT
-                      | CR_EN, qspi->io_base + QUADSPI_CR);
-
-       /*
-        * in stm32 qspi controller, QUADSPI_DCR register has a fsize field
-        * which define the size of nor flash.
-        * if fsize is NULL, the controller can't sent spi-nor command.
-        * set a temporary value just to discover the nor flash with
-        * "spi_nor_scan". After, the right value (mtd->size) can be set.
-        */
-       flash->fsize = FSIZE_VAL(SZ_1K);
-
-       ret = spi_nor_scan(&flash->nor, NULL, &hwcaps);
-       if (ret) {
-               dev_err(qspi->dev, "device scan failed\n");
-               return ret;
-       }
-
-       flash->fsize = FSIZE_VAL(mtd->size);
-       flash->prefetch_limit = mtd->size - STM32_QSPI_FIFO_SZ;
-
-       flash->read_mode = CCR_FMODE_MM;
-       if (mtd->size > qspi->mm_size)
-               flash->read_mode = CCR_FMODE_INDR;
-
-       writel_relaxed(DCR_CSHT(1), qspi->io_base + QUADSPI_DCR);
-
-       ret = mtd_device_register(mtd, NULL, 0);
-       if (ret) {
-               dev_err(qspi->dev, "mtd device parse failed\n");
-               return ret;
-       }
-
-       flash->registered = true;
-
-       dev_dbg(qspi->dev, "read mm:%s cs:%d bus:%d\n",
-               flash->read_mode == CCR_FMODE_MM ? "yes" : "no", cs_num, width);
-
-       return 0;
-}
-
-static void stm32_qspi_mtd_free(struct stm32_qspi *qspi)
-{
-       int i;
-
-       for (i = 0; i < STM32_MAX_NORCHIP; i++)
-               if (qspi->flash[i].registered)
-                       mtd_device_unregister(&qspi->flash[i].nor.mtd);
-}
-
-static int stm32_qspi_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct device_node *flash_np;
-       struct reset_control *rstc;
-       struct stm32_qspi *qspi;
-       struct resource *res;
-       int ret, irq;
-
-       qspi = devm_kzalloc(dev, sizeof(*qspi), GFP_KERNEL);
-       if (!qspi)
-               return -ENOMEM;
-
-       qspi->nor_num = of_get_child_count(dev->of_node);
-       if (!qspi->nor_num || qspi->nor_num > STM32_MAX_NORCHIP)
-               return -ENODEV;
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi");
-       qspi->io_base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(qspi->io_base))
-               return PTR_ERR(qspi->io_base);
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mm");
-       qspi->mm_base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(qspi->mm_base))
-               return PTR_ERR(qspi->mm_base);
-
-       qspi->mm_size = resource_size(res);
-
-       irq = platform_get_irq(pdev, 0);
-       ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0,
-                              dev_name(dev), qspi);
-       if (ret) {
-               dev_err(dev, "failed to request irq\n");
-               return ret;
-       }
-
-       init_completion(&qspi->cmd_completion);
-
-       qspi->clk = devm_clk_get(dev, NULL);
-       if (IS_ERR(qspi->clk))
-               return PTR_ERR(qspi->clk);
-
-       qspi->clk_rate = clk_get_rate(qspi->clk);
-       if (!qspi->clk_rate)
-               return -EINVAL;
-
-       ret = clk_prepare_enable(qspi->clk);
-       if (ret) {
-               dev_err(dev, "can not enable the clock\n");
-               return ret;
-       }
-
-       rstc = devm_reset_control_get_exclusive(dev, NULL);
-       if (!IS_ERR(rstc)) {
-               reset_control_assert(rstc);
-               udelay(2);
-               reset_control_deassert(rstc);
-       }
-
-       qspi->dev = dev;
-       platform_set_drvdata(pdev, qspi);
-       mutex_init(&qspi->lock);
-
-       for_each_available_child_of_node(dev->of_node, flash_np) {
-               ret = stm32_qspi_flash_setup(qspi, flash_np);
-               if (ret) {
-                       dev_err(dev, "unable to setup flash chip\n");
-                       goto err_flash;
-               }
-       }
-
-       return 0;
-
-err_flash:
-       mutex_destroy(&qspi->lock);
-       stm32_qspi_mtd_free(qspi);
-
-       clk_disable_unprepare(qspi->clk);
-       return ret;
-}
-
-static int stm32_qspi_remove(struct platform_device *pdev)
-{
-       struct stm32_qspi *qspi = platform_get_drvdata(pdev);
-
-       /* disable qspi */
-       writel_relaxed(0, qspi->io_base + QUADSPI_CR);
-
-       stm32_qspi_mtd_free(qspi);
-       mutex_destroy(&qspi->lock);
-
-       clk_disable_unprepare(qspi->clk);
-       return 0;
-}
-
-static const struct of_device_id stm32_qspi_match[] = {
-       {.compatible = "st,stm32f469-qspi"},
-       {}
-};
-MODULE_DEVICE_TABLE(of, stm32_qspi_match);
-
-static struct platform_driver stm32_qspi_driver = {
-       .probe  = stm32_qspi_probe,
-       .remove = stm32_qspi_remove,
-       .driver = {
-               .name = "stm32-quadspi",
-               .of_match_table = stm32_qspi_match,
-       },
-};
-module_platform_driver(stm32_qspi_driver);
-
-MODULE_AUTHOR("Ludovic Barre <ludovic.barre@st.com>");
-MODULE_DESCRIPTION("STMicroelectronics STM32 quad spi driver");
-MODULE_LICENSE("GPL v2");
index 7659d6c..e5c571f 100644 (file)
@@ -46,14 +46,14 @@ config MUX_GPIO
          be called mux-gpio.
 
 config MUX_MMIO
-       tristate "MMIO register bitfield-controlled Multiplexer"
-       depends on (OF && MFD_SYSCON) || COMPILE_TEST
+       tristate "MMIO/Regmap register bitfield-controlled Multiplexer"
+       depends on OF || COMPILE_TEST
        help
-         MMIO register bitfield-controlled Multiplexer controller.
+         MMIO/Regmap register bitfield-controlled Multiplexer controller.
 
-         The driver builds multiplexer controllers for bitfields in a syscon
-         register. For N bit wide bitfields, there will be 2^N possible
-         multiplexer states.
+         The driver builds multiplexer controllers for bitfields in either
+         a syscon register or a driver regmap register. For N bit wide
+         bitfields, there will be 2^N possible multiplexer states.
 
          To compile the driver as a module, choose M here: the module will
          be called mux-mmio.
index 935ac44..44a7a0e 100644 (file)
@@ -28,6 +28,7 @@ static const struct mux_control_ops mux_mmio_ops = {
 
 static const struct of_device_id mux_mmio_dt_ids[] = {
        { .compatible = "mmio-mux", },
+       { .compatible = "reg-mux", },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, mux_mmio_dt_ids);
@@ -43,7 +44,10 @@ static int mux_mmio_probe(struct platform_device *pdev)
        int ret;
        int i;
 
-       regmap = syscon_node_to_regmap(np->parent);
+       if (of_device_is_compatible(np, "mmio-mux"))
+               regmap = syscon_node_to_regmap(np->parent);
+       else
+               regmap = dev_get_regmap(dev->parent, NULL) ?: ERR_PTR(-ENODEV);
        if (IS_ERR(regmap)) {
                ret = PTR_ERR(regmap);
                dev_err(dev, "failed to get regmap: %d\n", ret);
index 09c16d8..bb6586d 100644 (file)
@@ -754,7 +754,7 @@ struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev)
        return (void *)misc_op;
 }
 
-static int hns_dsaf_dev_match(struct device *dev, void *fwnode)
+static int hns_dsaf_dev_match(struct device *dev, const void *fwnode)
 {
        return dev->fwnode == fwnode;
 }
index 28ec0d5..41c90f2 100644 (file)
@@ -2286,7 +2286,7 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
        struct ice_hw *hw;
        int err;
 
-       /* this driver uses devres, see Documentation/driver-model/devres.txt */
+       /* this driver uses devres, see Documentation/driver-model/devres.rst */
        err = pcim_enable_device(pdev);
        if (err)
                return err;
index 48e0924..4e184ee 100644 (file)
@@ -151,9 +151,9 @@ static void cpsw_gmii_sel_dra7xx(struct cpsw_phy_sel_priv *priv,
 }
 
 static struct platform_driver cpsw_phy_sel_driver;
-static int match(struct device *dev, void *data)
+static int match(struct device *dev, const void *data)
 {
-       struct device_node *node = (struct device_node *)data;
+       const struct device_node *node = (const struct device_node *)data;
        return dev->of_node == node &&
                dev->driver == &cpsw_phy_sel_driver.driver;
 }
index 5f4ece0..ae27be8 100644 (file)
@@ -1371,7 +1371,7 @@ static int emac_devioctl(struct net_device *ndev, struct ifreq *ifrq, int cmd)
                return -EOPNOTSUPP;
 }
 
-static int match_first_device(struct device *dev, void *data)
+static int match_first_device(struct device *dev, const void *data)
 {
        if (dev->parent && dev->parent->of_node)
                return of_device_is_compatible(dev->parent->of_node,
index c50a977..8479a44 100644 (file)
@@ -694,10 +694,10 @@ err_out:
  * should provide a "tc35815-mac" device with a MAC address in its
  * platform_data.
  */
-static int tc35815_mac_match(struct device *dev, void *data)
+static int tc35815_mac_match(struct device *dev, const void *data)
 {
        struct platform_device *plat_dev = to_platform_device(dev);
-       struct pci_dev *pci_dev = data;
+       const struct pci_dev *pci_dev = data;
        unsigned int id = pci_dev->irq;
        return !strcmp(plat_dev->name, "tc35815-mac") && plat_dev->id == id;
 }
index 81caa37..3bdda1c 100644 (file)
@@ -598,7 +598,7 @@ enum ht_channel_width {
        HT_CHANNEL_WIDTH_MAX,
 };
 
-/* 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 {
index 9b497d7..dcb2b79 100644 (file)
@@ -2112,7 +2112,8 @@ nvme_fc_map_data(struct nvme_fc_ctrl *ctrl, struct request *rq,
 
        freq->sg_table.sgl = freq->first_sgl;
        ret = sg_alloc_table_chained(&freq->sg_table,
-                       blk_rq_nr_phys_segments(rq), freq->sg_table.sgl);
+                       blk_rq_nr_phys_segments(rq), freq->sg_table.sgl,
+                       SG_CHUNK_SIZE);
        if (ret)
                return -ENOMEM;
 
@@ -2122,7 +2123,7 @@ nvme_fc_map_data(struct nvme_fc_ctrl *ctrl, struct request *rq,
        freq->sg_cnt = fc_dma_map_sg(ctrl->lport->dev, freq->sg_table.sgl,
                                op->nents, dir);
        if (unlikely(freq->sg_cnt <= 0)) {
-               sg_free_table_chained(&freq->sg_table, true);
+               sg_free_table_chained(&freq->sg_table, SG_CHUNK_SIZE);
                freq->sg_cnt = 0;
                return -EFAULT;
        }
@@ -2148,7 +2149,7 @@ nvme_fc_unmap_data(struct nvme_fc_ctrl *ctrl, struct request *rq,
 
        nvme_cleanup_cmd(rq);
 
-       sg_free_table_chained(&freq->sg_table, true);
+       sg_free_table_chained(&freq->sg_table, SG_CHUNK_SIZE);
 
        freq->sg_cnt = 0;
 }
index 97f668a..676619c 100644 (file)
@@ -1144,7 +1144,7 @@ static void nvme_rdma_unmap_data(struct nvme_rdma_queue *queue,
                                    WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
 
        nvme_cleanup_cmd(rq);
-       sg_free_table_chained(&req->sg_table, true);
+       sg_free_table_chained(&req->sg_table, SG_CHUNK_SIZE);
 }
 
 static int nvme_rdma_set_sg_null(struct nvme_command *c)
@@ -1259,7 +1259,8 @@ static int nvme_rdma_map_data(struct nvme_rdma_queue *queue,
 
        req->sg_table.sgl = req->first_sgl;
        ret = sg_alloc_table_chained(&req->sg_table,
-                       blk_rq_nr_phys_segments(rq), req->sg_table.sgl);
+                       blk_rq_nr_phys_segments(rq), req->sg_table.sgl,
+                       SG_CHUNK_SIZE);
        if (ret)
                return -ENOMEM;
 
@@ -1299,7 +1300,7 @@ out_unmap_sg:
                        req->nents, rq_data_dir(rq) ==
                        WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
 out_free_table:
-       sg_free_table_chained(&req->sg_table, true);
+       sg_free_table_chained(&req->sg_table, SG_CHUNK_SIZE);
        return ret;
 }
 
index 9e211ad..b16dc39 100644 (file)
@@ -77,7 +77,7 @@ static void nvme_loop_complete_rq(struct request *req)
        struct nvme_loop_iod *iod = blk_mq_rq_to_pdu(req);
 
        nvme_cleanup_cmd(req);
-       sg_free_table_chained(&iod->sg_table, true);
+       sg_free_table_chained(&iod->sg_table, SG_CHUNK_SIZE);
        nvme_complete_rq(req);
 }
 
@@ -157,7 +157,7 @@ static blk_status_t nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx,
                iod->sg_table.sgl = iod->first_sgl;
                if (sg_alloc_table_chained(&iod->sg_table,
                                blk_rq_nr_phys_segments(req),
-                               iod->sg_table.sgl))
+                               iod->sg_table.sgl, SG_CHUNK_SIZE))
                        return BLK_STS_RESOURCE;
 
                iod->req.sg = iod->sg_table.sgl;
index afa4335..c2ec750 100644 (file)
@@ -47,6 +47,13 @@ config NVMEM_IMX_OCOTP
          This driver can also be built as a module. If so, the module
          will be called nvmem-imx-ocotp.
 
+config NVMEM_IMX_OCOTP_SCU
+       tristate "i.MX8 SCU On-Chip OTP Controller support"
+       depends on IMX_SCU
+       help
+         This is a driver for the SCU On-Chip OTP Controller (OCOTP)
+         available on i.MX8 SoCs.
+
 config NVMEM_LPC18XX_EEPROM
        tristate "NXP LPC18XX EEPROM Memory Support"
        depends on ARCH_LPC18XX || COMPILE_TEST
@@ -188,7 +195,7 @@ config MESON_MX_EFUSE
 
 config NVMEM_SNVS_LPGPR
        tristate "Support for Low Power General Purpose Register"
-       depends on SOC_IMX6 || SOC_IMX7D || COMPILE_TEST
+       depends on ARCH_MXC || COMPILE_TEST
        help
          This is a driver for Low Power General Purpose Register (LPGPR) available on
          i.MX6 and i.MX7 SoCs in Secure Non-Volatile Storage (SNVS) of this chip.
index c1fe476..e5c153d 100644 (file)
@@ -16,6 +16,8 @@ obj-$(CONFIG_NVMEM_IMX_IIM)   += nvmem-imx-iim.o
 nvmem-imx-iim-y                        := imx-iim.o
 obj-$(CONFIG_NVMEM_IMX_OCOTP)  += nvmem-imx-ocotp.o
 nvmem-imx-ocotp-y              := imx-ocotp.o
+obj-$(CONFIG_NVMEM_IMX_OCOTP_SCU)      += nvmem-imx-ocotp-scu.o
+nvmem-imx-ocotp-scu-y          := imx-ocotp-scu.o
 obj-$(CONFIG_NVMEM_LPC18XX_EEPROM)     += nvmem_lpc18xx_eeprom.o
 nvmem_lpc18xx_eeprom-y := lpc18xx_eeprom.o
 obj-$(CONFIG_NVMEM_LPC18XX_OTP)        += nvmem_lpc18xx_otp.o
index c7892c3..ac5d945 100644 (file)
@@ -76,7 +76,7 @@ static struct bus_type nvmem_bus_type = {
        .name           = "nvmem",
 };
 
-static int of_nvmem_match(struct device *dev, void *nvmem_np)
+static int of_nvmem_match(struct device *dev, const void *nvmem_np)
 {
        return dev->of_node == nvmem_np;
 }
diff --git a/drivers/nvmem/imx-ocotp-scu.c b/drivers/nvmem/imx-ocotp-scu.c
new file mode 100644 (file)
index 0000000..d9dc482
--- /dev/null
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * i.MX8 OCOTP fusebox driver
+ *
+ * Copyright 2019 NXP
+ *
+ * Peng Fan <peng.fan@nxp.com>
+ */
+
+#include <linux/firmware/imx/sci.h>
+#include <linux/module.h>
+#include <linux/nvmem-provider.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+enum ocotp_devtype {
+       IMX8QXP,
+};
+
+struct ocotp_devtype_data {
+       int devtype;
+       int nregs;
+};
+
+struct ocotp_priv {
+       struct device *dev;
+       const struct ocotp_devtype_data *data;
+       struct imx_sc_ipc *nvmem_ipc;
+};
+
+struct imx_sc_msg_misc_fuse_read {
+       struct imx_sc_rpc_msg hdr;
+       u32 word;
+} __packed;
+
+static struct ocotp_devtype_data imx8qxp_data = {
+       .devtype = IMX8QXP,
+       .nregs = 800,
+};
+
+static int imx_sc_misc_otp_fuse_read(struct imx_sc_ipc *ipc, u32 word,
+                                    u32 *val)
+{
+       struct imx_sc_msg_misc_fuse_read msg;
+       struct imx_sc_rpc_msg *hdr = &msg.hdr;
+       int ret;
+
+       hdr->ver = IMX_SC_RPC_VERSION;
+       hdr->svc = IMX_SC_RPC_SVC_MISC;
+       hdr->func = IMX_SC_MISC_FUNC_OTP_FUSE_READ;
+       hdr->size = 2;
+
+       msg.word = word;
+
+       ret = imx_scu_call_rpc(ipc, &msg, true);
+       if (ret)
+               return ret;
+
+       *val = msg.word;
+
+       return 0;
+}
+
+static int imx_scu_ocotp_read(void *context, unsigned int offset,
+                             void *val, size_t bytes)
+{
+       struct ocotp_priv *priv = context;
+       u32 count, index, num_bytes;
+       u32 *buf;
+       void *p;
+       int i, ret;
+
+       index = offset >> 2;
+       num_bytes = round_up((offset % 4) + bytes, 4);
+       count = num_bytes >> 2;
+
+       if (count > (priv->data->nregs - index))
+               count = priv->data->nregs - index;
+
+       p = kzalloc(num_bytes, GFP_KERNEL);
+       if (!p)
+               return -ENOMEM;
+
+       buf = p;
+
+       for (i = index; i < (index + count); i++) {
+               if (priv->data->devtype == IMX8QXP) {
+                       if ((i > 271) && (i < 544)) {
+                               *buf++ = 0;
+                               continue;
+                       }
+               }
+
+               ret = imx_sc_misc_otp_fuse_read(priv->nvmem_ipc, i, buf);
+               if (ret) {
+                       kfree(p);
+                       return ret;
+               }
+               buf++;
+       }
+
+       memcpy(val, (u8 *)p + offset % 4, bytes);
+
+       kfree(p);
+
+       return 0;
+}
+
+static struct nvmem_config imx_scu_ocotp_nvmem_config = {
+       .name = "imx-scu-ocotp",
+       .read_only = true,
+       .word_size = 4,
+       .stride = 1,
+       .owner = THIS_MODULE,
+       .reg_read = imx_scu_ocotp_read,
+};
+
+static const struct of_device_id imx_scu_ocotp_dt_ids[] = {
+       { .compatible = "fsl,imx8qxp-scu-ocotp", (void *)&imx8qxp_data },
+       { },
+};
+MODULE_DEVICE_TABLE(of, imx_scu_ocotp_dt_ids);
+
+static int imx_scu_ocotp_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ocotp_priv *priv;
+       struct nvmem_device *nvmem;
+       int ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       ret = imx_scu_get_handle(&priv->nvmem_ipc);
+       if (ret)
+               return ret;
+
+       priv->data = of_device_get_match_data(dev);
+       priv->dev = dev;
+       imx_scu_ocotp_nvmem_config.size = 4 * priv->data->nregs;
+       imx_scu_ocotp_nvmem_config.dev = dev;
+       imx_scu_ocotp_nvmem_config.priv = priv;
+       nvmem = devm_nvmem_register(dev, &imx_scu_ocotp_nvmem_config);
+
+       return PTR_ERR_OR_ZERO(nvmem);
+}
+
+static struct platform_driver imx_scu_ocotp_driver = {
+       .probe  = imx_scu_ocotp_probe,
+       .driver = {
+               .name   = "imx_scu_ocotp",
+               .of_match_table = imx_scu_ocotp_dt_ids,
+       },
+};
+module_platform_driver(imx_scu_ocotp_driver);
+
+MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
+MODULE_DESCRIPTION("i.MX8 SCU OCOTP fuse box driver");
+MODULE_LICENSE("GPL v2");
index bd016b9..42d4451 100644 (file)
 #define IMX_OCOTP_ADDR_DATA2           0x0040
 #define IMX_OCOTP_ADDR_DATA3           0x0050
 
-#define IMX_OCOTP_BM_CTRL_ADDR         0x0000007F
+#define IMX_OCOTP_BM_CTRL_ADDR         0x000000FF
 #define IMX_OCOTP_BM_CTRL_BUSY         0x00000100
 #define IMX_OCOTP_BM_CTRL_ERROR                0x00000200
 #define IMX_OCOTP_BM_CTRL_REL_SHADOWS  0x00000400
 
-#define DEF_RELAX                      20      /* > 16.5ns */
+#define TIMING_STROBE_PROG_US          10      /* Min time to blow a fuse */
+#define TIMING_STROBE_READ_NS          37      /* Min time before read */
+#define TIMING_RELAX_NS                        17
 #define DEF_FSOURCE                    1001    /* > 1000 ns */
 #define DEF_STROBE_PROG                        10000   /* IPG clocks */
 #define IMX_OCOTP_WR_UNLOCK            0x3E770000
@@ -176,14 +178,41 @@ static void imx_ocotp_set_imx6_timing(struct ocotp_priv *priv)
         * fields with timing values to match the current frequency of the
         * ipg_clk. OTP writes will work at maximum bus frequencies as long
         * as the HW_OCOTP_TIMING parameters are set correctly.
+        *
+        * Note: there are minimum timings required to ensure an OTP fuse burns
+        * correctly that are independent of the ipg_clk. Those values are not
+        * formally documented anywhere however, working from the minimum
+        * timings given in u-boot we can say:
+        *
+        * - Minimum STROBE_PROG time is 10 microseconds. Intuitively 10
+        *   microseconds feels about right as representative of a minimum time
+        *   to physically burn out a fuse.
+        *
+        * - Minimum STROBE_READ i.e. the time to wait post OTP fuse burn before
+        *   performing another read is 37 nanoseconds
+        *
+        * - Minimum RELAX timing is 17 nanoseconds. This final RELAX minimum
+        *   timing is not entirely clear the documentation says "This
+        *   count value specifies the time to add to all default timing
+        *   parameters other than the Tpgm and Trd. It is given in number
+        *   of ipg_clk periods." where Tpgm and Trd refer to STROBE_PROG
+        *   and STROBE_READ respectively. What the other timing parameters
+        *   are though, is not specified. Experience shows a zero RELAX
+        *   value will mess up a re-load of the shadow registers post OTP
+        *   burn.
         */
        clk_rate = clk_get_rate(priv->clk);
 
-       relax = clk_rate / (1000000000 / DEF_RELAX) - 1;
-       strobe_prog = clk_rate / (1000000000 / 10000) + 2 * (DEF_RELAX + 1) - 1;
-       strobe_read = clk_rate / (1000000000 / 40) + 2 * (DEF_RELAX + 1) - 1;
+       relax = DIV_ROUND_UP(clk_rate * TIMING_RELAX_NS, 1000000000) - 1;
+       strobe_read = DIV_ROUND_UP(clk_rate * TIMING_STROBE_READ_NS,
+                                  1000000000);
+       strobe_read += 2 * (relax + 1) - 1;
+       strobe_prog = DIV_ROUND_CLOSEST(clk_rate * TIMING_STROBE_PROG_US,
+                                       1000000);
+       strobe_prog += 2 * (relax + 1) - 1;
 
-       timing = strobe_prog & 0x00000FFF;
+       timing = readl(priv->base + IMX_OCOTP_ADDR_TIMING) & 0x0FC00000;
+       timing |= strobe_prog & 0x00000FFF;
        timing |= (relax       << 12) & 0x0000F000;
        timing |= (strobe_read << 16) & 0x003F0000;
 
@@ -440,8 +469,14 @@ static const struct ocotp_params imx7ulp_params = {
 
 static const struct ocotp_params imx8mq_params = {
        .nregs = 256,
-       .bank_address_words = 4,
-       .set_timing = imx_ocotp_set_imx7_timing,
+       .bank_address_words = 0,
+       .set_timing = imx_ocotp_set_imx6_timing,
+};
+
+static const struct ocotp_params imx8mm_params = {
+       .nregs = 256,
+       .bank_address_words = 0,
+       .set_timing = imx_ocotp_set_imx6_timing,
 };
 
 static const struct of_device_id imx_ocotp_dt_ids[] = {
@@ -454,6 +489,7 @@ static const struct of_device_id imx_ocotp_dt_ids[] = {
        { .compatible = "fsl,imx6sll-ocotp", .data = &imx6sll_params },
        { .compatible = "fsl,imx7ulp-ocotp", .data = &imx7ulp_params },
        { .compatible = "fsl,imx8mq-ocotp", .data = &imx8mq_params },
+       { .compatible = "fsl,imx8mm-ocotp", .data = &imx8mm_params },
        { },
 };
 MODULE_DEVICE_TABLE(of, imx_ocotp_dt_ids);
index de893c9..9cdf14b 100644 (file)
@@ -38,7 +38,7 @@
  * memory entries in the /memory node. This function may be called
  * any time after initial_boot_param is set.
  */
-void of_fdt_limit_memory(int limit)
+void __init of_fdt_limit_memory(int limit)
 {
        int memory;
        int len;
@@ -78,57 +78,6 @@ void of_fdt_limit_memory(int limit)
        }
 }
 
-/**
- * of_fdt_is_compatible - Return true if given node from the given blob has
- * compat in its compatible list
- * @blob: A device tree blob
- * @node: node to test
- * @compat: compatible string to compare with compatible list.
- *
- * On match, returns a non-zero value with smaller values returned for more
- * specific compatible values.
- */
-static int of_fdt_is_compatible(const void *blob,
-                     unsigned long node, const char *compat)
-{
-       const char *cp;
-       int cplen;
-       unsigned long l, score = 0;
-
-       cp = fdt_getprop(blob, node, "compatible", &cplen);
-       if (cp == NULL)
-               return 0;
-       while (cplen > 0) {
-               score++;
-               if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
-                       return score;
-               l = strlen(cp) + 1;
-               cp += l;
-               cplen -= l;
-       }
-
-       return 0;
-}
-
-/**
- * of_fdt_is_big_endian - Return true if given node needs BE MMIO accesses
- * @blob: A device tree blob
- * @node: node to test
- *
- * Returns true if the node has a "big-endian" property, or if the kernel
- * was compiled for BE *and* the node has a "native-endian" property.
- * Returns false otherwise.
- */
-bool of_fdt_is_big_endian(const void *blob, unsigned long node)
-{
-       if (fdt_getprop(blob, node, "big-endian", NULL))
-               return true;
-       if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) &&
-           fdt_getprop(blob, node, "native-endian", NULL))
-               return true;
-       return false;
-}
-
 static bool of_fdt_device_is_available(const void *blob, unsigned long node)
 {
        const char *status = fdt_getprop(blob, node, "status", NULL);
@@ -142,27 +91,6 @@ static bool of_fdt_device_is_available(const void *blob, unsigned long node)
        return false;
 }
 
-/**
- * of_fdt_match - Return true if node matches a list of compatible values
- */
-int of_fdt_match(const void *blob, unsigned long node,
-                 const char *const *compat)
-{
-       unsigned int tmp, score = 0;
-
-       if (!compat)
-               return 0;
-
-       while (*compat) {
-               tmp = of_fdt_is_compatible(blob, node, *compat);
-               if (tmp && (score == 0 || (tmp < score)))
-                       score = tmp;
-               compat++;
-       }
-
-       return score;
-}
-
 static void *unflatten_dt_alloc(void **mem, unsigned long size,
                                       unsigned long align)
 {
@@ -535,7 +463,7 @@ EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
 int __initdata dt_root_addr_cells;
 int __initdata dt_root_size_cells;
 
-void *initial_boot_params;
+void *initial_boot_params __ro_after_init;
 
 #ifdef CONFIG_OF_EARLY_FLATTREE
 
@@ -551,7 +479,8 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
        phys_addr_t base, size;
        int len;
        const __be32 *prop;
-       int nomap, first = 1;
+       int first = 1;
+       bool nomap;
 
        prop = of_get_flat_dt_prop(node, "reg", &len);
        if (!prop)
@@ -666,7 +595,7 @@ void __init early_init_fdt_scan_reserved_mem(void)
                fdt_get_mem_rsv(initial_boot_params, n, &base, &size);
                if (!size)
                        break;
-               early_init_dt_reserve_memory_arch(base, size, 0);
+               early_init_dt_reserve_memory_arch(base, size, false);
        }
 
        of_scan_flat_dt(__fdt_scan_reserved_mem, NULL);
@@ -684,7 +613,7 @@ void __init early_init_fdt_reserve_self(void)
        /* Reserve the dtb region */
        early_init_dt_reserve_memory_arch(__pa(initial_boot_params),
                                          fdt_totalsize(initial_boot_params),
-                                         0);
+                                         false);
 }
 
 /**
@@ -758,7 +687,7 @@ int __init of_scan_flat_dt_subnodes(unsigned long parent,
  * @return offset of the subnode, or -FDT_ERR_NOTFOUND if there is none
  */
 
-int of_get_flat_dt_subnode_by_name(unsigned long node, const char *uname)
+int __init of_get_flat_dt_subnode_by_name(unsigned long node, const char *uname)
 {
        return fdt_subnode_offset(initial_boot_params, node, uname);
 }
@@ -771,14 +700,6 @@ unsigned long __init of_get_flat_dt_root(void)
        return 0;
 }
 
-/**
- * of_get_flat_dt_size - Return the total size of the FDT
- */
-int __init of_get_flat_dt_size(void)
-{
-       return fdt_totalsize(initial_boot_params);
-}
-
 /**
  * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr
  *
@@ -791,6 +712,38 @@ const void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
        return fdt_getprop(initial_boot_params, node, name, size);
 }
 
+/**
+ * of_fdt_is_compatible - Return true if given node from the given blob has
+ * compat in its compatible list
+ * @blob: A device tree blob
+ * @node: node to test
+ * @compat: compatible string to compare with compatible list.
+ *
+ * On match, returns a non-zero value with smaller values returned for more
+ * specific compatible values.
+ */
+static int of_fdt_is_compatible(const void *blob,
+                     unsigned long node, const char *compat)
+{
+       const char *cp;
+       int cplen;
+       unsigned long l, score = 0;
+
+       cp = fdt_getprop(blob, node, "compatible", &cplen);
+       if (cp == NULL)
+               return 0;
+       while (cplen > 0) {
+               score++;
+               if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
+                       return score;
+               l = strlen(cp) + 1;
+               cp += l;
+               cplen -= l;
+       }
+
+       return 0;
+}
+
 /**
  * of_flat_dt_is_compatible - Return true if given node has compat in compatible list
  * @node: node to test
@@ -804,9 +757,21 @@ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
 /**
  * of_flat_dt_match - Return true if node matches a list of compatible values
  */
-int __init of_flat_dt_match(unsigned long node, const char *const *compat)
+static int __init of_flat_dt_match(unsigned long node, const char *const *compat)
 {
-       return of_fdt_match(initial_boot_params, node, compat);
+       unsigned int tmp, score = 0;
+
+       if (!compat)
+               return 0;
+
+       while (*compat) {
+               tmp = of_fdt_is_compatible(initial_boot_params, node, *compat);
+               if (tmp && (score == 0 || (tmp < score)))
+                       score = tmp;
+               compat++;
+       }
+
+       return score;
 }
 
 /**
index 3b67896..44f5349 100644 (file)
@@ -281,7 +281,7 @@ unregister:
 EXPORT_SYMBOL(of_mdiobus_register);
 
 /* Helper function for of_phy_find_device */
-static int of_phy_match(struct device *dev, void *phy_np)
+static int of_phy_match(struct device *dev, const void *phy_np)
 {
        return dev->of_node == phy_np;
 }
index 89e190e..7989703 100644 (file)
@@ -324,6 +324,9 @@ int of_reserved_mem_device_init_by_idx(struct device *dev,
        if (!target)
                return -ENODEV;
 
+       if (!of_device_is_available(target))
+               return 0;
+
        rmem = __find_rmem(target);
        of_node_put(target);
 
index 04ad312..7801e25 100644 (file)
@@ -37,7 +37,7 @@ static const struct of_device_id of_skipped_node_table[] = {
        {} /* Empty terminated list */
 };
 
-static int of_dev_node_match(struct device *dev, void *data)
+static int of_dev_node_match(struct device *dev, const void *data)
 {
        return dev->of_node == data;
 }
@@ -92,8 +92,7 @@ static void of_device_make_bus_id(struct device *dev)
                reg = of_get_property(node, "reg", NULL);
                if (reg && (addr = of_translate_address(node, reg)) != OF_BAD_ADDR) {
                        dev_set_name(dev, dev_name(dev) ? "%llx.%pOFn:%s" : "%llx.%pOFn",
-                                    (unsigned long long)addr, node,
-                                    dev_name(dev));
+                                    addr, node, dev_name(dev));
                        return;
                }
 
index 3832a5d..e6b1753 100644 (file)
@@ -1946,7 +1946,7 @@ static int unittest_i2c_mux_probe(struct i2c_client *client,
 {
        int i, nchans;
        struct device *dev = &client->dev;
-       struct i2c_adapter *adap = to_i2c_adapter(dev->parent);
+       struct i2c_adapter *adap = client->adapter;
        struct device_node *np = client->dev.of_node, *child;
        struct i2c_mux_core *muxc;
        u32 reg, max_reg;
index 0e8e2c1..f9ef7ad 100644 (file)
@@ -64,7 +64,7 @@ static struct resource *get_pci_domain_busn_res(int domain_nr)
        return &r->res;
 }
 
-static int find_anything(struct device *dev, void *data)
+static int find_anything(struct device *dev, const void *data)
 {
        return 1;
 }
index 5c79226..7f4e658 100644 (file)
@@ -236,10 +236,10 @@ struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus,
 }
 EXPORT_SYMBOL(pci_get_domain_bus_and_slot);
 
-static int match_pci_dev_by_id(struct device *dev, void *data)
+static int match_pci_dev_by_id(struct device *dev, const void *data)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
-       struct pci_device_id *id = data;
+       const struct pci_device_id *id = data;
 
        if (pci_match_one_device(id, pdev))
                return 1;
index 6233a79..ac322d6 100644 (file)
@@ -188,7 +188,7 @@ static const struct regmap_config phy_g12a_usb3_pcie_cr_regmap_conf = {
        .reg_read = phy_g12a_usb3_pcie_cr_bus_read,
        .reg_write = phy_g12a_usb3_pcie_cr_bus_write,
        .max_register = 0xffff,
-       .fast_io = true,
+       .disable_locking = true,
 };
 
 static int phy_g12a_usb3_init(struct phy *phy)
index 7a6a6dd..f5c1f29 100644 (file)
@@ -368,6 +368,13 @@ static int brcm_usb_phy_probe(struct platform_device *pdev)
        return PTR_ERR_OR_ZERO(phy_provider);
 }
 
+static int brcm_usb_phy_remove(struct platform_device *pdev)
+{
+       sysfs_remove_group(&pdev->dev.kobj, &brcm_usb_phy_group);
+
+       return 0;
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int brcm_usb_phy_suspend(struct device *dev)
 {
@@ -433,9 +440,9 @@ MODULE_DEVICE_TABLE(of, brcm_usb_dt_ids);
 
 static struct platform_driver brcm_usb_driver = {
        .probe          = brcm_usb_phy_probe,
+       .remove         = brcm_usb_phy_remove,
        .driver         = {
                .name   = "brcmstb-usb-phy",
-               .owner  = THIS_MODULE,
                .pm = &brcm_usb_phy_pm_ops,
                .of_match_table = brcm_usb_dt_ids,
        },
index f435d64..320630f 100644 (file)
@@ -4,3 +4,13 @@ config PHY_FSL_IMX8MQ_USB
        depends on OF && HAS_IOMEM
        select GENERIC_PHY
        default ARCH_MXC && ARM64
+
+config PHY_MIXEL_MIPI_DPHY
+       tristate "Mixel MIPI DSI PHY support"
+       depends on OF && HAS_IOMEM
+       select GENERIC_PHY
+       select GENERIC_PHY_MIPI_DPHY
+       select REGMAP_MMIO
+       help
+         Enable this to add support for the Mixel DSI PHY as found
+         on NXP's i.MX8 family of SOCs.
index a459a44..1d02e38 100644 (file)
@@ -1,2 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_PHY_FSL_IMX8MQ_USB)       += phy-fsl-imx8mq-usb.o
+obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY)      += phy-fsl-imx8-mipi-dphy.o
diff --git a/drivers/phy/freescale/phy-fsl-imx8-mipi-dphy.c b/drivers/phy/freescale/phy-fsl-imx8-mipi-dphy.c
new file mode 100644 (file)
index 0000000..9f2c1da
--- /dev/null
@@ -0,0 +1,497 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2017,2018 NXP
+ * Copyright 2019 Purism SPC
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+/* DPHY registers */
+#define DPHY_PD_DPHY                   0x00
+#define DPHY_M_PRG_HS_PREPARE          0x04
+#define DPHY_MC_PRG_HS_PREPARE         0x08
+#define DPHY_M_PRG_HS_ZERO             0x0c
+#define DPHY_MC_PRG_HS_ZERO            0x10
+#define DPHY_M_PRG_HS_TRAIL            0x14
+#define DPHY_MC_PRG_HS_TRAIL           0x18
+#define DPHY_PD_PLL                    0x1c
+#define DPHY_TST                       0x20
+#define DPHY_CN                                0x24
+#define DPHY_CM                                0x28
+#define DPHY_CO                                0x2c
+#define DPHY_LOCK                      0x30
+#define DPHY_LOCK_BYP                  0x34
+#define DPHY_REG_BYPASS_PLL            0x4C
+
+#define MBPS(x) ((x) * 1000000)
+
+#define DATA_RATE_MAX_SPEED MBPS(1500)
+#define DATA_RATE_MIN_SPEED MBPS(80)
+
+#define PLL_LOCK_SLEEP 10
+#define PLL_LOCK_TIMEOUT 1000
+
+#define CN_BUF 0xcb7a89c0
+#define CO_BUF 0x63
+#define CM(x)  (                                 \
+               ((x) <  32) ? 0xe0 | ((x) - 16) : \
+               ((x) <  64) ? 0xc0 | ((x) - 32) : \
+               ((x) < 128) ? 0x80 | ((x) - 64) : \
+               ((x) - 128))
+#define CN(x)  (((x) == 1) ? 0x1f : (((CN_BUF) >> ((x) - 1)) & 0x1f))
+#define CO(x)  ((CO_BUF) >> (8 - (x)) & 0x03)
+
+/* PHY power on is active low */
+#define PWR_ON 0
+#define PWR_OFF        1
+
+enum mixel_dphy_devtype {
+       MIXEL_IMX8MQ,
+};
+
+struct mixel_dphy_devdata {
+       u8 reg_tx_rcal;
+       u8 reg_auto_pd_en;
+       u8 reg_rxlprp;
+       u8 reg_rxcdrp;
+       u8 reg_rxhs_settle;
+};
+
+static const struct mixel_dphy_devdata mixel_dphy_devdata[] = {
+       [MIXEL_IMX8MQ] = {
+               .reg_tx_rcal = 0x38,
+               .reg_auto_pd_en = 0x3c,
+               .reg_rxlprp = 0x40,
+               .reg_rxcdrp = 0x44,
+               .reg_rxhs_settle = 0x48,
+       },
+};
+
+struct mixel_dphy_cfg {
+       /* DPHY PLL parameters */
+       u32 cm;
+       u32 cn;
+       u32 co;
+       /* DPHY register values */
+       u8 mc_prg_hs_prepare;
+       u8 m_prg_hs_prepare;
+       u8 mc_prg_hs_zero;
+       u8 m_prg_hs_zero;
+       u8 mc_prg_hs_trail;
+       u8 m_prg_hs_trail;
+       u8 rxhs_settle;
+};
+
+struct mixel_dphy_priv {
+       struct mixel_dphy_cfg cfg;
+       struct regmap *regmap;
+       struct clk *phy_ref_clk;
+       const struct mixel_dphy_devdata *devdata;
+};
+
+static const struct regmap_config mixel_dphy_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 32,
+       .reg_stride = 4,
+       .max_register = DPHY_REG_BYPASS_PLL,
+       .name = "mipi-dphy",
+};
+
+static int phy_write(struct phy *phy, u32 value, unsigned int reg)
+{
+       struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
+       int ret;
+
+       ret = regmap_write(priv->regmap, reg, value);
+       if (ret < 0)
+               dev_err(&phy->dev, "Failed to write DPHY reg %d: %d\n", reg,
+                       ret);
+       return ret;
+}
+
+/*
+ * Find a ratio close to the desired one using continued fraction
+ * approximation ending either at exact match or maximum allowed
+ * nominator, denominator.
+ */
+static void get_best_ratio(u32 *pnum, u32 *pdenom, u32 max_n, u32 max_d)
+{
+       u32 a = *pnum;
+       u32 b = *pdenom;
+       u32 c;
+       u32 n[] = {0, 1};
+       u32 d[] = {1, 0};
+       u32 whole;
+       unsigned int i = 1;
+
+       while (b) {
+               i ^= 1;
+               whole = a / b;
+               n[i] += (n[i ^ 1] * whole);
+               d[i] += (d[i ^ 1] * whole);
+               if ((n[i] > max_n) || (d[i] > max_d)) {
+                       i ^= 1;
+                       break;
+               }
+               c = a - (b * whole);
+               a = b;
+               b = c;
+       }
+       *pnum = n[i];
+       *pdenom = d[i];
+}
+
+static int mixel_dphy_config_from_opts(struct phy *phy,
+              struct phy_configure_opts_mipi_dphy *dphy_opts,
+              struct mixel_dphy_cfg *cfg)
+{
+       struct mixel_dphy_priv *priv = dev_get_drvdata(phy->dev.parent);
+       unsigned long ref_clk = clk_get_rate(priv->phy_ref_clk);
+       u32 lp_t, numerator, denominator;
+       unsigned long long tmp;
+       u32 n;
+       int i;
+
+       if (dphy_opts->hs_clk_rate > DATA_RATE_MAX_SPEED ||
+           dphy_opts->hs_clk_rate < DATA_RATE_MIN_SPEED)
+               return -EINVAL;
+
+       numerator = dphy_opts->hs_clk_rate;
+       denominator = ref_clk;
+       get_best_ratio(&numerator, &denominator, 255, 256);
+       if (!numerator || !denominator) {
+               dev_err(&phy->dev, "Invalid %d/%d for %ld/%ld\n",
+                       numerator, denominator,
+                       dphy_opts->hs_clk_rate, ref_clk);
+               return -EINVAL;
+       }
+
+       while ((numerator < 16) && (denominator <= 128)) {
+               numerator <<= 1;
+               denominator <<= 1;
+       }
+       /*
+        * CM ranges between 16 and 255
+        * CN ranges between 1 and 32
+        * CO is power of 2: 1, 2, 4, 8
+        */
+       i = __ffs(denominator);
+       if (i > 3)
+               i = 3;
+       cfg->cn = denominator >> i;
+       cfg->co = 1 << i;
+       cfg->cm = numerator;
+
+       if (cfg->cm < 16 || cfg->cm > 255 ||
+           cfg->cn < 1 || cfg->cn > 32 ||
+           cfg->co < 1 || cfg->co > 8) {
+               dev_err(&phy->dev, "Invalid CM/CN/CO values: %u/%u/%u\n",
+                       cfg->cm, cfg->cn, cfg->co);
+               dev_err(&phy->dev, "for hs_clk/ref_clk=%ld/%ld ~ %d/%d\n",
+                       dphy_opts->hs_clk_rate, ref_clk,
+                       numerator, denominator);
+               return -EINVAL;
+       }
+
+       dev_dbg(&phy->dev, "hs_clk/ref_clk=%ld/%ld ~ %d/%d\n",
+               dphy_opts->hs_clk_rate, ref_clk, numerator, denominator);
+
+       /* LP clock period */
+       tmp = 1000000000000LL;
+       do_div(tmp, dphy_opts->lp_clk_rate); /* ps */
+       if (tmp > ULONG_MAX)
+               return -EINVAL;
+
+       lp_t = tmp;
+       dev_dbg(&phy->dev, "LP clock %lu, period: %u ps\n",
+               dphy_opts->lp_clk_rate, lp_t);
+
+       /* hs_prepare: in lp clock periods */
+       if (2 * dphy_opts->hs_prepare > 5 * lp_t) {
+               dev_err(&phy->dev,
+                       "hs_prepare (%u) > 2.5 * lp clock period (%u)\n",
+                       dphy_opts->hs_prepare, lp_t);
+               return -EINVAL;
+       }
+       /* 00: lp_t, 01: 1.5 * lp_t, 10: 2 * lp_t, 11: 2.5 * lp_t */
+       if (dphy_opts->hs_prepare < lp_t) {
+               n = 0;
+       } else {
+               tmp = 2 * (dphy_opts->hs_prepare - lp_t);
+               do_div(tmp, lp_t);
+               n = tmp;
+       }
+       cfg->m_prg_hs_prepare = n;
+
+       /* clk_prepare: in lp clock periods */
+       if (2 * dphy_opts->clk_prepare > 3 * lp_t) {
+               dev_err(&phy->dev,
+                       "clk_prepare (%u) > 1.5 * lp clock period (%u)\n",
+                       dphy_opts->clk_prepare, lp_t);
+               return -EINVAL;
+       }
+       /* 00: lp_t, 01: 1.5 * lp_t */
+       cfg->mc_prg_hs_prepare = dphy_opts->clk_prepare > lp_t ? 1 : 0;
+
+       /* hs_zero: formula from NXP BSP */
+       n = (144 * (dphy_opts->hs_clk_rate / 1000000) - 47500) / 10000;
+       cfg->m_prg_hs_zero = n < 1 ? 1 : n;
+
+       /* clk_zero: formula from NXP BSP */
+       n = (34 * (dphy_opts->hs_clk_rate / 1000000) - 2500) / 1000;
+       cfg->mc_prg_hs_zero = n < 1 ? 1 : n;
+
+       /* clk_trail, hs_trail: formula from NXP BSP */
+       n = (103 * (dphy_opts->hs_clk_rate / 1000000) + 10000) / 10000;
+       if (n > 15)
+               n = 15;
+       if (n < 1)
+               n = 1;
+       cfg->m_prg_hs_trail = n;
+       cfg->mc_prg_hs_trail = n;
+
+       /* rxhs_settle: formula from NXP BSP */
+       if (dphy_opts->hs_clk_rate < MBPS(80))
+               cfg->rxhs_settle = 0x0d;
+       else if (dphy_opts->hs_clk_rate < MBPS(90))
+               cfg->rxhs_settle = 0x0c;
+       else if (dphy_opts->hs_clk_rate < MBPS(125))
+               cfg->rxhs_settle = 0x0b;
+       else if (dphy_opts->hs_clk_rate < MBPS(150))
+               cfg->rxhs_settle = 0x0a;
+       else if (dphy_opts->hs_clk_rate < MBPS(225))
+               cfg->rxhs_settle = 0x09;
+       else if (dphy_opts->hs_clk_rate < MBPS(500))
+               cfg->rxhs_settle = 0x08;
+       else
+               cfg->rxhs_settle = 0x07;
+
+       dev_dbg(&phy->dev, "phy_config: %u %u %u %u %u %u %u\n",
+               cfg->m_prg_hs_prepare, cfg->mc_prg_hs_prepare,
+               cfg->m_prg_hs_zero, cfg->mc_prg_hs_zero,
+               cfg->m_prg_hs_trail, cfg->mc_prg_hs_trail,
+               cfg->rxhs_settle);
+
+       return 0;
+}
+
+static void mixel_phy_set_hs_timings(struct phy *phy)
+{
+       struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
+
+       phy_write(phy, priv->cfg.m_prg_hs_prepare, DPHY_M_PRG_HS_PREPARE);
+       phy_write(phy, priv->cfg.mc_prg_hs_prepare, DPHY_MC_PRG_HS_PREPARE);
+       phy_write(phy, priv->cfg.m_prg_hs_zero, DPHY_M_PRG_HS_ZERO);
+       phy_write(phy, priv->cfg.mc_prg_hs_zero, DPHY_MC_PRG_HS_ZERO);
+       phy_write(phy, priv->cfg.m_prg_hs_trail, DPHY_M_PRG_HS_TRAIL);
+       phy_write(phy, priv->cfg.mc_prg_hs_trail, DPHY_MC_PRG_HS_TRAIL);
+       phy_write(phy, priv->cfg.rxhs_settle, priv->devdata->reg_rxhs_settle);
+}
+
+static int mixel_dphy_set_pll_params(struct phy *phy)
+{
+       struct mixel_dphy_priv *priv = dev_get_drvdata(phy->dev.parent);
+
+       if (priv->cfg.cm < 16 || priv->cfg.cm > 255 ||
+           priv->cfg.cn < 1 || priv->cfg.cn > 32 ||
+           priv->cfg.co < 1 || priv->cfg.co > 8) {
+               dev_err(&phy->dev, "Invalid CM/CN/CO values! (%u/%u/%u)\n",
+                       priv->cfg.cm, priv->cfg.cn, priv->cfg.co);
+               return -EINVAL;
+       }
+       dev_dbg(&phy->dev, "Using CM:%u CN:%u CO:%u\n",
+               priv->cfg.cm, priv->cfg.cn, priv->cfg.co);
+       phy_write(phy, CM(priv->cfg.cm), DPHY_CM);
+       phy_write(phy, CN(priv->cfg.cn), DPHY_CN);
+       phy_write(phy, CO(priv->cfg.co), DPHY_CO);
+       return 0;
+}
+
+static int mixel_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
+{
+       struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
+       struct mixel_dphy_cfg cfg = { 0 };
+       int ret;
+
+       ret = mixel_dphy_config_from_opts(phy, &opts->mipi_dphy, &cfg);
+       if (ret)
+               return ret;
+
+       /* Update the configuration */
+       memcpy(&priv->cfg, &cfg, sizeof(struct mixel_dphy_cfg));
+
+       phy_write(phy, 0x00, DPHY_LOCK_BYP);
+       phy_write(phy, 0x01, priv->devdata->reg_tx_rcal);
+       phy_write(phy, 0x00, priv->devdata->reg_auto_pd_en);
+       phy_write(phy, 0x02, priv->devdata->reg_rxlprp);
+       phy_write(phy, 0x02, priv->devdata->reg_rxcdrp);
+       phy_write(phy, 0x25, DPHY_TST);
+
+       mixel_phy_set_hs_timings(phy);
+       ret = mixel_dphy_set_pll_params(phy);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int mixel_dphy_validate(struct phy *phy, enum phy_mode mode, int submode,
+                              union phy_configure_opts *opts)
+{
+       struct mixel_dphy_cfg cfg = { 0 };
+
+       if (mode != PHY_MODE_MIPI_DPHY)
+               return -EINVAL;
+
+       return mixel_dphy_config_from_opts(phy, &opts->mipi_dphy, &cfg);
+}
+
+static int mixel_dphy_init(struct phy *phy)
+{
+       phy_write(phy, PWR_OFF, DPHY_PD_PLL);
+       phy_write(phy, PWR_OFF, DPHY_PD_DPHY);
+
+       return 0;
+}
+
+static int mixel_dphy_exit(struct phy *phy)
+{
+       phy_write(phy, 0, DPHY_CM);
+       phy_write(phy, 0, DPHY_CN);
+       phy_write(phy, 0, DPHY_CO);
+
+       return 0;
+}
+
+static int mixel_dphy_power_on(struct phy *phy)
+{
+       struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
+       u32 locked;
+       int ret;
+
+       ret = clk_prepare_enable(priv->phy_ref_clk);
+       if (ret < 0)
+               return ret;
+
+       phy_write(phy, PWR_ON, DPHY_PD_PLL);
+       ret = regmap_read_poll_timeout(priv->regmap, DPHY_LOCK, locked,
+                                      locked, PLL_LOCK_SLEEP,
+                                      PLL_LOCK_TIMEOUT);
+       if (ret < 0) {
+               dev_err(&phy->dev, "Could not get DPHY lock (%d)!\n", ret);
+               goto clock_disable;
+       }
+       phy_write(phy, PWR_ON, DPHY_PD_DPHY);
+
+       return 0;
+clock_disable:
+       clk_disable_unprepare(priv->phy_ref_clk);
+       return ret;
+}
+
+static int mixel_dphy_power_off(struct phy *phy)
+{
+       struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
+
+       phy_write(phy, PWR_OFF, DPHY_PD_PLL);
+       phy_write(phy, PWR_OFF, DPHY_PD_DPHY);
+
+       clk_disable_unprepare(priv->phy_ref_clk);
+
+       return 0;
+}
+
+static const struct phy_ops mixel_dphy_phy_ops = {
+       .init = mixel_dphy_init,
+       .exit = mixel_dphy_exit,
+       .power_on = mixel_dphy_power_on,
+       .power_off = mixel_dphy_power_off,
+       .configure = mixel_dphy_configure,
+       .validate = mixel_dphy_validate,
+       .owner = THIS_MODULE,
+};
+
+static const struct of_device_id mixel_dphy_of_match[] = {
+       { .compatible = "fsl,imx8mq-mipi-dphy",
+         .data = &mixel_dphy_devdata[MIXEL_IMX8MQ] },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mixel_dphy_of_match);
+
+static int mixel_dphy_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct phy_provider *phy_provider;
+       struct mixel_dphy_priv *priv;
+       struct resource *res;
+       struct phy *phy;
+       void __iomem *base;
+
+       if (!np)
+               return -ENODEV;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->devdata = of_device_get_match_data(&pdev->dev);
+       if (!priv->devdata)
+               return -EINVAL;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+                                            &mixel_dphy_regmap_config);
+       if (IS_ERR(priv->regmap)) {
+               dev_err(dev, "Couldn't create the DPHY regmap\n");
+               return PTR_ERR(priv->regmap);
+       }
+
+       priv->phy_ref_clk = devm_clk_get(&pdev->dev, "phy_ref");
+       if (IS_ERR(priv->phy_ref_clk)) {
+               dev_err(dev, "No phy_ref clock found\n");
+               return PTR_ERR(priv->phy_ref_clk);
+       }
+       dev_dbg(dev, "phy_ref clock rate: %lu\n",
+               clk_get_rate(priv->phy_ref_clk));
+
+       dev_set_drvdata(dev, priv);
+
+       phy = devm_phy_create(dev, np, &mixel_dphy_phy_ops);
+       if (IS_ERR(phy)) {
+               dev_err(dev, "Failed to create phy %ld\n", PTR_ERR(phy));
+               return PTR_ERR(phy);
+       }
+       phy_set_drvdata(phy, priv);
+
+       phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+       return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static struct platform_driver mixel_dphy_driver = {
+       .probe  = mixel_dphy_probe,
+       .driver = {
+               .name = "mixel-mipi-dphy",
+               .of_match_table = mixel_dphy_of_match,
+       }
+};
+module_platform_driver(mixel_dphy_driver);
+
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("Mixel MIPI-DSI PHY driver");
+MODULE_LICENSE("GPL");
index eb49864..e46824d 100644 (file)
@@ -25,6 +25,14 @@ config PHY_QCOM_IPQ806X_SATA
        depends on OF
        select GENERIC_PHY
 
+config PHY_QCOM_PCIE2
+       tristate "Qualcomm PCIe Gen2 PHY Driver"
+       depends on OF && COMMON_CLK && (ARCH_QCOM || COMPILE_TEST)
+       select GENERIC_PHY
+       help
+         Enable this to support the Qualcomm PCIe PHY, used with the Synopsys
+         based PCIe controller.
+
 config PHY_QCOM_QMP
        tristate "Qualcomm QMP PHY Driver"
        depends on OF && COMMON_CLK && (ARCH_QCOM || COMPILE_TEST)
index c56efd3..283251d 100644 (file)
@@ -2,6 +2,7 @@
 obj-$(CONFIG_PHY_ATH79_USB)            += phy-ath79-usb.o
 obj-$(CONFIG_PHY_QCOM_APQ8064_SATA)    += phy-qcom-apq8064-sata.o
 obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA)    += phy-qcom-ipq806x-sata.o
+obj-$(CONFIG_PHY_QCOM_PCIE2)           += phy-qcom-pcie2.o
 obj-$(CONFIG_PHY_QCOM_QMP)             += phy-qcom-qmp.o
 obj-$(CONFIG_PHY_QCOM_QUSB2)           += phy-qcom-qusb2.o
 obj-$(CONFIG_PHY_QCOM_UFS)             += phy-qcom-ufs.o
diff --git a/drivers/phy/qualcomm/phy-qcom-pcie2.c b/drivers/phy/qualcomm/phy-qcom-pcie2.c
new file mode 100644 (file)
index 0000000..9dba359
--- /dev/null
@@ -0,0 +1,331 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019, Linaro Ltd.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/phy/phy.h>
+
+#define PCIE20_PARF_PHY_STTS         0x3c
+#define PCIE2_PHY_RESET_CTRL         0x44
+#define PCIE20_PARF_PHY_REFCLK_CTRL2 0xa0
+#define PCIE20_PARF_PHY_REFCLK_CTRL3 0xa4
+#define PCIE20_PARF_PCS_SWING_CTRL1  0x88
+#define PCIE20_PARF_PCS_SWING_CTRL2  0x8c
+#define PCIE20_PARF_PCS_DEEMPH1      0x74
+#define PCIE20_PARF_PCS_DEEMPH2      0x78
+#define PCIE20_PARF_PCS_DEEMPH3      0x7c
+#define PCIE20_PARF_CONFIGBITS       0x84
+#define PCIE20_PARF_PHY_CTRL3        0x94
+#define PCIE20_PARF_PCS_CTRL         0x80
+
+#define TX_AMP_VAL                   120
+#define PHY_RX0_EQ_GEN1_VAL          0
+#define PHY_RX0_EQ_GEN2_VAL          4
+#define TX_DEEMPH_GEN1_VAL           24
+#define TX_DEEMPH_GEN2_3_5DB_VAL     26
+#define TX_DEEMPH_GEN2_6DB_VAL       36
+#define PHY_TX0_TERM_OFFST_VAL       0
+
+struct qcom_phy {
+       struct device *dev;
+       void __iomem *base;
+
+       struct regulator_bulk_data vregs[2];
+
+       struct reset_control *phy_reset;
+       struct reset_control *pipe_reset;
+       struct clk *pipe_clk;
+};
+
+static int qcom_pcie2_phy_init(struct phy *phy)
+{
+       struct qcom_phy *qphy = phy_get_drvdata(phy);
+       int ret;
+
+       ret = reset_control_deassert(qphy->phy_reset);
+       if (ret) {
+               dev_err(qphy->dev, "cannot deassert pipe reset\n");
+               return ret;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
+       if (ret)
+               reset_control_assert(qphy->phy_reset);
+
+       return ret;
+}
+
+static int qcom_pcie2_phy_power_on(struct phy *phy)
+{
+       struct qcom_phy *qphy = phy_get_drvdata(phy);
+       int ret;
+       u32 val;
+
+       /* Program REF_CLK source */
+       val = readl(qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2);
+       val &= ~BIT(1);
+       writel(val, qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2);
+
+       usleep_range(1000, 2000);
+
+       /* Don't use PAD for refclock */
+       val = readl(qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2);
+       val &= ~BIT(0);
+       writel(val, qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2);
+
+       /* Program SSP ENABLE */
+       val = readl(qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL3);
+       val |= BIT(0);
+       writel(val, qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL3);
+
+       usleep_range(1000, 2000);
+
+       /* Assert Phy SW Reset */
+       val = readl(qphy->base + PCIE2_PHY_RESET_CTRL);
+       val |= BIT(0);
+       writel(val, qphy->base + PCIE2_PHY_RESET_CTRL);
+
+       /* Program Tx Amplitude */
+       val = readl(qphy->base + PCIE20_PARF_PCS_SWING_CTRL1);
+       val &= ~0x7f;
+       val |= TX_AMP_VAL;
+       writel(val, qphy->base + PCIE20_PARF_PCS_SWING_CTRL1);
+
+       val = readl(qphy->base + PCIE20_PARF_PCS_SWING_CTRL2);
+       val &= ~0x7f;
+       val |= TX_AMP_VAL;
+       writel(val, qphy->base + PCIE20_PARF_PCS_SWING_CTRL2);
+
+       /* Program De-Emphasis */
+       val = readl(qphy->base + PCIE20_PARF_PCS_DEEMPH1);
+       val &= ~0x3f;
+       val |= TX_DEEMPH_GEN2_6DB_VAL;
+       writel(val, qphy->base + PCIE20_PARF_PCS_DEEMPH1);
+
+       val = readl(qphy->base + PCIE20_PARF_PCS_DEEMPH2);
+       val &= ~0x3f;
+       val |= TX_DEEMPH_GEN2_3_5DB_VAL;
+       writel(val, qphy->base + PCIE20_PARF_PCS_DEEMPH2);
+
+       val = readl(qphy->base + PCIE20_PARF_PCS_DEEMPH3);
+       val &= ~0x3f;
+       val |= TX_DEEMPH_GEN1_VAL;
+       writel(val, qphy->base + PCIE20_PARF_PCS_DEEMPH3);
+
+       /* Program Rx_Eq */
+       val = readl(qphy->base + PCIE20_PARF_CONFIGBITS);
+       val &= ~0x7;
+       val |= PHY_RX0_EQ_GEN2_VAL;
+       writel(val, qphy->base + PCIE20_PARF_CONFIGBITS);
+
+       /* Program Tx0_term_offset */
+       val = readl(qphy->base + PCIE20_PARF_PHY_CTRL3);
+       val &= ~0x1f;
+       val |= PHY_TX0_TERM_OFFST_VAL;
+       writel(val, qphy->base + PCIE20_PARF_PHY_CTRL3);
+
+       /* disable Tx2Rx Loopback */
+       val = readl(qphy->base + PCIE20_PARF_PCS_CTRL);
+       val &= ~BIT(1);
+       writel(val, qphy->base + PCIE20_PARF_PCS_CTRL);
+
+       /* De-assert Phy SW Reset */
+       val = readl(qphy->base + PCIE2_PHY_RESET_CTRL);
+       val &= ~BIT(0);
+       writel(val, qphy->base + PCIE2_PHY_RESET_CTRL);
+
+       usleep_range(1000, 2000);
+
+       ret = reset_control_deassert(qphy->pipe_reset);
+       if (ret) {
+               dev_err(qphy->dev, "cannot deassert pipe reset\n");
+               goto out;
+       }
+
+       clk_set_rate(qphy->pipe_clk, 250000000);
+
+       ret = clk_prepare_enable(qphy->pipe_clk);
+       if (ret) {
+               dev_err(qphy->dev, "failed to enable pipe clock\n");
+               goto out;
+       }
+
+       ret = readl_poll_timeout(qphy->base + PCIE20_PARF_PHY_STTS, val,
+                                !(val & BIT(0)), 1000, 10);
+       if (ret)
+               dev_err(qphy->dev, "phy initialization failed\n");
+
+out:
+       return ret;
+}
+
+static int qcom_pcie2_phy_power_off(struct phy *phy)
+{
+       struct qcom_phy *qphy = phy_get_drvdata(phy);
+       u32 val;
+
+       val = readl(qphy->base + PCIE2_PHY_RESET_CTRL);
+       val |= BIT(0);
+       writel(val, qphy->base + PCIE2_PHY_RESET_CTRL);
+
+       clk_disable_unprepare(qphy->pipe_clk);
+       reset_control_assert(qphy->pipe_reset);
+
+       return 0;
+}
+
+static int qcom_pcie2_phy_exit(struct phy *phy)
+{
+       struct qcom_phy *qphy = phy_get_drvdata(phy);
+
+       regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
+       reset_control_assert(qphy->phy_reset);
+
+       return 0;
+}
+
+static const struct phy_ops qcom_pcie2_ops = {
+       .init = qcom_pcie2_phy_init,
+       .power_on = qcom_pcie2_phy_power_on,
+       .power_off = qcom_pcie2_phy_power_off,
+       .exit = qcom_pcie2_phy_exit,
+       .owner = THIS_MODULE,
+};
+
+/*
+ * Register a fixed rate pipe clock.
+ *
+ * The <s>_pipe_clksrc generated by PHY goes to the GCC that gate
+ * controls it. The <s>_pipe_clk coming out of the GCC is requested
+ * by the PHY driver for its operations.
+ * We register the <s>_pipe_clksrc here. The gcc driver takes care
+ * of assigning this <s>_pipe_clksrc as parent to <s>_pipe_clk.
+ * Below picture shows this relationship.
+ *
+ *         +---------------+
+ *         |   PHY block   |<<---------------------------------------+
+ *         |               |                                         |
+ *         |   +-------+   |                   +-----+               |
+ *   I/P---^-->|  PLL  |---^--->pipe_clksrc--->| GCC |--->pipe_clk---+
+ *    clk  |   +-------+   |                   +-----+
+ *         +---------------+
+ */
+static int phy_pipe_clksrc_register(struct qcom_phy *qphy)
+{
+       struct device_node *np = qphy->dev->of_node;
+       struct clk_fixed_rate *fixed;
+       struct clk_init_data init = { };
+       int ret;
+
+       ret = of_property_read_string(np, "clock-output-names", &init.name);
+       if (ret) {
+               dev_err(qphy->dev, "%s: No clock-output-names\n", np->name);
+               return ret;
+       }
+
+       fixed = devm_kzalloc(qphy->dev, sizeof(*fixed), GFP_KERNEL);
+       if (!fixed)
+               return -ENOMEM;
+
+       init.ops = &clk_fixed_rate_ops;
+
+       /* controllers using QMP phys use 250MHz pipe clock interface */
+       fixed->fixed_rate = 250000000;
+       fixed->hw.init = &init;
+
+       return devm_clk_hw_register(qphy->dev, &fixed->hw);
+}
+
+static int qcom_pcie2_phy_probe(struct platform_device *pdev)
+{
+       struct phy_provider *phy_provider;
+       struct qcom_phy *qphy;
+       struct resource *res;
+       struct device *dev = &pdev->dev;
+       struct phy *phy;
+       int ret;
+
+       qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
+       if (!qphy)
+               return -ENOMEM;
+
+       qphy->dev = dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       qphy->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(qphy->base))
+               return PTR_ERR(qphy->base);
+
+       ret = phy_pipe_clksrc_register(qphy);
+       if (ret) {
+               dev_err(dev, "failed to register pipe_clk\n");
+               return ret;
+       }
+
+       qphy->vregs[0].supply = "vdda-vp";
+       qphy->vregs[1].supply = "vdda-vph";
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(qphy->vregs), qphy->vregs);
+       if (ret < 0)
+               return ret;
+
+       qphy->pipe_clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(qphy->pipe_clk)) {
+               dev_err(dev, "failed to acquire pipe clock\n");
+               return PTR_ERR(qphy->pipe_clk);
+       }
+
+       qphy->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
+       if (IS_ERR(qphy->phy_reset)) {
+               dev_err(dev, "failed to acquire phy reset\n");
+               return PTR_ERR(qphy->phy_reset);
+       }
+
+       qphy->pipe_reset = devm_reset_control_get_exclusive(dev, "pipe");
+       if (IS_ERR(qphy->pipe_reset)) {
+               dev_err(dev, "failed to acquire pipe reset\n");
+               return PTR_ERR(qphy->pipe_reset);
+       }
+
+       phy = devm_phy_create(dev, dev->of_node, &qcom_pcie2_ops);
+       if (IS_ERR(phy)) {
+               dev_err(dev, "failed to create phy\n");
+               return PTR_ERR(phy);
+       }
+
+       phy_set_drvdata(phy, qphy);
+
+       phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+       if (IS_ERR(phy_provider))
+               dev_err(dev, "failed to register phy provider\n");
+
+       return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id qcom_pcie2_phy_match_table[] = {
+       { .compatible = "qcom,pcie2-phy" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, qcom_pcie2_phy_match_table);
+
+static struct platform_driver qcom_pcie2_phy_driver = {
+       .probe = qcom_pcie2_phy_probe,
+       .driver = {
+               .name = "phy-qcom-pcie2",
+               .of_match_table = qcom_pcie2_phy_match_table,
+       },
+};
+
+module_platform_driver(qcom_pcie2_phy_driver);
+
+MODULE_DESCRIPTION("Qualcomm PCIe PHY driver");
+MODULE_LICENSE("GPL v2");
index cd91b41..34ff643 100644 (file)
@@ -1074,6 +1074,7 @@ static const struct qmp_phy_cfg msm8996_pciephy_cfg = {
 
        .start_ctrl             = PCS_START | PLL_READY_GATE_EN,
        .pwrdn_ctrl             = SW_PWRDN | REFCLK_DRV_DSBL,
+       .mask_pcs_ready         = PHYSTATUS,
        .mask_com_pcs_ready     = PCS_READY,
 
        .has_phy_com_ctrl       = true,
@@ -1253,7 +1254,7 @@ static const struct qmp_phy_cfg msm8998_pciephy_cfg = {
 
        .start_ctrl             = SERDES_START | PCS_START,
        .pwrdn_ctrl             = SW_PWRDN | REFCLK_DRV_DSBL,
-       .mask_com_pcs_ready     = PCS_READY,
+       .mask_pcs_ready         = PHYSTATUS,
 };
 
 static const struct qmp_phy_cfg msm8998_usb3phy_cfg = {
@@ -1547,7 +1548,7 @@ static int qcom_qmp_phy_enable(struct phy *phy)
        status = pcs + cfg->regs[QPHY_PCS_READY_STATUS];
        mask = cfg->mask_pcs_ready;
 
-       ret = readl_poll_timeout(status, val, !(val & mask), 1,
+       ret = readl_poll_timeout(status, val, val & mask, 10,
                                 PHY_INIT_COMPLETE_TIMEOUT);
        if (ret) {
                dev_err(qmp->dev, "phy initialization timed-out\n");
index 1cbf1d6..bf94a52 100644 (file)
@@ -564,7 +564,7 @@ static int __maybe_unused qusb2_phy_runtime_resume(struct device *dev)
        }
 
        if (!qphy->has_se_clk_scheme) {
-               clk_prepare_enable(qphy->ref_clk);
+               ret = clk_prepare_enable(qphy->ref_clk);
                if (ret) {
                        dev_err(dev, "failed to enable ref clk, %d\n", ret);
                        goto disable_ahb_clk;
index 8dc5710..2926e49 100644 (file)
@@ -391,6 +391,7 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev)
                error = of_property_read_u32(np, "reg", &channel_num);
                if (error || channel_num > 2) {
                        dev_err(dev, "Invalid \"reg\" property\n");
+                       of_node_put(np);
                        return error;
                }
                channel->select_mask = select_mask[channel_num];
@@ -406,6 +407,7 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev)
                                                   data->gen2_phy_ops);
                        if (IS_ERR(phy->phy)) {
                                dev_err(dev, "Failed to create PHY\n");
+                               of_node_put(np);
                                return PTR_ERR(phy->phy);
                        }
                        phy_set_drvdata(phy->phy, phy);
index 1322185..8ffba67 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
@@ -106,6 +107,7 @@ struct rcar_gen3_chan {
        struct rcar_gen3_phy rphys[NUM_OF_PHYS];
        struct regulator *vbus;
        struct work_struct work;
+       struct mutex lock;      /* protects rphys[...].powered */
        enum usb_dr_mode dr_mode;
        bool extcon_host;
        bool is_otg_channel;
@@ -437,15 +439,16 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
        struct rcar_gen3_chan *channel = rphy->ch;
        void __iomem *usb2_base = channel->base;
        u32 val;
-       int ret;
+       int ret = 0;
 
+       mutex_lock(&channel->lock);
        if (!rcar_gen3_are_all_rphys_power_off(channel))
-               return 0;
+               goto out;
 
        if (channel->vbus) {
                ret = regulator_enable(channel->vbus);
                if (ret)
-                       return ret;
+                       goto out;
        }
 
        val = readl(usb2_base + USB2_USBCTR);
@@ -454,7 +457,10 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
        val &= ~USB2_USBCTR_PLL_RST;
        writel(val, usb2_base + USB2_USBCTR);
 
+out:
+       /* The powered flag should be set for any other phys anyway */
        rphy->powered = true;
+       mutex_unlock(&channel->lock);
 
        return 0;
 }
@@ -465,14 +471,18 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p)
        struct rcar_gen3_chan *channel = rphy->ch;
        int ret = 0;
 
+       mutex_lock(&channel->lock);
        rphy->powered = false;
 
        if (!rcar_gen3_are_all_rphys_power_off(channel))
-               return 0;
+               goto out;
 
        if (channel->vbus)
                ret = regulator_disable(channel->vbus);
 
+out:
+       mutex_unlock(&channel->lock);
+
        return ret;
 }
 
@@ -639,6 +649,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
        if (!phy_usb2_ops)
                return -EINVAL;
 
+       mutex_init(&channel->lock);
        for (i = 0; i < NUM_OF_PHYS; i++) {
                channel->rphys[i].phy = devm_phy_create(dev, NULL,
                                                        phy_usb2_ops);
index e51d45e..6c82f4f 100644 (file)
@@ -156,9 +156,8 @@ static int samsung_usb2_phy_probe(struct platform_device *pdev)
        if (!cfg)
                return -EINVAL;
 
-       drv = devm_kzalloc(dev, sizeof(struct samsung_usb2_phy_driver) +
-               cfg->num_phys * sizeof(struct samsung_usb2_phy_instance),
-                                                               GFP_KERNEL);
+       drv = devm_kzalloc(dev, struct_size(drv, instances, cfg->num_phys),
+                          GFP_KERNEL);
        if (!drv)
                return -ENOMEM;
 
index e8a2ba6..98d8492 100644 (file)
@@ -1713,6 +1713,13 @@ static const struct tegra_xusb_padctl_ops tegra124_xusb_padctl_ops = {
        .hsic_set_idle = tegra124_hsic_set_idle,
 };
 
+static const char * const tegra124_xusb_padctl_supply_names[] = {
+       "avdd-pll-utmip",
+       "avdd-pll-erefe",
+       "avdd-pex-pll",
+       "hvdd-pex-pll-e",
+};
+
 const struct tegra_xusb_padctl_soc tegra124_xusb_padctl_soc = {
        .num_pads = ARRAY_SIZE(tegra124_pads),
        .pads = tegra124_pads,
@@ -1735,6 +1742,8 @@ const struct tegra_xusb_padctl_soc tegra124_xusb_padctl_soc = {
                },
        },
        .ops = &tegra124_xusb_padctl_ops,
+       .supply_names = tegra124_xusb_padctl_supply_names,
+       .num_supplies = ARRAY_SIZE(tegra124_xusb_padctl_supply_names),
 };
 EXPORT_SYMBOL_GPL(tegra124_xusb_padctl_soc);
 
index 18cea83..0c0df68 100644 (file)
@@ -2009,6 +2009,13 @@ static const struct tegra_xusb_padctl_ops tegra210_xusb_padctl_ops = {
        .hsic_set_idle = tegra210_hsic_set_idle,
 };
 
+static const char * const tegra210_xusb_padctl_supply_names[] = {
+       "avdd-pll-utmip",
+       "avdd-pll-uerefe",
+       "dvdd-pex-pll",
+       "hvdd-pex-pll-e",
+};
+
 const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc = {
        .num_pads = ARRAY_SIZE(tegra210_pads),
        .pads = tegra210_pads,
@@ -2027,6 +2034,8 @@ const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc = {
                },
        },
        .ops = &tegra210_xusb_padctl_ops,
+       .supply_names = tegra210_xusb_padctl_supply_names,
+       .num_supplies = ARRAY_SIZE(tegra210_xusb_padctl_supply_names),
 };
 EXPORT_SYMBOL_GPL(tegra210_xusb_padctl_soc);
 
index d376920..f8edd08 100644 (file)
@@ -247,8 +247,8 @@ static void serdes_am654_release(struct phy *x)
        mux_control_deselect(phy->control);
 }
 
-struct phy *serdes_am654_xlate(struct device *dev, struct of_phandle_args
-                                *args)
+static struct phy *serdes_am654_xlate(struct device *dev,
+                                     struct of_phandle_args *args)
 {
        struct serdes_am654 *am654_phy;
        struct phy *phy;
index 068729b..ea89626 100644 (file)
@@ -2,6 +2,6 @@
 # Aspeed pinctrl support
 
 ccflags-y += $(call cc-option,-Woverride-init)
-obj-$(CONFIG_PINCTRL_ASPEED)   += pinctrl-aspeed.o
+obj-$(CONFIG_PINCTRL_ASPEED)   += pinctrl-aspeed.o pinmux-aspeed.o
 obj-$(CONFIG_PINCTRL_ASPEED_G4)        += pinctrl-aspeed-g4.o
 obj-$(CONFIG_PINCTRL_ASPEED_G5)        += pinctrl-aspeed-g5.o
index 73e2c9c..384396c 100644 (file)
 
 #include "../core.h"
 #include "../pinctrl-utils.h"
+#include "pinmux-aspeed.h"
 #include "pinctrl-aspeed.h"
 
+/*
+ * The "Multi-function Pins Mapping and Control" table in the SoC datasheet
+ * references registers by the device/offset mnemonic. The register macros
+ * below are named the same way to ease transcription and verification (as
+ * opposed to naming them e.g. PINMUX_CTRL_[0-9]). Further, signal expressions
+ * reference registers beyond those dedicated to pinmux, such as the system
+ * reset control and MAC clock configuration registers.
+ */
+#define SCU2C           0x2C /* Misc. Control Register */
+#define SCU3C           0x3C /* System Reset Control/Status Register */
+#define SCU48           0x48 /* MAC Interface Clock Delay Setting */
+#define HW_STRAP1       0x70 /* AST2400 strapping is 33 bits, is split */
+#define HW_REVISION_ID  0x7C /* Silicon revision ID register */
+#define SCU80           0x80 /* Multi-function Pin Control #1 */
+#define SCU84           0x84 /* Multi-function Pin Control #2 */
+#define SCU88           0x88 /* Multi-function Pin Control #3 */
+#define SCU8C           0x8C /* Multi-function Pin Control #4 */
+#define SCU90           0x90 /* Multi-function Pin Control #5 */
+#define SCU94           0x94 /* Multi-function Pin Control #6 */
+#define SCUA0           0xA0 /* Multi-function Pin Control #7 */
+#define SCUA4           0xA4 /* Multi-function Pin Control #8 */
+#define SCUA8           0xA8 /* Multi-function Pin Control #9 */
+#define SCUAC           0xAC /* Multi-function Pin Control #10 */
+#define HW_STRAP2       0xD0 /* Strapping */
+
 /*
  * Uses undefined macros for symbol naming and references, eg GPIOA0, MAC1LINK,
  * TIMER3 etc.
@@ -2386,13 +2412,73 @@ static const struct aspeed_pin_config aspeed_g4_configs[] = {
        { PIN_CONFIG_INPUT_DEBOUNCE, { C14, B14 }, SCUA8, 27 },
 };
 
+static int aspeed_g4_sig_expr_set(const struct aspeed_pinmux_data *ctx,
+                                 const struct aspeed_sig_expr *expr,
+                                 bool enable)
+{
+       int ret;
+       int i;
+
+       for (i = 0; i < expr->ndescs; i++) {
+               const struct aspeed_sig_desc *desc = &expr->descs[i];
+               u32 pattern = enable ? desc->enable : desc->disable;
+               u32 val = (pattern << __ffs(desc->mask));
+
+               if (!ctx->maps[desc->ip])
+                       return -ENODEV;
+
+               /*
+                * Strap registers are configured in hardware or by early-boot
+                * firmware. Treat them as read-only despite that we can write
+                * them. This may mean that certain functions cannot be
+                * deconfigured and is the reason we re-evaluate after writing
+                * all descriptor bits.
+                *
+                * Port D and port E GPIO loopback modes are the only exception
+                * as those are commonly used with front-panel buttons to allow
+                * normal operation of the host when the BMC is powered off or
+                * fails to boot. Once the BMC has booted, the loopback mode
+                * must be disabled for the BMC to control host power-on and
+                * reset.
+                */
+               if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP1 &&
+                   !(desc->mask & (BIT(21) | BIT(22))))
+                       continue;
+
+               if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP2)
+                       continue;
+
+               ret = regmap_update_bits(ctx->maps[desc->ip], desc->reg,
+                                        desc->mask, val);
+
+               if (ret)
+                       return ret;
+       }
+
+       ret = aspeed_sig_expr_eval(ctx, expr, enable);
+       if (ret < 0)
+               return ret;
+
+       if (!ret)
+               return -EPERM;
+
+       return 0;
+}
+
+static const struct aspeed_pinmux_ops aspeed_g4_ops = {
+       .set = aspeed_g4_sig_expr_set,
+};
+
 static struct aspeed_pinctrl_data aspeed_g4_pinctrl_data = {
        .pins = aspeed_g4_pins,
        .npins = ARRAY_SIZE(aspeed_g4_pins),
-       .groups = aspeed_g4_groups,
-       .ngroups = ARRAY_SIZE(aspeed_g4_groups),
-       .functions = aspeed_g4_functions,
-       .nfunctions = ARRAY_SIZE(aspeed_g4_functions),
+       .pinmux = {
+               .ops = &aspeed_g4_ops,
+               .groups = aspeed_g4_groups,
+               .ngroups = ARRAY_SIZE(aspeed_g4_groups),
+               .functions = aspeed_g4_functions,
+               .nfunctions = ARRAY_SIZE(aspeed_g4_functions),
+       },
        .configs = aspeed_g4_configs,
        .nconfigs = ARRAY_SIZE(aspeed_g4_configs),
 };
index aa7e148..053101f 100644 (file)
 #include "../pinctrl-utils.h"
 #include "pinctrl-aspeed.h"
 
+/*
+ * The "Multi-function Pins Mapping and Control" table in the SoC datasheet
+ * references registers by the device/offset mnemonic. The register macros
+ * below are named the same way to ease transcription and verification (as
+ * opposed to naming them e.g. PINMUX_CTRL_[0-9]). Further, signal expressions
+ * reference registers beyond those dedicated to pinmux, such as the system
+ * reset control and MAC clock configuration registers. The AST2500 goes a step
+ * further and references registers in the graphics IP block.
+ */
+#define SCU2C           0x2C /* Misc. Control Register */
+#define SCU3C           0x3C /* System Reset Control/Status Register */
+#define SCU48           0x48 /* MAC Interface Clock Delay Setting */
+#define HW_STRAP1       0x70 /* AST2400 strapping is 33 bits, is split */
+#define HW_REVISION_ID  0x7C /* Silicon revision ID register */
+#define SCU80           0x80 /* Multi-function Pin Control #1 */
+#define SCU84           0x84 /* Multi-function Pin Control #2 */
+#define SCU88           0x88 /* Multi-function Pin Control #3 */
+#define SCU8C           0x8C /* Multi-function Pin Control #4 */
+#define SCU90           0x90 /* Multi-function Pin Control #5 */
+#define SCU94           0x94 /* Multi-function Pin Control #6 */
+#define SCUA0           0xA0 /* Multi-function Pin Control #7 */
+#define SCUA4           0xA4 /* Multi-function Pin Control #8 */
+#define SCUA8           0xA8 /* Multi-function Pin Control #9 */
+#define SCUAC           0xAC /* Multi-function Pin Control #10 */
+#define HW_STRAP2       0xD0 /* Strapping */
+
 #define ASPEED_G5_NR_PINS 236
 
 #define COND1          { ASPEED_IP_SCU, SCU90, BIT(6), 0, 0 }
@@ -573,6 +599,8 @@ SS_PIN_DECL(N3, GPIOJ2, SGPMO);
 SIG_EXPR_LIST_DECL_SINGLE(SGPMI, SGPM, SIG_DESC_SET(SCU84, 11));
 SS_PIN_DECL(N4, GPIOJ3, SGPMI);
 
+FUNC_GROUP_DECL(SGPM, R2, L2, N3, N4);
+
 #define N5 76
 SIG_EXPR_LIST_DECL_SINGLE(VGAHS, VGAHS, SIG_DESC_SET(SCU84, 12));
 SIG_EXPR_LIST_DECL_SINGLE(DASHN5, DASHN5, SIG_DESC_SET(SCU94, 8));
@@ -2123,6 +2151,7 @@ static const struct aspeed_pin_group aspeed_g5_groups[] = {
        ASPEED_PINCTRL_GROUP(SD2),
        ASPEED_PINCTRL_GROUP(SDA1),
        ASPEED_PINCTRL_GROUP(SDA2),
+       ASPEED_PINCTRL_GROUP(SGPM),
        ASPEED_PINCTRL_GROUP(SGPS1),
        ASPEED_PINCTRL_GROUP(SGPS2),
        ASPEED_PINCTRL_GROUP(SIOONCTRL),
@@ -2292,6 +2321,7 @@ static const struct aspeed_pin_function aspeed_g5_functions[] = {
        ASPEED_PINCTRL_FUNC(SD2),
        ASPEED_PINCTRL_FUNC(SDA1),
        ASPEED_PINCTRL_FUNC(SDA2),
+       ASPEED_PINCTRL_FUNC(SGPM),
        ASPEED_PINCTRL_FUNC(SGPS1),
        ASPEED_PINCTRL_FUNC(SGPS2),
        ASPEED_PINCTRL_FUNC(SIOONCTRL),
@@ -2477,13 +2507,98 @@ static struct aspeed_pin_config aspeed_g5_configs[] = {
        { PIN_CONFIG_INPUT_DEBOUNCE, { A20, B19 }, SCUA8, 27 },
 };
 
+/**
+ * Configure a pin's signal by applying an expression's descriptor state for
+ * all descriptors in the expression.
+ *
+ * @ctx: The pinmux context
+ * @expr: The expression associated with the function whose signal is to be
+ *        configured
+ * @enable: true to enable an function's signal through a pin's signal
+ *          expression, false to disable the function's signal
+ *
+ * Return: 0 if the expression is configured as requested and a negative error
+ * code otherwise
+ */
+static int aspeed_g5_sig_expr_set(const struct aspeed_pinmux_data *ctx,
+                                 const struct aspeed_sig_expr *expr,
+                                 bool enable)
+{
+       int ret;
+       int i;
+
+       for (i = 0; i < expr->ndescs; i++) {
+               const struct aspeed_sig_desc *desc = &expr->descs[i];
+               u32 pattern = enable ? desc->enable : desc->disable;
+               u32 val = (pattern << __ffs(desc->mask));
+
+               if (!ctx->maps[desc->ip])
+                       return -ENODEV;
+
+               /*
+                * Strap registers are configured in hardware or by early-boot
+                * firmware. Treat them as read-only despite that we can write
+                * them. This may mean that certain functions cannot be
+                * deconfigured and is the reason we re-evaluate after writing
+                * all descriptor bits.
+                *
+                * Port D and port E GPIO loopback modes are the only exception
+                * as those are commonly used with front-panel buttons to allow
+                * normal operation of the host when the BMC is powered off or
+                * fails to boot. Once the BMC has booted, the loopback mode
+                * must be disabled for the BMC to control host power-on and
+                * reset.
+                */
+               if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP1 &&
+                   !(desc->mask & (BIT(21) | BIT(22))))
+                       continue;
+
+               if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP2)
+                       continue;
+
+               /* On AST2500, Set bits in SCU70 are cleared from SCU7C */
+               if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP1) {
+                       u32 value = ~val & desc->mask;
+
+                       if (value) {
+                               ret = regmap_write(ctx->maps[desc->ip],
+                                                  HW_REVISION_ID, value);
+                               if (ret < 0)
+                                       return ret;
+                       }
+               }
+
+               ret = regmap_update_bits(ctx->maps[desc->ip], desc->reg,
+                                        desc->mask, val);
+
+               if (ret)
+                       return ret;
+       }
+
+       ret = aspeed_sig_expr_eval(ctx, expr, enable);
+       if (ret < 0)
+               return ret;
+
+       if (!ret)
+               return -EPERM;
+
+       return 0;
+}
+
+static const struct aspeed_pinmux_ops aspeed_g5_ops = {
+       .set = aspeed_g5_sig_expr_set,
+};
+
 static struct aspeed_pinctrl_data aspeed_g5_pinctrl_data = {
        .pins = aspeed_g5_pins,
        .npins = ARRAY_SIZE(aspeed_g5_pins),
-       .groups = aspeed_g5_groups,
-       .ngroups = ARRAY_SIZE(aspeed_g5_groups),
-       .functions = aspeed_g5_functions,
-       .nfunctions = ARRAY_SIZE(aspeed_g5_functions),
+       .pinmux = {
+               .ops = &aspeed_g5_ops,
+               .groups = aspeed_g5_groups,
+               .ngroups = ARRAY_SIZE(aspeed_g5_groups),
+               .functions = aspeed_g5_functions,
+               .nfunctions = ARRAY_SIZE(aspeed_g5_functions),
+       },
        .configs = aspeed_g5_configs,
        .nconfigs = ARRAY_SIZE(aspeed_g5_configs),
 };
@@ -2539,7 +2654,7 @@ static int aspeed_g5_pinctrl_probe(struct platform_device *pdev)
                dev_warn(&pdev->dev, "No GFX phandle found, some mux configurations may fail\n");
                map = NULL;
        }
-       aspeed_g5_pinctrl_data.maps[ASPEED_IP_GFX] = map;
+       aspeed_g5_pinctrl_data.pinmux.maps[ASPEED_IP_GFX] = map;
 
        node = of_parse_phandle(pdev->dev.of_node, "aspeed,external-nodes", 1);
        if (node) {
@@ -2553,7 +2668,7 @@ static int aspeed_g5_pinctrl_probe(struct platform_device *pdev)
                map = NULL;
        }
        of_node_put(node);
-       aspeed_g5_pinctrl_data.maps[ASPEED_IP_LPC] = map;
+       aspeed_g5_pinctrl_data.pinmux.maps[ASPEED_IP_LPC] = map;
 
        return aspeed_pinctrl_probe(pdev, &aspeed_g5_pinctrl_desc,
                        &aspeed_g5_pinctrl_data);
index 4c775b8..535db3d 100644 (file)
 #include "../core.h"
 #include "pinctrl-aspeed.h"
 
-static const char *const aspeed_pinmux_ips[] = {
-       [ASPEED_IP_SCU] = "SCU",
-       [ASPEED_IP_GFX] = "GFX",
-       [ASPEED_IP_LPC] = "LPC",
-};
-
 int aspeed_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
 {
        struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
 
-       return pdata->ngroups;
+       return pdata->pinmux.ngroups;
 }
 
 const char *aspeed_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
@@ -28,7 +22,7 @@ const char *aspeed_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
 {
        struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
 
-       return pdata->groups[group].name;
+       return pdata->pinmux.groups[group].name;
 }
 
 int aspeed_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
@@ -37,8 +31,8 @@ int aspeed_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
 {
        struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
 
-       *pins = &pdata->groups[group].pins[0];
-       *npins = pdata->groups[group].npins;
+       *pins = &pdata->pinmux.groups[group].pins[0];
+       *npins = pdata->pinmux.groups[group].npins;
 
        return 0;
 }
@@ -53,7 +47,7 @@ int aspeed_pinmux_get_fn_count(struct pinctrl_dev *pctldev)
 {
        struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
 
-       return pdata->nfunctions;
+       return pdata->pinmux.nfunctions;
 }
 
 const char *aspeed_pinmux_get_fn_name(struct pinctrl_dev *pctldev,
@@ -61,7 +55,7 @@ const char *aspeed_pinmux_get_fn_name(struct pinctrl_dev *pctldev,
 {
        struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
 
-       return pdata->functions[function].name;
+       return pdata->pinmux.functions[function].name;
 }
 
 int aspeed_pinmux_get_fn_groups(struct pinctrl_dev *pctldev,
@@ -71,208 +65,38 @@ int aspeed_pinmux_get_fn_groups(struct pinctrl_dev *pctldev,
 {
        struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
 
-       *groups = pdata->functions[function].groups;
-       *num_groups = pdata->functions[function].ngroups;
+       *groups = pdata->pinmux.functions[function].groups;
+       *num_groups = pdata->pinmux.functions[function].ngroups;
 
        return 0;
 }
 
-static inline void aspeed_sig_desc_print_val(
-               const struct aspeed_sig_desc *desc, bool enable, u32 rv)
-{
-       pr_debug("Want %s%X[0x%08X]=0x%X, got 0x%X from 0x%08X\n",
-                       aspeed_pinmux_ips[desc->ip], desc->reg,
-                       desc->mask, enable ? desc->enable : desc->disable,
-                       (rv & desc->mask) >> __ffs(desc->mask), rv);
-}
-
-/**
- * Query the enabled or disabled state of a signal descriptor
- *
- * @desc: The signal descriptor of interest
- * @enabled: True to query the enabled state, false to query disabled state
- * @map: The IP block's regmap instance
- *
- * Return: 1 if the descriptor's bitfield is configured to the state
- * selected by @enabled, 0 if not, and less than zero if an unrecoverable
- * failure occurred
- *
- * Evaluation of descriptor state is non-trivial in that it is not a binary
- * outcome: The bitfields can be greater than one bit in size and thus can take
- * a value that is neither the enabled nor disabled state recorded in the
- * descriptor (typically this means a different function to the one of interest
- * is enabled). Thus we must explicitly test for either condition as required.
- */
-static int aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc,
-                                bool enabled, struct regmap *map)
+static int aspeed_sig_expr_enable(const struct aspeed_pinmux_data *ctx,
+                                 const struct aspeed_sig_expr *expr)
 {
        int ret;
-       unsigned int raw;
-       u32 want;
 
-       if (!map)
-               return -ENODEV;
-
-       ret = regmap_read(map, desc->reg, &raw);
-       if (ret)
-               return ret;
-
-       aspeed_sig_desc_print_val(desc, enabled, raw);
-       want = enabled ? desc->enable : desc->disable;
-
-       return ((raw & desc->mask) >> __ffs(desc->mask)) == want;
-}
-
-/**
- * Query the enabled or disabled state for a mux function's signal on a pin
- *
- * @expr: An expression controlling the signal for a mux function on a pin
- * @enabled: True to query the enabled state, false to query disabled state
- * @maps: The list of regmap instances
- *
- * Return: 1 if the expression composed by @enabled evaluates true, 0 if not,
- * and less than zero if an unrecoverable failure occurred.
- *
- * A mux function is enabled or disabled if the function's signal expression
- * for each pin in the function's pin group evaluates true for the desired
- * state. An signal expression evaluates true if all of its associated signal
- * descriptors evaluate true for the desired state.
- *
- * If an expression's state is described by more than one bit, either through
- * multi-bit bitfields in a single signal descriptor or through multiple signal
- * descriptors of a single bit then it is possible for the expression to be in
- * neither the enabled nor disabled state. Thus we must explicitly test for
- * either condition as required.
- */
-static int aspeed_sig_expr_eval(const struct aspeed_sig_expr *expr,
-                                bool enabled, struct regmap * const *maps)
-{
-       int i;
-       int ret;
-
-       for (i = 0; i < expr->ndescs; i++) {
-               const struct aspeed_sig_desc *desc = &expr->descs[i];
-
-               ret = aspeed_sig_desc_eval(desc, enabled, maps[desc->ip]);
-               if (ret <= 0)
-                       return ret;
-       }
-
-       return 1;
-}
-
-/**
- * Configure a pin's signal by applying an expression's descriptor state for
- * all descriptors in the expression.
- *
- * @expr: The expression associated with the function whose signal is to be
- *        configured
- * @enable: true to enable an function's signal through a pin's signal
- *          expression, false to disable the function's signal
- * @maps: The list of regmap instances for pinmux register access.
- *
- * Return: 0 if the expression is configured as requested and a negative error
- * code otherwise
- */
-static int aspeed_sig_expr_set(const struct aspeed_sig_expr *expr,
-                               bool enable, struct regmap * const *maps)
-{
-       int ret;
-       int i;
-
-       for (i = 0; i < expr->ndescs; i++) {
-               const struct aspeed_sig_desc *desc = &expr->descs[i];
-               u32 pattern = enable ? desc->enable : desc->disable;
-               u32 val = (pattern << __ffs(desc->mask));
-
-               if (!maps[desc->ip])
-                       return -ENODEV;
-
-               /*
-                * Strap registers are configured in hardware or by early-boot
-                * firmware. Treat them as read-only despite that we can write
-                * them. This may mean that certain functions cannot be
-                * deconfigured and is the reason we re-evaluate after writing
-                * all descriptor bits.
-                *
-                * Port D and port E GPIO loopback modes are the only exception
-                * as those are commonly used with front-panel buttons to allow
-                * normal operation of the host when the BMC is powered off or
-                * fails to boot. Once the BMC has booted, the loopback mode
-                * must be disabled for the BMC to control host power-on and
-                * reset.
-                */
-               if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP1 &&
-                   !(desc->mask & (BIT(21) | BIT(22))))
-                       continue;
-
-               if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP2)
-                       continue;
-
-               /* On AST2500, Set bits in SCU7C are cleared from SCU70 */
-               if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP1) {
-                       unsigned int rev_id;
-
-                       ret = regmap_read(maps[ASPEED_IP_SCU],
-                               HW_REVISION_ID, &rev_id);
-                       if (ret < 0)
-                               return ret;
-
-                       if (0x04 == (rev_id >> 24)) {
-                               u32 value = ~val & desc->mask;
-
-                               if (value) {
-                                       ret = regmap_write(maps[desc->ip],
-                                               HW_REVISION_ID, value);
-                                       if (ret < 0)
-                                               return ret;
-                               }
-                       }
-               }
-
-               ret = regmap_update_bits(maps[desc->ip], desc->reg,
-                                        desc->mask, val);
-
-               if (ret)
-                       return ret;
-       }
-
-       ret = aspeed_sig_expr_eval(expr, enable, maps);
-       if (ret < 0)
-               return ret;
-
-       if (!ret)
-               return -EPERM;
-
-       return 0;
-}
-
-static int aspeed_sig_expr_enable(const struct aspeed_sig_expr *expr,
-                                  struct regmap * const *maps)
-{
-       int ret;
-
-       ret = aspeed_sig_expr_eval(expr, true, maps);
+       ret = aspeed_sig_expr_eval(ctx, expr, true);
        if (ret < 0)
                return ret;
 
        if (!ret)
-               return aspeed_sig_expr_set(expr, true, maps);
+               return aspeed_sig_expr_set(ctx, expr, true);
 
        return 0;
 }
 
-static int aspeed_sig_expr_disable(const struct aspeed_sig_expr *expr,
-                                   struct regmap * const *maps)
+static int aspeed_sig_expr_disable(const struct aspeed_pinmux_data *ctx,
+                                  const struct aspeed_sig_expr *expr)
 {
        int ret;
 
-       ret = aspeed_sig_expr_eval(expr, true, maps);
+       ret = aspeed_sig_expr_eval(ctx, expr, true);
        if (ret < 0)
                return ret;
 
        if (ret)
-               return aspeed_sig_expr_set(expr, false, maps);
+               return aspeed_sig_expr_set(ctx, expr, false);
 
        return 0;
 }
@@ -280,13 +104,13 @@ static int aspeed_sig_expr_disable(const struct aspeed_sig_expr *expr,
 /**
  * Disable a signal on a pin by disabling all provided signal expressions.
  *
+ * @ctx: The pinmux context
  * @exprs: The list of signal expressions (from a priority level on a pin)
- * @maps: The list of regmap instances for pinmux register access.
  *
  * Return: 0 if all expressions are disabled, otherwise a negative error code
  */
-static int aspeed_disable_sig(const struct aspeed_sig_expr **exprs,
-                              struct regmap * const *maps)
+static int aspeed_disable_sig(const struct aspeed_pinmux_data *ctx,
+                             const struct aspeed_sig_expr **exprs)
 {
        int ret = 0;
 
@@ -294,7 +118,7 @@ static int aspeed_disable_sig(const struct aspeed_sig_expr **exprs,
                return true;
 
        while (*exprs && !ret) {
-               ret = aspeed_sig_expr_disable(*exprs, maps);
+               ret = aspeed_sig_expr_disable(ctx, *exprs);
                exprs++;
        }
 
@@ -395,9 +219,9 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
        int ret;
        const struct aspeed_pinctrl_data *pdata =
                pinctrl_dev_get_drvdata(pctldev);
-       const struct aspeed_pin_group *pgroup = &pdata->groups[group];
+       const struct aspeed_pin_group *pgroup = &pdata->pinmux.groups[group];
        const struct aspeed_pin_function *pfunc =
-               &pdata->functions[function];
+               &pdata->pinmux.functions[function];
 
        for (i = 0; i < pgroup->npins; i++) {
                int pin = pgroup->pins[i];
@@ -423,7 +247,7 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
                        if (expr)
                                break;
 
-                       ret = aspeed_disable_sig(funcs, pdata->maps);
+                       ret = aspeed_disable_sig(&pdata->pinmux, funcs);
                        if (ret)
                                return ret;
 
@@ -443,7 +267,7 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
                        return -ENXIO;
                }
 
-               ret = aspeed_sig_expr_enable(expr, pdata->maps);
+               ret = aspeed_sig_expr_enable(&pdata->pinmux, expr);
                if (ret)
                        return ret;
        }
@@ -500,7 +324,7 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev,
                if (aspeed_gpio_in_exprs(funcs))
                        break;
 
-               ret = aspeed_disable_sig(funcs, pdata->maps);
+               ret = aspeed_disable_sig(&pdata->pinmux, funcs);
                if (ret)
                        return ret;
 
@@ -531,7 +355,7 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev,
         * If GPIO is not the lowest priority signal type, assume there is only
         * one expression defined to enable the GPIO function
         */
-       return aspeed_sig_expr_enable(expr, pdata->maps);
+       return aspeed_sig_expr_enable(&pdata->pinmux, expr);
 }
 
 int aspeed_pinctrl_probe(struct platform_device *pdev,
@@ -547,12 +371,14 @@ int aspeed_pinctrl_probe(struct platform_device *pdev,
                return -ENODEV;
        }
 
-       pdata->maps[ASPEED_IP_SCU] = syscon_node_to_regmap(parent->of_node);
-       if (IS_ERR(pdata->maps[ASPEED_IP_SCU])) {
+       pdata->scu = syscon_node_to_regmap(parent->of_node);
+       if (IS_ERR(pdata->scu)) {
                dev_err(&pdev->dev, "No regmap for syscon pincontroller parent\n");
-               return PTR_ERR(pdata->maps[ASPEED_IP_SCU]);
+               return PTR_ERR(pdata->scu);
        }
 
+       pdata->pinmux.maps[ASPEED_IP_SCU] = pdata->scu;
+
        pctl = pinctrl_register(pdesc, &pdev->dev, pdata);
 
        if (IS_ERR(pctl)) {
@@ -587,7 +413,9 @@ static inline const struct aspeed_pin_config *find_pinconf_config(
        return NULL;
 }
 
-/**
+/*
+ * Aspeed pin configuration description.
+ *
  * @param: pinconf configuration parameter
  * @arg: The supported argument for @param, or -1 if any value is supported
  * @val: The register value to write to configure @arg for @param
@@ -661,7 +489,7 @@ int aspeed_pin_config_get(struct pinctrl_dev *pctldev, unsigned int offset,
        if (!pconf)
                return -ENOTSUPP;
 
-       rc = regmap_read(pdata->maps[ASPEED_IP_SCU], pconf->reg, &val);
+       rc = regmap_read(pdata->scu, pconf->reg, &val);
        if (rc < 0)
                return rc;
 
@@ -716,8 +544,8 @@ int aspeed_pin_config_set(struct pinctrl_dev *pctldev, unsigned int offset,
 
                val = pmap->val << pconf->bit;
 
-               rc = regmap_update_bits(pdata->maps[ASPEED_IP_SCU], pconf->reg,
-                               BIT(pconf->bit), val);
+               rc = regmap_update_bits(pdata->scu, pconf->reg,
+                                       BIT(pconf->bit), val);
 
                if (rc < 0)
                        return rc;
index 4b06ddb..a5d8398 100644 (file)
 #include <linux/pinctrl/pinconf-generic.h>
 #include <linux/regmap.h>
 
-/*
- * The ASPEED SoCs provide typically more than 200 pins for GPIO and other
- * functions. The SoC function enabled on a pin is determined on a priority
- * basis where a given pin can provide a number of different signal types.
- *
- * The signal active on a pin is described by both a priority level and
- * compound logical expressions involving multiple operators, registers and
- * bits. Some difficulty arises as the pin's function bit masks for each
- * priority level are frequently not the same (i.e. cannot just flip a bit to
- * change from a high to low priority signal), or even in the same register.
- * Further, not all signals can be unmuxed, as some expressions depend on
- * values in the hardware strapping register (which is treated as read-only).
- *
- * SoC Multi-function Pin Expression Examples
- * ------------------------------------------
- *
- * Here are some sample mux configurations from the AST2400 and AST2500
- * datasheets to illustrate the corner cases, roughly in order of least to most
- * corner. The signal priorities are in decending order from P0 (highest).
- *
- * D6 is a pin with a single function (beside GPIO); a high priority signal
- * that participates in one function:
- *
- * Ball | Default | P0 Signal | P0 Expression               | P1 Signal | P1 Expression | Other
- * -----+---------+-----------+-----------------------------+-----------+---------------+----------
- *  D6    GPIOA0    MAC1LINK    SCU80[0]=1                                                GPIOA0
- * -----+---------+-----------+-----------------------------+-----------+---------------+----------
- *
- * C5 is a multi-signal pin (high and low priority signals). Here we touch
- * different registers for the different functions that enable each signal:
- *
- * -----+---------+-----------+-----------------------------+-----------+---------------+----------
- *  C5    GPIOA4    SCL9        SCU90[22]=1                   TIMER5      SCU80[4]=1      GPIOA4
- * -----+---------+-----------+-----------------------------+-----------+---------------+----------
- *
- * E19 is a single-signal pin with two functions that influence the active
- * signal. In this case both bits have the same meaning - enable a dedicated
- * LPC reset pin. However it's not always the case that the bits in the
- * OR-relationship have the same meaning.
- *
- * -----+---------+-----------+-----------------------------+-----------+---------------+----------
- *  E19   GPIOB4    LPCRST#     SCU80[12]=1 | Strap[14]=1                                 GPIOB4
- * -----+---------+-----------+-----------------------------+-----------+---------------+----------
- *
- * For example, pin B19 has a low-priority signal that's enabled by two
- * distinct SoC functions: A specific SIOPBI bit in register SCUA4, and an ACPI
- * bit in the STRAP register. The ACPI bit configures signals on pins in
- * addition to B19. Both of the low priority functions as well as the high
- * priority function must be disabled for GPIOF1 to be used.
- *
- * Ball | Default | P0 Signal | P0 Expression                           | P1 Signal | P1 Expression                          | Other
- * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+----------
- *  B19   GPIOF1    NDCD4       SCU80[25]=1                               SIOPBI#     SCUA4[12]=1 | Strap[19]=0                GPIOF1
- * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+----------
- *
- * For pin E18, the SoC ANDs the expected state of three bits to determine the
- * pin's active signal:
- *
- * * SCU3C[3]: Enable external SOC reset function
- * * SCU80[15]: Enable SPICS1# or EXTRST# function pin
- * * SCU90[31]: Select SPI interface CS# output
- *
- * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+----------
- *  E18   GPIOB7    EXTRST#     SCU3C[3]=1 & SCU80[15]=1 & SCU90[31]=0    SPICS1#     SCU3C[3]=1 & SCU80[15]=1 & SCU90[31]=1   GPIOB7
- * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+----------
- *
- * (Bits SCU3C[3] and SCU80[15] appear to only be used in the expressions for
- * selecting the signals on pin E18)
- *
- * Pin T5 is a multi-signal pin with a more complex configuration:
- *
- * Ball | Default | P0 Signal | P0 Expression                | P1 Signal | P1 Expression | Other
- * -----+---------+-----------+------------------------------+-----------+---------------+----------
- *  T5    GPIOL1    VPIDE       SCU90[5:4]!=0 & SCU84[17]=1    NDCD1       SCU84[17]=1     GPIOL1
- * -----+---------+-----------+------------------------------+-----------+---------------+----------
- *
- * The high priority signal configuration is best thought of in terms of its
- * exploded form, with reference to the SCU90[5:4] bits:
- *
- * * SCU90[5:4]=00: disable
- * * SCU90[5:4]=01: 18 bits (R6/G6/B6) video mode.
- * * SCU90[5:4]=10: 24 bits (R8/G8/B8) video mode.
- * * SCU90[5:4]=11: 30 bits (R10/G10/B10) video mode.
- *
- * Re-writing:
- *
- * -----+---------+-----------+------------------------------+-----------+---------------+----------
- *  T5    GPIOL1    VPIDE      (SCU90[5:4]=1 & SCU84[17]=1)    NDCD1       SCU84[17]=1     GPIOL1
- *                             | (SCU90[5:4]=2 & SCU84[17]=1)
- *                             | (SCU90[5:4]=3 & SCU84[17]=1)
- * -----+---------+-----------+------------------------------+-----------+---------------+----------
- *
- * For reference the SCU84[17] bit configure the "UART1 NDCD1 or Video VPIDE
- * function pin", where the signal itself is determined by whether SCU94[5:4]
- * is disabled or in one of the 18, 24 or 30bit video modes.
- *
- * Other video-input-related pins require an explicit state in SCU90[5:4], e.g.
- * W1 and U5:
- *
- * -----+---------+-----------+------------------------------+-----------+---------------+----------
- *  W1    GPIOL6    VPIB0       SCU90[5:4]=3 & SCU84[22]=1     TXD1        SCU84[22]=1     GPIOL6
- *  U5    GPIOL7    VPIB1       SCU90[5:4]=3 & SCU84[23]=1     RXD1        SCU84[23]=1     GPIOL7
- * -----+---------+-----------+------------------------------+-----------+---------------+----------
- *
- * The examples of T5 and W1 are particularly fertile, as they also demonstrate
- * that despite operating as part of the video input bus each signal needs to
- * be enabled individually via it's own SCU84 (in the cases of T5 and W1)
- * register bit. This is a little crazy if the bus doesn't have optional
- * signals, but is used to decent effect with some of the UARTs where not all
- * signals are required. However, this isn't done consistently - UART1 is
- * enabled on a per-pin basis, and by contrast, all signals for UART6 are
- * enabled by a single bit.
- *
- * Further, the high and low priority signals listed in the table above share
- * a configuration bit. The VPI signals should operate in concert in a single
- * function, but the UART signals should retain the ability to be configured
- * independently. This pushes the implementation down the path of tagging a
- * signal's expressions with the function they participate in, rather than
- * defining masks affecting multiple signals per function. The latter approach
- * fails in this instance where applying the configuration for the UART pin of
- * interest will stomp on the state of other UART signals when disabling the
- * VPI functions on the current pin.
- *
- * Ball |  Default   | P0 Signal | P0 Expression             | P1 Signal | P1 Expression | Other
- * -----+------------+-----------+---------------------------+-----------+---------------+------------
- *  A12   RGMII1TXCK   GPIOT0      SCUA0[0]=1                  RMII1TXEN   Strap[6]=0      RGMII1TXCK
- *  B12   RGMII1TXCTL  GPIOT1      SCUA0[1]=1                  –           Strap[6]=0      RGMII1TXCTL
- * -----+------------+-----------+---------------------------+-----------+---------------+------------
- *
- * A12 demonstrates that the "Other" signal isn't always GPIO - in this case
- * GPIOT0 is a high-priority signal and RGMII1TXCK is Other. Thus, GPIO
- * should be treated like any other signal type with full function expression
- * requirements, and not assumed to be the default case. Separately, GPIOT0 and
- * GPIOT1's signal descriptor bits are distinct, therefore we must iterate all
- * pins in the function's group to disable the higher-priority signals such
- * that the signal for the function of interest is correctly enabled.
- *
- * Finally, three priority levels aren't always enough; the AST2500 brings with
- * it 18 pins of five priority levels, however the 18 pins only use three of
- * the five priority levels.
- *
- * Ultimately the requirement to control pins in the examples above drive the
- * design:
- *
- * * Pins provide signals according to functions activated in the mux
- *   configuration
- *
- * * Pins provide up to five signal types in a priority order
- *
- * * For priorities levels defined on a pin, each priority provides one signal
- *
- * * Enabling lower priority signals requires higher priority signals be
- *   disabled
- *
- * * A function represents a set of signals; functions are distinct if their
- *   sets of signals are not equal
- *
- * * Signals participate in one or more functions
- *
- * * A function is described by an expression of one or more signal
- *   descriptors, which compare bit values in a register
- *
- * * A signal expression is the smallest set of signal descriptors whose
- *   comparisons must evaluate 'true' for a signal to be enabled on a pin.
- *
- * * A function's signal is active on a pin if evaluating all signal
- *   descriptors in the pin's signal expression for the function yields a 'true'
- *   result
- *
- * * A signal at a given priority on a given pin is active if any of the
- *   functions in which the signal participates are active, and no higher
- *   priority signal on the pin is active
- *
- * * GPIO is configured per-pin
- *
- * And so:
- *
- * * To disable a signal, any function(s) activating the signal must be
- *   disabled
- *
- * * Each pin must know the signal expressions of functions in which it
- *   participates, for the purpose of enabling the Other function. This is done
- *   by deactivating all functions that activate higher priority signals on the
- *   pin.
- *
- * As a concrete example:
- *
- * * T5 provides three signals types: VPIDE, NDCD1 and GPIO
- *
- * * The VPIDE signal participates in 3 functions: VPI18, VPI24 and VPI30
- *
- * * The NDCD1 signal participates in just its own NDCD1 function
- *
- * * VPIDE is high priority, NDCD1 is low priority, and GPIOL1 is the least
- *   prioritised
- *
- * * The prerequisit for activating the NDCD1 signal is that the VPI18, VPI24
- *   and VPI30 functions all be disabled
- *
- * * Similarly, all of VPI18, VPI24, VPI30 and NDCD1 functions must be disabled
- *   to provide GPIOL6
- *
- * Considerations
- * --------------
- *
- * If pinctrl allows us to allocate a pin we can configure a function without
- * concern for the function of already allocated pins, if pin groups are
- * created with respect to the SoC functions in which they participate. This is
- * intuitive, but it did not feel obvious from the bit/pin relationships.
- *
- * Conversely, failing to allocate all pins in a group indicates some bits (as
- * well as pins) required for the group's configuration will already be in use,
- * likely in a way that's inconsistent with the requirements of the failed
- * group.
- */
-
-#define ASPEED_IP_SCU          0
-#define ASPEED_IP_GFX          1
-#define ASPEED_IP_LPC          2
-#define ASPEED_NR_PINMUX_IPS   3
-
-/*
- * The "Multi-function Pins Mapping and Control" table in the SoC datasheet
- * references registers by the device/offset mnemonic. The register macros
- * below are named the same way to ease transcription and verification (as
- * opposed to naming them e.g. PINMUX_CTRL_[0-9]). Further, signal expressions
- * reference registers beyond those dedicated to pinmux, such as the system
- * reset control and MAC clock configuration registers. The AST2500 goes a step
- * further and references registers in the graphics IP block, but that isn't
- * handled yet.
- */
-#define SCU2C           0x2C /* Misc. Control Register */
-#define SCU3C           0x3C /* System Reset Control/Status Register */
-#define SCU48           0x48 /* MAC Interface Clock Delay Setting */
-#define HW_STRAP1       0x70 /* AST2400 strapping is 33 bits, is split */
-#define HW_REVISION_ID  0x7C /* Silicon revision ID register */
-#define SCU80           0x80 /* Multi-function Pin Control #1 */
-#define SCU84           0x84 /* Multi-function Pin Control #2 */
-#define SCU88           0x88 /* Multi-function Pin Control #3 */
-#define SCU8C           0x8C /* Multi-function Pin Control #4 */
-#define SCU90           0x90 /* Multi-function Pin Control #5 */
-#define SCU94           0x94 /* Multi-function Pin Control #6 */
-#define SCUA0           0xA0 /* Multi-function Pin Control #7 */
-#define SCUA4           0xA4 /* Multi-function Pin Control #8 */
-#define SCUA8           0xA8 /* Multi-function Pin Control #9 */
-#define SCUAC           0xAC /* Multi-function Pin Control #10 */
-#define HW_STRAP2       0xD0 /* Strapping */
-
- /**
-  * A signal descriptor, which describes the register, bits and the
-  * enable/disable values that should be compared or written.
-  *
-  * @ip: The IP block identifier, used as an index into the regmap array in
-  *      struct aspeed_pinctrl_data
-  * @reg: The register offset with respect to the base address of the IP block
-  * @mask: The mask to apply to the register. The lowest set bit of the mask is
-  *        used to derive the shift value.
-  * @enable: The value that enables the function. Value should be in the LSBs,
-  *          not at the position of the mask.
-  * @disable: The value that disables the function. Value should be in the
-  *           LSBs, not at the position of the mask.
-  */
-struct aspeed_sig_desc {
-       unsigned int ip;
-       unsigned int reg;
-       u32 mask;
-       u32 enable;
-       u32 disable;
-};
-
-/**
- * Describes a signal expression. The expression is evaluated by ANDing the
- * evaluation of the descriptors.
- *
- * @signal: The signal name for the priority level on the pin. If the signal
- *          type is GPIO, then the signal name must begin with the string
- *          "GPIO", e.g. GPIOA0, GPIOT4 etc.
- * @function: The name of the function the signal participates in for the
- *            associated expression
- * @ndescs: The number of signal descriptors in the expression
- * @descs: Pointer to an array of signal descriptors that comprise the
- *         function expression
- */
-struct aspeed_sig_expr {
-       const char *signal;
-       const char *function;
-       int ndescs;
-       const struct aspeed_sig_desc *descs;
-};
-
-/**
- * A struct capturing the list of expressions enabling signals at each priority
- * for a given pin. The signal configuration for a priority level is evaluated
- * by ORing the evaluation of the signal expressions in the respective
- * priority's list.
- *
- * @name: A name for the pin
- * @prios: A pointer to an array of expression list pointers
- *
- */
-struct aspeed_pin_desc {
-       const char *name;
-       const struct aspeed_sig_expr ***prios;
-};
-
-/* Macro hell */
-
-#define SIG_DESC_IP_BIT(ip, reg, idx, val) \
-       { ip, reg, BIT_MASK(idx), val, (((val) + 1) & 1) }
-
-/**
- * Short-hand macro for describing an SCU descriptor enabled by the state of
- * one bit. The disable value is derived.
- *
- * @reg: The signal's associated register, offset from base
- * @idx: The signal's bit index in the register
- * @val: The value (0 or 1) that enables the function
- */
-#define SIG_DESC_BIT(reg, idx, val) \
-       SIG_DESC_IP_BIT(ASPEED_IP_SCU, reg, idx, val)
-
-#define SIG_DESC_IP_SET(ip, reg, idx) SIG_DESC_IP_BIT(ip, reg, idx, 1)
-
-/**
- * A further short-hand macro expanding to an SCU descriptor enabled by a set
- * bit.
- *
- * @reg: The register, offset from base
- * @idx: The bit index in the register
- */
-#define SIG_DESC_SET(reg, idx) SIG_DESC_IP_BIT(ASPEED_IP_SCU, reg, idx, 1)
-
-#define SIG_DESC_LIST_SYM(sig, func) sig_descs_ ## sig ## _ ## func
-#define SIG_DESC_LIST_DECL(sig, func, ...) \
-       static const struct aspeed_sig_desc SIG_DESC_LIST_SYM(sig, func)[] = \
-               { __VA_ARGS__ }
-
-#define SIG_EXPR_SYM(sig, func) sig_expr_ ## sig ## _ ## func
-#define SIG_EXPR_DECL_(sig, func) \
-       static const struct aspeed_sig_expr SIG_EXPR_SYM(sig, func) = \
-       { \
-               .signal = #sig, \
-               .function = #func, \
-               .ndescs = ARRAY_SIZE(SIG_DESC_LIST_SYM(sig, func)), \
-               .descs = &(SIG_DESC_LIST_SYM(sig, func))[0], \
-       }
-
-/**
- * Declare a signal expression.
- *
- * @sig: A macro symbol name for the signal (is subjected to stringification
- *        and token pasting)
- * @func: The function in which the signal is participating
- * @...: Signal descriptors that define the signal expression
- *
- * For example, the following declares the ROMD8 signal for the ROM16 function:
- *
- *     SIG_EXPR_DECL(ROMD8, ROM16, SIG_DESC_SET(SCU90, 6));
- *
- * And with multiple signal descriptors:
- *
- *     SIG_EXPR_DECL(ROMD8, ROM16S, SIG_DESC_SET(HW_STRAP1, 4),
- *              { HW_STRAP1, GENMASK(1, 0), 0, 0 });
- */
-#define SIG_EXPR_DECL(sig, func, ...) \
-       SIG_DESC_LIST_DECL(sig, func, __VA_ARGS__); \
-       SIG_EXPR_DECL_(sig, func)
-
-/**
- * Declare a pointer to a signal expression
- *
- * @sig: The macro symbol name for the signal (subjected to token pasting)
- * @func: The macro symbol name for the function (subjected to token pasting)
- */
-#define SIG_EXPR_PTR(sig, func) (&SIG_EXPR_SYM(sig, func))
-
-#define SIG_EXPR_LIST_SYM(sig) sig_exprs_ ## sig
-
-/**
- * Declare a signal expression list for reference in a struct aspeed_pin_prio.
- *
- * @sig: A macro symbol name for the signal (is subjected to token pasting)
- * @...: Signal expression structure pointers (use SIG_EXPR_PTR())
- *
- * For example, the 16-bit ROM bus can be enabled by one of two possible signal
- * expressions:
- *
- *     SIG_EXPR_DECL(ROMD8, ROM16, SIG_DESC_SET(SCU90, 6));
- *     SIG_EXPR_DECL(ROMD8, ROM16S, SIG_DESC_SET(HW_STRAP1, 4),
- *              { HW_STRAP1, GENMASK(1, 0), 0, 0 });
- *     SIG_EXPR_LIST_DECL(ROMD8, SIG_EXPR_PTR(ROMD8, ROM16),
- *              SIG_EXPR_PTR(ROMD8, ROM16S));
- */
-#define SIG_EXPR_LIST_DECL(sig, ...) \
-       static const struct aspeed_sig_expr *SIG_EXPR_LIST_SYM(sig)[] = \
-               { __VA_ARGS__, NULL }
-
-/**
- * A short-hand macro for declaring a function expression and an expression
- * list with a single function.
- *
- * @func: A macro symbol name for the function (is subjected to token pasting)
- * @...: Function descriptors that define the function expression
- *
- * For example, signal NCTS6 participates in its own function with one group:
- *
- *     SIG_EXPR_LIST_DECL_SINGLE(NCTS6, NCTS6, SIG_DESC_SET(SCU90, 7));
- */
-#define SIG_EXPR_LIST_DECL_SINGLE(sig, func, ...) \
-       SIG_DESC_LIST_DECL(sig, func, __VA_ARGS__); \
-       SIG_EXPR_DECL_(sig, func); \
-       SIG_EXPR_LIST_DECL(sig, SIG_EXPR_PTR(sig, func))
-
-#define SIG_EXPR_LIST_DECL_DUAL(sig, f0, f1) \
-       SIG_EXPR_LIST_DECL(sig, SIG_EXPR_PTR(sig, f0), SIG_EXPR_PTR(sig, f1))
-
-#define SIG_EXPR_LIST_PTR(sig) (&SIG_EXPR_LIST_SYM(sig)[0])
-
-#define PIN_EXPRS_SYM(pin) pin_exprs_ ## pin
-#define PIN_EXPRS_PTR(pin) (&PIN_EXPRS_SYM(pin)[0])
-#define PIN_SYM(pin) pin_ ## pin
-
-#define MS_PIN_DECL_(pin, ...) \
-       static const struct aspeed_sig_expr **PIN_EXPRS_SYM(pin)[] = \
-               { __VA_ARGS__, NULL }; \
-       static const struct aspeed_pin_desc PIN_SYM(pin) = \
-               { #pin, PIN_EXPRS_PTR(pin) }
-
-/**
- * Declare a multi-signal pin
- *
- * @pin: The pin number
- * @other: Macro name for "other" functionality (subjected to stringification)
- * @high: Macro name for the highest priority signal functions
- * @low: Macro name for the low signal functions
- *
- * For example:
- *
- *     #define A8 56
- *     SIG_EXPR_DECL(ROMD8, ROM16, SIG_DESC_SET(SCU90, 6));
- *     SIG_EXPR_DECL(ROMD8, ROM16S, SIG_DESC_SET(HW_STRAP1, 4),
- *              { HW_STRAP1, GENMASK(1, 0), 0, 0 });
- *     SIG_EXPR_LIST_DECL(ROMD8, SIG_EXPR_PTR(ROMD8, ROM16),
- *              SIG_EXPR_PTR(ROMD8, ROM16S));
- *     SIG_EXPR_LIST_DECL_SINGLE(NCTS6, NCTS6, SIG_DESC_SET(SCU90, 7));
- *     MS_PIN_DECL(A8, GPIOH0, ROMD8, NCTS6);
- */
-#define MS_PIN_DECL(pin, other, high, low) \
-       SIG_EXPR_LIST_DECL_SINGLE(other, other); \
-       MS_PIN_DECL_(pin, \
-                       SIG_EXPR_LIST_PTR(high), \
-                       SIG_EXPR_LIST_PTR(low), \
-                       SIG_EXPR_LIST_PTR(other))
-
-#define PIN_GROUP_SYM(func) pins_ ## func
-#define FUNC_GROUP_SYM(func) groups_ ## func
-#define FUNC_GROUP_DECL(func, ...) \
-       static const int PIN_GROUP_SYM(func)[] = { __VA_ARGS__ }; \
-       static const char *FUNC_GROUP_SYM(func)[] = { #func }
-
-/**
- * Declare a single signal pin
- *
- * @pin: The pin number
- * @other: Macro name for "other" functionality (subjected to stringification)
- * @sig: Macro name for the signal (subjected to stringification)
- *
- * For example:
- *
- *     #define E3 80
- *     SIG_EXPR_LIST_DECL_SINGLE(SCL5, I2C5, I2C5_DESC);
- *     SS_PIN_DECL(E3, GPIOK0, SCL5);
- */
-#define SS_PIN_DECL(pin, other, sig) \
-       SIG_EXPR_LIST_DECL_SINGLE(other, other); \
-       MS_PIN_DECL_(pin, SIG_EXPR_LIST_PTR(sig), SIG_EXPR_LIST_PTR(other))
-
-/**
- * Single signal, single function pin declaration
- *
- * @pin: The pin number
- * @other: Macro name for "other" functionality (subjected to stringification)
- * @sig: Macro name for the signal (subjected to stringification)
- * @...: Signal descriptors that define the function expression
- *
- * For example:
- *
- *    SSSF_PIN_DECL(A4, GPIOA2, TIMER3, SIG_DESC_SET(SCU80, 2));
- */
-#define SSSF_PIN_DECL(pin, other, sig, ...) \
-       SIG_EXPR_LIST_DECL_SINGLE(sig, sig, __VA_ARGS__); \
-       SIG_EXPR_LIST_DECL_SINGLE(other, other); \
-       MS_PIN_DECL_(pin, SIG_EXPR_LIST_PTR(sig), SIG_EXPR_LIST_PTR(other)); \
-       FUNC_GROUP_DECL(sig, pin)
-
-#define GPIO_PIN_DECL(pin, gpio) \
-       SIG_EXPR_LIST_DECL_SINGLE(gpio, gpio); \
-       MS_PIN_DECL_(pin, SIG_EXPR_LIST_PTR(gpio))
+#include "pinmux-aspeed.h"
 
 /**
  * @param The pinconf parameter type
@@ -525,22 +28,6 @@ struct aspeed_pin_config {
        u8 value;
 };
 
-struct aspeed_pinctrl_data {
-       struct regmap *maps[ASPEED_NR_PINMUX_IPS];
-
-       const struct pinctrl_pin_desc *pins;
-       const unsigned int npins;
-
-       const struct aspeed_pin_group *groups;
-       const unsigned int ngroups;
-
-       const struct aspeed_pin_function *functions;
-       const unsigned int nfunctions;
-
-       const struct aspeed_pin_config *configs;
-       const unsigned int nconfigs;
-};
-
 #define ASPEED_PINCTRL_PIN(name_) \
        [name_] = { \
                .number = name_, \
@@ -548,30 +35,19 @@ struct aspeed_pinctrl_data {
                .drv_data = (void *) &(PIN_SYM(name_)) \
        }
 
-struct aspeed_pin_group {
-       const char *name;
-       const unsigned int *pins;
+struct aspeed_pinctrl_data {
+       struct regmap *scu;
+
+       const struct pinctrl_pin_desc *pins;
        const unsigned int npins;
-};
 
-#define ASPEED_PINCTRL_GROUP(name_) { \
-       .name = #name_, \
-       .pins = &(PIN_GROUP_SYM(name_))[0], \
-       .npins = ARRAY_SIZE(PIN_GROUP_SYM(name_)), \
-}
+       const struct aspeed_pin_config *configs;
+       const unsigned int nconfigs;
 
-struct aspeed_pin_function {
-       const char *name;
-       const char *const *groups;
-       unsigned int ngroups;
+       struct aspeed_pinmux_data pinmux;
 };
 
-#define ASPEED_PINCTRL_FUNC(name_, ...) { \
-       .name = #name_, \
-       .groups = &FUNC_GROUP_SYM(name_)[0], \
-       .ngroups = ARRAY_SIZE(FUNC_GROUP_SYM(name_)), \
-}
-
+/* Aspeed pinctrl helpers */
 int aspeed_pinctrl_get_groups_count(struct pinctrl_dev *pctldev);
 const char *aspeed_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
                unsigned int group);
diff --git a/drivers/pinctrl/aspeed/pinmux-aspeed.c b/drivers/pinctrl/aspeed/pinmux-aspeed.c
new file mode 100644 (file)
index 0000000..5b0fe17
--- /dev/null
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Copyright (C) 2019 IBM Corp. */
+
+/* Pieces to enable drivers to implement the .set callback */
+
+#include "pinmux-aspeed.h"
+
+const char *const aspeed_pinmux_ips[] = {
+       [ASPEED_IP_SCU] = "SCU",
+       [ASPEED_IP_GFX] = "GFX",
+       [ASPEED_IP_LPC] = "LPC",
+};
+
+static inline void aspeed_sig_desc_print_val(
+               const struct aspeed_sig_desc *desc, bool enable, u32 rv)
+{
+       pr_debug("Want %s%X[0x%08X]=0x%X, got 0x%X from 0x%08X\n",
+                       aspeed_pinmux_ips[desc->ip], desc->reg,
+                       desc->mask, enable ? desc->enable : desc->disable,
+                       (rv & desc->mask) >> __ffs(desc->mask), rv);
+}
+
+/**
+ * Query the enabled or disabled state of a signal descriptor
+ *
+ * @desc: The signal descriptor of interest
+ * @enabled: True to query the enabled state, false to query disabled state
+ * @map: The IP block's regmap instance
+ *
+ * Return: 1 if the descriptor's bitfield is configured to the state
+ * selected by @enabled, 0 if not, and less than zero if an unrecoverable
+ * failure occurred
+ *
+ * Evaluation of descriptor state is non-trivial in that it is not a binary
+ * outcome: The bitfields can be greater than one bit in size and thus can take
+ * a value that is neither the enabled nor disabled state recorded in the
+ * descriptor (typically this means a different function to the one of interest
+ * is enabled). Thus we must explicitly test for either condition as required.
+ */
+int aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc,
+                        bool enabled, struct regmap *map)
+{
+       int ret;
+       unsigned int raw;
+       u32 want;
+
+       if (!map)
+               return -ENODEV;
+
+       ret = regmap_read(map, desc->reg, &raw);
+       if (ret)
+               return ret;
+
+       aspeed_sig_desc_print_val(desc, enabled, raw);
+       want = enabled ? desc->enable : desc->disable;
+
+       return ((raw & desc->mask) >> __ffs(desc->mask)) == want;
+}
+
+/**
+ * Query the enabled or disabled state for a mux function's signal on a pin
+ *
+ * @ctx: The driver context for the pinctrl IP
+ * @expr: An expression controlling the signal for a mux function on a pin
+ * @enabled: True to query the enabled state, false to query disabled state
+ *
+ * Return: 1 if the expression composed by @enabled evaluates true, 0 if not,
+ * and less than zero if an unrecoverable failure occurred.
+ *
+ * A mux function is enabled or disabled if the function's signal expression
+ * for each pin in the function's pin group evaluates true for the desired
+ * state. An signal expression evaluates true if all of its associated signal
+ * descriptors evaluate true for the desired state.
+ *
+ * If an expression's state is described by more than one bit, either through
+ * multi-bit bitfields in a single signal descriptor or through multiple signal
+ * descriptors of a single bit then it is possible for the expression to be in
+ * neither the enabled nor disabled state. Thus we must explicitly test for
+ * either condition as required.
+ */
+int aspeed_sig_expr_eval(const struct aspeed_pinmux_data *ctx,
+                        const struct aspeed_sig_expr *expr, bool enabled)
+{
+       int i;
+       int ret;
+
+       for (i = 0; i < expr->ndescs; i++) {
+               const struct aspeed_sig_desc *desc = &expr->descs[i];
+
+               ret = aspeed_sig_desc_eval(desc, enabled, ctx->maps[desc->ip]);
+               if (ret <= 0)
+                       return ret;
+       }
+
+       return 1;
+}
diff --git a/drivers/pinctrl/aspeed/pinmux-aspeed.h b/drivers/pinctrl/aspeed/pinmux-aspeed.h
new file mode 100644 (file)
index 0000000..329d54d
--- /dev/null
@@ -0,0 +1,735 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright (C) 2019 IBM Corp.  */
+
+#ifndef ASPEED_PINMUX_H
+#define ASPEED_PINMUX_H
+
+#include <linux/regmap.h>
+#include <stdbool.h>
+
+/*
+ * The ASPEED SoCs provide typically more than 200 pins for GPIO and other
+ * functions. The SoC function enabled on a pin is determined on a priority
+ * basis where a given pin can provide a number of different signal types.
+ *
+ * The signal active on a pin is described by both a priority level and
+ * compound logical expressions involving multiple operators, registers and
+ * bits. Some difficulty arises as the pin's function bit masks for each
+ * priority level are frequently not the same (i.e. cannot just flip a bit to
+ * change from a high to low priority signal), or even in the same register.
+ * Further, not all signals can be unmuxed, as some expressions depend on
+ * values in the hardware strapping register (which may be treated as
+ * read-only).
+ *
+ * SoC Multi-function Pin Expression Examples
+ * ------------------------------------------
+ *
+ * Here are some sample mux configurations from the AST2400 and AST2500
+ * datasheets to illustrate the corner cases, roughly in order of least to most
+ * corner. The signal priorities are in decending order from P0 (highest).
+ *
+ * D6 is a pin with a single function (beside GPIO); a high priority signal
+ * that participates in one function:
+ *
+ * Ball | Default | P0 Signal | P0 Expression               | P1 Signal | P1 Expression | Other
+ * -----+---------+-----------+-----------------------------+-----------+---------------+----------
+ *  D6    GPIOA0    MAC1LINK    SCU80[0]=1                                                GPIOA0
+ * -----+---------+-----------+-----------------------------+-----------+---------------+----------
+ *
+ * C5 is a multi-signal pin (high and low priority signals). Here we touch
+ * different registers for the different functions that enable each signal:
+ *
+ * -----+---------+-----------+-----------------------------+-----------+---------------+----------
+ *  C5    GPIOA4    SCL9        SCU90[22]=1                   TIMER5      SCU80[4]=1      GPIOA4
+ * -----+---------+-----------+-----------------------------+-----------+---------------+----------
+ *
+ * E19 is a single-signal pin with two functions that influence the active
+ * signal. In this case both bits have the same meaning - enable a dedicated
+ * LPC reset pin. However it's not always the case that the bits in the
+ * OR-relationship have the same meaning.
+ *
+ * -----+---------+-----------+-----------------------------+-----------+---------------+----------
+ *  E19   GPIOB4    LPCRST#     SCU80[12]=1 | Strap[14]=1                                 GPIOB4
+ * -----+---------+-----------+-----------------------------+-----------+---------------+----------
+ *
+ * For example, pin B19 has a low-priority signal that's enabled by two
+ * distinct SoC functions: A specific SIOPBI bit in register SCUA4, and an ACPI
+ * bit in the STRAP register. The ACPI bit configures signals on pins in
+ * addition to B19. Both of the low priority functions as well as the high
+ * priority function must be disabled for GPIOF1 to be used.
+ *
+ * Ball | Default | P0 Signal | P0 Expression                           | P1 Signal | P1 Expression                          | Other
+ * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+----------
+ *  B19   GPIOF1    NDCD4       SCU80[25]=1                               SIOPBI#     SCUA4[12]=1 | Strap[19]=0                GPIOF1
+ * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+----------
+ *
+ * For pin E18, the SoC ANDs the expected state of three bits to determine the
+ * pin's active signal:
+ *
+ * * SCU3C[3]: Enable external SOC reset function
+ * * SCU80[15]: Enable SPICS1# or EXTRST# function pin
+ * * SCU90[31]: Select SPI interface CS# output
+ *
+ * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+----------
+ *  E18   GPIOB7    EXTRST#     SCU3C[3]=1 & SCU80[15]=1 & SCU90[31]=0    SPICS1#     SCU3C[3]=1 & SCU80[15]=1 & SCU90[31]=1   GPIOB7
+ * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+----------
+ *
+ * (Bits SCU3C[3] and SCU80[15] appear to only be used in the expressions for
+ * selecting the signals on pin E18)
+ *
+ * Pin T5 is a multi-signal pin with a more complex configuration:
+ *
+ * Ball | Default | P0 Signal | P0 Expression                | P1 Signal | P1 Expression | Other
+ * -----+---------+-----------+------------------------------+-----------+---------------+----------
+ *  T5    GPIOL1    VPIDE       SCU90[5:4]!=0 & SCU84[17]=1    NDCD1       SCU84[17]=1     GPIOL1
+ * -----+---------+-----------+------------------------------+-----------+---------------+----------
+ *
+ * The high priority signal configuration is best thought of in terms of its
+ * exploded form, with reference to the SCU90[5:4] bits:
+ *
+ * * SCU90[5:4]=00: disable
+ * * SCU90[5:4]=01: 18 bits (R6/G6/B6) video mode.
+ * * SCU90[5:4]=10: 24 bits (R8/G8/B8) video mode.
+ * * SCU90[5:4]=11: 30 bits (R10/G10/B10) video mode.
+ *
+ * Re-writing:
+ *
+ * -----+---------+-----------+------------------------------+-----------+---------------+----------
+ *  T5    GPIOL1    VPIDE      (SCU90[5:4]=1 & SCU84[17]=1)    NDCD1       SCU84[17]=1     GPIOL1
+ *                             | (SCU90[5:4]=2 & SCU84[17]=1)
+ *                             | (SCU90[5:4]=3 & SCU84[17]=1)
+ * -----+---------+-----------+------------------------------+-----------+---------------+----------
+ *
+ * For reference the SCU84[17] bit configure the "UART1 NDCD1 or Video VPIDE
+ * function pin", where the signal itself is determined by whether SCU94[5:4]
+ * is disabled or in one of the 18, 24 or 30bit video modes.
+ *
+ * Other video-input-related pins require an explicit state in SCU90[5:4], e.g.
+ * W1 and U5:
+ *
+ * -----+---------+-----------+------------------------------+-----------+---------------+----------
+ *  W1    GPIOL6    VPIB0       SCU90[5:4]=3 & SCU84[22]=1     TXD1        SCU84[22]=1     GPIOL6
+ *  U5    GPIOL7    VPIB1       SCU90[5:4]=3 & SCU84[23]=1     RXD1        SCU84[23]=1     GPIOL7
+ * -----+---------+-----------+------------------------------+-----------+---------------+----------
+ *
+ * The examples of T5 and W1 are particularly fertile, as they also demonstrate
+ * that despite operating as part of the video input bus each signal needs to
+ * be enabled individually via it's own SCU84 (in the cases of T5 and W1)
+ * register bit. This is a little crazy if the bus doesn't have optional
+ * signals, but is used to decent effect with some of the UARTs where not all
+ * signals are required. However, this isn't done consistently - UART1 is
+ * enabled on a per-pin basis, and by contrast, all signals for UART6 are
+ * enabled by a single bit.
+ *
+ * Further, the high and low priority signals listed in the table above share
+ * a configuration bit. The VPI signals should operate in concert in a single
+ * function, but the UART signals should retain the ability to be configured
+ * independently. This pushes the implementation down the path of tagging a
+ * signal's expressions with the function they participate in, rather than
+ * defining masks affecting multiple signals per function. The latter approach
+ * fails in this instance where applying the configuration for the UART pin of
+ * interest will stomp on the state of other UART signals when disabling the
+ * VPI functions on the current pin.
+ *
+ * Ball |  Default   | P0 Signal | P0 Expression             | P1 Signal | P1 Expression | Other
+ * -----+------------+-----------+---------------------------+-----------+---------------+------------
+ *  A12   RGMII1TXCK   GPIOT0      SCUA0[0]=1                  RMII1TXEN   Strap[6]=0      RGMII1TXCK
+ *  B12   RGMII1TXCTL  GPIOT1      SCUA0[1]=1                  –           Strap[6]=0      RGMII1TXCTL
+ * -----+------------+-----------+---------------------------+-----------+---------------+------------
+ *
+ * A12 demonstrates that the "Other" signal isn't always GPIO - in this case
+ * GPIOT0 is a high-priority signal and RGMII1TXCK is Other. Thus, GPIO
+ * should be treated like any other signal type with full function expression
+ * requirements, and not assumed to be the default case. Separately, GPIOT0 and
+ * GPIOT1's signal descriptor bits are distinct, therefore we must iterate all
+ * pins in the function's group to disable the higher-priority signals such
+ * that the signal for the function of interest is correctly enabled.
+ *
+ * Finally, three priority levels aren't always enough; the AST2500 brings with
+ * it 18 pins of five priority levels, however the 18 pins only use three of
+ * the five priority levels.
+ *
+ * Ultimately the requirement to control pins in the examples above drive the
+ * design:
+ *
+ * * Pins provide signals according to functions activated in the mux
+ *   configuration
+ *
+ * * Pins provide up to five signal types in a priority order
+ *
+ * * For priorities levels defined on a pin, each priority provides one signal
+ *
+ * * Enabling lower priority signals requires higher priority signals be
+ *   disabled
+ *
+ * * A function represents a set of signals; functions are distinct if their
+ *   sets of signals are not equal
+ *
+ * * Signals participate in one or more functions
+ *
+ * * A function is described by an expression of one or more signal
+ *   descriptors, which compare bit values in a register
+ *
+ * * A signal expression is the smallest set of signal descriptors whose
+ *   comparisons must evaluate 'true' for a signal to be enabled on a pin.
+ *
+ * * A signal participating in a function is active on a pin if evaluating all
+ *   signal descriptors in the pin's signal expression for the function yields
+ *   a 'true' result
+ *
+ * * A signal at a given priority on a given pin is active if any of the
+ *   functions in which the signal participates are active, and no higher
+ *   priority signal on the pin is active
+ *
+ * * GPIO is configured per-pin
+ *
+ * And so:
+ *
+ * * To disable a signal, any function(s) activating the signal must be
+ *   disabled
+ *
+ * * Each pin must know the signal expressions of functions in which it
+ *   participates, for the purpose of enabling the Other function. This is done
+ *   by deactivating all functions that activate higher priority signals on the
+ *   pin.
+ *
+ * As a concrete example:
+ *
+ * * T5 provides three signals types: VPIDE, NDCD1 and GPIO
+ *
+ * * The VPIDE signal participates in 3 functions: VPI18, VPI24 and VPI30
+ *
+ * * The NDCD1 signal participates in just its own NDCD1 function
+ *
+ * * VPIDE is high priority, NDCD1 is low priority, and GPIOL1 is the least
+ *   prioritised
+ *
+ * * The prerequisit for activating the NDCD1 signal is that the VPI18, VPI24
+ *   and VPI30 functions all be disabled
+ *
+ * * Similarly, all of VPI18, VPI24, VPI30 and NDCD1 functions must be disabled
+ *   to provide GPIOL6
+ *
+ * Considerations
+ * --------------
+ *
+ * If pinctrl allows us to allocate a pin we can configure a function without
+ * concern for the function of already allocated pins, if pin groups are
+ * created with respect to the SoC functions in which they participate. This is
+ * intuitive, but it did not feel obvious from the bit/pin relationships.
+ *
+ * Conversely, failing to allocate all pins in a group indicates some bits (as
+ * well as pins) required for the group's configuration will already be in use,
+ * likely in a way that's inconsistent with the requirements of the failed
+ * group.
+ *
+ * Implementation
+ * --------------
+ *
+ * Beyond the documentation below the various structures and helper macros that
+ * allow the implementation to hang together are defined. The macros are fairly
+ * dense, so below we walk through some raw examples of the configuration
+ * tables in an effort to clarify the concepts.
+ *
+ * The complexity of configuring the mux combined with the scale of the pins
+ * and functions was a concern, so the table design along with the macro jungle
+ * is an attempt to address it. The rough principles of the approach are:
+ *
+ * 1. Use a data-driven solution rather than embedding state into code
+ * 2. Minimise editing to the specifics of the given mux configuration
+ * 3. Detect as many errors as possible at compile time
+ *
+ * Addressing point 3 leads to naming of symbols in terms of the four
+ * properties associated with a given mux configuration: The pin, the signal,
+ * the group and the function. In this way copy/paste errors cause duplicate
+ * symbols to be defined, which prevents successful compilation. Failing to
+ * properly parent the tables leads to unused symbol warnings, and use of
+ * designated initialisers and additional warnings ensures that there are
+ * no override errors in the pin, group and function arrays.
+ *
+ * Addressing point 2 drives the development of the macro jungle, as it
+ * centralises the definition noise at the cost of taking some time to
+ * understand.
+ *
+ * Here's a complete, concrete "pre-processed" example of the table structures
+ * used to describe the D6 ball from the examples above:
+ *
+ * ```
+ * static const struct aspeed_sig_desc sig_descs_MAC1LINK_MAC1LINK[] = {
+ *     {
+ *         .ip = ASPEED_IP_SCU,
+ *         .reg = 0x80,
+ *         .mask = BIT(0),
+ *         .enable = 1,
+ *         .disable = 0
+ *     },
+ * };
+ *
+ * static const struct aspeed_sig_expr sig_expr_MAC1LINK_MAC1LINK = {
+ *     .signal = "MAC1LINK",
+ *     .function = "MAC1LINK",
+ *     .ndescs = ARRAY_SIZE(sig_descs_MAC1LINK_MAC1LINK),
+ *     .descs = &(sig_descs_MAC1LINK_MAC1LINK)[0],
+ * };
+ *
+ * static const struct aspeed_sig_expr *sig_exprs_MAC1LINK_MAC1LINK[] = {
+ *     &sig_expr_MAC1LINK_MAC1LINK,
+ *     NULL,
+ * };
+ *
+ * static const struct aspeed_sig_desc sig_descs_GPIOA0_GPIOA0[] = { };
+ *
+ * static const struct aspeed_sig_expr sig_expr_GPIOA0_GPIOA0 = {
+ *     .signal = "GPIOA0",
+ *     .function = "GPIOA0",
+ *     .ndescs = ARRAY_SIZE(sig_descs_GPIOA0_GPIOA0),
+ *     .descs = &(sig_descs_GPIOA0_GPIOA0)[0],
+ * };
+ *
+ * static const struct aspeed_sig_expr *sig_exprs_GPIOA0_GPIOA0[] = {
+ *     &sig_expr_GPIOA0_GPIOA0,
+ *     NULL
+ * };
+ *
+ * static const struct aspeed_sig_expr **pin_exprs_0[] = {
+ *     sig_exprs_MAC1LINK_MAC1LINK,
+ *     sig_exprs_GPIOA0_GPIOA0,
+ *     NULL
+ * };
+ *
+ * static const struct aspeed_pin_desc pin_0 = { "0", (&pin_exprs_0[0]) };
+ * static const int group_pins_MAC1LINK[] = { 0 };
+ * static const char *func_groups_MAC1LINK[] = { "MAC1LINK" };
+ *
+ * static struct pinctrl_pin_desc aspeed_g4_pins[] = {
+ *     [0] = { .number = 0, .name = "D6", .drv_data = &pin_0 },
+ * };
+ *
+ * static const struct aspeed_pin_group aspeed_g4_groups[] = {
+ *     {
+ *         .name = "MAC1LINK",
+ *         .pins = &(group_pins_MAC1LINK)[0],
+ *         .npins = ARRAY_SIZE(group_pins_MAC1LINK),
+ *     },
+ * };
+ *
+ * static const struct aspeed_pin_function aspeed_g4_functions[] = {
+ *     {
+ *         .name = "MAC1LINK",
+ *         .groups = &func_groups_MAC1LINK[0],
+ *         .ngroups = ARRAY_SIZE(func_groups_MAC1LINK),
+ *     },
+ * };
+ * ```
+ *
+ * At the end of the day much of the above code is compressed into the
+ * following two lines:
+ *
+ * ```
+ * #define D6 0
+ * SSSF_PIN_DECL(D6, GPIOA0, MAC1LINK, SIG_DESC_SET(SCU80, 0));
+ * ```
+ *
+ * The two examples below show just the differences from the example above.
+ *
+ * Ball E18 demonstrates a function, EXTRST, that requires multiple descriptors
+ * be set for it to be muxed:
+ *
+ * ```
+ * static const struct aspeed_sig_desc sig_descs_EXTRST_EXTRST[] = {
+ *     {
+ *         .ip = ASPEED_IP_SCU,
+ *         .reg = 0x3C,
+ *         .mask = BIT(3),
+ *         .enable = 1,
+ *         .disable = 0
+ *     },
+ *     {
+ *         .ip = ASPEED_IP_SCU,
+ *         .reg = 0x80,
+ *         .mask = BIT(15),
+ *         .enable = 1,
+ *         .disable = 0
+ *     },
+ *     {
+ *         .ip = ASPEED_IP_SCU,
+ *         .reg = 0x90,
+ *         .mask = BIT(31),
+ *         .enable = 0,
+ *         .disable = 1
+ *     },
+ * };
+ *
+ * static const struct aspeed_sig_expr sig_expr_EXTRST_EXTRST = {
+ *     .signal = "EXTRST",
+ *     .function = "EXTRST",
+ *     .ndescs = ARRAY_SIZE(sig_descs_EXTRST_EXTRST),
+ *     .descs = &(sig_descs_EXTRST_EXTRST)[0],
+ * };
+ * ...
+ * ```
+ *
+ * For ball E19, we have multiple functions enabling a single signal, LPCRST#.
+ * The data structures look like:
+ *
+ * static const struct aspeed_sig_desc sig_descs_LPCRST_LPCRST[] = {
+ *     {
+ *         .ip = ASPEED_IP_SCU,
+ *         .reg = 0x80,
+ *         .mask = BIT(12),
+ *         .enable = 1,
+ *         .disable = 0
+ *     },
+ * };
+ *
+ * static const struct aspeed_sig_expr sig_expr_LPCRST_LPCRST = {
+ *     .signal = "LPCRST",
+ *     .function = "LPCRST",
+ *     .ndescs = ARRAY_SIZE(sig_descs_LPCRST_LPCRST),
+ *     .descs = &(sig_descs_LPCRST_LPCRST)[0],
+ * };
+ *
+ * static const struct aspeed_sig_desc sig_descs_LPCRST_LPCRSTS[] = {
+ *     {
+ *         .ip = ASPEED_IP_SCU,
+ *         .reg = 0x70,
+ *         .mask = BIT(14),
+ *         .enable = 1,
+ *         .disable = 0
+ *     },
+ * };
+ *
+ * static const struct aspeed_sig_expr sig_expr_LPCRST_LPCRSTS = {
+ *     .signal = "LPCRST",
+ *     .function = "LPCRSTS",
+ *     .ndescs = ARRAY_SIZE(sig_descs_LPCRST_LPCRSTS),
+ *     .descs = &(sig_descs_LPCRST_LPCRSTS)[0],
+ * };
+ *
+ * static const struct aspeed_sig_expr *sig_exprs_LPCRST_LPCRST[] = {
+ *     &sig_expr_LPCRST_LPCRST,
+ *     &sig_expr_LPCRST_LPCRSTS,
+ *     NULL,
+ * };
+ * ...
+ * ```
+ *
+ * Both expressions listed in the sig_exprs_LPCRST_LPCRST array need to be set
+ * to disabled for the associated GPIO to be muxed.
+ *
+ */
+
+#define ASPEED_IP_SCU          0
+#define ASPEED_IP_GFX          1
+#define ASPEED_IP_LPC          2
+#define ASPEED_NR_PINMUX_IPS   3
+
+ /**
+  * A signal descriptor, which describes the register, bits and the
+  * enable/disable values that should be compared or written.
+  *
+  * @ip: The IP block identifier, used as an index into the regmap array in
+  *      struct aspeed_pinctrl_data
+  * @reg: The register offset with respect to the base address of the IP block
+  * @mask: The mask to apply to the register. The lowest set bit of the mask is
+  *        used to derive the shift value.
+  * @enable: The value that enables the function. Value should be in the LSBs,
+  *          not at the position of the mask.
+  * @disable: The value that disables the function. Value should be in the
+  *           LSBs, not at the position of the mask.
+  */
+struct aspeed_sig_desc {
+       unsigned int ip;
+       unsigned int reg;
+       u32 mask;
+       u32 enable;
+       u32 disable;
+};
+
+/**
+ * Describes a signal expression. The expression is evaluated by ANDing the
+ * evaluation of the descriptors.
+ *
+ * @signal: The signal name for the priority level on the pin. If the signal
+ *          type is GPIO, then the signal name must begin with the string
+ *          "GPIO", e.g. GPIOA0, GPIOT4 etc.
+ * @function: The name of the function the signal participates in for the
+ *            associated expression
+ * @ndescs: The number of signal descriptors in the expression
+ * @descs: Pointer to an array of signal descriptors that comprise the
+ *         function expression
+ */
+struct aspeed_sig_expr {
+       const char *signal;
+       const char *function;
+       int ndescs;
+       const struct aspeed_sig_desc *descs;
+};
+
+/**
+ * A struct capturing the list of expressions enabling signals at each priority
+ * for a given pin. The signal configuration for a priority level is evaluated
+ * by ORing the evaluation of the signal expressions in the respective
+ * priority's list.
+ *
+ * @name: A name for the pin
+ * @prios: A pointer to an array of expression list pointers
+ *
+ */
+struct aspeed_pin_desc {
+       const char *name;
+       const struct aspeed_sig_expr ***prios;
+};
+
+/* Macro hell */
+
+#define SIG_DESC_IP_BIT(ip, reg, idx, val) \
+       { ip, reg, BIT_MASK(idx), val, (((val) + 1) & 1) }
+
+/**
+ * Short-hand macro for describing an SCU descriptor enabled by the state of
+ * one bit. The disable value is derived.
+ *
+ * @reg: The signal's associated register, offset from base
+ * @idx: The signal's bit index in the register
+ * @val: The value (0 or 1) that enables the function
+ */
+#define SIG_DESC_BIT(reg, idx, val) \
+       SIG_DESC_IP_BIT(ASPEED_IP_SCU, reg, idx, val)
+
+#define SIG_DESC_IP_SET(ip, reg, idx) SIG_DESC_IP_BIT(ip, reg, idx, 1)
+
+/**
+ * A further short-hand macro expanding to an SCU descriptor enabled by a set
+ * bit.
+ *
+ * @reg: The register, offset from base
+ * @idx: The bit index in the register
+ */
+#define SIG_DESC_SET(reg, idx) SIG_DESC_IP_BIT(ASPEED_IP_SCU, reg, idx, 1)
+
+#define SIG_DESC_LIST_SYM(sig, func) sig_descs_ ## sig ## _ ## func
+#define SIG_DESC_LIST_DECL(sig, func, ...) \
+       static const struct aspeed_sig_desc SIG_DESC_LIST_SYM(sig, func)[] = \
+               { __VA_ARGS__ }
+
+#define SIG_EXPR_SYM(sig, func) sig_expr_ ## sig ## _ ## func
+#define SIG_EXPR_DECL_(sig, func) \
+       static const struct aspeed_sig_expr SIG_EXPR_SYM(sig, func) = \
+       { \
+               .signal = #sig, \
+               .function = #func, \
+               .ndescs = ARRAY_SIZE(SIG_DESC_LIST_SYM(sig, func)), \
+               .descs = &(SIG_DESC_LIST_SYM(sig, func))[0], \
+       }
+
+/**
+ * Declare a signal expression.
+ *
+ * @sig: A macro symbol name for the signal (is subjected to stringification
+ *        and token pasting)
+ * @func: The function in which the signal is participating
+ * @...: Signal descriptors that define the signal expression
+ *
+ * For example, the following declares the ROMD8 signal for the ROM16 function:
+ *
+ *     SIG_EXPR_DECL(ROMD8, ROM16, SIG_DESC_SET(SCU90, 6));
+ *
+ * And with multiple signal descriptors:
+ *
+ *     SIG_EXPR_DECL(ROMD8, ROM16S, SIG_DESC_SET(HW_STRAP1, 4),
+ *              { HW_STRAP1, GENMASK(1, 0), 0, 0 });
+ */
+#define SIG_EXPR_DECL(sig, func, ...) \
+       SIG_DESC_LIST_DECL(sig, func, __VA_ARGS__); \
+       SIG_EXPR_DECL_(sig, func)
+
+/**
+ * Declare a pointer to a signal expression
+ *
+ * @sig: The macro symbol name for the signal (subjected to token pasting)
+ * @func: The macro symbol name for the function (subjected to token pasting)
+ */
+#define SIG_EXPR_PTR(sig, func) (&SIG_EXPR_SYM(sig, func))
+
+#define SIG_EXPR_LIST_SYM(sig) sig_exprs_ ## sig
+
+/**
+ * Declare a signal expression list for reference in a struct aspeed_pin_prio.
+ *
+ * @sig: A macro symbol name for the signal (is subjected to token pasting)
+ * @...: Signal expression structure pointers (use SIG_EXPR_PTR())
+ *
+ * For example, the 16-bit ROM bus can be enabled by one of two possible signal
+ * expressions:
+ *
+ *     SIG_EXPR_DECL(ROMD8, ROM16, SIG_DESC_SET(SCU90, 6));
+ *     SIG_EXPR_DECL(ROMD8, ROM16S, SIG_DESC_SET(HW_STRAP1, 4),
+ *              { HW_STRAP1, GENMASK(1, 0), 0, 0 });
+ *     SIG_EXPR_LIST_DECL(ROMD8, SIG_EXPR_PTR(ROMD8, ROM16),
+ *              SIG_EXPR_PTR(ROMD8, ROM16S));
+ */
+#define SIG_EXPR_LIST_DECL(sig, ...) \
+       static const struct aspeed_sig_expr *SIG_EXPR_LIST_SYM(sig)[] = \
+               { __VA_ARGS__, NULL }
+
+/**
+ * A short-hand macro for declaring a function expression and an expression
+ * list with a single function.
+ *
+ * @func: A macro symbol name for the function (is subjected to token pasting)
+ * @...: Function descriptors that define the function expression
+ *
+ * For example, signal NCTS6 participates in its own function with one group:
+ *
+ *     SIG_EXPR_LIST_DECL_SINGLE(NCTS6, NCTS6, SIG_DESC_SET(SCU90, 7));
+ */
+#define SIG_EXPR_LIST_DECL_SINGLE(sig, func, ...) \
+       SIG_DESC_LIST_DECL(sig, func, __VA_ARGS__); \
+       SIG_EXPR_DECL_(sig, func); \
+       SIG_EXPR_LIST_DECL(sig, SIG_EXPR_PTR(sig, func))
+
+#define SIG_EXPR_LIST_DECL_DUAL(sig, f0, f1) \
+       SIG_EXPR_LIST_DECL(sig, SIG_EXPR_PTR(sig, f0), SIG_EXPR_PTR(sig, f1))
+
+#define SIG_EXPR_LIST_PTR(sig) (&SIG_EXPR_LIST_SYM(sig)[0])
+
+#define PIN_EXPRS_SYM(pin) pin_exprs_ ## pin
+#define PIN_EXPRS_PTR(pin) (&PIN_EXPRS_SYM(pin)[0])
+#define PIN_SYM(pin) pin_ ## pin
+
+#define MS_PIN_DECL_(pin, ...) \
+       static const struct aspeed_sig_expr **PIN_EXPRS_SYM(pin)[] = \
+               { __VA_ARGS__, NULL }; \
+       static const struct aspeed_pin_desc PIN_SYM(pin) = \
+               { #pin, PIN_EXPRS_PTR(pin) }
+
+/**
+ * Declare a multi-signal pin
+ *
+ * @pin: The pin number
+ * @other: Macro name for "other" functionality (subjected to stringification)
+ * @high: Macro name for the highest priority signal functions
+ * @low: Macro name for the low signal functions
+ *
+ * For example:
+ *
+ *     #define A8 56
+ *     SIG_EXPR_DECL(ROMD8, ROM16, SIG_DESC_SET(SCU90, 6));
+ *     SIG_EXPR_DECL(ROMD8, ROM16S, SIG_DESC_SET(HW_STRAP1, 4),
+ *              { HW_STRAP1, GENMASK(1, 0), 0, 0 });
+ *     SIG_EXPR_LIST_DECL(ROMD8, SIG_EXPR_PTR(ROMD8, ROM16),
+ *              SIG_EXPR_PTR(ROMD8, ROM16S));
+ *     SIG_EXPR_LIST_DECL_SINGLE(NCTS6, NCTS6, SIG_DESC_SET(SCU90, 7));
+ *     MS_PIN_DECL(A8, GPIOH0, ROMD8, NCTS6);
+ */
+#define MS_PIN_DECL(pin, other, high, low) \
+       SIG_EXPR_LIST_DECL_SINGLE(other, other); \
+       MS_PIN_DECL_(pin, \
+                       SIG_EXPR_LIST_PTR(high), \
+                       SIG_EXPR_LIST_PTR(low), \
+                       SIG_EXPR_LIST_PTR(other))
+
+#define PIN_GROUP_SYM(func) pins_ ## func
+#define FUNC_GROUP_SYM(func) groups_ ## func
+#define FUNC_GROUP_DECL(func, ...) \
+       static const int PIN_GROUP_SYM(func)[] = { __VA_ARGS__ }; \
+       static const char *FUNC_GROUP_SYM(func)[] = { #func }
+
+/**
+ * Declare a single signal pin
+ *
+ * @pin: The pin number
+ * @other: Macro name for "other" functionality (subjected to stringification)
+ * @sig: Macro name for the signal (subjected to stringification)
+ *
+ * For example:
+ *
+ *     #define E3 80
+ *     SIG_EXPR_LIST_DECL_SINGLE(SCL5, I2C5, I2C5_DESC);
+ *     SS_PIN_DECL(E3, GPIOK0, SCL5);
+ */
+#define SS_PIN_DECL(pin, other, sig) \
+       SIG_EXPR_LIST_DECL_SINGLE(other, other); \
+       MS_PIN_DECL_(pin, SIG_EXPR_LIST_PTR(sig), SIG_EXPR_LIST_PTR(other))
+
+/**
+ * Single signal, single function pin declaration
+ *
+ * @pin: The pin number
+ * @other: Macro name for "other" functionality (subjected to stringification)
+ * @sig: Macro name for the signal (subjected to stringification)
+ * @...: Signal descriptors that define the function expression
+ *
+ * For example:
+ *
+ *    SSSF_PIN_DECL(A4, GPIOA2, TIMER3, SIG_DESC_SET(SCU80, 2));
+ */
+#define SSSF_PIN_DECL(pin, other, sig, ...) \
+       SIG_EXPR_LIST_DECL_SINGLE(sig, sig, __VA_ARGS__); \
+       SIG_EXPR_LIST_DECL_SINGLE(other, other); \
+       MS_PIN_DECL_(pin, SIG_EXPR_LIST_PTR(sig), SIG_EXPR_LIST_PTR(other)); \
+       FUNC_GROUP_DECL(sig, pin)
+
+#define GPIO_PIN_DECL(pin, gpio) \
+       SIG_EXPR_LIST_DECL_SINGLE(gpio, gpio); \
+       MS_PIN_DECL_(pin, SIG_EXPR_LIST_PTR(gpio))
+
+struct aspeed_pin_group {
+       const char *name;
+       const unsigned int *pins;
+       const unsigned int npins;
+};
+
+#define ASPEED_PINCTRL_GROUP(name_) { \
+       .name = #name_, \
+       .pins = &(PIN_GROUP_SYM(name_))[0], \
+       .npins = ARRAY_SIZE(PIN_GROUP_SYM(name_)), \
+}
+
+struct aspeed_pin_function {
+       const char *name;
+       const char *const *groups;
+       unsigned int ngroups;
+};
+
+#define ASPEED_PINCTRL_FUNC(name_, ...) { \
+       .name = #name_, \
+       .groups = &FUNC_GROUP_SYM(name_)[0], \
+       .ngroups = ARRAY_SIZE(FUNC_GROUP_SYM(name_)), \
+}
+
+struct aspeed_pinmux_data;
+
+struct aspeed_pinmux_ops {
+       int (*set)(const struct aspeed_pinmux_data *ctx,
+                  const struct aspeed_sig_expr *expr, bool enabled);
+};
+
+struct aspeed_pinmux_data {
+       struct regmap *maps[ASPEED_NR_PINMUX_IPS];
+
+       const struct aspeed_pinmux_ops *ops;
+
+       const struct aspeed_pin_group *groups;
+       const unsigned int ngroups;
+
+       const struct aspeed_pin_function *functions;
+       const unsigned int nfunctions;
+};
+
+int aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc, bool enabled,
+                        struct regmap *map);
+
+int aspeed_sig_expr_eval(const struct aspeed_pinmux_data *ctx,
+                        const struct aspeed_sig_expr *expr,
+                        bool enabled);
+
+static inline int aspeed_sig_expr_set(const struct aspeed_pinmux_data *ctx,
+                                     const struct aspeed_sig_expr *expr,
+                                     bool enabled)
+{
+       return ctx->ops->set(ctx, expr, enabled);
+}
+
+#endif /* ASPEED_PINMUX_H */
index 97284c3..dcf7df7 100644 (file)
@@ -18,11 +18,15 @@ config PINCTRL_BCM281XX
          framework.  GPIO is provided by a separate GPIO driver.
 
 config PINCTRL_BCM2835
-       bool
+       bool "Broadcom BCM2835 GPIO (with PINCONF) driver"
+       depends on OF && (ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST)
        select PINMUX
        select PINCONF
        select GENERIC_PINCONF
        select GPIOLIB_IRQCHIP
+       default ARCH_BCM2835 || ARCH_BRCMSTB
+       help
+          Say Y here to enable the Broadcom BCM2835 GPIO driver.
 
 config PINCTRL_IPROC_GPIO
        bool "Broadcom iProc GPIO (with PINCONF) driver"
index 4b5cf0e..2bf6af7 100644 (file)
@@ -1048,6 +1048,8 @@ static int ns2_pinmux_probe(struct platform_device *pdev)
                return PTR_ERR(pinctrl->base0);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!res)
+               return -EINVAL;
        pinctrl->base1 = devm_ioremap_nocache(&pdev->dev, res->start,
                                        resource_size(res));
        if (!pinctrl->base1) {
index 06b5916..53a8eab 100644 (file)
@@ -1,12 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Pinctrl for Cirrus Logic CS47L35
  *
  * Copyright (C) 2016-2017 Cirrus Logic
- *
- * This program is free software; 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.
  */
 
 #include <linux/err.h>
index 0a322e2..e08c799 100644 (file)
@@ -1,12 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Pinctrl for Cirrus Logic CS47L85
  *
  * Copyright (C) 2016-2017 Cirrus Logic
- *
- * This program is free software; 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.
  */
 
 #include <linux/err.h>
index fc38f57..3151f10 100644 (file)
@@ -1,12 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Pinctrl for Cirrus Logic CS47L90
  *
  * Copyright (C) 2016-2017 Cirrus Logic
- *
- * This program is free software; 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.
  */
 
 #include <linux/err.h>
index 7c96945..c6b9f65 100644 (file)
@@ -1,12 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Pinctrl for Cirrus Logic Madera codecs
  *
  * Copyright (C) 2016-2018 Cirrus Logic
- *
- * This program is free software; 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.
  */
 
 #include <linux/err.h>
index 8000f4f..4ae1391 100644 (file)
@@ -1,12 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Pinctrl for Cirrus Logic Madera codecs
  *
  * Copyright (C) 2016-2017 Cirrus Logic
- *
- * This program is free software; 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.
  */
 
 #ifndef PINCTRL_MADERA_H
index a64849a..b70df27 100644 (file)
@@ -98,7 +98,7 @@ EXPORT_SYMBOL_GPL(pinctrl_dev_get_drvdata);
  */
 struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *devname)
 {
-       struct pinctrl_dev *pctldev = NULL;
+       struct pinctrl_dev *pctldev;
 
        if (!devname)
                return NULL;
@@ -177,29 +177,6 @@ const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin)
        return desc->name;
 }
 
-/**
- * pin_is_valid() - check if pin exists on controller
- * @pctldev: the pin control device to check the pin on
- * @pin: pin to check, use the local pin controller index number
- *
- * This tells us whether a certain pin exist on a certain pin controller or
- * not. Pin lists may be sparse, so some pins may not exist.
- */
-bool pin_is_valid(struct pinctrl_dev *pctldev, int pin)
-{
-       struct pin_desc *pindesc;
-
-       if (pin < 0)
-               return false;
-
-       mutex_lock(&pctldev->mutex);
-       pindesc = pin_desc_get(pctldev, pin);
-       mutex_unlock(&pctldev->mutex);
-
-       return pindesc != NULL;
-}
-EXPORT_SYMBOL_GPL(pin_is_valid);
-
 /* Deletes a range of pin descriptors */
 static void pinctrl_free_pindescs(struct pinctrl_dev *pctldev,
                                  const struct pinctrl_pin_desc *pins,
@@ -311,7 +288,7 @@ static inline int gpio_to_pin(struct pinctrl_gpio_range *range,
 static struct pinctrl_gpio_range *
 pinctrl_match_gpio_range(struct pinctrl_dev *pctldev, unsigned gpio)
 {
-       struct pinctrl_gpio_range *range = NULL;
+       struct pinctrl_gpio_range *range;
 
        mutex_lock(&pctldev->mutex);
        /* Loop over the ranges */
@@ -391,7 +368,7 @@ static int pinctrl_get_device_gpio_range(unsigned gpio,
                                         struct pinctrl_dev **outdev,
                                         struct pinctrl_gpio_range **outrange)
 {
-       struct pinctrl_dev *pctldev = NULL;
+       struct pinctrl_dev *pctldev;
 
        mutex_lock(&pinctrldev_list_mutex);
 
@@ -1215,6 +1192,15 @@ struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p,
 }
 EXPORT_SYMBOL_GPL(pinctrl_lookup_state);
 
+static void pinctrl_link_add(struct pinctrl_dev *pctldev,
+                            struct device *consumer)
+{
+       if (pctldev->desc->link_consumers)
+               device_link_add(consumer, pctldev->dev,
+                               DL_FLAG_PM_RUNTIME |
+                               DL_FLAG_AUTOREMOVE_CONSUMER);
+}
+
 /**
  * pinctrl_commit_state() - select/activate/program a pinctrl state to HW
  * @p: the pinctrl handle for the device that requests configuration
@@ -1260,6 +1246,10 @@ static int pinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state)
                if (ret < 0) {
                        goto unapply_new_state;
                }
+
+               /* Do not link hogs (circular dependency) */
+               if (p != setting->pctldev->p)
+                       pinctrl_link_add(setting->pctldev, p->dev);
        }
 
        p->state = state;
@@ -1665,7 +1655,7 @@ DEFINE_SHOW_ATTRIBUTE(pinctrl_groups);
 static int pinctrl_gpioranges_show(struct seq_file *s, void *what)
 {
        struct pinctrl_dev *pctldev = s->private;
-       struct pinctrl_gpio_range *range = NULL;
+       struct pinctrl_gpio_range *range;
 
        seq_puts(s, "GPIO ranges handled:\n");
 
index f7e354f..88ddbb2 100644 (file)
@@ -112,12 +112,11 @@ static int dt_to_map_one_config(struct pinctrl *p,
                np_pctldev = of_get_next_parent(np_pctldev);
                if (!np_pctldev || of_node_is_root(np_pctldev)) {
                        of_node_put(np_pctldev);
-                       ret = driver_deferred_probe_check_state(p->dev);
                        /* keep deferring if modules are enabled unless we've timed out */
-                       if (IS_ENABLED(CONFIG_MODULES) && !allow_default && ret == -ENODEV)
-                               ret = -EPROBE_DEFER;
+                       if (IS_ENABLED(CONFIG_MODULES) && !allow_default)
+                               return driver_deferred_probe_check_state_continue(p->dev);
 
-                       return ret;
+                       return driver_deferred_probe_check_state(p->dev);
                }
                /* If we're creating a hog we can use the passed pctldev */
                if (hog_pctldev && (np_pctldev == p->dev->of_node)) {
index aeab0d9..5f40580 100644 (file)
@@ -130,6 +130,13 @@ config PINCTRL_IMX8MM
        help
          Say Y here to enable the imx8mm pinctrl driver
 
+config PINCTRL_IMX8MN
+       bool "IMX8MN pinctrl driver"
+       depends on ARCH_MXC && ARM64
+       select PINCTRL_IMX
+       help
+         Say Y here to enable the imx8mn pinctrl driver
+
 config PINCTRL_IMX8MQ
        bool "IMX8MQ pinctrl driver"
        depends on ARCH_MXC && ARM64
index 02020a7..78e9140 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_PINCTRL_IMX6UL)  += pinctrl-imx6ul.o
 obj-$(CONFIG_PINCTRL_IMX7D)    += pinctrl-imx7d.o
 obj-$(CONFIG_PINCTRL_IMX7ULP)  += pinctrl-imx7ulp.o
 obj-$(CONFIG_PINCTRL_IMX8MM)   += pinctrl-imx8mm.o
+obj-$(CONFIG_PINCTRL_IMX8MN)   += pinctrl-imx8mn.o
 obj-$(CONFIG_PINCTRL_IMX8MQ)   += pinctrl-imx8mq.o
 obj-$(CONFIG_PINCTRL_IMX8QM)   += pinctrl-imx8qm.o
 obj-$(CONFIG_PINCTRL_IMX8QXP)  += pinctrl-imx8qxp.o
diff --git a/drivers/pinctrl/freescale/pinctrl-imx8mn.c b/drivers/pinctrl/freescale/pinctrl-imx8mn.c
new file mode 100644 (file)
index 0000000..100ed8c
--- /dev/null
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2018-2019 NXP
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-imx.h"
+
+enum imx8mn_pads {
+       MX8MN_PAD_RESERVE0 = 0,
+       MX8MN_PAD_RESERVE1 = 1,
+       MX8MN_PAD_RESERVE2 = 2,
+       MX8MN_PAD_RESERVE3 = 3,
+       MX8MN_PAD_RESERVE4 = 4,
+       MX8MN_PAD_RESERVE5 = 5,
+       MX8MN_PAD_RESERVE6 = 6,
+       MX8MN_PAD_RESERVE7 = 7,
+       MX8MN_IOMUXC_BOOT_MODE2 = 8,
+       MX8MN_IOMUXC_BOOT_MODE3 = 9,
+       MX8MN_IOMUXC_GPIO1_IO00 = 10,
+       MX8MN_IOMUXC_GPIO1_IO01 = 11,
+       MX8MN_IOMUXC_GPIO1_IO02 = 12,
+       MX8MN_IOMUXC_GPIO1_IO03 = 13,
+       MX8MN_IOMUXC_GPIO1_IO04 = 14,
+       MX8MN_IOMUXC_GPIO1_IO05 = 15,
+       MX8MN_IOMUXC_GPIO1_IO06 = 16,
+       MX8MN_IOMUXC_GPIO1_IO07 = 17,
+       MX8MN_IOMUXC_GPIO1_IO08 = 18,
+       MX8MN_IOMUXC_GPIO1_IO09 = 19,
+       MX8MN_IOMUXC_GPIO1_IO10 = 20,
+       MX8MN_IOMUXC_GPIO1_IO11 = 21,
+       MX8MN_IOMUXC_GPIO1_IO12 = 22,
+       MX8MN_IOMUXC_GPIO1_IO13 = 23,
+       MX8MN_IOMUXC_GPIO1_IO14 = 24,
+       MX8MN_IOMUXC_GPIO1_IO15 = 25,
+       MX8MN_IOMUXC_ENET_MDC = 26,
+       MX8MN_IOMUXC_ENET_MDIO = 27,
+       MX8MN_IOMUXC_ENET_TD3 = 28,
+       MX8MN_IOMUXC_ENET_TD2 = 29,
+       MX8MN_IOMUXC_ENET_TD1 = 30,
+       MX8MN_IOMUXC_ENET_TD0 = 31,
+       MX8MN_IOMUXC_ENET_TX_CTL = 32,
+       MX8MN_IOMUXC_ENET_TXC = 33,
+       MX8MN_IOMUXC_ENET_RX_CTL = 34,
+       MX8MN_IOMUXC_ENET_RXC = 35,
+       MX8MN_IOMUXC_ENET_RD0 = 36,
+       MX8MN_IOMUXC_ENET_RD1 = 37,
+       MX8MN_IOMUXC_ENET_RD2 = 38,
+       MX8MN_IOMUXC_ENET_RD3 = 39,
+       MX8MN_IOMUXC_SD1_CLK = 40,
+       MX8MN_IOMUXC_SD1_CMD = 41,
+       MX8MN_IOMUXC_SD1_DATA0 = 42,
+       MX8MN_IOMUXC_SD1_DATA1 = 43,
+       MX8MN_IOMUXC_SD1_DATA2 = 44,
+       MX8MN_IOMUXC_SD1_DATA3 = 45,
+       MX8MN_IOMUXC_SD1_DATA4 = 46,
+       MX8MN_IOMUXC_SD1_DATA5 = 47,
+       MX8MN_IOMUXC_SD1_DATA6 = 48,
+       MX8MN_IOMUXC_SD1_DATA7 = 49,
+       MX8MN_IOMUXC_SD1_RESET_B = 50,
+       MX8MN_IOMUXC_SD1_STROBE = 51,
+       MX8MN_IOMUXC_SD2_CD_B = 52,
+       MX8MN_IOMUXC_SD2_CLK = 53,
+       MX8MN_IOMUXC_SD2_CMD = 54,
+       MX8MN_IOMUXC_SD2_DATA0 = 55,
+       MX8MN_IOMUXC_SD2_DATA1 = 56,
+       MX8MN_IOMUXC_SD2_DATA2 = 57,
+       MX8MN_IOMUXC_SD2_DATA3 = 58,
+       MX8MN_IOMUXC_SD2_RESET_B = 59,
+       MX8MN_IOMUXC_SD2_WP = 60,
+       MX8MN_IOMUXC_NAND_ALE = 61,
+       MX8MN_IOMUXC_NAND_CE0 = 62,
+       MX8MN_IOMUXC_NAND_CE1 = 63,
+       MX8MN_IOMUXC_NAND_CE2 = 64,
+       MX8MN_IOMUXC_NAND_CE3 = 65,
+       MX8MN_IOMUXC_NAND_CLE = 66,
+       MX8MN_IOMUXC_NAND_DATA00 = 67,
+       MX8MN_IOMUXC_NAND_DATA01 = 68,
+       MX8MN_IOMUXC_NAND_DATA02 = 69,
+       MX8MN_IOMUXC_NAND_DATA03 = 70,
+       MX8MN_IOMUXC_NAND_DATA04 = 71,
+       MX8MN_IOMUXC_NAND_DATA05 = 72,
+       MX8MN_IOMUXC_NAND_DATA06 = 73,
+       MX8MN_IOMUXC_NAND_DATA07 = 74,
+       MX8MN_IOMUXC_NAND_DQS = 75,
+       MX8MN_IOMUXC_NAND_RE_B = 76,
+       MX8MN_IOMUXC_NAND_READY_B = 77,
+       MX8MN_IOMUXC_NAND_WE_B = 78,
+       MX8MN_IOMUXC_NAND_WP_B = 79,
+       MX8MN_IOMUXC_SAI5_RXFS = 80,
+       MX8MN_IOMUXC_SAI5_RXC = 81,
+       MX8MN_IOMUXC_SAI5_RXD0 = 82,
+       MX8MN_IOMUXC_SAI5_RXD1 = 83,
+       MX8MN_IOMUXC_SAI5_RXD2 = 84,
+       MX8MN_IOMUXC_SAI5_RXD3 = 85,
+       MX8MN_IOMUXC_SAI5_MCLK = 86,
+       MX8MN_IOMUXC_SAI1_RXFS = 87,
+       MX8MN_IOMUXC_SAI1_RXC = 88,
+       MX8MN_IOMUXC_SAI1_RXD0 = 89,
+       MX8MN_IOMUXC_SAI1_RXD1 = 90,
+       MX8MN_IOMUXC_SAI1_RXD2 = 91,
+       MX8MN_IOMUXC_SAI1_RXD3 = 92,
+       MX8MN_IOMUXC_SAI1_RXD4 = 93,
+       MX8MN_IOMUXC_SAI1_RXD5 = 94,
+       MX8MN_IOMUXC_SAI1_RXD6 = 95,
+       MX8MN_IOMUXC_SAI1_RXD7 = 96,
+       MX8MN_IOMUXC_SAI1_TXFS = 97,
+       MX8MN_IOMUXC_SAI1_TXC = 98,
+       MX8MN_IOMUXC_SAI1_TXD0 = 99,
+       MX8MN_IOMUXC_SAI1_TXD1 = 100,
+       MX8MN_IOMUXC_SAI1_TXD2 = 101,
+       MX8MN_IOMUXC_SAI1_TXD3 = 102,
+       MX8MN_IOMUXC_SAI1_TXD4 = 103,
+       MX8MN_IOMUXC_SAI1_TXD5 = 104,
+       MX8MN_IOMUXC_SAI1_TXD6 = 105,
+       MX8MN_IOMUXC_SAI1_TXD7 = 106,
+       MX8MN_IOMUXC_SAI1_MCLK = 107,
+       MX8MN_IOMUXC_SAI2_RXFS = 108,
+       MX8MN_IOMUXC_SAI2_RXC = 109,
+       MX8MN_IOMUXC_SAI2_RXD0 = 110,
+       MX8MN_IOMUXC_SAI2_TXFS = 111,
+       MX8MN_IOMUXC_SAI2_TXC = 112,
+       MX8MN_IOMUXC_SAI2_TXD0 = 113,
+       MX8MN_IOMUXC_SAI2_MCLK = 114,
+       MX8MN_IOMUXC_SAI3_RXFS = 115,
+       MX8MN_IOMUXC_SAI3_RXC = 116,
+       MX8MN_IOMUXC_SAI3_RXD = 117,
+       MX8MN_IOMUXC_SAI3_TXFS = 118,
+       MX8MN_IOMUXC_SAI3_TXC = 119,
+       MX8MN_IOMUXC_SAI3_TXD = 120,
+       MX8MN_IOMUXC_SAI3_MCLK = 121,
+       MX8MN_IOMUXC_SPDIF_TX = 122,
+       MX8MN_IOMUXC_SPDIF_RX = 123,
+       MX8MN_IOMUXC_SPDIF_EXT_CLK = 124,
+       MX8MN_IOMUXC_ECSPI1_SCLK = 125,
+       MX8MN_IOMUXC_ECSPI1_MOSI = 126,
+       MX8MN_IOMUXC_ECSPI1_MISO = 127,
+       MX8MN_IOMUXC_ECSPI1_SS0 = 128,
+       MX8MN_IOMUXC_ECSPI2_SCLK = 129,
+       MX8MN_IOMUXC_ECSPI2_MOSI = 130,
+       MX8MN_IOMUXC_ECSPI2_MISO = 131,
+       MX8MN_IOMUXC_ECSPI2_SS0 = 132,
+       MX8MN_IOMUXC_I2C1_SCL = 133,
+       MX8MN_IOMUXC_I2C1_SDA = 134,
+       MX8MN_IOMUXC_I2C2_SCL = 135,
+       MX8MN_IOMUXC_I2C2_SDA = 136,
+       MX8MN_IOMUXC_I2C3_SCL = 137,
+       MX8MN_IOMUXC_I2C3_SDA = 138,
+       MX8MN_IOMUXC_I2C4_SCL = 139,
+       MX8MN_IOMUXC_I2C4_SDA = 140,
+       MX8MN_IOMUXC_UART1_RXD = 141,
+       MX8MN_IOMUXC_UART1_TXD = 142,
+       MX8MN_IOMUXC_UART2_RXD = 143,
+       MX8MN_IOMUXC_UART2_TXD = 144,
+       MX8MN_IOMUXC_UART3_RXD = 145,
+       MX8MN_IOMUXC_UART3_TXD = 146,
+       MX8MN_IOMUXC_UART4_RXD = 147,
+       MX8MN_IOMUXC_UART4_TXD = 148,
+};
+
+/* Pad names for the pinmux subsystem */
+static const struct pinctrl_pin_desc imx8mn_pinctrl_pads[] = {
+       IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE0),
+       IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE1),
+       IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE2),
+       IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE3),
+       IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE4),
+       IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE5),
+       IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE6),
+       IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE7),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_BOOT_MODE2),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_BOOT_MODE3),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO00),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO01),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO02),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO03),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO04),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO05),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO06),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO07),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO08),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO09),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO10),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO11),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO12),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO13),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO14),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO15),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_MDC),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_MDIO),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_TD3),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_TD2),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_TD1),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_TD0),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_TX_CTL),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_TXC),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_RX_CTL),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_RXC),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_RD0),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_RD1),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_RD2),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_RD3),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_CLK),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_CMD),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA0),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA1),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA2),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA3),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA4),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA5),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA6),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA7),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_RESET_B),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_STROBE),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_CD_B),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_CLK),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_CMD),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_DATA0),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_DATA1),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_DATA2),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_DATA3),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_RESET_B),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_WP),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_ALE),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_CE0),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_CE1),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_CE2),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_CE3),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_CLE),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA00),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA01),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA02),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA03),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA04),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA05),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA06),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA07),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DQS),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_RE_B),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_READY_B),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_WE_B),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_WP_B),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_RXFS),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_RXC),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_RXD0),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_RXD1),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_RXD2),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_RXD3),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_MCLK),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXFS),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXC),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD0),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD1),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD2),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD3),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD4),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD5),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD6),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD7),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXFS),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXC),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD0),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD1),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD2),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD3),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD4),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD5),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD6),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD7),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_MCLK),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_RXFS),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_RXC),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_RXD0),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_TXFS),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_TXC),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_TXD0),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_MCLK),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_RXFS),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_RXC),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_RXD),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_TXFS),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_TXC),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_TXD),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_MCLK),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SPDIF_TX),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SPDIF_RX),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_SPDIF_EXT_CLK),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI1_SCLK),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI1_MOSI),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI1_MISO),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI1_SS0),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI2_SCLK),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI2_MOSI),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI2_MISO),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI2_SS0),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C1_SCL),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C1_SDA),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C2_SCL),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C2_SDA),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C3_SCL),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C3_SDA),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C4_SCL),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C4_SDA),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART1_RXD),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART1_TXD),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART2_RXD),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART2_TXD),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART3_RXD),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART3_TXD),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART4_RXD),
+       IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART4_TXD),
+};
+
+static struct imx_pinctrl_soc_info imx8mn_pinctrl_info = {
+       .pins = imx8mn_pinctrl_pads,
+       .npins = ARRAY_SIZE(imx8mn_pinctrl_pads),
+       .gpr_compatible = "fsl,imx8mn-iomuxc-gpr",
+};
+
+static const struct of_device_id imx8mn_pinctrl_of_match[] = {
+       { .compatible = "fsl,imx8mn-iomuxc", .data = &imx8mn_pinctrl_info, },
+       { /* sentinel */ }
+};
+
+static int imx8mn_pinctrl_probe(struct platform_device *pdev)
+{
+       return imx_pinctrl_probe(pdev, &imx8mn_pinctrl_info);
+}
+
+static struct platform_driver imx8mn_pinctrl_driver = {
+       .driver = {
+               .name = "imx8mn-pinctrl",
+               .of_match_table = of_match_ptr(imx8mn_pinctrl_of_match),
+               .suppress_bind_attrs = true,
+       },
+       .probe = imx8mn_pinctrl_probe,
+};
+
+static int __init imx8mn_pinctrl_init(void)
+{
+       return platform_driver_register(&imx8mn_pinctrl_driver);
+}
+arch_initcall(imx8mn_pinctrl_init);
index 18d9ad5..e5a112a 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinconf-generic.h>
 
+#include "pinctrl-intel.h"
+
 /* memory mapped register offsets */
 #define BYT_CONF0_REG          0x000
 #define BYT_CONF1_REG          0x004
@@ -35,6 +37,7 @@
 /* BYT_CONF0_REG register bits */
 #define BYT_IODEN              BIT(31)
 #define BYT_DIRECT_IRQ_EN      BIT(27)
+#define BYT_TRIG_MASK          GENMASK(26, 24)
 #define BYT_TRIG_NEG           BIT(26)
 #define BYT_TRIG_POS           BIT(25)
 #define BYT_TRIG_LVL           BIT(24)
 #define BYT_GLITCH_F_SLOW_CLK  BIT(17)
 #define BYT_GLITCH_F_FAST_CLK  BIT(16)
 #define BYT_PULL_STR_SHIFT     9
-#define BYT_PULL_STR_MASK      (3 << BYT_PULL_STR_SHIFT)
+#define BYT_PULL_STR_MASK      GENMASK(10, 9)
 #define BYT_PULL_STR_2K                (0 << BYT_PULL_STR_SHIFT)
 #define BYT_PULL_STR_10K       (1 << BYT_PULL_STR_SHIFT)
 #define BYT_PULL_STR_20K       (2 << BYT_PULL_STR_SHIFT)
 #define BYT_PULL_STR_40K       (3 << BYT_PULL_STR_SHIFT)
 #define BYT_PULL_ASSIGN_SHIFT  7
-#define BYT_PULL_ASSIGN_MASK   (3 << BYT_PULL_ASSIGN_SHIFT)
+#define BYT_PULL_ASSIGN_MASK   GENMASK(8, 7)
 #define BYT_PULL_ASSIGN_UP     (1 << BYT_PULL_ASSIGN_SHIFT)
 #define BYT_PULL_ASSIGN_DOWN   (2 << BYT_PULL_ASSIGN_SHIFT)
-#define BYT_PIN_MUX            0x07
+#define BYT_PIN_MUX            GENMASK(2, 0)
 
 /* BYT_VAL_REG register bits */
+#define BYT_DIR_MASK           GENMASK(2, 1)
 #define BYT_INPUT_EN           BIT(2)  /* 0: input enabled (active low)*/
 #define BYT_OUTPUT_EN          BIT(1)  /* 0: output enabled (active low)*/
 #define BYT_LEVEL              BIT(0)
 
-#define BYT_DIR_MASK           (BIT(1) | BIT(2))
-#define BYT_TRIG_MASK          (BIT(26) | BIT(25) | BIT(24))
-
-#define BYT_CONF0_RESTORE_MASK (BYT_DIRECT_IRQ_EN | BYT_TRIG_MASK | \
-                                BYT_PIN_MUX)
+#define BYT_CONF0_RESTORE_MASK (BYT_DIRECT_IRQ_EN | BYT_TRIG_MASK | BYT_PIN_MUX)
 #define BYT_VAL_RESTORE_MASK   (BYT_DIR_MASK | BYT_LEVEL)
 
 /* BYT_DEBOUNCE_REG bits */
-#define BYT_DEBOUNCE_PULSE_MASK                0x7
+#define BYT_DEBOUNCE_PULSE_MASK                GENMASK(2, 0)
 #define BYT_DEBOUNCE_PULSE_375US       1
 #define BYT_DEBOUNCE_PULSE_750US       2
 #define BYT_DEBOUNCE_PULSE_1500US      3
  * does not find a match for the requested function.
  */
 #define BYT_DEFAULT_GPIO_MUX   0
+#define BYT_ALTER_GPIO_MUX     1
 
 struct byt_gpio_pin_context {
        u32 conf0;
        u32 val;
 };
 
-struct byt_simple_func_mux {
-       const char *name;
-       unsigned short func;
-};
-
-struct byt_mixed_func_mux {
-       const char *name;
-       const unsigned short *func_values;
-};
-
-struct byt_pingroup {
-       const char *name;
-       const unsigned int *pins;
-       size_t npins;
-       unsigned short has_simple_funcs;
-       union {
-               const struct byt_simple_func_mux *simple_funcs;
-               const struct byt_mixed_func_mux *mixed_funcs;
-       };
-       size_t nfuncs;
-};
-
-struct byt_function {
-       const char *name;
-       const char * const *groups;
-       size_t ngroups;
-};
-
 struct byt_community {
        unsigned int pin_base;
        size_t npins;
@@ -132,47 +105,6 @@ struct byt_community {
        void __iomem *reg_base;
 };
 
-#define SIMPLE_FUNC(n, f)      \
-       {                       \
-               .name   = (n),  \
-               .func   = (f),  \
-       }
-#define MIXED_FUNC(n, f)               \
-       {                               \
-               .name           = (n),  \
-               .func_values    = (f),  \
-       }
-
-#define PIN_GROUP_SIMPLE(n, p, f)                              \
-       {                                                       \
-               .name                   = (n),                  \
-               .pins                   = (p),                  \
-               .npins                  = ARRAY_SIZE((p)),      \
-               .has_simple_funcs       = 1,                    \
-               {                                               \
-                       .simple_funcs           = (f),          \
-               },                                              \
-               .nfuncs                 = ARRAY_SIZE((f)),      \
-       }
-#define PIN_GROUP_MIXED(n, p, f)                               \
-       {                                                       \
-               .name                   = (n),                  \
-               .pins                   = (p),                  \
-               .npins                  = ARRAY_SIZE((p)),      \
-               .has_simple_funcs       = 0,                    \
-               {                                               \
-                       .mixed_funcs            = (f),          \
-               },                                              \
-               .nfuncs                 = ARRAY_SIZE((f)),      \
-       }
-
-#define FUNCTION(n, g)                                 \
-       {                                               \
-               .name           = (n),                  \
-               .groups         = (g),                  \
-               .ngroups        = ARRAY_SIZE((g)),      \
-       }
-
 #define COMMUNITY(p, n, map)           \
        {                               \
                .pin_base       = (p),  \
@@ -184,9 +116,9 @@ struct byt_pinctrl_soc_data {
        const char *uid;
        const struct pinctrl_pin_desc *pins;
        size_t npins;
-       const struct byt_pingroup *groups;
+       const struct intel_pingroup *groups;
        size_t ngroups;
-       const struct byt_function *functions;
+       const struct intel_function *functions;
        size_t nfunctions;
        const struct byt_community *communities;
        size_t ncommunities;
@@ -326,20 +258,11 @@ static const unsigned int byt_score_pins_map[BYT_NGPIO_SCORE] = {
 /* SCORE groups */
 static const unsigned int byt_score_uart1_pins[] = { 70, 71, 72, 73 };
 static const unsigned int byt_score_uart2_pins[] = { 74, 75, 76, 77 };
-static const struct byt_simple_func_mux byt_score_uart_mux[] = {
-       SIMPLE_FUNC("uart", 1),
-};
 
 static const unsigned int byt_score_pwm0_pins[] = { 94 };
 static const unsigned int byt_score_pwm1_pins[] = { 95 };
-static const struct byt_simple_func_mux byt_score_pwm_mux[] = {
-       SIMPLE_FUNC("pwm", 1),
-};
 
 static const unsigned int byt_score_sio_spi_pins[] = { 66, 67, 68, 69 };
-static const struct byt_simple_func_mux byt_score_spi_mux[] = {
-       SIMPLE_FUNC("spi", 1),
-};
 
 static const unsigned int byt_score_i2c5_pins[] = { 88, 89 };
 static const unsigned int byt_score_i2c6_pins[] = { 90, 91 };
@@ -348,50 +271,29 @@ static const unsigned int byt_score_i2c3_pins[] = { 84, 85 };
 static const unsigned int byt_score_i2c2_pins[] = { 82, 83 };
 static const unsigned int byt_score_i2c1_pins[] = { 80, 81 };
 static const unsigned int byt_score_i2c0_pins[] = { 78, 79 };
-static const struct byt_simple_func_mux byt_score_i2c_mux[] = {
-       SIMPLE_FUNC("i2c", 1),
-};
 
 static const unsigned int byt_score_ssp0_pins[] = { 8, 9, 10, 11 };
 static const unsigned int byt_score_ssp1_pins[] = { 12, 13, 14, 15 };
 static const unsigned int byt_score_ssp2_pins[] = { 62, 63, 64, 65 };
-static const struct byt_simple_func_mux byt_score_ssp_mux[] = {
-       SIMPLE_FUNC("ssp", 1),
-};
 
 static const unsigned int byt_score_sdcard_pins[] = {
        7, 33, 34, 35, 36, 37, 38, 39, 40, 41,
 };
-static const unsigned short byt_score_sdcard_mux_values[] = {
+static const unsigned int byt_score_sdcard_mux_values[] = {
        2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 };
-static const struct byt_mixed_func_mux byt_score_sdcard_mux[] = {
-       MIXED_FUNC("sdcard", byt_score_sdcard_mux_values),
-};
 
 static const unsigned int byt_score_sdio_pins[] = { 27, 28, 29, 30, 31, 32 };
-static const struct byt_simple_func_mux byt_score_sdio_mux[] = {
-       SIMPLE_FUNC("sdio", 1),
-};
 
 static const unsigned int byt_score_emmc_pins[] = {
        16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
 };
-static const struct byt_simple_func_mux byt_score_emmc_mux[] = {
-       SIMPLE_FUNC("emmc", 1),
-};
 
 static const unsigned int byt_score_ilb_lpc_pins[] = {
        42, 43, 44, 45, 46, 47, 48, 49, 50,
 };
-static const struct byt_simple_func_mux byt_score_lpc_mux[] = {
-       SIMPLE_FUNC("lpc", 1),
-};
 
 static const unsigned int byt_score_sata_pins[] = { 0, 1, 2 };
-static const struct byt_simple_func_mux byt_score_sata_mux[] = {
-       SIMPLE_FUNC("sata", 1),
-};
 
 static const unsigned int byt_score_plt_clk0_pins[] = { 96 };
 static const unsigned int byt_score_plt_clk1_pins[] = { 97 };
@@ -399,70 +301,37 @@ static const unsigned int byt_score_plt_clk2_pins[] = { 98 };
 static const unsigned int byt_score_plt_clk3_pins[] = { 99 };
 static const unsigned int byt_score_plt_clk4_pins[] = { 100 };
 static const unsigned int byt_score_plt_clk5_pins[] = { 101 };
-static const struct byt_simple_func_mux byt_score_plt_clk_mux[] = {
-       SIMPLE_FUNC("plt_clk", 1),
-};
 
 static const unsigned int byt_score_smbus_pins[] = { 51, 52, 53 };
-static const struct byt_simple_func_mux byt_score_smbus_mux[] = {
-       SIMPLE_FUNC("smbus", 1),
-};
 
-static const struct byt_pingroup byt_score_groups[] = {
-       PIN_GROUP_SIMPLE("uart1_grp",
-                        byt_score_uart1_pins, byt_score_uart_mux),
-       PIN_GROUP_SIMPLE("uart2_grp",
-                        byt_score_uart2_pins, byt_score_uart_mux),
-       PIN_GROUP_SIMPLE("pwm0_grp",
-                        byt_score_pwm0_pins, byt_score_pwm_mux),
-       PIN_GROUP_SIMPLE("pwm1_grp",
-                        byt_score_pwm1_pins, byt_score_pwm_mux),
-       PIN_GROUP_SIMPLE("ssp2_grp",
-                        byt_score_ssp2_pins, byt_score_pwm_mux),
-       PIN_GROUP_SIMPLE("sio_spi_grp",
-                        byt_score_sio_spi_pins, byt_score_spi_mux),
-       PIN_GROUP_SIMPLE("i2c5_grp",
-                        byt_score_i2c5_pins, byt_score_i2c_mux),
-       PIN_GROUP_SIMPLE("i2c6_grp",
-                        byt_score_i2c6_pins, byt_score_i2c_mux),
-       PIN_GROUP_SIMPLE("i2c4_grp",
-                        byt_score_i2c4_pins, byt_score_i2c_mux),
-       PIN_GROUP_SIMPLE("i2c3_grp",
-                        byt_score_i2c3_pins, byt_score_i2c_mux),
-       PIN_GROUP_SIMPLE("i2c2_grp",
-                        byt_score_i2c2_pins, byt_score_i2c_mux),
-       PIN_GROUP_SIMPLE("i2c1_grp",
-                        byt_score_i2c1_pins, byt_score_i2c_mux),
-       PIN_GROUP_SIMPLE("i2c0_grp",
-                        byt_score_i2c0_pins, byt_score_i2c_mux),
-       PIN_GROUP_SIMPLE("ssp0_grp",
-                        byt_score_ssp0_pins, byt_score_ssp_mux),
-       PIN_GROUP_SIMPLE("ssp1_grp",
-                        byt_score_ssp1_pins, byt_score_ssp_mux),
-       PIN_GROUP_MIXED("sdcard_grp",
-                       byt_score_sdcard_pins, byt_score_sdcard_mux),
-       PIN_GROUP_SIMPLE("sdio_grp",
-                        byt_score_sdio_pins, byt_score_sdio_mux),
-       PIN_GROUP_SIMPLE("emmc_grp",
-                        byt_score_emmc_pins, byt_score_emmc_mux),
-       PIN_GROUP_SIMPLE("lpc_grp",
-                        byt_score_ilb_lpc_pins, byt_score_lpc_mux),
-       PIN_GROUP_SIMPLE("sata_grp",
-                        byt_score_sata_pins, byt_score_sata_mux),
-       PIN_GROUP_SIMPLE("plt_clk0_grp",
-                        byt_score_plt_clk0_pins, byt_score_plt_clk_mux),
-       PIN_GROUP_SIMPLE("plt_clk1_grp",
-                        byt_score_plt_clk1_pins, byt_score_plt_clk_mux),
-       PIN_GROUP_SIMPLE("plt_clk2_grp",
-                        byt_score_plt_clk2_pins, byt_score_plt_clk_mux),
-       PIN_GROUP_SIMPLE("plt_clk3_grp",
-                        byt_score_plt_clk3_pins, byt_score_plt_clk_mux),
-       PIN_GROUP_SIMPLE("plt_clk4_grp",
-                        byt_score_plt_clk4_pins, byt_score_plt_clk_mux),
-       PIN_GROUP_SIMPLE("plt_clk5_grp",
-                        byt_score_plt_clk5_pins, byt_score_plt_clk_mux),
-       PIN_GROUP_SIMPLE("smbus_grp",
-                        byt_score_smbus_pins, byt_score_smbus_mux),
+static const struct intel_pingroup byt_score_groups[] = {
+       PIN_GROUP("uart1_grp", byt_score_uart1_pins, 1),
+       PIN_GROUP("uart2_grp", byt_score_uart2_pins, 1),
+       PIN_GROUP("pwm0_grp", byt_score_pwm0_pins, 1),
+       PIN_GROUP("pwm1_grp", byt_score_pwm1_pins, 1),
+       PIN_GROUP("ssp2_grp", byt_score_ssp2_pins, 1),
+       PIN_GROUP("sio_spi_grp", byt_score_sio_spi_pins, 1),
+       PIN_GROUP("i2c5_grp", byt_score_i2c5_pins, 1),
+       PIN_GROUP("i2c6_grp", byt_score_i2c6_pins, 1),
+       PIN_GROUP("i2c4_grp", byt_score_i2c4_pins, 1),
+       PIN_GROUP("i2c3_grp", byt_score_i2c3_pins, 1),
+       PIN_GROUP("i2c2_grp", byt_score_i2c2_pins, 1),
+       PIN_GROUP("i2c1_grp", byt_score_i2c1_pins, 1),
+       PIN_GROUP("i2c0_grp", byt_score_i2c0_pins, 1),
+       PIN_GROUP("ssp0_grp", byt_score_ssp0_pins, 1),
+       PIN_GROUP("ssp1_grp", byt_score_ssp1_pins, 1),
+       PIN_GROUP("sdcard_grp", byt_score_sdcard_pins, byt_score_sdcard_mux_values),
+       PIN_GROUP("sdio_grp", byt_score_sdio_pins, 1),
+       PIN_GROUP("emmc_grp", byt_score_emmc_pins, 1),
+       PIN_GROUP("lpc_grp", byt_score_ilb_lpc_pins, 1),
+       PIN_GROUP("sata_grp", byt_score_sata_pins, 1),
+       PIN_GROUP("plt_clk0_grp", byt_score_plt_clk0_pins, 1),
+       PIN_GROUP("plt_clk1_grp", byt_score_plt_clk1_pins, 1),
+       PIN_GROUP("plt_clk2_grp", byt_score_plt_clk2_pins, 1),
+       PIN_GROUP("plt_clk3_grp", byt_score_plt_clk3_pins, 1),
+       PIN_GROUP("plt_clk4_grp", byt_score_plt_clk4_pins, 1),
+       PIN_GROUP("plt_clk5_grp", byt_score_plt_clk5_pins, 1),
+       PIN_GROUP("smbus_grp", byt_score_smbus_pins, 1),
 };
 
 static const char * const byt_score_uart_groups[] = {
@@ -496,10 +365,9 @@ static const char * const byt_score_gpio_groups[] = {
        "sdcard_grp", "sdio_grp", "emmc_grp", "lpc_grp", "sata_grp",
        "plt_clk0_grp", "plt_clk1_grp", "plt_clk2_grp", "plt_clk3_grp",
        "plt_clk4_grp", "plt_clk5_grp", "smbus_grp",
-
 };
 
-static const struct byt_function byt_score_functions[] = {
+static const struct intel_function byt_score_functions[] = {
        FUNCTION("uart", byt_score_uart_groups),
        FUNCTION("pwm", byt_score_pwm_groups),
        FUNCTION("ssp", byt_score_ssp_groups),
@@ -588,38 +456,30 @@ static const unsigned int byt_sus_pins_map[BYT_NGPIO_SUS] = {
 };
 
 static const unsigned int byt_sus_usb_over_current_pins[] = { 19, 20 };
-static const struct byt_simple_func_mux byt_sus_usb_oc_mux[] = {
-       SIMPLE_FUNC("usb", 0),
-       SIMPLE_FUNC("gpio", 1),
-};
+static const unsigned int byt_sus_usb_over_current_mode_values[] = { 0, 0 };
+static const unsigned int byt_sus_usb_over_current_gpio_mode_values[] = { 1, 1 };
 
 static const unsigned int byt_sus_usb_ulpi_pins[] = {
        14, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
 };
-static const unsigned short byt_sus_usb_ulpi_mode_values[] = {
+static const unsigned int byt_sus_usb_ulpi_mode_values[] = {
        2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 };
-static const unsigned short byt_sus_usb_ulpi_gpio_mode_values[] = {
-       1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-static const struct byt_mixed_func_mux byt_sus_usb_ulpi_mux[] = {
-       MIXED_FUNC("usb", byt_sus_usb_ulpi_mode_values),
-       MIXED_FUNC("gpio", byt_sus_usb_ulpi_gpio_mode_values),
+static const unsigned int byt_sus_usb_ulpi_gpio_mode_values[] = {
+       1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 };
 
 static const unsigned int byt_sus_pcu_spi_pins[] = { 21 };
-static const struct byt_simple_func_mux byt_sus_pcu_spi_mux[] = {
-       SIMPLE_FUNC("spi", 0),
-       SIMPLE_FUNC("gpio", 1),
-};
+static const unsigned int byt_sus_pcu_spi_mode_values[] = { 0 };
+static const unsigned int byt_sus_pcu_spi_gpio_mode_values[] = { 1 };
 
-static const struct byt_pingroup byt_sus_groups[] = {
-       PIN_GROUP_SIMPLE("usb_oc_grp",
-                       byt_sus_usb_over_current_pins, byt_sus_usb_oc_mux),
-       PIN_GROUP_MIXED("usb_ulpi_grp",
-                       byt_sus_usb_ulpi_pins, byt_sus_usb_ulpi_mux),
-       PIN_GROUP_SIMPLE("pcu_spi_grp",
-                       byt_sus_pcu_spi_pins, byt_sus_pcu_spi_mux),
+static const struct intel_pingroup byt_sus_groups[] = {
+       PIN_GROUP("usb_oc_grp", byt_sus_usb_over_current_pins, byt_sus_usb_over_current_mode_values),
+       PIN_GROUP("usb_ulpi_grp", byt_sus_usb_ulpi_pins, byt_sus_usb_ulpi_mode_values),
+       PIN_GROUP("pcu_spi_grp", byt_sus_pcu_spi_pins, byt_sus_pcu_spi_mode_values),
+       PIN_GROUP("usb_oc_grp_gpio", byt_sus_usb_over_current_pins, byt_sus_usb_over_current_gpio_mode_values),
+       PIN_GROUP("usb_ulpi_grp_gpio", byt_sus_usb_ulpi_pins, byt_sus_usb_ulpi_gpio_mode_values),
+       PIN_GROUP("pcu_spi_grp_gpio", byt_sus_pcu_spi_pins, byt_sus_pcu_spi_gpio_mode_values),
 };
 
 static const char * const byt_sus_usb_groups[] = {
@@ -627,10 +487,10 @@ static const char * const byt_sus_usb_groups[] = {
 };
 static const char * const byt_sus_spi_groups[] = { "pcu_spi_grp" };
 static const char * const byt_sus_gpio_groups[] = {
-       "usb_oc_grp", "usb_ulpi_grp", "pcu_spi_grp",
+       "usb_oc_grp_gpio", "usb_ulpi_grp_gpio", "pcu_spi_grp_gpio",
 };
 
-static const struct byt_function byt_sus_functions[] = {
+static const struct intel_function byt_sus_functions[] = {
        FUNCTION("usb", byt_sus_usb_groups),
        FUNCTION("spi", byt_sus_spi_groups),
        FUNCTION("gpio", byt_sus_gpio_groups),
@@ -810,41 +670,9 @@ static int byt_get_function_groups(struct pinctrl_dev *pctldev,
        return 0;
 }
 
-static int byt_get_group_simple_mux(const struct byt_pingroup group,
-                                   const char *func_name,
-                                   unsigned short *func)
-{
-       int i;
-
-       for (i = 0; i < group.nfuncs; i++) {
-               if (!strcmp(group.simple_funcs[i].name, func_name)) {
-                       *func = group.simple_funcs[i].func;
-                       return 0;
-               }
-       }
-
-       return 1;
-}
-
-static int byt_get_group_mixed_mux(const struct byt_pingroup group,
-                                  const char *func_name,
-                                  const unsigned short **func)
-{
-       int i;
-
-       for (i = 0; i < group.nfuncs; i++) {
-               if (!strcmp(group.mixed_funcs[i].name, func_name)) {
-                       *func = group.mixed_funcs[i].func_values;
-                       return 0;
-               }
-       }
-
-       return 1;
-}
-
 static void byt_set_group_simple_mux(struct byt_gpio *vg,
-                                    const struct byt_pingroup group,
-                                    unsigned short func)
+                                    const struct intel_pingroup group,
+                                    unsigned int func)
 {
        unsigned long flags;
        int i;
@@ -873,8 +701,8 @@ static void byt_set_group_simple_mux(struct byt_gpio *vg,
 }
 
 static void byt_set_group_mixed_mux(struct byt_gpio *vg,
-                                   const struct byt_pingroup group,
-                                   const unsigned short *func)
+                                   const struct intel_pingroup group,
+                                   const unsigned int *func)
 {
        unsigned long flags;
        int i;
@@ -906,23 +734,15 @@ static int byt_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector,
                       unsigned int group_selector)
 {
        struct byt_gpio *vg = pinctrl_dev_get_drvdata(pctldev);
-       const struct byt_function func = vg->soc_data->functions[func_selector];
-       const struct byt_pingroup group = vg->soc_data->groups[group_selector];
-       const unsigned short *mixed_func;
-       unsigned short simple_func;
-       int ret = 1;
-
-       if (group.has_simple_funcs)
-               ret = byt_get_group_simple_mux(group, func.name, &simple_func);
-       else
-               ret = byt_get_group_mixed_mux(group, func.name, &mixed_func);
+       const struct intel_function func = vg->soc_data->functions[func_selector];
+       const struct intel_pingroup group = vg->soc_data->groups[group_selector];
 
-       if (ret)
+       if (group.modes)
+               byt_set_group_mixed_mux(vg, group, group.modes);
+       else if (!strcmp(func.name, "gpio"))
                byt_set_group_simple_mux(vg, group, BYT_DEFAULT_GPIO_MUX);
-       else if (group.has_simple_funcs)
-               byt_set_group_simple_mux(vg, group, simple_func);
        else
-               byt_set_group_mixed_mux(vg, group, mixed_func);
+               byt_set_group_simple_mux(vg, group, group.mode);
 
        return 0;
 }
@@ -932,14 +752,14 @@ static u32 byt_get_gpio_mux(struct byt_gpio *vg, unsigned int offset)
        /* SCORE pin 92-93 */
        if (!strcmp(vg->soc_data->uid, BYT_SCORE_ACPI_UID) &&
            offset >= 92 && offset <= 93)
-               return 1;
+               return BYT_ALTER_GPIO_MUX;
 
        /* SUS pin 11-21 */
        if (!strcmp(vg->soc_data->uid, BYT_SUS_ACPI_UID) &&
            offset >= 11 && offset <= 21)
-               return 1;
+               return BYT_ALTER_GPIO_MUX;
 
-       return 0;
+       return BYT_DEFAULT_GPIO_MUX;
 }
 
 static void byt_gpio_clear_triggering(struct byt_gpio *vg, unsigned int offset)
index 2c7409e..9a74d50 100644 (file)
@@ -583,6 +583,7 @@ static struct platform_driver mt8183_pinctrl_driver = {
        .driver = {
                .name = "mt8183-pinctrl",
                .of_match_table = mt8183_pinctrl_of_match,
+               .pm = &mtk_paris_pinctrl_pm_ops,
        },
        .probe = mt8183_pinctrl_probe,
 };
index d3b34e9..923264d 100644 (file)
@@ -926,3 +926,22 @@ int mtk_paris_pinctrl_probe(struct platform_device *pdev,
 
        return 0;
 }
+
+static int mtk_paris_pinctrl_suspend(struct device *device)
+{
+       struct mtk_pinctrl *pctl = dev_get_drvdata(device);
+
+       return mtk_eint_do_suspend(pctl->eint);
+}
+
+static int mtk_paris_pinctrl_resume(struct device *device)
+{
+       struct mtk_pinctrl *pctl = dev_get_drvdata(device);
+
+       return mtk_eint_do_resume(pctl->eint);
+}
+
+const struct dev_pm_ops mtk_paris_pinctrl_pm_ops = {
+       .suspend_noirq = mtk_paris_pinctrl_suspend,
+       .resume_noirq = mtk_paris_pinctrl_resume,
+};
index 37146ca..3d43771 100644 (file)
@@ -60,4 +60,6 @@
 int mtk_paris_pinctrl_probe(struct platform_device *pdev,
                            const struct mtk_pin_soc *soc);
 
+extern const struct dev_pm_ops mtk_paris_pinctrl_pm_ops;
+
 #endif /* __PINCTRL_PARIS_H */
index d494492..3475cd7 100644 (file)
@@ -1304,28 +1304,28 @@ static struct meson_pmx_func meson_g12a_aobus_functions[] = {
 };
 
 static struct meson_bank meson_g12a_periphs_banks[] = {
-       /* name  first  last  irq  pullen  pull  dir  out  in */
-       BANK("Z",    GPIOZ_0,    GPIOZ_15, 12, 27,
-            4,  0,  4,  0,  12,  0,  13, 0,  14, 0),
-       BANK("H",    GPIOH_0,    GPIOH_8, 28, 36,
-            3,  0,  3,  0,  9,  0,  10,  0,  11,  0),
-       BANK("BOOT", BOOT_0,     BOOT_15,  37, 52,
-            0,  0,  0,  0,  0, 0,  1, 0,  2, 0),
-       BANK("C",    GPIOC_0,    GPIOC_7,  53, 60,
-            1,  0,  1,  0,  3, 0,  4, 0,  5, 0),
-       BANK("A",    GPIOA_0,    GPIOA_15,  61, 76,
-            5,  0,  5,  0,  16,  0,  17,  0,  18,  0),
-       BANK("X",    GPIOX_0,    GPIOX_19,   77, 96,
-            2,  0,  2,  0,  6,  0,  7,  0,  8,  0),
+       /* name  first  last  irq  pullen  pull  dir  out  in  ds */
+       BANK_DS("Z",    GPIOZ_0,    GPIOZ_15, 12, 27,
+               4,  0,  4,  0,  12,  0,  13, 0,  14, 0, 5, 0),
+       BANK_DS("H",    GPIOH_0,    GPIOH_8, 28, 36,
+               3,  0,  3,  0,  9,  0,  10,  0,  11,  0, 4, 0),
+       BANK_DS("BOOT", BOOT_0,     BOOT_15,  37, 52,
+               0,  0,  0,  0,  0, 0,  1, 0,  2, 0, 0, 0),
+       BANK_DS("C",    GPIOC_0,    GPIOC_7,  53, 60,
+               1,  0,  1,  0,  3, 0,  4, 0,  5, 0, 1, 0),
+       BANK_DS("A",    GPIOA_0,    GPIOA_15,  61, 76,
+               5,  0,  5,  0,  16,  0,  17,  0,  18,  0, 6, 0),
+       BANK_DS("X",    GPIOX_0,    GPIOX_19,   77, 96,
+               2,  0,  2,  0,  6,  0,  7,  0,  8,  0, 2, 0),
 };
 
 static struct meson_bank meson_g12a_aobus_banks[] = {
-       /* name  first  last  irq  pullen  pull  dir  out  in  */
-       BANK("AO",   GPIOAO_0,  GPIOAO_11,  0, 11,
-            3,  0,  2, 0,  0,  0,  4, 0,  1,  0),
+       /* name  first  last  irq  pullen  pull  dir  out  in  ds */
+       BANK_DS("AO", GPIOAO_0, GPIOAO_11, 0, 11, 3, 0, 2, 0, 0, 0, 4, 0, 1, 0,
+               0, 0),
        /* GPIOE actually located in the AO bank */
-       BANK("E",   GPIOE_0,  GPIOE_2,   97, 99,
-            3,  16,  2, 16,  0,  16,  4, 16,  1,  16),
+       BANK_DS("E", GPIOE_0, GPIOE_2, 97, 99, 3, 16, 2, 16, 0, 16, 4, 16, 1,
+               16, 1, 0),
 };
 
 static struct meson_pmx_bank meson_g12a_periphs_pmx_banks[] = {
index 077de59..5967869 100644 (file)
@@ -168,68 +168,223 @@ int meson_pmx_get_groups(struct pinctrl_dev *pcdev, unsigned selector,
        return 0;
 }
 
-static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin,
-                            unsigned long *configs, unsigned num_configs)
+static int meson_pinconf_set_gpio_bit(struct meson_pinctrl *pc,
+                                     unsigned int pin,
+                                     unsigned int reg_type,
+                                     bool arg)
 {
-       struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
        struct meson_bank *bank;
-       enum pin_config_param param;
        unsigned int reg, bit;
-       int i, ret;
+       int ret;
+
+       ret = meson_get_bank(pc, pin, &bank);
+       if (ret)
+               return ret;
+
+       meson_calc_reg_and_bit(bank, pin, reg_type, &reg, &bit);
+       return regmap_update_bits(pc->reg_gpio, reg, BIT(bit),
+                                 arg ? BIT(bit) : 0);
+}
+
+static int meson_pinconf_get_gpio_bit(struct meson_pinctrl *pc,
+                                     unsigned int pin,
+                                     unsigned int reg_type)
+{
+       struct meson_bank *bank;
+       unsigned int reg, bit, val;
+       int ret;
 
        ret = meson_get_bank(pc, pin, &bank);
        if (ret)
                return ret;
 
+       meson_calc_reg_and_bit(bank, pin, reg_type, &reg, &bit);
+       ret = regmap_read(pc->reg_gpio, reg, &val);
+       if (ret)
+               return ret;
+
+       return BIT(bit) & val ? 1 : 0;
+}
+
+static int meson_pinconf_set_output(struct meson_pinctrl *pc,
+                                   unsigned int pin,
+                                   bool out)
+{
+       return meson_pinconf_set_gpio_bit(pc, pin, REG_DIR, !out);
+}
+
+static int meson_pinconf_get_output(struct meson_pinctrl *pc,
+                                   unsigned int pin)
+{
+       int ret = meson_pinconf_get_gpio_bit(pc, pin, REG_DIR);
+
+       if (ret < 0)
+               return ret;
+
+       return !ret;
+}
+
+static int meson_pinconf_set_drive(struct meson_pinctrl *pc,
+                                  unsigned int pin,
+                                  bool high)
+{
+       return meson_pinconf_set_gpio_bit(pc, pin, REG_OUT, high);
+}
+
+static int meson_pinconf_get_drive(struct meson_pinctrl *pc,
+                                  unsigned int pin)
+{
+       return meson_pinconf_get_gpio_bit(pc, pin, REG_OUT);
+}
+
+static int meson_pinconf_set_output_drive(struct meson_pinctrl *pc,
+                                         unsigned int pin,
+                                         bool high)
+{
+       int ret;
+
+       ret = meson_pinconf_set_output(pc, pin, true);
+       if (ret)
+               return ret;
+
+       return meson_pinconf_set_drive(pc, pin, high);
+}
+
+static int meson_pinconf_disable_bias(struct meson_pinctrl *pc,
+                                     unsigned int pin)
+{
+       struct meson_bank *bank;
+       unsigned int reg, bit = 0;
+       int ret;
+
+       ret = meson_get_bank(pc, pin, &bank);
+       if (ret)
+               return ret;
+
+       meson_calc_reg_and_bit(bank, pin, REG_PULLEN, &reg, &bit);
+       ret = regmap_update_bits(pc->reg_pullen, reg, BIT(bit), 0);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int meson_pinconf_enable_bias(struct meson_pinctrl *pc, unsigned int pin,
+                                    bool pull_up)
+{
+       struct meson_bank *bank;
+       unsigned int reg, bit, val = 0;
+       int ret;
+
+       ret = meson_get_bank(pc, pin, &bank);
+       if (ret)
+               return ret;
+
+       meson_calc_reg_and_bit(bank, pin, REG_PULL, &reg, &bit);
+       if (pull_up)
+               val = BIT(bit);
+
+       ret = regmap_update_bits(pc->reg_pull, reg, BIT(bit), val);
+       if (ret)
+               return ret;
+
+       meson_calc_reg_and_bit(bank, pin, REG_PULLEN, &reg, &bit);
+       ret = regmap_update_bits(pc->reg_pullen, reg, BIT(bit), BIT(bit));
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int meson_pinconf_set_drive_strength(struct meson_pinctrl *pc,
+                                           unsigned int pin,
+                                           u16 drive_strength_ua)
+{
+       struct meson_bank *bank;
+       unsigned int reg, bit, ds_val;
+       int ret;
+
+       if (!pc->reg_ds) {
+               dev_err(pc->dev, "drive-strength not supported\n");
+               return -ENOTSUPP;
+       }
+
+       ret = meson_get_bank(pc, pin, &bank);
+       if (ret)
+               return ret;
+
+       meson_calc_reg_and_bit(bank, pin, REG_DS, &reg, &bit);
+       bit = bit << 1;
+
+       if (drive_strength_ua <= 500) {
+               ds_val = MESON_PINCONF_DRV_500UA;
+       } else if (drive_strength_ua <= 2500) {
+               ds_val = MESON_PINCONF_DRV_2500UA;
+       } else if (drive_strength_ua <= 3000) {
+               ds_val = MESON_PINCONF_DRV_3000UA;
+       } else if (drive_strength_ua <= 4000) {
+               ds_val = MESON_PINCONF_DRV_4000UA;
+       } else {
+               dev_warn_once(pc->dev,
+                             "pin %u: invalid drive-strength : %d , default to 4mA\n",
+                             pin, drive_strength_ua);
+               ds_val = MESON_PINCONF_DRV_4000UA;
+       }
+
+       ret = regmap_update_bits(pc->reg_ds, reg, 0x3 << bit, ds_val << bit);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin,
+                            unsigned long *configs, unsigned num_configs)
+{
+       struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+       enum pin_config_param param;
+       unsigned int arg = 0;
+       int i, ret;
+
        for (i = 0; i < num_configs; i++) {
                param = pinconf_to_config_param(configs[i]);
 
+               switch (param) {
+               case PIN_CONFIG_DRIVE_STRENGTH_UA:
+               case PIN_CONFIG_OUTPUT_ENABLE:
+               case PIN_CONFIG_OUTPUT:
+                       arg = pinconf_to_config_argument(configs[i]);
+                       break;
+
+               default:
+                       break;
+               }
+
                switch (param) {
                case PIN_CONFIG_BIAS_DISABLE:
-                       dev_dbg(pc->dev, "pin %u: disable bias\n", pin);
-
-                       meson_calc_reg_and_bit(bank, pin, REG_PULLEN, &reg,
-                                              &bit);
-                       ret = regmap_update_bits(pc->reg_pullen, reg,
-                                                BIT(bit), 0);
-                       if (ret)
-                               return ret;
+                       ret = meson_pinconf_disable_bias(pc, pin);
                        break;
                case PIN_CONFIG_BIAS_PULL_UP:
-                       dev_dbg(pc->dev, "pin %u: enable pull-up\n", pin);
-
-                       meson_calc_reg_and_bit(bank, pin, REG_PULLEN,
-                                              &reg, &bit);
-                       ret = regmap_update_bits(pc->reg_pullen, reg,
-                                                BIT(bit), BIT(bit));
-                       if (ret)
-                               return ret;
-
-                       meson_calc_reg_and_bit(bank, pin, REG_PULL, &reg, &bit);
-                       ret = regmap_update_bits(pc->reg_pull, reg,
-                                                BIT(bit), BIT(bit));
-                       if (ret)
-                               return ret;
+                       ret = meson_pinconf_enable_bias(pc, pin, true);
                        break;
                case PIN_CONFIG_BIAS_PULL_DOWN:
-                       dev_dbg(pc->dev, "pin %u: enable pull-down\n", pin);
-
-                       meson_calc_reg_and_bit(bank, pin, REG_PULLEN,
-                                              &reg, &bit);
-                       ret = regmap_update_bits(pc->reg_pullen, reg,
-                                                BIT(bit), BIT(bit));
-                       if (ret)
-                               return ret;
-
-                       meson_calc_reg_and_bit(bank, pin, REG_PULL, &reg, &bit);
-                       ret = regmap_update_bits(pc->reg_pull, reg,
-                                                BIT(bit), 0);
-                       if (ret)
-                               return ret;
+                       ret = meson_pinconf_enable_bias(pc, pin, false);
+                       break;
+               case PIN_CONFIG_DRIVE_STRENGTH_UA:
+                       ret = meson_pinconf_set_drive_strength(pc, pin, arg);
+                       break;
+               case PIN_CONFIG_OUTPUT_ENABLE:
+                       ret = meson_pinconf_set_output(pc, pin, arg);
+                       break;
+               case PIN_CONFIG_OUTPUT:
+                       ret = meson_pinconf_set_output_drive(pc, pin, arg);
                        break;
                default:
-                       return -ENOTSUPP;
+                       ret = -ENOTSUPP;
                }
+
+               if (ret)
+                       return ret;
        }
 
        return 0;
@@ -269,12 +424,55 @@ static int meson_pinconf_get_pull(struct meson_pinctrl *pc, unsigned int pin)
        return conf;
 }
 
+static int meson_pinconf_get_drive_strength(struct meson_pinctrl *pc,
+                                           unsigned int pin,
+                                           u16 *drive_strength_ua)
+{
+       struct meson_bank *bank;
+       unsigned int reg, bit;
+       unsigned int val;
+       int ret;
+
+       if (!pc->reg_ds)
+               return -ENOTSUPP;
+
+       ret = meson_get_bank(pc, pin, &bank);
+       if (ret)
+               return ret;
+
+       meson_calc_reg_and_bit(bank, pin, REG_DS, &reg, &bit);
+
+       ret = regmap_read(pc->reg_ds, reg, &val);
+       if (ret)
+               return ret;
+
+       switch ((val >> bit) & 0x3) {
+       case MESON_PINCONF_DRV_500UA:
+               *drive_strength_ua = 500;
+               break;
+       case MESON_PINCONF_DRV_2500UA:
+               *drive_strength_ua = 2500;
+               break;
+       case MESON_PINCONF_DRV_3000UA:
+               *drive_strength_ua = 3000;
+               break;
+       case MESON_PINCONF_DRV_4000UA:
+               *drive_strength_ua = 4000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin,
                             unsigned long *config)
 {
        struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
        enum pin_config_param param = pinconf_to_config_param(*config);
        u16 arg;
+       int ret;
 
        switch (param) {
        case PIN_CONFIG_BIAS_DISABLE:
@@ -285,6 +483,29 @@ static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin,
                else
                        return -EINVAL;
                break;
+       case PIN_CONFIG_DRIVE_STRENGTH_UA:
+               ret = meson_pinconf_get_drive_strength(pc, pin, &arg);
+               if (ret)
+                       return ret;
+               break;
+       case PIN_CONFIG_OUTPUT_ENABLE:
+               ret = meson_pinconf_get_output(pc, pin);
+               if (ret <= 0)
+                       return -EINVAL;
+               arg = 1;
+               break;
+       case PIN_CONFIG_OUTPUT:
+               ret = meson_pinconf_get_output(pc, pin);
+               if (ret <= 0)
+                       return -EINVAL;
+
+               ret = meson_pinconf_get_drive(pc, pin);
+               if (ret < 0)
+                       return -EINVAL;
+
+               arg = ret;
+               break;
+
        default:
                return -ENOTSUPP;
        }
@@ -329,56 +550,19 @@ static const struct pinconf_ops meson_pinconf_ops = {
 
 static int meson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
 {
-       struct meson_pinctrl *pc = gpiochip_get_data(chip);
-       unsigned int reg, bit;
-       struct meson_bank *bank;
-       int ret;
-
-       ret = meson_get_bank(pc, gpio, &bank);
-       if (ret)
-               return ret;
-
-       meson_calc_reg_and_bit(bank, gpio, REG_DIR, &reg, &bit);
-
-       return regmap_update_bits(pc->reg_gpio, reg, BIT(bit), BIT(bit));
+       return meson_pinconf_set_output(gpiochip_get_data(chip), gpio, false);
 }
 
 static int meson_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
                                       int value)
 {
-       struct meson_pinctrl *pc = gpiochip_get_data(chip);
-       unsigned int reg, bit;
-       struct meson_bank *bank;
-       int ret;
-
-       ret = meson_get_bank(pc, gpio, &bank);
-       if (ret)
-               return ret;
-
-       meson_calc_reg_and_bit(bank, gpio, REG_DIR, &reg, &bit);
-       ret = regmap_update_bits(pc->reg_gpio, reg, BIT(bit), 0);
-       if (ret)
-               return ret;
-
-       meson_calc_reg_and_bit(bank, gpio, REG_OUT, &reg, &bit);
-       return regmap_update_bits(pc->reg_gpio, reg, BIT(bit),
-                                 value ? BIT(bit) : 0);
+       return meson_pinconf_set_output_drive(gpiochip_get_data(chip),
+                                             gpio, value);
 }
 
 static void meson_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
 {
-       struct meson_pinctrl *pc = gpiochip_get_data(chip);
-       unsigned int reg, bit;
-       struct meson_bank *bank;
-       int ret;
-
-       ret = meson_get_bank(pc, gpio, &bank);
-       if (ret)
-               return;
-
-       meson_calc_reg_and_bit(bank, gpio, REG_OUT, &reg, &bit);
-       regmap_update_bits(pc->reg_gpio, reg, BIT(bit),
-                          value ? BIT(bit) : 0);
+       meson_pinconf_set_drive(gpiochip_get_data(chip), gpio, value);
 }
 
 static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio)
index adab4ea..c696f32 100644 (file)
@@ -65,9 +65,20 @@ enum meson_reg_type {
        REG_DIR,
        REG_OUT,
        REG_IN,
+       REG_DS,
        NUM_REG,
 };
 
+/**
+ * enum meson_pinconf_drv - value of drive-strength supported
+ */
+enum meson_pinconf_drv {
+       MESON_PINCONF_DRV_500UA,
+       MESON_PINCONF_DRV_2500UA,
+       MESON_PINCONF_DRV_3000UA,
+       MESON_PINCONF_DRV_4000UA,
+};
+
 /**
  * struct meson bank
  *
@@ -126,7 +137,8 @@ struct meson_pinctrl {
                .num_groups = ARRAY_SIZE(fn ## _groups),                \
        }
 
-#define BANK(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib)        \
+#define BANK_DS(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib,     \
+               dsr, dsb)                                                      \
        {                                                               \
                .name           = n,                                    \
                .first          = f,                                    \
@@ -139,9 +151,13 @@ struct meson_pinctrl {
                        [REG_DIR]       = { dr, db },                   \
                        [REG_OUT]       = { or, ob },                   \
                        [REG_IN]        = { ir, ib },                   \
+                       [REG_DS]        = { dsr, dsb },                 \
                },                                                      \
         }
 
+#define BANK(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib) \
+       BANK_DS(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib, 0, 0)
+
 #define MESON_PIN(x) PINCTRL_PIN(x, #x)
 
 /* Common pmx functions */
index 19e6970..d45c31f 100644 (file)
 
 #include "pinctrl-mvebu.h"
 
-#define V(f6180, f6190, f6192, f6281, f6282, dx4122)   \
+#define V(f6180, f6190, f6192, f6281, f6282, dx4122, dx1135)   \
        ((f6180 << 0) | (f6190 << 1) | (f6192 << 2) |   \
-        (f6281 << 3) | (f6282 << 4) | (dx4122 << 5))
+        (f6281 << 3) | (f6282 << 4) | (dx4122 << 5) |  \
+        (dx1135 << 6))
 
 enum kirkwood_variant {
-       VARIANT_MV88F6180       = V(1, 0, 0, 0, 0, 0),
-       VARIANT_MV88F6190       = V(0, 1, 0, 0, 0, 0),
-       VARIANT_MV88F6192       = V(0, 0, 1, 0, 0, 0),
-       VARIANT_MV88F6281       = V(0, 0, 0, 1, 0, 0),
-       VARIANT_MV88F6282       = V(0, 0, 0, 0, 1, 0),
-       VARIANT_MV98DX4122      = V(0, 0, 0, 0, 0, 1),
+       VARIANT_MV88F6180       = V(1, 0, 0, 0, 0, 0, 0),
+       VARIANT_MV88F6190       = V(0, 1, 0, 0, 0, 0, 0),
+       VARIANT_MV88F6192       = V(0, 0, 1, 0, 0, 0, 0),
+       VARIANT_MV88F6281       = V(0, 0, 0, 1, 0, 0, 0),
+       VARIANT_MV88F6282       = V(0, 0, 0, 0, 1, 0, 0),
+       VARIANT_MV98DX4122      = V(0, 0, 0, 0, 0, 1, 0),
+       VARIANT_MV98DX1135      = V(0, 0, 0, 0, 0, 0, 1),
 };
 
 static struct mvebu_mpp_mode mv88f6xxx_mpp_modes[] = {
        MPP_MODE(0,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "nand", "io2",     V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x2, "spi", "cs",       V(1, 1, 1, 1, 1, 1))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "nand", "io2",     V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x2, "spi", "cs",       V(1, 1, 1, 1, 1, 1, 1))),
        MPP_MODE(1,
-               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "nand", "io3",     V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x2, "spi", "mosi",     V(1, 1, 1, 1, 1, 1))),
+               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "nand", "io3",     V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x2, "spi", "mosi",     V(1, 1, 1, 1, 1, 1, 1))),
        MPP_MODE(2,
-               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "nand", "io4",     V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x2, "spi", "sck",      V(1, 1, 1, 1, 1, 1))),
+               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "nand", "io4",     V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x2, "spi", "sck",      V(1, 1, 1, 1, 1, 1, 1))),
        MPP_MODE(3,
-               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "nand", "io5",     V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x2, "spi", "miso",     V(1, 1, 1, 1, 1, 1))),
+               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "nand", "io5",     V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x2, "spi", "miso",     V(1, 1, 1, 1, 1, 1, 1))),
        MPP_MODE(4,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "nand", "io6",     V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x2, "uart0", "rxd",    V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x5, "sata1", "act",    V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "hsync",    V(0, 0, 0, 0, 1, 0)),
-               MPP_VAR_FUNCTION(0xd, "ptp", "clk",      V(1, 1, 1, 1, 0, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "nand", "io6",     V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x2, "uart0", "rxd",    V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x5, "sata1", "act",    V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "hsync",    V(0, 0, 0, 0, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xd, "ptp", "clk",      V(1, 1, 1, 1, 0, 0, 0))),
        MPP_MODE(5,
-               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "nand", "io7",     V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x2, "uart0", "txd",    V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x4, "ptp", "trig",     V(1, 1, 1, 1, 0, 0)),
-               MPP_VAR_FUNCTION(0x5, "sata0", "act",    V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "vsync",    V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "nand", "io7",     V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x2, "uart0", "txd",    V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x4, "ptp", "trig",     V(1, 1, 1, 1, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x5, "sata0", "act",    V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "vsync",    V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(6,
-               MPP_VAR_FUNCTION(0x1, "sysrst", "out",   V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x2, "spi", "mosi",     V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x3, "ptp", "trig",     V(1, 1, 1, 1, 0, 0))),
+               MPP_VAR_FUNCTION(0x1, "sysrst", "out",   V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x2, "spi", "mosi",     V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x3, "ptp", "trig",     V(1, 1, 1, 1, 0, 0, 0))),
        MPP_MODE(7,
-               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "pex", "rsto",     V(1, 1, 1, 1, 0, 1)),
-               MPP_VAR_FUNCTION(0x2, "spi", "cs",       V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x3, "ptp", "trig",     V(1, 1, 1, 1, 0, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "pwm",      V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "pex", "rsto",     V(1, 1, 1, 1, 0, 1, 1)),
+               MPP_VAR_FUNCTION(0x2, "spi", "cs",       V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x3, "ptp", "trig",     V(1, 1, 1, 1, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "pwm",      V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(8,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "twsi0", "sda",    V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x2, "uart0", "rts",    V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x3, "uart1", "rts",    V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x4, "mii-1", "rxerr",  V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x5, "sata1", "prsnt",  V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xc, "ptp", "clk",      V(1, 1, 1, 1, 0, 0)),
-               MPP_VAR_FUNCTION(0xd, "mii", "col",      V(1, 1, 1, 1, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "twsi0", "sda",    V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x2, "uart0", "rts",    V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x3, "uart1", "rts",    V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x4, "mii-1", "rxerr",  V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x5, "sata1", "prsnt",  V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xc, "ptp", "clk",      V(1, 1, 1, 1, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0xd, "mii", "col",      V(1, 1, 1, 1, 1, 0, 0))),
        MPP_MODE(9,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "twsi0", "sck",    V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x2, "uart0", "cts",    V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x3, "uart1", "cts",    V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x5, "sata0", "prsnt",  V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xc, "ptp", "evreq",    V(1, 1, 1, 1, 0, 0)),
-               MPP_VAR_FUNCTION(0xd, "mii", "crs",      V(1, 1, 1, 1, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "twsi0", "sck",    V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x2, "uart0", "cts",    V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x3, "uart1", "cts",    V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x5, "sata0", "prsnt",  V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xc, "ptp", "evreq",    V(1, 1, 1, 1, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0xd, "mii", "crs",      V(1, 1, 1, 1, 1, 0, 0))),
        MPP_MODE(10,
-               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x2, "spi", "sck",      V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0X3, "uart0", "txd",    V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x5, "sata1", "act",    V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xc, "ptp", "trig",     V(1, 1, 1, 1, 0, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x2, "spi", "sck",      V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0X3, "uart0", "txd",    V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x5, "sata1", "act",    V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xc, "ptp", "trig",     V(1, 1, 1, 1, 0, 0, 0))),
        MPP_MODE(11,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x2, "spi", "miso",     V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x3, "uart0", "rxd",    V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x4, "ptp-1", "evreq",  V(1, 1, 1, 1, 0, 0)),
-               MPP_VAR_FUNCTION(0xc, "ptp-2", "trig",   V(1, 1, 1, 1, 0, 0)),
-               MPP_VAR_FUNCTION(0xd, "ptp", "clk",      V(1, 1, 1, 1, 0, 0)),
-               MPP_VAR_FUNCTION(0x5, "sata0", "act",    V(0, 1, 1, 1, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x2, "spi", "miso",     V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x3, "uart0", "rxd",    V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x4, "ptp-1", "evreq",  V(1, 1, 1, 1, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0xc, "ptp-2", "trig",   V(1, 1, 1, 1, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0xd, "ptp", "clk",      V(1, 1, 1, 1, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x5, "sata0", "act",    V(0, 1, 1, 1, 1, 0, 0))),
        MPP_MODE(12,
-               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 0, 1, 0)),
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 0, 0)),
-               MPP_VAR_FUNCTION(0x1, "sdio", "clk",     V(1, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xa, "audio", "spdifo", V(0, 0, 0, 0, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "spi", "mosi",     V(0, 0, 0, 0, 1, 0)),
-               MPP_VAR_FUNCTION(0xd, "twsi1", "sda",    V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 0, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x1, "sdio", "clk",     V(1, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xa, "audio", "spdifo", V(0, 0, 0, 0, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "spi", "mosi",     V(0, 0, 0, 0, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xd, "twsi1", "sda",    V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(13,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "sdio", "cmd",     V(1, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x3, "uart1", "txd",    V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0xa, "audio", "rmclk",  V(0, 0, 0, 0, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "pwm",      V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "sdio", "cmd",     V(1, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x3, "uart1", "txd",    V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0xa, "audio", "rmclk",  V(0, 0, 0, 0, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "pwm",      V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(14,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "sdio", "d0",      V(1, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x3, "uart1", "rxd",    V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x4, "sata1", "prsnt",  V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xa, "audio", "spdifi", V(0, 0, 0, 0, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "audio-1", "sdi",  V(0, 0, 0, 0, 1, 0)),
-               MPP_VAR_FUNCTION(0xd, "mii", "col",      V(1, 1, 1, 1, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "sdio", "d0",      V(1, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x3, "uart1", "rxd",    V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x4, "sata1", "prsnt",  V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xa, "audio", "spdifi", V(0, 0, 0, 0, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "audio-1", "sdi",  V(0, 0, 0, 0, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xd, "mii", "col",      V(1, 1, 1, 1, 1, 0, 0))),
        MPP_MODE(15,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "sdio", "d1",      V(1, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "uart0", "rts",    V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x3, "uart1", "txd",    V(1, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "sata0", "act",    V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "spi", "cs",       V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "sdio", "d1",      V(1, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "uart0", "rts",    V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x3, "uart1", "txd",    V(1, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "sata0", "act",    V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "spi", "cs",       V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(16,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "sdio", "d2",      V(1, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "uart0", "cts",    V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x3, "uart1", "rxd",    V(1, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "sata1", "act",    V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "extclk",   V(0, 0, 0, 0, 1, 0)),
-               MPP_VAR_FUNCTION(0xd, "mii", "crs",      V(1, 1, 1, 1, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "sdio", "d2",      V(1, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "uart0", "cts",    V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x3, "uart1", "rxd",    V(1, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "sata1", "act",    V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "extclk",   V(0, 0, 0, 0, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xd, "mii", "crs",      V(1, 1, 1, 1, 1, 0, 0))),
        MPP_MODE(17,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x1, "sdio", "d3",      V(1, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "sata0", "prsnt",  V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xa, "sata1", "act",    V(0, 0, 0, 0, 1, 0)),
-               MPP_VAR_FUNCTION(0xd, "twsi1", "sck",    V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x1, "sdio", "d3",      V(1, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "sata0", "prsnt",  V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xa, "sata1", "act",    V(0, 0, 0, 0, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xd, "twsi1", "sck",    V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(18,
-               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "nand", "io0",     V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x2, "pex", "clkreq",   V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "nand", "io0",     V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x2, "pex", "clkreq",   V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(19,
-               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "nand", "io1",     V(1, 1, 1, 1, 1, 1))),
+               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "nand", "io1",     V(1, 1, 1, 1, 1, 1, 1))),
        MPP_MODE(20,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp0",       V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql",    V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x3, "ge1", "txd0",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x5, "sata1", "act",    V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d0",       V(0, 0, 0, 0, 1, 0)),
-               MPP_VAR_FUNCTION(0xc, "mii", "rxerr",    V(0, 0, 0, 0, 0, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp0",       V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql",    V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x3, "ge1", "txd0",     V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x5, "sata1", "act",    V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d0",       V(0, 0, 0, 0, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xc, "mii", "rxerr",    V(0, 0, 0, 0, 0, 0, 0))),
        MPP_MODE(21,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp1",       V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql",    V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x3, "ge1", "txd1",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 0, 0, 0, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x5, "sata0", "act",    V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d1",       V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp1",       V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql",    V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x3, "ge1", "txd1",     V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x5, "sata0", "act",    V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d1",       V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(22,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp2",       V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql",    V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x3, "ge1", "txd2",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 0, 0, 0, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "rmclk",  V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x5, "sata1", "prsnt",  V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d2",       V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp2",       V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql",    V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x3, "ge1", "txd2",     V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "rmclk",  V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x5, "sata1", "prsnt",  V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d2",       V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(23,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp3",       V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql",    V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x3, "ge1", "txd3",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "rmclk",  V(0, 0, 0, 0, 0, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "bclk",   V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x5, "sata0", "prsnt",  V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d3",       V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp3",       V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql",    V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x3, "ge1", "txd3",     V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "rmclk",  V(0, 0, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "bclk",   V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x5, "sata0", "prsnt",  V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d3",       V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(24,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp4",       V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0",  V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x3, "ge1", "rxd0",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "bclk",   V(0, 0, 0, 0, 0, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "sdo",    V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d4",       V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp4",       V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0",  V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x3, "ge1", "rxd0",     V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "bclk",   V(0, 0, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "sdo",    V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d4",       V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(25,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp5",       V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck",  V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x3, "ge1", "rxd1",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "sdo",    V(0, 0, 0, 0, 0, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "lrclk",  V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d5",       V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp5",       V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck",  V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x3, "ge1", "rxd1",     V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "sdo",    V(0, 0, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "lrclk",  V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d5",       V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(26,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp6",       V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x3, "ge1", "rxd2",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "lrclk",  V(0, 0, 0, 0, 0, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "mclk",   V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d6",       V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp6",       V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x3, "ge1", "rxd2",     V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "lrclk",  V(0, 0, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "mclk",   V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d6",       V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(27,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp7",       V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x3, "ge1", "rxd3",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "mclk",   V(0, 0, 0, 0, 0, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "sdi",    V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d7",       V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp7",       V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x3, "ge1", "rxd3",     V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "mclk",   V(0, 0, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "sdi",    V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d7",       V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(28,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp8",       V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "int",      V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x3, "ge1", "col",      V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "sdi",    V(0, 0, 0, 0, 0, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d8",       V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp8",       V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "int",      V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x3, "ge1", "col",      V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "sdi",    V(0, 0, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d8",       V(0, 0, 0, 0, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x1, "nand", "ren",     V(0, 0, 0, 0, 0, 0, 1))),
        MPP_MODE(29,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp9",       V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "rst",      V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x3, "ge1", "txclk",    V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 0, 0, 0, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d9",       V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp9",       V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "rst",      V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x3, "ge1", "txclk",    V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d9",       V(0, 0, 0, 0, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x1, "nand", "wen",     V(0, 0, 0, 0, 0, 0, 1))),
        MPP_MODE(30,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp10",      V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "pclk",     V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x3, "ge1", "rxctl",    V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d10",      V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp10",      V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "pclk",     V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x3, "ge1", "rxctl",    V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d10",      V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(31,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp11",      V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "fs",       V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x3, "ge1", "rxclk",    V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d11",      V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp11",      V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "fs",       V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x3, "ge1", "rxclk",    V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d11",      V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(32,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp12",      V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "drx",      V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x3, "ge1", "txclko",   V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d12",      V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp12",      V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "drx",      V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x3, "ge1", "txclko",   V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d12",      V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(33,
-               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "dtx",      V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x3, "ge1", "txctl",    V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d13",      V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(0, 1, 1, 1, 1, 0, 1)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "dtx",      V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x3, "ge1", "txctl",    V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d13",      V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(34,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1",  V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x3, "ge1", "txen",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x5, "sata1", "act",    V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d14",      V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1",  V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x3, "ge1", "txen",     V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x5, "sata1", "act",    V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d14",      V(0, 0, 0, 0, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x1, "nand", "ale",     V(0, 0, 0, 0, 0, 0, 1))),
        MPP_MODE(35,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql",    V(0, 0, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x3, "ge1", "rxerr",    V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x5, "sata0", "act",    V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d15",      V(0, 0, 0, 0, 1, 0)),
-               MPP_VAR_FUNCTION(0xc, "mii", "rxerr",    V(1, 1, 1, 1, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql",    V(0, 0, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x3, "ge1", "rxerr",    V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x5, "sata0", "act",    V(0, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d15",      V(0, 0, 0, 0, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xc, "mii", "rxerr",    V(1, 1, 1, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x1, "nand", "cen",     V(0, 0, 0, 0, 0, 0, 1))),
        MPP_MODE(36,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp0",       V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1",  V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(1, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "twsi1", "sda",    V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp0",       V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1",  V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(1, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "twsi1", "sda",    V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(37,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp1",       V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql",    V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(1, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "twsi1", "sck",    V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp1",       V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql",    V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(1, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "twsi1", "sck",    V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(38,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp2",       V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql",    V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "rmclk",  V(1, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d18",      V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp2",       V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql",    V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "rmclk",  V(1, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d18",      V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(39,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp3",       V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0",  V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "bclk",   V(1, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d19",      V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp3",       V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0",  V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "bclk",   V(1, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d19",      V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(40,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp4",       V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck",  V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "sdo",    V(1, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d20",      V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp4",       V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck",  V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "sdo",    V(1, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d20",      V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(41,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp5",       V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "lrclk",  V(1, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d21",      V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp5",       V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "lrclk",  V(1, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d21",      V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(42,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp6",       V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "mclk",   V(1, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d22",      V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp6",       V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "mclk",   V(1, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d22",      V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(43,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp7",       V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "int",      V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "sdi",    V(1, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d23",      V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp7",       V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "int",      V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "sdi",    V(1, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d23",      V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(44,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp8",       V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "rst",      V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(1, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "clk",      V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp8",       V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "rst",      V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(1, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "clk",      V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(45,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp9",       V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "pclk",     V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "e",        V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp9",       V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "pclk",     V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "e",        V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(46,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp10",      V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "fs",       V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "hsync",    V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp10",      V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "fs",       V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "hsync",    V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(47,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp11",      V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "drx",      V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "vsync",    V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp11",      V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "drx",      V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "vsync",    V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(48,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp12",      V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "dtx",      V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d16",      V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp12",      V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "dtx",      V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d16",      V(0, 0, 0, 0, 1, 0, 0))),
        MPP_MODE(49,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 0, 1)),
-               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(0, 0, 0, 0, 1, 0)),
-               MPP_VAR_FUNCTION(0x1, "ts", "mp9",       V(0, 0, 0, 1, 0, 0)),
-               MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql",    V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x5, "ptp", "clk",      V(0, 0, 0, 1, 0, 0)),
-               MPP_VAR_FUNCTION(0xa, "pex", "clkreq",   V(0, 0, 0, 0, 1, 0)),
-               MPP_VAR_FUNCTION(0xb, "lcd", "d17",      V(0, 0, 0, 0, 1, 0))),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 0, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(0, 0, 0, 0, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x1, "ts", "mp9",       V(0, 0, 0, 1, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql",    V(0, 0, 0, 1, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0x5, "ptp", "clk",      V(0, 0, 0, 1, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0xa, "pex", "clkreq",   V(0, 0, 0, 0, 1, 0, 0)),
+               MPP_VAR_FUNCTION(0xb, "lcd", "d17",      V(0, 0, 0, 0, 1, 0, 0))),
 };
 
 static const struct mvebu_mpp_ctrl mv88f6180_mpp_controls[] = {
@@ -440,6 +446,17 @@ static struct mvebu_pinctrl_soc_info mv98dx4122_info = {
        .ngpioranges = ARRAY_SIZE(mv88f628x_gpio_ranges),
 };
 
+static struct mvebu_pinctrl_soc_info mv98dx1135_info = {
+       .variant = VARIANT_MV98DX1135,
+       .controls = mv88f628x_mpp_controls,
+       .ncontrols = ARRAY_SIZE(mv88f628x_mpp_controls),
+       .modes = mv88f6xxx_mpp_modes,
+       .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes),
+       .gpioranges = mv88f628x_gpio_ranges,
+       .ngpioranges = ARRAY_SIZE(mv88f628x_gpio_ranges),
+};
+
+
 static const struct of_device_id kirkwood_pinctrl_of_match[] = {
        { .compatible = "marvell,88f6180-pinctrl", .data = &mv88f6180_info },
        { .compatible = "marvell,88f6190-pinctrl", .data = &mv88f6190_info },
@@ -447,6 +464,7 @@ static const struct of_device_id kirkwood_pinctrl_of_match[] = {
        { .compatible = "marvell,88f6281-pinctrl", .data = &mv88f6281_info },
        { .compatible = "marvell,88f6282-pinctrl", .data = &mv88f6282_info },
        { .compatible = "marvell,98dx4122-pinctrl", .data = &mv98dx4122_info },
+       { .compatible = "marvell,98dx1135-pinctrl", .data = &mv98dx1135_info },
        { }
 };
 
index 4ccd71b..9eb8630 100644 (file)
@@ -38,6 +38,7 @@ static const struct pin_config_item conf_items[] = {
        PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL, false),
        PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL, false),
        PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA", true),
+       PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH_UA, "output drive strength", "uA", true),
        PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec", true),
        PCONFDUMP(PIN_CONFIG_INPUT_ENABLE, "input enabled", NULL, false),
        PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL, false),
@@ -166,6 +167,7 @@ static const struct pinconf_generic_params dt_params[] = {
        { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 },
        { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 },
        { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
+       { "drive-strength-microamp", PIN_CONFIG_DRIVE_STRENGTH_UA, 0 },
        { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 },
        { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
        { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
index 446b07d..63b130c 100644 (file)
@@ -27,6 +27,7 @@
  * @ngroups:   Number of @groups
  * @funcs:     Pinmux functions
  * @nfuncs:    Number of @funcs
+ * @pconf:     Pinconf data
  */
 struct bm1880_pinctrl {
        void __iomem *base;
@@ -35,6 +36,7 @@ struct bm1880_pinctrl {
        unsigned int ngroups;
        const struct bm1880_pinmux_function *funcs;
        unsigned int nfuncs;
+       const struct bm1880_pinconf_data *pinconf;
 };
 
 /**
@@ -55,7 +57,6 @@ struct bm1880_pctrl_group {
  * @groups:    List of pingroups for this function.
  * @ngroups:   Number of entries in @groups.
  * @mux_val:   Selector for this function
- * @mux_mask:   Mask for function specific selector
  * @mux:       Offset of function specific mux
  * @mux_shift: Shift for function specific selector
  */
@@ -64,11 +65,18 @@ struct bm1880_pinmux_function {
        const char * const *groups;
        unsigned int ngroups;
        u32 mux_val;
-       u32 mux_mask;
        u32 mux;
        u8 mux_shift;
 };
 
+/**
+ * struct bm1880_pinconf_data - pinconf data
+ * @drv_bits:  Drive strength bit width
+ */
+struct bm1880_pinconf_data {
+       u32 drv_bits;
+};
+
 static const struct pinctrl_pin_desc bm1880_pins[] = {
        PINCTRL_PIN(0,   "MIO0"),
        PINCTRL_PIN(1,   "MIO1"),
@@ -636,165 +644,273 @@ static const char * const i2s1_group[] = { "i2s1_grp" };
 static const char * const i2s1_mclkin_group[] = { "i2s1_mclkin_grp" };
 static const char * const spi0_group[] = { "spi0_grp" };
 
-#define BM1880_PINMUX_FUNCTION(fname, mval, mask)      \
+#define BM1880_PINMUX_FUNCTION(fname, mval)            \
        [F_##fname] = {                                 \
                .name = #fname,                         \
                .groups = fname##_group,                \
                .ngroups = ARRAY_SIZE(fname##_group),   \
                .mux_val = mval,                        \
-               .mux_mask = mask,                       \
        }
 
-#define BM1880_PINMUX_FUNCTION_MUX(fname, mval, mask, offset, shift)\
-       [F_##fname] = {                                 \
-               .name = #fname,                         \
-               .groups = fname##_group,                \
-               .ngroups = ARRAY_SIZE(fname##_group),   \
-               .mux_val = mval,                        \
-               .mux_mask = mask,                       \
-               .mux = offset,                          \
-               .mux_shift = shift,                     \
+static const struct bm1880_pinmux_function bm1880_pmux_functions[] = {
+       BM1880_PINMUX_FUNCTION(nand, 2),
+       BM1880_PINMUX_FUNCTION(spi, 0),
+       BM1880_PINMUX_FUNCTION(emmc, 1),
+       BM1880_PINMUX_FUNCTION(sdio, 0),
+       BM1880_PINMUX_FUNCTION(eth0, 0),
+       BM1880_PINMUX_FUNCTION(pwm0, 2),
+       BM1880_PINMUX_FUNCTION(pwm1, 2),
+       BM1880_PINMUX_FUNCTION(pwm2, 2),
+       BM1880_PINMUX_FUNCTION(pwm3, 2),
+       BM1880_PINMUX_FUNCTION(pwm4, 2),
+       BM1880_PINMUX_FUNCTION(pwm5, 2),
+       BM1880_PINMUX_FUNCTION(pwm6, 2),
+       BM1880_PINMUX_FUNCTION(pwm7, 2),
+       BM1880_PINMUX_FUNCTION(pwm8, 2),
+       BM1880_PINMUX_FUNCTION(pwm9, 2),
+       BM1880_PINMUX_FUNCTION(pwm10, 2),
+       BM1880_PINMUX_FUNCTION(pwm11, 2),
+       BM1880_PINMUX_FUNCTION(pwm12, 2),
+       BM1880_PINMUX_FUNCTION(pwm13, 2),
+       BM1880_PINMUX_FUNCTION(pwm14, 2),
+       BM1880_PINMUX_FUNCTION(pwm15, 2),
+       BM1880_PINMUX_FUNCTION(pwm16, 2),
+       BM1880_PINMUX_FUNCTION(pwm17, 2),
+       BM1880_PINMUX_FUNCTION(pwm18, 2),
+       BM1880_PINMUX_FUNCTION(pwm19, 2),
+       BM1880_PINMUX_FUNCTION(pwm20, 2),
+       BM1880_PINMUX_FUNCTION(pwm21, 2),
+       BM1880_PINMUX_FUNCTION(pwm22, 2),
+       BM1880_PINMUX_FUNCTION(pwm23, 2),
+       BM1880_PINMUX_FUNCTION(pwm24, 2),
+       BM1880_PINMUX_FUNCTION(pwm25, 2),
+       BM1880_PINMUX_FUNCTION(pwm26, 2),
+       BM1880_PINMUX_FUNCTION(pwm27, 2),
+       BM1880_PINMUX_FUNCTION(pwm28, 2),
+       BM1880_PINMUX_FUNCTION(pwm29, 2),
+       BM1880_PINMUX_FUNCTION(pwm30, 2),
+       BM1880_PINMUX_FUNCTION(pwm31, 2),
+       BM1880_PINMUX_FUNCTION(pwm32, 2),
+       BM1880_PINMUX_FUNCTION(pwm33, 2),
+       BM1880_PINMUX_FUNCTION(pwm34, 2),
+       BM1880_PINMUX_FUNCTION(pwm35, 2),
+       BM1880_PINMUX_FUNCTION(pwm36, 2),
+       BM1880_PINMUX_FUNCTION(pwm37, 2),
+       BM1880_PINMUX_FUNCTION(i2c0, 1),
+       BM1880_PINMUX_FUNCTION(i2c1, 1),
+       BM1880_PINMUX_FUNCTION(i2c2, 1),
+       BM1880_PINMUX_FUNCTION(i2c3, 1),
+       BM1880_PINMUX_FUNCTION(i2c4, 1),
+       BM1880_PINMUX_FUNCTION(uart0, 3),
+       BM1880_PINMUX_FUNCTION(uart1, 3),
+       BM1880_PINMUX_FUNCTION(uart2, 3),
+       BM1880_PINMUX_FUNCTION(uart3, 3),
+       BM1880_PINMUX_FUNCTION(uart4, 1),
+       BM1880_PINMUX_FUNCTION(uart5, 1),
+       BM1880_PINMUX_FUNCTION(uart6, 1),
+       BM1880_PINMUX_FUNCTION(uart7, 1),
+       BM1880_PINMUX_FUNCTION(uart8, 1),
+       BM1880_PINMUX_FUNCTION(uart9, 1),
+       BM1880_PINMUX_FUNCTION(uart10, 1),
+       BM1880_PINMUX_FUNCTION(uart11, 1),
+       BM1880_PINMUX_FUNCTION(uart12, 3),
+       BM1880_PINMUX_FUNCTION(uart13, 3),
+       BM1880_PINMUX_FUNCTION(uart14, 3),
+       BM1880_PINMUX_FUNCTION(uart15, 3),
+       BM1880_PINMUX_FUNCTION(gpio0, 0),
+       BM1880_PINMUX_FUNCTION(gpio1, 0),
+       BM1880_PINMUX_FUNCTION(gpio2, 0),
+       BM1880_PINMUX_FUNCTION(gpio3, 0),
+       BM1880_PINMUX_FUNCTION(gpio4, 0),
+       BM1880_PINMUX_FUNCTION(gpio5, 0),
+       BM1880_PINMUX_FUNCTION(gpio6, 0),
+       BM1880_PINMUX_FUNCTION(gpio7, 0),
+       BM1880_PINMUX_FUNCTION(gpio8, 0),
+       BM1880_PINMUX_FUNCTION(gpio9, 0),
+       BM1880_PINMUX_FUNCTION(gpio10, 0),
+       BM1880_PINMUX_FUNCTION(gpio11, 0),
+       BM1880_PINMUX_FUNCTION(gpio12, 1),
+       BM1880_PINMUX_FUNCTION(gpio13, 1),
+       BM1880_PINMUX_FUNCTION(gpio14, 0),
+       BM1880_PINMUX_FUNCTION(gpio15, 0),
+       BM1880_PINMUX_FUNCTION(gpio16, 0),
+       BM1880_PINMUX_FUNCTION(gpio17, 0),
+       BM1880_PINMUX_FUNCTION(gpio18, 0),
+       BM1880_PINMUX_FUNCTION(gpio19, 0),
+       BM1880_PINMUX_FUNCTION(gpio20, 0),
+       BM1880_PINMUX_FUNCTION(gpio21, 0),
+       BM1880_PINMUX_FUNCTION(gpio22, 0),
+       BM1880_PINMUX_FUNCTION(gpio23, 0),
+       BM1880_PINMUX_FUNCTION(gpio24, 0),
+       BM1880_PINMUX_FUNCTION(gpio25, 0),
+       BM1880_PINMUX_FUNCTION(gpio26, 0),
+       BM1880_PINMUX_FUNCTION(gpio27, 0),
+       BM1880_PINMUX_FUNCTION(gpio28, 0),
+       BM1880_PINMUX_FUNCTION(gpio29, 0),
+       BM1880_PINMUX_FUNCTION(gpio30, 0),
+       BM1880_PINMUX_FUNCTION(gpio31, 0),
+       BM1880_PINMUX_FUNCTION(gpio32, 0),
+       BM1880_PINMUX_FUNCTION(gpio33, 0),
+       BM1880_PINMUX_FUNCTION(gpio34, 0),
+       BM1880_PINMUX_FUNCTION(gpio35, 0),
+       BM1880_PINMUX_FUNCTION(gpio36, 0),
+       BM1880_PINMUX_FUNCTION(gpio37, 0),
+       BM1880_PINMUX_FUNCTION(gpio38, 0),
+       BM1880_PINMUX_FUNCTION(gpio39, 0),
+       BM1880_PINMUX_FUNCTION(gpio40, 0),
+       BM1880_PINMUX_FUNCTION(gpio41, 0),
+       BM1880_PINMUX_FUNCTION(gpio42, 0),
+       BM1880_PINMUX_FUNCTION(gpio43, 0),
+       BM1880_PINMUX_FUNCTION(gpio44, 0),
+       BM1880_PINMUX_FUNCTION(gpio45, 0),
+       BM1880_PINMUX_FUNCTION(gpio46, 0),
+       BM1880_PINMUX_FUNCTION(gpio47, 0),
+       BM1880_PINMUX_FUNCTION(gpio48, 0),
+       BM1880_PINMUX_FUNCTION(gpio49, 0),
+       BM1880_PINMUX_FUNCTION(gpio50, 0),
+       BM1880_PINMUX_FUNCTION(gpio51, 0),
+       BM1880_PINMUX_FUNCTION(gpio52, 0),
+       BM1880_PINMUX_FUNCTION(gpio53, 0),
+       BM1880_PINMUX_FUNCTION(gpio54, 0),
+       BM1880_PINMUX_FUNCTION(gpio55, 0),
+       BM1880_PINMUX_FUNCTION(gpio56, 0),
+       BM1880_PINMUX_FUNCTION(gpio57, 0),
+       BM1880_PINMUX_FUNCTION(gpio58, 0),
+       BM1880_PINMUX_FUNCTION(gpio59, 0),
+       BM1880_PINMUX_FUNCTION(gpio60, 0),
+       BM1880_PINMUX_FUNCTION(gpio61, 0),
+       BM1880_PINMUX_FUNCTION(gpio62, 0),
+       BM1880_PINMUX_FUNCTION(gpio63, 0),
+       BM1880_PINMUX_FUNCTION(gpio64, 0),
+       BM1880_PINMUX_FUNCTION(gpio65, 0),
+       BM1880_PINMUX_FUNCTION(gpio66, 0),
+       BM1880_PINMUX_FUNCTION(gpio67, 0),
+       BM1880_PINMUX_FUNCTION(eth1, 1),
+       BM1880_PINMUX_FUNCTION(i2s0, 2),
+       BM1880_PINMUX_FUNCTION(i2s0_mclkin, 1),
+       BM1880_PINMUX_FUNCTION(i2s1, 2),
+       BM1880_PINMUX_FUNCTION(i2s1_mclkin, 1),
+       BM1880_PINMUX_FUNCTION(spi0, 1),
+};
+
+#define BM1880_PINCONF_DAT(_width)             \
+       {                                       \
+               .drv_bits = _width,             \
        }
 
-static const struct bm1880_pinmux_function bm1880_pmux_functions[] = {
-       BM1880_PINMUX_FUNCTION(nand, 2, 0x03),
-       BM1880_PINMUX_FUNCTION(spi, 0, 0x03),
-       BM1880_PINMUX_FUNCTION(emmc, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(sdio, 0, 0x03),
-       BM1880_PINMUX_FUNCTION(eth0, 0, 0x03),
-       BM1880_PINMUX_FUNCTION_MUX(pwm0, 2, 0x0F, 0x50, 0x00),
-       BM1880_PINMUX_FUNCTION_MUX(pwm1, 2, 0x0F, 0x50, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(pwm2, 2, 0x0F, 0x50, 0x08),
-       BM1880_PINMUX_FUNCTION_MUX(pwm3, 2, 0x0F, 0x50, 0x0C),
-       BM1880_PINMUX_FUNCTION_MUX(pwm4, 2, 0x0F, 0x50, 0x10),
-       BM1880_PINMUX_FUNCTION_MUX(pwm5, 2, 0x0F, 0x50, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(pwm6, 2, 0x0F, 0x50, 0x18),
-       BM1880_PINMUX_FUNCTION_MUX(pwm7, 2, 0x0F, 0x50, 0x1C),
-       BM1880_PINMUX_FUNCTION_MUX(pwm8, 2, 0x0F, 0x54, 0x00),
-       BM1880_PINMUX_FUNCTION_MUX(pwm9, 2, 0x0F, 0x54, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(pwm10, 2, 0x0F, 0x54, 0x08),
-       BM1880_PINMUX_FUNCTION_MUX(pwm11, 2, 0x0F, 0x54, 0x0C),
-       BM1880_PINMUX_FUNCTION_MUX(pwm12, 2, 0x0F, 0x54, 0x10),
-       BM1880_PINMUX_FUNCTION_MUX(pwm13, 2, 0x0F, 0x54, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(pwm14, 2, 0x0F, 0x54, 0x18),
-       BM1880_PINMUX_FUNCTION_MUX(pwm15, 2, 0x0F, 0x54, 0x1C),
-       BM1880_PINMUX_FUNCTION_MUX(pwm16, 2, 0x0F, 0x58, 0x00),
-       BM1880_PINMUX_FUNCTION_MUX(pwm17, 2, 0x0F, 0x58, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(pwm18, 2, 0x0F, 0x58, 0x08),
-       BM1880_PINMUX_FUNCTION_MUX(pwm19, 2, 0x0F, 0x58, 0x0C),
-       BM1880_PINMUX_FUNCTION_MUX(pwm20, 2, 0x0F, 0x58, 0x10),
-       BM1880_PINMUX_FUNCTION_MUX(pwm21, 2, 0x0F, 0x58, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(pwm22, 2, 0x0F, 0x58, 0x18),
-       BM1880_PINMUX_FUNCTION_MUX(pwm23, 2, 0x0F, 0x58, 0x1C),
-       BM1880_PINMUX_FUNCTION_MUX(pwm24, 2, 0x0F, 0x5C, 0x00),
-       BM1880_PINMUX_FUNCTION_MUX(pwm25, 2, 0x0F, 0x5C, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(pwm26, 2, 0x0F, 0x5C, 0x08),
-       BM1880_PINMUX_FUNCTION_MUX(pwm27, 2, 0x0F, 0x5C, 0x0C),
-       BM1880_PINMUX_FUNCTION_MUX(pwm28, 2, 0x0F, 0x5C, 0x10),
-       BM1880_PINMUX_FUNCTION_MUX(pwm29, 2, 0x0F, 0x5C, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(pwm30, 2, 0x0F, 0x5C, 0x18),
-       BM1880_PINMUX_FUNCTION_MUX(pwm31, 2, 0x0F, 0x5C, 0x1C),
-       BM1880_PINMUX_FUNCTION_MUX(pwm32, 2, 0x0F, 0x60, 0x00),
-       BM1880_PINMUX_FUNCTION_MUX(pwm33, 2, 0x0F, 0x60, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(pwm34, 2, 0x0F, 0x60, 0x08),
-       BM1880_PINMUX_FUNCTION_MUX(pwm35, 2, 0x0F, 0x60, 0x0C),
-       BM1880_PINMUX_FUNCTION_MUX(pwm36, 2, 0x0F, 0x60, 0x10),
-       BM1880_PINMUX_FUNCTION_MUX(pwm37, 2, 0x0F, 0x60, 0x1C),
-       BM1880_PINMUX_FUNCTION(i2c0, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(i2c1, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(i2c2, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(i2c3, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(i2c4, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(uart0, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(uart1, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(uart2, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(uart3, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(uart4, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(uart5, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(uart6, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(uart7, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(uart8, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(uart9, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(uart10, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(uart11, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(uart12, 3, 0x03),
-       BM1880_PINMUX_FUNCTION(uart13, 3, 0x03),
-       BM1880_PINMUX_FUNCTION(uart14, 3, 0x03),
-       BM1880_PINMUX_FUNCTION(uart15, 3, 0x03),
-       BM1880_PINMUX_FUNCTION_MUX(gpio0, 0, 0x03, 0x4E0, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio1, 0, 0x03, 0x4E4, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio2, 0, 0x03, 0x4E4, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio3, 0, 0x03, 0x4E8, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio4, 0, 0x03, 0x4E8, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio5, 0, 0x03, 0x4EC, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio6, 0, 0x03, 0x4EC, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio7, 0, 0x03, 0x4F0, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio8, 0, 0x03, 0x4F0, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio9, 0, 0x03, 0x4F4, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio10, 0, 0x03, 0x4F4, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio11, 0, 0x03, 0x4F8, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio12, 1, 0x03, 0x4F8, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio13, 1, 0x03, 0x4FC, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio14, 0, 0x03, 0x474, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio15, 0, 0x03, 0x478, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio16, 0, 0x03, 0x478, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio17, 0, 0x03, 0x47C, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio18, 0, 0x03, 0x47C, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio19, 0, 0x03, 0x480, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio20, 0, 0x03, 0x480, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio21, 0, 0x03, 0x484, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio22, 0, 0x03, 0x484, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio23, 0, 0x03, 0x488, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio24, 0, 0x03, 0x488, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio25, 0, 0x03, 0x48C, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio26, 0, 0x03, 0x48C, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio27, 0, 0x03, 0x490, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio28, 0, 0x03, 0x490, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio29, 0, 0x03, 0x494, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio30, 0, 0x03, 0x494, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio31, 0, 0x03, 0x498, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio32, 0, 0x03, 0x498, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio33, 0, 0x03, 0x49C, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio34, 0, 0x03, 0x49C, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio35, 0, 0x03, 0x4A0, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio36, 0, 0x03, 0x4A0, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio37, 0, 0x03, 0x4A4, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio38, 0, 0x03, 0x4A4, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio39, 0, 0x03, 0x4A8, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio40, 0, 0x03, 0x4A8, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio41, 0, 0x03, 0x4AC, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio42, 0, 0x03, 0x4AC, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio43, 0, 0x03, 0x4B0, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio44, 0, 0x03, 0x4B0, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio45, 0, 0x03, 0x4B4, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio46, 0, 0x03, 0x4B4, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio47, 0, 0x03, 0x4B8, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio48, 0, 0x03, 0x4B8, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio49, 0, 0x03, 0x4BC, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio50, 0, 0x03, 0x4BC, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio51, 0, 0x03, 0x4C0, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio52, 0, 0x03, 0x4C0, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio53, 0, 0x03, 0x4C4, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio54, 0, 0x03, 0x4C4, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio55, 0, 0x03, 0x4C8, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio56, 0, 0x03, 0x4C8, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio57, 0, 0x03, 0x4CC, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio58, 0, 0x03, 0x4CC, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio59, 0, 0x03, 0x4D0, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio60, 0, 0x03, 0x4D0, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio61, 0, 0x03, 0x4D4, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio62, 0, 0x03, 0x4D4, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio63, 0, 0x03, 0x4D8, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio64, 0, 0x03, 0x4D8, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio65, 0, 0x03, 0x4DC, 0x04),
-       BM1880_PINMUX_FUNCTION_MUX(gpio66, 0, 0x03, 0x4DC, 0x14),
-       BM1880_PINMUX_FUNCTION_MUX(gpio67, 0, 0x03, 0x4E0, 0x04),
-       BM1880_PINMUX_FUNCTION(eth1, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(i2s0, 2, 0x03),
-       BM1880_PINMUX_FUNCTION(i2s0_mclkin, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(i2s1, 2, 0x03),
-       BM1880_PINMUX_FUNCTION(i2s1_mclkin, 1, 0x03),
-       BM1880_PINMUX_FUNCTION(spi0, 1, 0x03),
+static const struct bm1880_pinconf_data bm1880_pinconf[] = {
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x03),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
+       BM1880_PINCONF_DAT(0x02),
 };
 
 static int bm1880_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
@@ -870,33 +986,308 @@ static int bm1880_pinmux_set_mux(struct pinctrl_dev *pctldev,
        const struct bm1880_pinmux_function *func = &pctrl->funcs[function];
        int i;
 
-       if (func->mux) {
+       for (i = 0; i < pgrp->npins; i++) {
+               unsigned int pin = pgrp->pins[i];
+               u32 offset = (pin >> 1) << 2;
+               u32 mux_offset = ((!((pin + 1) & 1) << 4) + 4);
                u32 regval = readl_relaxed(pctrl->base + BM1880_REG_MUX +
-                                          func->mux);
+                                          offset);
+
+               regval &= ~(0x03 << mux_offset);
+               regval |= func->mux_val << mux_offset;
+
+               writel_relaxed(regval, pctrl->base + BM1880_REG_MUX + offset);
+       }
+
+       return 0;
+}
+
+#define BM1880_PINCONF(pin, idx) ((!((pin + 1) & 1) << 4) + idx)
+#define BM1880_PINCONF_PULLCTRL(pin)   BM1880_PINCONF(pin, 0)
+#define BM1880_PINCONF_PULLUP(pin)     BM1880_PINCONF(pin, 1)
+#define BM1880_PINCONF_PULLDOWN(pin)   BM1880_PINCONF(pin, 2)
+#define BM1880_PINCONF_DRV(pin)                BM1880_PINCONF(pin, 6)
+#define BM1880_PINCONF_SCHMITT(pin)    BM1880_PINCONF(pin, 9)
+#define BM1880_PINCONF_SLEW(pin)       BM1880_PINCONF(pin, 10)
+
+static int bm1880_pinconf_drv_set(unsigned int mA, u32 width,
+                                 u32 *regval, u32 bit_offset)
+{
+       u32 _regval;
+
+       _regval = *regval;
+
+       /*
+        * There are two sets of drive strength bit width exposed by the
+        * SoC at 4mA step, hence we need to handle them separately.
+        */
+       if (width == 0x03) {
+               switch (mA) {
+               case 4:
+                       _regval &= ~(width << bit_offset);
+                       _regval |= (0 << bit_offset);
+                       break;
+               case 8:
+                       _regval &= ~(width << bit_offset);
+                       _regval |= (1 << bit_offset);
+                       break;
+               case 12:
+                       _regval &= ~(width << bit_offset);
+                       _regval |= (2 << bit_offset);
+                       break;
+               case 16:
+                       _regval &= ~(width << bit_offset);
+                       _regval |= (3 << bit_offset);
+                       break;
+               case 20:
+                       _regval &= ~(width << bit_offset);
+                       _regval |= (4 << bit_offset);
+                       break;
+               case 24:
+                       _regval &= ~(width << bit_offset);
+                       _regval |= (5 << bit_offset);
+                       break;
+               case 28:
+                       _regval &= ~(width << bit_offset);
+                       _regval |= (6 << bit_offset);
+                       break;
+               case 32:
+                       _regval &= ~(width << bit_offset);
+                       _regval |= (7 << bit_offset);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       } else {
+               switch (mA) {
+               case 4:
+                       _regval &= ~(width << bit_offset);
+                       _regval |= (0 << bit_offset);
+                       break;
+               case 8:
+                       _regval &= ~(width << bit_offset);
+                       _regval |= (1 << bit_offset);
+                       break;
+               case 12:
+                       _regval &= ~(width << bit_offset);
+                       _regval |= (2 << bit_offset);
+                       break;
+               case 16:
+                       _regval &= ~(width << bit_offset);
+                       _regval |= (3 << bit_offset);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       *regval = _regval;
+
+       return 0;
+}
+
+static int bm1880_pinconf_drv_get(u32 width, u32 drv)
+{
+       int ret = -ENOTSUPP;
 
-               regval &= ~(func->mux_mask << func->mux_shift);
-               regval |= func->mux_val << func->mux_shift;
-               writel_relaxed(regval, pctrl->base + BM1880_REG_MUX +
-                              func->mux);
+       /*
+        * There are two sets of drive strength bit width exposed by the
+        * SoC at 4mA step, hence we need to handle them separately.
+        */
+       if (width == 0x03) {
+               switch (drv) {
+               case 0:
+                       ret  = 4;
+                       break;
+               case 1:
+                       ret  = 8;
+                       break;
+               case 2:
+                       ret  = 12;
+                       break;
+               case 3:
+                       ret  = 16;
+                       break;
+               case 4:
+                       ret  = 20;
+                       break;
+               case 5:
+                       ret  = 24;
+                       break;
+               case 6:
+                       ret  = 28;
+                       break;
+               case 7:
+                       ret  = 32;
+                       break;
+               default:
+                       break;
+               }
        } else {
-               for (i = 0; i < pgrp->npins; i++) {
-                       unsigned int pin = pgrp->pins[i];
-                       u32 offset = (pin >> 1) << 2;
-                       u32 mux_offset = ((!((pin + 1) & 1) << 4) + 4);
-                       u32 regval = readl_relaxed(pctrl->base +
-                                                  BM1880_REG_MUX + offset);
-
-                       regval &= ~(func->mux_mask << mux_offset);
-                       regval |= func->mux_val << mux_offset;
-
-                       writel_relaxed(regval, pctrl->base +
-                                      BM1880_REG_MUX + offset);
+               switch (drv) {
+               case 0:
+                       ret  = 4;
+                       break;
+               case 1:
+                       ret  = 8;
+                       break;
+               case 2:
+                       ret  = 12;
+                       break;
+               case 3:
+                       ret  = 16;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+static int bm1880_pinconf_cfg_get(struct pinctrl_dev *pctldev,
+                                 unsigned int pin,
+                                 unsigned long *config)
+{
+       struct bm1880_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+       unsigned int param = pinconf_to_config_param(*config);
+       unsigned int arg = 0;
+       u32 regval, offset, bit_offset;
+       int ret;
+
+       offset = (pin >> 1) << 2;
+       regval = readl_relaxed(pctrl->base + BM1880_REG_MUX + offset);
+
+       switch (param) {
+       case PIN_CONFIG_BIAS_PULL_UP:
+               bit_offset = BM1880_PINCONF_PULLUP(pin);
+               arg = !!(regval & BIT(bit_offset));
+               break;
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+               bit_offset = BM1880_PINCONF_PULLDOWN(pin);
+               arg = !!(regval & BIT(bit_offset));
+               break;
+       case PIN_CONFIG_BIAS_DISABLE:
+               bit_offset = BM1880_PINCONF_PULLCTRL(pin);
+               arg = !!(regval & BIT(bit_offset));
+               break;
+       case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+               bit_offset = BM1880_PINCONF_SCHMITT(pin);
+               arg = !!(regval & BIT(bit_offset));
+               break;
+       case PIN_CONFIG_SLEW_RATE:
+               bit_offset = BM1880_PINCONF_SLEW(pin);
+               arg = !!(regval & BIT(bit_offset));
+               break;
+       case PIN_CONFIG_DRIVE_STRENGTH:
+               bit_offset = BM1880_PINCONF_DRV(pin);
+               ret = bm1880_pinconf_drv_get(pctrl->pinconf[pin].drv_bits,
+                                            !!(regval & BIT(bit_offset)));
+               if (ret < 0)
+                       return ret;
+
+               arg = ret;
+               break;
+       default:
+               return -ENOTSUPP;
+       }
+
+       *config = pinconf_to_config_packed(param, arg);
+
+       return 0;
+}
+
+static int bm1880_pinconf_cfg_set(struct pinctrl_dev *pctldev,
+                                 unsigned int pin,
+                                 unsigned long *configs,
+                                 unsigned int num_configs)
+{
+       struct bm1880_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+       u32 regval, offset, bit_offset;
+       int i, ret;
+
+       offset = (pin >> 1) << 2;
+       regval = readl_relaxed(pctrl->base + BM1880_REG_MUX + offset);
+
+       for (i = 0; i < num_configs; i++) {
+               unsigned int param = pinconf_to_config_param(configs[i]);
+               unsigned int arg = pinconf_to_config_argument(configs[i]);
+
+               switch (param) {
+               case PIN_CONFIG_BIAS_PULL_UP:
+                       bit_offset = BM1880_PINCONF_PULLUP(pin);
+                       regval |= BIT(bit_offset);
+                       break;
+               case PIN_CONFIG_BIAS_PULL_DOWN:
+                       bit_offset = BM1880_PINCONF_PULLDOWN(pin);
+                       regval |= BIT(bit_offset);
+                       break;
+               case PIN_CONFIG_BIAS_DISABLE:
+                       bit_offset = BM1880_PINCONF_PULLCTRL(pin);
+                       regval |= BIT(bit_offset);
+                       break;
+               case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+                       bit_offset = BM1880_PINCONF_SCHMITT(pin);
+                       if (arg)
+                               regval |= BIT(bit_offset);
+                       else
+                               regval &= ~BIT(bit_offset);
+                       break;
+               case PIN_CONFIG_SLEW_RATE:
+                       bit_offset = BM1880_PINCONF_SLEW(pin);
+                       if (arg)
+                               regval |= BIT(bit_offset);
+                       else
+                               regval &= ~BIT(bit_offset);
+                       break;
+               case PIN_CONFIG_DRIVE_STRENGTH:
+                       bit_offset = BM1880_PINCONF_DRV(pin);
+                       ret = bm1880_pinconf_drv_set(arg,
+                                               pctrl->pinconf[pin].drv_bits,
+                                               &regval, bit_offset);
+                       if (ret < 0)
+                               return ret;
+
+                       break;
+               default:
+                       dev_warn(pctldev->dev,
+                                "unsupported configuration parameter '%u'\n",
+                                param);
+                       continue;
                }
+
+               writel_relaxed(regval, pctrl->base + BM1880_REG_MUX + offset);
        }
 
        return 0;
 }
 
+static int bm1880_pinconf_group_set(struct pinctrl_dev *pctldev,
+                                   unsigned int selector,
+                                   unsigned long *configs,
+                                   unsigned int  num_configs)
+{
+       int i, ret;
+       struct bm1880_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+       const struct bm1880_pctrl_group *pgrp = &pctrl->groups[selector];
+
+       for (i = 0; i < pgrp->npins; i++) {
+               ret = bm1880_pinconf_cfg_set(pctldev, pgrp->pins[i], configs,
+                                            num_configs);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static const struct pinconf_ops bm1880_pinconf_ops = {
+       .is_generic = true,
+       .pin_config_get = bm1880_pinconf_cfg_get,
+       .pin_config_set = bm1880_pinconf_cfg_set,
+       .pin_config_group_set = bm1880_pinconf_group_set,
+};
+
 static const struct pinmux_ops bm1880_pinmux_ops = {
        .get_functions_count = bm1880_pmux_get_functions_count,
        .get_function_name = bm1880_pmux_get_function_name,
@@ -910,6 +1301,7 @@ static struct pinctrl_desc bm1880_desc = {
        .npins = ARRAY_SIZE(bm1880_pins),
        .pctlops = &bm1880_pctrl_ops,
        .pmxops = &bm1880_pinmux_ops,
+       .confops = &bm1880_pinconf_ops,
        .owner = THIS_MODULE,
 };
 
@@ -932,6 +1324,7 @@ static int bm1880_pinctrl_probe(struct platform_device *pdev)
        pctrl->ngroups = ARRAY_SIZE(bm1880_pctrl_groups);
        pctrl->funcs = bm1880_pmux_functions;
        pctrl->nfuncs = ARRAY_SIZE(bm1880_pmux_functions);
+       pctrl->pinconf = bm1880_pinconf;
 
        pctrl->pctrldev = devm_pinctrl_register(&pdev->dev, &bm1880_desc,
                                                pctrl);
index 807a326..62a6221 100644 (file)
@@ -3204,6 +3204,7 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank,
                                                    base,
                                                    &rockchip_regmap_config);
                }
+               of_node_put(node);
        }
 
        bank->irq = irq_of_parse_and_map(bank->of_node, 0);
index eba872c..d3332da 100644 (file)
@@ -622,6 +622,7 @@ static int stmfx_pinctrl_probe(struct platform_device *pdev)
        pctl->pctl_desc.pins = stmfx_pins;
        pctl->pctl_desc.npins = ARRAY_SIZE(stmfx_pins);
        pctl->pctl_desc.owner = THIS_MODULE;
+       pctl->pctl_desc.link_consumers = true;
 
        ret = devm_pinctrl_register_and_init(pctl->dev, &pctl->pctl_desc,
                                             pctl, &pctl->pctl_dev);
index 02b43f5..1f64e2e 100644 (file)
@@ -471,22 +471,22 @@ struct tb10x_port {
  * @base: register set base address.
  * @pingroups: pointer to an array of the pin groups this driver manages.
  * @pinfuncgrpcnt: number of pingroups in @pingroups.
- * @pinfuncs: pointer to an array of pin functions this driver manages.
  * @pinfuncnt: number of pin functions in @pinfuncs.
  * @mutex: mutex for exclusive access to a pin controller's state.
  * @ports: current state of each port.
  * @gpios: Indicates if a given pin is currently used as GPIO (1) or not (0).
+ * @pinfuncs: flexible array of pin functions this driver manages.
  */
 struct tb10x_pinctrl {
        struct pinctrl_dev *pctl;
        void *base;
        const struct tb10x_pinfuncgrp *pingroups;
        unsigned int pinfuncgrpcnt;
-       struct tb10x_of_pinfunc *pinfuncs;
        unsigned int pinfuncnt;
        struct mutex mutex;
        struct tb10x_port ports[TB10X_PORTS];
        DECLARE_BITMAP(gpios, MAX_PIN + 1);
+       struct tb10x_of_pinfunc pinfuncs[];
 };
 
 static inline void tb10x_pinctrl_set_config(struct tb10x_pinctrl *state,
@@ -759,15 +759,13 @@ static int tb10x_pinctrl_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       state = devm_kzalloc(dev, sizeof(struct tb10x_pinctrl) +
-                                       of_get_child_count(of_node)
-                                       * sizeof(struct tb10x_of_pinfunc),
-                               GFP_KERNEL);
+       state = devm_kzalloc(dev, struct_size(state, pinfuncs,
+                                             of_get_child_count(of_node)),
+                            GFP_KERNEL);
        if (!state)
                return -ENOMEM;
 
        platform_set_drvdata(pdev, state);
-       state->pinfuncs = (struct tb10x_of_pinfunc *)(state + 1);
        mutex_init(&state->mutex);
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
index 890d0a3..8e14a5f 100644 (file)
@@ -169,11 +169,20 @@ config PINCTRL_SDM660
 
 config PINCTRL_SDM845
        tristate "Qualcomm Technologies Inc SDM845 pin controller driver"
-       depends on GPIOLIB && OF
+       depends on GPIOLIB && (OF || ACPI)
        select PINCTRL_MSM
        help
          This is the pinctrl, pinmux, pinconf and gpiolib driver for the
          Qualcomm Technologies Inc TLMM block found on the Qualcomm
          Technologies Inc SDM845 platform.
 
+config PINCTRL_SM8150
+       tristate "Qualcomm Technologies Inc SM8150 pin controller driver"
+       depends on GPIOLIB && OF
+       select PINCTRL_MSM
+       help
+         This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+         Qualcomm Technologies Inc TLMM block found on the Qualcomm
+         Technologies Inc SM8150 platform.
+
 endif
index 344b4c6..ebe9068 100644 (file)
@@ -22,3 +22,4 @@ obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o
 obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-mpp.o
 obj-$(CONFIG_PINCTRL_SDM660)   += pinctrl-sdm660.o
 obj-$(CONFIG_PINCTRL_SDM845) += pinctrl-sdm845.o
+obj-$(CONFIG_PINCTRL_SM8150) += pinctrl-sm8150.o
index 6e319bc..7f35c19 100644 (file)
@@ -599,8 +599,23 @@ static int msm_gpio_init_valid_mask(struct gpio_chip *chip)
        int ret;
        unsigned int len, i;
        unsigned int max_gpios = pctrl->soc->ngpios;
+       const int *reserved = pctrl->soc->reserved_gpios;
        u16 *tmp;
 
+       /* Driver provided reserved list overrides DT and ACPI */
+       if (reserved) {
+               bitmap_fill(chip->valid_mask, max_gpios);
+               for (i = 0; reserved[i] >= 0; i++) {
+                       if (i >= max_gpios || reserved[i] >= max_gpios) {
+                               dev_err(pctrl->dev, "invalid list of reserved GPIOs\n");
+                               return -EINVAL;
+                       }
+                       clear_bit(reserved[i], chip->valid_mask);
+               }
+
+               return 0;
+       }
+
        /* The number of GPIOs in the ACPI tables */
        len = ret = device_property_read_u16_array(pctrl->dev, "gpios", NULL,
                                                   0);
@@ -729,7 +744,7 @@ static void msm_gpio_irq_mask(struct irq_data *d)
        raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 }
 
-static void msm_gpio_irq_unmask(struct irq_data *d)
+static void msm_gpio_irq_clear_unmask(struct irq_data *d, bool status_clear)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
        struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
@@ -741,6 +756,17 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
 
        raw_spin_lock_irqsave(&pctrl->lock, flags);
 
+       if (status_clear) {
+               /*
+                * clear the interrupt status bit before unmask to avoid
+                * any erroneous interrupts that would have got latched
+                * when the interrupt is not in use.
+                */
+               val = msm_readl_intr_status(pctrl, g);
+               val &= ~BIT(g->intr_status_bit);
+               msm_writel_intr_status(val, pctrl, g);
+       }
+
        val = msm_readl_intr_cfg(pctrl, g);
        val |= BIT(g->intr_raw_status_bit);
        val |= BIT(g->intr_enable_bit);
@@ -751,6 +777,17 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
        raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 }
 
+static void msm_gpio_irq_enable(struct irq_data *d)
+{
+
+       msm_gpio_irq_clear_unmask(d, true);
+}
+
+static void msm_gpio_irq_unmask(struct irq_data *d)
+{
+       msm_gpio_irq_clear_unmask(d, false);
+}
+
 static void msm_gpio_irq_ack(struct irq_data *d)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
@@ -956,6 +993,9 @@ static void msm_gpio_irq_handler(struct irq_desc *desc)
 
 static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl)
 {
+       if (pctrl->soc->reserved_gpios)
+               return true;
+
        return device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0) > 0;
 }
 
@@ -978,6 +1018,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
        chip->need_valid_mask = msm_gpio_needs_valid_mask(pctrl);
 
        pctrl->irq_chip.name = "msmgpio";
+       pctrl->irq_chip.irq_enable = msm_gpio_irq_enable;
        pctrl->irq_chip.irq_mask = msm_gpio_irq_mask;
        pctrl->irq_chip.irq_unmask = msm_gpio_irq_unmask;
        pctrl->irq_chip.irq_ack = msm_gpio_irq_ack;
index b724581..48569cd 100644 (file)
@@ -113,6 +113,7 @@ struct msm_pinctrl_soc_data {
        bool pull_no_keeper;
        const char *const *tiles;
        unsigned int ntiles;
+       const int *reserved_gpios;
 };
 
 extern const struct dev_pm_ops msm_pinctrl_dev_pm_ops;
index c97f20f..39f498c 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  */
 
+#include <linux/acpi.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
@@ -420,10 +421,10 @@ DECLARE_MSM_GPIO_PINS(147);
 DECLARE_MSM_GPIO_PINS(148);
 DECLARE_MSM_GPIO_PINS(149);
 
-static const unsigned int sdc2_clk_pins[] = { 150 };
-static const unsigned int sdc2_cmd_pins[] = { 151 };
-static const unsigned int sdc2_data_pins[] = { 152 };
-static const unsigned int ufs_reset_pins[] = { 153 };
+static const unsigned int ufs_reset_pins[] = { 150 };
+static const unsigned int sdc2_clk_pins[] = { 151 };
+static const unsigned int sdc2_cmd_pins[] = { 152 };
+static const unsigned int sdc2_data_pins[] = { 153 };
 
 enum sdm845_functions {
        msm_mux_gpio,
@@ -1271,10 +1272,14 @@ static const struct msm_pingroup sdm845_groups[] = {
        PINGROUP(147, NORTH, _, _, _, _, _, _, _, _, _, _),
        PINGROUP(148, NORTH, _, _, _, _, _, _, _, _, _, _),
        PINGROUP(149, NORTH, _, _, _, _, _, _, _, _, _, _),
+       UFS_RESET(ufs_reset, 0x99f000),
        SDC_QDSD_PINGROUP(sdc2_clk, 0x99a000, 14, 6),
        SDC_QDSD_PINGROUP(sdc2_cmd, 0x99a000, 11, 3),
        SDC_QDSD_PINGROUP(sdc2_data, 0x99a000, 9, 0),
-       UFS_RESET(ufs_reset, 0x99f000),
+};
+
+static const int sdm845_acpi_reserved_gpios[] = {
+       0, 1, 2, 3, 81, 82, 83, 84, -1
 };
 
 static const struct msm_pinctrl_soc_data sdm845_pinctrl = {
@@ -1284,14 +1289,42 @@ static const struct msm_pinctrl_soc_data sdm845_pinctrl = {
        .nfunctions = ARRAY_SIZE(sdm845_functions),
        .groups = sdm845_groups,
        .ngroups = ARRAY_SIZE(sdm845_groups),
+       .ngpios = 151,
+};
+
+static const struct msm_pinctrl_soc_data sdm845_acpi_pinctrl = {
+       .pins = sdm845_pins,
+       .npins = ARRAY_SIZE(sdm845_pins),
+       .groups = sdm845_groups,
+       .ngroups = ARRAY_SIZE(sdm845_groups),
+       .reserved_gpios = sdm845_acpi_reserved_gpios,
        .ngpios = 150,
 };
 
 static int sdm845_pinctrl_probe(struct platform_device *pdev)
 {
-       return msm_pinctrl_probe(pdev, &sdm845_pinctrl);
+       int ret;
+
+       if (pdev->dev.of_node) {
+               ret = msm_pinctrl_probe(pdev, &sdm845_pinctrl);
+       } else if (has_acpi_companion(&pdev->dev)) {
+               ret = msm_pinctrl_probe(pdev, &sdm845_acpi_pinctrl);
+       } else {
+               dev_err(&pdev->dev, "DT and ACPI disabled\n");
+               return -EINVAL;
+       }
+
+       return ret;
 }
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id sdm845_pinctrl_acpi_match[] = {
+       { "QCOM0217"},
+       { },
+};
+MODULE_DEVICE_TABLE(acpi, sdm845_pinctrl_acpi_match);
+#endif
+
 static const struct of_device_id sdm845_pinctrl_of_match[] = {
        { .compatible = "qcom,sdm845-pinctrl", },
        { },
@@ -1302,6 +1335,7 @@ static struct platform_driver sdm845_pinctrl_driver = {
                .name = "sdm845-pinctrl",
                .pm = &msm_pinctrl_dev_pm_ops,
                .of_match_table = sdm845_pinctrl_of_match,
+               .acpi_match_table = ACPI_PTR(sdm845_pinctrl_acpi_match),
        },
        .probe = sdm845_pinctrl_probe,
        .remove = msm_pinctrl_remove,
diff --git a/drivers/pinctrl/qcom/pinctrl-sm8150.c b/drivers/pinctrl/qcom/pinctrl-sm8150.c
new file mode 100644 (file)
index 0000000..7359bae
--- /dev/null
@@ -0,0 +1,1548 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+static const char * const sm8150_tiles[] = {
+       "north",
+       "south",
+       "east",
+       "west"
+};
+
+enum {
+       NORTH,
+       SOUTH,
+       EAST,
+       WEST
+};
+
+#define FUNCTION(fname)                                        \
+       [msm_mux_##fname] = {                           \
+               .name = #fname,                         \
+               .groups = fname##_groups,               \
+               .ngroups = ARRAY_SIZE(fname##_groups),  \
+       }
+
+#define PINGROUP(id, _tile, f1, f2, f3, f4, f5, f6, f7, f8, f9)        \
+       {                                               \
+               .name = "gpio" #id,                     \
+               .pins = gpio##id##_pins,                \
+               .npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins),     \
+               .funcs = (int[]){                       \
+                       msm_mux_gpio, /* gpio mode */   \
+                       msm_mux_##f1,                   \
+                       msm_mux_##f2,                   \
+                       msm_mux_##f3,                   \
+                       msm_mux_##f4,                   \
+                       msm_mux_##f5,                   \
+                       msm_mux_##f6,                   \
+                       msm_mux_##f7,                   \
+                       msm_mux_##f8,                   \
+                       msm_mux_##f9                    \
+               },                                      \
+               .nfuncs = 10,                           \
+               .ctl_reg = 0x1000 * id,         \
+               .io_reg = 0x1000 * id + 0x4,            \
+               .intr_cfg_reg = 0x1000 * id + 0x8,      \
+               .intr_status_reg = 0x1000 * id + 0xc,   \
+               .intr_target_reg = 0x1000 * id + 0x8,   \
+               .tile = _tile,                  \
+               .mux_bit = 2,                   \
+               .pull_bit = 0,                  \
+               .drv_bit = 6,                   \
+               .oe_bit = 9,                    \
+               .in_bit = 0,                    \
+               .out_bit = 1,                   \
+               .intr_enable_bit = 0,           \
+               .intr_status_bit = 0,           \
+               .intr_target_bit = 5,           \
+               .intr_target_kpss_val = 3,      \
+               .intr_raw_status_bit = 4,       \
+               .intr_polarity_bit = 1,         \
+               .intr_detection_bit = 2,        \
+               .intr_detection_width = 2,      \
+       }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv)     \
+       {                                               \
+               .name = #pg_name,                       \
+               .pins = pg_name##_pins,                 \
+               .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins),      \
+               .ctl_reg = ctl,                         \
+               .io_reg = 0,                            \
+               .intr_cfg_reg = 0,                      \
+               .intr_status_reg = 0,                   \
+               .intr_target_reg = 0,                   \
+               .tile = NORTH,                          \
+               .mux_bit = -1,                          \
+               .pull_bit = pull,                       \
+               .drv_bit = drv,                         \
+               .oe_bit = -1,                           \
+               .in_bit = -1,                           \
+               .out_bit = -1,                          \
+               .intr_enable_bit = -1,                  \
+               .intr_status_bit = -1,                  \
+               .intr_target_bit = -1,                  \
+               .intr_raw_status_bit = -1,              \
+               .intr_polarity_bit = -1,                \
+               .intr_detection_bit = -1,               \
+               .intr_detection_width = -1,             \
+       }
+
+#define UFS_RESET(pg_name, offset)                             \
+       {                                               \
+               .name = #pg_name,                       \
+               .pins = pg_name##_pins,                 \
+               .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins),      \
+               .ctl_reg = offset,                      \
+               .io_reg = offset + 0x4,                 \
+               .intr_cfg_reg = 0,                      \
+               .intr_status_reg = 0,                   \
+               .intr_target_reg = 0,                   \
+               .tile = SOUTH,                          \
+               .mux_bit = -1,                          \
+               .pull_bit = 3,                          \
+               .drv_bit = 0,                           \
+               .oe_bit = -1,                           \
+               .in_bit = -1,                           \
+               .out_bit = 0,                           \
+               .intr_enable_bit = -1,                  \
+               .intr_status_bit = -1,                  \
+               .intr_target_bit = -1,                  \
+               .intr_raw_status_bit = -1,              \
+               .intr_polarity_bit = -1,                \
+               .intr_detection_bit = -1,               \
+               .intr_detection_width = -1,             \
+       }
+
+static const struct pinctrl_pin_desc sm8150_pins[] = {
+       PINCTRL_PIN(0, "GPIO_0"),
+       PINCTRL_PIN(1, "GPIO_1"),
+       PINCTRL_PIN(2, "GPIO_2"),
+       PINCTRL_PIN(3, "GPIO_3"),
+       PINCTRL_PIN(4, "GPIO_4"),
+       PINCTRL_PIN(5, "GPIO_5"),
+       PINCTRL_PIN(6, "GPIO_6"),
+       PINCTRL_PIN(7, "GPIO_7"),
+       PINCTRL_PIN(8, "GPIO_8"),
+       PINCTRL_PIN(9, "GPIO_9"),
+       PINCTRL_PIN(10, "GPIO_10"),
+       PINCTRL_PIN(11, "GPIO_11"),
+       PINCTRL_PIN(12, "GPIO_12"),
+       PINCTRL_PIN(13, "GPIO_13"),
+       PINCTRL_PIN(14, "GPIO_14"),
+       PINCTRL_PIN(15, "GPIO_15"),
+       PINCTRL_PIN(16, "GPIO_16"),
+       PINCTRL_PIN(17, "GPIO_17"),
+       PINCTRL_PIN(18, "GPIO_18"),
+       PINCTRL_PIN(19, "GPIO_19"),
+       PINCTRL_PIN(20, "GPIO_20"),
+       PINCTRL_PIN(21, "GPIO_21"),
+       PINCTRL_PIN(22, "GPIO_22"),
+       PINCTRL_PIN(23, "GPIO_23"),
+       PINCTRL_PIN(24, "GPIO_24"),
+       PINCTRL_PIN(25, "GPIO_25"),
+       PINCTRL_PIN(26, "GPIO_26"),
+       PINCTRL_PIN(27, "GPIO_27"),
+       PINCTRL_PIN(28, "GPIO_28"),
+       PINCTRL_PIN(29, "GPIO_29"),
+       PINCTRL_PIN(30, "GPIO_30"),
+       PINCTRL_PIN(31, "GPIO_31"),
+       PINCTRL_PIN(32, "GPIO_32"),
+       PINCTRL_PIN(33, "GPIO_33"),
+       PINCTRL_PIN(34, "GPIO_34"),
+       PINCTRL_PIN(35, "GPIO_35"),
+       PINCTRL_PIN(36, "GPIO_36"),
+       PINCTRL_PIN(37, "GPIO_37"),
+       PINCTRL_PIN(38, "GPIO_38"),
+       PINCTRL_PIN(39, "GPIO_39"),
+       PINCTRL_PIN(40, "GPIO_40"),
+       PINCTRL_PIN(41, "GPIO_41"),
+       PINCTRL_PIN(42, "GPIO_42"),
+       PINCTRL_PIN(43, "GPIO_43"),
+       PINCTRL_PIN(44, "GPIO_44"),
+       PINCTRL_PIN(45, "GPIO_45"),
+       PINCTRL_PIN(46, "GPIO_46"),
+       PINCTRL_PIN(47, "GPIO_47"),
+       PINCTRL_PIN(48, "GPIO_48"),
+       PINCTRL_PIN(49, "GPIO_49"),
+       PINCTRL_PIN(50, "GPIO_50"),
+       PINCTRL_PIN(51, "GPIO_51"),
+       PINCTRL_PIN(52, "GPIO_52"),
+       PINCTRL_PIN(53, "GPIO_53"),
+       PINCTRL_PIN(54, "GPIO_54"),
+       PINCTRL_PIN(55, "GPIO_55"),
+       PINCTRL_PIN(56, "GPIO_56"),
+       PINCTRL_PIN(57, "GPIO_57"),
+       PINCTRL_PIN(58, "GPIO_58"),
+       PINCTRL_PIN(59, "GPIO_59"),
+       PINCTRL_PIN(60, "GPIO_60"),
+       PINCTRL_PIN(61, "GPIO_61"),
+       PINCTRL_PIN(62, "GPIO_62"),
+       PINCTRL_PIN(63, "GPIO_63"),
+       PINCTRL_PIN(64, "GPIO_64"),
+       PINCTRL_PIN(65, "GPIO_65"),
+       PINCTRL_PIN(66, "GPIO_66"),
+       PINCTRL_PIN(67, "GPIO_67"),
+       PINCTRL_PIN(68, "GPIO_68"),
+       PINCTRL_PIN(69, "GPIO_69"),
+       PINCTRL_PIN(70, "GPIO_70"),
+       PINCTRL_PIN(71, "GPIO_71"),
+       PINCTRL_PIN(72, "GPIO_72"),
+       PINCTRL_PIN(73, "GPIO_73"),
+       PINCTRL_PIN(74, "GPIO_74"),
+       PINCTRL_PIN(75, "GPIO_75"),
+       PINCTRL_PIN(76, "GPIO_76"),
+       PINCTRL_PIN(77, "GPIO_77"),
+       PINCTRL_PIN(78, "GPIO_78"),
+       PINCTRL_PIN(79, "GPIO_79"),
+       PINCTRL_PIN(80, "GPIO_80"),
+       PINCTRL_PIN(81, "GPIO_81"),
+       PINCTRL_PIN(82, "GPIO_82"),
+       PINCTRL_PIN(83, "GPIO_83"),
+       PINCTRL_PIN(84, "GPIO_84"),
+       PINCTRL_PIN(85, "GPIO_85"),
+       PINCTRL_PIN(86, "GPIO_86"),
+       PINCTRL_PIN(87, "GPIO_87"),
+       PINCTRL_PIN(88, "GPIO_88"),
+       PINCTRL_PIN(89, "GPIO_89"),
+       PINCTRL_PIN(90, "GPIO_90"),
+       PINCTRL_PIN(91, "GPIO_91"),
+       PINCTRL_PIN(92, "GPIO_92"),
+       PINCTRL_PIN(93, "GPIO_93"),
+       PINCTRL_PIN(94, "GPIO_94"),
+       PINCTRL_PIN(95, "GPIO_95"),
+       PINCTRL_PIN(96, "GPIO_96"),
+       PINCTRL_PIN(97, "GPIO_97"),
+       PINCTRL_PIN(98, "GPIO_98"),
+       PINCTRL_PIN(99, "GPIO_99"),
+       PINCTRL_PIN(100, "GPIO_100"),
+       PINCTRL_PIN(101, "GPIO_101"),
+       PINCTRL_PIN(102, "GPIO_102"),
+       PINCTRL_PIN(103, "GPIO_103"),
+       PINCTRL_PIN(104, "GPIO_104"),
+       PINCTRL_PIN(105, "GPIO_105"),
+       PINCTRL_PIN(106, "GPIO_106"),
+       PINCTRL_PIN(107, "GPIO_107"),
+       PINCTRL_PIN(108, "GPIO_108"),
+       PINCTRL_PIN(109, "GPIO_109"),
+       PINCTRL_PIN(110, "GPIO_110"),
+       PINCTRL_PIN(111, "GPIO_111"),
+       PINCTRL_PIN(112, "GPIO_112"),
+       PINCTRL_PIN(113, "GPIO_113"),
+       PINCTRL_PIN(114, "GPIO_114"),
+       PINCTRL_PIN(115, "GPIO_115"),
+       PINCTRL_PIN(116, "GPIO_116"),
+       PINCTRL_PIN(117, "GPIO_117"),
+       PINCTRL_PIN(118, "GPIO_118"),
+       PINCTRL_PIN(119, "GPIO_119"),
+       PINCTRL_PIN(120, "GPIO_120"),
+       PINCTRL_PIN(121, "GPIO_121"),
+       PINCTRL_PIN(122, "GPIO_122"),
+       PINCTRL_PIN(123, "GPIO_123"),
+       PINCTRL_PIN(124, "GPIO_124"),
+       PINCTRL_PIN(125, "GPIO_125"),
+       PINCTRL_PIN(126, "GPIO_126"),
+       PINCTRL_PIN(127, "GPIO_127"),
+       PINCTRL_PIN(128, "GPIO_128"),
+       PINCTRL_PIN(129, "GPIO_129"),
+       PINCTRL_PIN(130, "GPIO_130"),
+       PINCTRL_PIN(131, "GPIO_131"),
+       PINCTRL_PIN(132, "GPIO_132"),
+       PINCTRL_PIN(133, "GPIO_133"),
+       PINCTRL_PIN(134, "GPIO_134"),
+       PINCTRL_PIN(135, "GPIO_135"),
+       PINCTRL_PIN(136, "GPIO_136"),
+       PINCTRL_PIN(137, "GPIO_137"),
+       PINCTRL_PIN(138, "GPIO_138"),
+       PINCTRL_PIN(139, "GPIO_139"),
+       PINCTRL_PIN(140, "GPIO_140"),
+       PINCTRL_PIN(141, "GPIO_141"),
+       PINCTRL_PIN(142, "GPIO_142"),
+       PINCTRL_PIN(143, "GPIO_143"),
+       PINCTRL_PIN(144, "GPIO_144"),
+       PINCTRL_PIN(145, "GPIO_145"),
+       PINCTRL_PIN(146, "GPIO_146"),
+       PINCTRL_PIN(147, "GPIO_147"),
+       PINCTRL_PIN(148, "GPIO_148"),
+       PINCTRL_PIN(149, "GPIO_149"),
+       PINCTRL_PIN(150, "GPIO_150"),
+       PINCTRL_PIN(151, "GPIO_151"),
+       PINCTRL_PIN(152, "GPIO_152"),
+       PINCTRL_PIN(153, "GPIO_153"),
+       PINCTRL_PIN(154, "GPIO_154"),
+       PINCTRL_PIN(155, "GPIO_155"),
+       PINCTRL_PIN(156, "GPIO_156"),
+       PINCTRL_PIN(157, "GPIO_157"),
+       PINCTRL_PIN(158, "GPIO_158"),
+       PINCTRL_PIN(159, "GPIO_159"),
+       PINCTRL_PIN(160, "GPIO_160"),
+       PINCTRL_PIN(161, "GPIO_161"),
+       PINCTRL_PIN(162, "GPIO_162"),
+       PINCTRL_PIN(163, "GPIO_163"),
+       PINCTRL_PIN(164, "GPIO_164"),
+       PINCTRL_PIN(165, "GPIO_165"),
+       PINCTRL_PIN(166, "GPIO_166"),
+       PINCTRL_PIN(167, "GPIO_167"),
+       PINCTRL_PIN(168, "GPIO_168"),
+       PINCTRL_PIN(169, "GPIO_169"),
+       PINCTRL_PIN(170, "GPIO_170"),
+       PINCTRL_PIN(171, "GPIO_171"),
+       PINCTRL_PIN(172, "GPIO_172"),
+       PINCTRL_PIN(173, "GPIO_173"),
+       PINCTRL_PIN(174, "GPIO_174"),
+       PINCTRL_PIN(175, "UFS_RESET"),
+       PINCTRL_PIN(176, "SDC2_CLK"),
+       PINCTRL_PIN(177, "SDC2_CMD"),
+       PINCTRL_PIN(178, "SDC2_DATA"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+       static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+DECLARE_MSM_GPIO_PINS(134);
+DECLARE_MSM_GPIO_PINS(135);
+DECLARE_MSM_GPIO_PINS(136);
+DECLARE_MSM_GPIO_PINS(137);
+DECLARE_MSM_GPIO_PINS(138);
+DECLARE_MSM_GPIO_PINS(139);
+DECLARE_MSM_GPIO_PINS(140);
+DECLARE_MSM_GPIO_PINS(141);
+DECLARE_MSM_GPIO_PINS(142);
+DECLARE_MSM_GPIO_PINS(143);
+DECLARE_MSM_GPIO_PINS(144);
+DECLARE_MSM_GPIO_PINS(145);
+DECLARE_MSM_GPIO_PINS(146);
+DECLARE_MSM_GPIO_PINS(147);
+DECLARE_MSM_GPIO_PINS(148);
+DECLARE_MSM_GPIO_PINS(149);
+DECLARE_MSM_GPIO_PINS(150);
+DECLARE_MSM_GPIO_PINS(151);
+DECLARE_MSM_GPIO_PINS(152);
+DECLARE_MSM_GPIO_PINS(153);
+DECLARE_MSM_GPIO_PINS(154);
+DECLARE_MSM_GPIO_PINS(155);
+DECLARE_MSM_GPIO_PINS(156);
+DECLARE_MSM_GPIO_PINS(157);
+DECLARE_MSM_GPIO_PINS(158);
+DECLARE_MSM_GPIO_PINS(159);
+DECLARE_MSM_GPIO_PINS(160);
+DECLARE_MSM_GPIO_PINS(161);
+DECLARE_MSM_GPIO_PINS(162);
+DECLARE_MSM_GPIO_PINS(163);
+DECLARE_MSM_GPIO_PINS(164);
+DECLARE_MSM_GPIO_PINS(165);
+DECLARE_MSM_GPIO_PINS(166);
+DECLARE_MSM_GPIO_PINS(167);
+DECLARE_MSM_GPIO_PINS(168);
+DECLARE_MSM_GPIO_PINS(169);
+DECLARE_MSM_GPIO_PINS(170);
+DECLARE_MSM_GPIO_PINS(171);
+DECLARE_MSM_GPIO_PINS(172);
+DECLARE_MSM_GPIO_PINS(173);
+DECLARE_MSM_GPIO_PINS(174);
+
+static const unsigned int ufs_reset_pins[] = { 175 };
+static const unsigned int sdc2_clk_pins[] = { 176 };
+static const unsigned int sdc2_cmd_pins[] = { 177 };
+static const unsigned int sdc2_data_pins[] = { 178 };
+
+enum sm8150_functions {
+       msm_mux_adsp_ext,
+       msm_mux_agera_pll,
+       msm_mux_aoss_cti,
+       msm_mux_atest_char,
+       msm_mux_atest_char0,
+       msm_mux_atest_char1,
+       msm_mux_atest_char2,
+       msm_mux_atest_char3,
+       msm_mux_atest_usb1,
+       msm_mux_atest_usb2,
+       msm_mux_atest_usb10,
+       msm_mux_atest_usb11,
+       msm_mux_atest_usb12,
+       msm_mux_atest_usb13,
+       msm_mux_atest_usb20,
+       msm_mux_atest_usb21,
+       msm_mux_atest_usb22,
+       msm_mux_atest_usb23,
+       msm_mux_audio_ref,
+       msm_mux_btfm_slimbus,
+       msm_mux_cam_mclk,
+       msm_mux_cci_async,
+       msm_mux_cci_i2c,
+       msm_mux_cci_timer0,
+       msm_mux_cci_timer1,
+       msm_mux_cci_timer2,
+       msm_mux_cci_timer3,
+       msm_mux_cci_timer4,
+       msm_mux_cri_trng,
+       msm_mux_cri_trng0,
+       msm_mux_cri_trng1,
+       msm_mux_dbg_out,
+       msm_mux_ddr_bist,
+       msm_mux_ddr_pxi0,
+       msm_mux_ddr_pxi1,
+       msm_mux_ddr_pxi2,
+       msm_mux_ddr_pxi3,
+       msm_mux_edp_hot,
+       msm_mux_edp_lcd,
+       msm_mux_emac_phy,
+       msm_mux_emac_pps,
+       msm_mux_gcc_gp1,
+       msm_mux_gcc_gp2,
+       msm_mux_gcc_gp3,
+       msm_mux_gpio,
+       msm_mux_jitter_bist,
+       msm_mux_hs1_mi2s,
+       msm_mux_hs2_mi2s,
+       msm_mux_hs3_mi2s,
+       msm_mux_lpass_slimbus,
+       msm_mux_mdp_vsync,
+       msm_mux_mdp_vsync0,
+       msm_mux_mdp_vsync1,
+       msm_mux_mdp_vsync2,
+       msm_mux_mdp_vsync3,
+       msm_mux_mss_lte,
+       msm_mux_m_voc,
+       msm_mux_nav_pps,
+       msm_mux_pa_indicator,
+       msm_mux_pci_e0,
+       msm_mux_pci_e1,
+       msm_mux_phase_flag,
+       msm_mux_pll_bist,
+       msm_mux_pll_bypassnl,
+       msm_mux_pll_reset,
+       msm_mux_pri_mi2s,
+       msm_mux_pri_mi2s_ws,
+       msm_mux_prng_rosc,
+       msm_mux_qdss,
+       msm_mux_qdss_cti,
+       msm_mux_qlink_enable,
+       msm_mux_qlink_request,
+       msm_mux_qspi0,
+       msm_mux_qspi1,
+       msm_mux_qspi2,
+       msm_mux_qspi3,
+       msm_mux_qspi_clk,
+       msm_mux_qspi_cs,
+       msm_mux_qua_mi2s,
+       msm_mux_qup0,
+       msm_mux_qup1,
+       msm_mux_qup2,
+       msm_mux_qup3,
+       msm_mux_qup4,
+       msm_mux_qup5,
+       msm_mux_qup6,
+       msm_mux_qup7,
+       msm_mux_qup8,
+       msm_mux_qup9,
+       msm_mux_qup10,
+       msm_mux_qup11,
+       msm_mux_qup12,
+       msm_mux_qup13,
+       msm_mux_qup14,
+       msm_mux_qup15,
+       msm_mux_qup16,
+       msm_mux_qup17,
+       msm_mux_qup18,
+       msm_mux_qup19,
+       msm_mux_qup_l4,
+       msm_mux_qup_l5,
+       msm_mux_qup_l6,
+       msm_mux_rgmii,
+       msm_mux_sdc4,
+       msm_mux_sd_write,
+       msm_mux_sec_mi2s,
+       msm_mux_spkr_i2s,
+       msm_mux_sp_cmu,
+       msm_mux_ter_mi2s,
+       msm_mux_tgu_ch0,
+       msm_mux_tgu_ch2,
+       msm_mux_tgu_ch1,
+       msm_mux_tgu_ch3,
+       msm_mux_tsense_pwm1,
+       msm_mux_tsense_pwm2,
+       msm_mux_tsif1,
+       msm_mux_tsif2,
+       msm_mux_uim1,
+       msm_mux_uim2,
+       msm_mux_uim_batt,
+       msm_mux_usb2phy_ac,
+       msm_mux_usb_phy,
+       msm_mux_vfr_1,
+       msm_mux_vsense_trigger,
+       msm_mux_wlan1_adc1,
+       msm_mux_wlan1_adc0,
+       msm_mux_wlan2_adc1,
+       msm_mux_wlan2_adc0,
+       msm_mux_wmss_reset,
+       msm_mux__,
+};
+
+static const char * const phase_flag_groups[] = {
+       "gpio18", "gpio19", "gpio20", "gpio55", "gpio56",
+       "gpio57", "gpio59", "gpio64", "gpio68", "gpio76",
+       "gpio79", "gpio80", "gpio90", "gpio91", "gpio92",
+       "gpio93", "gpio94", "gpio96", "gpio114", "gpio115",
+       "gpio116", "gpio117", "gpio118", "gpio119", "gpio120",
+       "gpio121", "gpio122", "gpio126", "gpio127", "gpio128",
+       "gpio144", "gpio145",
+};
+
+static const char * const emac_pps_groups[] = {
+       "gpio81",
+};
+
+static const char * const qup12_groups[] = {
+       "gpio83", "gpio84", "gpio85", "gpio86",
+};
+
+static const char * const qup16_groups[] = {
+       "gpio83", "gpio84", "gpio85", "gpio86",
+};
+
+static const char * const tsif1_groups[] = {
+       "gpio88", "gpio89", "gpio90", "gpio91", "gpio97",
+};
+
+static const char * const qup8_groups[] = {
+       "gpio88", "gpio89", "gpio90", "gpio91",
+};
+
+static const char * const qspi_cs_groups[] = {
+       "gpio88", "gpio94",
+};
+
+static const char * const tgu_ch3_groups[] = {
+       "gpio88",
+};
+
+static const char * const qspi0_groups[] = {
+       "gpio89",
+};
+
+static const char * const mdp_vsync0_groups[] = {
+       "gpio89",
+};
+
+static const char * const mdp_vsync1_groups[] = {
+       "gpio89",
+};
+
+static const char * const mdp_vsync2_groups[] = {
+       "gpio89",
+};
+
+static const char * const mdp_vsync3_groups[] = {
+       "gpio89",
+};
+
+static const char * const tgu_ch0_groups[] = {
+       "gpio89",
+};
+
+static const char * const qspi1_groups[] = {
+       "gpio90",
+};
+
+static const char * const sdc4_groups[] = {
+       "gpio90", "gpio91", "gpio92", "gpio93", "gpio94", "gpio95",
+};
+
+static const char * const tgu_ch1_groups[] = {
+       "gpio90",
+};
+
+static const char * const wlan1_adc1_groups[] = {
+       "gpio90",
+};
+
+static const char * const qspi2_groups[] = {
+       "gpio91",
+};
+
+static const char * const vfr_1_groups[] = {
+       "gpio91",
+};
+
+static const char * const tgu_ch2_groups[] = {
+       "gpio91",
+};
+
+static const char * const wlan1_adc0_groups[] = {
+       "gpio91",
+};
+
+static const char * const tsif2_groups[] = {
+       "gpio92", "gpio93", "gpio94", "gpio95", "gpio96",
+};
+
+static const char * const qup11_groups[] = {
+       "gpio92", "gpio93", "gpio94", "gpio95",
+};
+
+static const char * const qspi_clk_groups[] = {
+       "gpio92",
+};
+
+static const char * const wlan2_adc1_groups[] = {
+       "gpio92",
+};
+
+static const char * const qspi3_groups[] = {
+       "gpio93",
+};
+
+static const char * const wlan2_adc0_groups[] = {
+       "gpio93",
+};
+
+static const char * const sd_write_groups[] = {
+       "gpio97",
+};
+
+static const char * const qup7_groups[] = {
+       "gpio98", "gpio99", "gpio100", "gpio101",
+};
+
+static const char * const ddr_bist_groups[] = {
+       "gpio98", "gpio99", "gpio145", "gpio146",
+};
+
+static const char * const ddr_pxi3_groups[] = {
+       "gpio98", "gpio101",
+};
+
+static const char * const atest_usb13_groups[] = {
+       "gpio99",
+};
+
+static const char * const ddr_pxi1_groups[] = {
+       "gpio99", "gpio100",
+};
+
+static const char * const pll_bypassnl_groups[] = {
+       "gpio100",
+};
+
+static const char * const atest_usb12_groups[] = {
+       "gpio100",
+};
+
+static const char * const pll_reset_groups[] = {
+       "gpio101",
+};
+
+static const char * const pci_e1_groups[] = {
+       "gpio102", "gpio103",
+};
+
+static const char * const uim2_groups[] = {
+       "gpio105", "gpio106", "gpio107", "gpio108",
+};
+
+static const char * const uim1_groups[] = {
+       "gpio109", "gpio110", "gpio111", "gpio112",
+};
+
+static const char * const uim_batt_groups[] = {
+       "gpio113",
+};
+
+static const char * const usb2phy_ac_groups[] = {
+       "gpio113", "gpio123",
+};
+
+static const char * const aoss_cti_groups[] = {
+       "gpio113",
+};
+
+static const char * const qup1_groups[] = {
+       "gpio114", "gpio115", "gpio116", "gpio117",
+};
+
+static const char * const rgmii_groups[] = {
+       "gpio4", "gpio5", "gpio6", "gpio7", "gpio59",
+       "gpio114", "gpio115", "gpio116", "gpio117",
+       "gpio118", "gpio119", "gpio120", "gpio121", "gpio122",
+};
+
+static const char * const adsp_ext_groups[] = {
+       "gpio115",
+};
+
+static const char * const qup5_groups[] = {
+       "gpio119", "gpio120", "gpio121", "gpio122",
+};
+
+static const char * const atest_usb22_groups[] = {
+       "gpio123",
+};
+
+static const char * const emac_phy_groups[] = {
+       "gpio124",
+};
+
+static const char * const hs3_mi2s_groups[] = {
+       "gpio125", "gpio165", "gpio166", "gpio167", "gpio168",
+};
+
+static const char * const sec_mi2s_groups[] = {
+       "gpio126", "gpio127", "gpio128", "gpio129", "gpio130",
+};
+
+static const char * const qup2_groups[] = {
+       "gpio126", "gpio127", "gpio128", "gpio129",
+};
+
+static const char * const jitter_bist_groups[] = {
+       "gpio129",
+};
+
+static const char * const atest_usb21_groups[] = {
+       "gpio129",
+};
+
+static const char * const pll_bist_groups[] = {
+       "gpio130",
+};
+
+static const char * const atest_usb20_groups[] = {
+       "gpio130",
+};
+
+static const char * const atest_char0_groups[] = {
+       "gpio130",
+};
+
+static const char * const ter_mi2s_groups[] = {
+       "gpio131", "gpio132", "gpio133", "gpio134", "gpio135",
+};
+
+static const char * const gcc_gp1_groups[] = {
+       "gpio131", "gpio136",
+};
+
+static const char * const atest_char1_groups[] = {
+       "gpio133",
+};
+
+static const char * const atest_char2_groups[] = {
+       "gpio134",
+};
+
+static const char * const atest_char3_groups[] = {
+       "gpio135",
+};
+
+static const char * const qua_mi2s_groups[] = {
+       "gpio136", "gpio137", "gpio138", "gpio139", "gpio140", "gpio141",
+       "gpio142",
+};
+
+static const char * const pri_mi2s_groups[] = {
+       "gpio143", "gpio144", "gpio146", "gpio147",
+};
+
+static const char * const qup3_groups[] = {
+       "gpio144", "gpio145", "gpio146", "gpio147",
+};
+
+static const char * const ddr_pxi0_groups[] = {
+       "gpio144", "gpio145",
+};
+
+static const char * const pri_mi2s_ws_groups[] = {
+       "gpio145",
+};
+
+static const char * const vsense_trigger_groups[] = {
+       "gpio145",
+};
+
+static const char * const atest_usb1_groups[] = {
+       "gpio145",
+};
+
+static const char * const atest_usb11_groups[] = {
+       "gpio146",
+};
+
+static const char * const ddr_pxi2_groups[] = {
+       "gpio146", "gpio147",
+};
+
+static const char * const dbg_out_groups[] = {
+       "gpio147",
+};
+
+static const char * const atest_usb10_groups[] = {
+       "gpio147",
+};
+
+static const char * const spkr_i2s_groups[] = {
+       "gpio148", "gpio149", "gpio150", "gpio151", "gpio152",
+};
+
+static const char * const audio_ref_groups[] = {
+       "gpio148",
+};
+
+static const char * const lpass_slimbus_groups[] = {
+       "gpio149", "gpio150", "gpio151", "gpio152",
+};
+
+static const char * const tsense_pwm1_groups[] = {
+       "gpio150",
+};
+
+static const char * const tsense_pwm2_groups[] = {
+       "gpio150",
+};
+
+static const char * const btfm_slimbus_groups[] = {
+       "gpio153", "gpio154",
+};
+
+static const char * const hs1_mi2s_groups[] = {
+       "gpio155", "gpio156", "gpio157", "gpio158", "gpio159",
+};
+
+static const char * const cri_trng0_groups[] = {
+       "gpio159",
+};
+
+static const char * const hs2_mi2s_groups[] = {
+       "gpio160", "gpio161", "gpio162", "gpio163", "gpio164",
+};
+
+static const char * const cri_trng1_groups[] = {
+       "gpio160",
+};
+
+static const char * const cri_trng_groups[] = {
+       "gpio161",
+};
+
+static const char * const sp_cmu_groups[] = {
+       "gpio162",
+};
+
+static const char * const prng_rosc_groups[] = {
+       "gpio163",
+};
+
+static const char * const qup0_groups[] = {
+       "gpio0", "gpio1", "gpio2", "gpio3",
+};
+
+static const char * const gpio_groups[] = {
+       "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+       "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+       "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+       "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+       "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+       "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+       "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+       "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+       "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+       "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+       "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+       "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+       "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91",
+       "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+       "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104",
+       "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+       "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116",
+       "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122",
+       "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128",
+       "gpio129", "gpio130", "gpio131", "gpio132", "gpio133", "gpio134",
+       "gpio135", "gpio136", "gpio137", "gpio138", "gpio139", "gpio140",
+       "gpio141", "gpio142", "gpio143", "gpio144", "gpio145", "gpio146",
+       "gpio147", "gpio148", "gpio149", "gpio150", "gpio151", "gpio152",
+       "gpio153", "gpio154", "gpio155", "gpio156", "gpio157", "gpio158",
+       "gpio159", "gpio160", "gpio161", "gpio162", "gpio163", "gpio164",
+       "gpio165", "gpio166", "gpio167", "gpio168", "gpio169", "gpio170",
+       "gpio171", "gpio172", "gpio173", "gpio174",
+};
+
+static const char * const qup6_groups[] = {
+       "gpio4", "gpio5", "gpio6", "gpio7",
+};
+
+static const char * const qup_l6_groups[] = {
+       "gpio6", "gpio34", "gpio97", "gpio123",
+};
+
+static const char * const qup_l5_groups[] = {
+       "gpio7", "gpio33", "gpio82", "gpio96",
+};
+
+static const char * const mdp_vsync_groups[] = {
+       "gpio8", "gpio9", "gpio10", "gpio81", "gpio82",
+};
+
+static const char * const edp_lcd_groups[] = {
+       "gpio9",
+};
+
+static const char * const qup10_groups[] = {
+       "gpio9", "gpio10", "gpio11", "gpio12",
+};
+
+static const char * const m_voc_groups[] = {
+       "gpio10",
+};
+
+static const char * const edp_hot_groups[] = {
+       "gpio10",
+};
+
+static const char * const cam_mclk_groups[] = {
+       "gpio13", "gpio14", "gpio15", "gpio16",
+};
+
+static const char * const qdss_groups[] = {
+       "gpio13", "gpio14", "gpio15", "gpio16", "gpio17",
+       "gpio18", "gpio19", "gpio20", "gpio21", "gpio22",
+       "gpio23", "gpio24", "gpio25", "gpio26", "gpio27",
+       "gpio28", "gpio29", "gpio30", "gpio31", "gpio32",
+       "gpio33", "gpio39", "gpio40", "gpio41", "gpio42",
+       "gpio47", "gpio48", "gpio83", "gpio117", "gpio118",
+       "gpio119", "gpio120", "gpio121", "gpio132",
+       "gpio133", "gpio134",
+};
+
+static const char * const cci_i2c_groups[] = {
+       "gpio17", "gpio18", "gpio19", "gpio20", "gpio31", "gpio32", "gpio33",
+       "gpio34",
+};
+
+static const char * const cci_timer0_groups[] = {
+       "gpio21",
+};
+
+static const char * const gcc_gp2_groups[] = {
+       "gpio21", "gpio137",
+};
+
+static const char * const cci_timer1_groups[] = {
+       "gpio22",
+};
+
+static const char * const gcc_gp3_groups[] = {
+       "gpio22", "gpio138",
+};
+
+static const char * const cci_timer2_groups[] = {
+       "gpio23",
+};
+
+static const char * const qup18_groups[] = {
+       "gpio23", "gpio24", "gpio25", "gpio26",
+};
+
+static const char * const cci_timer3_groups[] = {
+       "gpio24",
+};
+
+static const char * const cci_async_groups[] = {
+       "gpio24", "gpio25", "gpio26",
+};
+
+static const char * const cci_timer4_groups[] = {
+       "gpio25",
+};
+
+static const char * const qup15_groups[] = {
+       "gpio27", "gpio28", "gpio29", "gpio30",
+};
+
+static const char * const pci_e0_groups[] = {
+       "gpio35", "gpio36",
+};
+
+static const char * const qup_l4_groups[] = {
+       "gpio37", "gpio59", "gpio81", "gpio95",
+};
+
+static const char * const agera_pll_groups[] = {
+       "gpio37",
+};
+
+static const char * const usb_phy_groups[] = {
+       "gpio38",
+};
+
+static const char * const qup9_groups[] = {
+       "gpio39", "gpio40", "gpio41", "gpio42",
+};
+
+static const char * const qup13_groups[] = {
+       "gpio43", "gpio44", "gpio45", "gpio46",
+};
+
+static const char * const qdss_cti_groups[] = {
+       "gpio45", "gpio46", "gpio49", "gpio50", "gpio56", "gpio57", "gpio58",
+       "gpio58",
+};
+
+static const char * const qup14_groups[] = {
+       "gpio47", "gpio48", "gpio49", "gpio50",
+};
+
+static const char * const qup4_groups[] = {
+       "gpio51", "gpio52", "gpio53", "gpio54",
+};
+
+static const char * const qup17_groups[] = {
+       "gpio55", "gpio56", "gpio57", "gpio58",
+};
+
+static const char * const qup19_groups[] = {
+       "gpio55", "gpio56", "gpio57", "gpio58",
+};
+
+static const char * const atest_char_groups[] = {
+       "gpio59",
+};
+
+static const char * const nav_pps_groups[] = {
+       "gpio60", "gpio60", "gpio76", "gpio76", "gpio77", "gpio77", "gpio81",
+       "gpio81", "gpio82", "gpio82",
+};
+
+static const char * const atest_usb2_groups[] = {
+       "gpio60",
+};
+
+static const char * const qlink_request_groups[] = {
+       "gpio61",
+};
+
+static const char * const qlink_enable_groups[] = {
+       "gpio62",
+};
+
+static const char * const wmss_reset_groups[] = {
+       "gpio63",
+};
+
+static const char * const atest_usb23_groups[] = {
+       "gpio63",
+};
+
+static const char * const pa_indicator_groups[] = {
+       "gpio68",
+};
+
+static const char * const mss_lte_groups[] = {
+       "gpio69", "gpio70",
+};
+
+static const struct msm_function sm8150_functions[] = {
+       FUNCTION(adsp_ext),
+       FUNCTION(agera_pll),
+       FUNCTION(aoss_cti),
+       FUNCTION(ddr_pxi2),
+       FUNCTION(atest_char),
+       FUNCTION(atest_char0),
+       FUNCTION(atest_char1),
+       FUNCTION(atest_char2),
+       FUNCTION(atest_char3),
+       FUNCTION(audio_ref),
+       FUNCTION(atest_usb1),
+       FUNCTION(atest_usb2),
+       FUNCTION(atest_usb10),
+       FUNCTION(atest_usb11),
+       FUNCTION(atest_usb12),
+       FUNCTION(atest_usb13),
+       FUNCTION(atest_usb20),
+       FUNCTION(atest_usb21),
+       FUNCTION(atest_usb22),
+       FUNCTION(atest_usb23),
+       FUNCTION(btfm_slimbus),
+       FUNCTION(cam_mclk),
+       FUNCTION(cci_async),
+       FUNCTION(cci_i2c),
+       FUNCTION(cci_timer0),
+       FUNCTION(cci_timer1),
+       FUNCTION(cci_timer2),
+       FUNCTION(cci_timer3),
+       FUNCTION(cci_timer4),
+       FUNCTION(cri_trng),
+       FUNCTION(cri_trng0),
+       FUNCTION(cri_trng1),
+       FUNCTION(dbg_out),
+       FUNCTION(ddr_bist),
+       FUNCTION(ddr_pxi0),
+       FUNCTION(ddr_pxi1),
+       FUNCTION(ddr_pxi3),
+       FUNCTION(edp_hot),
+       FUNCTION(edp_lcd),
+       FUNCTION(emac_phy),
+       FUNCTION(emac_pps),
+       FUNCTION(gcc_gp1),
+       FUNCTION(gcc_gp2),
+       FUNCTION(gcc_gp3),
+       FUNCTION(gpio),
+       FUNCTION(hs1_mi2s),
+       FUNCTION(hs2_mi2s),
+       FUNCTION(hs3_mi2s),
+       FUNCTION(jitter_bist),
+       FUNCTION(lpass_slimbus),
+       FUNCTION(mdp_vsync),
+       FUNCTION(mdp_vsync0),
+       FUNCTION(mdp_vsync1),
+       FUNCTION(mdp_vsync2),
+       FUNCTION(mdp_vsync3),
+       FUNCTION(mss_lte),
+       FUNCTION(m_voc),
+       FUNCTION(nav_pps),
+       FUNCTION(pa_indicator),
+       FUNCTION(pci_e0),
+       FUNCTION(phase_flag),
+       FUNCTION(pll_bypassnl),
+       FUNCTION(pll_bist),
+       FUNCTION(pci_e1),
+       FUNCTION(pll_reset),
+       FUNCTION(pri_mi2s),
+       FUNCTION(pri_mi2s_ws),
+       FUNCTION(prng_rosc),
+       FUNCTION(qdss),
+       FUNCTION(qdss_cti),
+       FUNCTION(qlink_request),
+       FUNCTION(qlink_enable),
+       FUNCTION(qspi0),
+       FUNCTION(qspi1),
+       FUNCTION(qspi2),
+       FUNCTION(qspi3),
+       FUNCTION(qspi_clk),
+       FUNCTION(qspi_cs),
+       FUNCTION(qua_mi2s),
+       FUNCTION(qup0),
+       FUNCTION(qup1),
+       FUNCTION(qup2),
+       FUNCTION(qup3),
+       FUNCTION(qup4),
+       FUNCTION(qup5),
+       FUNCTION(qup6),
+       FUNCTION(qup7),
+       FUNCTION(qup8),
+       FUNCTION(qup9),
+       FUNCTION(qup10),
+       FUNCTION(qup11),
+       FUNCTION(qup12),
+       FUNCTION(qup13),
+       FUNCTION(qup14),
+       FUNCTION(qup15),
+       FUNCTION(qup16),
+       FUNCTION(qup17),
+       FUNCTION(qup18),
+       FUNCTION(qup19),
+       FUNCTION(qup_l4),
+       FUNCTION(qup_l5),
+       FUNCTION(qup_l6),
+       FUNCTION(rgmii),
+       FUNCTION(sdc4),
+       FUNCTION(sd_write),
+       FUNCTION(sec_mi2s),
+       FUNCTION(spkr_i2s),
+       FUNCTION(sp_cmu),
+       FUNCTION(ter_mi2s),
+       FUNCTION(tgu_ch0),
+       FUNCTION(tgu_ch1),
+       FUNCTION(tgu_ch2),
+       FUNCTION(tgu_ch3),
+       FUNCTION(tsense_pwm1),
+       FUNCTION(tsense_pwm2),
+       FUNCTION(tsif1),
+       FUNCTION(tsif2),
+       FUNCTION(uim1),
+       FUNCTION(uim2),
+       FUNCTION(uim_batt),
+       FUNCTION(usb2phy_ac),
+       FUNCTION(usb_phy),
+       FUNCTION(vfr_1),
+       FUNCTION(vsense_trigger),
+       FUNCTION(wlan1_adc0),
+       FUNCTION(wlan1_adc1),
+       FUNCTION(wlan2_adc0),
+       FUNCTION(wlan2_adc1),
+       FUNCTION(wmss_reset),
+};
+
+/*
+ * Every pin is maintained as a single group, and missing or non-existing pin
+ * would be maintained as dummy group to synchronize pin group index with
+ * pin descriptor registered with pinctrl core.
+ * Clients would not be able to request these dummy pin groups.
+ */
+static const struct msm_pingroup sm8150_groups[] = {
+       [0] = PINGROUP(0, SOUTH, qup0, _, _, _, _, _, _, _, _),
+       [1] = PINGROUP(1, SOUTH, qup0, _, _, _, _, _, _, _, _),
+       [2] = PINGROUP(2, SOUTH, qup0, _, _, _, _, _, _, _, _),
+       [3] = PINGROUP(3, SOUTH, qup0, _, _, _, _, _, _, _, _),
+       [4] = PINGROUP(4, SOUTH, qup6, rgmii, _, _, _, _, _, _, _),
+       [5] = PINGROUP(5, SOUTH, qup6, rgmii, _, _, _, _, _, _, _),
+       [6] = PINGROUP(6, SOUTH, qup6, rgmii, qup_l6, _, _, _, _, _, _),
+       [7] = PINGROUP(7, SOUTH, qup6, rgmii, qup_l5, _, _, _, _, _, _),
+       [8] = PINGROUP(8, NORTH, mdp_vsync, _, _, _, _, _, _, _, _),
+       [9] = PINGROUP(9, NORTH, mdp_vsync, edp_lcd, qup10, _, _, _, _, _, _),
+       [10] = PINGROUP(10, NORTH, mdp_vsync, m_voc, edp_hot, qup10, _, _, _, _, _),
+       [11] = PINGROUP(11, NORTH, qup10, _, _, _, _, _, _, _, _),
+       [12] = PINGROUP(12, NORTH, qup10, _, _, _, _, _, _, _, _),
+       [13] = PINGROUP(13, NORTH, cam_mclk, qdss, _, _, _, _, _, _, _),
+       [14] = PINGROUP(14, NORTH, cam_mclk, qdss, _, _, _, _, _, _, _),
+       [15] = PINGROUP(15, NORTH, cam_mclk, qdss, _, _, _, _, _, _, _),
+       [16] = PINGROUP(16, NORTH, cam_mclk, qdss, _, _, _, _, _, _, _),
+       [17] = PINGROUP(17, NORTH, cci_i2c, qdss, _, _, _, _, _, _, _),
+       [18] = PINGROUP(18, NORTH, cci_i2c, phase_flag, _, qdss, _, _, _, _, _),
+       [19] = PINGROUP(19, NORTH, cci_i2c, phase_flag, _, qdss, _, _, _, _, _),
+       [20] = PINGROUP(20, NORTH, cci_i2c, phase_flag, _, qdss, _, _, _, _, _),
+       [21] = PINGROUP(21, EAST, cci_timer0, gcc_gp2, qdss, _, _, _, _, _, _),
+       [22] = PINGROUP(22, EAST, cci_timer1, gcc_gp3, qdss, _, _, _, _, _, _),
+       [23] = PINGROUP(23, EAST, cci_timer2, qup18, qdss, _, _, _, _, _, _),
+       [24] = PINGROUP(24, EAST, cci_timer3, cci_async, qup18, qdss, _, _, _, _, _),
+       [25] = PINGROUP(25, EAST, cci_timer4, cci_async, qup18, qdss, _, _, _, _, _),
+       [26] = PINGROUP(26, EAST, cci_async, qup18, qdss, _, _, _, _, _, _),
+       [27] = PINGROUP(27, EAST, qup15, _, qdss, _, _, _, _, _, _),
+       [28] = PINGROUP(28, EAST, qup15, qdss, _, _, _, _, _, _, _),
+       [29] = PINGROUP(29, EAST, qup15, qdss, _, _, _, _, _, _, _),
+       [30] = PINGROUP(30, EAST, qup15, qdss, _, _, _, _, _, _, _),
+       [31] = PINGROUP(31, NORTH, cci_i2c, qdss, _, _, _, _, _, _, _),
+       [32] = PINGROUP(32, NORTH, cci_i2c, qdss, _, _, _, _, _, _, _),
+       [33] = PINGROUP(33, NORTH, cci_i2c, qup_l5, qdss, _, _, _, _, _, _),
+       [34] = PINGROUP(34, NORTH, cci_i2c, qup_l6, _, _, _, _, _, _, _),
+       [35] = PINGROUP(35, NORTH, pci_e0, _, _, _, _, _, _, _, _),
+       [36] = PINGROUP(36, NORTH, pci_e0, _, _, _, _, _, _, _, _),
+       [37] = PINGROUP(37, NORTH, qup_l4, agera_pll, _, _, _, _, _, _, _),
+       [38] = PINGROUP(38, SOUTH, usb_phy, _, _, _, _, _, _, _, _),
+       [39] = PINGROUP(39, NORTH, qup9, qdss, _, _, _, _, _, _, _),
+       [40] = PINGROUP(40, NORTH, qup9, qdss, _, _, _, _, _, _, _),
+       [41] = PINGROUP(41, NORTH, qup9, qdss, _, _, _, _, _, _, _),
+       [42] = PINGROUP(42, NORTH, qup9, qdss, _, _, _, _, _, _, _),
+       [43] = PINGROUP(43, EAST, qup13, _, _, _, _, _, _, _, _),
+       [44] = PINGROUP(44, EAST, qup13, _, _, _, _, _, _, _, _),
+       [45] = PINGROUP(45, EAST, qup13, qdss_cti, _, _, _, _, _, _, _),
+       [46] = PINGROUP(46, EAST, qup13, qdss_cti, _, _, _, _, _, _, _),
+       [47] = PINGROUP(47, EAST, qup14, qdss, _, _, _, _, _, _, _),
+       [48] = PINGROUP(48, EAST, qup14, qdss, _, _, _, _, _, _, _),
+       [49] = PINGROUP(49, EAST, qup14, _, qdss_cti, _, _, _, _, _, _),
+       [50] = PINGROUP(50, EAST, qup14, qdss_cti, _, _, _, _, _, _, _),
+       [51] = PINGROUP(51, SOUTH, qup4, _, _, _, _, _, _, _, _),
+       [52] = PINGROUP(52, SOUTH, qup4, _, _, _, _, _, _, _, _),
+       [53] = PINGROUP(53, SOUTH, qup4, _, _, _, _, _, _, _, _),
+       [54] = PINGROUP(54, SOUTH, qup4, _, _, _, _, _, _, _, _),
+       [55] = PINGROUP(55, SOUTH, qup17, qup19, phase_flag, _, _, _, _, _, _),
+       [56] = PINGROUP(56, SOUTH, qup17, qup19, qdss_cti, phase_flag, _, _, _, _, _),
+       [57] = PINGROUP(57, SOUTH, qup17, qup19, qdss_cti, phase_flag, _, _, _, _, _),
+       [58] = PINGROUP(58, SOUTH, qup17, qup19, qdss_cti, phase_flag, _, _, _, _, _),
+       [59] = PINGROUP(59, SOUTH, rgmii, qup_l4, phase_flag, _, atest_char, _, _, _, _),
+       [60] = PINGROUP(60, SOUTH, _, nav_pps, nav_pps, atest_usb2, _, _, _, _, _),
+       [61] = PINGROUP(61, SOUTH, qlink_request, _, _, _, _, _, _, _, _),
+       [62] = PINGROUP(62, SOUTH, qlink_enable, _, _, _, _, _, _, _, _),
+       [63] = PINGROUP(63, SOUTH, wmss_reset, atest_usb23, _, _, _, _, _, _, _),
+       [64] = PINGROUP(64, SOUTH, _, phase_flag, _, _, _, _, _, _, _),
+       [65] = PINGROUP(65, SOUTH, _, _, _, _, _, _, _, _, _),
+       [66] = PINGROUP(66, SOUTH, _, _, _, _, _, _, _, _, _),
+       [67] = PINGROUP(67, SOUTH, _, _, _, _, _, _, _, _, _),
+       [68] = PINGROUP(68, SOUTH, _, pa_indicator, phase_flag, _, _, _, _, _, _),
+       [69] = PINGROUP(69, SOUTH, mss_lte, _, _, _, _, _, _, _, _),
+       [70] = PINGROUP(70, SOUTH, mss_lte, _, _, _, _, _, _, _, _),
+       [71] = PINGROUP(71, SOUTH, _, _, _, _, _, _, _, _, _),
+       [72] = PINGROUP(72, SOUTH, _, _, _, _, _, _, _, _, _),
+       [73] = PINGROUP(73, SOUTH, _, _, _, _, _, _, _, _, _),
+       [74] = PINGROUP(74, SOUTH, _, _, _, _, _, _, _, _, _),
+       [75] = PINGROUP(75, SOUTH, _, _, _, _, _, _, _, _, _),
+       [76] = PINGROUP(76, SOUTH, _, _, _, nav_pps, nav_pps, phase_flag, _, _, _),
+       [77] = PINGROUP(77, SOUTH, _, _, _, nav_pps, nav_pps, _, _, _, _),
+       [78] = PINGROUP(78, SOUTH, _, _, _, _, _, _, _, _, _),
+       [79] = PINGROUP(79, SOUTH, _, _, phase_flag, _, _, _, _, _, _),
+       [80] = PINGROUP(80, SOUTH, _, _, phase_flag, _, _, _, _, _, _),
+       [81] = PINGROUP(81, SOUTH, _, _, _, nav_pps, nav_pps, qup_l4, mdp_vsync, emac_pps, _),
+       [82] = PINGROUP(82, SOUTH, _, _, _, nav_pps, nav_pps, qup_l5, mdp_vsync, _, _),
+       [83] = PINGROUP(83, NORTH, qup12, qup16, _, qdss, _, _, _, _, _),
+       [84] = PINGROUP(84, NORTH, qup12, qup16, _, _, _, _, _, _, _),
+       [85] = PINGROUP(85, NORTH, qup12, qup16, _, _, _, _, _, _, _),
+       [86] = PINGROUP(86, NORTH, qup12, qup16, _, _, _, _, _, _, _),
+       [87] = PINGROUP(87, EAST, _, _, _, _, _, _, _, _, _),
+       [88] = PINGROUP(88, NORTH, tsif1, qup8, qspi_cs, tgu_ch3, _, _, _, _, _),
+       [89] = PINGROUP(89, NORTH, tsif1, qup8, qspi0, mdp_vsync0, mdp_vsync1, mdp_vsync2, mdp_vsync3, tgu_ch0, _),
+       [90] = PINGROUP(90, NORTH, tsif1, qup8, qspi1, sdc4, phase_flag, tgu_ch1, _, _, wlan1_adc1),
+       [91] = PINGROUP(91, NORTH, tsif1, qup8, qspi2, sdc4, vfr_1, phase_flag, tgu_ch2, _, _),
+       [92] = PINGROUP(92, NORTH, tsif2, qup11, qspi_clk, sdc4, phase_flag, _, wlan2_adc1, _, _),
+       [93] = PINGROUP(93, NORTH, tsif2, qup11, qspi3, sdc4, phase_flag, _, wlan2_adc0, _, _),
+       [94] = PINGROUP(94, NORTH, tsif2, qup11, qspi_cs, sdc4, phase_flag, _, _, _, _),
+       [95] = PINGROUP(95, NORTH, tsif2, qup11, sdc4, qup_l4, _, _, _, _, _),
+       [96] = PINGROUP(96, NORTH, tsif2, qup_l5, phase_flag, _, _, _, _, _, _),
+       [97] = PINGROUP(97, NORTH, sd_write, tsif1, qup_l6, _, _, _, _, _, _),
+       [98] = PINGROUP(98, SOUTH, qup7, ddr_bist, ddr_pxi3, _, _, _, _, _, _),
+       [99] = PINGROUP(99, SOUTH, qup7, ddr_bist, atest_usb13, ddr_pxi1, _, _, _, _, _),
+       [100] = PINGROUP(100, SOUTH, qup7, pll_bypassnl, atest_usb12, ddr_pxi1, _, _, _, _, _),
+       [101] = PINGROUP(101, SOUTH, qup7, pll_reset, ddr_pxi3, _, _, _, _, _, _),
+       [102] = PINGROUP(102, NORTH, pci_e1, _, _, _, _, _, _, _, _),
+       [103] = PINGROUP(103, NORTH, pci_e1, _, _, _, _, _, _, _, _),
+       [104] = PINGROUP(104, NORTH, _, _, _, _, _, _, _, _, _),
+       [105] = PINGROUP(105, WEST, uim2, _, _, _, _, _, _, _, _),
+       [106] = PINGROUP(106, WEST, uim2, _, _, _, _, _, _, _, _),
+       [107] = PINGROUP(107, WEST, uim2, _, _, _, _, _, _, _, _),
+       [108] = PINGROUP(108, WEST, uim2, _, _, _, _, _, _, _, _),
+       [109] = PINGROUP(109, WEST, uim1, _, _, _, _, _, _, _, _),
+       [110] = PINGROUP(110, WEST, uim1, _, _, _, _, _, _, _, _),
+       [111] = PINGROUP(111, WEST, uim1, _, _, _, _, _, _, _, _),
+       [112] = PINGROUP(112, WEST, uim1, _, _, _, _, _, _, _, _),
+       [113] = PINGROUP(113, WEST, uim_batt, usb2phy_ac, aoss_cti, _, _, _, _, _, _),
+       [114] = PINGROUP(114, SOUTH, qup1, rgmii, phase_flag, _, _, _, _, _, _),
+       [115] = PINGROUP(115, SOUTH, qup1, rgmii, phase_flag, adsp_ext, _, _, _, _, _),
+       [116] = PINGROUP(116, SOUTH, qup1, rgmii, phase_flag, _, _, _, _, _, _),
+       [117] = PINGROUP(117, SOUTH, qup1, rgmii, phase_flag, _, qdss, _, _, _, _),
+       [118] = PINGROUP(118, SOUTH, rgmii, phase_flag, _, qdss, _, _, _, _, _),
+       [119] = PINGROUP(119, SOUTH, qup5, rgmii, phase_flag, _, qdss, _, _, _, _),
+       [120] = PINGROUP(120, SOUTH, qup5, rgmii, phase_flag, _, qdss, _, _, _, _),
+       [121] = PINGROUP(121, SOUTH, qup5, rgmii, phase_flag, _, qdss, _, _, _, _),
+       [122] = PINGROUP(122, SOUTH, qup5, rgmii, phase_flag, _, _, _, _, _, _),
+       [123] = PINGROUP(123, SOUTH, usb2phy_ac, qup_l6, atest_usb22, _, _, _, _, _, _),
+       [124] = PINGROUP(124, SOUTH, emac_phy, _, _, _, _, _, _, _, _),
+       [125] = PINGROUP(125, WEST, hs3_mi2s, _, _, _, _, _, _, _, _),
+       [126] = PINGROUP(126, SOUTH, sec_mi2s, qup2, phase_flag, _, _, _, _, _, _),
+       [127] = PINGROUP(127, SOUTH, sec_mi2s, qup2, phase_flag, _, _, _, _, _, _),
+       [128] = PINGROUP(128, SOUTH, sec_mi2s, qup2, phase_flag, _, _, _, _, _, _),
+       [129] = PINGROUP(129, SOUTH, sec_mi2s, qup2, jitter_bist, atest_usb21, _, _, _, _, _),
+       [130] = PINGROUP(130, SOUTH, sec_mi2s, pll_bist, atest_usb20, atest_char0, _, _, _, _, _),
+       [131] = PINGROUP(131, SOUTH, ter_mi2s, gcc_gp1, _, _, _, _, _, _, _),
+       [132] = PINGROUP(132, SOUTH, ter_mi2s, _, qdss, _, _, _, _, _, _),
+       [133] = PINGROUP(133, SOUTH, ter_mi2s, qdss, atest_char1, _, _, _, _, _, _),
+       [134] = PINGROUP(134, SOUTH, ter_mi2s, qdss, atest_char2, _, _, _, _, _, _),
+       [135] = PINGROUP(135, SOUTH, ter_mi2s, atest_char3, _, _, _, _, _, _, _),
+       [136] = PINGROUP(136, SOUTH, qua_mi2s, gcc_gp1, _, _, _, _, _, _, _),
+       [137] = PINGROUP(137, SOUTH, qua_mi2s, gcc_gp2, _, _, _, _, _, _, _),
+       [138] = PINGROUP(138, SOUTH, qua_mi2s, gcc_gp3, _, _, _, _, _, _, _),
+       [139] = PINGROUP(139, SOUTH, qua_mi2s, _, _, _, _, _, _, _, _),
+       [140] = PINGROUP(140, SOUTH, qua_mi2s, _, _, _, _, _, _, _, _),
+       [141] = PINGROUP(141, SOUTH, qua_mi2s, _, _, _, _, _, _, _, _),
+       [142] = PINGROUP(142, SOUTH, qua_mi2s, _, _, _, _, _, _, _, _),
+       [143] = PINGROUP(143, SOUTH, pri_mi2s, _, _, _, _, _, _, _, _),
+       [144] = PINGROUP(144, SOUTH, pri_mi2s, qup3, phase_flag, _, ddr_pxi0, _, _, _, _),
+       [145] = PINGROUP(145, SOUTH, pri_mi2s_ws, qup3, phase_flag, ddr_bist, _, vsense_trigger, atest_usb1, ddr_pxi0, _),
+       [146] = PINGROUP(146, SOUTH, pri_mi2s, qup3, ddr_bist, atest_usb11, ddr_pxi2, _, _, _, _),
+       [147] = PINGROUP(147, SOUTH, pri_mi2s, qup3, dbg_out, atest_usb10, ddr_pxi2, _, _, _, _),
+       [148] = PINGROUP(148, SOUTH, spkr_i2s, audio_ref, _, _, _, _, _, _, _),
+       [149] = PINGROUP(149, SOUTH, lpass_slimbus, spkr_i2s, _, _, _, _, _, _, _),
+       [150] = PINGROUP(150, SOUTH, lpass_slimbus, spkr_i2s, tsense_pwm1, tsense_pwm2, _, _, _, _, _),
+       [151] = PINGROUP(151, SOUTH, lpass_slimbus, spkr_i2s, _, _, _, _, _, _, _),
+       [152] = PINGROUP(152, SOUTH, lpass_slimbus, spkr_i2s, _, _, _, _, _, _, _),
+       [153] = PINGROUP(153, SOUTH, btfm_slimbus, _, _, _, _, _, _, _, _),
+       [154] = PINGROUP(154, SOUTH, btfm_slimbus, _, _, _, _, _, _, _, _),
+       [155] = PINGROUP(155, WEST, hs1_mi2s, _, _, _, _, _, _, _, _),
+       [156] = PINGROUP(156, WEST, hs1_mi2s, _, _, _, _, _, _, _, _),
+       [157] = PINGROUP(157, WEST, hs1_mi2s, _, _, _, _, _, _, _, _),
+       [158] = PINGROUP(158, WEST, hs1_mi2s, _, _, _, _, _, _, _, _),
+       [159] = PINGROUP(159, WEST, hs1_mi2s, cri_trng0, _, _, _, _, _, _, _),
+       [160] = PINGROUP(160, WEST, hs2_mi2s, cri_trng1, _, _, _, _, _, _, _),
+       [161] = PINGROUP(161, WEST, hs2_mi2s, cri_trng, _, _, _, _, _, _, _),
+       [162] = PINGROUP(162, WEST, hs2_mi2s, sp_cmu, _, _, _, _, _, _, _),
+       [163] = PINGROUP(163, WEST, hs2_mi2s, prng_rosc, _, _, _, _, _, _, _),
+       [164] = PINGROUP(164, WEST, hs2_mi2s, _, _, _, _, _, _, _, _),
+       [165] = PINGROUP(165, WEST, hs3_mi2s, _, _, _, _, _, _, _, _),
+       [166] = PINGROUP(166, WEST, hs3_mi2s, _, _, _, _, _, _, _, _),
+       [167] = PINGROUP(167, WEST, hs3_mi2s, _, _, _, _, _, _, _, _),
+       [168] = PINGROUP(168, WEST, hs3_mi2s, _, _, _, _, _, _, _, _),
+       [169] = PINGROUP(169, NORTH, _, _, _, _, _, _, _, _, _),
+       [170] = PINGROUP(170, NORTH, _, _, _, _, _, _, _, _, _),
+       [171] = PINGROUP(171, NORTH, _, _, _, _, _, _, _, _, _),
+       [172] = PINGROUP(172, NORTH, _, _, _, _, _, _, _, _, _),
+       [173] = PINGROUP(173, NORTH, _, _, _, _, _, _, _, _, _),
+       [174] = PINGROUP(174, NORTH, _, _, _, _, _, _, _, _, _),
+       [175] = UFS_RESET(ufs_reset, 0xB6000),
+       [176] = SDC_QDSD_PINGROUP(sdc2_clk, 0xB2000, 14, 6),
+       [177] = SDC_QDSD_PINGROUP(sdc2_cmd, 0xB2000, 11, 3),
+       [178] = SDC_QDSD_PINGROUP(sdc2_data, 0xB2000, 9, 0),
+};
+
+static const struct msm_pinctrl_soc_data sm8150_pinctrl = {
+       .pins = sm8150_pins,
+       .npins = ARRAY_SIZE(sm8150_pins),
+       .functions = sm8150_functions,
+       .nfunctions = ARRAY_SIZE(sm8150_functions),
+       .groups = sm8150_groups,
+       .ngroups = ARRAY_SIZE(sm8150_groups),
+       .ngpios = 176,
+       .tiles = sm8150_tiles,
+       .ntiles = ARRAY_SIZE(sm8150_tiles),
+};
+
+static int sm8150_pinctrl_probe(struct platform_device *pdev)
+{
+       return msm_pinctrl_probe(pdev, &sm8150_pinctrl);
+}
+
+static const struct of_device_id sm8150_pinctrl_of_match[] = {
+       { .compatible = "qcom,sm8150-pinctrl", },
+       { },
+};
+
+static struct platform_driver sm8150_pinctrl_driver = {
+       .driver = {
+               .name = "sm8150-pinctrl",
+               .of_match_table = sm8150_pinctrl_of_match,
+       },
+       .probe = sm8150_pinctrl_probe,
+       .remove = msm_pinctrl_remove,
+};
+
+static int __init sm8150_pinctrl_init(void)
+{
+       return platform_driver_register(&sm8150_pinctrl_driver);
+}
+arch_initcall(sm8150_pinctrl_init);
+
+static void __exit sm8150_pinctrl_exit(void)
+{
+       platform_driver_unregister(&sm8150_pinctrl_driver);
+}
+module_exit(sm8150_pinctrl_exit);
+
+MODULE_DESCRIPTION("QTI sm8150 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, sm8150_pinctrl_of_match);
index 3f989f5..b8640ad 100644 (file)
@@ -717,7 +717,7 @@ static int sh_pfc_suspend_init(struct sh_pfc *pfc) { return 0; }
 #endif /* CONFIG_PM_SLEEP && CONFIG_ARM_PSCI_FW */
 
 #ifdef DEBUG
-static bool is0s(const u16 *enum_ids, unsigned int n)
+static bool __init is0s(const u16 *enum_ids, unsigned int n)
 {
        unsigned int i;
 
@@ -728,11 +728,11 @@ static bool is0s(const u16 *enum_ids, unsigned int n)
        return true;
 }
 
-static unsigned int sh_pfc_errors;
-static unsigned int sh_pfc_warnings;
+static unsigned int sh_pfc_errors __initdata = 0;
+static unsigned int sh_pfc_warnings __initdata = 0;
 
-static void sh_pfc_check_cfg_reg(const char *drvname,
-                                const struct pinmux_cfg_reg *cfg_reg)
+static void __init sh_pfc_check_cfg_reg(const char *drvname,
+                                       const struct pinmux_cfg_reg *cfg_reg)
 {
        unsigned int i, n, rw, fw;
 
@@ -764,7 +764,7 @@ static void sh_pfc_check_cfg_reg(const char *drvname,
        }
 }
 
-static void sh_pfc_check_info(const struct sh_pfc_soc_info *info)
+static void __init sh_pfc_check_info(const struct sh_pfc_soc_info *info)
 {
        const struct sh_pfc_function *func;
        const char *drvname = info->name;
@@ -773,6 +773,35 @@ static void sh_pfc_check_info(const struct sh_pfc_soc_info *info)
 
        pr_info("Checking %s\n", drvname);
 
+       /* Check pins */
+       for (i = 0; i < info->nr_pins; i++) {
+               for (j = 0; j < i; j++) {
+                       if (!strcmp(info->pins[i].name, info->pins[j].name)) {
+                               pr_err("%s: pin %s/%s: name conflict\n",
+                                      drvname, info->pins[i].name,
+                                      info->pins[j].name);
+                               sh_pfc_errors++;
+                       }
+
+                       if (info->pins[i].pin != (u16)-1 &&
+                           info->pins[i].pin == info->pins[j].pin) {
+                               pr_err("%s: pin %s/%s: pin %u conflict\n",
+                                      drvname, info->pins[i].name,
+                                      info->pins[j].name, info->pins[i].pin);
+                               sh_pfc_errors++;
+                       }
+
+                       if (info->pins[i].enum_id &&
+                           info->pins[i].enum_id == info->pins[j].enum_id) {
+                               pr_err("%s: pin %s/%s: enum_id %u conflict\n",
+                                      drvname, info->pins[i].name,
+                                      info->pins[j].name,
+                                      info->pins[i].enum_id);
+                               sh_pfc_errors++;
+                       }
+               }
+       }
+
        /* Check groups and functions */
        refcnts = kcalloc(info->nr_groups, sizeof(*refcnts), GFP_KERNEL);
        if (!refcnts)
@@ -780,9 +809,15 @@ static void sh_pfc_check_info(const struct sh_pfc_soc_info *info)
 
        for (i = 0; i < info->nr_functions; i++) {
                func = &info->functions[i];
+               if (!func->name) {
+                       pr_err("%s: empty function %u\n", drvname, i);
+                       sh_pfc_errors++;
+                       continue;
+               }
                for (j = 0; j < func->nr_groups; j++) {
                        for (k = 0; k < info->nr_groups; k++) {
-                               if (!strcmp(func->groups[j],
+                               if (info->groups[k].name &&
+                                   !strcmp(func->groups[j],
                                            info->groups[k].name)) {
                                        refcnts[k]++;
                                        break;
@@ -798,13 +833,18 @@ static void sh_pfc_check_info(const struct sh_pfc_soc_info *info)
        }
 
        for (i = 0; i < info->nr_groups; i++) {
+               if (!info->groups[i].name) {
+                       pr_err("%s: empty group %u\n", drvname, i);
+                       sh_pfc_errors++;
+                       continue;
+               }
                if (!refcnts[i]) {
                        pr_err("%s: orphan group %s\n", drvname,
                               info->groups[i].name);
                        sh_pfc_errors++;
                } else if (refcnts[i] > 1) {
-                       pr_err("%s: group %s referred by %u functions\n",
-                              drvname, info->groups[i].name, refcnts[i]);
+                       pr_warn("%s: group %s referenced by %u functions\n",
+                               drvname, info->groups[i].name, refcnts[i]);
                        sh_pfc_warnings++;
                }
        }
@@ -816,7 +856,7 @@ static void sh_pfc_check_info(const struct sh_pfc_soc_info *info)
                sh_pfc_check_cfg_reg(drvname, &info->cfg_regs[i]);
 }
 
-static void sh_pfc_check_driver(const struct platform_driver *pdrv)
+static void __init sh_pfc_check_driver(const struct platform_driver *pdrv)
 {
        unsigned int i;
 
index 0af1ef8..6c66fc3 100644 (file)
        PORT_1(155, fn, pfx##155, sfx), PORT_1(156, fn, pfx##156, sfx), \
        PORT_1(157, fn, pfx##157, sfx), PORT_1(158, fn, pfx##158, sfx)
 
+#define CPU_ALL_NOGP(fn)               \
+       PIN_NOGP(LCD3_B2, "B15", fn),   \
+       PIN_NOGP(LCD3_B3, "C15", fn),   \
+       PIN_NOGP(LCD3_B4, "D15", fn),   \
+       PIN_NOGP(LCD3_B5, "B14", fn),   \
+       PIN_NOGP(LCD3_B6, "C14", fn),   \
+       PIN_NOGP(LCD3_B7, "D14", fn),   \
+       PIN_NOGP(LCD3_G2, "B17", fn),   \
+       PIN_NOGP(LCD3_G3, "C17", fn),   \
+       PIN_NOGP(LCD3_G4, "D17", fn),   \
+       PIN_NOGP(LCD3_G5, "B16", fn),   \
+       PIN_NOGP(LCD3_G6, "C16", fn),   \
+       PIN_NOGP(LCD3_G7, "D16", fn)
+
 enum {
        PINMUX_RESERVED = 0,
 
@@ -218,10 +232,13 @@ enum {
        PINMUX_MARK_END,
 };
 
-/* Pin numbers for pins without a corresponding GPIO port number are computed
- * from the row and column numbers with a 1000 offset to avoid collisions with
- * GPIO port numbers. */
-#define PIN_NUMBER(row, col)            (1000+((row)-1)*23+(col)-1)
+/*
+ * Pins not associated with a GPIO port.
+ */
+enum {
+       PORT_ASSIGN_LAST(),
+       NOGP_ALL(),
+};
 
 /* Expand to a list of sh_pfc_pin entries (named PORT#).
  * NOTE: No config are recorded since the driver do not handle pinconf. */
@@ -230,20 +247,7 @@ enum {
 
 static const struct sh_pfc_pin pinmux_pins[] = {
        PINMUX_EMEV_GPIO_ALL(),
-
-       /* Pins not associated with a GPIO port */
-       SH_PFC_PIN_NAMED(2, 14, B14),
-       SH_PFC_PIN_NAMED(2, 15, B15),
-       SH_PFC_PIN_NAMED(2, 16, B16),
-       SH_PFC_PIN_NAMED(2, 17, B17),
-       SH_PFC_PIN_NAMED(3, 14, C14),
-       SH_PFC_PIN_NAMED(3, 15, C15),
-       SH_PFC_PIN_NAMED(3, 16, C16),
-       SH_PFC_PIN_NAMED(3, 17, C17),
-       SH_PFC_PIN_NAMED(4, 14, D14),
-       SH_PFC_PIN_NAMED(4, 15, D15),
-       SH_PFC_PIN_NAMED(4, 16, D16),
-       SH_PFC_PIN_NAMED(4, 17, D17),
+       PINMUX_NOGP_ALL(),
 };
 
 /* Expand to a list of name_DATA, name_FN marks */
@@ -829,12 +833,10 @@ static const unsigned int lcd3_rgb888_pins[] = {
        /* R[0:7], G[0:7], B[0:7] */
        32, 33, 34, 35,
        36, 37, 38, 39,
-       40, 41, PIN_NUMBER(2, 17), PIN_NUMBER(3, 17),
-       PIN_NUMBER(4, 17), PIN_NUMBER(2, 16), PIN_NUMBER(3, 16),
-       PIN_NUMBER(4, 16),
-       42, 43, PIN_NUMBER(2, 15), PIN_NUMBER(3, 15),
-       PIN_NUMBER(4, 15), PIN_NUMBER(2, 14), PIN_NUMBER(3, 14),
-       PIN_NUMBER(4, 14)
+       40, 41, PIN_LCD3_G2, PIN_LCD3_G3,
+       PIN_LCD3_G4, PIN_LCD3_G5, PIN_LCD3_G6, PIN_LCD3_G7,
+       42, 43, PIN_LCD3_B2, PIN_LCD3_B3,
+       PIN_LCD3_B4, PIN_LCD3_B5, PIN_LCD3_B6, PIN_LCD3_B7
 };
 static const unsigned int lcd3_rgb888_mux[] = {
        LCD3_R0_MARK, LCD3_R1_MARK, LCD3_R2_MARK, LCD3_R3_MARK,
@@ -850,12 +852,10 @@ static const unsigned int yuv3_pins[] = {
        /* CLK_O, HS, VS, DE */
        18, 21, 22, 23,
        /* YUV3_D[0:15] */
-       40, 41, PIN_NUMBER(2, 17), PIN_NUMBER(3, 17),
-       PIN_NUMBER(4, 17), PIN_NUMBER(2, 16), PIN_NUMBER(3, 16),
-       PIN_NUMBER(4, 16),
-       42, 43, PIN_NUMBER(2, 15), PIN_NUMBER(3, 15),
-       PIN_NUMBER(4, 15), PIN_NUMBER(2, 14), PIN_NUMBER(3, 14),
-       PIN_NUMBER(4, 14),
+       40, 41, PIN_LCD3_G2, PIN_LCD3_G3,
+       PIN_LCD3_G4, PIN_LCD3_G5, PIN_LCD3_G6, PIN_LCD3_G7,
+       42, 43, PIN_LCD3_B2, PIN_LCD3_B3,
+       PIN_LCD3_B4, PIN_LCD3_B5, PIN_LCD3_B6, PIN_LCD3_B7,
 };
 static const unsigned int yuv3_mux[] = {
        YUV3_CLK_O_MARK, YUV3_HS_MARK, YUV3_VS_MARK, YUV3_DE_MARK,
@@ -972,12 +972,10 @@ static const unsigned int tp33_pins[] = {
        /* CLK, CTRL */
        38, 39,
        /* TP33_DATA[0:15] */
-       40, 41, PIN_NUMBER(2, 17), PIN_NUMBER(3, 17),
-       PIN_NUMBER(4, 17), PIN_NUMBER(2, 16), PIN_NUMBER(3, 16),
-       PIN_NUMBER(4, 16),
-       42, 43, PIN_NUMBER(2, 15), PIN_NUMBER(3, 15),
-       PIN_NUMBER(4, 15), PIN_NUMBER(2, 14), PIN_NUMBER(3, 14),
-       PIN_NUMBER(4, 14),
+       40, 41, PIN_LCD3_G2, PIN_LCD3_G3,
+       PIN_LCD3_G4, PIN_LCD3_G5, PIN_LCD3_G6, PIN_LCD3_G7,
+       42, 43, PIN_LCD3_B2, PIN_LCD3_B3,
+       PIN_LCD3_B4, PIN_LCD3_B5, PIN_LCD3_B6, PIN_LCD3_B7,
 };
 static const unsigned int tp33_mux[] = {
        TP33_CLK_MARK, TP33_CTRL_MARK,
index bf12849..b21f5af 100644 (file)
@@ -1252,7 +1252,7 @@ static const u16 pinmux_data[] = {
 
 #define __O    (SH_PFC_PIN_CFG_OUTPUT)
 #define __IO   (SH_PFC_PIN_CFG_INPUT | SH_PFC_PIN_CFG_OUTPUT)
-#define __PUD  (SH_PFC_PIN_CFG_PULL_DOWN | SH_PFC_PIN_CFG_PULL_UP)
+#define __PUD  (SH_PFC_PIN_CFG_PULL_UP_DOWN)
 
 #define R8A73A4_PIN_IO_PU_PD(pin)       SH_PFC_PIN_CFG(pin, __IO | __PUD)
 #define R8A73A4_PIN_O(pin)              SH_PFC_PIN_CFG(pin, __O)
index 696a0f6..fdf1b0f 100644 (file)
@@ -1515,7 +1515,7 @@ static const u16 pinmux_data[] = {
 #define __IO           (SH_PFC_PIN_CFG_INPUT | SH_PFC_PIN_CFG_OUTPUT)
 #define __PD           (SH_PFC_PIN_CFG_PULL_DOWN)
 #define __PU           (SH_PFC_PIN_CFG_PULL_UP)
-#define __PUD          (SH_PFC_PIN_CFG_PULL_DOWN | SH_PFC_PIN_CFG_PULL_UP)
+#define __PUD          (SH_PFC_PIN_CFG_PULL_UP_DOWN)
 
 #define R8A7740_PIN_I_PD(pin)          SH_PFC_PIN_CFG(pin, __I | __PD)
 #define R8A7740_PIN_I_PU(pin)          SH_PFC_PIN_CFG(pin, __I | __PU)
index c05dc14..b3b116d 100644 (file)
@@ -10,7 +10,7 @@
 
 #include "sh_pfc.h"
 
-#define CPU_ALL_PORT(fn, sfx)                                          \
+#define CPU_ALL_GP(fn, sfx)                                            \
        PORT_GP_4(0, fn, sfx),                                          \
        PORT_GP_1(0, 4, fn, sfx),                                       \
        PORT_GP_CFG_1(0,  5, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE),       \
index 49fe52d..24866a5 100644 (file)
 #define PORT_GP_PUP_1(bank, pin, fn, sfx)      \
        PORT_GP_CFG_1(bank, pin, fn, sfx, SH_PFC_PIN_CFG_PULL_UP)
 
-#define PORT_GP_PUP_27(bank, fn, sfx)                                  \
-       PORT_GP_PUP_1(bank, 0,  fn, sfx), PORT_GP_PUP_1(bank, 1,  fn, sfx),     \
-       PORT_GP_PUP_1(bank, 2,  fn, sfx), PORT_GP_PUP_1(bank, 3,  fn, sfx),     \
-       PORT_GP_PUP_1(bank, 4,  fn, sfx), PORT_GP_PUP_1(bank, 5,  fn, sfx),     \
-       PORT_GP_PUP_1(bank, 6,  fn, sfx), PORT_GP_PUP_1(bank, 7,  fn, sfx),     \
-       PORT_GP_PUP_1(bank, 8,  fn, sfx), PORT_GP_PUP_1(bank, 9,  fn, sfx),     \
-       PORT_GP_PUP_1(bank, 10, fn, sfx), PORT_GP_PUP_1(bank, 11, fn, sfx),     \
-       PORT_GP_PUP_1(bank, 12, fn, sfx), PORT_GP_PUP_1(bank, 13, fn, sfx),     \
-       PORT_GP_PUP_1(bank, 14, fn, sfx), PORT_GP_PUP_1(bank, 15, fn, sfx),     \
-       PORT_GP_PUP_1(bank, 16, fn, sfx), PORT_GP_PUP_1(bank, 17, fn, sfx),     \
-       PORT_GP_PUP_1(bank, 18, fn, sfx), PORT_GP_PUP_1(bank, 19, fn, sfx),     \
-       PORT_GP_PUP_1(bank, 20, fn, sfx), PORT_GP_PUP_1(bank, 21, fn, sfx),     \
-       PORT_GP_PUP_1(bank, 22, fn, sfx), PORT_GP_PUP_1(bank, 23, fn, sfx),     \
-       PORT_GP_PUP_1(bank, 24, fn, sfx), PORT_GP_PUP_1(bank, 25, fn, sfx),     \
-       PORT_GP_PUP_1(bank, 26, fn, sfx)
-
-#define CPU_ALL_PORT(fn, sfx)          \
+#define CPU_ALL_GP(fn, sfx)            \
        PORT_GP_CFG_32(0, fn, sfx, SH_PFC_PIN_CFG_PULL_UP),             \
        PORT_GP_CFG_32(1, fn, sfx, SH_PFC_PIN_CFG_PULL_UP),             \
        PORT_GP_CFG_32(2, fn, sfx, SH_PFC_PIN_CFG_PULL_UP),             \
        PORT_GP_CFG_32(3, fn, sfx, SH_PFC_PIN_CFG_PULL_UP),             \
-       PORT_GP_PUP_27(4, fn, sfx)
+       PORT_GP_CFG_27(4, fn, sfx, SH_PFC_PIN_CFG_PULL_UP)
+
+#define CPU_ALL_NOGP(fn)               \
+       PIN_NOGP(CLKOUT, "B25", fn),    \
+       PIN_NOGP(CS0, "A20", fn),       \
+       PIN_NOGP(CS1_A26, "C20", fn)
 
 enum {
        PINMUX_RESERVED = 0,
@@ -1253,19 +1242,17 @@ static const u16 pinmux_data[] = {
        PINMUX_IPSR_MSEL(IP10_24_22,    CAN_CLK_C,      SEL_CANCLK_C),
 };
 
-/* Pin numbers for pins without a corresponding GPIO port number are computed
- * from the row and column numbers with a 1000 offset to avoid collisions with
- * GPIO port numbers.
+/*
+ * Pins not associated with a GPIO port.
  */
-#define PIN_NUMBER(row, col)           (1000+((row)-1)*25+(col)-1)
+enum {
+       GP_ASSIGN_LAST(),
+       NOGP_ALL(),
+};
 
 static const struct sh_pfc_pin pinmux_pins[] = {
        PINMUX_GPIO_GP_ALL(),
-
-       /* Pins not associated with a GPIO port */
-       SH_PFC_PIN_NAMED(3, 20, C20),
-       SH_PFC_PIN_NAMED(1, 20, A20),
-       SH_PFC_PIN_NAMED(2, 25, B25),
+       PINMUX_NOGP_ALL(),
 };
 
 /* - macro */
@@ -1400,7 +1387,7 @@ HSPI_PFC_DAT(hspi1_a,     HSPI_CLK1_A,            HSPI_CS1_A,
                        HSPI_RX1_A,             HSPI_TX1_A);
 
 HSPI_PFC_PIN(hspi1_b,  RCAR_GP_PIN(0, 27),     RCAR_GP_PIN(0, 26),
-                       PIN_NUMBER(1, 20),      PIN_NUMBER(2, 25));
+                       PIN_CS0,                PIN_CLKOUT);
 HSPI_PFC_DAT(hspi1_b,  HSPI_CLK1_B,            HSPI_CS1_B,
                        HSPI_RX1_B,             HSPI_TX1_B);
 
@@ -1426,7 +1413,7 @@ I2C_PFC_PIN(i2c1_b,       RCAR_GP_PIN(4, 17),     RCAR_GP_PIN(4, 18));
 I2C_PFC_MUX(i2c1_b,    SDA1_B,                 SCL1_B);
 
 /* - I2C2 ------------------------------------------------------------------ */
-I2C_PFC_PIN(i2c2_a,    PIN_NUMBER(3, 20),      RCAR_GP_PIN(1, 3));
+I2C_PFC_PIN(i2c2_a,    PIN_CS1_A26,            RCAR_GP_PIN(1, 3));
 I2C_PFC_MUX(i2c2_a,    SDA2_A,                 SCL2_A);
 I2C_PFC_PIN(i2c2_b,    RCAR_GP_PIN(0, 3),      RCAR_GP_PIN(0, 4));
 I2C_PFC_MUX(i2c2_b,    SDA2_B,                 SCL2_B);
@@ -1516,7 +1503,7 @@ SCIF_PFC_PIN(scif2_data_e,        RCAR_GP_PIN(0, 3),      RCAR_GP_PIN(0, 4));
 SCIF_PFC_DAT(scif2_data_e,     TX2_E,                  RX2_E);
 SCIF_PFC_PIN(scif2_clk_a,      RCAR_GP_PIN(3, 9));
 SCIF_PFC_CLK(scif2_clk_a,      SCK2_A);
-SCIF_PFC_PIN(scif2_clk_b,      PIN_NUMBER(3, 20));
+SCIF_PFC_PIN(scif2_clk_b,      PIN_CS1_A26);
 SCIF_PFC_CLK(scif2_clk_b,      SCK2_B);
 SCIF_PFC_PIN(scif2_clk_c,      RCAR_GP_PIN(4, 12));
 SCIF_PFC_CLK(scif2_clk_c,      SCK2_C);
@@ -1631,7 +1618,7 @@ SSI_PFC_PINS(ssi0_data,           RCAR_GP_PIN(3, 10));
 SSI_PFC_DATA(ssi0_data,                SSI_SDATA0);
 SSI_PFC_PINS(ssi1_a_ctrl,      RCAR_GP_PIN(2, 20),     RCAR_GP_PIN(2, 21));
 SSI_PFC_CTRL(ssi1_a_ctrl,      SSI_SCK1_A,             SSI_WS1_A);
-SSI_PFC_PINS(ssi1_b_ctrl,      PIN_NUMBER(3, 20),      RCAR_GP_PIN(1, 3));
+SSI_PFC_PINS(ssi1_b_ctrl,      PIN_CS1_A26,            RCAR_GP_PIN(1, 3));
 SSI_PFC_CTRL(ssi1_b_ctrl,      SSI_SCK1_B,             SSI_WS1_B);
 SSI_PFC_PINS(ssi1_data,                RCAR_GP_PIN(3, 9));
 SSI_PFC_DATA(ssi1_data,                SSI_SDATA1);
@@ -2921,8 +2908,6 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
        { },
 };
 
-#define PIN_NONE       U16_MAX
-
 static const struct pinmux_bias_reg pinmux_bias_regs[] = {
        { PINMUX_BIAS_REG("PUPR0", 0x100, "N/A", 0) {
                [ 0] = RCAR_GP_PIN(0,  6),      /* A0 */
@@ -2969,28 +2954,28 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [ 7] = RCAR_GP_PIN(1, 10),      /* DACK0        */
                [ 8] = RCAR_GP_PIN(1, 12),      /* IRQ0         */
                [ 9] = RCAR_GP_PIN(1, 13),      /* IRQ1         */
-               [10] = PIN_NONE,
-               [11] = PIN_NONE,
-               [12] = PIN_NONE,
-               [13] = PIN_NONE,
-               [14] = PIN_NONE,
-               [15] = PIN_NONE,
-               [16] = PIN_NONE,
-               [17] = PIN_NONE,
-               [18] = PIN_NONE,
-               [19] = PIN_NONE,
-               [20] = PIN_NONE,
-               [21] = PIN_NONE,
-               [22] = PIN_NONE,
-               [23] = PIN_NONE,
-               [24] = PIN_NONE,
-               [25] = PIN_NONE,
-               [26] = PIN_NONE,
-               [27] = PIN_NONE,
-               [28] = PIN_NONE,
-               [29] = PIN_NONE,
-               [30] = PIN_NONE,
-               [31] = PIN_NONE,
+               [10] = SH_PFC_PIN_NONE,
+               [11] = SH_PFC_PIN_NONE,
+               [12] = SH_PFC_PIN_NONE,
+               [13] = SH_PFC_PIN_NONE,
+               [14] = SH_PFC_PIN_NONE,
+               [15] = SH_PFC_PIN_NONE,
+               [16] = SH_PFC_PIN_NONE,
+               [17] = SH_PFC_PIN_NONE,
+               [18] = SH_PFC_PIN_NONE,
+               [19] = SH_PFC_PIN_NONE,
+               [20] = SH_PFC_PIN_NONE,
+               [21] = SH_PFC_PIN_NONE,
+               [22] = SH_PFC_PIN_NONE,
+               [23] = SH_PFC_PIN_NONE,
+               [24] = SH_PFC_PIN_NONE,
+               [25] = SH_PFC_PIN_NONE,
+               [26] = SH_PFC_PIN_NONE,
+               [27] = SH_PFC_PIN_NONE,
+               [28] = SH_PFC_PIN_NONE,
+               [29] = SH_PFC_PIN_NONE,
+               [30] = SH_PFC_PIN_NONE,
+               [31] = SH_PFC_PIN_NONE,
        } },
        { PINMUX_BIAS_REG("PUPR2", 0x108, "N/A", 0) {
                [ 0] = RCAR_GP_PIN(1, 22),      /* DU0_DR0      */
@@ -3112,21 +3097,21 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [14] = RCAR_GP_PIN(4, 20),      /* ETH_MAGIC    */
                [15] = RCAR_GP_PIN(4, 25),      /* AVS1         */
                [16] = RCAR_GP_PIN(4, 26),      /* AVS2         */
-               [17] = PIN_NONE,
-               [18] = PIN_NONE,
-               [19] = PIN_NONE,
-               [20] = PIN_NONE,
-               [21] = PIN_NONE,
-               [22] = PIN_NONE,
-               [23] = PIN_NONE,
-               [24] = PIN_NONE,
-               [25] = PIN_NONE,
-               [26] = PIN_NONE,
-               [27] = PIN_NONE,
-               [28] = PIN_NONE,
-               [29] = PIN_NONE,
-               [30] = PIN_NONE,
-               [31] = PIN_NONE,
+               [17] = SH_PFC_PIN_NONE,
+               [18] = SH_PFC_PIN_NONE,
+               [19] = SH_PFC_PIN_NONE,
+               [20] = SH_PFC_PIN_NONE,
+               [21] = SH_PFC_PIN_NONE,
+               [22] = SH_PFC_PIN_NONE,
+               [23] = SH_PFC_PIN_NONE,
+               [24] = SH_PFC_PIN_NONE,
+               [25] = SH_PFC_PIN_NONE,
+               [26] = SH_PFC_PIN_NONE,
+               [27] = SH_PFC_PIN_NONE,
+               [28] = SH_PFC_PIN_NONE,
+               [29] = SH_PFC_PIN_NONE,
+               [30] = SH_PFC_PIN_NONE,
+               [31] = SH_PFC_PIN_NONE,
        } },
        { /* sentinel */ },
 };
index 0c121b2..3e47cdc 100644 (file)
@@ -11,7 +11,7 @@
 
 #include "sh_pfc.h"
 
-#define CPU_ALL_PORT(fn, sfx)                                          \
+#define CPU_ALL_GP(fn, sfx)                                            \
        PORT_GP_32(0, fn, sfx),                                         \
        PORT_GP_32(1, fn, sfx),                                         \
        PORT_GP_32(2, fn, sfx),                                         \
index c41a676..3366ed5 100644 (file)
@@ -20,7 +20,7 @@
  * All pins assigned to GPIO bank 3 can be used for SD interfaces in
  * which case they support both 3.3V and 1.8V signalling.
  */
-#define CPU_ALL_PORT(fn, sfx)                                          \
+#define CPU_ALL_GP(fn, sfx)                                            \
        PORT_GP_32(0, fn, sfx),                                         \
        PORT_GP_30(1, fn, sfx),                                         \
        PORT_GP_30(2, fn, sfx),                                         \
        PORT_GP_32(4, fn, sfx),                                         \
        PORT_GP_32(5, fn, sfx)
 
+#define CPU_ALL_NOGP(fn)               \
+       PIN_NOGP(IIC0_SDA, "AF15", fn), \
+       PIN_NOGP(IIC0_SCL, "AG15", fn), \
+       PIN_NOGP(IIC3_SDA, "AH15", fn), \
+       PIN_NOGP(IIC3_SCL, "AJ15", fn)
+
 enum {
        PINMUX_RESERVED = 0,
 
@@ -1727,19 +1733,17 @@ static const u16 pinmux_data[] = {
        PINMUX_DATA(I2C3_SDA_MARK, FN_SEL_IICDVFS_1),
 };
 
-/* R8A7790 has 6 banks with 32 GPIOs in each = 192 GPIOs */
-#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r))
-#define PIN_NUMBER(r, c) (((r) - 'A') * 31 + (c) + 200)
-#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c)
+/*
+ * Pins not associated with a GPIO port.
+ */
+enum {
+       GP_ASSIGN_LAST(),
+       NOGP_ALL(),
+};
 
 static const struct sh_pfc_pin pinmux_pins[] = {
        PINMUX_GPIO_GP_ALL(),
-
-       /* Pins not associated with a GPIO port */
-       SH_PFC_PIN_NAMED(ROW_GROUP_A('F'), 15, AF15),
-       SH_PFC_PIN_NAMED(ROW_GROUP_A('G'), 15, AG15),
-       SH_PFC_PIN_NAMED(ROW_GROUP_A('H'), 15, AH15),
-       SH_PFC_PIN_NAMED(ROW_GROUP_A('J'), 15, AJ15),
+       PINMUX_NOGP_ALL(),
 };
 
 /* - AUDIO CLOCK ------------------------------------------------------------ */
@@ -2135,7 +2139,7 @@ static const unsigned int hscif1_ctrl_b_mux[] = {
 /* - I2C0 ------------------------------------------------------------------- */
 static const unsigned int i2c0_pins[] = {
        /* SCL, SDA */
-       PIN_A_NUMBER('G', 15), PIN_A_NUMBER('F', 15),
+       PIN_IIC0_SCL, PIN_IIC0_SDA,
 };
 static const unsigned int i2c0_mux[] = {
        I2C0_SCL_MARK, I2C0_SDA_MARK,
@@ -2201,7 +2205,7 @@ static const unsigned int i2c2_e_mux[] = {
 /* - I2C3 ------------------------------------------------------------------- */
 static const unsigned int i2c3_pins[] = {
        /* SCL, SDA */
-       PIN_A_NUMBER('J', 15), PIN_A_NUMBER('H', 15),
+       PIN_IIC3_SCL, PIN_IIC3_SDA,
 };
 static const unsigned int i2c3_mux[] = {
        I2C3_SCL_MARK, I2C3_SDA_MARK,
@@ -2209,7 +2213,7 @@ static const unsigned int i2c3_mux[] = {
 /* - IIC0 (I2C4) ------------------------------------------------------------ */
 static const unsigned int iic0_pins[] = {
        /* SCL, SDA */
-       PIN_A_NUMBER('G', 15), PIN_A_NUMBER('F', 15),
+       PIN_IIC0_SCL, PIN_IIC0_SDA,
 };
 static const unsigned int iic0_mux[] = {
        IIC0_SCL_MARK, IIC0_SDA_MARK,
@@ -2274,8 +2278,8 @@ static const unsigned int iic2_e_mux[] = {
 };
 /* - IIC3 (I2C7) ------------------------------------------------------------ */
 static const unsigned int iic3_pins[] = {
-/* SCL, SDA */
-       PIN_A_NUMBER('J', 15), PIN_A_NUMBER('H', 15),
+       /* SCL, SDA */
+       PIN_IIC3_SCL, PIN_IIC3_SDA,
 };
 static const unsigned int iic3_mux[] = {
        IIC3_SCL_MARK, IIC3_SDA_MARK,
index 1292ec8..bc9caf8 100644 (file)
@@ -15,7 +15,7 @@
  * Pins 0-23 assigned to GPIO bank 6 can be used for SD interfaces in
  * which case they support both 3.3V and 1.8V signalling.
  */
-#define CPU_ALL_PORT(fn, sfx)                                          \
+#define CPU_ALL_GP(fn, sfx)                                            \
        PORT_GP_32(0, fn, sfx),                                         \
        PORT_GP_26(1, fn, sfx),                                         \
        PORT_GP_32(2, fn, sfx),                                         \
index bbace14..258f82f 100644 (file)
@@ -11,7 +11,7 @@
 #include "core.h"
 #include "sh_pfc.h"
 
-#define CPU_ALL_PORT(fn, sfx)                                          \
+#define CPU_ALL_GP(fn, sfx)                                            \
        PORT_GP_29(0, fn, sfx),                                         \
        PORT_GP_23(1, fn, sfx),                                         \
        PORT_GP_32(2, fn, sfx),                                         \
index 1ff4969..34481b6 100644 (file)
@@ -14,7 +14,7 @@
 #include "core.h"
 #include "sh_pfc.h"
 
-#define CPU_ALL_PORT(fn, sfx)                                          \
+#define CPU_ALL_GP(fn, sfx)                                            \
        PORT_GP_32(0, fn, sfx),                                         \
        PORT_GP_26(1, fn, sfx),                                         \
        PORT_GP_32(2, fn, sfx),                                         \
index f16dfba..95f9aae 100644 (file)
 #include "core.h"
 #include "sh_pfc.h"
 
-#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | \
-                  SH_PFC_PIN_CFG_PULL_UP | \
-                  SH_PFC_PIN_CFG_PULL_DOWN)
+#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_PULL_UP_DOWN)
 
-#define CPU_ALL_PORT(fn, sfx)                                          \
+#define CPU_ALL_GP(fn, sfx)                                            \
        PORT_GP_CFG_16(0, fn, sfx, CFG_FLAGS),  \
        PORT_GP_CFG_28(1, fn, sfx, CFG_FLAGS),  \
        PORT_GP_CFG_15(2, fn, sfx, CFG_FLAGS),  \
        PORT_GP_CFG_26(5, fn, sfx, CFG_FLAGS),  \
        PORT_GP_CFG_32(6, fn, sfx, CFG_FLAGS),  \
        PORT_GP_CFG_4(7, fn, sfx, CFG_FLAGS)
+
+#define CPU_ALL_NOGP(fn)                                               \
+       PIN_NOGP_CFG(ASEBRK, "ASEBRK", fn, CFG_FLAGS),                  \
+       PIN_NOGP_CFG(AVB_MDIO, "AVB_MDIO", fn, CFG_FLAGS),              \
+       PIN_NOGP_CFG(AVB_RD0, "AVB_RD0", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_RD1, "AVB_RD1", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_RD2, "AVB_RD2", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_RD3, "AVB_RD3", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_RXC, "AVB_RXC", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_RX_CTL, "AVB_RX_CTL", fn, CFG_FLAGS),          \
+       PIN_NOGP_CFG(AVB_TD0, "AVB_TD0", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TD1, "AVB_TD1", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TD2, "AVB_TD2", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TD3, "AVB_TD3", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TXC, "AVB_TXC", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TXCREFCLK, "AVB_TXCREFCLK", fn, CFG_FLAGS),    \
+       PIN_NOGP_CFG(AVB_TX_CTL, "AVB_TX_CTL", fn, CFG_FLAGS),          \
+       PIN_NOGP_CFG(CLKOUT, "CLKOUT", fn, CFG_FLAGS),                  \
+       PIN_NOGP_CFG(DU_DOTCLKIN0, "DU_DOTCLKIN0", fn, CFG_FLAGS),      \
+       PIN_NOGP_CFG(DU_DOTCLKIN1, "DU_DOTCLKIN1", fn, CFG_FLAGS),      \
+       PIN_NOGP_CFG(DU_DOTCLKIN2, "DU_DOTCLKIN2", fn, CFG_FLAGS),      \
+       PIN_NOGP_CFG(DU_DOTCLKIN3, "DU_DOTCLKIN3", fn, CFG_FLAGS),      \
+       PIN_NOGP_CFG(EXTALR, "EXTALR", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),\
+       PIN_NOGP_CFG(FSCLKST_N, "FSCLKST#", fn, CFG_FLAGS),             \
+       PIN_NOGP_CFG(MLB_REF, "MLB_REF", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT#", fn, CFG_FLAGS),         \
+       PIN_NOGP_CFG(QSPI0_IO2, "QSPI0_IO2", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(QSPI0_IO3, "QSPI0_IO3", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(QSPI0_MISO_IO1, "QSPI0_MISO_IO1", fn, CFG_FLAGS),  \
+       PIN_NOGP_CFG(QSPI0_MOSI_IO0, "QSPI0_MOSI_IO0", fn, CFG_FLAGS),  \
+       PIN_NOGP_CFG(QSPI0_SPCLK, "QSPI0_SPCLK", fn, CFG_FLAGS),        \
+       PIN_NOGP_CFG(QSPI0_SSL, "QSPI0_SSL", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(QSPI1_IO2, "QSPI1_IO2", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(QSPI1_IO3, "QSPI1_IO3", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(QSPI1_MISO_IO1, "QSPI1_MISO_IO1", fn, CFG_FLAGS),  \
+       PIN_NOGP_CFG(QSPI1_MOSI_IO0, "QSPI1_MOSI_IO0", fn, CFG_FLAGS),  \
+       PIN_NOGP_CFG(QSPI1_SPCLK, "QSPI1_SPCLK", fn, CFG_FLAGS),        \
+       PIN_NOGP_CFG(QSPI1_SSL, "QSPI1_SSL", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(RPC_INT_N, "RPC_INT#", fn, CFG_FLAGS),             \
+       PIN_NOGP_CFG(RPC_RESET_N, "RPC_RESET#", fn, CFG_FLAGS),         \
+       PIN_NOGP_CFG(RPC_WP_N, "RPC_WP#", fn, CFG_FLAGS),               \
+       PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),      \
+       PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),      \
+       PIN_NOGP_CFG(TDO, "TDO", fn, SH_PFC_PIN_CFG_DRIVE_STRENGTH),    \
+       PIN_NOGP_CFG(TMS, "TMS", fn, CFG_FLAGS),                        \
+       PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN)
+
 /*
  * F_() : just information
  * FM() : macro for FN_xxx / xxx_MARK
@@ -1447,69 +1492,16 @@ static const u16 pinmux_data[] = {
 };
 
 /*
- * R8A7795 has 8 banks with 32 GPIOs in each => 256 GPIOs.
- * Physical layout rows: A - AW, cols: 1 - 39.
+ * Pins not associated with a GPIO port.
  */
-#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r))
-#define PIN_NUMBER(r, c) (((r) - 'A') * 39 + (c) + 300)
-#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c)
-#define PIN_NONE U16_MAX
+enum {
+       GP_ASSIGN_LAST(),
+       NOGP_ALL(),
+};
 
 static const struct sh_pfc_pin pinmux_pins[] = {
        PINMUX_GPIO_GP_ALL(),
-
-       /*
-        * Pins not associated with a GPIO port.
-        *
-        * The pin positions are different between different r8a7795
-        * packages, all that is needed for the pfc driver is a unique
-        * number for each pin. To this end use the pin layout from
-        * R-Car H3SiP to calculate a unique number for each pin.
-        */
-       SH_PFC_PIN_NAMED_CFG('A',  8, AVB_TX_CTL, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A',  9, AVB_MDIO, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 12, AVB_TXCREFCLK, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 13, AVB_RD0, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 14, AVB_RD2, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 16, AVB_RX_CTL, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 17, AVB_TD2, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 18, AVB_TD0, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 19, AVB_TXC, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('B', 13, AVB_RD1, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('B', 14, AVB_RD3, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('B', 17, AVB_TD3, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('C',  1, PRESETOUT#, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('F',  1, CLKOUT, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('V',  3, QSPI1_SPCLK, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('V',  5, QSPI1_SSL, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('V',  6, RPC_WP#, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('V',  7, RPC_RESET#, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('W',  3, QSPI0_SPCLK, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('Y',  3, QSPI0_SSL, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('Y',  6, QSPI0_IO2, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('Y',  7, RPC_INT#, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'),  4, QSPI0_MISO_IO1, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'),  6, QSPI0_IO3, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  3, QSPI1_IO3, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  5, QSPI0_MOSI_IO0, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  7, QSPI1_MOSI_IO0, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 38, FSCLKST#, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 39, EXTALR, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'),  4, QSPI1_IO2, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'),  5, QSPI1_MISO_IO1, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'),  7, DU_DOTCLKIN0, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'),  8, DU_DOTCLKIN1, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'),  7, DU_DOTCLKIN2, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'),  8, DU_DOTCLKIN3, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 26, TRST#, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 29, TDI, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 30, TMS, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 27, TCK, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 28, TDO, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, CFG_FLAGS),
+       PINMUX_NOGP_ALL(),
 };
 
 /* - AUDIO CLOCK ------------------------------------------------------------ */
@@ -1658,7 +1650,7 @@ static const unsigned int avb_phy_int_mux[] = {
 };
 static const unsigned int avb_mdio_pins[] = {
        /* AVB_MDC, AVB_MDIO */
-       RCAR_GP_PIN(2, 9), PIN_NUMBER('A', 9),
+       RCAR_GP_PIN(2, 9), PIN_AVB_MDIO,
 };
 static const unsigned int avb_mdio_mux[] = {
        AVB_MDC_MARK, AVB_MDIO_MARK,
@@ -1671,11 +1663,11 @@ static const unsigned int avb_mii_pins[] = {
         * AVB_RD1, AVB_RD2, AVB_RD3,
         * AVB_TXCREFCLK
         */
-       PIN_NUMBER('A', 8), PIN_NUMBER('A', 19), PIN_NUMBER('A', 18),
-       PIN_NUMBER('B', 18), PIN_NUMBER('A', 17), PIN_NUMBER('B', 17),
-       PIN_NUMBER('A', 16), PIN_NUMBER('B', 19), PIN_NUMBER('A', 13),
-       PIN_NUMBER('B', 13), PIN_NUMBER('A', 14), PIN_NUMBER('B', 14),
-       PIN_NUMBER('A', 12),
+       PIN_AVB_TX_CTL, PIN_AVB_TXC, PIN_AVB_TD0,
+       PIN_AVB_TD1, PIN_AVB_TD2, PIN_AVB_TD3,
+       PIN_AVB_RX_CTL, PIN_AVB_RXC, PIN_AVB_RD0,
+       PIN_AVB_RD1, PIN_AVB_RD2, PIN_AVB_RD3,
+       PIN_AVB_TXCREFCLK,
 
 };
 static const unsigned int avb_mii_mux[] = {
@@ -3137,22 +3129,21 @@ static const unsigned int pwm6_b_mux[] = {
 /* - QSPI0 ------------------------------------------------------------------ */
 static const unsigned int qspi0_ctrl_pins[] = {
        /* QSPI0_SPCLK, QSPI0_SSL */
-       PIN_NUMBER('W', 3), PIN_NUMBER('Y', 3),
+       PIN_QSPI0_SPCLK, PIN_QSPI0_SSL,
 };
 static const unsigned int qspi0_ctrl_mux[] = {
        QSPI0_SPCLK_MARK, QSPI0_SSL_MARK,
 };
 static const unsigned int qspi0_data2_pins[] = {
        /* QSPI0_MOSI_IO0, QSPI0_MISO_IO1 */
-       PIN_A_NUMBER('C', 5), PIN_A_NUMBER('B', 4),
+       PIN_QSPI0_MOSI_IO0, PIN_QSPI0_MISO_IO1,
 };
 static const unsigned int qspi0_data2_mux[] = {
        QSPI0_MOSI_IO0_MARK, QSPI0_MISO_IO1_MARK,
 };
 static const unsigned int qspi0_data4_pins[] = {
        /* QSPI0_MOSI_IO0, QSPI0_MISO_IO1, QSPI0_IO2, QSPI0_IO3 */
-       PIN_A_NUMBER('C', 5), PIN_A_NUMBER('B', 4),
-       PIN_NUMBER('Y', 6), PIN_A_NUMBER('B', 6),
+       PIN_QSPI0_MOSI_IO0, PIN_QSPI0_MISO_IO1, PIN_QSPI0_IO2, PIN_QSPI0_IO3,
 };
 static const unsigned int qspi0_data4_mux[] = {
        QSPI0_MOSI_IO0_MARK, QSPI0_MISO_IO1_MARK,
@@ -3161,22 +3152,21 @@ static const unsigned int qspi0_data4_mux[] = {
 /* - QSPI1 ------------------------------------------------------------------ */
 static const unsigned int qspi1_ctrl_pins[] = {
        /* QSPI1_SPCLK, QSPI1_SSL */
-       PIN_NUMBER('V', 3), PIN_NUMBER('V', 5),
+       PIN_QSPI1_SPCLK, PIN_QSPI1_SSL,
 };
 static const unsigned int qspi1_ctrl_mux[] = {
        QSPI1_SPCLK_MARK, QSPI1_SSL_MARK,
 };
 static const unsigned int qspi1_data2_pins[] = {
        /* QSPI1_MOSI_IO0, QSPI1_MISO_IO1 */
-       PIN_A_NUMBER('C', 7), PIN_A_NUMBER('E', 5),
+       PIN_QSPI1_MOSI_IO0, PIN_QSPI1_MISO_IO1,
 };
 static const unsigned int qspi1_data2_mux[] = {
        QSPI1_MOSI_IO0_MARK, QSPI1_MISO_IO1_MARK,
 };
 static const unsigned int qspi1_data4_pins[] = {
        /* QSPI1_MOSI_IO0, QSPI1_MISO_IO1, QSPI1_IO2, QSPI1_IO3 */
-       PIN_A_NUMBER('C', 7), PIN_A_NUMBER('E', 5),
-       PIN_A_NUMBER('E', 4), PIN_A_NUMBER('C', 3),
+       PIN_QSPI1_MOSI_IO0, PIN_QSPI1_MISO_IO1, PIN_QSPI1_IO2, PIN_QSPI1_IO3,
 };
 static const unsigned int qspi1_data4_mux[] = {
        QSPI1_MOSI_IO0_MARK, QSPI1_MISO_IO1_MARK,
@@ -3812,6 +3802,36 @@ static const unsigned int tmu_tclk2_b_mux[] = {
        TCLK2_B_MARK,
 };
 
+/* - TPU ------------------------------------------------------------------- */
+static const unsigned int tpu_to0_pins[] = {
+       /* TPU0TO0 */
+       RCAR_GP_PIN(6, 28),
+};
+static const unsigned int tpu_to0_mux[] = {
+       TPU0TO0_MARK,
+};
+static const unsigned int tpu_to1_pins[] = {
+       /* TPU0TO1 */
+       RCAR_GP_PIN(6, 29),
+};
+static const unsigned int tpu_to1_mux[] = {
+       TPU0TO1_MARK,
+};
+static const unsigned int tpu_to2_pins[] = {
+       /* TPU0TO2 */
+       RCAR_GP_PIN(6, 30),
+};
+static const unsigned int tpu_to2_mux[] = {
+       TPU0TO2_MARK,
+};
+static const unsigned int tpu_to3_pins[] = {
+       /* TPU0TO3 */
+       RCAR_GP_PIN(6, 31),
+};
+static const unsigned int tpu_to3_mux[] = {
+       TPU0TO3_MARK,
+};
+
 /* - USB0 ------------------------------------------------------------------- */
 static const unsigned int usb0_pins[] = {
        /* PWEN, OVC */
@@ -4165,6 +4185,10 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(tmu_tclk1_b),
        SH_PFC_PIN_GROUP(tmu_tclk2_a),
        SH_PFC_PIN_GROUP(tmu_tclk2_b),
+       SH_PFC_PIN_GROUP(tpu_to0),
+       SH_PFC_PIN_GROUP(tpu_to1),
+       SH_PFC_PIN_GROUP(tpu_to2),
+       SH_PFC_PIN_GROUP(tpu_to3),
        SH_PFC_PIN_GROUP(usb0),
        SH_PFC_PIN_GROUP(usb1),
        SH_PFC_PIN_GROUP(usb2),
@@ -4635,6 +4659,13 @@ static const char * const tmu_groups[] = {
        "tmu_tclk2_b",
 };
 
+static const char * const tpu_groups[] = {
+       "tpu_to0",
+       "tpu_to1",
+       "tpu_to2",
+       "tpu_to3",
+};
+
 static const char * const usb0_groups[] = {
        "usb0",
 };
@@ -4707,6 +4738,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
        SH_PFC_FUNCTION(sdhi3),
        SH_PFC_FUNCTION(ssi),
        SH_PFC_FUNCTION(tmu),
+       SH_PFC_FUNCTION(tpu),
        SH_PFC_FUNCTION(usb0),
        SH_PFC_FUNCTION(usb1),
        SH_PFC_FUNCTION(usb2),
@@ -5272,44 +5304,44 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
 
 static const struct pinmux_drive_reg pinmux_drive_regs[] = {
        { PINMUX_DRIVE_REG("DRVCTRL0", 0xe6060300) {
-               { PIN_NUMBER('W', 3),   28, 2 },        /* QSPI0_SPCLK */
-               { PIN_A_NUMBER('C', 5), 24, 2 },        /* QSPI0_MOSI_IO0 */
-               { PIN_A_NUMBER('B', 4), 20, 2 },        /* QSPI0_MISO_IO1 */
-               { PIN_NUMBER('Y', 6),   16, 2 },        /* QSPI0_IO2 */
-               { PIN_A_NUMBER('B', 6), 12, 2 },        /* QSPI0_IO3 */
-               { PIN_NUMBER('Y', 3),    8, 2 },        /* QSPI0_SSL */
-               { PIN_NUMBER('V', 3),    4, 2 },        /* QSPI1_SPCLK */
-               { PIN_A_NUMBER('C', 7),  0, 2 },        /* QSPI1_MOSI_IO0 */
+               { PIN_QSPI0_SPCLK,    28, 2 },  /* QSPI0_SPCLK */
+               { PIN_QSPI0_MOSI_IO0, 24, 2 },  /* QSPI0_MOSI_IO0 */
+               { PIN_QSPI0_MISO_IO1, 20, 2 },  /* QSPI0_MISO_IO1 */
+               { PIN_QSPI0_IO2,      16, 2 },  /* QSPI0_IO2 */
+               { PIN_QSPI0_IO3,      12, 2 },  /* QSPI0_IO3 */
+               { PIN_QSPI0_SSL,       8, 2 },  /* QSPI0_SSL */
+               { PIN_QSPI1_SPCLK,     4, 2 },  /* QSPI1_SPCLK */
+               { PIN_QSPI1_MOSI_IO0,  0, 2 },  /* QSPI1_MOSI_IO0 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL1", 0xe6060304) {
-               { PIN_A_NUMBER('E', 5), 28, 2 },        /* QSPI1_MISO_IO1 */
-               { PIN_A_NUMBER('E', 4), 24, 2 },        /* QSPI1_IO2 */
-               { PIN_A_NUMBER('C', 3), 20, 2 },        /* QSPI1_IO3 */
-               { PIN_NUMBER('V', 5),   16, 2 },        /* QSPI1_SSL */
-               { PIN_NUMBER('Y', 7),   12, 2 },        /* RPC_INT# */
-               { PIN_NUMBER('V', 6),    8, 2 },        /* RPC_WP# */
-               { PIN_NUMBER('V', 7),    4, 2 },        /* RPC_RESET# */
-               { PIN_NUMBER('A', 16),   0, 3 },        /* AVB_RX_CTL */
+               { PIN_QSPI1_MISO_IO1, 28, 2 },  /* QSPI1_MISO_IO1 */
+               { PIN_QSPI1_IO2,      24, 2 },  /* QSPI1_IO2 */
+               { PIN_QSPI1_IO3,      20, 2 },  /* QSPI1_IO3 */
+               { PIN_QSPI1_SSL,      16, 2 },  /* QSPI1_SSL */
+               { PIN_RPC_INT_N,      12, 2 },  /* RPC_INT# */
+               { PIN_RPC_WP_N,        8, 2 },  /* RPC_WP# */
+               { PIN_RPC_RESET_N,     4, 2 },  /* RPC_RESET# */
+               { PIN_AVB_RX_CTL,      0, 3 },  /* AVB_RX_CTL */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL2", 0xe6060308) {
-               { PIN_NUMBER('B', 19),  28, 3 },        /* AVB_RXC */
-               { PIN_NUMBER('A', 13),  24, 3 },        /* AVB_RD0 */
-               { PIN_NUMBER('B', 13),  20, 3 },        /* AVB_RD1 */
-               { PIN_NUMBER('A', 14),  16, 3 },        /* AVB_RD2 */
-               { PIN_NUMBER('B', 14),  12, 3 },        /* AVB_RD3 */
-               { PIN_NUMBER('A', 8),    8, 3 },        /* AVB_TX_CTL */
-               { PIN_NUMBER('A', 19),   4, 3 },        /* AVB_TXC */
-               { PIN_NUMBER('A', 18),   0, 3 },        /* AVB_TD0 */
+               { PIN_AVB_RXC,        28, 3 },  /* AVB_RXC */
+               { PIN_AVB_RD0,        24, 3 },  /* AVB_RD0 */
+               { PIN_AVB_RD1,        20, 3 },  /* AVB_RD1 */
+               { PIN_AVB_RD2,        16, 3 },  /* AVB_RD2 */
+               { PIN_AVB_RD3,        12, 3 },  /* AVB_RD3 */
+               { PIN_AVB_TX_CTL,      8, 3 },  /* AVB_TX_CTL */
+               { PIN_AVB_TXC,         4, 3 },  /* AVB_TXC */
+               { PIN_AVB_TD0,         0, 3 },  /* AVB_TD0 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL3", 0xe606030c) {
-               { PIN_NUMBER('B', 18),  28, 3 },        /* AVB_TD1 */
-               { PIN_NUMBER('A', 17),  24, 3 },        /* AVB_TD2 */
-               { PIN_NUMBER('B', 17),  20, 3 },        /* AVB_TD3 */
-               { PIN_NUMBER('A', 12),  16, 3 },        /* AVB_TXCREFCLK */
-               { PIN_NUMBER('A', 9),   12, 3 },        /* AVB_MDIO */
-               { RCAR_GP_PIN(2,  9),    8, 3 },        /* AVB_MDC */
-               { RCAR_GP_PIN(2, 10),    4, 3 },        /* AVB_MAGIC */
-               { RCAR_GP_PIN(2, 11),    0, 3 },        /* AVB_PHY_INT */
+               { PIN_AVB_TD1,        28, 3 },  /* AVB_TD1 */
+               { PIN_AVB_TD2,        24, 3 },  /* AVB_TD2 */
+               { PIN_AVB_TD3,        20, 3 },  /* AVB_TD3 */
+               { PIN_AVB_TXCREFCLK,  16, 3 },  /* AVB_TXCREFCLK */
+               { PIN_AVB_MDIO,       12, 3 },  /* AVB_MDIO */
+               { RCAR_GP_PIN(2,  9),  8, 3 },  /* AVB_MDC */
+               { RCAR_GP_PIN(2, 10),  4, 3 },  /* AVB_MAGIC */
+               { RCAR_GP_PIN(2, 11),  0, 3 },  /* AVB_PHY_INT */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL4", 0xe6060310) {
                { RCAR_GP_PIN(2, 12), 28, 3 },  /* AVB_LINK */
@@ -5352,7 +5384,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
                { RCAR_GP_PIN(1, 19),  0, 3 },  /* A19 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL8", 0xe6060320) {
-               { PIN_NUMBER('F', 1), 28, 3 },  /* CLKOUT */
+               { PIN_CLKOUT,         28, 3 },  /* CLKOUT */
                { RCAR_GP_PIN(1, 20), 24, 3 },  /* CS0 */
                { RCAR_GP_PIN(1, 21), 20, 3 },  /* CS1_A26 */
                { RCAR_GP_PIN(1, 22), 16, 3 },  /* BS */
@@ -5363,7 +5395,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
        } },
        { PINMUX_DRIVE_REG("DRVCTRL9", 0xe6060324) {
                { RCAR_GP_PIN(1, 27), 28, 3 },  /* EX_WAIT0 */
-               { PIN_NUMBER('C', 1), 24, 3 },  /* PRESETOUT# */
+               { PIN_PRESETOUT_N,    24, 3 },  /* PRESETOUT# */
                { RCAR_GP_PIN(0,  0), 20, 3 },  /* D0 */
                { RCAR_GP_PIN(0,  1), 16, 3 },  /* D1 */
                { RCAR_GP_PIN(0,  2), 12, 3 },  /* D2 */
@@ -5382,30 +5414,30 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
                { RCAR_GP_PIN(0, 13),  0, 3 },  /* D13 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL11", 0xe606032c) {
-               { RCAR_GP_PIN(0, 14),   28, 3 },        /* D14 */
-               { RCAR_GP_PIN(0, 15),   24, 3 },        /* D15 */
-               { RCAR_GP_PIN(7,  0),   20, 3 },        /* AVS1 */
-               { RCAR_GP_PIN(7,  1),   16, 3 },        /* AVS2 */
-               { RCAR_GP_PIN(7,  2),   12, 3 },        /* GP7_02 */
-               { RCAR_GP_PIN(7,  3),    8, 3 },        /* GP7_03 */
-               { PIN_A_NUMBER('P', 7),  4, 2 },        /* DU_DOTCLKIN0 */
-               { PIN_A_NUMBER('P', 8),  0, 2 },        /* DU_DOTCLKIN1 */
+               { RCAR_GP_PIN(0, 14), 28, 3 },  /* D14 */
+               { RCAR_GP_PIN(0, 15), 24, 3 },  /* D15 */
+               { RCAR_GP_PIN(7,  0), 20, 3 },  /* AVS1 */
+               { RCAR_GP_PIN(7,  1), 16, 3 },  /* AVS2 */
+               { RCAR_GP_PIN(7,  2), 12, 3 },  /* GP7_02 */
+               { RCAR_GP_PIN(7,  3),  8, 3 },  /* GP7_03 */
+               { PIN_DU_DOTCLKIN0,    4, 2 },  /* DU_DOTCLKIN0 */
+               { PIN_DU_DOTCLKIN1,    0, 2 },  /* DU_DOTCLKIN1 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL12", 0xe6060330) {
-               { PIN_A_NUMBER('R', 7),  28, 2 },       /* DU_DOTCLKIN2 */
-               { PIN_A_NUMBER('R', 8),  24, 2 },       /* DU_DOTCLKIN3 */
-               { PIN_A_NUMBER('D', 38), 20, 2 },       /* FSCLKST# */
-               { PIN_A_NUMBER('R', 30),  4, 2 },       /* TMS */
+               { PIN_DU_DOTCLKIN2,   28, 2 },  /* DU_DOTCLKIN2 */
+               { PIN_DU_DOTCLKIN3,   24, 2 },  /* DU_DOTCLKIN3 */
+               { PIN_FSCLKST_N,      20, 2 },  /* FSCLKST# */
+               { PIN_TMS,             4, 2 },  /* TMS */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL13", 0xe6060334) {
-               { PIN_A_NUMBER('T', 28), 28, 2 },       /* TDO */
-               { PIN_A_NUMBER('T', 30), 24, 2 },       /* ASEBRK */
-               { RCAR_GP_PIN(3,  0),    20, 3 },       /* SD0_CLK */
-               { RCAR_GP_PIN(3,  1),    16, 3 },       /* SD0_CMD */
-               { RCAR_GP_PIN(3,  2),    12, 3 },       /* SD0_DAT0 */
-               { RCAR_GP_PIN(3,  3),     8, 3 },       /* SD0_DAT1 */
-               { RCAR_GP_PIN(3,  4),     4, 3 },       /* SD0_DAT2 */
-               { RCAR_GP_PIN(3,  5),     0, 3 },       /* SD0_DAT3 */
+               { PIN_TDO,            28, 2 },  /* TDO */
+               { PIN_ASEBRK,         24, 2 },  /* ASEBRK */
+               { RCAR_GP_PIN(3,  0), 20, 3 },  /* SD0_CLK */
+               { RCAR_GP_PIN(3,  1), 16, 3 },  /* SD0_CMD */
+               { RCAR_GP_PIN(3,  2), 12, 3 },  /* SD0_DAT0 */
+               { RCAR_GP_PIN(3,  3),  8, 3 },  /* SD0_DAT1 */
+               { RCAR_GP_PIN(3,  4),  4, 3 },  /* SD0_DAT2 */
+               { RCAR_GP_PIN(3,  5),  0, 3 },  /* SD0_DAT3 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL14", 0xe6060338) {
                { RCAR_GP_PIN(3,  6), 28, 3 },  /* SD1_CLK */
@@ -5474,7 +5506,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
                { RCAR_GP_PIN(5, 23), 16, 3 },  /* MLB_CLK */
                { RCAR_GP_PIN(5, 24), 12, 3 },  /* MLB_SIG */
                { RCAR_GP_PIN(5, 25),  8, 3 },  /* MLB_DAT */
-               { PIN_NUMBER('H', 37),  4, 3 }, /* MLB_REF */
+               { PIN_MLB_REF,         4, 3 },  /* MLB_REF */
                { RCAR_GP_PIN(6,  0),  0, 3 },  /* SSI_SCK01239 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL21", 0xe6060354) {
@@ -5548,35 +5580,35 @@ static int r8a7795es1_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin,
 
 static const struct pinmux_bias_reg pinmux_bias_regs[] = {
        { PINMUX_BIAS_REG("PUEN0", 0xe6060400, "PUD0", 0xe6060440) {
-               [ 0] = PIN_NUMBER('W', 3),      /* QSPI0_SPCLK */
-               [ 1] = PIN_A_NUMBER('C', 5),    /* QSPI0_MOSI_IO0 */
-               [ 2] = PIN_A_NUMBER('B', 4),    /* QSPI0_MISO_IO1 */
-               [ 3] = PIN_NUMBER('Y', 6),      /* QSPI0_IO2 */
-               [ 4] = PIN_A_NUMBER('B', 6),    /* QSPI0_IO3 */
-               [ 5] = PIN_NUMBER('Y', 3),      /* QSPI0_SSL */
-               [ 6] = PIN_NUMBER('V', 3),      /* QSPI1_SPCLK */
-               [ 7] = PIN_A_NUMBER('C', 7),    /* QSPI1_MOSI_IO0 */
-               [ 8] = PIN_A_NUMBER('E', 5),    /* QSPI1_MISO_IO1 */
-               [ 9] = PIN_A_NUMBER('E', 4),    /* QSPI1_IO2 */
-               [10] = PIN_A_NUMBER('C', 3),    /* QSPI1_IO3 */
-               [11] = PIN_NUMBER('V', 5),      /* QSPI1_SSL */
-               [12] = PIN_NUMBER('Y', 7),      /* RPC_INT# */
-               [13] = PIN_NUMBER('V', 6),      /* RPC_WP# */
-               [14] = PIN_NUMBER('V', 7),      /* RPC_RESET# */
-               [15] = PIN_NUMBER('A', 16),     /* AVB_RX_CTL */
-               [16] = PIN_NUMBER('B', 19),     /* AVB_RXC */
-               [17] = PIN_NUMBER('A', 13),     /* AVB_RD0 */
-               [18] = PIN_NUMBER('B', 13),     /* AVB_RD1 */
-               [19] = PIN_NUMBER('A', 14),     /* AVB_RD2 */
-               [20] = PIN_NUMBER('B', 14),     /* AVB_RD3 */
-               [21] = PIN_NUMBER('A', 8),      /* AVB_TX_CTL */
-               [22] = PIN_NUMBER('A', 19),     /* AVB_TXC */
-               [23] = PIN_NUMBER('A', 18),     /* AVB_TD0 */
-               [24] = PIN_NUMBER('B', 18),     /* AVB_TD1 */
-               [25] = PIN_NUMBER('A', 17),     /* AVB_TD2 */
-               [26] = PIN_NUMBER('B', 17),     /* AVB_TD3 */
-               [27] = PIN_NUMBER('A', 12),     /* AVB_TXCREFCLK */
-               [28] = PIN_NUMBER('A', 9),      /* AVB_MDIO */
+               [ 0] = PIN_QSPI0_SPCLK,         /* QSPI0_SPCLK */
+               [ 1] = PIN_QSPI0_MOSI_IO0,      /* QSPI0_MOSI_IO0 */
+               [ 2] = PIN_QSPI0_MISO_IO1,      /* QSPI0_MISO_IO1 */
+               [ 3] = PIN_QSPI0_IO2,           /* QSPI0_IO2 */
+               [ 4] = PIN_QSPI0_IO3,           /* QSPI0_IO3 */
+               [ 5] = PIN_QSPI0_SSL,           /* QSPI0_SSL */
+               [ 6] = PIN_QSPI1_SPCLK,         /* QSPI1_SPCLK */
+               [ 7] = PIN_QSPI1_MOSI_IO0,      /* QSPI1_MOSI_IO0 */
+               [ 8] = PIN_QSPI1_MISO_IO1,      /* QSPI1_MISO_IO1 */
+               [ 9] = PIN_QSPI1_IO2,           /* QSPI1_IO2 */
+               [10] = PIN_QSPI1_IO3,           /* QSPI1_IO3 */
+               [11] = PIN_QSPI1_SSL,           /* QSPI1_SSL */
+               [12] = PIN_RPC_INT_N,           /* RPC_INT# */
+               [13] = PIN_RPC_WP_N,            /* RPC_WP# */
+               [14] = PIN_RPC_RESET_N,         /* RPC_RESET# */
+               [15] = PIN_AVB_RX_CTL,          /* AVB_RX_CTL */
+               [16] = PIN_AVB_RXC,             /* AVB_RXC */
+               [17] = PIN_AVB_RD0,             /* AVB_RD0 */
+               [18] = PIN_AVB_RD1,             /* AVB_RD1 */
+               [19] = PIN_AVB_RD2,             /* AVB_RD2 */
+               [20] = PIN_AVB_RD3,             /* AVB_RD3 */
+               [21] = PIN_AVB_TX_CTL,          /* AVB_TX_CTL */
+               [22] = PIN_AVB_TXC,             /* AVB_TXC */
+               [23] = PIN_AVB_TD0,             /* AVB_TD0 */
+               [24] = PIN_AVB_TD1,             /* AVB_TD1 */
+               [25] = PIN_AVB_TD2,             /* AVB_TD2 */
+               [26] = PIN_AVB_TD3,             /* AVB_TD3 */
+               [27] = PIN_AVB_TXCREFCLK,       /* AVB_TXCREFCLK */
+               [28] = PIN_AVB_MDIO,            /* AVB_MDIO */
                [29] = RCAR_GP_PIN(2,  9),      /* AVB_MDC */
                [30] = RCAR_GP_PIN(2, 10),      /* AVB_MAGIC */
                [31] = RCAR_GP_PIN(2, 11),      /* AVB_PHY_INT */
@@ -5616,7 +5648,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [31] = RCAR_GP_PIN(1, 19),      /* A19 */
        } },
        { PINMUX_BIAS_REG("PUEN2", 0xe6060408, "PUD2", 0xe6060448) {
-               [ 0] = PIN_NUMBER('F', 1),      /* CLKOUT */
+               [ 0] = PIN_CLKOUT,              /* CLKOUT */
                [ 1] = RCAR_GP_PIN(1, 20),      /* CS0_N */
                [ 2] = RCAR_GP_PIN(1, 21),      /* CS1_N_A26 */
                [ 3] = RCAR_GP_PIN(1, 22),      /* BS_N */
@@ -5625,7 +5657,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [ 6] = RCAR_GP_PIN(1, 25),      /* WE0_N */
                [ 7] = RCAR_GP_PIN(1, 26),      /* WE1_N */
                [ 8] = RCAR_GP_PIN(1, 27),      /* EX_WAIT0_A */
-               [ 9] = PIN_NUMBER('C', 1),      /* PRESETOUT# */
+               [ 9] = PIN_PRESETOUT_N,         /* PRESETOUT# */
                [10] = RCAR_GP_PIN(0,  0),      /* D0 */
                [11] = RCAR_GP_PIN(0,  1),      /* D1 */
                [12] = RCAR_GP_PIN(0,  2),      /* D2 */
@@ -5646,20 +5678,20 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [27] = RCAR_GP_PIN(7,  1),      /* AVS2 */
                [28] = RCAR_GP_PIN(7,  2),      /* GP7_02 */
                [29] = RCAR_GP_PIN(7,  3),      /* GP7_03 */
-               [30] = PIN_A_NUMBER('P', 7),    /* DU_DOTCLKIN0 */
-               [31] = PIN_A_NUMBER('P', 8),    /* DU_DOTCLKIN1 */
+               [30] = PIN_DU_DOTCLKIN0,        /* DU_DOTCLKIN0 */
+               [31] = PIN_DU_DOTCLKIN1,        /* DU_DOTCLKIN1 */
        } },
        { PINMUX_BIAS_REG("PUEN3", 0xe606040c, "PUD3", 0xe606044c) {
-               [ 0] = PIN_A_NUMBER('R', 7),    /* DU_DOTCLKIN2 */
-               [ 1] = PIN_A_NUMBER('R', 8),    /* DU_DOTCLKIN3 */
-               [ 2] = PIN_A_NUMBER('D', 38),   /* FSCLKST# */
-               [ 3] = PIN_A_NUMBER('D', 39),   /* EXTALR*/
-               [ 4] = PIN_A_NUMBER('R', 26),   /* TRST# */
-               [ 5] = PIN_A_NUMBER('T', 27),   /* TCK */
-               [ 6] = PIN_A_NUMBER('R', 30),   /* TMS */
-               [ 7] = PIN_A_NUMBER('R', 29),   /* TDI */
-               [ 8] = PIN_NONE,
-               [ 9] = PIN_A_NUMBER('T', 30),   /* ASEBRK */
+               [ 0] = PIN_DU_DOTCLKIN2,        /* DU_DOTCLKIN2 */
+               [ 1] = PIN_DU_DOTCLKIN3,        /* DU_DOTCLKIN3 */
+               [ 2] = PIN_FSCLKST_N,           /* FSCLKST# */
+               [ 3] = PIN_EXTALR,              /* EXTALR*/
+               [ 4] = PIN_TRST_N,              /* TRST# */
+               [ 5] = PIN_TCK,                 /* TCK */
+               [ 6] = PIN_TMS,                 /* TMS */
+               [ 7] = PIN_TDI,                 /* TDI */
+               [ 8] = SH_PFC_PIN_NONE,
+               [ 9] = PIN_ASEBRK,              /* ASEBRK */
                [10] = RCAR_GP_PIN(3,  0),      /* SD0_CLK */
                [11] = RCAR_GP_PIN(3,  1),      /* SD0_CMD */
                [12] = RCAR_GP_PIN(3,  2),      /* SD0_DAT0 */
@@ -5724,7 +5756,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [ 3] = RCAR_GP_PIN(5, 23),      /* MLB_CLK */
                [ 4] = RCAR_GP_PIN(5, 24),      /* MLB_SIG */
                [ 5] = RCAR_GP_PIN(5, 25),      /* MLB_DAT */
-               [ 6] = PIN_NUMBER('H', 37),     /* MLB_REF */
+               [ 6] = PIN_MLB_REF,             /* MLB_REF */
                [ 7] = RCAR_GP_PIN(6,  0),      /* SSI_SCK01239 */
                [ 8] = RCAR_GP_PIN(6,  1),      /* SSI_WS01239 */
                [ 9] = RCAR_GP_PIN(6,  2),      /* SSI_SDATA0 */
@@ -5759,31 +5791,31 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [ 4] = RCAR_GP_PIN(6, 29),      /* USB30_OVC */
                [ 5] = RCAR_GP_PIN(6, 30),      /* USB31_PWEN */
                [ 6] = RCAR_GP_PIN(6, 31),      /* USB31_OVC */
-               [ 7] = PIN_NONE,
-               [ 8] = PIN_NONE,
-               [ 9] = PIN_NONE,
-               [10] = PIN_NONE,
-               [11] = PIN_NONE,
-               [12] = PIN_NONE,
-               [13] = PIN_NONE,
-               [14] = PIN_NONE,
-               [15] = PIN_NONE,
-               [16] = PIN_NONE,
-               [17] = PIN_NONE,
-               [18] = PIN_NONE,
-               [19] = PIN_NONE,
-               [20] = PIN_NONE,
-               [21] = PIN_NONE,
-               [22] = PIN_NONE,
-               [23] = PIN_NONE,
-               [24] = PIN_NONE,
-               [25] = PIN_NONE,
-               [26] = PIN_NONE,
-               [27] = PIN_NONE,
-               [28] = PIN_NONE,
-               [29] = PIN_NONE,
-               [30] = PIN_NONE,
-               [31] = PIN_NONE,
+               [ 7] = SH_PFC_PIN_NONE,
+               [ 8] = SH_PFC_PIN_NONE,
+               [ 9] = SH_PFC_PIN_NONE,
+               [10] = SH_PFC_PIN_NONE,
+               [11] = SH_PFC_PIN_NONE,
+               [12] = SH_PFC_PIN_NONE,
+               [13] = SH_PFC_PIN_NONE,
+               [14] = SH_PFC_PIN_NONE,
+               [15] = SH_PFC_PIN_NONE,
+               [16] = SH_PFC_PIN_NONE,
+               [17] = SH_PFC_PIN_NONE,
+               [18] = SH_PFC_PIN_NONE,
+               [19] = SH_PFC_PIN_NONE,
+               [20] = SH_PFC_PIN_NONE,
+               [21] = SH_PFC_PIN_NONE,
+               [22] = SH_PFC_PIN_NONE,
+               [23] = SH_PFC_PIN_NONE,
+               [24] = SH_PFC_PIN_NONE,
+               [25] = SH_PFC_PIN_NONE,
+               [26] = SH_PFC_PIN_NONE,
+               [27] = SH_PFC_PIN_NONE,
+               [28] = SH_PFC_PIN_NONE,
+               [29] = SH_PFC_PIN_NONE,
+               [30] = SH_PFC_PIN_NONE,
+               [31] = SH_PFC_PIN_NONE,
        } },
        { /* sentinel */ },
 };
index 68bcb89..7df010f 100644 (file)
 #include "core.h"
 #include "sh_pfc.h"
 
-#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | \
-                  SH_PFC_PIN_CFG_PULL_UP | \
-                  SH_PFC_PIN_CFG_PULL_DOWN)
+#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_PULL_UP_DOWN)
 
-#define CPU_ALL_PORT(fn, sfx)                                          \
+#define CPU_ALL_GP(fn, sfx)                                            \
        PORT_GP_CFG_16(0, fn, sfx, CFG_FLAGS),  \
        PORT_GP_CFG_29(1, fn, sfx, CFG_FLAGS),  \
        PORT_GP_CFG_15(2, fn, sfx, CFG_FLAGS),  \
        PORT_GP_CFG_26(5, fn, sfx, CFG_FLAGS),  \
        PORT_GP_CFG_32(6, fn, sfx, CFG_FLAGS),  \
        PORT_GP_CFG_4(7, fn, sfx, CFG_FLAGS)
+
+#define CPU_ALL_NOGP(fn)                                               \
+       PIN_NOGP_CFG(ASEBRK, "ASEBRK", fn, CFG_FLAGS),                  \
+       PIN_NOGP_CFG(AVB_MDIO, "AVB_MDIO", fn, CFG_FLAGS),              \
+       PIN_NOGP_CFG(AVB_RD0, "AVB_RD0", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_RD1, "AVB_RD1", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_RD2, "AVB_RD2", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_RD3, "AVB_RD3", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_RXC, "AVB_RXC", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_RX_CTL, "AVB_RX_CTL", fn, CFG_FLAGS),          \
+       PIN_NOGP_CFG(AVB_TD0, "AVB_TD0", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TD1, "AVB_TD1", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TD2, "AVB_TD2", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TD3, "AVB_TD3", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TXC, "AVB_TXC", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TXCREFCLK, "AVB_TXCREFCLK", fn, CFG_FLAGS),    \
+       PIN_NOGP_CFG(AVB_TX_CTL, "AVB_TX_CTL", fn, CFG_FLAGS),          \
+       PIN_NOGP_CFG(DU_DOTCLKIN0, "DU_DOTCLKIN0", fn, CFG_FLAGS),      \
+       PIN_NOGP_CFG(DU_DOTCLKIN1, "DU_DOTCLKIN1", fn, CFG_FLAGS),      \
+       PIN_NOGP_CFG(DU_DOTCLKIN2, "DU_DOTCLKIN2", fn, CFG_FLAGS),      \
+       PIN_NOGP_CFG(DU_DOTCLKIN3, "DU_DOTCLKIN3", fn, CFG_FLAGS),      \
+       PIN_NOGP_CFG(EXTALR, "EXTALR", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),\
+       PIN_NOGP_CFG(FSCLKST_N, "FSCLKST#", fn, CFG_FLAGS),             \
+       PIN_NOGP_CFG(MLB_REF, "MLB_REF", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT#", fn, CFG_FLAGS),         \
+       PIN_NOGP_CFG(QSPI0_IO2, "QSPI0_IO2", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(QSPI0_IO3, "QSPI0_IO3", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(QSPI0_MISO_IO1, "QSPI0_MISO_IO1", fn, CFG_FLAGS),  \
+       PIN_NOGP_CFG(QSPI0_MOSI_IO0, "QSPI0_MOSI_IO0", fn, CFG_FLAGS),  \
+       PIN_NOGP_CFG(QSPI0_SPCLK, "QSPI0_SPCLK", fn, CFG_FLAGS),        \
+       PIN_NOGP_CFG(QSPI0_SSL, "QSPI0_SSL", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(QSPI1_IO2, "QSPI1_IO2", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(QSPI1_IO3, "QSPI1_IO3", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(QSPI1_MISO_IO1, "QSPI1_MISO_IO1", fn, CFG_FLAGS),  \
+       PIN_NOGP_CFG(QSPI1_MOSI_IO0, "QSPI1_MOSI_IO0", fn, CFG_FLAGS),  \
+       PIN_NOGP_CFG(QSPI1_SPCLK, "QSPI1_SPCLK", fn, CFG_FLAGS),        \
+       PIN_NOGP_CFG(QSPI1_SSL, "QSPI1_SSL", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(RPC_INT_N, "RPC_INT#", fn, CFG_FLAGS),             \
+       PIN_NOGP_CFG(RPC_RESET_N, "RPC_RESET#", fn, CFG_FLAGS),         \
+       PIN_NOGP_CFG(RPC_WP_N, "RPC_WP#", fn, CFG_FLAGS),               \
+       PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),      \
+       PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),      \
+       PIN_NOGP_CFG(TDO, "TDO", fn, SH_PFC_PIN_CFG_DRIVE_STRENGTH),    \
+       PIN_NOGP_CFG(TMS, "TMS", fn, CFG_FLAGS),                        \
+       PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN)
+
 /*
  * F_() : just information
  * FM() : macro for FN_xxx / xxx_MARK
@@ -1508,68 +1552,16 @@ static const u16 pinmux_data[] = {
 };
 
 /*
- * R8A7795 has 8 banks with 32 GPIOs in each => 256 GPIOs.
- * Physical layout rows: A - AW, cols: 1 - 39.
+ * Pins not associated with a GPIO port.
  */
-#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r))
-#define PIN_NUMBER(r, c) (((r) - 'A') * 39 + (c) + 300)
-#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c)
-#define PIN_NONE U16_MAX
+enum {
+       GP_ASSIGN_LAST(),
+       NOGP_ALL(),
+};
 
 static const struct sh_pfc_pin pinmux_pins[] = {
        PINMUX_GPIO_GP_ALL(),
-
-       /*
-        * Pins not associated with a GPIO port.
-        *
-        * The pin positions are different between different r8a7795
-        * packages, all that is needed for the pfc driver is a unique
-        * number for each pin. To this end use the pin layout from
-        * R-Car H3SiP to calculate a unique number for each pin.
-        */
-       SH_PFC_PIN_NAMED_CFG('A',  8, AVB_TX_CTL, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A',  9, AVB_MDIO, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 12, AVB_TXCREFCLK, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 13, AVB_RD0, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 14, AVB_RD2, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 16, AVB_RX_CTL, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 17, AVB_TD2, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 18, AVB_TD0, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 19, AVB_TXC, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('B', 13, AVB_RD1, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('B', 14, AVB_RD3, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('B', 17, AVB_TD3, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('C',  1, PRESETOUT#, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('V',  3, QSPI1_SPCLK, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('V',  5, QSPI1_SSL, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('V',  6, RPC_WP#, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('V',  7, RPC_RESET#, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('W',  3, QSPI0_SPCLK, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('Y',  3, QSPI0_SSL, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('Y',  6, QSPI0_IO2, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('Y',  7, RPC_INT#, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'),  4, QSPI0_MISO_IO1, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'),  6, QSPI0_IO3, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  3, QSPI1_IO3, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  5, QSPI0_MOSI_IO0, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  7, QSPI1_MOSI_IO0, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 38, FSCLKST#, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 39, EXTALR, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'),  4, QSPI1_IO2, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'),  5, QSPI1_MISO_IO1, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'),  7, DU_DOTCLKIN0, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'),  8, DU_DOTCLKIN1, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'),  7, DU_DOTCLKIN2, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'),  8, DU_DOTCLKIN3, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 26, TRST#, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 29, TDI, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 30, TMS, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 27, TCK, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 28, TDO, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, CFG_FLAGS),
+       PINMUX_NOGP_ALL(),
 };
 
 /* - AUDIO CLOCK ------------------------------------------------------------ */
@@ -1717,7 +1709,7 @@ static const unsigned int avb_phy_int_mux[] = {
 };
 static const unsigned int avb_mdio_pins[] = {
        /* AVB_MDC, AVB_MDIO */
-       RCAR_GP_PIN(2, 9), PIN_NUMBER('A', 9),
+       RCAR_GP_PIN(2, 9), PIN_AVB_MDIO,
 };
 static const unsigned int avb_mdio_mux[] = {
        AVB_MDC_MARK, AVB_MDIO_MARK,
@@ -1730,11 +1722,11 @@ static const unsigned int avb_mii_pins[] = {
         * AVB_RD1, AVB_RD2, AVB_RD3,
         * AVB_TXCREFCLK
         */
-       PIN_NUMBER('A', 8), PIN_NUMBER('A', 19), PIN_NUMBER('A', 18),
-       PIN_NUMBER('B', 18), PIN_NUMBER('A', 17), PIN_NUMBER('B', 17),
-       PIN_NUMBER('A', 16), PIN_NUMBER('B', 19), PIN_NUMBER('A', 13),
-       PIN_NUMBER('B', 13), PIN_NUMBER('A', 14), PIN_NUMBER('B', 14),
-       PIN_NUMBER('A', 12),
+       PIN_AVB_TX_CTL, PIN_AVB_TXC, PIN_AVB_TD0,
+       PIN_AVB_TD1, PIN_AVB_TD2, PIN_AVB_TD3,
+       PIN_AVB_RX_CTL, PIN_AVB_RXC, PIN_AVB_RD0,
+       PIN_AVB_RD1, PIN_AVB_RD2, PIN_AVB_RD3,
+       PIN_AVB_TXCREFCLK,
 
 };
 static const unsigned int avb_mii_mux[] = {
@@ -3901,6 +3893,36 @@ static const unsigned int tmu_tclk2_b_mux[] = {
        TCLK2_B_MARK,
 };
 
+/* - TPU ------------------------------------------------------------------- */
+static const unsigned int tpu_to0_pins[] = {
+       /* TPU0TO0 */
+       RCAR_GP_PIN(6, 28),
+};
+static const unsigned int tpu_to0_mux[] = {
+       TPU0TO0_MARK,
+};
+static const unsigned int tpu_to1_pins[] = {
+       /* TPU0TO1 */
+       RCAR_GP_PIN(6, 29),
+};
+static const unsigned int tpu_to1_mux[] = {
+       TPU0TO1_MARK,
+};
+static const unsigned int tpu_to2_pins[] = {
+       /* TPU0TO2 */
+       RCAR_GP_PIN(6, 30),
+};
+static const unsigned int tpu_to2_mux[] = {
+       TPU0TO2_MARK,
+};
+static const unsigned int tpu_to3_pins[] = {
+       /* TPU0TO3 */
+       RCAR_GP_PIN(6, 31),
+};
+static const unsigned int tpu_to3_mux[] = {
+       TPU0TO3_MARK,
+};
+
 /* - USB0 ------------------------------------------------------------------- */
 static const unsigned int usb0_pins[] = {
        /* PWEN, OVC */
@@ -4451,6 +4473,10 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(tmu_tclk1_b),
        SH_PFC_PIN_GROUP(tmu_tclk2_a),
        SH_PFC_PIN_GROUP(tmu_tclk2_b),
+       SH_PFC_PIN_GROUP(tpu_to0),
+       SH_PFC_PIN_GROUP(tpu_to1),
+       SH_PFC_PIN_GROUP(tpu_to2),
+       SH_PFC_PIN_GROUP(tpu_to3),
        SH_PFC_PIN_GROUP(usb0),
        SH_PFC_PIN_GROUP(usb1),
        SH_PFC_PIN_GROUP(usb2),
@@ -4946,6 +4972,13 @@ static const char * const tmu_groups[] = {
        "tmu_tclk2_b",
 };
 
+static const char * const tpu_groups[] = {
+       "tpu_to0",
+       "tpu_to1",
+       "tpu_to2",
+       "tpu_to3",
+};
+
 static const char * const usb0_groups[] = {
        "usb0",
 };
@@ -5048,6 +5081,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
        SH_PFC_FUNCTION(sdhi3),
        SH_PFC_FUNCTION(ssi),
        SH_PFC_FUNCTION(tmu),
+       SH_PFC_FUNCTION(tpu),
        SH_PFC_FUNCTION(usb0),
        SH_PFC_FUNCTION(usb1),
        SH_PFC_FUNCTION(usb2),
@@ -5623,44 +5657,44 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
 
 static const struct pinmux_drive_reg pinmux_drive_regs[] = {
        { PINMUX_DRIVE_REG("DRVCTRL0", 0xe6060300) {
-               { PIN_NUMBER('W', 3),   28, 2 },        /* QSPI0_SPCLK */
-               { PIN_A_NUMBER('C', 5), 24, 2 },        /* QSPI0_MOSI_IO0 */
-               { PIN_A_NUMBER('B', 4), 20, 2 },        /* QSPI0_MISO_IO1 */
-               { PIN_NUMBER('Y', 6),   16, 2 },        /* QSPI0_IO2 */
-               { PIN_A_NUMBER('B', 6), 12, 2 },        /* QSPI0_IO3 */
-               { PIN_NUMBER('Y', 3),    8, 2 },        /* QSPI0_SSL */
-               { PIN_NUMBER('V', 3),    4, 2 },        /* QSPI1_SPCLK */
-               { PIN_A_NUMBER('C', 7),  0, 2 },        /* QSPI1_MOSI_IO0 */
+               { PIN_QSPI0_SPCLK,    28, 2 },  /* QSPI0_SPCLK */
+               { PIN_QSPI0_MOSI_IO0, 24, 2 },  /* QSPI0_MOSI_IO0 */
+               { PIN_QSPI0_MISO_IO1, 20, 2 },  /* QSPI0_MISO_IO1 */
+               { PIN_QSPI0_IO2,      16, 2 },  /* QSPI0_IO2 */
+               { PIN_QSPI0_IO3,      12, 2 },  /* QSPI0_IO3 */
+               { PIN_QSPI0_SSL,       8, 2 },  /* QSPI0_SSL */
+               { PIN_QSPI1_SPCLK,     4, 2 },  /* QSPI1_SPCLK */
+               { PIN_QSPI1_MOSI_IO0,  0, 2 },  /* QSPI1_MOSI_IO0 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL1", 0xe6060304) {
-               { PIN_A_NUMBER('E', 5), 28, 2 },        /* QSPI1_MISO_IO1 */
-               { PIN_A_NUMBER('E', 4), 24, 2 },        /* QSPI1_IO2 */
-               { PIN_A_NUMBER('C', 3), 20, 2 },        /* QSPI1_IO3 */
-               { PIN_NUMBER('V', 5),   16, 2 },        /* QSPI1_SSL */
-               { PIN_NUMBER('Y', 7),   12, 2 },        /* RPC_INT# */
-               { PIN_NUMBER('V', 6),    8, 2 },        /* RPC_WP# */
-               { PIN_NUMBER('V', 7),    4, 2 },        /* RPC_RESET# */
-               { PIN_NUMBER('A', 16),   0, 3 },        /* AVB_RX_CTL */
+               { PIN_QSPI1_MISO_IO1, 28, 2 },  /* QSPI1_MISO_IO1 */
+               { PIN_QSPI1_IO2,      24, 2 },  /* QSPI1_IO2 */
+               { PIN_QSPI1_IO3,      20, 2 },  /* QSPI1_IO3 */
+               { PIN_QSPI1_SSL,      16, 2 },  /* QSPI1_SSL */
+               { PIN_RPC_INT_N,      12, 2 },  /* RPC_INT# */
+               { PIN_RPC_WP_N,        8, 2 },  /* RPC_WP# */
+               { PIN_RPC_RESET_N,     4, 2 },  /* RPC_RESET# */
+               { PIN_AVB_RX_CTL,      0, 3 },  /* AVB_RX_CTL */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL2", 0xe6060308) {
-               { PIN_NUMBER('B', 19),  28, 3 },        /* AVB_RXC */
-               { PIN_NUMBER('A', 13),  24, 3 },        /* AVB_RD0 */
-               { PIN_NUMBER('B', 13),  20, 3 },        /* AVB_RD1 */
-               { PIN_NUMBER('A', 14),  16, 3 },        /* AVB_RD2 */
-               { PIN_NUMBER('B', 14),  12, 3 },        /* AVB_RD3 */
-               { PIN_NUMBER('A', 8),    8, 3 },        /* AVB_TX_CTL */
-               { PIN_NUMBER('A', 19),   4, 3 },        /* AVB_TXC */
-               { PIN_NUMBER('A', 18),   0, 3 },        /* AVB_TD0 */
+               { PIN_AVB_RXC,        28, 3 },  /* AVB_RXC */
+               { PIN_AVB_RD0,        24, 3 },  /* AVB_RD0 */
+               { PIN_AVB_RD1,        20, 3 },  /* AVB_RD1 */
+               { PIN_AVB_RD2,        16, 3 },  /* AVB_RD2 */
+               { PIN_AVB_RD3,        12, 3 },  /* AVB_RD3 */
+               { PIN_AVB_TX_CTL,      8, 3 },  /* AVB_TX_CTL */
+               { PIN_AVB_TXC,         4, 3 },  /* AVB_TXC */
+               { PIN_AVB_TD0,         0, 3 },  /* AVB_TD0 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL3", 0xe606030c) {
-               { PIN_NUMBER('B', 18),  28, 3 },        /* AVB_TD1 */
-               { PIN_NUMBER('A', 17),  24, 3 },        /* AVB_TD2 */
-               { PIN_NUMBER('B', 17),  20, 3 },        /* AVB_TD3 */
-               { PIN_NUMBER('A', 12),  16, 3 },        /* AVB_TXCREFCLK */
-               { PIN_NUMBER('A', 9),   12, 3 },        /* AVB_MDIO */
-               { RCAR_GP_PIN(2,  9),    8, 3 },        /* AVB_MDC */
-               { RCAR_GP_PIN(2, 10),    4, 3 },        /* AVB_MAGIC */
-               { RCAR_GP_PIN(2, 11),    0, 3 },        /* AVB_PHY_INT */
+               { PIN_AVB_TD1,        28, 3 },  /* AVB_TD1 */
+               { PIN_AVB_TD2,        24, 3 },  /* AVB_TD2 */
+               { PIN_AVB_TD3,        20, 3 },  /* AVB_TD3 */
+               { PIN_AVB_TXCREFCLK,  16, 3 },  /* AVB_TXCREFCLK */
+               { PIN_AVB_MDIO,       12, 3 },  /* AVB_MDIO */
+               { RCAR_GP_PIN(2,  9),  8, 3 },  /* AVB_MDC */
+               { RCAR_GP_PIN(2, 10),  4, 3 },  /* AVB_MAGIC */
+               { RCAR_GP_PIN(2, 11),  0, 3 },  /* AVB_PHY_INT */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL4", 0xe6060310) {
                { RCAR_GP_PIN(2, 12), 28, 3 },  /* AVB_LINK */
@@ -5714,7 +5748,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
        } },
        { PINMUX_DRIVE_REG("DRVCTRL9", 0xe6060324) {
                { RCAR_GP_PIN(1, 27), 28, 3 },  /* EX_WAIT0 */
-               { PIN_NUMBER('C', 1), 24, 3 },  /* PRESETOUT# */
+               { PIN_PRESETOUT_N,    24, 3 },  /* PRESETOUT# */
                { RCAR_GP_PIN(0,  0), 20, 3 },  /* D0 */
                { RCAR_GP_PIN(0,  1), 16, 3 },  /* D1 */
                { RCAR_GP_PIN(0,  2), 12, 3 },  /* D2 */
@@ -5733,30 +5767,30 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
                { RCAR_GP_PIN(0, 13),  0, 3 },  /* D13 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL11", 0xe606032c) {
-               { RCAR_GP_PIN(0, 14),   28, 3 },        /* D14 */
-               { RCAR_GP_PIN(0, 15),   24, 3 },        /* D15 */
-               { RCAR_GP_PIN(7,  0),   20, 3 },        /* AVS1 */
-               { RCAR_GP_PIN(7,  1),   16, 3 },        /* AVS2 */
-               { RCAR_GP_PIN(7,  2),   12, 3 },        /* GP7_02 */
-               { RCAR_GP_PIN(7,  3),    8, 3 },        /* GP7_03 */
-               { PIN_A_NUMBER('P', 7),  4, 2 },        /* DU_DOTCLKIN0 */
-               { PIN_A_NUMBER('P', 8),  0, 2 },        /* DU_DOTCLKIN1 */
+               { RCAR_GP_PIN(0, 14), 28, 3 },  /* D14 */
+               { RCAR_GP_PIN(0, 15), 24, 3 },  /* D15 */
+               { RCAR_GP_PIN(7,  0), 20, 3 },  /* AVS1 */
+               { RCAR_GP_PIN(7,  1), 16, 3 },  /* AVS2 */
+               { RCAR_GP_PIN(7,  2), 12, 3 },  /* GP7_02 */
+               { RCAR_GP_PIN(7,  3),  8, 3 },  /* GP7_03 */
+               { PIN_DU_DOTCLKIN0,    4, 2 },  /* DU_DOTCLKIN0 */
+               { PIN_DU_DOTCLKIN1,    0, 2 },  /* DU_DOTCLKIN1 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL12", 0xe6060330) {
-               { PIN_A_NUMBER('R', 7),  28, 2 },       /* DU_DOTCLKIN2 */
-               { PIN_A_NUMBER('R', 8),  24, 2 },       /* DU_DOTCLKIN3 */
-               { PIN_A_NUMBER('D', 38), 20, 2 },       /* FSCLKST# */
-               { PIN_A_NUMBER('R', 30),  4, 2 },       /* TMS */
+               { PIN_DU_DOTCLKIN2,   28, 2 },  /* DU_DOTCLKIN2 */
+               { PIN_DU_DOTCLKIN3,   24, 2 },  /* DU_DOTCLKIN3 */
+               { PIN_FSCLKST_N,      20, 2 },  /* FSCLKST# */
+               { PIN_TMS,             4, 2 },  /* TMS */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL13", 0xe6060334) {
-               { PIN_A_NUMBER('T', 28), 28, 2 },       /* TDO */
-               { PIN_A_NUMBER('T', 30), 24, 2 },       /* ASEBRK */
-               { RCAR_GP_PIN(3,  0),    20, 3 },       /* SD0_CLK */
-               { RCAR_GP_PIN(3,  1),    16, 3 },       /* SD0_CMD */
-               { RCAR_GP_PIN(3,  2),    12, 3 },       /* SD0_DAT0 */
-               { RCAR_GP_PIN(3,  3),     8, 3 },       /* SD0_DAT1 */
-               { RCAR_GP_PIN(3,  4),     4, 3 },       /* SD0_DAT2 */
-               { RCAR_GP_PIN(3,  5),     0, 3 },       /* SD0_DAT3 */
+               { PIN_TDO,            28, 2 },  /* TDO */
+               { PIN_ASEBRK,         24, 2 },  /* ASEBRK */
+               { RCAR_GP_PIN(3,  0), 20, 3 },  /* SD0_CLK */
+               { RCAR_GP_PIN(3,  1), 16, 3 },  /* SD0_CMD */
+               { RCAR_GP_PIN(3,  2), 12, 3 },  /* SD0_DAT0 */
+               { RCAR_GP_PIN(3,  3),  8, 3 },  /* SD0_DAT1 */
+               { RCAR_GP_PIN(3,  4),  4, 3 },  /* SD0_DAT2 */
+               { RCAR_GP_PIN(3,  5),  0, 3 },  /* SD0_DAT3 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL14", 0xe6060338) {
                { RCAR_GP_PIN(3,  6), 28, 3 },  /* SD1_CLK */
@@ -5825,7 +5859,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
                { RCAR_GP_PIN(5, 23), 16, 3 },  /* MLB_CLK */
                { RCAR_GP_PIN(5, 24), 12, 3 },  /* MLB_SIG */
                { RCAR_GP_PIN(5, 25),  8, 3 },  /* MLB_DAT */
-               { PIN_NUMBER('H', 37),  4, 3 }, /* MLB_REF */
+               { PIN_MLB_REF,         4, 3 },  /* MLB_REF */
                { RCAR_GP_PIN(6,  0),  0, 3 },  /* SSI_SCK01239 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL21", 0xe6060354) {
@@ -5898,35 +5932,35 @@ static int r8a7795_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *poc
 
 static const struct pinmux_bias_reg pinmux_bias_regs[] = {
        { PINMUX_BIAS_REG("PUEN0", 0xe6060400, "PUD0", 0xe6060440) {
-               [ 0] = PIN_NUMBER('W', 3),      /* QSPI0_SPCLK */
-               [ 1] = PIN_A_NUMBER('C', 5),    /* QSPI0_MOSI_IO0 */
-               [ 2] = PIN_A_NUMBER('B', 4),    /* QSPI0_MISO_IO1 */
-               [ 3] = PIN_NUMBER('Y', 6),      /* QSPI0_IO2 */
-               [ 4] = PIN_A_NUMBER('B', 6),    /* QSPI0_IO3 */
-               [ 5] = PIN_NUMBER('Y', 3),      /* QSPI0_SSL */
-               [ 6] = PIN_NUMBER('V', 3),      /* QSPI1_SPCLK */
-               [ 7] = PIN_A_NUMBER('C', 7),    /* QSPI1_MOSI_IO0 */
-               [ 8] = PIN_A_NUMBER('E', 5),    /* QSPI1_MISO_IO1 */
-               [ 9] = PIN_A_NUMBER('E', 4),    /* QSPI1_IO2 */
-               [10] = PIN_A_NUMBER('C', 3),    /* QSPI1_IO3 */
-               [11] = PIN_NUMBER('V', 5),      /* QSPI1_SSL */
-               [12] = PIN_NUMBER('Y', 7),      /* RPC_INT# */
-               [13] = PIN_NUMBER('V', 6),      /* RPC_WP# */
-               [14] = PIN_NUMBER('V', 7),      /* RPC_RESET# */
-               [15] = PIN_NUMBER('A', 16),     /* AVB_RX_CTL */
-               [16] = PIN_NUMBER('B', 19),     /* AVB_RXC */
-               [17] = PIN_NUMBER('A', 13),     /* AVB_RD0 */
-               [18] = PIN_NUMBER('B', 13),     /* AVB_RD1 */
-               [19] = PIN_NUMBER('A', 14),     /* AVB_RD2 */
-               [20] = PIN_NUMBER('B', 14),     /* AVB_RD3 */
-               [21] = PIN_NUMBER('A', 8),      /* AVB_TX_CTL */
-               [22] = PIN_NUMBER('A', 19),     /* AVB_TXC */
-               [23] = PIN_NUMBER('A', 18),     /* AVB_TD0 */
-               [24] = PIN_NUMBER('B', 18),     /* AVB_TD1 */
-               [25] = PIN_NUMBER('A', 17),     /* AVB_TD2 */
-               [26] = PIN_NUMBER('B', 17),     /* AVB_TD3 */
-               [27] = PIN_NUMBER('A', 12),     /* AVB_TXCREFCLK */
-               [28] = PIN_NUMBER('A', 9),      /* AVB_MDIO */
+               [ 0] = PIN_QSPI0_SPCLK,         /* QSPI0_SPCLK */
+               [ 1] = PIN_QSPI0_MOSI_IO0,      /* QSPI0_MOSI_IO0 */
+               [ 2] = PIN_QSPI0_MISO_IO1,      /* QSPI0_MISO_IO1 */
+               [ 3] = PIN_QSPI0_IO2,           /* QSPI0_IO2 */
+               [ 4] = PIN_QSPI0_IO3,           /* QSPI0_IO3 */
+               [ 5] = PIN_QSPI0_SSL,           /* QSPI0_SSL */
+               [ 6] = PIN_QSPI1_SPCLK,         /* QSPI1_SPCLK */
+               [ 7] = PIN_QSPI1_MOSI_IO0,      /* QSPI1_MOSI_IO0 */
+               [ 8] = PIN_QSPI1_MISO_IO1,      /* QSPI1_MISO_IO1 */
+               [ 9] = PIN_QSPI1_IO2,           /* QSPI1_IO2 */
+               [10] = PIN_QSPI1_IO3,           /* QSPI1_IO3 */
+               [11] = PIN_QSPI1_SSL,           /* QSPI1_SSL */
+               [12] = PIN_RPC_INT_N,           /* RPC_INT# */
+               [13] = PIN_RPC_WP_N,            /* RPC_WP# */
+               [14] = PIN_RPC_RESET_N,         /* RPC_RESET# */
+               [15] = PIN_AVB_RX_CTL,          /* AVB_RX_CTL */
+               [16] = PIN_AVB_RXC,             /* AVB_RXC */
+               [17] = PIN_AVB_RD0,             /* AVB_RD0 */
+               [18] = PIN_AVB_RD1,             /* AVB_RD1 */
+               [19] = PIN_AVB_RD2,             /* AVB_RD2 */
+               [20] = PIN_AVB_RD3,             /* AVB_RD3 */
+               [21] = PIN_AVB_TX_CTL,          /* AVB_TX_CTL */
+               [22] = PIN_AVB_TXC,             /* AVB_TXC */
+               [23] = PIN_AVB_TD0,             /* AVB_TD0 */
+               [24] = PIN_AVB_TD1,             /* AVB_TD1 */
+               [25] = PIN_AVB_TD2,             /* AVB_TD2 */
+               [26] = PIN_AVB_TD3,             /* AVB_TD3 */
+               [27] = PIN_AVB_TXCREFCLK,       /* AVB_TXCREFCLK */
+               [28] = PIN_AVB_MDIO,            /* AVB_MDIO */
                [29] = RCAR_GP_PIN(2,  9),      /* AVB_MDC */
                [30] = RCAR_GP_PIN(2, 10),      /* AVB_MAGIC */
                [31] = RCAR_GP_PIN(2, 11),      /* AVB_PHY_INT */
@@ -5975,7 +6009,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [ 6] = RCAR_GP_PIN(1, 25),      /* WE0_N */
                [ 7] = RCAR_GP_PIN(1, 26),      /* WE1_N */
                [ 8] = RCAR_GP_PIN(1, 27),      /* EX_WAIT0_A */
-               [ 9] = PIN_NUMBER('C', 1),      /* PRESETOUT# */
+               [ 9] = PIN_PRESETOUT_N,         /* PRESETOUT# */
                [10] = RCAR_GP_PIN(0,  0),      /* D0 */
                [11] = RCAR_GP_PIN(0,  1),      /* D1 */
                [12] = RCAR_GP_PIN(0,  2),      /* D2 */
@@ -5996,20 +6030,20 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [27] = RCAR_GP_PIN(7,  1),      /* AVS2 */
                [28] = RCAR_GP_PIN(7,  2),      /* GP7_02 */
                [29] = RCAR_GP_PIN(7,  3),      /* GP7_03 */
-               [30] = PIN_A_NUMBER('P', 7),    /* DU_DOTCLKIN0 */
-               [31] = PIN_A_NUMBER('P', 8),    /* DU_DOTCLKIN1 */
+               [30] = PIN_DU_DOTCLKIN0,        /* DU_DOTCLKIN0 */
+               [31] = PIN_DU_DOTCLKIN1,        /* DU_DOTCLKIN1 */
        } },
        { PINMUX_BIAS_REG("PUEN3", 0xe606040c, "PUD3", 0xe606044c) {
-               [ 0] = PIN_A_NUMBER('R', 7),    /* DU_DOTCLKIN2 */
-               [ 1] = PIN_A_NUMBER('R', 8),    /* DU_DOTCLKIN3 */
-               [ 2] = PIN_A_NUMBER('D', 38),   /* FSCLKST# */
-               [ 3] = PIN_A_NUMBER('D', 39),   /* EXTALR*/
-               [ 4] = PIN_A_NUMBER('R', 26),   /* TRST# */
-               [ 5] = PIN_A_NUMBER('T', 27),   /* TCK */
-               [ 6] = PIN_A_NUMBER('R', 30),   /* TMS */
-               [ 7] = PIN_A_NUMBER('R', 29),   /* TDI */
-               [ 8] = PIN_NONE,
-               [ 9] = PIN_A_NUMBER('T', 30),   /* ASEBRK */
+               [ 0] = PIN_DU_DOTCLKIN2,        /* DU_DOTCLKIN2 */
+               [ 1] = PIN_DU_DOTCLKIN3,        /* DU_DOTCLKIN3 */
+               [ 2] = PIN_FSCLKST_N,           /* FSCLKST# */
+               [ 3] = PIN_EXTALR,              /* EXTALR*/
+               [ 4] = PIN_TRST_N,              /* TRST# */
+               [ 5] = PIN_TCK,                 /* TCK */
+               [ 6] = PIN_TMS,                 /* TMS */
+               [ 7] = PIN_TDI,                 /* TDI */
+               [ 8] = SH_PFC_PIN_NONE,
+               [ 9] = PIN_ASEBRK,              /* ASEBRK */
                [10] = RCAR_GP_PIN(3,  0),      /* SD0_CLK */
                [11] = RCAR_GP_PIN(3,  1),      /* SD0_CMD */
                [12] = RCAR_GP_PIN(3,  2),      /* SD0_DAT0 */
@@ -6074,7 +6108,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [ 3] = RCAR_GP_PIN(5, 23),      /* MLB_CLK */
                [ 4] = RCAR_GP_PIN(5, 24),      /* MLB_SIG */
                [ 5] = RCAR_GP_PIN(5, 25),      /* MLB_DAT */
-               [ 6] = PIN_NUMBER('H', 37),     /* MLB_REF */
+               [ 6] = PIN_MLB_REF,             /* MLB_REF */
                [ 7] = RCAR_GP_PIN(6,  0),      /* SSI_SCK01239 */
                [ 8] = RCAR_GP_PIN(6,  1),      /* SSI_WS01239 */
                [ 9] = RCAR_GP_PIN(6,  2),      /* SSI_SDATA0 */
@@ -6109,31 +6143,31 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [ 4] = RCAR_GP_PIN(6, 29),      /* USB30_OVC */
                [ 5] = RCAR_GP_PIN(6, 30),      /* USB2_CH3_PWEN */
                [ 6] = RCAR_GP_PIN(6, 31),      /* USB2_CH3_OVC */
-               [ 7] = PIN_NONE,
-               [ 8] = PIN_NONE,
-               [ 9] = PIN_NONE,
-               [10] = PIN_NONE,
-               [11] = PIN_NONE,
-               [12] = PIN_NONE,
-               [13] = PIN_NONE,
-               [14] = PIN_NONE,
-               [15] = PIN_NONE,
-               [16] = PIN_NONE,
-               [17] = PIN_NONE,
-               [18] = PIN_NONE,
-               [19] = PIN_NONE,
-               [20] = PIN_NONE,
-               [21] = PIN_NONE,
-               [22] = PIN_NONE,
-               [23] = PIN_NONE,
-               [24] = PIN_NONE,
-               [25] = PIN_NONE,
-               [26] = PIN_NONE,
-               [27] = PIN_NONE,
-               [28] = PIN_NONE,
-               [29] = PIN_NONE,
-               [30] = PIN_NONE,
-               [31] = PIN_NONE,
+               [ 7] = SH_PFC_PIN_NONE,
+               [ 8] = SH_PFC_PIN_NONE,
+               [ 9] = SH_PFC_PIN_NONE,
+               [10] = SH_PFC_PIN_NONE,
+               [11] = SH_PFC_PIN_NONE,
+               [12] = SH_PFC_PIN_NONE,
+               [13] = SH_PFC_PIN_NONE,
+               [14] = SH_PFC_PIN_NONE,
+               [15] = SH_PFC_PIN_NONE,
+               [16] = SH_PFC_PIN_NONE,
+               [17] = SH_PFC_PIN_NONE,
+               [18] = SH_PFC_PIN_NONE,
+               [19] = SH_PFC_PIN_NONE,
+               [20] = SH_PFC_PIN_NONE,
+               [21] = SH_PFC_PIN_NONE,
+               [22] = SH_PFC_PIN_NONE,
+               [23] = SH_PFC_PIN_NONE,
+               [24] = SH_PFC_PIN_NONE,
+               [25] = SH_PFC_PIN_NONE,
+               [26] = SH_PFC_PIN_NONE,
+               [27] = SH_PFC_PIN_NONE,
+               [28] = SH_PFC_PIN_NONE,
+               [29] = SH_PFC_PIN_NONE,
+               [30] = SH_PFC_PIN_NONE,
+               [31] = SH_PFC_PIN_NONE,
        } },
        { /* sentinel */ },
 };
index 38cce69..61db7c7 100644 (file)
 #include "core.h"
 #include "sh_pfc.h"
 
-#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | \
-                  SH_PFC_PIN_CFG_PULL_UP | \
-                  SH_PFC_PIN_CFG_PULL_DOWN)
+#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_PULL_UP_DOWN)
 
-#define CPU_ALL_PORT(fn, sfx)                                          \
+#define CPU_ALL_GP(fn, sfx)                                            \
        PORT_GP_CFG_16(0, fn, sfx, CFG_FLAGS),  \
        PORT_GP_CFG_29(1, fn, sfx, CFG_FLAGS),  \
        PORT_GP_CFG_15(2, fn, sfx, CFG_FLAGS),  \
        PORT_GP_CFG_26(5, fn, sfx, CFG_FLAGS),  \
        PORT_GP_CFG_32(6, fn, sfx, CFG_FLAGS),  \
        PORT_GP_CFG_4(7, fn, sfx, CFG_FLAGS)
+
+#define CPU_ALL_NOGP(fn)                                               \
+       PIN_NOGP_CFG(ASEBRK, "ASEBRK", fn, CFG_FLAGS),                  \
+       PIN_NOGP_CFG(AVB_MDIO, "AVB_MDIO", fn, CFG_FLAGS),              \
+       PIN_NOGP_CFG(AVB_RD0, "AVB_RD0", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_RD1, "AVB_RD1", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_RD2, "AVB_RD2", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_RD3, "AVB_RD3", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_RXC, "AVB_RXC", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_RX_CTL, "AVB_RX_CTL", fn, CFG_FLAGS),          \
+       PIN_NOGP_CFG(AVB_TD0, "AVB_TD0", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TD1, "AVB_TD1", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TD2, "AVB_TD2", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TD3, "AVB_TD3", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TXC, "AVB_TXC", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TXCREFCLK, "AVB_TXCREFCLK", fn, CFG_FLAGS),    \
+       PIN_NOGP_CFG(AVB_TX_CTL, "AVB_TX_CTL", fn, CFG_FLAGS),          \
+       PIN_NOGP_CFG(DU_DOTCLKIN0, "DU_DOTCLKIN0", fn, CFG_FLAGS),      \
+       PIN_NOGP_CFG(DU_DOTCLKIN1, "DU_DOTCLKIN1", fn, CFG_FLAGS),      \
+       PIN_NOGP_CFG(DU_DOTCLKIN2, "DU_DOTCLKIN2", fn, CFG_FLAGS),      \
+       PIN_NOGP_CFG(EXTALR, "EXTALR", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),\
+       PIN_NOGP_CFG(FSCLKST, "FSCLKST", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(MLB_REF, "MLB_REF", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT#", fn, CFG_FLAGS),         \
+       PIN_NOGP_CFG(QSPI0_IO2, "QSPI0_IO2", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(QSPI0_IO3, "QSPI0_IO3", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(QSPI0_MISO_IO1, "QSPI0_MISO_IO1", fn, CFG_FLAGS),  \
+       PIN_NOGP_CFG(QSPI0_MOSI_IO0, "QSPI0_MOSI_IO0", fn, CFG_FLAGS),  \
+       PIN_NOGP_CFG(QSPI0_SPCLK, "QSPI0_SPCLK", fn, CFG_FLAGS),        \
+       PIN_NOGP_CFG(QSPI0_SSL, "QSPI0_SSL", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(QSPI1_IO2, "QSPI1_IO2", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(QSPI1_IO3, "QSPI1_IO3", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(QSPI1_MISO_IO1, "QSPI1_MISO_IO1", fn, CFG_FLAGS),  \
+       PIN_NOGP_CFG(QSPI1_MOSI_IO0, "QSPI1_MOSI_IO0", fn, CFG_FLAGS),  \
+       PIN_NOGP_CFG(QSPI1_SPCLK, "QSPI1_SPCLK", fn, CFG_FLAGS),        \
+       PIN_NOGP_CFG(QSPI1_SSL, "QSPI1_SSL", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(RPC_INT_N, "RPC_INT#", fn, CFG_FLAGS),             \
+       PIN_NOGP_CFG(RPC_RESET_N, "RPC_RESET#", fn, CFG_FLAGS),         \
+       PIN_NOGP_CFG(RPC_WP_N, "RPC_WP#", fn, CFG_FLAGS),               \
+       PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),      \
+       PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),      \
+       PIN_NOGP_CFG(TDO, "TDO", fn, SH_PFC_PIN_CFG_DRIVE_STRENGTH),    \
+       PIN_NOGP_CFG(TMS, "TMS", fn, CFG_FLAGS),                        \
+       PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN)
+
 /*
  * F_() : just information
  * FM() : macro for FN_xxx / xxx_MARK
@@ -1512,67 +1555,16 @@ static const u16 pinmux_data[] = {
 };
 
 /*
- * R8A7796 has 8 banks with 32 GPIOs in each => 256 GPIOs.
- * Physical layout rows: A - AW, cols: 1 - 39.
+ * Pins not associated with a GPIO port.
  */
-#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r))
-#define PIN_NUMBER(r, c) (((r) - 'A') * 39 + (c) + 300)
-#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c)
-#define PIN_NONE U16_MAX
+enum {
+       GP_ASSIGN_LAST(),
+       NOGP_ALL(),
+};
 
 static const struct sh_pfc_pin pinmux_pins[] = {
        PINMUX_GPIO_GP_ALL(),
-
-       /*
-        * Pins not associated with a GPIO port.
-        *
-        * The pin positions are different between different r8a7796
-        * packages, all that is needed for the pfc driver is a unique
-        * number for each pin. To this end use the pin layout from
-        * R-Car M3SiP to calculate a unique number for each pin.
-        */
-       SH_PFC_PIN_NAMED_CFG('A',  8, AVB_TX_CTL, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A',  9, AVB_MDIO, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 12, AVB_TXCREFCLK, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 13, AVB_RD0, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 14, AVB_RD2, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 16, AVB_RX_CTL, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 17, AVB_TD2, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 18, AVB_TD0, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 19, AVB_TXC, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('B', 13, AVB_RD1, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('B', 14, AVB_RD3, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('B', 17, AVB_TD3, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('C',  1, PRESETOUT#, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('V',  3, QSPI1_SPCLK, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('V',  5, QSPI1_SSL, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('V',  6, RPC_WP#, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('V',  7, RPC_RESET#, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('W',  3, QSPI0_SPCLK, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('Y',  3, QSPI0_SSL, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('Y',  6, QSPI0_IO2, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('Y',  7, RPC_INT#, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'),  4, QSPI0_MISO_IO1, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'),  6, QSPI0_IO3, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  3, QSPI1_IO3, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  5, QSPI0_MOSI_IO0, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  7, QSPI1_MOSI_IO0, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 38, FSCLKST, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 39, EXTALR, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'),  4, QSPI1_IO2, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'),  5, QSPI1_MISO_IO1, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'),  7, DU_DOTCLKIN0, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'),  8, DU_DOTCLKIN1, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'),  8, DU_DOTCLKIN2, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 26, TRST#, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 29, TDI, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 30, TMS, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 27, TCK, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 28, TDO, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, CFG_FLAGS),
+       PINMUX_NOGP_ALL(),
 };
 
 /* - AUDIO CLOCK ------------------------------------------------------------ */
@@ -1721,7 +1713,7 @@ static const unsigned int avb_phy_int_mux[] = {
 };
 static const unsigned int avb_mdio_pins[] = {
        /* AVB_MDC, AVB_MDIO */
-       RCAR_GP_PIN(2, 9), PIN_NUMBER('A', 9),
+       RCAR_GP_PIN(2, 9), PIN_AVB_MDIO,
 };
 static const unsigned int avb_mdio_mux[] = {
        AVB_MDC_MARK, AVB_MDIO_MARK,
@@ -1734,11 +1726,11 @@ static const unsigned int avb_mii_pins[] = {
         * AVB_RD1, AVB_RD2, AVB_RD3,
         * AVB_TXCREFCLK
         */
-       PIN_NUMBER('A', 8), PIN_NUMBER('A', 19), PIN_NUMBER('A', 18),
-       PIN_NUMBER('B', 18), PIN_NUMBER('A', 17), PIN_NUMBER('B', 17),
-       PIN_NUMBER('A', 16), PIN_NUMBER('B', 19), PIN_NUMBER('A', 13),
-       PIN_NUMBER('B', 13), PIN_NUMBER('A', 14), PIN_NUMBER('B', 14),
-       PIN_NUMBER('A', 12),
+       PIN_AVB_TX_CTL, PIN_AVB_TXC, PIN_AVB_TD0,
+       PIN_AVB_TD1, PIN_AVB_TD2, PIN_AVB_TD3,
+       PIN_AVB_RX_CTL, PIN_AVB_RXC, PIN_AVB_RD0,
+       PIN_AVB_RD1, PIN_AVB_RD2, PIN_AVB_RD3,
+       PIN_AVB_TXCREFCLK,
 
 };
 static const unsigned int avb_mii_mux[] = {
@@ -3891,6 +3883,36 @@ static const unsigned int tmu_tclk2_b_mux[] = {
        TCLK2_B_MARK,
 };
 
+/* - TPU ------------------------------------------------------------------- */
+static const unsigned int tpu_to0_pins[] = {
+       /* TPU0TO0 */
+       RCAR_GP_PIN(6, 28),
+};
+static const unsigned int tpu_to0_mux[] = {
+       TPU0TO0_MARK,
+};
+static const unsigned int tpu_to1_pins[] = {
+       /* TPU0TO1 */
+       RCAR_GP_PIN(6, 29),
+};
+static const unsigned int tpu_to1_mux[] = {
+       TPU0TO1_MARK,
+};
+static const unsigned int tpu_to2_pins[] = {
+       /* TPU0TO2 */
+       RCAR_GP_PIN(6, 30),
+};
+static const unsigned int tpu_to2_mux[] = {
+       TPU0TO2_MARK,
+};
+static const unsigned int tpu_to3_pins[] = {
+       /* TPU0TO3 */
+       RCAR_GP_PIN(6, 31),
+};
+static const unsigned int tpu_to3_mux[] = {
+       TPU0TO3_MARK,
+};
+
 /* - USB0 ------------------------------------------------------------------- */
 static const unsigned int usb0_pins[] = {
        /* PWEN, OVC */
@@ -4110,7 +4132,7 @@ static const unsigned int vin5_clk_mux[] = {
 };
 
 static const struct {
-       struct sh_pfc_pin_group common[312];
+       struct sh_pfc_pin_group common[316];
        struct sh_pfc_pin_group automotive[30];
 } pinmux_groups = {
        .common = {
@@ -4397,6 +4419,10 @@ static const struct {
                SH_PFC_PIN_GROUP(tmu_tclk1_b),
                SH_PFC_PIN_GROUP(tmu_tclk2_a),
                SH_PFC_PIN_GROUP(tmu_tclk2_b),
+               SH_PFC_PIN_GROUP(tpu_to0),
+               SH_PFC_PIN_GROUP(tpu_to1),
+               SH_PFC_PIN_GROUP(tpu_to2),
+               SH_PFC_PIN_GROUP(tpu_to3),
                SH_PFC_PIN_GROUP(usb0),
                SH_PFC_PIN_GROUP(usb1),
                SH_PFC_PIN_GROUP(usb30),
@@ -4918,6 +4944,13 @@ static const char * const tmu_groups[] = {
        "tmu_tclk2_b",
 };
 
+static const char * const tpu_groups[] = {
+       "tpu_to0",
+       "tpu_to1",
+       "tpu_to2",
+       "tpu_to3",
+};
+
 static const char * const usb0_groups[] = {
        "usb0",
 };
@@ -4963,7 +4996,7 @@ static const char * const vin5_groups[] = {
 };
 
 static const struct {
-       struct sh_pfc_function common[49];
+       struct sh_pfc_function common[50];
        struct sh_pfc_function automotive[4];
 } pinmux_functions = {
        .common = {
@@ -5011,6 +5044,7 @@ static const struct {
                SH_PFC_FUNCTION(sdhi3),
                SH_PFC_FUNCTION(ssi),
                SH_PFC_FUNCTION(tmu),
+               SH_PFC_FUNCTION(tpu),
                SH_PFC_FUNCTION(usb0),
                SH_PFC_FUNCTION(usb1),
                SH_PFC_FUNCTION(usb30),
@@ -5590,44 +5624,44 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
 
 static const struct pinmux_drive_reg pinmux_drive_regs[] = {
        { PINMUX_DRIVE_REG("DRVCTRL0", 0xe6060300) {
-               { PIN_NUMBER('W', 3),   28, 2 },        /* QSPI0_SPCLK */
-               { PIN_A_NUMBER('C', 5), 24, 2 },        /* QSPI0_MOSI_IO0 */
-               { PIN_A_NUMBER('B', 4), 20, 2 },        /* QSPI0_MISO_IO1 */
-               { PIN_NUMBER('Y', 6),   16, 2 },        /* QSPI0_IO2 */
-               { PIN_A_NUMBER('B', 6), 12, 2 },        /* QSPI0_IO3 */
-               { PIN_NUMBER('Y', 3),    8, 2 },        /* QSPI0_SSL */
-               { PIN_NUMBER('V', 3),    4, 2 },        /* QSPI1_SPCLK */
-               { PIN_A_NUMBER('C', 7),  0, 2 },        /* QSPI1_MOSI_IO0 */
+               { PIN_QSPI0_SPCLK,    28, 2 },  /* QSPI0_SPCLK */
+               { PIN_QSPI0_MOSI_IO0, 24, 2 },  /* QSPI0_MOSI_IO0 */
+               { PIN_QSPI0_MISO_IO1, 20, 2 },  /* QSPI0_MISO_IO1 */
+               { PIN_QSPI0_IO2,      16, 2 },  /* QSPI0_IO2 */
+               { PIN_QSPI0_IO3,      12, 2 },  /* QSPI0_IO3 */
+               { PIN_QSPI0_SSL,       8, 2 },  /* QSPI0_SSL */
+               { PIN_QSPI1_SPCLK,     4, 2 },  /* QSPI1_SPCLK */
+               { PIN_QSPI1_MOSI_IO0,  0, 2 },  /* QSPI1_MOSI_IO0 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL1", 0xe6060304) {
-               { PIN_A_NUMBER('E', 5), 28, 2 },        /* QSPI1_MISO_IO1 */
-               { PIN_A_NUMBER('E', 4), 24, 2 },        /* QSPI1_IO2 */
-               { PIN_A_NUMBER('C', 3), 20, 2 },        /* QSPI1_IO3 */
-               { PIN_NUMBER('V', 5),   16, 2 },        /* QSPI1_SSL */
-               { PIN_NUMBER('Y', 7),   12, 2 },        /* RPC_INT# */
-               { PIN_NUMBER('V', 6),    8, 2 },        /* RPC_WP# */
-               { PIN_NUMBER('V', 7),    4, 2 },        /* RPC_RESET# */
-               { PIN_NUMBER('A', 16),   0, 3 },        /* AVB_RX_CTL */
+               { PIN_QSPI1_MISO_IO1, 28, 2 },  /* QSPI1_MISO_IO1 */
+               { PIN_QSPI1_IO2,      24, 2 },  /* QSPI1_IO2 */
+               { PIN_QSPI1_IO3,      20, 2 },  /* QSPI1_IO3 */
+               { PIN_QSPI1_SSL,      16, 2 },  /* QSPI1_SSL */
+               { PIN_RPC_INT_N,      12, 2 },  /* RPC_INT# */
+               { PIN_RPC_WP_N,        8, 2 },  /* RPC_WP# */
+               { PIN_RPC_RESET_N,     4, 2 },  /* RPC_RESET# */
+               { PIN_AVB_RX_CTL,      0, 3 },  /* AVB_RX_CTL */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL2", 0xe6060308) {
-               { PIN_NUMBER('B', 19),  28, 3 },        /* AVB_RXC */
-               { PIN_NUMBER('A', 13),  24, 3 },        /* AVB_RD0 */
-               { PIN_NUMBER('B', 13),  20, 3 },        /* AVB_RD1 */
-               { PIN_NUMBER('A', 14),  16, 3 },        /* AVB_RD2 */
-               { PIN_NUMBER('B', 14),  12, 3 },        /* AVB_RD3 */
-               { PIN_NUMBER('A', 8),    8, 3 },        /* AVB_TX_CTL */
-               { PIN_NUMBER('A', 19),   4, 3 },        /* AVB_TXC */
-               { PIN_NUMBER('A', 18),   0, 3 },        /* AVB_TD0 */
+               { PIN_AVB_RXC,        28, 3 },  /* AVB_RXC */
+               { PIN_AVB_RD0,        24, 3 },  /* AVB_RD0 */
+               { PIN_AVB_RD1,        20, 3 },  /* AVB_RD1 */
+               { PIN_AVB_RD2,        16, 3 },  /* AVB_RD2 */
+               { PIN_AVB_RD3,        12, 3 },  /* AVB_RD3 */
+               { PIN_AVB_TX_CTL,      8, 3 },  /* AVB_TX_CTL */
+               { PIN_AVB_TXC,         4, 3 },  /* AVB_TXC */
+               { PIN_AVB_TD0,         0, 3 },  /* AVB_TD0 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL3", 0xe606030c) {
-               { PIN_NUMBER('B', 18),  28, 3 },        /* AVB_TD1 */
-               { PIN_NUMBER('A', 17),  24, 3 },        /* AVB_TD2 */
-               { PIN_NUMBER('B', 17),  20, 3 },        /* AVB_TD3 */
-               { PIN_NUMBER('A', 12),  16, 3 },        /* AVB_TXCREFCLK */
-               { PIN_NUMBER('A', 9),   12, 3 },        /* AVB_MDIO */
-               { RCAR_GP_PIN(2,  9),    8, 3 },        /* AVB_MDC */
-               { RCAR_GP_PIN(2, 10),    4, 3 },        /* AVB_MAGIC */
-               { RCAR_GP_PIN(2, 11),    0, 3 },        /* AVB_PHY_INT */
+               { PIN_AVB_TD1,        28, 3 },  /* AVB_TD1 */
+               { PIN_AVB_TD2,        24, 3 },  /* AVB_TD2 */
+               { PIN_AVB_TD3,        20, 3 },  /* AVB_TD3 */
+               { PIN_AVB_TXCREFCLK,  16, 3 },  /* AVB_TXCREFCLK */
+               { PIN_AVB_MDIO,       12, 3 },  /* AVB_MDIO */
+               { RCAR_GP_PIN(2,  9),  8, 3 },  /* AVB_MDC */
+               { RCAR_GP_PIN(2, 10),  4, 3 },  /* AVB_MAGIC */
+               { RCAR_GP_PIN(2, 11),  0, 3 },  /* AVB_PHY_INT */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL4", 0xe6060310) {
                { RCAR_GP_PIN(2, 12), 28, 3 },  /* AVB_LINK */
@@ -5681,7 +5715,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
        } },
        { PINMUX_DRIVE_REG("DRVCTRL9", 0xe6060324) {
                { RCAR_GP_PIN(1, 27), 28, 3 },  /* EX_WAIT0 */
-               { PIN_NUMBER('C', 1), 24, 3 },  /* PRESETOUT# */
+               { PIN_PRESETOUT_N,    24, 3 },  /* PRESETOUT# */
                { RCAR_GP_PIN(0,  0), 20, 3 },  /* D0 */
                { RCAR_GP_PIN(0,  1), 16, 3 },  /* D1 */
                { RCAR_GP_PIN(0,  2), 12, 3 },  /* D2 */
@@ -5700,29 +5734,29 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
                { RCAR_GP_PIN(0, 13),  0, 3 },  /* D13 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL11", 0xe606032c) {
-               { RCAR_GP_PIN(0, 14),   28, 3 },        /* D14 */
-               { RCAR_GP_PIN(0, 15),   24, 3 },        /* D15 */
-               { RCAR_GP_PIN(7,  0),   20, 3 },        /* AVS1 */
-               { RCAR_GP_PIN(7,  1),   16, 3 },        /* AVS2 */
-               { RCAR_GP_PIN(7,  2),   12, 3 },        /* GP7_02 */
-               { RCAR_GP_PIN(7,  3),    8, 3 },        /* GP7_03 */
-               { PIN_A_NUMBER('P', 7),  4, 2 },        /* DU_DOTCLKIN0 */
-               { PIN_A_NUMBER('P', 8),  0, 2 },        /* DU_DOTCLKIN1 */
+               { RCAR_GP_PIN(0, 14), 28, 3 },  /* D14 */
+               { RCAR_GP_PIN(0, 15), 24, 3 },  /* D15 */
+               { RCAR_GP_PIN(7,  0), 20, 3 },  /* AVS1 */
+               { RCAR_GP_PIN(7,  1), 16, 3 },  /* AVS2 */
+               { RCAR_GP_PIN(7,  2), 12, 3 },  /* GP7_02 */
+               { RCAR_GP_PIN(7,  3),  8, 3 },  /* GP7_03 */
+               { PIN_DU_DOTCLKIN0,    4, 2 },  /* DU_DOTCLKIN0 */
+               { PIN_DU_DOTCLKIN1,    0, 2 },  /* DU_DOTCLKIN1 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL12", 0xe6060330) {
-               { PIN_A_NUMBER('R', 8),  28, 2 },       /* DU_DOTCLKIN2 */
-               { PIN_A_NUMBER('D', 38), 20, 2 },       /* FSCLKST */
-               { PIN_A_NUMBER('R', 30),  4, 2 },       /* TMS */
+               { PIN_DU_DOTCLKIN2,   28, 2 },  /* DU_DOTCLKIN2 */
+               { PIN_FSCLKST,        20, 2 },  /* FSCLKST */
+               { PIN_TMS,             4, 2 },  /* TMS */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL13", 0xe6060334) {
-               { PIN_A_NUMBER('T', 28), 28, 2 },       /* TDO */
-               { PIN_A_NUMBER('T', 30), 24, 2 },       /* ASEBRK */
-               { RCAR_GP_PIN(3,  0),    20, 3 },       /* SD0_CLK */
-               { RCAR_GP_PIN(3,  1),    16, 3 },       /* SD0_CMD */
-               { RCAR_GP_PIN(3,  2),    12, 3 },       /* SD0_DAT0 */
-               { RCAR_GP_PIN(3,  3),     8, 3 },       /* SD0_DAT1 */
-               { RCAR_GP_PIN(3,  4),     4, 3 },       /* SD0_DAT2 */
-               { RCAR_GP_PIN(3,  5),     0, 3 },       /* SD0_DAT3 */
+               { PIN_TDO,            28, 2 },  /* TDO */
+               { PIN_ASEBRK,         24, 2 },  /* ASEBRK */
+               { RCAR_GP_PIN(3,  0), 20, 3 },  /* SD0_CLK */
+               { RCAR_GP_PIN(3,  1), 16, 3 },  /* SD0_CMD */
+               { RCAR_GP_PIN(3,  2), 12, 3 },  /* SD0_DAT0 */
+               { RCAR_GP_PIN(3,  3),  8, 3 },  /* SD0_DAT1 */
+               { RCAR_GP_PIN(3,  4),  4, 3 },  /* SD0_DAT2 */
+               { RCAR_GP_PIN(3,  5),  0, 3 },  /* SD0_DAT3 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL14", 0xe6060338) {
                { RCAR_GP_PIN(3,  6), 28, 3 },  /* SD1_CLK */
@@ -5791,7 +5825,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
                { RCAR_GP_PIN(5, 23), 16, 3 },  /* MLB_CLK */
                { RCAR_GP_PIN(5, 24), 12, 3 },  /* MLB_SIG */
                { RCAR_GP_PIN(5, 25),  8, 3 },  /* MLB_DAT */
-               { PIN_NUMBER('H', 37),  4, 3 }, /* MLB_REF */
+               { PIN_MLB_REF,         4, 3 },  /* MLB_REF */
                { RCAR_GP_PIN(6,  0),  0, 3 },  /* SSI_SCK01239 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL21", 0xe6060354) {
@@ -5864,35 +5898,35 @@ static int r8a7796_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *poc
 
 static const struct pinmux_bias_reg pinmux_bias_regs[] = {
        { PINMUX_BIAS_REG("PUEN0", 0xe6060400, "PUD0", 0xe6060440) {
-               [ 0] = PIN_NUMBER('W', 3),      /* QSPI0_SPCLK */
-               [ 1] = PIN_A_NUMBER('C', 5),    /* QSPI0_MOSI_IO0 */
-               [ 2] = PIN_A_NUMBER('B', 4),    /* QSPI0_MISO_IO1 */
-               [ 3] = PIN_NUMBER('Y', 6),      /* QSPI0_IO2 */
-               [ 4] = PIN_A_NUMBER('B', 6),    /* QSPI0_IO3 */
-               [ 5] = PIN_NUMBER('Y', 3),      /* QSPI0_SSL */
-               [ 6] = PIN_NUMBER('V', 3),      /* QSPI1_SPCLK */
-               [ 7] = PIN_A_NUMBER('C', 7),    /* QSPI1_MOSI_IO0 */
-               [ 8] = PIN_A_NUMBER('E', 5),    /* QSPI1_MISO_IO1 */
-               [ 9] = PIN_A_NUMBER('E', 4),    /* QSPI1_IO2 */
-               [10] = PIN_A_NUMBER('C', 3),    /* QSPI1_IO3 */
-               [11] = PIN_NUMBER('V', 5),      /* QSPI1_SSL */
-               [12] = PIN_NUMBER('Y', 7),      /* RPC_INT# */
-               [13] = PIN_NUMBER('V', 6),      /* RPC_WP# */
-               [14] = PIN_NUMBER('V', 7),      /* RPC_RESET# */
-               [15] = PIN_NUMBER('A', 16),     /* AVB_RX_CTL */
-               [16] = PIN_NUMBER('B', 19),     /* AVB_RXC */
-               [17] = PIN_NUMBER('A', 13),     /* AVB_RD0 */
-               [18] = PIN_NUMBER('B', 13),     /* AVB_RD1 */
-               [19] = PIN_NUMBER('A', 14),     /* AVB_RD2 */
-               [20] = PIN_NUMBER('B', 14),     /* AVB_RD3 */
-               [21] = PIN_NUMBER('A', 8),      /* AVB_TX_CTL */
-               [22] = PIN_NUMBER('A', 19),     /* AVB_TXC */
-               [23] = PIN_NUMBER('A', 18),     /* AVB_TD0 */
-               [24] = PIN_NUMBER('B', 18),     /* AVB_TD1 */
-               [25] = PIN_NUMBER('A', 17),     /* AVB_TD2 */
-               [26] = PIN_NUMBER('B', 17),     /* AVB_TD3 */
-               [27] = PIN_NUMBER('A', 12),     /* AVB_TXCREFCLK */
-               [28] = PIN_NUMBER('A', 9),      /* AVB_MDIO */
+               [ 0] = PIN_QSPI0_SPCLK,         /* QSPI0_SPCLK */
+               [ 1] = PIN_QSPI0_MOSI_IO0,      /* QSPI0_MOSI_IO0 */
+               [ 2] = PIN_QSPI0_MISO_IO1,      /* QSPI0_MISO_IO1 */
+               [ 3] = PIN_QSPI0_IO2,           /* QSPI0_IO2 */
+               [ 4] = PIN_QSPI0_IO3,           /* QSPI0_IO3 */
+               [ 5] = PIN_QSPI0_SSL,           /* QSPI0_SSL */
+               [ 6] = PIN_QSPI1_SPCLK,         /* QSPI1_SPCLK */
+               [ 7] = PIN_QSPI1_MOSI_IO0,      /* QSPI1_MOSI_IO0 */
+               [ 8] = PIN_QSPI1_MISO_IO1,      /* QSPI1_MISO_IO1 */
+               [ 9] = PIN_QSPI1_IO2,           /* QSPI1_IO2 */
+               [10] = PIN_QSPI1_IO3,           /* QSPI1_IO3 */
+               [11] = PIN_QSPI1_SSL,           /* QSPI1_SSL */
+               [12] = PIN_RPC_INT_N,           /* RPC_INT# */
+               [13] = PIN_RPC_WP_N,            /* RPC_WP# */
+               [14] = PIN_RPC_RESET_N,         /* RPC_RESET# */
+               [15] = PIN_AVB_RX_CTL,          /* AVB_RX_CTL */
+               [16] = PIN_AVB_RXC,             /* AVB_RXC */
+               [17] = PIN_AVB_RD0,             /* AVB_RD0 */
+               [18] = PIN_AVB_RD1,             /* AVB_RD1 */
+               [19] = PIN_AVB_RD2,             /* AVB_RD2 */
+               [20] = PIN_AVB_RD3,             /* AVB_RD3 */
+               [21] = PIN_AVB_TX_CTL,          /* AVB_TX_CTL */
+               [22] = PIN_AVB_TXC,             /* AVB_TXC */
+               [23] = PIN_AVB_TD0,             /* AVB_TD0 */
+               [24] = PIN_AVB_TD1,             /* AVB_TD1 */
+               [25] = PIN_AVB_TD2,             /* AVB_TD2 */
+               [26] = PIN_AVB_TD3,             /* AVB_TD3 */
+               [27] = PIN_AVB_TXCREFCLK,       /* AVB_TXCREFCLK */
+               [28] = PIN_AVB_MDIO,            /* AVB_MDIO */
                [29] = RCAR_GP_PIN(2,  9),      /* AVB_MDC */
                [30] = RCAR_GP_PIN(2, 10),      /* AVB_MAGIC */
                [31] = RCAR_GP_PIN(2, 11),      /* AVB_PHY_INT */
@@ -5941,7 +5975,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [ 6] = RCAR_GP_PIN(1, 25),      /* WE0_N */
                [ 7] = RCAR_GP_PIN(1, 26),      /* WE1_N */
                [ 8] = RCAR_GP_PIN(1, 27),      /* EX_WAIT0_A */
-               [ 9] = PIN_NUMBER('C', 1),      /* PRESETOUT# */
+               [ 9] = PIN_PRESETOUT_N,         /* PRESETOUT# */
                [10] = RCAR_GP_PIN(0,  0),      /* D0 */
                [11] = RCAR_GP_PIN(0,  1),      /* D1 */
                [12] = RCAR_GP_PIN(0,  2),      /* D2 */
@@ -5962,20 +5996,20 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [27] = RCAR_GP_PIN(7,  1),      /* AVS2 */
                [28] = RCAR_GP_PIN(7,  2),      /* GP7_02 */
                [29] = RCAR_GP_PIN(7,  3),      /* GP7_03 */
-               [30] = PIN_A_NUMBER('P', 7),    /* DU_DOTCLKIN0 */
-               [31] = PIN_A_NUMBER('P', 8),    /* DU_DOTCLKIN1 */
+               [30] = PIN_DU_DOTCLKIN0,        /* DU_DOTCLKIN0 */
+               [31] = PIN_DU_DOTCLKIN1,        /* DU_DOTCLKIN1 */
        } },
        { PINMUX_BIAS_REG("PUEN3", 0xe606040c, "PUD3", 0xe606044c) {
-               [ 0] = PIN_A_NUMBER('R', 8),    /* DU_DOTCLKIN2 */
-               [ 1] = PIN_NONE,
-               [ 2] = PIN_A_NUMBER('D', 38),   /* FSCLKST */
-               [ 3] = PIN_A_NUMBER('D', 39),   /* EXTALR*/
-               [ 4] = PIN_A_NUMBER('R', 26),   /* TRST# */
-               [ 5] = PIN_A_NUMBER('T', 27),   /* TCK */
-               [ 6] = PIN_A_NUMBER('R', 30),   /* TMS */
-               [ 7] = PIN_A_NUMBER('R', 29),   /* TDI */
-               [ 8] = PIN_NONE,
-               [ 9] = PIN_A_NUMBER('T', 30),   /* ASEBRK */
+               [ 0] = PIN_DU_DOTCLKIN2,        /* DU_DOTCLKIN2 */
+               [ 1] = SH_PFC_PIN_NONE,
+               [ 2] = PIN_FSCLKST,             /* FSCLKST */
+               [ 3] = PIN_EXTALR,              /* EXTALR*/
+               [ 4] = PIN_TRST_N,              /* TRST# */
+               [ 5] = PIN_TCK,                 /* TCK */
+               [ 6] = PIN_TMS,                 /* TMS */
+               [ 7] = PIN_TDI,                 /* TDI */
+               [ 8] = SH_PFC_PIN_NONE,
+               [ 9] = PIN_ASEBRK,              /* ASEBRK */
                [10] = RCAR_GP_PIN(3,  0),      /* SD0_CLK */
                [11] = RCAR_GP_PIN(3,  1),      /* SD0_CMD */
                [12] = RCAR_GP_PIN(3,  2),      /* SD0_DAT0 */
@@ -6040,7 +6074,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [ 3] = RCAR_GP_PIN(5, 23),      /* MLB_CLK */
                [ 4] = RCAR_GP_PIN(5, 24),      /* MLB_SIG */
                [ 5] = RCAR_GP_PIN(5, 25),      /* MLB_DAT */
-               [ 6] = PIN_NUMBER('H', 37),     /* MLB_REF */
+               [ 6] = PIN_MLB_REF,             /* MLB_REF */
                [ 7] = RCAR_GP_PIN(6,  0),      /* SSI_SCK01239 */
                [ 8] = RCAR_GP_PIN(6,  1),      /* SSI_WS01239 */
                [ 9] = RCAR_GP_PIN(6,  2),      /* SSI_SDATA0 */
@@ -6075,31 +6109,31 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [ 4] = RCAR_GP_PIN(6, 29),      /* USB30_OVC */
                [ 5] = RCAR_GP_PIN(6, 30),      /* GP6_30 */
                [ 6] = RCAR_GP_PIN(6, 31),      /* GP6_31 */
-               [ 7] = PIN_NONE,
-               [ 8] = PIN_NONE,
-               [ 9] = PIN_NONE,
-               [10] = PIN_NONE,
-               [11] = PIN_NONE,
-               [12] = PIN_NONE,
-               [13] = PIN_NONE,
-               [14] = PIN_NONE,
-               [15] = PIN_NONE,
-               [16] = PIN_NONE,
-               [17] = PIN_NONE,
-               [18] = PIN_NONE,
-               [19] = PIN_NONE,
-               [20] = PIN_NONE,
-               [21] = PIN_NONE,
-               [22] = PIN_NONE,
-               [23] = PIN_NONE,
-               [24] = PIN_NONE,
-               [25] = PIN_NONE,
-               [26] = PIN_NONE,
-               [27] = PIN_NONE,
-               [28] = PIN_NONE,
-               [29] = PIN_NONE,
-               [30] = PIN_NONE,
-               [31] = PIN_NONE,
+               [ 7] = SH_PFC_PIN_NONE,
+               [ 8] = SH_PFC_PIN_NONE,
+               [ 9] = SH_PFC_PIN_NONE,
+               [10] = SH_PFC_PIN_NONE,
+               [11] = SH_PFC_PIN_NONE,
+               [12] = SH_PFC_PIN_NONE,
+               [13] = SH_PFC_PIN_NONE,
+               [14] = SH_PFC_PIN_NONE,
+               [15] = SH_PFC_PIN_NONE,
+               [16] = SH_PFC_PIN_NONE,
+               [17] = SH_PFC_PIN_NONE,
+               [18] = SH_PFC_PIN_NONE,
+               [19] = SH_PFC_PIN_NONE,
+               [20] = SH_PFC_PIN_NONE,
+               [21] = SH_PFC_PIN_NONE,
+               [22] = SH_PFC_PIN_NONE,
+               [23] = SH_PFC_PIN_NONE,
+               [24] = SH_PFC_PIN_NONE,
+               [25] = SH_PFC_PIN_NONE,
+               [26] = SH_PFC_PIN_NONE,
+               [27] = SH_PFC_PIN_NONE,
+               [28] = SH_PFC_PIN_NONE,
+               [29] = SH_PFC_PIN_NONE,
+               [30] = SH_PFC_PIN_NONE,
+               [31] = SH_PFC_PIN_NONE,
        } },
        { /* sentinel */ },
 };
index 0900243..697c77a 100644 (file)
 #include "core.h"
 #include "sh_pfc.h"
 
-#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | \
-                  SH_PFC_PIN_CFG_PULL_UP | \
-                  SH_PFC_PIN_CFG_PULL_DOWN)
+#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_PULL_UP_DOWN)
 
-#define CPU_ALL_PORT(fn, sfx)                                          \
+#define CPU_ALL_GP(fn, sfx)                                            \
        PORT_GP_CFG_16(0, fn, sfx, CFG_FLAGS),  \
        PORT_GP_CFG_29(1, fn, sfx, CFG_FLAGS),  \
        PORT_GP_CFG_15(2, fn, sfx, CFG_FLAGS),  \
        PORT_GP_CFG_26(5, fn, sfx, CFG_FLAGS),  \
        PORT_GP_CFG_32(6, fn, sfx, CFG_FLAGS),  \
        PORT_GP_CFG_4(7, fn, sfx, CFG_FLAGS)
+
+#define CPU_ALL_NOGP(fn)                                               \
+       PIN_NOGP_CFG(ASEBRK, "ASEBRK", fn, CFG_FLAGS),                  \
+       PIN_NOGP_CFG(AVB_MDIO, "AVB_MDIO", fn, CFG_FLAGS),              \
+       PIN_NOGP_CFG(AVB_RD0, "AVB_RD0", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_RD1, "AVB_RD1", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_RD2, "AVB_RD2", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_RD3, "AVB_RD3", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_RXC, "AVB_RXC", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_RX_CTL, "AVB_RX_CTL", fn, CFG_FLAGS),          \
+       PIN_NOGP_CFG(AVB_TD0, "AVB_TD0", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TD1, "AVB_TD1", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TD2, "AVB_TD2", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TD3, "AVB_TD3", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TXC, "AVB_TXC", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TXCREFCLK, "AVB_TXCREFCLK", fn, CFG_FLAGS),    \
+       PIN_NOGP_CFG(AVB_TX_CTL, "AVB_TX_CTL", fn, CFG_FLAGS),          \
+       PIN_NOGP_CFG(DU_DOTCLKIN0, "DU_DOTCLKIN0", fn, CFG_FLAGS),      \
+       PIN_NOGP_CFG(DU_DOTCLKIN1, "DU_DOTCLKIN1", fn, CFG_FLAGS),      \
+       PIN_NOGP_CFG(DU_DOTCLKIN3, "DU_DOTCLKIN3", fn, CFG_FLAGS),      \
+       PIN_NOGP_CFG(EXTALR, "EXTALR", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),\
+       PIN_NOGP_CFG(FSCLKST, "FSCLKST", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(MLB_REF, "MLB_REF", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT#", fn, CFG_FLAGS),         \
+       PIN_NOGP_CFG(QSPI0_IO2, "QSPI0_IO2", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(QSPI0_IO3, "QSPI0_IO3", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(QSPI0_MISO_IO1, "QSPI0_MISO_IO1", fn, CFG_FLAGS),  \
+       PIN_NOGP_CFG(QSPI0_MOSI_IO0, "QSPI0_MOSI_IO0", fn, CFG_FLAGS),  \
+       PIN_NOGP_CFG(QSPI0_SPCLK, "QSPI0_SPCLK", fn, CFG_FLAGS),        \
+       PIN_NOGP_CFG(QSPI0_SSL, "QSPI0_SSL", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(QSPI1_IO2, "QSPI1_IO2", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(QSPI1_IO3, "QSPI1_IO3", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(QSPI1_MISO_IO1, "QSPI1_MISO_IO1", fn, CFG_FLAGS),  \
+       PIN_NOGP_CFG(QSPI1_MOSI_IO0, "QSPI1_MOSI_IO0", fn, CFG_FLAGS),  \
+       PIN_NOGP_CFG(QSPI1_SPCLK, "QSPI1_SPCLK", fn, CFG_FLAGS),        \
+       PIN_NOGP_CFG(QSPI1_SSL, "QSPI1_SSL", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(RPC_INT_N, "RPC_INT#", fn, CFG_FLAGS),             \
+       PIN_NOGP_CFG(RPC_RESET_N, "RPC_RESET#", fn, CFG_FLAGS),         \
+       PIN_NOGP_CFG(RPC_WP_N, "RPC_WP#", fn, CFG_FLAGS),               \
+       PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),      \
+       PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),      \
+       PIN_NOGP_CFG(TDO, "TDO", fn, SH_PFC_PIN_CFG_DRIVE_STRENGTH),    \
+       PIN_NOGP_CFG(TMS, "TMS", fn, CFG_FLAGS),                        \
+       PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN)
+
 /*
  * F_() : just information
  * FM() : macro for FN_xxx / xxx_MARK
@@ -1517,67 +1560,16 @@ static const u16 pinmux_data[] = {
 };
 
 /*
- * R8A77965 has 8 banks with 32 GPIOs in each => 256 GPIOs.
- * Physical layout rows: A - AW, cols: 1 - 39.
+ * Pins not associated with a GPIO port.
  */
-#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r))
-#define PIN_NUMBER(r, c) (((r) - 'A') * 39 + (c) + 300)
-#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c)
-#define PIN_NONE U16_MAX
+enum {
+       GP_ASSIGN_LAST(),
+       NOGP_ALL(),
+};
 
 static const struct sh_pfc_pin pinmux_pins[] = {
        PINMUX_GPIO_GP_ALL(),
-
-       /*
-        * Pins not associated with a GPIO port.
-        *
-        * The pin positions are different between different r8a77965
-        * packages, all that is needed for the pfc driver is a unique
-        * number for each pin. To this end use the pin layout from
-        * R-Car M3SiP to calculate a unique number for each pin.
-        */
-       SH_PFC_PIN_NAMED_CFG('A',  8, AVB_TX_CTL, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A',  9, AVB_MDIO, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 12, AVB_TXCREFCLK, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 13, AVB_RD0, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 14, AVB_RD2, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 16, AVB_RX_CTL, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 17, AVB_TD2, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 18, AVB_TD0, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('A', 19, AVB_TXC, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('B', 13, AVB_RD1, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('B', 14, AVB_RD3, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('B', 17, AVB_TD3, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('C',  1, PRESETOUT#, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('V',  3, QSPI1_SPCLK, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('V',  5, QSPI1_SSL, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('V',  6, RPC_WP#, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('V',  7, RPC_RESET#, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('W',  3, QSPI0_SPCLK, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('Y',  3, QSPI0_SSL, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('Y',  6, QSPI0_IO2, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('Y',  7, RPC_INT#, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'),  4, QSPI0_MISO_IO1, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'),  6, QSPI0_IO3, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  3, QSPI1_IO3, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  5, QSPI0_MOSI_IO0, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  7, QSPI1_MOSI_IO0, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 38, FSCLKST, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 39, EXTALR, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'),  4, QSPI1_IO2, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'),  5, QSPI1_MISO_IO1, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'),  7, DU_DOTCLKIN0, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'),  8, DU_DOTCLKIN1, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'),  8, DU_DOTCLKIN3, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 26, TRST#, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 29, TDI, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 30, TMS, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 27, TCK, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 28, TDO, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, CFG_FLAGS),
+       PINMUX_NOGP_ALL(),
 };
 
 /* - AUDIO CLOCK ------------------------------------------------------------ */
@@ -1726,7 +1718,7 @@ static const unsigned int avb_phy_int_mux[] = {
 };
 static const unsigned int avb_mdio_pins[] = {
        /* AVB_MDC, AVB_MDIO */
-       RCAR_GP_PIN(2, 9), PIN_NUMBER('A', 9),
+       RCAR_GP_PIN(2, 9), PIN_AVB_MDIO,
 };
 static const unsigned int avb_mdio_mux[] = {
        AVB_MDC_MARK, AVB_MDIO_MARK,
@@ -1739,11 +1731,11 @@ static const unsigned int avb_mii_pins[] = {
         * AVB_RD1, AVB_RD2, AVB_RD3,
         * AVB_TXCREFCLK
         */
-       PIN_NUMBER('A', 8), PIN_NUMBER('A', 19), PIN_NUMBER('A', 18),
-       PIN_NUMBER('B', 18), PIN_NUMBER('A', 17), PIN_NUMBER('B', 17),
-       PIN_NUMBER('A', 16), PIN_NUMBER('B', 19), PIN_NUMBER('A', 13),
-       PIN_NUMBER('B', 13), PIN_NUMBER('A', 14), PIN_NUMBER('B', 14),
-       PIN_NUMBER('A', 12),
+       PIN_AVB_TX_CTL, PIN_AVB_TXC, PIN_AVB_TD0,
+       PIN_AVB_TD1, PIN_AVB_TD2, PIN_AVB_TD3,
+       PIN_AVB_RX_CTL, PIN_AVB_RXC, PIN_AVB_RD0,
+       PIN_AVB_RD1, PIN_AVB_RD2, PIN_AVB_RD3,
+       PIN_AVB_TXCREFCLK,
 
 };
 static const unsigned int avb_mii_mux[] = {
@@ -4116,6 +4108,36 @@ static const unsigned int tmu_tclk2_b_mux[] = {
        TCLK2_B_MARK,
 };
 
+/* - TPU ------------------------------------------------------------------- */
+static const unsigned int tpu_to0_pins[] = {
+       /* TPU0TO0 */
+       RCAR_GP_PIN(6, 28),
+};
+static const unsigned int tpu_to0_mux[] = {
+       TPU0TO0_MARK,
+};
+static const unsigned int tpu_to1_pins[] = {
+       /* TPU0TO1 */
+       RCAR_GP_PIN(6, 29),
+};
+static const unsigned int tpu_to1_mux[] = {
+       TPU0TO1_MARK,
+};
+static const unsigned int tpu_to2_pins[] = {
+       /* TPU0TO2 */
+       RCAR_GP_PIN(6, 30),
+};
+static const unsigned int tpu_to2_mux[] = {
+       TPU0TO2_MARK,
+};
+static const unsigned int tpu_to3_pins[] = {
+       /* TPU0TO3 */
+       RCAR_GP_PIN(6, 31),
+};
+static const unsigned int tpu_to3_mux[] = {
+       TPU0TO3_MARK,
+};
+
 /* - USB0 ------------------------------------------------------------------- */
 static const unsigned int usb0_pins[] = {
        /* PWEN, OVC */
@@ -4672,6 +4694,10 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(tmu_tclk1_b),
        SH_PFC_PIN_GROUP(tmu_tclk2_a),
        SH_PFC_PIN_GROUP(tmu_tclk2_b),
+       SH_PFC_PIN_GROUP(tpu_to0),
+       SH_PFC_PIN_GROUP(tpu_to1),
+       SH_PFC_PIN_GROUP(tpu_to2),
+       SH_PFC_PIN_GROUP(tpu_to3),
        SH_PFC_PIN_GROUP(usb0),
        SH_PFC_PIN_GROUP(usb1),
        SH_PFC_PIN_GROUP(usb30),
@@ -5164,6 +5190,13 @@ static const char * const tmu_groups[] = {
        "tmu_tclk2_b",
 };
 
+static const char * const tpu_groups[] = {
+       "tpu_to0",
+       "tpu_to1",
+       "tpu_to2",
+       "tpu_to3",
+};
+
 static const char * const usb0_groups[] = {
        "usb0",
 };
@@ -5258,6 +5291,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
        SH_PFC_FUNCTION(sdhi3),
        SH_PFC_FUNCTION(ssi),
        SH_PFC_FUNCTION(tmu),
+       SH_PFC_FUNCTION(tpu),
        SH_PFC_FUNCTION(usb0),
        SH_PFC_FUNCTION(usb1),
        SH_PFC_FUNCTION(usb30),
@@ -5830,44 +5864,44 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
 
 static const struct pinmux_drive_reg pinmux_drive_regs[] = {
        { PINMUX_DRIVE_REG("DRVCTRL0", 0xe6060300) {
-               { PIN_NUMBER('W', 3),   28, 2 },        /* QSPI0_SPCLK */
-               { PIN_A_NUMBER('C', 5), 24, 2 },        /* QSPI0_MOSI_IO0 */
-               { PIN_A_NUMBER('B', 4), 20, 2 },        /* QSPI0_MISO_IO1 */
-               { PIN_NUMBER('Y', 6),   16, 2 },        /* QSPI0_IO2 */
-               { PIN_A_NUMBER('B', 6), 12, 2 },        /* QSPI0_IO3 */
-               { PIN_NUMBER('Y', 3),    8, 2 },        /* QSPI0_SSL */
-               { PIN_NUMBER('V', 3),    4, 2 },        /* QSPI1_SPCLK */
-               { PIN_A_NUMBER('C', 7),  0, 2 },        /* QSPI1_MOSI_IO0 */
+               { PIN_QSPI0_SPCLK,    28, 2 },  /* QSPI0_SPCLK */
+               { PIN_QSPI0_MOSI_IO0, 24, 2 },  /* QSPI0_MOSI_IO0 */
+               { PIN_QSPI0_MISO_IO1, 20, 2 },  /* QSPI0_MISO_IO1 */
+               { PIN_QSPI0_IO2,      16, 2 },  /* QSPI0_IO2 */
+               { PIN_QSPI0_IO3,      12, 2 },  /* QSPI0_IO3 */
+               { PIN_QSPI0_SSL,       8, 2 },  /* QSPI0_SSL */
+               { PIN_QSPI1_SPCLK,     4, 2 },  /* QSPI1_SPCLK */
+               { PIN_QSPI1_MOSI_IO0,  0, 2 },  /* QSPI1_MOSI_IO0 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL1", 0xe6060304) {
-               { PIN_A_NUMBER('E', 5), 28, 2 },        /* QSPI1_MISO_IO1 */
-               { PIN_A_NUMBER('E', 4), 24, 2 },        /* QSPI1_IO2 */
-               { PIN_A_NUMBER('C', 3), 20, 2 },        /* QSPI1_IO3 */
-               { PIN_NUMBER('V', 5),   16, 2 },        /* QSPI1_SSL */
-               { PIN_NUMBER('Y', 7),   12, 2 },        /* RPC_INT# */
-               { PIN_NUMBER('V', 6),    8, 2 },        /* RPC_WP# */
-               { PIN_NUMBER('V', 7),    4, 2 },        /* RPC_RESET# */
-               { PIN_NUMBER('A', 16),   0, 3 },        /* AVB_RX_CTL */
+               { PIN_QSPI1_MISO_IO1, 28, 2 },  /* QSPI1_MISO_IO1 */
+               { PIN_QSPI1_IO2,      24, 2 },  /* QSPI1_IO2 */
+               { PIN_QSPI1_IO3,      20, 2 },  /* QSPI1_IO3 */
+               { PIN_QSPI1_SSL,      16, 2 },  /* QSPI1_SSL */
+               { PIN_RPC_INT_N,      12, 2 },  /* RPC_INT# */
+               { PIN_RPC_WP_N,        8, 2 },  /* RPC_WP# */
+               { PIN_RPC_RESET_N,     4, 2 },  /* RPC_RESET# */
+               { PIN_AVB_RX_CTL,      0, 3 },  /* AVB_RX_CTL */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL2", 0xe6060308) {
-               { PIN_NUMBER('B', 19),  28, 3 },        /* AVB_RXC */
-               { PIN_NUMBER('A', 13),  24, 3 },        /* AVB_RD0 */
-               { PIN_NUMBER('B', 13),  20, 3 },        /* AVB_RD1 */
-               { PIN_NUMBER('A', 14),  16, 3 },        /* AVB_RD2 */
-               { PIN_NUMBER('B', 14),  12, 3 },        /* AVB_RD3 */
-               { PIN_NUMBER('A', 8),    8, 3 },        /* AVB_TX_CTL */
-               { PIN_NUMBER('A', 19),   4, 3 },        /* AVB_TXC */
-               { PIN_NUMBER('A', 18),   0, 3 },        /* AVB_TD0 */
+               { PIN_AVB_RXC,        28, 3 },  /* AVB_RXC */
+               { PIN_AVB_RD0,        24, 3 },  /* AVB_RD0 */
+               { PIN_AVB_RD1,        20, 3 },  /* AVB_RD1 */
+               { PIN_AVB_RD2,        16, 3 },  /* AVB_RD2 */
+               { PIN_AVB_RD3,        12, 3 },  /* AVB_RD3 */
+               { PIN_AVB_TX_CTL,      8, 3 },  /* AVB_TX_CTL */
+               { PIN_AVB_TXC,         4, 3 },  /* AVB_TXC */
+               { PIN_AVB_TD0,         0, 3 },  /* AVB_TD0 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL3", 0xe606030c) {
-               { PIN_NUMBER('B', 18),  28, 3 },        /* AVB_TD1 */
-               { PIN_NUMBER('A', 17),  24, 3 },        /* AVB_TD2 */
-               { PIN_NUMBER('B', 17),  20, 3 },        /* AVB_TD3 */
-               { PIN_NUMBER('A', 12),  16, 3 },        /* AVB_TXCREFCLK */
-               { PIN_NUMBER('A', 9),   12, 3 },        /* AVB_MDIO */
-               { RCAR_GP_PIN(2,  9),    8, 3 },        /* AVB_MDC */
-               { RCAR_GP_PIN(2, 10),    4, 3 },        /* AVB_MAGIC */
-               { RCAR_GP_PIN(2, 11),    0, 3 },        /* AVB_PHY_INT */
+               { PIN_AVB_TD1,        28, 3 },  /* AVB_TD1 */
+               { PIN_AVB_TD2,        24, 3 },  /* AVB_TD2 */
+               { PIN_AVB_TD3,        20, 3 },  /* AVB_TD3 */
+               { PIN_AVB_TXCREFCLK,  16, 3 },  /* AVB_TXCREFCLK */
+               { PIN_AVB_MDIO,       12, 3 },  /* AVB_MDIO */
+               { RCAR_GP_PIN(2,  9),  8, 3 },  /* AVB_MDC */
+               { RCAR_GP_PIN(2, 10),  4, 3 },  /* AVB_MAGIC */
+               { RCAR_GP_PIN(2, 11),  0, 3 },  /* AVB_PHY_INT */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL4", 0xe6060310) {
                { RCAR_GP_PIN(2, 12), 28, 3 },  /* AVB_LINK */
@@ -5921,7 +5955,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
        } },
        { PINMUX_DRIVE_REG("DRVCTRL9", 0xe6060324) {
                { RCAR_GP_PIN(1, 27), 28, 3 },  /* EX_WAIT0 */
-               { PIN_NUMBER('C', 1), 24, 3 },  /* PRESETOUT# */
+               { PIN_PRESETOUT_N,    24, 3 },  /* PRESETOUT# */
                { RCAR_GP_PIN(0,  0), 20, 3 },  /* D0 */
                { RCAR_GP_PIN(0,  1), 16, 3 },  /* D1 */
                { RCAR_GP_PIN(0,  2), 12, 3 },  /* D2 */
@@ -5940,29 +5974,29 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
                { RCAR_GP_PIN(0, 13),  0, 3 },  /* D13 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL11", 0xe606032c) {
-               { RCAR_GP_PIN(0, 14),   28, 3 },        /* D14 */
-               { RCAR_GP_PIN(0, 15),   24, 3 },        /* D15 */
-               { RCAR_GP_PIN(7,  0),   20, 3 },        /* AVS1 */
-               { RCAR_GP_PIN(7,  1),   16, 3 },        /* AVS2 */
-               { RCAR_GP_PIN(7,  2),   12, 3 },        /* GP7_02 */
-               { RCAR_GP_PIN(7,  3),    8, 3 },        /* GP7_03 */
-               { PIN_A_NUMBER('P', 7),  4, 2 },        /* DU_DOTCLKIN0 */
-               { PIN_A_NUMBER('P', 8),  0, 2 },        /* DU_DOTCLKIN1 */
+               { RCAR_GP_PIN(0, 14), 28, 3 },  /* D14 */
+               { RCAR_GP_PIN(0, 15), 24, 3 },  /* D15 */
+               { RCAR_GP_PIN(7,  0), 20, 3 },  /* AVS1 */
+               { RCAR_GP_PIN(7,  1), 16, 3 },  /* AVS2 */
+               { RCAR_GP_PIN(7,  2), 12, 3 },  /* GP7_02 */
+               { RCAR_GP_PIN(7,  3),  8, 3 },  /* GP7_03 */
+               { PIN_DU_DOTCLKIN0,    4, 2 },  /* DU_DOTCLKIN0 */
+               { PIN_DU_DOTCLKIN1,    0, 2 },  /* DU_DOTCLKIN1 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL12", 0xe6060330) {
-               { PIN_A_NUMBER('R', 8),  28, 2 },       /* DU_DOTCLKIN3 */
-               { PIN_A_NUMBER('D', 38), 20, 2 },       /* FSCLKST */
-               { PIN_A_NUMBER('R', 30),  4, 2 },       /* TMS */
+               { PIN_DU_DOTCLKIN3,   28, 2 },  /* DU_DOTCLKIN3 */
+               { PIN_FSCLKST,        20, 2 },  /* FSCLKST */
+               { PIN_TMS,             4, 2 },  /* TMS */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL13", 0xe6060334) {
-               { PIN_A_NUMBER('T', 28), 28, 2 },       /* TDO */
-               { PIN_A_NUMBER('T', 30), 24, 2 },       /* ASEBRK */
-               { RCAR_GP_PIN(3,  0),    20, 3 },       /* SD0_CLK */
-               { RCAR_GP_PIN(3,  1),    16, 3 },       /* SD0_CMD */
-               { RCAR_GP_PIN(3,  2),    12, 3 },       /* SD0_DAT0 */
-               { RCAR_GP_PIN(3,  3),     8, 3 },       /* SD0_DAT1 */
-               { RCAR_GP_PIN(3,  4),     4, 3 },       /* SD0_DAT2 */
-               { RCAR_GP_PIN(3,  5),     0, 3 },       /* SD0_DAT3 */
+               { PIN_TDO,            28, 2 },  /* TDO */
+               { PIN_ASEBRK,         24, 2 },  /* ASEBRK */
+               { RCAR_GP_PIN(3,  0), 20, 3 },  /* SD0_CLK */
+               { RCAR_GP_PIN(3,  1), 16, 3 },  /* SD0_CMD */
+               { RCAR_GP_PIN(3,  2), 12, 3 },  /* SD0_DAT0 */
+               { RCAR_GP_PIN(3,  3),  8, 3 },  /* SD0_DAT1 */
+               { RCAR_GP_PIN(3,  4),  4, 3 },  /* SD0_DAT2 */
+               { RCAR_GP_PIN(3,  5),  0, 3 },  /* SD0_DAT3 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL14", 0xe6060338) {
                { RCAR_GP_PIN(3,  6), 28, 3 },  /* SD1_CLK */
@@ -6031,7 +6065,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
                { RCAR_GP_PIN(5, 23), 16, 3 },  /* MLB_CLK */
                { RCAR_GP_PIN(5, 24), 12, 3 },  /* MLB_SIG */
                { RCAR_GP_PIN(5, 25),  8, 3 },  /* MLB_DAT */
-               { PIN_NUMBER('H', 37),  4, 3 }, /* MLB_REF */
+               { PIN_MLB_REF,         4, 3 },  /* MLB_REF */
                { RCAR_GP_PIN(6,  0),  0, 3 },  /* SSI_SCK01239 */
        } },
        { PINMUX_DRIVE_REG("DRVCTRL21", 0xe6060354) {
@@ -6104,35 +6138,35 @@ static int r8a77965_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *po
 
 static const struct pinmux_bias_reg pinmux_bias_regs[] = {
        { PINMUX_BIAS_REG("PUEN0", 0xe6060400, "PUD0", 0xe6060440) {
-               [ 0] = PIN_NUMBER('W', 3),      /* QSPI0_SPCLK */
-               [ 1] = PIN_A_NUMBER('C', 5),    /* QSPI0_MOSI_IO0 */
-               [ 2] = PIN_A_NUMBER('B', 4),    /* QSPI0_MISO_IO1 */
-               [ 3] = PIN_NUMBER('Y', 6),      /* QSPI0_IO2 */
-               [ 4] = PIN_A_NUMBER('B', 6),    /* QSPI0_IO3 */
-               [ 5] = PIN_NUMBER('Y', 3),      /* QSPI0_SSL */
-               [ 6] = PIN_NUMBER('V', 3),      /* QSPI1_SPCLK */
-               [ 7] = PIN_A_NUMBER('C', 7),    /* QSPI1_MOSI_IO0 */
-               [ 8] = PIN_A_NUMBER('E', 5),    /* QSPI1_MISO_IO1 */
-               [ 9] = PIN_A_NUMBER('E', 4),    /* QSPI1_IO2 */
-               [10] = PIN_A_NUMBER('C', 3),    /* QSPI1_IO3 */
-               [11] = PIN_NUMBER('V', 5),      /* QSPI1_SSL */
-               [12] = PIN_NUMBER('Y', 7),      /* RPC_INT# */
-               [13] = PIN_NUMBER('V', 6),      /* RPC_WP# */
-               [14] = PIN_NUMBER('V', 7),      /* RPC_RESET# */
-               [15] = PIN_NUMBER('A', 16),     /* AVB_RX_CTL */
-               [16] = PIN_NUMBER('B', 19),     /* AVB_RXC */
-               [17] = PIN_NUMBER('A', 13),     /* AVB_RD0 */
-               [18] = PIN_NUMBER('B', 13),     /* AVB_RD1 */
-               [19] = PIN_NUMBER('A', 14),     /* AVB_RD2 */
-               [20] = PIN_NUMBER('B', 14),     /* AVB_RD3 */
-               [21] = PIN_NUMBER('A', 8),      /* AVB_TX_CTL */
-               [22] = PIN_NUMBER('A', 19),     /* AVB_TXC */
-               [23] = PIN_NUMBER('A', 18),     /* AVB_TD0 */
-               [24] = PIN_NUMBER('B', 18),     /* AVB_TD1 */
-               [25] = PIN_NUMBER('A', 17),     /* AVB_TD2 */
-               [26] = PIN_NUMBER('B', 17),     /* AVB_TD3 */
-               [27] = PIN_NUMBER('A', 12),     /* AVB_TXCREFCLK */
-               [28] = PIN_NUMBER('A', 9),      /* AVB_MDIO */
+               [ 0] = PIN_QSPI0_SPCLK,         /* QSPI0_SPCLK */
+               [ 1] = PIN_QSPI0_MOSI_IO0,      /* QSPI0_MOSI_IO0 */
+               [ 2] = PIN_QSPI0_MISO_IO1,      /* QSPI0_MISO_IO1 */
+               [ 3] = PIN_QSPI0_IO2,           /* QSPI0_IO2 */
+               [ 4] = PIN_QSPI0_IO3,           /* QSPI0_IO3 */
+               [ 5] = PIN_QSPI0_SSL,           /* QSPI0_SSL */
+               [ 6] = PIN_QSPI1_SPCLK,         /* QSPI1_SPCLK */
+               [ 7] = PIN_QSPI1_MOSI_IO0,      /* QSPI1_MOSI_IO0 */
+               [ 8] = PIN_QSPI1_MISO_IO1,      /* QSPI1_MISO_IO1 */
+               [ 9] = PIN_QSPI1_IO2,           /* QSPI1_IO2 */
+               [10] = PIN_QSPI1_IO3,           /* QSPI1_IO3 */
+               [11] = PIN_QSPI1_SSL,           /* QSPI1_SSL */
+               [12] = PIN_RPC_INT_N,           /* RPC_INT# */
+               [13] = PIN_RPC_WP_N,            /* RPC_WP# */
+               [14] = PIN_RPC_RESET_N,         /* RPC_RESET# */
+               [15] = PIN_AVB_RX_CTL,          /* AVB_RX_CTL */
+               [16] = PIN_AVB_RXC,             /* AVB_RXC */
+               [17] = PIN_AVB_RD0,             /* AVB_RD0 */
+               [18] = PIN_AVB_RD1,             /* AVB_RD1 */
+               [19] = PIN_AVB_RD2,             /* AVB_RD2 */
+               [20] = PIN_AVB_RD3,             /* AVB_RD3 */
+               [21] = PIN_AVB_TX_CTL,          /* AVB_TX_CTL */
+               [22] = PIN_AVB_TXC,             /* AVB_TXC */
+               [23] = PIN_AVB_TD0,             /* AVB_TD0 */
+               [24] = PIN_AVB_TD1,             /* AVB_TD1 */
+               [25] = PIN_AVB_TD2,             /* AVB_TD2 */
+               [26] = PIN_AVB_TD3,             /* AVB_TD3 */
+               [27] = PIN_AVB_TXCREFCLK,       /* AVB_TXCREFCLK */
+               [28] = PIN_AVB_MDIO,            /* AVB_MDIO */
                [29] = RCAR_GP_PIN(2,  9),      /* AVB_MDC */
                [30] = RCAR_GP_PIN(2, 10),      /* AVB_MAGIC */
                [31] = RCAR_GP_PIN(2, 11),      /* AVB_PHY_INT */
@@ -6181,7 +6215,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [ 6] = RCAR_GP_PIN(1, 25),      /* WE0_N */
                [ 7] = RCAR_GP_PIN(1, 26),      /* WE1_N */
                [ 8] = RCAR_GP_PIN(1, 27),      /* EX_WAIT0_A */
-               [ 9] = PIN_NUMBER('C', 1),      /* PRESETOUT# */
+               [ 9] = PIN_PRESETOUT_N,         /* PRESETOUT# */
                [10] = RCAR_GP_PIN(0,  0),      /* D0 */
                [11] = RCAR_GP_PIN(0,  1),      /* D1 */
                [12] = RCAR_GP_PIN(0,  2),      /* D2 */
@@ -6202,20 +6236,20 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [27] = RCAR_GP_PIN(7,  1),      /* AVS2 */
                [28] = RCAR_GP_PIN(7,  2),      /* GP7_02 */
                [29] = RCAR_GP_PIN(7,  3),      /* GP7_03 */
-               [30] = PIN_A_NUMBER('P', 7),    /* DU_DOTCLKIN0 */
-               [31] = PIN_A_NUMBER('P', 8),    /* DU_DOTCLKIN1 */
+               [30] = PIN_DU_DOTCLKIN0,        /* DU_DOTCLKIN0 */
+               [31] = PIN_DU_DOTCLKIN1,        /* DU_DOTCLKIN1 */
        } },
        { PINMUX_BIAS_REG("PUEN3", 0xe606040c, "PUD3", 0xe606044c) {
-               [ 0] = PIN_A_NUMBER('R', 8),    /* DU_DOTCLKIN3 */
-               [ 1] = PIN_NONE,
-               [ 2] = PIN_A_NUMBER('D', 38),   /* FSCLKST */
-               [ 3] = PIN_A_NUMBER('D', 39),   /* EXTALR*/
-               [ 4] = PIN_A_NUMBER('R', 26),   /* TRST# */
-               [ 5] = PIN_A_NUMBER('T', 27),   /* TCK */
-               [ 6] = PIN_A_NUMBER('R', 30),   /* TMS */
-               [ 7] = PIN_A_NUMBER('R', 29),   /* TDI */
-               [ 8] = PIN_NONE,
-               [ 9] = PIN_A_NUMBER('T', 30),   /* ASEBRK */
+               [ 0] = PIN_DU_DOTCLKIN3,        /* DU_DOTCLKIN3 */
+               [ 1] = SH_PFC_PIN_NONE,
+               [ 2] = PIN_FSCLKST,             /* FSCLKST */
+               [ 3] = PIN_EXTALR,              /* EXTALR*/
+               [ 4] = PIN_TRST_N,              /* TRST# */
+               [ 5] = PIN_TCK,                 /* TCK */
+               [ 6] = PIN_TMS,                 /* TMS */
+               [ 7] = PIN_TDI,                 /* TDI */
+               [ 8] = SH_PFC_PIN_NONE,
+               [ 9] = PIN_ASEBRK,              /* ASEBRK */
                [10] = RCAR_GP_PIN(3,  0),      /* SD0_CLK */
                [11] = RCAR_GP_PIN(3,  1),      /* SD0_CMD */
                [12] = RCAR_GP_PIN(3,  2),      /* SD0_DAT0 */
@@ -6280,7 +6314,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [ 3] = RCAR_GP_PIN(5, 23),      /* MLB_CLK */
                [ 4] = RCAR_GP_PIN(5, 24),      /* MLB_SIG */
                [ 5] = RCAR_GP_PIN(5, 25),      /* MLB_DAT */
-               [ 6] = PIN_NUMBER('H', 37),     /* MLB_REF */
+               [ 6] = PIN_MLB_REF,             /* MLB_REF */
                [ 7] = RCAR_GP_PIN(6,  0),      /* SSI_SCK01239 */
                [ 8] = RCAR_GP_PIN(6,  1),      /* SSI_WS01239 */
                [ 9] = RCAR_GP_PIN(6,  2),      /* SSI_SDATA0 */
@@ -6315,31 +6349,31 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [ 4] = RCAR_GP_PIN(6, 29),      /* USB30_OVC */
                [ 5] = RCAR_GP_PIN(6, 30),      /* GP6_30 */
                [ 6] = RCAR_GP_PIN(6, 31),      /* GP6_31 */
-               [ 7] = PIN_NONE,
-               [ 8] = PIN_NONE,
-               [ 9] = PIN_NONE,
-               [10] = PIN_NONE,
-               [11] = PIN_NONE,
-               [12] = PIN_NONE,
-               [13] = PIN_NONE,
-               [14] = PIN_NONE,
-               [15] = PIN_NONE,
-               [16] = PIN_NONE,
-               [17] = PIN_NONE,
-               [18] = PIN_NONE,
-               [19] = PIN_NONE,
-               [20] = PIN_NONE,
-               [21] = PIN_NONE,
-               [22] = PIN_NONE,
-               [23] = PIN_NONE,
-               [24] = PIN_NONE,
-               [25] = PIN_NONE,
-               [26] = PIN_NONE,
-               [27] = PIN_NONE,
-               [28] = PIN_NONE,
-               [29] = PIN_NONE,
-               [30] = PIN_NONE,
-               [31] = PIN_NONE,
+               [ 7] = SH_PFC_PIN_NONE,
+               [ 8] = SH_PFC_PIN_NONE,
+               [ 9] = SH_PFC_PIN_NONE,
+               [10] = SH_PFC_PIN_NONE,
+               [11] = SH_PFC_PIN_NONE,
+               [12] = SH_PFC_PIN_NONE,
+               [13] = SH_PFC_PIN_NONE,
+               [14] = SH_PFC_PIN_NONE,
+               [15] = SH_PFC_PIN_NONE,
+               [16] = SH_PFC_PIN_NONE,
+               [17] = SH_PFC_PIN_NONE,
+               [18] = SH_PFC_PIN_NONE,
+               [19] = SH_PFC_PIN_NONE,
+               [20] = SH_PFC_PIN_NONE,
+               [21] = SH_PFC_PIN_NONE,
+               [22] = SH_PFC_PIN_NONE,
+               [23] = SH_PFC_PIN_NONE,
+               [24] = SH_PFC_PIN_NONE,
+               [25] = SH_PFC_PIN_NONE,
+               [26] = SH_PFC_PIN_NONE,
+               [27] = SH_PFC_PIN_NONE,
+               [28] = SH_PFC_PIN_NONE,
+               [29] = SH_PFC_PIN_NONE,
+               [30] = SH_PFC_PIN_NONE,
+               [31] = SH_PFC_PIN_NONE,
        } },
        { /* sentinel */ },
 };
index 2d76b54..25e27b6 100644 (file)
@@ -19,7 +19,7 @@
 #include "core.h"
 #include "sh_pfc.h"
 
-#define CPU_ALL_PORT(fn, sfx)                                          \
+#define CPU_ALL_GP(fn, sfx)                                            \
        PORT_GP_CFG_22(0, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE),          \
        PORT_GP_28(1, fn, sfx),                                         \
        PORT_GP_CFG_17(2, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE),          \
 #define IP6_19_16      FM(VI1_DATA8)                   F_(0, 0)                FM(CTS4_N)      FM(D11)         FM(MMC_D5)              F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
 #define IP6_23_20      FM(VI1_DATA9)                   F_(0, 0)                FM(RTS4_N)      FM(D12)         FM(MMC_D6)              FM(SCL3_B)      F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
 #define IP6_27_24      FM(VI1_DATA10)                  F_(0, 0)                F_(0, 0)        FM(D13)         FM(MMC_D7)              FM(SDA3_B)      F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP6_31_28      FM(VI1_DATA11)                  FM(SCL4)                FM(IRQ4)        FM(D14)         FM(MMC_WP)              F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP7_3_0                FM(VI1_FIELD)                   FM(SDA4)                FM(IRQ5)        FM(D15)         FM(MMC_CD)              F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP6_31_28      FM(VI1_DATA11)                  FM(SCL4)                FM(IRQ4)        FM(D14)         F_(0, 0)                F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP7_3_0                FM(VI1_FIELD)                   FM(SDA4)                FM(IRQ5)        FM(D15)         F_(0, 0)                F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
 #define IP7_7_4                FM(SCL0)                        FM(DU_DR0)              FM(TPU0TO0)     FM(CLKOUT)      F_(0, 0)                FM(MSIOF0_RXD)  F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
 #define IP7_11_8       FM(SDA0)                        FM(DU_DR1)              FM(TPU0TO1)     FM(BS_N)        FM(SCK0)                FM(MSIOF0_TXD)  F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
 #define IP7_15_12      FM(SCL1)                        FM(DU_DG0)              FM(TPU0TO2)     FM(RD_N)        FM(CTS0_N)              FM(MSIOF0_SCK)  F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
@@ -631,14 +631,12 @@ static const u16 pinmux_data[] = {
        PINMUX_IPSR_GPSR(IP6_31_28,     SCL4),
        PINMUX_IPSR_GPSR(IP6_31_28,     IRQ4),
        PINMUX_IPSR_GPSR(IP6_31_28,     D14),
-       PINMUX_IPSR_GPSR(IP6_31_28,     MMC_WP),
 
        /* IPSR7 */
        PINMUX_IPSR_GPSR(IP7_3_0,       VI1_FIELD),
        PINMUX_IPSR_GPSR(IP7_3_0,       SDA4),
        PINMUX_IPSR_GPSR(IP7_3_0,       IRQ5),
        PINMUX_IPSR_GPSR(IP7_3_0,       D15),
-       PINMUX_IPSR_GPSR(IP7_3_0,       MMC_CD),
 
        PINMUX_IPSR_GPSR(IP7_7_4,       SCL0),
        PINMUX_IPSR_GPSR(IP7_7_4,       DU_DR0),
@@ -1121,20 +1119,6 @@ static const unsigned int mmc_ctrl_pins[] = {
 static const unsigned int mmc_ctrl_mux[] = {
        MMC_CLK_MARK, MMC_CMD_MARK,
 };
-static const unsigned int mmc_cd_pins[] = {
-       /* CD */
-       RCAR_GP_PIN(3, 16),
-};
-static const unsigned int mmc_cd_mux[] = {
-       MMC_CD_MARK,
-};
-static const unsigned int mmc_wp_pins[] = {
-       /* WP */
-       RCAR_GP_PIN(3, 15),
-};
-static const unsigned int mmc_wp_mux[] = {
-       MMC_WP_MARK,
-};
 
 /* - MSIOF0 ----------------------------------------------------------------- */
 static const unsigned int msiof0_clk_pins[] = {
@@ -1726,8 +1710,6 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(mmc_data4),
        SH_PFC_PIN_GROUP(mmc_data8),
        SH_PFC_PIN_GROUP(mmc_ctrl),
-       SH_PFC_PIN_GROUP(mmc_cd),
-       SH_PFC_PIN_GROUP(mmc_wp),
        SH_PFC_PIN_GROUP(msiof0_clk),
        SH_PFC_PIN_GROUP(msiof0_sync),
        SH_PFC_PIN_GROUP(msiof0_ss1),
@@ -1897,8 +1879,6 @@ static const char * const mmc_groups[] = {
        "mmc_data4",
        "mmc_data8",
        "mmc_ctrl",
-       "mmc_cd",
-       "mmc_wp",
 };
 
 static const char * const msiof0_groups[] = {
index 9ed4ead..14fe403 100644 (file)
@@ -19,7 +19,7 @@
 #include "core.h"
 #include "sh_pfc.h"
 
-#define CPU_ALL_PORT(fn, sfx)  \
+#define CPU_ALL_GP(fn, sfx)    \
        PORT_GP_CFG_22(0, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE),  \
        PORT_GP_28(1, fn, sfx), \
        PORT_GP_CFG_30(2, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE),  \
index 91a837b..2dfb8d9 100644 (file)
 #include "core.h"
 #include "sh_pfc.h"
 
-#define CFG_FLAGS (SH_PFC_PIN_CFG_PULL_UP | \
-                  SH_PFC_PIN_CFG_PULL_DOWN)
+#define CFG_FLAGS (SH_PFC_PIN_CFG_PULL_UP_DOWN)
 
-#define CPU_ALL_PORT(fn, sfx) \
+#define CPU_ALL_GP(fn, sfx) \
        PORT_GP_CFG_18(0, fn, sfx, CFG_FLAGS), \
        PORT_GP_CFG_23(1, fn, sfx, CFG_FLAGS), \
        PORT_GP_CFG_26(2, fn, sfx, CFG_FLAGS), \
        PORT_GP_CFG_1(6, 15, fn, sfx, CFG_FLAGS), \
        PORT_GP_CFG_1(6, 16, fn, sfx, CFG_FLAGS), \
        PORT_GP_CFG_1(6, 17, fn, sfx, CFG_FLAGS)
+
+#define CPU_ALL_NOGP(fn)                                               \
+       PIN_NOGP_CFG(ASEBRK, "ASEBRK", fn, CFG_FLAGS),                  \
+       PIN_NOGP_CFG(AVB_MDC, "AVB_MDC", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_MDIO, "AVB_MDIO", fn, CFG_FLAGS),              \
+       PIN_NOGP_CFG(AVB_TD0, "AVB_TD0", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TD1, "AVB_TD1", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TD2, "AVB_TD2", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TD3, "AVB_TD3", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TXC, "AVB_TXC", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(AVB_TX_CTL, "AVB_TX_CTL", fn, CFG_FLAGS),          \
+       PIN_NOGP_CFG(FSCLKST_N, "FSCLKST_N", fn, CFG_FLAGS),            \
+       PIN_NOGP_CFG(MLB_REF, "MLB_REF", fn, CFG_FLAGS),                \
+       PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT_N", fn, CFG_FLAGS),        \
+       PIN_NOGP_CFG(TCK, "TCK", fn, CFG_FLAGS),                        \
+       PIN_NOGP_CFG(TDI, "TDI", fn, CFG_FLAGS),                        \
+       PIN_NOGP_CFG(TMS, "TMS", fn, CFG_FLAGS),                        \
+       PIN_NOGP_CFG(TRST_N, "TRST_N", fn, CFG_FLAGS)
+
 /*
  * F_() : just information
  * FM() : macro for FN_xxx / xxx_MARK
@@ -1277,41 +1295,16 @@ static const u16 pinmux_data[] = {
 };
 
 /*
- * R8A77990 has 7 banks with 32 GPIOs in each => 224 GPIOs.
- * Physical layout rows: A - AE, cols: 1 - 25.
+ * Pins not associated with a GPIO port.
  */
-#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r))
-#define PIN_NUMBER(r, c) (((r) - 'A') * 25 + (c) + 300)
-#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c)
-#define PIN_NONE U16_MAX
+enum {
+       GP_ASSIGN_LAST(),
+       NOGP_ALL(),
+};
 
 static const struct sh_pfc_pin pinmux_pins[] = {
        PINMUX_GPIO_GP_ALL(),
-
-       /*
-        * Pins not associated with a GPIO port.
-        *
-        * The pin positions are different between different R8A77990
-        * packages, all that is needed for the pfc driver is a unique
-        * number for each pin. To this end use the pin layout from
-        * R8A77990 to calculate a unique number for each pin.
-        */
-       SH_PFC_PIN_NAMED_CFG('F',  1, TRST_N,           CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('F',  3, TMS,              CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('F',  4, TCK,              CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('G',  2, TDI,              CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('G',  3, FSCLKST_N,        CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('H',  1, ASEBRK,           CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('N',  1, AVB_TXC,          CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('N',  2, AVB_TD0,          CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('N',  3, AVB_TD1,          CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('N',  5, AVB_TD2,          CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('N',  6, AVB_TD3,          CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('P',  3, AVB_TX_CTL,       CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('P',  4, AVB_MDIO,         CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('P',  5, AVB_MDC,          CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('T', 21, MLB_REF,          CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 3, PRESETOUT_N, CFG_FLAGS),
+       PINMUX_NOGP_ALL(),
 };
 
 /* - AUDIO CLOCK ------------------------------------------------------------ */
@@ -5026,15 +5019,15 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                 [0] = RCAR_GP_PIN(2, 23),      /* RD# */
                 [1] = RCAR_GP_PIN(2, 22),      /* BS# */
                 [2] = RCAR_GP_PIN(2, 21),      /* AVB_PHY_INT */
-                [3] = PIN_NUMBER('P', 5),      /* AVB_MDC */
-                [4] = PIN_NUMBER('P', 4),      /* AVB_MDIO */
+                [3] = PIN_AVB_MDC,             /* AVB_MDC */
+                [4] = PIN_AVB_MDIO,            /* AVB_MDIO */
                 [5] = RCAR_GP_PIN(2, 20),      /* AVB_TXCREFCLK */
-                [6] = PIN_NUMBER('N', 6),      /* AVB_TD3 */
-                [7] = PIN_NUMBER('N', 5),      /* AVB_TD2 */
-                [8] = PIN_NUMBER('N', 3),      /* AVB_TD1 */
-                [9] = PIN_NUMBER('N', 2),      /* AVB_TD0 */
-               [10] = PIN_NUMBER('N', 1),      /* AVB_TXC */
-               [11] = PIN_NUMBER('P', 3),      /* AVB_TX_CTL */
+                [6] = PIN_AVB_TD3,             /* AVB_TD3 */
+                [7] = PIN_AVB_TD2,             /* AVB_TD2 */
+                [8] = PIN_AVB_TD1,             /* AVB_TD1 */
+                [9] = PIN_AVB_TD0,             /* AVB_TD0 */
+               [10] = PIN_AVB_TXC,             /* AVB_TXC */
+               [11] = PIN_AVB_TX_CTL,          /* AVB_TX_CTL */
                [12] = RCAR_GP_PIN(2, 19),      /* AVB_RD3 */
                [13] = RCAR_GP_PIN(2, 18),      /* AVB_RD2 */
                [14] = RCAR_GP_PIN(2, 17),      /* AVB_RD1 */
@@ -5085,33 +5078,33 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [25] = RCAR_GP_PIN(1,  2),      /* A2 */
                [26] = RCAR_GP_PIN(1,  1),      /* A1 */
                [27] = RCAR_GP_PIN(1,  0),      /* A0 */
-               [28] = PIN_NONE,
-               [29] = PIN_NONE,
+               [28] = SH_PFC_PIN_NONE,
+               [29] = SH_PFC_PIN_NONE,
                [30] = RCAR_GP_PIN(2, 25),      /* PUEN_EX_WAIT0 */
                [31] = RCAR_GP_PIN(2, 24),      /* PUEN_RD/WR# */
        } },
        { PINMUX_BIAS_REG("PUEN2", 0xe6060408, "PUD2", 0xe6060448) {
                 [0] = RCAR_GP_PIN(3,  1),      /* SD0_CMD */
                 [1] = RCAR_GP_PIN(3,  0),      /* SD0_CLK */
-                [2] = PIN_NUMBER('H', 1),      /* ASEBRK */
-                [3] = PIN_NONE,
-                [4] = PIN_NUMBER('G', 2),      /* TDI */
-                [5] = PIN_NUMBER('F', 3),      /* TMS */
-                [6] = PIN_NUMBER('F', 4),      /* TCK */
-                [7] = PIN_NUMBER('F', 1),      /* TRST# */
-                [8] = PIN_NONE,
-                [9] = PIN_NONE,
-               [10] = PIN_NONE,
-               [11] = PIN_NONE,
-               [12] = PIN_NONE,
-               [13] = PIN_NONE,
-               [14] = PIN_NONE,
-               [15] = PIN_NUMBER('G', 3),      /* FSCLKST# */
+                [2] = PIN_ASEBRK,              /* ASEBRK */
+                [3] = SH_PFC_PIN_NONE,
+                [4] = PIN_TDI,                 /* TDI */
+                [5] = PIN_TMS,                 /* TMS */
+                [6] = PIN_TCK,                 /* TCK */
+                [7] = PIN_TRST_N,              /* TRST# */
+                [8] = SH_PFC_PIN_NONE,
+                [9] = SH_PFC_PIN_NONE,
+               [10] = SH_PFC_PIN_NONE,
+               [11] = SH_PFC_PIN_NONE,
+               [12] = SH_PFC_PIN_NONE,
+               [13] = SH_PFC_PIN_NONE,
+               [14] = SH_PFC_PIN_NONE,
+               [15] = PIN_FSCLKST_N,           /* FSCLKST# */
                [16] = RCAR_GP_PIN(0, 17),      /* SDA4 */
                [17] = RCAR_GP_PIN(0, 16),      /* SCL4 */
-               [18] = PIN_NONE,
-               [19] = PIN_NONE,
-               [20] = PIN_A_NUMBER('D', 3),    /* PRESETOUT# */
+               [18] = SH_PFC_PIN_NONE,
+               [19] = SH_PFC_PIN_NONE,
+               [20] = PIN_PRESETOUT_N,         /* PRESETOUT# */
                [21] = RCAR_GP_PIN(0, 15),      /* D15 */
                [22] = RCAR_GP_PIN(0, 14),      /* D14 */
                [23] = RCAR_GP_PIN(0, 13),      /* D13 */
@@ -5130,8 +5123,8 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                 [2] = RCAR_GP_PIN(5,  3),      /* CTS0#_A */
                 [3] = RCAR_GP_PIN(5,  2),      /* TX0_A */
                 [4] = RCAR_GP_PIN(5,  1),      /* RX0_A */
-                [5] = PIN_NONE,
-                [6] = PIN_NONE,
+                [5] = SH_PFC_PIN_NONE,
+                [6] = SH_PFC_PIN_NONE,
                 [7] = RCAR_GP_PIN(3, 15),      /* SD1_WP */
                 [8] = RCAR_GP_PIN(3, 14),      /* SD1_CD */
                 [9] = RCAR_GP_PIN(3, 13),      /* SD0_WP */
@@ -5175,7 +5168,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [13] = RCAR_GP_PIN(6,  2),      /* SSI_SDATA0 */
                [14] = RCAR_GP_PIN(6,  1),      /* SSI_WS01239 */
                [15] = RCAR_GP_PIN(6,  0),      /* SSI_SCK01239 */
-               [16] = PIN_NUMBER('T', 21),     /* MLB_REF */
+               [16] = PIN_MLB_REF,             /* MLB_REF */
                [17] = RCAR_GP_PIN(5, 19),      /* MLB_DAT */
                [18] = RCAR_GP_PIN(5, 18),      /* MLB_SIG */
                [19] = RCAR_GP_PIN(5, 17),      /* MLB_CLK */
@@ -5193,36 +5186,36 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
                [31] = RCAR_GP_PIN(5,  5),      /* RX1 */
        } },
        { PINMUX_BIAS_REG("PUEN5", 0xe6060414, "PUD5", 0xe6060454) {
-                [0] = PIN_NONE,
-                [1] = PIN_NONE,
-                [2] = PIN_NONE,
-                [3] = PIN_NONE,
-                [4] = PIN_NONE,
-                [5] = PIN_NONE,
-                [6] = PIN_NONE,
-                [7] = PIN_NONE,
-                [8] = PIN_NONE,
-                [9] = PIN_NONE,
-               [10] = PIN_NONE,
-               [11] = PIN_NONE,
-               [12] = PIN_NONE,
-               [13] = PIN_NONE,
-               [14] = PIN_NONE,
-               [15] = PIN_NONE,
-               [16] = PIN_NONE,
-               [17] = PIN_NONE,
-               [18] = PIN_NONE,
-               [19] = PIN_NONE,
-               [20] = PIN_NONE,
-               [21] = PIN_NONE,
-               [22] = PIN_NONE,
-               [23] = PIN_NONE,
-               [24] = PIN_NONE,
-               [25] = PIN_NONE,
-               [26] = PIN_NONE,
-               [27] = PIN_NONE,
-               [28] = PIN_NONE,
-               [29] = PIN_NONE,
+                [0] = SH_PFC_PIN_NONE,
+                [1] = SH_PFC_PIN_NONE,
+                [2] = SH_PFC_PIN_NONE,
+                [3] = SH_PFC_PIN_NONE,
+                [4] = SH_PFC_PIN_NONE,
+                [5] = SH_PFC_PIN_NONE,
+                [6] = SH_PFC_PIN_NONE,
+                [7] = SH_PFC_PIN_NONE,
+                [8] = SH_PFC_PIN_NONE,
+                [9] = SH_PFC_PIN_NONE,
+               [10] = SH_PFC_PIN_NONE,
+               [11] = SH_PFC_PIN_NONE,
+               [12] = SH_PFC_PIN_NONE,
+               [13] = SH_PFC_PIN_NONE,
+               [14] = SH_PFC_PIN_NONE,
+               [15] = SH_PFC_PIN_NONE,
+               [16] = SH_PFC_PIN_NONE,
+               [17] = SH_PFC_PIN_NONE,
+               [18] = SH_PFC_PIN_NONE,
+               [19] = SH_PFC_PIN_NONE,
+               [20] = SH_PFC_PIN_NONE,
+               [21] = SH_PFC_PIN_NONE,
+               [22] = SH_PFC_PIN_NONE,
+               [23] = SH_PFC_PIN_NONE,
+               [24] = SH_PFC_PIN_NONE,
+               [25] = SH_PFC_PIN_NONE,
+               [26] = SH_PFC_PIN_NONE,
+               [27] = SH_PFC_PIN_NONE,
+               [28] = SH_PFC_PIN_NONE,
+               [29] = SH_PFC_PIN_NONE,
                [30] = RCAR_GP_PIN(6,  9),      /* PUEN_USB30_OVC */
                [31] = RCAR_GP_PIN(6, 17),      /* PUEN_USB30_PWEN */
        } },
index dd87085..c10b756 100644 (file)
@@ -17,7 +17,7 @@
 #include "core.h"
 #include "sh_pfc.h"
 
-#define CPU_ALL_PORT(fn, sfx)                  \
+#define CPU_ALL_GP(fn, sfx)                    \
                PORT_GP_9(0,  fn, sfx),         \
                PORT_GP_32(1, fn, sfx),         \
                PORT_GP_32(2, fn, sfx),         \
index e1276d1..afabd95 100644 (file)
@@ -43,6 +43,9 @@
        PORT_1(288, fn, pfx##288, sfx), PORT_1(289, fn, pfx##289, sfx), \
        PORT_10(290, fn, pfx##29, sfx), PORT_10(300, fn, pfx##30, sfx)
 
+#define CPU_ALL_NOGP(fn)       \
+       PIN_NOGP(A11, "F26", fn)
+
 enum {
        PINMUX_RESERVED = 0,
 
@@ -1147,7 +1150,7 @@ static const u16 pinmux_data[] = {
 #define __IO           (SH_PFC_PIN_CFG_INPUT | SH_PFC_PIN_CFG_OUTPUT)
 #define __PD           (SH_PFC_PIN_CFG_PULL_DOWN)
 #define __PU           (SH_PFC_PIN_CFG_PULL_UP)
-#define __PUD          (SH_PFC_PIN_CFG_PULL_DOWN | SH_PFC_PIN_CFG_PULL_UP)
+#define __PUD          (SH_PFC_PIN_CFG_PULL_UP_DOWN)
 
 #define SH73A0_PIN_I_PD(pin)           SH_PFC_PIN_CFG(pin, __I | __PD)
 #define SH73A0_PIN_I_PU(pin)           SH_PFC_PIN_CFG(pin, __I | __PU)
@@ -1158,11 +1161,13 @@ static const u16 pinmux_data[] = {
 #define SH73A0_PIN_IO_PU_PD(pin)       SH_PFC_PIN_CFG(pin, __IO | __PUD)
 #define SH73A0_PIN_O(pin)              SH_PFC_PIN_CFG(pin, __O)
 
-/* Pin numbers for pins without a corresponding GPIO port number are computed
- * from the row and column numbers with a 1000 offset to avoid collisions with
- * GPIO port numbers.
+/*
+ * Pins not associated with a GPIO port.
  */
-#define PIN_NUMBER(row, col)           (1000+((row)-1)*34+(col)-1)
+enum {
+       PORT_ASSIGN_LAST(),
+       NOGP_ALL(),
+};
 
 static const struct sh_pfc_pin pinmux_pins[] = {
        /* Table 25-1 (I/O and Pull U/D) */
@@ -1437,7 +1442,7 @@ static const struct sh_pfc_pin pinmux_pins[] = {
        SH73A0_PIN_O(309),
 
        /* Pins not associated with a GPIO port */
-       SH_PFC_PIN_NAMED(6, 26, F26),
+       PINMUX_NOGP_ALL(),
 };
 
 /* - BSC -------------------------------------------------------------------- */
@@ -1863,7 +1868,7 @@ static const unsigned int keysc_out7_2_mux[] = {
 };
 static const unsigned int keysc_out8_0_pins[] = {
        /* KEYOUT8 */
-       PIN_NUMBER(6, 26),
+       PIN_A11,
 };
 static const unsigned int keysc_out8_0_mux[] = {
        KEYOUT8_MARK,
@@ -3073,7 +3078,7 @@ static const unsigned int tpu4_to2_mux[] = {
 };
 static const unsigned int tpu4_to3_pins[] = {
        /* TO */
-       PIN_NUMBER(6, 26),
+       PIN_A11,
 };
 static const unsigned int tpu4_to3_mux[] = {
        TPU4TO3_MARK,
index fac7b46..5dfd991 100644 (file)
@@ -11,7 +11,7 @@
 
 #include "sh_pfc.h"
 
-#define CPU_ALL_PORT(fn, sfx)                                          \
+#define CPU_ALL_GP(fn, sfx)                                            \
        PORT_GP_32(0, fn, sfx),                                         \
        PORT_GP_32(1, fn, sfx),                                         \
        PORT_GP_32(2, fn, sfx),                                         \
index c97d2ba..2824be4 100644 (file)
@@ -569,8 +569,7 @@ static bool sh_pfc_pinconf_validate(struct sh_pfc *pfc, unsigned int _pin,
 
        switch (param) {
        case PIN_CONFIG_BIAS_DISABLE:
-               return pin->configs &
-                       (SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN);
+               return pin->configs & SH_PFC_PIN_CFG_PULL_UP_DOWN;
 
        case PIN_CONFIG_BIAS_PULL_UP:
                return pin->configs & SH_PFC_PIN_CFG_PULL_UP;
index 7db5819..835148f 100644 (file)
@@ -21,10 +21,14 @@ enum {
        PINMUX_TYPE_INPUT,
 };
 
+#define SH_PFC_PIN_NONE                        U16_MAX
+
 #define SH_PFC_PIN_CFG_INPUT           (1 << 0)
 #define SH_PFC_PIN_CFG_OUTPUT          (1 << 1)
 #define SH_PFC_PIN_CFG_PULL_UP         (1 << 2)
 #define SH_PFC_PIN_CFG_PULL_DOWN       (1 << 3)
+#define SH_PFC_PIN_CFG_PULL_UP_DOWN    (SH_PFC_PIN_CFG_PULL_UP | \
+                                        SH_PFC_PIN_CFG_PULL_DOWN)
 #define SH_PFC_PIN_CFG_IO_VOLTAGE      (1 << 4)
 #define SH_PFC_PIN_CFG_DRIVE_STRENGTH  (1 << 5)
 #define SH_PFC_PIN_CFG_NO_GPIO         (1 << 31)
@@ -542,9 +546,13 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info;
        PORT_GP_CFG_1(bank, 25, fn, sfx, cfg)
 #define PORT_GP_26(bank, fn, sfx)      PORT_GP_CFG_26(bank, fn, sfx, 0)
 
-#define PORT_GP_CFG_28(bank, fn, sfx, cfg)                             \
+#define PORT_GP_CFG_27(bank, fn, sfx, cfg)                             \
        PORT_GP_CFG_26(bank, fn, sfx, cfg),                             \
-       PORT_GP_CFG_1(bank, 26, fn, sfx, cfg),                          \
+       PORT_GP_CFG_1(bank, 26, fn, sfx, cfg)
+#define PORT_GP_27(bank, fn, sfx)      PORT_GP_CFG_27(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_28(bank, fn, sfx, cfg)                             \
+       PORT_GP_CFG_27(bank, fn, sfx, cfg),                             \
        PORT_GP_CFG_1(bank, 27, fn, sfx, cfg)
 #define PORT_GP_28(bank, fn, sfx)      PORT_GP_CFG_28(bank, fn, sfx, 0)
 
@@ -584,7 +592,7 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info;
 
 /* GP_ALL(suffix) - Expand to a list of GP_#_#_suffix */
 #define _GP_ALL(bank, pin, name, sfx, cfg)     name##_##sfx
-#define GP_ALL(str)                    CPU_ALL_PORT(_GP_ALL, str)
+#define GP_ALL(str)                    CPU_ALL_GP(_GP_ALL, str)
 
 /* PINMUX_GPIO_GP_ALL - Expand to a list of sh_pfc_pin entries */
 #define _GP_GPIO(bank, _pin, _name, sfx, cfg)                          \
@@ -594,11 +602,29 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info;
                .enum_id = _name##_DATA,                                \
                .configs = cfg,                                         \
        }
-#define PINMUX_GPIO_GP_ALL()           CPU_ALL_PORT(_GP_GPIO, unused)
+#define PINMUX_GPIO_GP_ALL()           CPU_ALL_GP(_GP_GPIO, unused)
 
 /* PINMUX_DATA_GP_ALL -  Expand to a list of name_DATA, name_FN marks */
 #define _GP_DATA(bank, pin, name, sfx, cfg)    PINMUX_DATA(name##_DATA, name##_FN)
-#define PINMUX_DATA_GP_ALL()           CPU_ALL_PORT(_GP_DATA, unused)
+#define PINMUX_DATA_GP_ALL()           CPU_ALL_GP(_GP_DATA, unused)
+
+/*
+ * GP_ASSIGN_LAST() - Expand to an enum definition for the last GP pin
+ *
+ * The largest GP pin index is obtained by taking the size of a union,
+ * containing one array per GP pin, sized by the corresponding pin index.
+ * As the fields in the CPU_ALL_GP() macro definition are separated by commas,
+ * while the members of a union must be terminated by semicolons, the commas
+ * are absorbed by wrapping them inside dummy attributes.
+ */
+#define _GP_ENTRY(bank, pin, name, sfx, cfg)                           \
+       deprecated)); char name[(bank * 32) + pin] __attribute__((deprecated
+#define GP_ASSIGN_LAST()                                               \
+       GP_LAST = sizeof(union {                                        \
+               char dummy[0] __attribute__((deprecated,                \
+               CPU_ALL_GP(_GP_ENTRY, unused),                          \
+               deprecated));                                           \
+       })
 
 /*
  * PORT style (linear pin space)
@@ -641,22 +667,6 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info;
                .configs = cfgs,                                        \
        }
 
-/* SH_PFC_PIN_NAMED - Expand to a sh_pfc_pin entry with the given name */
-#define SH_PFC_PIN_NAMED(row, col, _name)                              \
-       {                                                               \
-               .pin = PIN_NUMBER(row, col),                            \
-               .name = __stringify(PIN_##_name),                       \
-               .configs = SH_PFC_PIN_CFG_NO_GPIO,                      \
-       }
-
-/* SH_PFC_PIN_NAMED_CFG - Expand to a sh_pfc_pin entry with the given name */
-#define SH_PFC_PIN_NAMED_CFG(row, col, _name, cfgs)                    \
-       {                                                               \
-               .pin = PIN_NUMBER(row, col),                            \
-               .name = __stringify(PIN_##_name),                       \
-               .configs = SH_PFC_PIN_CFG_NO_GPIO | cfgs,               \
-       }
-
 /* PINMUX_DATA_ALL - Expand to a list of PORT_name_DATA, PORT_name_FN0,
  *                  PORT_name_OUT, PORT_name_IN marks
  */
@@ -665,6 +675,24 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info;
                    PORT##pfx##_OUT, PORT##pfx##_IN)
 #define PINMUX_DATA_ALL()              CPU_ALL_PORT(_PORT_DATA, , unused)
 
+/*
+ * PORT_ASSIGN_LAST() - Expand to an enum definition for the last PORT pin
+ *
+ * The largest PORT pin index is obtained by taking the size of a union,
+ * containing one array per PORT pin, sized by the corresponding pin index.
+ * As the fields in the CPU_ALL_PORT() macro definition are separated by
+ * commas, while the members of a union must be terminated by semicolons, the
+ * commas are absorbed by wrapping them inside dummy attributes.
+ */
+#define _PORT_ENTRY(pn, pfx, sfx)                                      \
+       deprecated)); char pfx[pn] __attribute__((deprecated
+#define PORT_ASSIGN_LAST()                                             \
+       PORT_LAST = sizeof(union {                                      \
+               char dummy[0] __attribute__((deprecated,                \
+               CPU_ALL_PORT(_PORT_ENTRY, PORT, unused),                \
+               deprecated));                                           \
+       })
+
 /* GPIO_FN(name) - Expand to a sh_pfc_pin entry for a function GPIO */
 #define PINMUX_GPIO_FN(gpio, base, data_or_mark)                       \
        [gpio - (base)] = {                                             \
@@ -674,6 +702,26 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info;
 #define GPIO_FN(str)                                                   \
        PINMUX_GPIO_FN(GPIO_FN_##str, PINMUX_FN_BASE, str##_MARK)
 
+/*
+ * Pins not associated with a GPIO port
+ */
+
+#define PIN_NOGP_CFG(pin, name, fn, cfg)       fn(pin, name, cfg)
+#define PIN_NOGP(pin, name, fn)                        fn(pin, name, 0)
+
+/* NOGP_ALL - Expand to a list of PIN_id */
+#define _NOGP_ALL(pin, name, cfg)              PIN_##pin
+#define NOGP_ALL()                             CPU_ALL_NOGP(_NOGP_ALL)
+
+/* PINMUX_NOGP_ALL - Expand to a list of sh_pfc_pin entries */
+#define _NOGP_PINMUX(_pin, _name, cfg)                                 \
+       {                                                               \
+               .pin = PIN_##_pin,                                      \
+               .name = "PIN_" _name,                                   \
+               .configs = SH_PFC_PIN_CFG_NO_GPIO | cfg,                \
+       }
+#define PINMUX_NOGP_ALL()              CPU_ALL_NOGP(_NOGP_PINMUX)
+
 /*
  * PORTnCR helper macro for SH-Mobile/R-Mobile
  */
index 2317ccf..b453aed 100644 (file)
 #define STM32_GPIO_AFRL                0x20
 #define STM32_GPIO_AFRH                0x24
 
+/* custom bitfield to backup pin status */
+#define STM32_GPIO_BKP_MODE_SHIFT      0
+#define STM32_GPIO_BKP_MODE_MASK       GENMASK(1, 0)
+#define STM32_GPIO_BKP_ALT_SHIFT       2
+#define STM32_GPIO_BKP_ALT_MASK                GENMASK(5, 2)
+#define STM32_GPIO_BKP_SPEED_SHIFT     6
+#define STM32_GPIO_BKP_SPEED_MASK      GENMASK(7, 6)
+#define STM32_GPIO_BKP_PUPD_SHIFT      8
+#define STM32_GPIO_BKP_PUPD_MASK       GENMASK(9, 8)
+#define STM32_GPIO_BKP_TYPE            10
+#define STM32_GPIO_BKP_VAL             11
+
 #define STM32_GPIO_PINS_PER_BANK 16
 #define STM32_GPIO_IRQ_LINE     16
 
@@ -79,6 +91,7 @@ struct stm32_gpio_bank {
        struct irq_domain *domain;
        u32 bank_nr;
        u32 bank_ioport_nr;
+       u32 pin_backup[STM32_GPIO_PINS_PER_BANK];
 };
 
 struct stm32_pinctrl {
@@ -98,6 +111,8 @@ struct stm32_pinctrl {
        struct stm32_desc_pin *pins;
        u32 npins;
        u32 pkg;
+       u16 irqmux_map;
+       spinlock_t irqmux_lock;
 };
 
 static inline int stm32_gpio_pin(int gpio)
@@ -133,11 +148,50 @@ static inline u32 stm32_gpio_get_alt(u32 function)
        return 0;
 }
 
+static void stm32_gpio_backup_value(struct stm32_gpio_bank *bank,
+                                   u32 offset, u32 value)
+{
+       bank->pin_backup[offset] &= ~BIT(STM32_GPIO_BKP_VAL);
+       bank->pin_backup[offset] |= value << STM32_GPIO_BKP_VAL;
+}
+
+static void stm32_gpio_backup_mode(struct stm32_gpio_bank *bank, u32 offset,
+                                  u32 mode, u32 alt)
+{
+       bank->pin_backup[offset] &= ~(STM32_GPIO_BKP_MODE_MASK |
+                                     STM32_GPIO_BKP_ALT_MASK);
+       bank->pin_backup[offset] |= mode << STM32_GPIO_BKP_MODE_SHIFT;
+       bank->pin_backup[offset] |= alt << STM32_GPIO_BKP_ALT_SHIFT;
+}
+
+static void stm32_gpio_backup_driving(struct stm32_gpio_bank *bank, u32 offset,
+                                     u32 drive)
+{
+       bank->pin_backup[offset] &= ~BIT(STM32_GPIO_BKP_TYPE);
+       bank->pin_backup[offset] |= drive << STM32_GPIO_BKP_TYPE;
+}
+
+static void stm32_gpio_backup_speed(struct stm32_gpio_bank *bank, u32 offset,
+                                   u32 speed)
+{
+       bank->pin_backup[offset] &= ~STM32_GPIO_BKP_SPEED_MASK;
+       bank->pin_backup[offset] |= speed << STM32_GPIO_BKP_SPEED_SHIFT;
+}
+
+static void stm32_gpio_backup_bias(struct stm32_gpio_bank *bank, u32 offset,
+                                  u32 bias)
+{
+       bank->pin_backup[offset] &= ~STM32_GPIO_BKP_PUPD_MASK;
+       bank->pin_backup[offset] |= bias << STM32_GPIO_BKP_PUPD_SHIFT;
+}
+
 /* GPIO functions */
 
 static inline void __stm32_gpio_set(struct stm32_gpio_bank *bank,
        unsigned offset, int value)
 {
+       stm32_gpio_backup_value(bank, offset, value);
+
        if (!value)
                offset += STM32_GPIO_PINS_PER_BANK;
 
@@ -307,9 +361,53 @@ static int stm32_gpio_domain_activate(struct irq_domain *d,
 {
        struct stm32_gpio_bank *bank = d->host_data;
        struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
+       unsigned long flags;
+       int ret = 0;
+
+       /*
+        * gpio irq mux is shared between several banks, a lock has to be done
+        * to avoid overriding.
+        */
+       spin_lock_irqsave(&pctl->irqmux_lock, flags);
+       if (pctl->hwlock)
+               ret = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT);
+
+       if (ret) {
+               dev_err(pctl->dev, "Can't get hwspinlock\n");
+               goto unlock;
+       }
+
+       if (pctl->irqmux_map & BIT(irq_data->hwirq)) {
+               dev_err(pctl->dev, "irq line %ld already requested.\n",
+                       irq_data->hwirq);
+               ret = -EBUSY;
+               if (pctl->hwlock)
+                       hwspin_unlock(pctl->hwlock);
+               goto unlock;
+       } else {
+               pctl->irqmux_map |= BIT(irq_data->hwirq);
+       }
 
        regmap_field_write(pctl->irqmux[irq_data->hwirq], bank->bank_ioport_nr);
-       return 0;
+
+       if (pctl->hwlock)
+               hwspin_unlock(pctl->hwlock);
+
+unlock:
+       spin_unlock_irqrestore(&pctl->irqmux_lock, flags);
+       return ret;
+}
+
+static void stm32_gpio_domain_deactivate(struct irq_domain *d,
+                                        struct irq_data *irq_data)
+{
+       struct stm32_gpio_bank *bank = d->host_data;
+       struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
+       unsigned long flags;
+
+       spin_lock_irqsave(&pctl->irqmux_lock, flags);
+       pctl->irqmux_map &= ~BIT(irq_data->hwirq);
+       spin_unlock_irqrestore(&pctl->irqmux_lock, flags);
 }
 
 static int stm32_gpio_domain_alloc(struct irq_domain *d,
@@ -338,6 +436,7 @@ static const struct irq_domain_ops stm32_gpio_domain_ops = {
        .alloc          = stm32_gpio_domain_alloc,
        .free           = irq_domain_free_irqs_common,
        .activate       = stm32_gpio_domain_activate,
+       .deactivate     = stm32_gpio_domain_deactivate,
 };
 
 /* Pinctrl functions */
@@ -620,6 +719,8 @@ static int stm32_pmx_set_mode(struct stm32_gpio_bank *bank,
        if (pctl->hwlock)
                hwspin_unlock(pctl->hwlock);
 
+       stm32_gpio_backup_mode(bank, pin, mode, alt);
+
 unlock:
        spin_unlock_irqrestore(&bank->lock, flags);
        clk_disable(bank->clk);
@@ -732,6 +833,8 @@ static int stm32_pconf_set_driving(struct stm32_gpio_bank *bank,
        if (pctl->hwlock)
                hwspin_unlock(pctl->hwlock);
 
+       stm32_gpio_backup_driving(bank, offset, drive);
+
 unlock:
        spin_unlock_irqrestore(&bank->lock, flags);
        clk_disable(bank->clk);
@@ -784,6 +887,8 @@ static int stm32_pconf_set_speed(struct stm32_gpio_bank *bank,
        if (pctl->hwlock)
                hwspin_unlock(pctl->hwlock);
 
+       stm32_gpio_backup_speed(bank, offset, speed);
+
 unlock:
        spin_unlock_irqrestore(&bank->lock, flags);
        clk_disable(bank->clk);
@@ -836,6 +941,8 @@ static int stm32_pconf_set_bias(struct stm32_gpio_bank *bank,
        if (pctl->hwlock)
                hwspin_unlock(pctl->hwlock);
 
+       stm32_gpio_backup_bias(bank, offset, bias);
+
 unlock:
        spin_unlock_irqrestore(&bank->lock, flags);
        clk_disable(bank->clk);
@@ -1290,6 +1397,8 @@ int stm32_pctl_probe(struct platform_device *pdev)
                pctl->hwlock = hwspin_lock_request_specific(hwlock_id);
        }
 
+       spin_lock_init(&pctl->irqmux_lock);
+
        pctl->dev = dev;
        pctl->match_data = match->data;
 
@@ -1329,6 +1438,7 @@ int stm32_pctl_probe(struct platform_device *pdev)
        pctl->pctl_desc.owner = THIS_MODULE;
        pctl->pctl_desc.pins = pins;
        pctl->pctl_desc.npins = pctl->npins;
+       pctl->pctl_desc.link_consumers = true;
        pctl->pctl_desc.confops = &stm32_pconf_ops;
        pctl->pctl_desc.pctlops = &stm32_pctrl_ops;
        pctl->pctl_desc.pmxops = &stm32_pmx_ops;
@@ -1369,3 +1479,75 @@ int stm32_pctl_probe(struct platform_device *pdev)
 
        return 0;
 }
+
+static int __maybe_unused stm32_pinctrl_restore_gpio_regs(
+                                       struct stm32_pinctrl *pctl, u32 pin)
+{
+       const struct pin_desc *desc = pin_desc_get(pctl->pctl_dev, pin);
+       u32 val, alt, mode, offset = stm32_gpio_pin(pin);
+       struct pinctrl_gpio_range *range;
+       struct stm32_gpio_bank *bank;
+       bool pin_is_irq;
+       int ret;
+
+       range = pinctrl_find_gpio_range_from_pin(pctl->pctl_dev, pin);
+       if (!range)
+               return 0;
+
+       pin_is_irq = gpiochip_line_is_irq(range->gc, offset);
+
+       if (!desc || (!pin_is_irq && !desc->gpio_owner))
+               return 0;
+
+       bank = gpiochip_get_data(range->gc);
+
+       alt = bank->pin_backup[offset] & STM32_GPIO_BKP_ALT_MASK;
+       alt >>= STM32_GPIO_BKP_ALT_SHIFT;
+       mode = bank->pin_backup[offset] & STM32_GPIO_BKP_MODE_MASK;
+       mode >>= STM32_GPIO_BKP_MODE_SHIFT;
+
+       ret = stm32_pmx_set_mode(bank, offset, mode, alt);
+       if (ret)
+               return ret;
+
+       if (mode == 1) {
+               val = bank->pin_backup[offset] & BIT(STM32_GPIO_BKP_VAL);
+               val = val >> STM32_GPIO_BKP_VAL;
+               __stm32_gpio_set(bank, offset, val);
+       }
+
+       val = bank->pin_backup[offset] & BIT(STM32_GPIO_BKP_TYPE);
+       val >>= STM32_GPIO_BKP_TYPE;
+       ret = stm32_pconf_set_driving(bank, offset, val);
+       if (ret)
+               return ret;
+
+       val = bank->pin_backup[offset] & STM32_GPIO_BKP_SPEED_MASK;
+       val >>= STM32_GPIO_BKP_SPEED_SHIFT;
+       ret = stm32_pconf_set_speed(bank, offset, val);
+       if (ret)
+               return ret;
+
+       val = bank->pin_backup[offset] & STM32_GPIO_BKP_PUPD_MASK;
+       val >>= STM32_GPIO_BKP_PUPD_SHIFT;
+       ret = stm32_pconf_set_bias(bank, offset, val);
+       if (ret)
+               return ret;
+
+       if (pin_is_irq)
+               regmap_field_write(pctl->irqmux[offset], bank->bank_ioport_nr);
+
+       return 0;
+}
+
+int __maybe_unused stm32_pinctrl_resume(struct device *dev)
+{
+       struct stm32_pinctrl *pctl = dev_get_drvdata(dev);
+       struct stm32_pinctrl_group *g = pctl->groups;
+       int i;
+
+       for (i = g->pin; i < g->pin + pctl->ngroups; i++)
+               stm32_pinctrl_restore_gpio_regs(pctl, i);
+
+       return 0;
+}
index de5e701..ec0d34c 100644 (file)
@@ -65,5 +65,7 @@ struct stm32_gpio_bank;
 int stm32_pctl_probe(struct platform_device *pdev);
 void stm32_pmx_get_mode(struct stm32_gpio_bank *bank,
                        int pin, u32 *mode, u32 *alt);
+int stm32_pinctrl_resume(struct device *dev);
+
 #endif /* __PINCTRL_STM32_H */
 
index 320544f..2ccb99d 100644 (file)
@@ -2342,11 +2342,16 @@ static const struct of_device_id stm32mp157_pctrl_match[] = {
        { }
 };
 
+static const struct dev_pm_ops stm32_pinctrl_dev_pm_ops = {
+        SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, stm32_pinctrl_resume)
+};
+
 static struct platform_driver stm32mp157_pinctrl_driver = {
        .probe = stm32_pctl_probe,
        .driver = {
                .name = "stm32mp157-pinctrl",
                .of_match_table = stm32mp157_pctrl_match,
+               .pm = &stm32_pinctrl_dev_pm_ops,
        },
 };
 
index 5906a85..a67d0d9 100644 (file)
@@ -24,6 +24,10 @@ config PINCTRL_TEGRA210
        bool
        select PINCTRL_TEGRA
 
+config PINCTRL_TEGRA194
+       bool
+       select PINCTRL_TEGRA
+
 config PINCTRL_TEGRA_XUSB
        def_bool y if ARCH_TEGRA
        select GENERIC_PHY
index bbcb043..ead4e10 100644 (file)
@@ -5,4 +5,5 @@ obj-$(CONFIG_PINCTRL_TEGRA30)           += pinctrl-tegra30.o
 obj-$(CONFIG_PINCTRL_TEGRA114)         += pinctrl-tegra114.o
 obj-$(CONFIG_PINCTRL_TEGRA124)         += pinctrl-tegra124.o
 obj-$(CONFIG_PINCTRL_TEGRA210)         += pinctrl-tegra210.o
+obj-$(CONFIG_PINCTRL_TEGRA194)         += pinctrl-tegra194.o
 obj-$(CONFIG_PINCTRL_TEGRA_XUSB)       += pinctrl-tegra-xusb.o
index abcfbad..186ef98 100644 (file)
@@ -284,7 +284,7 @@ static int tegra_pinconf_reg(struct tegra_pmx *pmx,
                             const struct tegra_pingroup *g,
                             enum tegra_pinconf_param param,
                             bool report_err,
-                            s8 *bank, s16 *reg, s8 *bit, s8 *width)
+                            s8 *bank, s32 *reg, s8 *bit, s8 *width)
 {
        switch (param) {
        case TEGRA_PINCONF_PARAM_PULL:
@@ -443,7 +443,7 @@ static int tegra_pinconf_group_get(struct pinctrl_dev *pctldev,
        const struct tegra_pingroup *g;
        int ret;
        s8 bank, bit, width;
-       s16 reg;
+       s32 reg;
        u32 val, mask;
 
        g = &pmx->soc->groups[group];
@@ -472,7 +472,7 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
        const struct tegra_pingroup *g;
        int ret, i;
        s8 bank, bit, width;
-       s16 reg;
+       s32 reg;
        u32 val, mask;
 
        g = &pmx->soc->groups[group];
@@ -540,7 +540,7 @@ static void tegra_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
        const struct tegra_pingroup *g;
        int i, ret;
        s8 bank, bit, width;
-       s16 reg;
+       s32 reg;
        u32 val;
 
        g = &pmx->soc->groups[group];
@@ -613,10 +613,20 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
 
        for (i = 0; i < pmx->soc->ngroups; ++i) {
                g = &pmx->soc->groups[i];
-               if (g->parked_bit >= 0) {
-                       val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
-                       val &= ~(1 << g->parked_bit);
-                       pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
+               if (g->parked_bitmask > 0) {
+                       unsigned int bank, reg;
+
+                       if (g->mux_reg != -1) {
+                               bank = g->mux_bank;
+                               reg = g->mux_reg;
+                       } else {
+                               bank = g->drv_bank;
+                               reg = g->drv_reg;
+                       }
+
+                       val = pmx_readl(pmx, bank, reg);
+                       val &= ~g->parked_bitmask;
+                       pmx_writel(pmx, val, bank, reg);
                }
        }
 }
index 9b5a716..1053097 100644 (file)
@@ -96,7 +96,6 @@ struct tegra_function {
  * @tri_reg:           Tri-state register offset.
  * @tri_bank:          Tri-state register bank.
  * @tri_bit:           Tri-state register bit.
- * @parked_bit:                Parked register bit. -1 if unsupported.
  * @einput_bit:                Enable-input register bit.
  * @odrain_bit:                Open-drain register bit.
  * @lock_bit:          Lock register bit.
@@ -118,6 +117,7 @@ struct tegra_function {
  * @slwf_bit:          Slew Falling register bit.
  * @slwf_width:                Slew Falling field width.
  * @drvtype_bit:       Drive type register bit.
+ * @parked_bitmask:    Parked register mask. 0 if unsupported.
  *
  * -1 in a *_reg field means that feature is unsupported for this group.
  * *_bank and *_reg values are irrelevant when *_reg is -1.
@@ -135,10 +135,10 @@ struct tegra_pingroup {
        const unsigned *pins;
        u8 npins;
        u8 funcs[4];
-       s16 mux_reg;
-       s16 pupd_reg;
-       s16 tri_reg;
-       s16 drv_reg;
+       s32 mux_reg;
+       s32 pupd_reg;
+       s32 tri_reg;
+       s32 drv_reg;
        u32 mux_bank:2;
        u32 pupd_bank:2;
        u32 tri_bank:2;
@@ -146,7 +146,6 @@ struct tegra_pingroup {
        s32 mux_bit:6;
        s32 pupd_bit:6;
        s32 tri_bit:6;
-       s32 parked_bit:6;
        s32 einput_bit:6;
        s32 odrain_bit:6;
        s32 lock_bit:6;
@@ -164,6 +163,7 @@ struct tegra_pingroup {
        s32 drvup_width:6;
        s32 slwr_width:6;
        s32 slwf_width:6;
+       u32 parked_bitmask;
 };
 
 /**
index 762151f..e72ab1e 100644 (file)
@@ -1572,8 +1572,8 @@ static struct tegra_function tegra114_functions[] = {
                .lock_bit = 7,                                          \
                .ioreset_bit = PINGROUP_BIT_##ior(8),                   \
                .rcv_sel_bit = PINGROUP_BIT_##rcv_sel(9),               \
-               .parked_bit = -1,                                       \
                .drv_reg = -1,                                          \
+               .parked_bitmask = 0,                                    \
        }
 
 #define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b, drvdn_b,    \
@@ -1593,7 +1593,6 @@ static struct tegra_function tegra114_functions[] = {
                .rcv_sel_bit = -1,                                      \
                .drv_reg = DRV_PINGROUP_REG(r),                         \
                .drv_bank = 0,                                          \
-               .parked_bit = -1,                                       \
                .hsm_bit = hsm_b,                                       \
                .schmitt_bit = schmitt_b,                               \
                .lpmd_bit = lpmd_b,                                     \
@@ -1606,6 +1605,7 @@ static struct tegra_function tegra114_functions[] = {
                .slwf_bit = slwf_b,                                     \
                .slwf_width = slwf_w,                                   \
                .drvtype_bit = PINGROUP_BIT_##drvtype(6),               \
+               .parked_bitmask = 0,                                    \
        }
 
 static const struct tegra_pingroup tegra114_groups[] = {
@@ -1831,7 +1831,7 @@ static const struct tegra_pingroup tegra114_groups[] = {
 
 static const struct tegra_pinctrl_soc_data tegra114_pinctrl = {
        .ngpios = NUM_GPIOS,
-       .gpio_compatible = "nvidia,tegra30-gpio",
+       .gpio_compatible = "nvidia,tegra114-gpio",
        .pins = tegra114_pins,
        .npins = ARRAY_SIZE(tegra114_pins),
        .functions = tegra114_functions,
index 930c437..26096c6 100644 (file)
@@ -1741,8 +1741,8 @@ static struct tegra_function tegra124_functions[] = {
                .lock_bit = 7,                                          \
                .ioreset_bit = PINGROUP_BIT_##ior(8),                   \
                .rcv_sel_bit = PINGROUP_BIT_##rcv_sel(9),               \
-               .parked_bit = -1,                                       \
                .drv_reg = -1,                                          \
+               .parked_bitmask = 0,                                    \
        }
 
 #define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b, drvdn_b,    \
@@ -1762,7 +1762,6 @@ static struct tegra_function tegra124_functions[] = {
                .rcv_sel_bit = -1,                                      \
                .drv_reg = DRV_PINGROUP_REG(r),                         \
                .drv_bank = 0,                                          \
-               .parked_bit = -1,                                       \
                .hsm_bit = hsm_b,                                       \
                .schmitt_bit = schmitt_b,                               \
                .lpmd_bit = lpmd_b,                                     \
@@ -1775,6 +1774,7 @@ static struct tegra_function tegra124_functions[] = {
                .slwf_bit = slwf_b,                                     \
                .slwf_width = slwf_w,                                   \
                .drvtype_bit = PINGROUP_BIT_##drvtype(6),               \
+               .parked_bitmask = 0,                                    \
        }
 
 #define MIPI_PAD_CTRL_PINGROUP(pg_name, r, b, f0, f1)                  \
@@ -2043,7 +2043,7 @@ static const struct tegra_pingroup tegra124_groups[] = {
 
 static const struct tegra_pinctrl_soc_data tegra124_pinctrl = {
        .ngpios = NUM_GPIOS,
-       .gpio_compatible = "nvidia,tegra30-gpio",
+       .gpio_compatible = "nvidia,tegra124-gpio",
        .pins = tegra124_pins,
        .npins = ARRAY_SIZE(tegra124_pins),
        .functions = tegra124_functions,
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra194.c b/drivers/pinctrl/tegra/pinctrl-tegra194.c
new file mode 100644 (file)
index 0000000..daf44cf
--- /dev/null
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Pinctrl data for the NVIDIA Tegra194 pinmux
+ *
+ * Copyright (c) 2019, 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/init.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "pinctrl-tegra.h"
+
+/* Define unique ID for each pins */
+enum pin_id {
+       TEGRA_PIN_PEX_L5_CLKREQ_N_PGG0 = 256,
+       TEGRA_PIN_PEX_L5_RST_N_PGG1 = 257,
+       TEGRA_PIN_NUM_GPIOS = 258,
+};
+
+/* Table for pin descriptor */
+static const struct pinctrl_pin_desc tegra194_pins[] = {
+       PINCTRL_PIN(TEGRA_PIN_PEX_L5_CLKREQ_N_PGG0,
+                   "TEGRA_PIN_PEX_L5_CLKREQ_N_PGG0"),
+       PINCTRL_PIN(TEGRA_PIN_PEX_L5_RST_N_PGG1,
+                   "TEGRA_PIN_PEX_L5_RST_N_PGG1"),
+};
+
+static const unsigned int pex_l5_clkreq_n_pgg0_pins[] = {
+       TEGRA_PIN_PEX_L5_CLKREQ_N_PGG0,
+};
+
+static const unsigned int pex_l5_rst_n_pgg1_pins[] = {
+       TEGRA_PIN_PEX_L5_RST_N_PGG1,
+};
+
+/* Define unique ID for each function */
+enum tegra_mux_dt {
+       TEGRA_MUX_RSVD0,
+       TEGRA_MUX_RSVD1,
+       TEGRA_MUX_RSVD2,
+       TEGRA_MUX_RSVD3,
+       TEGRA_MUX_PE5,
+};
+
+/* Make list of each function name */
+#define TEGRA_PIN_FUNCTION(lid)                        \
+       {                                       \
+               .name = #lid,                   \
+       }
+static struct tegra_function tegra194_functions[] = {
+       TEGRA_PIN_FUNCTION(rsvd0),
+       TEGRA_PIN_FUNCTION(rsvd1),
+       TEGRA_PIN_FUNCTION(rsvd2),
+       TEGRA_PIN_FUNCTION(rsvd3),
+       TEGRA_PIN_FUNCTION(pe5),
+};
+
+#define DRV_PINGROUP_ENTRY_Y(r, drvdn_b, drvdn_w, drvup_b,     \
+                            drvup_w, slwr_b, slwr_w, slwf_b,   \
+                            slwf_w, bank)                      \
+               .drv_reg = ((r)),                       \
+               .drv_bank = bank,                               \
+               .drvdn_bit = drvdn_b,                           \
+               .drvdn_width = drvdn_w,                         \
+               .drvup_bit = drvup_b,                           \
+               .drvup_width = drvup_w,                         \
+               .slwr_bit = slwr_b,                             \
+               .slwr_width = slwr_w,                           \
+               .slwf_bit = slwf_b,                             \
+               .slwf_width = slwf_w
+
+#define PIN_PINGROUP_ENTRY_Y(r, bank, pupd, e_lpbk, e_input,   \
+                            e_od, schmitt_b, drvtype)          \
+               .mux_reg = ((r)),                               \
+               .lpmd_bit = -1,                                 \
+               .lock_bit = -1,                                 \
+               .hsm_bit = -1,                                  \
+               .mux_bank = bank,                               \
+               .mux_bit = 0,                                   \
+               .pupd_reg = ((r)),              \
+               .pupd_bank = bank,                              \
+               .pupd_bit = 2,                                  \
+               .tri_reg = ((r)),                               \
+               .tri_bank = bank,                               \
+               .tri_bit = 4,                                   \
+               .einput_bit = e_input,                          \
+               .odrain_bit = e_od,                             \
+               .schmitt_bit = schmitt_b,                       \
+               .drvtype_bit = 13,                              \
+               .drv_reg = -1,                                  \
+               .parked_bitmask = 0
+
+#define drive_pex_l5_clkreq_n_pgg0                             \
+       DRV_PINGROUP_ENTRY_Y(0x14004, 12, 5, 20, 5, -1, -1, -1, -1, 0)
+#define drive_pex_l5_rst_n_pgg1                                        \
+       DRV_PINGROUP_ENTRY_Y(0x1400c, 12, 5, 20, 5, -1, -1, -1, -1, 0)
+
+#define PINGROUP(pg_name, f0, f1, f2, f3, r, bank, pupd, e_lpbk,       \
+                e_input, e_lpdr, e_od, schmitt_b, drvtype, io_rail)    \
+       {                                                       \
+               .name = #pg_name,                               \
+               .pins = pg_name##_pins,                         \
+               .npins = ARRAY_SIZE(pg_name##_pins),            \
+                       .funcs = {                              \
+                               TEGRA_MUX_##f0,                 \
+                               TEGRA_MUX_##f1,                 \
+                               TEGRA_MUX_##f2,                 \
+                               TEGRA_MUX_##f3,                 \
+                       },                                      \
+               PIN_PINGROUP_ENTRY_Y(r, bank, pupd, e_lpbk,     \
+                                    e_input, e_od,             \
+                                    schmitt_b, drvtype),       \
+               drive_##pg_name,                                \
+       }
+
+static const struct tegra_pingroup tegra194_groups[] = {
+       PINGROUP(pex_l5_clkreq_n_pgg0, PE5, RSVD1, RSVD2, RSVD3, 0x14000, 0,
+                Y, -1, 6, 8, 11, 12, N, "vddio_pex_ctl_2"),
+       PINGROUP(pex_l5_rst_n_pgg1, PE5, RSVD1, RSVD2, RSVD3, 0x14008, 0,
+                Y, -1, 6, 8, 11, 12, N, "vddio_pex_ctl_2"),
+};
+
+static const struct tegra_pinctrl_soc_data tegra194_pinctrl = {
+       .ngpios = TEGRA_PIN_NUM_GPIOS,
+       .pins = tegra194_pins,
+       .npins = ARRAY_SIZE(tegra194_pins),
+       .functions = tegra194_functions,
+       .nfunctions = ARRAY_SIZE(tegra194_functions),
+       .groups = tegra194_groups,
+       .ngroups = ARRAY_SIZE(tegra194_groups),
+       .hsm_in_mux = true,
+       .schmitt_in_mux = true,
+       .drvtype_in_mux = true,
+};
+
+static int tegra194_pinctrl_probe(struct platform_device *pdev)
+{
+       return tegra_pinctrl_probe(pdev, &tegra194_pinctrl);
+}
+
+static const struct of_device_id tegra194_pinctrl_of_match[] = {
+       { .compatible = "nvidia,tegra194-pinmux", },
+       { },
+};
+
+static struct platform_driver tegra194_pinctrl_driver = {
+       .driver = {
+               .name = "tegra194-pinctrl",
+               .of_match_table = tegra194_pinctrl_of_match,
+       },
+       .probe = tegra194_pinctrl_probe,
+};
+
+static int __init tegra194_pinctrl_init(void)
+{
+       return platform_driver_register(&tegra194_pinctrl_driver);
+}
+arch_initcall(tegra194_pinctrl_init);
index 4b7837e..0dc2cf0 100644 (file)
@@ -1989,13 +1989,13 @@ static struct tegra_function tegra20_functions[] = {
                .tri_reg = ((tri_r) - TRISTATE_REG_A),          \
                .tri_bank = 0,                                  \
                .tri_bit = tri_b,                               \
-               .parked_bit = -1,                               \
                .einput_bit = -1,                               \
                .odrain_bit = -1,                               \
                .lock_bit = -1,                                 \
                .ioreset_bit = -1,                              \
                .rcv_sel_bit = -1,                              \
                .drv_reg = -1,                                  \
+               .parked_bitmask = 0,                            \
        }
 
 /* Pin groups with only pull up and pull down control */
@@ -2009,7 +2009,7 @@ static struct tegra_function tegra20_functions[] = {
                .pupd_bank = 2,                                 \
                .pupd_bit = pupd_b,                             \
                .drv_reg = -1,                                  \
-               .parked_bit = -1,                               \
+               .parked_bitmask = 0,                            \
        }
 
 /* Pin groups for drive strength registers (configurable version) */
@@ -2025,7 +2025,7 @@ static struct tegra_function tegra20_functions[] = {
                .tri_reg = -1,                                  \
                .drv_reg = ((r) - PINGROUP_REG_A),              \
                .drv_bank = 3,                                  \
-               .parked_bit = -1,                               \
+               .parked_bitmask = 0,                            \
                .hsm_bit = hsm_b,                               \
                .schmitt_bit = schmitt_b,                       \
                .lpmd_bit = lpmd_b,                             \
index 0b56ad5..39ab648 100644 (file)
@@ -1302,7 +1302,6 @@ static struct tegra_function tegra210_functions[] = {
                .lock_bit = 7,                                          \
                .ioreset_bit = -1,                                      \
                .rcv_sel_bit = PINGROUP_BIT_##e_io_hv(10),              \
-               .parked_bit = 5,                                        \
                .hsm_bit = PINGROUP_BIT_##hsm(9),                       \
                .schmitt_bit = 12,                                      \
                .drvtype_bit = PINGROUP_BIT_##drvtype(13),              \
@@ -1317,10 +1316,11 @@ static struct tegra_function tegra210_functions[] = {
                .slwr_width = slwr_w,                                   \
                .slwf_bit = slwf_b,                                     \
                .slwf_width = slwf_w,                                   \
+               .parked_bitmask = BIT(5),                               \
        }
 
-#define DRV_PINGROUP(pg_name, r, drvdn_b, drvdn_w, drvup_b, drvup_w,   \
-                    slwr_b, slwr_w, slwf_b, slwf_w)                    \
+#define DRV_PINGROUP(pg_name, r, prk_mask, drvdn_b, drvdn_w, drvup_b,  \
+                    drvup_w, slwr_b, slwr_w, slwf_b, slwf_w)           \
        {                                                               \
                .name = "drive_" #pg_name,                              \
                .pins = drive_##pg_name##_pins,                         \
@@ -1335,7 +1335,6 @@ static struct tegra_function tegra210_functions[] = {
                .rcv_sel_bit = -1,                                      \
                .drv_reg = DRV_PINGROUP_REG(r),                         \
                .drv_bank = 0,                                          \
-               .parked_bit = -1,                                       \
                .hsm_bit = -1,                                          \
                .schmitt_bit = -1,                                      \
                .lpmd_bit = -1,                                         \
@@ -1348,6 +1347,7 @@ static struct tegra_function tegra210_functions[] = {
                .slwf_bit = slwf_b,                                     \
                .slwf_width = slwf_w,                                   \
                .drvtype_bit = -1,                                      \
+               .parked_bitmask = prk_mask,                             \
        }
 
 static const struct tegra_pingroup tegra210_groups[] = {
@@ -1515,37 +1515,37 @@ static const struct tegra_pingroup tegra210_groups[] = {
        PINGROUP(pz4,                  SDMMC1,     RSVD1,  RSVD2, RSVD3, 0x328c, N,   N,       N,       -1,    -1,      -1,      -1,      -1,      -1,     -1,     -1,     -1),
        PINGROUP(pz5,                  SOC,        RSVD1,  RSVD2, RSVD3, 0x3290, N,   N,       N,       -1,    -1,      -1,      -1,      -1,      -1,     -1,     -1,     -1),
 
-       /* pg_name, r, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w */
-       DRV_PINGROUP(pa6,    0x9c0, 12, 5,  20, 5,  -1, -1, -1, -1),
-       DRV_PINGROUP(pcc7,   0x9c4, 12, 5,  20, 5,  -1, -1, -1, -1),
-       DRV_PINGROUP(pe6,    0x9c8, 12, 5,  20, 5,  -1, -1, -1, -1),
-       DRV_PINGROUP(pe7,    0x9cc, 12, 5,  20, 5,  -1, -1, -1, -1),
-       DRV_PINGROUP(ph6,    0x9d0, 12, 5,  20, 5,  -1, -1, -1, -1),
-       DRV_PINGROUP(pk0,    0x9d4, -1, -1, -1, -1, 28, 2,  30, 2),
-       DRV_PINGROUP(pk1,    0x9d8, -1, -1, -1, -1, 28, 2,  30, 2),
-       DRV_PINGROUP(pk2,    0x9dc, -1, -1, -1, -1, 28, 2,  30, 2),
-       DRV_PINGROUP(pk3,    0x9e0, -1, -1, -1, -1, 28, 2,  30, 2),
-       DRV_PINGROUP(pk4,    0x9e4, -1, -1, -1, -1, 28, 2,  30, 2),
-       DRV_PINGROUP(pk5,    0x9e8, -1, -1, -1, -1, 28, 2,  30, 2),
-       DRV_PINGROUP(pk6,    0x9ec, -1, -1, -1, -1, 28, 2,  30, 2),
-       DRV_PINGROUP(pk7,    0x9f0, -1, -1, -1, -1, 28, 2,  30, 2),
-       DRV_PINGROUP(pl0,    0x9f4, -1, -1, -1, -1, 28, 2,  30, 2),
-       DRV_PINGROUP(pl1,    0x9f8, -1, -1, -1, -1, 28, 2,  30, 2),
-       DRV_PINGROUP(pz0,    0x9fc, 12, 7,  20, 7,  -1, -1, -1, -1),
-       DRV_PINGROUP(pz1,    0xa00, 12, 7,  20, 7,  -1, -1, -1, -1),
-       DRV_PINGROUP(pz2,    0xa04, 12, 7,  20, 7,  -1, -1, -1, -1),
-       DRV_PINGROUP(pz3,    0xa08, 12, 7,  20, 7,  -1, -1, -1, -1),
-       DRV_PINGROUP(pz4,    0xa0c, 12, 7,  20, 7,  -1, -1, -1, -1),
-       DRV_PINGROUP(pz5,    0xa10, 12, 7,  20, 7,  -1, -1, -1, -1),
-       DRV_PINGROUP(sdmmc1, 0xa98, 12, 7,  20, 7,  28, 2,  30, 2),
-       DRV_PINGROUP(sdmmc2, 0xa9c, 2,  6,  8,  6,  28, 2,  30, 2),
-       DRV_PINGROUP(sdmmc3, 0xab0, 12, 7,  20, 7,  28, 2,  30, 2),
-       DRV_PINGROUP(sdmmc4, 0xab4, 2,  6,  8,  6,  28, 2,  30, 2),
+       /* pg_name, r, prk_mask, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w */
+       DRV_PINGROUP(pa6,    0x9c0, 0x0,       12, 5,  20, 5,  -1, -1, -1, -1),
+       DRV_PINGROUP(pcc7,   0x9c4, 0x0,       12, 5,  20, 5,  -1, -1, -1, -1),
+       DRV_PINGROUP(pe6,    0x9c8, 0x0,       12, 5,  20, 5,  -1, -1, -1, -1),
+       DRV_PINGROUP(pe7,    0x9cc, 0x0,       12, 5,  20, 5,  -1, -1, -1, -1),
+       DRV_PINGROUP(ph6,    0x9d0, 0x0,       12, 5,  20, 5,  -1, -1, -1, -1),
+       DRV_PINGROUP(pk0,    0x9d4, 0x0,       -1, -1, -1, -1, 28, 2,  30, 2),
+       DRV_PINGROUP(pk1,    0x9d8, 0x0,       -1, -1, -1, -1, 28, 2,  30, 2),
+       DRV_PINGROUP(pk2,    0x9dc, 0x0,       -1, -1, -1, -1, 28, 2,  30, 2),
+       DRV_PINGROUP(pk3,    0x9e0, 0x0,       -1, -1, -1, -1, 28, 2,  30, 2),
+       DRV_PINGROUP(pk4,    0x9e4, 0x0,       -1, -1, -1, -1, 28, 2,  30, 2),
+       DRV_PINGROUP(pk5,    0x9e8, 0x0,       -1, -1, -1, -1, 28, 2,  30, 2),
+       DRV_PINGROUP(pk6,    0x9ec, 0x0,       -1, -1, -1, -1, 28, 2,  30, 2),
+       DRV_PINGROUP(pk7,    0x9f0, 0x0,       -1, -1, -1, -1, 28, 2,  30, 2),
+       DRV_PINGROUP(pl0,    0x9f4, 0x0,       -1, -1, -1, -1, 28, 2,  30, 2),
+       DRV_PINGROUP(pl1,    0x9f8, 0x0,       -1, -1, -1, -1, 28, 2,  30, 2),
+       DRV_PINGROUP(pz0,    0x9fc, 0x0,       12, 7,  20, 7,  -1, -1, -1, -1),
+       DRV_PINGROUP(pz1,    0xa00, 0x0,       12, 7,  20, 7,  -1, -1, -1, -1),
+       DRV_PINGROUP(pz2,    0xa04, 0x0,       12, 7,  20, 7,  -1, -1, -1, -1),
+       DRV_PINGROUP(pz3,    0xa08, 0x0,       12, 7,  20, 7,  -1, -1, -1, -1),
+       DRV_PINGROUP(pz4,    0xa0c, 0x0,       12, 7,  20, 7,  -1, -1, -1, -1),
+       DRV_PINGROUP(pz5,    0xa10, 0x0,       12, 7,  20, 7,  -1, -1, -1, -1),
+       DRV_PINGROUP(sdmmc1, 0xa98, 0x0,       12, 7,  20, 7,  28, 2,  30, 2),
+       DRV_PINGROUP(sdmmc2, 0xa9c, 0x7ffc000, 2,  6,  8,  6,  28, 2,  30, 2),
+       DRV_PINGROUP(sdmmc3, 0xab0, 0x0,       12, 7,  20, 7,  28, 2,  30, 2),
+       DRV_PINGROUP(sdmmc4, 0xab4, 0x7ffc000, 2,  6,  8,  6,  28, 2,  30, 2),
 };
 
 static const struct tegra_pinctrl_soc_data tegra210_pinctrl = {
        .ngpios = NUM_GPIOS,
-       .gpio_compatible = "nvidia,tegra30-gpio",
+       .gpio_compatible = "nvidia,tegra210-gpio",
        .pins = tegra210_pins,
        .npins = ARRAY_SIZE(tegra210_pins),
        .functions = tegra210_functions,
index 610124c..7299a37 100644 (file)
@@ -2133,8 +2133,8 @@ static struct tegra_function tegra30_functions[] = {
                .lock_bit = 7,                                          \
                .ioreset_bit = PINGROUP_BIT_##ior(8),                   \
                .rcv_sel_bit = -1,                                      \
-               .parked_bit = -1,                                       \
                .drv_reg = -1,                                          \
+               .parked_bitmask = 0,                                    \
        }
 
 #define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b, drvdn_b,    \
@@ -2154,7 +2154,6 @@ static struct tegra_function tegra30_functions[] = {
                .rcv_sel_bit = -1,                                      \
                .drv_reg = DRV_PINGROUP_REG(r),                         \
                .drv_bank = 0,                                          \
-               .parked_bit = -1,                                       \
                .hsm_bit = hsm_b,                                       \
                .schmitt_bit = schmitt_b,                               \
                .lpmd_bit = lpmd_b,                                     \
@@ -2167,6 +2166,7 @@ static struct tegra_function tegra30_functions[] = {
                .slwf_bit = slwf_b,                                     \
                .slwf_width = slwf_w,                                   \
                .drvtype_bit = -1,                                      \
+               .parked_bitmask = 0,                                    \
        }
 
 static const struct tegra_pingroup tegra30_groups[] = {
index 2826f71..970679d 100644 (file)
@@ -72,6 +72,19 @@ config CROS_EC_RPMSG
          To compile this driver as a module, choose M here: the
          module will be called cros_ec_rpmsg.
 
+config CROS_EC_ISHTP
+       tristate "ChromeOS Embedded Controller (ISHTP)"
+       depends on MFD_CROS_EC
+       depends on INTEL_ISH_HID
+       help
+         If you say Y here, you get support for talking to the ChromeOS EC
+         firmware running on Intel Integrated Sensor Hub (ISH), using the
+         ISH Transport protocol (ISH-TP). This uses a simple byte-level
+         protocol with a checksum.
+
+         To compile this driver as a module, choose M here: the
+         module will be called cros_ec_ishtp.
+
 config CROS_EC_SPI
        tristate "ChromeOS Embedded Controller (SPI)"
        depends on MFD_CROS_EC && SPI
@@ -83,28 +96,17 @@ config CROS_EC_SPI
          'pre-amble' bytes before the response actually starts.
 
 config CROS_EC_LPC
-        tristate "ChromeOS Embedded Controller (LPC)"
-        depends on MFD_CROS_EC && ACPI && (X86 || COMPILE_TEST)
-        help
-          If you say Y here, you get support for talking to the ChromeOS EC
-          over an LPC bus. This uses a simple byte-level protocol with a
-          checksum. This is used for userspace access only. The kernel
-          typically has its own communication methods.
-
-          To compile this driver as a module, choose M here: the
-          module will be called cros_ec_lpc.
-
-config CROS_EC_LPC_MEC
-       bool "ChromeOS Embedded Controller LPC Microchip EC (MEC) variant"
-       depends on CROS_EC_LPC
-       default n
+       tristate "ChromeOS Embedded Controller (LPC)"
+       depends on MFD_CROS_EC && ACPI && (X86 || COMPILE_TEST)
        help
-         If you say Y here, a variant LPC protocol for the Microchip EC
-         will be used. Note that this variant is not backward compatible
-         with non-Microchip ECs.
+         If you say Y here, you get support for talking to the ChromeOS EC
+         over an LPC bus, including the LPC Microchip EC (MEC) variant.
+         This uses a simple byte-level protocol with a checksum. This is
+         used for userspace access only. The kernel typically has its own
+         communication methods.
 
-         If you have a ChromeOS Embedded Controller Microchip EC variant
-         choose Y here.
+         To compile this driver as a module, choose M here: the
+         module will be called cros_ec_lpcs.
 
 config CROS_EC_PROTO
         bool
index 1b2f1dc..fd0af05 100644 (file)
@@ -7,10 +7,10 @@ obj-$(CONFIG_CHROMEOS_LAPTOP)         += chromeos_laptop.o
 obj-$(CONFIG_CHROMEOS_PSTORE)          += chromeos_pstore.o
 obj-$(CONFIG_CHROMEOS_TBMC)            += chromeos_tbmc.o
 obj-$(CONFIG_CROS_EC_I2C)              += cros_ec_i2c.o
+obj-$(CONFIG_CROS_EC_ISHTP)            += cros_ec_ishtp.o
 obj-$(CONFIG_CROS_EC_RPMSG)            += cros_ec_rpmsg.o
 obj-$(CONFIG_CROS_EC_SPI)              += cros_ec_spi.o
-cros_ec_lpcs-objs                      := cros_ec_lpc.o cros_ec_lpc_reg.o
-cros_ec_lpcs-$(CONFIG_CROS_EC_LPC_MEC) += cros_ec_lpc_mec.o
+cros_ec_lpcs-objs                      := cros_ec_lpc.o cros_ec_lpc_mec.o
 obj-$(CONFIG_CROS_EC_LPC)              += cros_ec_lpcs.o
 obj-$(CONFIG_CROS_EC_PROTO)            += cros_ec_proto.o cros_ec_trace.o
 obj-$(CONFIG_CROS_KBD_LED_BACKLIGHT)   += cros_kbd_led_backlight.o
index 4c2a27f..8ec1cc2 100644 (file)
@@ -25,7 +25,8 @@
 
 #define CIRC_ADD(idx, size, value)     (((idx) + (value)) & ((size) - 1))
 
-/* struct cros_ec_debugfs - ChromeOS EC debugging information
+/**
+ * struct cros_ec_debugfs - EC debugging information.
  *
  * @ec: EC device this debugfs information belongs to
  * @dir: dentry for debugfs files
@@ -241,7 +242,35 @@ static ssize_t cros_ec_pdinfo_read(struct file *file,
                                       read_buf, p - read_buf);
 }
 
-const struct file_operations cros_ec_console_log_fops = {
+static ssize_t cros_ec_uptime_read(struct file *file, char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct cros_ec_debugfs *debug_info = file->private_data;
+       struct cros_ec_device *ec_dev = debug_info->ec->ec_dev;
+       struct {
+               struct cros_ec_command cmd;
+               struct ec_response_uptime_info resp;
+       } __packed msg = {};
+       struct ec_response_uptime_info *resp;
+       char read_buf[32];
+       int ret;
+
+       resp = (struct ec_response_uptime_info *)&msg.resp;
+
+       msg.cmd.command = EC_CMD_GET_UPTIME_INFO;
+       msg.cmd.insize = sizeof(*resp);
+
+       ret = cros_ec_cmd_xfer_status(ec_dev, &msg.cmd);
+       if (ret < 0)
+               return ret;
+
+       ret = scnprintf(read_buf, sizeof(read_buf), "%u\n",
+                       resp->time_since_ec_boot_ms);
+
+       return simple_read_from_buffer(user_buf, count, ppos, read_buf, ret);
+}
+
+static const struct file_operations cros_ec_console_log_fops = {
        .owner = THIS_MODULE,
        .open = cros_ec_console_log_open,
        .read = cros_ec_console_log_read,
@@ -250,13 +279,20 @@ const struct file_operations cros_ec_console_log_fops = {
        .release = cros_ec_console_log_release,
 };
 
-const struct file_operations cros_ec_pdinfo_fops = {
+static const struct file_operations cros_ec_pdinfo_fops = {
        .owner = THIS_MODULE,
        .open = simple_open,
        .read = cros_ec_pdinfo_read,
        .llseek = default_llseek,
 };
 
+static const struct file_operations cros_ec_uptime_fops = {
+       .owner = THIS_MODULE,
+       .open = simple_open,
+       .read = cros_ec_uptime_read,
+       .llseek = default_llseek,
+};
+
 static int ec_read_version_supported(struct cros_ec_dev *ec)
 {
        struct ec_params_get_cmd_versions_v1 *params;
@@ -408,6 +444,12 @@ static int cros_ec_debugfs_probe(struct platform_device *pd)
        debugfs_create_file("pdinfo", 0444, debug_info->dir, debug_info,
                            &cros_ec_pdinfo_fops);
 
+       debugfs_create_file("uptime", 0444, debug_info->dir, debug_info,
+                           &cros_ec_uptime_fops);
+
+       debugfs_create_x32("last_resume_result", 0444, debug_info->dir,
+                          &ec->ec_dev->last_resume_result);
+
        ec->debug_info = debug_info;
 
        dev_set_drvdata(&pd->dev, ec);
diff --git a/drivers/platform/chrome/cros_ec_ishtp.c b/drivers/platform/chrome/cros_ec_ishtp.c
new file mode 100644 (file)
index 0000000..e504d25
--- /dev/null
@@ -0,0 +1,763 @@
+// SPDX-License-Identifier: GPL-2.0
+// ISHTP interface for ChromeOS Embedded Controller
+//
+// Copyright (c) 2019, Intel Corporation.
+//
+// ISHTP client driver for talking to the Chrome OS EC firmware running
+// on Intel Integrated Sensor Hub (ISH) using the ISH Transport protocol
+// (ISH-TP).
+
+#include <linux/delay.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/cros_ec.h>
+#include <linux/mfd/cros_ec_commands.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/intel-ish-client-if.h>
+
+/*
+ * ISH TX/RX ring buffer pool size
+ *
+ * The AP->ISH messages and corresponding ISH->AP responses are
+ * serialized. We need 1 TX and 1 RX buffer for these.
+ *
+ * The MKBP ISH->AP events are serialized. We need one additional RX
+ * buffer for them.
+ */
+#define CROS_ISH_CL_TX_RING_SIZE               8
+#define CROS_ISH_CL_RX_RING_SIZE               8
+
+/* ISH CrOS EC Host Commands */
+enum cros_ec_ish_channel {
+       CROS_EC_COMMAND = 1,                    /* AP->ISH message */
+       CROS_MKBP_EVENT = 2,                    /* ISH->AP events */
+};
+
+/*
+ * ISH firmware timeout for 1 message send failure is 1Hz, and the
+ * firmware will retry 2 times, so 3Hz is used for timeout.
+ */
+#define ISHTP_SEND_TIMEOUT                     (3 * HZ)
+
+/* ISH Transport CrOS EC ISH client unique GUID */
+static const guid_t cros_ish_guid =
+       GUID_INIT(0x7b7154d0, 0x56f4, 0x4bdc,
+                 0xb0, 0xd8, 0x9e, 0x7c, 0xda, 0xe0, 0xd6, 0xa0);
+
+struct header {
+       u8 channel;
+       u8 status;
+       u8 reserved[2];
+} __packed;
+
+struct cros_ish_out_msg {
+       struct header hdr;
+       struct ec_host_request ec_request;
+} __packed;
+
+struct cros_ish_in_msg {
+       struct header hdr;
+       struct ec_host_response ec_response;
+} __packed;
+
+#define IN_MSG_EC_RESPONSE_PREAMBLE                                    \
+       offsetof(struct cros_ish_in_msg, ec_response)
+
+#define OUT_MSG_EC_REQUEST_PREAMBLE                                    \
+       offsetof(struct cros_ish_out_msg, ec_request)
+
+#define cl_data_to_dev(client_data) ishtp_device((client_data)->cl_device)
+
+/*
+ * The Read-Write Semaphore is used to prevent message TX or RX while
+ * the ishtp client is being initialized or undergoing reset.
+ *
+ * The readers are the kernel function calls responsible for IA->ISH
+ * and ISH->AP messaging.
+ *
+ * The writers are .reset() and .probe() function.
+ */
+DECLARE_RWSEM(init_lock);
+
+/**
+ * struct response_info - Encapsulate firmware response related
+ * information for passing between function ish_send() and
+ * process_recv() callback.
+ *
+ * @data: Copy the data received from firmware here.
+ * @max_size: Max size allocated for the @data buffer. If the received
+ * data exceeds this value, we log an error.
+ * @size: Actual size of data received from firmware.
+ * @error: 0 for success, negative error code for a failure in process_recv().
+ * @received: Set to true on receiving a valid firmware        response to host command
+ * @wait_queue: Wait queue for host to wait for firmware response.
+ */
+struct response_info {
+       void *data;
+       size_t max_size;
+       size_t size;
+       int error;
+       bool received;
+       wait_queue_head_t wait_queue;
+};
+
+/**
+ * struct ishtp_cl_data - Encapsulate per ISH TP Client.
+ *
+ * @cros_ish_cl: ISHTP firmware client instance.
+ * @cl_device: ISHTP client device instance.
+ * @response: Response info passing between ish_send() and process_recv().
+ * @work_ishtp_reset: Work queue reset handling.
+ * @work_ec_evt: Work queue for EC events.
+ * @ec_dev: CrOS EC MFD device.
+ *
+ * This structure is used to store per client data.
+ */
+struct ishtp_cl_data {
+       struct ishtp_cl *cros_ish_cl;
+       struct ishtp_cl_device *cl_device;
+
+       /*
+        * Used for passing firmware response information between
+        * ish_send() and process_recv() callback.
+        */
+       struct response_info response;
+
+       struct work_struct work_ishtp_reset;
+       struct work_struct work_ec_evt;
+       struct cros_ec_device *ec_dev;
+};
+
+/**
+ * ish_evt_handler - ISH to AP event handler
+ * @work: Work struct
+ */
+static void ish_evt_handler(struct work_struct *work)
+{
+       struct ishtp_cl_data *client_data =
+               container_of(work, struct ishtp_cl_data, work_ec_evt);
+       struct cros_ec_device *ec_dev = client_data->ec_dev;
+
+       if (cros_ec_get_next_event(ec_dev, NULL) > 0) {
+               blocking_notifier_call_chain(&ec_dev->event_notifier,
+                                            0, ec_dev);
+       }
+}
+
+/**
+ * ish_send() - Send message from host to firmware
+ *
+ * @client_data: Client data instance
+ * @out_msg: Message buffer to be sent to firmware
+ * @out_size: Size of out going message
+ * @in_msg: Message buffer where the incoming data is copied. This buffer
+ * is allocated by calling
+ * @in_size: Max size of incoming message
+ *
+ * Return: Number of bytes copied in the in_msg on success, negative
+ * error code on failure.
+ */
+static int ish_send(struct ishtp_cl_data *client_data,
+                   u8 *out_msg, size_t out_size,
+                   u8 *in_msg, size_t in_size)
+{
+       int rv;
+       struct header *out_hdr = (struct header *)out_msg;
+       struct ishtp_cl *cros_ish_cl = client_data->cros_ish_cl;
+
+       dev_dbg(cl_data_to_dev(client_data),
+               "%s: channel=%02u status=%02u\n",
+               __func__, out_hdr->channel, out_hdr->status);
+
+       /* Setup for incoming response */
+       client_data->response.data = in_msg;
+       client_data->response.max_size = in_size;
+       client_data->response.error = 0;
+       client_data->response.received = false;
+
+       rv = ishtp_cl_send(cros_ish_cl, out_msg, out_size);
+       if (rv) {
+               dev_err(cl_data_to_dev(client_data),
+                       "ishtp_cl_send error %d\n", rv);
+               return rv;
+       }
+
+       wait_event_interruptible_timeout(client_data->response.wait_queue,
+                                        client_data->response.received,
+                                        ISHTP_SEND_TIMEOUT);
+       if (!client_data->response.received) {
+               dev_err(cl_data_to_dev(client_data),
+                       "Timed out for response to host message\n");
+               return -ETIMEDOUT;
+       }
+
+       if (client_data->response.error < 0)
+               return client_data->response.error;
+
+       return client_data->response.size;
+}
+
+/**
+ * process_recv() - Received and parse incoming packet
+ * @cros_ish_cl: Client instance to get stats
+ * @rb_in_proc: Host interface message buffer
+ *
+ * Parse the incoming packet. If it is a response packet then it will
+ * update per instance flags and wake up the caller waiting to for the
+ * response. If it is an event packet then it will schedule event work.
+ */
+static void process_recv(struct ishtp_cl *cros_ish_cl,
+                        struct ishtp_cl_rb *rb_in_proc)
+{
+       size_t data_len = rb_in_proc->buf_idx;
+       struct ishtp_cl_data *client_data =
+               ishtp_get_client_data(cros_ish_cl);
+       struct device *dev = cl_data_to_dev(client_data);
+       struct cros_ish_in_msg *in_msg =
+               (struct cros_ish_in_msg *)rb_in_proc->buffer.data;
+
+       /* Proceed only if reset or init is not in progress */
+       if (!down_read_trylock(&init_lock)) {
+               /* Free the buffer */
+               ishtp_cl_io_rb_recycle(rb_in_proc);
+               dev_warn(dev,
+                        "Host is not ready to receive incoming messages\n");
+               return;
+       }
+
+       /*
+        * All firmware messages contain a header. Check the buffer size
+        * before accessing elements inside.
+        */
+       if (!rb_in_proc->buffer.data) {
+               dev_warn(dev, "rb_in_proc->buffer.data returned null");
+               client_data->response.error = -EBADMSG;
+               goto end_error;
+       }
+
+       if (data_len < sizeof(struct header)) {
+               dev_err(dev, "data size %zu is less than header %zu\n",
+                       data_len, sizeof(struct header));
+               client_data->response.error = -EMSGSIZE;
+               goto end_error;
+       }
+
+       dev_dbg(dev, "channel=%02u status=%02u\n",
+               in_msg->hdr.channel, in_msg->hdr.status);
+
+       switch (in_msg->hdr.channel) {
+       case CROS_EC_COMMAND:
+               /* Sanity check */
+               if (!client_data->response.data) {
+                       dev_err(dev,
+                               "Receiving buffer is null. Should be allocated by calling function\n");
+                       client_data->response.error = -EINVAL;
+                       goto error_wake_up;
+               }
+
+               if (client_data->response.received) {
+                       dev_err(dev,
+                               "Previous firmware message not yet processed\n");
+                       client_data->response.error = -EINVAL;
+                       goto error_wake_up;
+               }
+
+               if (data_len > client_data->response.max_size) {
+                       dev_err(dev,
+                               "Received buffer size %zu is larger than allocated buffer %zu\n",
+                               data_len, client_data->response.max_size);
+                       client_data->response.error = -EMSGSIZE;
+                       goto error_wake_up;
+               }
+
+               if (in_msg->hdr.status) {
+                       dev_err(dev, "firmware returned status %d\n",
+                               in_msg->hdr.status);
+                       client_data->response.error = -EIO;
+                       goto error_wake_up;
+               }
+
+               /* Update the actual received buffer size */
+               client_data->response.size = data_len;
+
+               /*
+                * Copy the buffer received in firmware response for the
+                * calling thread.
+                */
+               memcpy(client_data->response.data,
+                      rb_in_proc->buffer.data, data_len);
+
+               /* Set flag before waking up the caller */
+               client_data->response.received = true;
+error_wake_up:
+               /* Wake the calling thread */
+               wake_up_interruptible(&client_data->response.wait_queue);
+
+               break;
+
+       case CROS_MKBP_EVENT:
+               /* The event system doesn't send any data in buffer */
+               schedule_work(&client_data->work_ec_evt);
+
+               break;
+
+       default:
+               dev_err(dev, "Invalid channel=%02d\n", in_msg->hdr.channel);
+       }
+
+end_error:
+       /* Free the buffer */
+       ishtp_cl_io_rb_recycle(rb_in_proc);
+
+       up_read(&init_lock);
+}
+
+/**
+ * ish_event_cb() - bus driver callback for incoming message
+ * @cl_device: ISHTP client device for which this message is targeted.
+ *
+ * Remove the packet from the list and process the message by calling
+ * process_recv.
+ */
+static void ish_event_cb(struct ishtp_cl_device *cl_device)
+{
+       struct ishtp_cl_rb *rb_in_proc;
+       struct ishtp_cl *cros_ish_cl = ishtp_get_drvdata(cl_device);
+
+       while ((rb_in_proc = ishtp_cl_rx_get_rb(cros_ish_cl)) != NULL) {
+               /* Decide what to do with received data */
+               process_recv(cros_ish_cl, rb_in_proc);
+       }
+}
+
+/**
+ * cros_ish_init() - Init function for ISHTP client
+ * @cros_ish_cl: ISHTP client instance
+ *
+ * This function complete the initializtion of the client.
+ *
+ * Return: 0 for success, negative error code for failure.
+ */
+static int cros_ish_init(struct ishtp_cl *cros_ish_cl)
+{
+       int rv;
+       struct ishtp_device *dev;
+       struct ishtp_fw_client *fw_client;
+       struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl);
+
+       rv = ishtp_cl_link(cros_ish_cl);
+       if (rv) {
+               dev_err(cl_data_to_dev(client_data),
+                       "ishtp_cl_link failed\n");
+               return rv;
+       }
+
+       dev = ishtp_get_ishtp_device(cros_ish_cl);
+
+       /* Connect to firmware client */
+       ishtp_set_tx_ring_size(cros_ish_cl, CROS_ISH_CL_TX_RING_SIZE);
+       ishtp_set_rx_ring_size(cros_ish_cl, CROS_ISH_CL_RX_RING_SIZE);
+
+       fw_client = ishtp_fw_cl_get_client(dev, &cros_ish_guid);
+       if (!fw_client) {
+               dev_err(cl_data_to_dev(client_data),
+                       "ish client uuid not found\n");
+               rv = -ENOENT;
+               goto err_cl_unlink;
+       }
+
+       ishtp_cl_set_fw_client_id(cros_ish_cl,
+                                 ishtp_get_fw_client_id(fw_client));
+       ishtp_set_connection_state(cros_ish_cl, ISHTP_CL_CONNECTING);
+
+       rv = ishtp_cl_connect(cros_ish_cl);
+       if (rv) {
+               dev_err(cl_data_to_dev(client_data),
+                       "client connect fail\n");
+               goto err_cl_unlink;
+       }
+
+       ishtp_register_event_cb(client_data->cl_device, ish_event_cb);
+       return 0;
+
+err_cl_unlink:
+       ishtp_cl_unlink(cros_ish_cl);
+       return rv;
+}
+
+/**
+ * cros_ish_deinit() - Deinit function for ISHTP client
+ * @cros_ish_cl: ISHTP client instance
+ *
+ * Unlink and free cros_ec client
+ */
+static void cros_ish_deinit(struct ishtp_cl *cros_ish_cl)
+{
+       ishtp_set_connection_state(cros_ish_cl, ISHTP_CL_DISCONNECTING);
+       ishtp_cl_disconnect(cros_ish_cl);
+       ishtp_cl_unlink(cros_ish_cl);
+       ishtp_cl_flush_queues(cros_ish_cl);
+
+       /* Disband and free all Tx and Rx client-level rings */
+       ishtp_cl_free(cros_ish_cl);
+}
+
+/**
+ * prepare_cros_ec_rx() - Check & prepare receive buffer
+ * @ec_dev: CrOS EC MFD device.
+ * @in_msg: Incoming message buffer
+ * @msg: cros_ec command used to send & receive data
+ *
+ * Return: 0 for success, negative error code for failure.
+ *
+ * Check the received buffer. Convert to cros_ec_command format.
+ */
+static int prepare_cros_ec_rx(struct cros_ec_device *ec_dev,
+                             const struct cros_ish_in_msg *in_msg,
+                             struct cros_ec_command *msg)
+{
+       u8 sum = 0;
+       int i, rv, offset;
+
+       /* Check response error code */
+       msg->result = in_msg->ec_response.result;
+       rv = cros_ec_check_result(ec_dev, msg);
+       if (rv < 0)
+               return rv;
+
+       if (in_msg->ec_response.data_len > msg->insize) {
+               dev_err(ec_dev->dev, "Packet too long (%d bytes, expected %d)",
+                       in_msg->ec_response.data_len, msg->insize);
+               return -ENOSPC;
+       }
+
+       /* Copy response packet payload and compute checksum */
+       for (i = 0; i < sizeof(struct ec_host_response); i++)
+               sum += ((u8 *)in_msg)[IN_MSG_EC_RESPONSE_PREAMBLE + i];
+
+       offset = sizeof(struct cros_ish_in_msg);
+       for (i = 0; i < in_msg->ec_response.data_len; i++)
+               sum += msg->data[i] = ((u8 *)in_msg)[offset + i];
+
+       if (sum) {
+               dev_dbg(ec_dev->dev, "Bad received packet checksum %d\n", sum);
+               return -EBADMSG;
+       }
+
+       return 0;
+}
+
+static int cros_ec_pkt_xfer_ish(struct cros_ec_device *ec_dev,
+                               struct cros_ec_command *msg)
+{
+       int rv;
+       struct ishtp_cl *cros_ish_cl = ec_dev->priv;
+       struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl);
+       struct device *dev = cl_data_to_dev(client_data);
+       struct cros_ish_in_msg *in_msg = (struct cros_ish_in_msg *)ec_dev->din;
+       struct cros_ish_out_msg *out_msg =
+               (struct cros_ish_out_msg *)ec_dev->dout;
+       size_t in_size = sizeof(struct cros_ish_in_msg) + msg->insize;
+       size_t out_size = sizeof(struct cros_ish_out_msg) + msg->outsize;
+
+       /* Sanity checks */
+       if (in_size > ec_dev->din_size) {
+               dev_err(dev,
+                       "Incoming payload size %zu is too large for ec_dev->din_size %d\n",
+                       in_size, ec_dev->din_size);
+               return -EMSGSIZE;
+       }
+
+       if (out_size > ec_dev->dout_size) {
+               dev_err(dev,
+                       "Outgoing payload size %zu is too large for ec_dev->dout_size %d\n",
+                       out_size, ec_dev->dout_size);
+               return -EMSGSIZE;
+       }
+
+       /* Proceed only if reset-init is not in progress */
+       if (!down_read_trylock(&init_lock)) {
+               dev_warn(dev,
+                        "Host is not ready to send messages to ISH. Try again\n");
+               return -EAGAIN;
+       }
+
+       /* Prepare the package to be sent over ISH TP */
+       out_msg->hdr.channel = CROS_EC_COMMAND;
+       out_msg->hdr.status = 0;
+
+       ec_dev->dout += OUT_MSG_EC_REQUEST_PREAMBLE;
+       cros_ec_prepare_tx(ec_dev, msg);
+       ec_dev->dout -= OUT_MSG_EC_REQUEST_PREAMBLE;
+
+       dev_dbg(dev,
+               "out_msg: struct_ver=0x%x checksum=0x%x command=0x%x command_ver=0x%x data_len=0x%x\n",
+               out_msg->ec_request.struct_version,
+               out_msg->ec_request.checksum,
+               out_msg->ec_request.command,
+               out_msg->ec_request.command_version,
+               out_msg->ec_request.data_len);
+
+       /* Send command to ISH EC firmware and read response */
+       rv = ish_send(client_data,
+                     (u8 *)out_msg, out_size,
+                     (u8 *)in_msg, in_size);
+       if (rv < 0)
+               goto end_error;
+
+       rv = prepare_cros_ec_rx(ec_dev, in_msg, msg);
+       if (rv)
+               goto end_error;
+
+       rv = in_msg->ec_response.data_len;
+
+       dev_dbg(dev,
+               "in_msg: struct_ver=0x%x checksum=0x%x result=0x%x data_len=0x%x\n",
+               in_msg->ec_response.struct_version,
+               in_msg->ec_response.checksum,
+               in_msg->ec_response.result,
+               in_msg->ec_response.data_len);
+
+end_error:
+       if (msg->command == EC_CMD_REBOOT_EC)
+               msleep(EC_REBOOT_DELAY_MS);
+
+       up_read(&init_lock);
+
+       return rv;
+}
+
+static int cros_ec_dev_init(struct ishtp_cl_data *client_data)
+{
+       struct cros_ec_device *ec_dev;
+       struct device *dev = cl_data_to_dev(client_data);
+
+       ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL);
+       if (!ec_dev)
+               return -ENOMEM;
+
+       client_data->ec_dev = ec_dev;
+       dev->driver_data = ec_dev;
+
+       ec_dev->dev = dev;
+       ec_dev->priv = client_data->cros_ish_cl;
+       ec_dev->cmd_xfer = NULL;
+       ec_dev->pkt_xfer = cros_ec_pkt_xfer_ish;
+       ec_dev->phys_name = dev_name(dev);
+       ec_dev->din_size = sizeof(struct cros_ish_in_msg) +
+                          sizeof(struct ec_response_get_protocol_info);
+       ec_dev->dout_size = sizeof(struct cros_ish_out_msg);
+
+       return cros_ec_register(ec_dev);
+}
+
+static void reset_handler(struct work_struct *work)
+{
+       int rv;
+       struct device *dev;
+       struct ishtp_cl *cros_ish_cl;
+       struct ishtp_cl_device *cl_device;
+       struct ishtp_cl_data *client_data =
+               container_of(work, struct ishtp_cl_data, work_ishtp_reset);
+
+       /* Lock for reset to complete */
+       down_write(&init_lock);
+
+       cros_ish_cl = client_data->cros_ish_cl;
+       cl_device = client_data->cl_device;
+
+       /* Unlink, flush queues & start again */
+       ishtp_cl_unlink(cros_ish_cl);
+       ishtp_cl_flush_queues(cros_ish_cl);
+       ishtp_cl_free(cros_ish_cl);
+
+       cros_ish_cl = ishtp_cl_allocate(cl_device);
+       if (!cros_ish_cl) {
+               up_write(&init_lock);
+               return;
+       }
+
+       ishtp_set_drvdata(cl_device, cros_ish_cl);
+       ishtp_set_client_data(cros_ish_cl, client_data);
+       client_data->cros_ish_cl = cros_ish_cl;
+
+       rv = cros_ish_init(cros_ish_cl);
+       if (rv) {
+               ishtp_cl_free(cros_ish_cl);
+               dev_err(cl_data_to_dev(client_data), "Reset Failed\n");
+               up_write(&init_lock);
+               return;
+       }
+
+       /* Refresh ec_dev device pointers */
+       client_data->ec_dev->priv = client_data->cros_ish_cl;
+       dev = cl_data_to_dev(client_data);
+       dev->driver_data = client_data->ec_dev;
+
+       dev_info(cl_data_to_dev(client_data), "Chrome EC ISH reset done\n");
+
+       up_write(&init_lock);
+}
+
+/**
+ * cros_ec_ishtp_probe() - ISHTP client driver probe callback
+ * @cl_device: ISHTP client device instance
+ *
+ * Return: 0 for success, negative error code for failure.
+ */
+static int cros_ec_ishtp_probe(struct ishtp_cl_device *cl_device)
+{
+       int rv;
+       struct ishtp_cl *cros_ish_cl;
+       struct ishtp_cl_data *client_data =
+               devm_kzalloc(ishtp_device(cl_device),
+                            sizeof(*client_data), GFP_KERNEL);
+       if (!client_data)
+               return -ENOMEM;
+
+       /* Lock for initialization to complete */
+       down_write(&init_lock);
+
+       cros_ish_cl = ishtp_cl_allocate(cl_device);
+       if (!cros_ish_cl) {
+               rv = -ENOMEM;
+               goto end_ishtp_cl_alloc_error;
+       }
+
+       ishtp_set_drvdata(cl_device, cros_ish_cl);
+       ishtp_set_client_data(cros_ish_cl, client_data);
+       client_data->cros_ish_cl = cros_ish_cl;
+       client_data->cl_device = cl_device;
+
+       init_waitqueue_head(&client_data->response.wait_queue);
+
+       INIT_WORK(&client_data->work_ishtp_reset,
+                 reset_handler);
+       INIT_WORK(&client_data->work_ec_evt,
+                 ish_evt_handler);
+
+       rv = cros_ish_init(cros_ish_cl);
+       if (rv)
+               goto end_ishtp_cl_init_error;
+
+       ishtp_get_device(cl_device);
+
+       up_write(&init_lock);
+
+       /* Register croc_ec_dev mfd */
+       rv = cros_ec_dev_init(client_data);
+       if (rv)
+               goto end_cros_ec_dev_init_error;
+
+       return 0;
+
+end_cros_ec_dev_init_error:
+       ishtp_set_connection_state(cros_ish_cl, ISHTP_CL_DISCONNECTING);
+       ishtp_cl_disconnect(cros_ish_cl);
+       ishtp_cl_unlink(cros_ish_cl);
+       ishtp_cl_flush_queues(cros_ish_cl);
+       ishtp_put_device(cl_device);
+end_ishtp_cl_init_error:
+       ishtp_cl_free(cros_ish_cl);
+end_ishtp_cl_alloc_error:
+       up_write(&init_lock);
+       return rv;
+}
+
+/**
+ * cros_ec_ishtp_remove() - ISHTP client driver remove callback
+ * @cl_device: ISHTP client device instance
+ *
+ * Return: 0
+ */
+static int cros_ec_ishtp_remove(struct ishtp_cl_device *cl_device)
+{
+       struct ishtp_cl *cros_ish_cl = ishtp_get_drvdata(cl_device);
+       struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl);
+
+       cancel_work_sync(&client_data->work_ishtp_reset);
+       cancel_work_sync(&client_data->work_ec_evt);
+       cros_ish_deinit(cros_ish_cl);
+       ishtp_put_device(cl_device);
+
+       return 0;
+}
+
+/**
+ * cros_ec_ishtp_reset() - ISHTP client driver reset callback
+ * @cl_device: ISHTP client device instance
+ *
+ * Return: 0
+ */
+static int cros_ec_ishtp_reset(struct ishtp_cl_device *cl_device)
+{
+       struct ishtp_cl *cros_ish_cl = ishtp_get_drvdata(cl_device);
+       struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl);
+
+       schedule_work(&client_data->work_ishtp_reset);
+
+       return 0;
+}
+
+/**
+ * cros_ec_ishtp_suspend() - ISHTP client driver suspend callback
+ * @device: device instance
+ *
+ * Return: 0 for success, negative error code for failure.
+ */
+static int __maybe_unused cros_ec_ishtp_suspend(struct device *device)
+{
+       struct ishtp_cl_device *cl_device = dev_get_drvdata(device);
+       struct ishtp_cl *cros_ish_cl = ishtp_get_drvdata(cl_device);
+       struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl);
+
+       return cros_ec_suspend(client_data->ec_dev);
+}
+
+/**
+ * cros_ec_ishtp_resume() - ISHTP client driver resume callback
+ * @device: device instance
+ *
+ * Return: 0 for success, negative error code for failure.
+ */
+static int __maybe_unused cros_ec_ishtp_resume(struct device *device)
+{
+       struct ishtp_cl_device *cl_device = dev_get_drvdata(device);
+       struct ishtp_cl *cros_ish_cl = ishtp_get_drvdata(cl_device);
+       struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl);
+
+       return cros_ec_resume(client_data->ec_dev);
+}
+
+static SIMPLE_DEV_PM_OPS(cros_ec_ishtp_pm_ops, cros_ec_ishtp_suspend,
+                        cros_ec_ishtp_resume);
+
+static struct ishtp_cl_driver  cros_ec_ishtp_driver = {
+       .name = "cros_ec_ishtp",
+       .guid = &cros_ish_guid,
+       .probe = cros_ec_ishtp_probe,
+       .remove = cros_ec_ishtp_remove,
+       .reset = cros_ec_ishtp_reset,
+       .driver = {
+               .pm = &cros_ec_ishtp_pm_ops,
+       },
+};
+
+static int __init cros_ec_ishtp_mod_init(void)
+{
+       return ishtp_cl_driver_register(&cros_ec_ishtp_driver, THIS_MODULE);
+}
+
+static void __exit cros_ec_ishtp_mod_exit(void)
+{
+       ishtp_cl_driver_unregister(&cros_ec_ishtp_driver);
+}
+
+module_init(cros_ec_ishtp_mod_init);
+module_exit(cros_ec_ishtp_mod_exit);
+
+MODULE_DESCRIPTION("ChromeOS EC ISHTP Client Driver");
+MODULE_AUTHOR("Rushikesh S Kadam <rushikesh.s.kadam@intel.com>");
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("ishtp:*");
index d30a665..609598b 100644 (file)
@@ -547,7 +547,7 @@ static struct attribute *__lb_cmds_attrs[] = {
        NULL,
 };
 
-struct attribute_group cros_ec_lightbar_attr_group = {
+static struct attribute_group cros_ec_lightbar_attr_group = {
        .name = "lightbar",
        .attrs = __lb_cmds_attrs,
 };
@@ -600,7 +600,7 @@ static int cros_ec_lightbar_remove(struct platform_device *pd)
 
 static int __maybe_unused cros_ec_lightbar_resume(struct device *dev)
 {
-       struct cros_ec_dev *ec_dev = dev_get_drvdata(dev);
+       struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
 
        if (userspace_control)
                return 0;
@@ -610,7 +610,7 @@ static int __maybe_unused cros_ec_lightbar_resume(struct device *dev)
 
 static int __maybe_unused cros_ec_lightbar_suspend(struct device *dev)
 {
-       struct cros_ec_dev *ec_dev = dev_get_drvdata(dev);
+       struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
 
        if (userspace_control)
                return 0;
index c9c240f..2c44c7f 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/printk.h>
 #include <linux/suspend.h>
 
-#include "cros_ec_lpc_reg.h"
+#include "cros_ec_lpc_mec.h"
 
 #define DRV_NAME "cros_ec_lpcs"
 #define ACPI_DRV_NAME "GOOG0004"
 /* True if ACPI device is present */
 static bool cros_ec_lpc_acpi_device_found;
 
+/**
+ * struct lpc_driver_ops - LPC driver operations
+ * @read: Copy length bytes from EC address offset into buffer dest. Returns
+ *        the 8-bit checksum of all bytes read.
+ * @write: Copy length bytes from buffer msg into EC address offset. Returns
+ *         the 8-bit checksum of all bytes written.
+ */
+struct lpc_driver_ops {
+       u8 (*read)(unsigned int offset, unsigned int length, u8 *dest);
+       u8 (*write)(unsigned int offset, unsigned int length, const u8 *msg);
+};
+
+static struct lpc_driver_ops cros_ec_lpc_ops = { };
+
+/*
+ * A generic instance of the read function of struct lpc_driver_ops, used for
+ * the LPC EC.
+ */
+static u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length,
+                                u8 *dest)
+{
+       int sum = 0;
+       int i;
+
+       for (i = 0; i < length; ++i) {
+               dest[i] = inb(offset + i);
+               sum += dest[i];
+       }
+
+       /* Return checksum of all bytes read */
+       return sum;
+}
+
+/*
+ * A generic instance of the write function of struct lpc_driver_ops, used for
+ * the LPC EC.
+ */
+static u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length,
+                                 const u8 *msg)
+{
+       int sum = 0;
+       int i;
+
+       for (i = 0; i < length; ++i) {
+               outb(msg[i], offset + i);
+               sum += msg[i];
+       }
+
+       /* Return checksum of all bytes written */
+       return sum;
+}
+
+/*
+ * An instance of the read function of struct lpc_driver_ops, used for the
+ * MEC variant of LPC EC.
+ */
+static u8 cros_ec_lpc_mec_read_bytes(unsigned int offset, unsigned int length,
+                                    u8 *dest)
+{
+       int in_range = cros_ec_lpc_mec_in_range(offset, length);
+
+       if (in_range < 0)
+               return 0;
+
+       return in_range ?
+               cros_ec_lpc_io_bytes_mec(MEC_IO_READ,
+                                        offset - EC_HOST_CMD_REGION0,
+                                        length, dest) :
+               cros_ec_lpc_read_bytes(offset, length, dest);
+}
+
+/*
+ * An instance of the write function of struct lpc_driver_ops, used for the
+ * MEC variant of LPC EC.
+ */
+static u8 cros_ec_lpc_mec_write_bytes(unsigned int offset, unsigned int length,
+                                     const u8 *msg)
+{
+       int in_range = cros_ec_lpc_mec_in_range(offset, length);
+
+       if (in_range < 0)
+               return 0;
+
+       return in_range ?
+               cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE,
+                                        offset - EC_HOST_CMD_REGION0,
+                                        length, (u8 *)msg) :
+               cros_ec_lpc_write_bytes(offset, length, msg);
+}
+
 static int ec_response_timed_out(void)
 {
        unsigned long one_second = jiffies + HZ;
@@ -38,7 +128,7 @@ static int ec_response_timed_out(void)
 
        usleep_range(200, 300);
        do {
-               if (!(cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_CMD, 1, &data) &
+               if (!(cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_CMD, 1, &data) &
                    EC_LPC_STATUS_BUSY_MASK))
                        return 0;
                usleep_range(100, 200);
@@ -58,11 +148,11 @@ static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec,
        ret = cros_ec_prepare_tx(ec, msg);
 
        /* Write buffer */
-       cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_PACKET, ret, ec->dout);
+       cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_PACKET, ret, ec->dout);
 
        /* Here we go */
        sum = EC_COMMAND_PROTOCOL_3;
-       cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_CMD, 1, &sum);
+       cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_CMD, 1, &sum);
 
        if (ec_response_timed_out()) {
                dev_warn(ec->dev, "EC responsed timed out\n");
@@ -71,15 +161,15 @@ static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec,
        }
 
        /* Check result */
-       msg->result = cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_DATA, 1, &sum);
+       msg->result = cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_DATA, 1, &sum);
        ret = cros_ec_check_result(ec, msg);
        if (ret)
                goto done;
 
        /* Read back response */
        dout = (u8 *)&response;
-       sum = cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_PACKET, sizeof(response),
-                                    dout);
+       sum = cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_PACKET, sizeof(response),
+                                  dout);
 
        msg->result = response.result;
 
@@ -92,9 +182,9 @@ static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec,
        }
 
        /* Read response and process checksum */
-       sum += cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_PACKET +
-                                     sizeof(response), response.data_len,
-                                     msg->data);
+       sum += cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_PACKET +
+                                   sizeof(response), response.data_len,
+                                   msg->data);
 
        if (sum) {
                dev_err(ec->dev,
@@ -134,17 +224,17 @@ static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec,
        sum = msg->command + args.flags + args.command_version + args.data_size;
 
        /* Copy data and update checksum */
-       sum += cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_PARAM, msg->outsize,
-                                      msg->data);
+       sum += cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_PARAM, msg->outsize,
+                                    msg->data);
 
        /* Finalize checksum and write args */
        args.checksum = sum;
-       cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_ARGS, sizeof(args),
-                               (u8 *)&args);
+       cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_ARGS, sizeof(args),
+                             (u8 *)&args);
 
        /* Here we go */
        sum = msg->command;
-       cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_CMD, 1, &sum);
+       cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_CMD, 1, &sum);
 
        if (ec_response_timed_out()) {
                dev_warn(ec->dev, "EC responsed timed out\n");
@@ -153,14 +243,13 @@ static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec,
        }
 
        /* Check result */
-       msg->result = cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_DATA, 1, &sum);
+       msg->result = cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_DATA, 1, &sum);
        ret = cros_ec_check_result(ec, msg);
        if (ret)
                goto done;
 
        /* Read back args */
-       cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_ARGS, sizeof(args),
-                              (u8 *)&args);
+       cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_ARGS, sizeof(args), (u8 *)&args);
 
        if (args.data_size > msg->insize) {
                dev_err(ec->dev,
@@ -174,8 +263,8 @@ static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec,
        sum = msg->command + args.flags + args.command_version + args.data_size;
 
        /* Read response and update checksum */
-       sum += cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_PARAM, args.data_size,
-                                     msg->data);
+       sum += cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_PARAM, args.data_size,
+                                   msg->data);
 
        /* Verify checksum */
        if (args.checksum != sum) {
@@ -205,13 +294,13 @@ static int cros_ec_lpc_readmem(struct cros_ec_device *ec, unsigned int offset,
 
        /* fixed length */
        if (bytes) {
-               cros_ec_lpc_read_bytes(EC_LPC_ADDR_MEMMAP + offset, bytes, s);
+               cros_ec_lpc_ops.read(EC_LPC_ADDR_MEMMAP + offset, bytes, s);
                return bytes;
        }
 
        /* string */
        for (; i < EC_MEMMAP_SIZE; i++, s++) {
-               cros_ec_lpc_read_bytes(EC_LPC_ADDR_MEMMAP + i, 1, s);
+               cros_ec_lpc_ops.read(EC_LPC_ADDR_MEMMAP + i, 1, s);
                cnt++;
                if (!*s)
                        break;
@@ -248,10 +337,25 @@ static int cros_ec_lpc_probe(struct platform_device *pdev)
                return -EBUSY;
        }
 
-       cros_ec_lpc_read_bytes(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID, 2, buf);
+       /*
+        * Read the mapped ID twice, the first one is assuming the
+        * EC is a Microchip Embedded Controller (MEC) variant, if the
+        * protocol fails, fallback to the non MEC variant and try to
+        * read again the ID.
+        */
+       cros_ec_lpc_ops.read = cros_ec_lpc_mec_read_bytes;
+       cros_ec_lpc_ops.write = cros_ec_lpc_mec_write_bytes;
+       cros_ec_lpc_ops.read(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID, 2, buf);
        if (buf[0] != 'E' || buf[1] != 'C') {
-               dev_err(dev, "EC ID not detected\n");
-               return -ENODEV;
+               /* Re-assign read/write operations for the non MEC variant */
+               cros_ec_lpc_ops.read = cros_ec_lpc_read_bytes;
+               cros_ec_lpc_ops.write = cros_ec_lpc_write_bytes;
+               cros_ec_lpc_ops.read(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID, 2,
+                                    buf);
+               if (buf[0] != 'E' || buf[1] != 'C') {
+                       dev_err(dev, "EC ID not detected\n");
+                       return -ENODEV;
+               }
        }
 
        if (!devm_request_region(dev, EC_HOST_CMD_REGION0,
@@ -405,7 +509,7 @@ static int cros_ec_lpc_resume(struct device *dev)
 }
 #endif
 
-const struct dev_pm_ops cros_ec_lpc_pm_ops = {
+static const struct dev_pm_ops cros_ec_lpc_pm_ops = {
        SET_LATE_SYSTEM_SLEEP_PM_OPS(cros_ec_lpc_suspend, cros_ec_lpc_resume)
 };
 
@@ -446,13 +550,14 @@ static int __init cros_ec_lpc_init(void)
                return -ENODEV;
        }
 
-       cros_ec_lpc_reg_init();
+       cros_ec_lpc_mec_init(EC_HOST_CMD_REGION0,
+                            EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SIZE);
 
        /* Register the driver */
        ret = platform_driver_register(&cros_ec_lpc_driver);
        if (ret) {
                pr_err(DRV_NAME ": can't register driver: %d\n", ret);
-               cros_ec_lpc_reg_destroy();
+               cros_ec_lpc_mec_destroy();
                return ret;
        }
 
@@ -462,7 +567,7 @@ static int __init cros_ec_lpc_init(void)
                if (ret) {
                        pr_err(DRV_NAME ": can't register device: %d\n", ret);
                        platform_driver_unregister(&cros_ec_lpc_driver);
-                       cros_ec_lpc_reg_destroy();
+                       cros_ec_lpc_mec_destroy();
                }
        }
 
@@ -474,7 +579,7 @@ static void __exit cros_ec_lpc_exit(void)
        if (!cros_ec_lpc_acpi_device_found)
                platform_device_unregister(&cros_ec_lpc_device);
        platform_driver_unregister(&cros_ec_lpc_driver);
-       cros_ec_lpc_reg_destroy();
+       cros_ec_lpc_mec_destroy();
 }
 
 module_init(cros_ec_lpc_init);
index d8890ba..9035b17 100644 (file)
 static struct mutex io_mutex;
 static u16 mec_emi_base, mec_emi_end;
 
-/*
- * cros_ec_lpc_mec_emi_write_address
- *
- * Initialize EMI read / write at a given address.
+/**
+ * cros_ec_lpc_mec_emi_write_address() - Initialize EMI at a given address.
  *
- * @addr:        Starting read / write address
+ * @addr: Starting read / write address
  * @access_type: Type of access, typically 32-bit auto-increment
  */
 static void cros_ec_lpc_mec_emi_write_address(u16 addr,
@@ -61,15 +59,15 @@ int cros_ec_lpc_mec_in_range(unsigned int offset, unsigned int length)
        return 0;
 }
 
-/*
- * cros_ec_lpc_io_bytes_mec - Read / write bytes to MEC EMI port
+/**
+ * cros_ec_lpc_io_bytes_mec() - Read / write bytes to MEC EMI port.
  *
  * @io_type: MEC_IO_READ or MEC_IO_WRITE, depending on request
  * @offset:  Base read / write address
  * @length:  Number of bytes to read / write
  * @buf:     Destination / source buffer
  *
- * @return 8-bit checksum of all bytes read / written
+ * Return: 8-bit checksum of all bytes read / written
  */
 u8 cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type,
                            unsigned int offset, unsigned int length,
diff --git a/drivers/platform/chrome/cros_ec_lpc_reg.c b/drivers/platform/chrome/cros_ec_lpc_reg.c
deleted file mode 100644 (file)
index 0f5cd0a..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// LPC interface for ChromeOS Embedded Controller
-//
-// Copyright (C) 2016 Google, Inc
-
-#include <linux/io.h>
-#include <linux/mfd/cros_ec.h>
-#include <linux/mfd/cros_ec_commands.h>
-
-#include "cros_ec_lpc_mec.h"
-
-static u8 lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest)
-{
-       int i;
-       int sum = 0;
-
-       for (i = 0; i < length; ++i) {
-               dest[i] = inb(offset + i);
-               sum += dest[i];
-       }
-
-       /* Return checksum of all bytes read */
-       return sum;
-}
-
-static u8 lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg)
-{
-       int i;
-       int sum = 0;
-
-       for (i = 0; i < length; ++i) {
-               outb(msg[i], offset + i);
-               sum += msg[i];
-       }
-
-       /* Return checksum of all bytes written */
-       return sum;
-}
-
-#ifdef CONFIG_CROS_EC_LPC_MEC
-
-u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest)
-{
-       int in_range = cros_ec_lpc_mec_in_range(offset, length);
-
-       if (in_range < 0)
-               return 0;
-
-       return in_range ?
-               cros_ec_lpc_io_bytes_mec(MEC_IO_READ,
-                                        offset - EC_HOST_CMD_REGION0,
-                                        length, dest) :
-               lpc_read_bytes(offset, length, dest);
-}
-
-u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg)
-{
-       int in_range = cros_ec_lpc_mec_in_range(offset, length);
-
-       if (in_range < 0)
-               return 0;
-
-       return in_range ?
-               cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE,
-                                        offset - EC_HOST_CMD_REGION0,
-                                        length, msg) :
-               lpc_write_bytes(offset, length, msg);
-}
-
-void cros_ec_lpc_reg_init(void)
-{
-       cros_ec_lpc_mec_init(EC_HOST_CMD_REGION0,
-                            EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SIZE);
-}
-
-void cros_ec_lpc_reg_destroy(void)
-{
-       cros_ec_lpc_mec_destroy();
-}
-
-#else /* CONFIG_CROS_EC_LPC_MEC */
-
-u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest)
-{
-       return lpc_read_bytes(offset, length, dest);
-}
-
-u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg)
-{
-       return lpc_write_bytes(offset, length, msg);
-}
-
-void cros_ec_lpc_reg_init(void)
-{
-}
-
-void cros_ec_lpc_reg_destroy(void)
-{
-}
-
-#endif /* CONFIG_CROS_EC_LPC_MEC */
diff --git a/drivers/platform/chrome/cros_ec_lpc_reg.h b/drivers/platform/chrome/cros_ec_lpc_reg.h
deleted file mode 100644 (file)
index 416fd25..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * LPC interface for ChromeOS Embedded Controller
- *
- * Copyright (C) 2016 Google, Inc
- */
-
-#ifndef __CROS_EC_LPC_REG_H
-#define __CROS_EC_LPC_REG_H
-
-/**
- * cros_ec_lpc_read_bytes - Read bytes from a given LPC-mapped address.
- * Returns 8-bit checksum of all bytes read.
- *
- * @offset: Base read address
- * @length: Number of bytes to read
- * @dest: Destination buffer
- */
-u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest);
-
-/**
- * cros_ec_lpc_write_bytes - Write bytes to a given LPC-mapped address.
- * Returns 8-bit checksum of all bytes written.
- *
- * @offset: Base write address
- * @length: Number of bytes to write
- * @msg: Write data buffer
- */
-u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg);
-
-/**
- * cros_ec_lpc_reg_init
- *
- * Initialize register I/O.
- */
-void cros_ec_lpc_reg_init(void);
-
-/**
- * cros_ec_lpc_reg_destroy
- *
- * Cleanup reg I/O.
- */
-void cros_ec_lpc_reg_destroy(void);
-
-#endif /* __CROS_EC_LPC_REG_H */
index 8e94517..006a8ff 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
-
+#include <uapi/linux/sched/types.h>
 
 /* The header byte, which follows the preamble */
 #define EC_MSG_HEADER                  0xec
  *      is sent when we want to turn on CS at the start of a transaction.
  * @end_of_msg_delay: used to set the delay_usecs on the spi_transfer that
  *      is sent when we want to turn off CS at the end of a transaction.
+ * @high_pri_worker: Used to schedule high priority work.
  */
 struct cros_ec_spi {
        struct spi_device *spi;
        s64 last_transfer_ns;
        unsigned int start_of_msg_delay;
        unsigned int end_of_msg_delay;
+       struct kthread_worker *high_pri_worker;
 };
 
 typedef int (*cros_ec_xfer_fn_t) (struct cros_ec_device *ec_dev,
@@ -89,7 +91,7 @@ typedef int (*cros_ec_xfer_fn_t) (struct cros_ec_device *ec_dev,
  */
 
 struct cros_ec_xfer_work_params {
-       struct work_struct work;
+       struct kthread_work work;
        cros_ec_xfer_fn_t fn;
        struct cros_ec_device *ec_dev;
        struct cros_ec_command *ec_msg;
@@ -632,7 +634,7 @@ exit:
        return ret;
 }
 
-static void cros_ec_xfer_high_pri_work(struct work_struct *work)
+static void cros_ec_xfer_high_pri_work(struct kthread_work *work)
 {
        struct cros_ec_xfer_work_params *params;
 
@@ -644,12 +646,14 @@ static int cros_ec_xfer_high_pri(struct cros_ec_device *ec_dev,
                                 struct cros_ec_command *ec_msg,
                                 cros_ec_xfer_fn_t fn)
 {
-       struct cros_ec_xfer_work_params params;
-
-       INIT_WORK_ONSTACK(&params.work, cros_ec_xfer_high_pri_work);
-       params.ec_dev = ec_dev;
-       params.ec_msg = ec_msg;
-       params.fn = fn;
+       struct cros_ec_spi *ec_spi = ec_dev->priv;
+       struct cros_ec_xfer_work_params params = {
+               .work = KTHREAD_WORK_INIT(params.work,
+                                         cros_ec_xfer_high_pri_work),
+               .ec_dev = ec_dev,
+               .ec_msg = ec_msg,
+               .fn = fn,
+       };
 
        /*
         * This looks a bit ridiculous.  Why do the work on a
@@ -660,9 +664,8 @@ static int cros_ec_xfer_high_pri(struct cros_ec_device *ec_dev,
         * context switched out for too long and the EC giving up on
         * the transfer.
         */
-       queue_work(system_highpri_wq, &params.work);
-       flush_work(&params.work);
-       destroy_work_on_stack(&params.work);
+       kthread_queue_work(ec_spi->high_pri_worker, &params.work);
+       kthread_flush_work(&params.work);
 
        return params.ret;
 }
@@ -694,6 +697,40 @@ static void cros_ec_spi_dt_probe(struct cros_ec_spi *ec_spi, struct device *dev)
                ec_spi->end_of_msg_delay = val;
 }
 
+static void cros_ec_spi_high_pri_release(void *worker)
+{
+       kthread_destroy_worker(worker);
+}
+
+static int cros_ec_spi_devm_high_pri_alloc(struct device *dev,
+                                          struct cros_ec_spi *ec_spi)
+{
+       struct sched_param sched_priority = {
+               .sched_priority = MAX_RT_PRIO - 1,
+       };
+       int err;
+
+       ec_spi->high_pri_worker =
+               kthread_create_worker(0, "cros_ec_spi_high_pri");
+
+       if (IS_ERR(ec_spi->high_pri_worker)) {
+               err = PTR_ERR(ec_spi->high_pri_worker);
+               dev_err(dev, "Can't create cros_ec high pri worker: %d\n", err);
+               return err;
+       }
+
+       err = devm_add_action_or_reset(dev, cros_ec_spi_high_pri_release,
+                                      ec_spi->high_pri_worker);
+       if (err)
+               return err;
+
+       err = sched_setscheduler_nocheck(ec_spi->high_pri_worker->task,
+                                        SCHED_FIFO, &sched_priority);
+       if (err)
+               dev_err(dev, "Can't set cros_ec high pri priority: %d\n", err);
+       return err;
+}
+
 static int cros_ec_spi_probe(struct spi_device *spi)
 {
        struct device *dev = &spi->dev;
@@ -703,6 +740,7 @@ static int cros_ec_spi_probe(struct spi_device *spi)
 
        spi->bits_per_word = 8;
        spi->mode = SPI_MODE_0;
+       spi->rt = true;
        err = spi_setup(spi);
        if (err < 0)
                return err;
@@ -732,6 +770,10 @@ static int cros_ec_spi_probe(struct spi_device *spi)
 
        ec_spi->last_transfer_ns = ktime_get_ns();
 
+       err = cros_ec_spi_devm_high_pri_alloc(dev, ec_spi);
+       if (err)
+               return err;
+
        err = cros_ec_register(ec_dev);
        if (err) {
                dev_err(dev, "cannot register EC\n");
@@ -777,7 +819,7 @@ MODULE_DEVICE_TABLE(spi, cros_ec_spi_id);
 static struct spi_driver cros_ec_driver_spi = {
        .driver = {
                .name   = "cros-ec-spi",
-               .of_match_table = of_match_ptr(cros_ec_spi_of_match),
+               .of_match_table = cros_ec_spi_of_match,
                .pm     = &cros_ec_spi_pm_ops,
        },
        .probe          = cros_ec_spi_probe,
index fe0b761..3edb237 100644 (file)
@@ -335,7 +335,7 @@ static umode_t cros_ec_ctrl_visible(struct kobject *kobj,
        return a->mode;
 }
 
-struct attribute_group cros_ec_attr_group = {
+static struct attribute_group cros_ec_attr_group = {
        .attrs = __ec_attrs,
        .is_visible = cros_ec_ctrl_visible,
 };
index 8392a1e..2aaefed 100644 (file)
@@ -101,7 +101,7 @@ static struct bin_attribute *cros_ec_vbc_bin_attrs[] = {
        NULL
 };
 
-struct attribute_group cros_ec_vbc_attr_group = {
+static struct attribute_group cros_ec_vbc_attr_group = {
        .name = "vbc",
        .bin_attrs = cros_ec_vbc_bin_attrs,
 };
index fd29cbf..89007b0 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 config WILCO_EC
        tristate "ChromeOS Wilco Embedded Controller"
-       depends on ACPI && X86 && CROS_EC_LPC && CROS_EC_LPC_MEC
+       depends on ACPI && X86 && CROS_EC_LPC
        help
          If you say Y here, you get support for talking to the ChromeOS
          Wilco EC over an eSPI bus. This uses a simple byte-level protocol
@@ -19,3 +19,19 @@ config WILCO_EC_DEBUGFS
          manipulation and allow for testing arbitrary commands.  This
          interface is intended for debug only and will not be present
          on production devices.
+
+config WILCO_EC_EVENTS
+       tristate "Enable event forwarding from EC to userspace"
+       depends on WILCO_EC
+       help
+         If you say Y here, you get support for the EC to send events
+         (such as power state changes) to userspace. The EC sends the events
+         over ACPI, and a driver queues up the events to be read by a
+         userspace daemon from /dev/wilco_event using read() and poll().
+
+config WILCO_EC_TELEMETRY
+       tristate "Enable querying telemetry data from EC"
+       depends on WILCO_EC
+       help
+         If you say Y here, you get support to query EC telemetry data from
+         /dev/wilco_telem0 using write() and then read().
index 063e7fb..bc81716 100644 (file)
@@ -1,6 +1,10 @@
 # SPDX-License-Identifier: GPL-2.0
 
-wilco_ec-objs                          := core.o mailbox.o
+wilco_ec-objs                          := core.o mailbox.o properties.o sysfs.o
 obj-$(CONFIG_WILCO_EC)                 += wilco_ec.o
 wilco_ec_debugfs-objs                  := debugfs.o
 obj-$(CONFIG_WILCO_EC_DEBUGFS)         += wilco_ec_debugfs.o
+wilco_ec_events-objs                   := event.o
+obj-$(CONFIG_WILCO_EC_EVENTS)          += wilco_ec_events.o
+wilco_ec_telem-objs                    := telemetry.o
+obj-$(CONFIG_WILCO_EC_TELEMETRY)       += wilco_ec_telem.o
index 05e1e2b..3724bf4 100644 (file)
@@ -52,9 +52,7 @@ static int wilco_ec_probe(struct platform_device *pdev)
        ec->dev = dev;
        mutex_init(&ec->mailbox_lock);
 
-       /* Largest data buffer size requirement is extended data response */
-       ec->data_size = sizeof(struct wilco_ec_response) +
-               EC_MAILBOX_DATA_SIZE_EXTENDED;
+       ec->data_size = sizeof(struct wilco_ec_response) + EC_MAILBOX_DATA_SIZE;
        ec->data_buffer = devm_kzalloc(dev, ec->data_size, GFP_KERNEL);
        if (!ec->data_buffer)
                return -ENOMEM;
@@ -89,8 +87,28 @@ static int wilco_ec_probe(struct platform_device *pdev)
                goto unregister_debugfs;
        }
 
+       ret = wilco_ec_add_sysfs(ec);
+       if (ret < 0) {
+               dev_err(dev, "Failed to create sysfs entries: %d", ret);
+               goto unregister_rtc;
+       }
+
+       /* Register child device that will be found by the telemetry driver. */
+       ec->telem_pdev = platform_device_register_data(dev, "wilco_telem",
+                                                      PLATFORM_DEVID_AUTO,
+                                                      ec, sizeof(*ec));
+       if (IS_ERR(ec->telem_pdev)) {
+               dev_err(dev, "Failed to create telemetry platform device\n");
+               ret = PTR_ERR(ec->telem_pdev);
+               goto remove_sysfs;
+       }
+
        return 0;
 
+remove_sysfs:
+       wilco_ec_remove_sysfs(ec);
+unregister_rtc:
+       platform_device_unregister(ec->rtc_pdev);
 unregister_debugfs:
        if (ec->debugfs_pdev)
                platform_device_unregister(ec->debugfs_pdev);
@@ -102,6 +120,8 @@ static int wilco_ec_remove(struct platform_device *pdev)
 {
        struct wilco_ec_device *ec = platform_get_drvdata(pdev);
 
+       wilco_ec_remove_sysfs(ec);
+       platform_device_unregister(ec->telem_pdev);
        platform_device_unregister(ec->rtc_pdev);
        if (ec->debugfs_pdev)
                platform_device_unregister(ec->debugfs_pdev);
index f163476..8d65a1e 100644 (file)
 
 #define DRV_NAME "wilco-ec-debugfs"
 
-/* The 256 raw bytes will take up more space when represented as a hex string */
-#define FORMATTED_BUFFER_SIZE (EC_MAILBOX_DATA_SIZE_EXTENDED * 4)
+/* The raw bytes will take up more space when represented as a hex string */
+#define FORMATTED_BUFFER_SIZE (EC_MAILBOX_DATA_SIZE * 4)
 
 struct wilco_ec_debugfs {
        struct wilco_ec_device *ec;
        struct dentry *dir;
        size_t response_size;
-       u8 raw_data[EC_MAILBOX_DATA_SIZE_EXTENDED];
+       u8 raw_data[EC_MAILBOX_DATA_SIZE];
        u8 formatted_data[FORMATTED_BUFFER_SIZE];
 };
 static struct wilco_ec_debugfs *debug_info;
@@ -124,12 +124,6 @@ static ssize_t raw_write(struct file *file, const char __user *user_buf,
        msg.response_data = debug_info->raw_data;
        msg.response_size = EC_MAILBOX_DATA_SIZE;
 
-       /* Telemetry commands use extended response data */
-       if (msg.type == WILCO_EC_MSG_TELEMETRY_LONG) {
-               msg.flags |= WILCO_EC_FLAG_EXTENDED_DATA;
-               msg.response_size = EC_MAILBOX_DATA_SIZE_EXTENDED;
-       }
-
        ret = wilco_ec_mailbox(debug_info->ec, &msg);
        if (ret < 0)
                return ret;
diff --git a/drivers/platform/chrome/wilco_ec/event.c b/drivers/platform/chrome/wilco_ec/event.c
new file mode 100644 (file)
index 0000000..dba3d44
--- /dev/null
@@ -0,0 +1,581 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ACPI event handling for Wilco Embedded Controller
+ *
+ * Copyright 2019 Google LLC
+ *
+ * The Wilco Embedded Controller can create custom events that
+ * are not handled as standard ACPI objects. These events can
+ * contain information about changes in EC controlled features,
+ * such as errors and events in the dock or display. For example,
+ * an event is triggered if the dock is plugged into a display
+ * incorrectly. These events are needed for telemetry and
+ * diagnostics reasons, and for possibly alerting the user.
+
+ * These events are triggered by the EC with an ACPI Notify(0x90),
+ * and then the BIOS reads the event buffer from EC RAM via an
+ * ACPI method. When the OS receives these events via ACPI,
+ * it passes them along to this driver. The events are put into
+ * a queue which can be read by a userspace daemon via a char device
+ * that implements read() and poll(). The event queue acts as a
+ * circular buffer of size 64, so if there are no userspace consumers
+ * the kernel will not run out of memory. The char device will appear at
+ * /dev/wilco_event{n}, where n is some small non-negative integer,
+ * starting from 0. Standard ACPI events such as the battery getting
+ * plugged/unplugged can also come through this path, but they are
+ * dealt with via other paths, and are ignored here.
+
+ * To test, you can tail the binary data with
+ * $ cat /dev/wilco_event0 | hexdump -ve '1/1 "%x\n"'
+ * and then create an event by plugging/unplugging the battery.
+ */
+
+#include <linux/acpi.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+
+/* ACPI Notify event code indicating event data is available. */
+#define EC_ACPI_NOTIFY_EVENT           0x90
+/* ACPI Method to execute to retrieve event data buffer from the EC. */
+#define EC_ACPI_GET_EVENT              "QSET"
+/* Maximum number of words in event data returned by the EC. */
+#define EC_ACPI_MAX_EVENT_WORDS                6
+#define EC_ACPI_MAX_EVENT_SIZE \
+       (sizeof(struct ec_event) + (EC_ACPI_MAX_EVENT_WORDS) * sizeof(u16))
+
+/* Node will appear in /dev/EVENT_DEV_NAME */
+#define EVENT_DEV_NAME         "wilco_event"
+#define EVENT_CLASS_NAME       EVENT_DEV_NAME
+#define DRV_NAME               EVENT_DEV_NAME
+#define EVENT_DEV_NAME_FMT     (EVENT_DEV_NAME "%d")
+static struct class event_class = {
+       .owner  = THIS_MODULE,
+       .name   = EVENT_CLASS_NAME,
+};
+
+/* Keep track of all the device numbers used. */
+#define EVENT_MAX_DEV 128
+static int event_major;
+static DEFINE_IDA(event_ida);
+
+/* Size of circular queue of events. */
+#define MAX_NUM_EVENTS 64
+
+/**
+ * struct ec_event - Extended event returned by the EC.
+ * @size: Number of 16bit words in structure after the size word.
+ * @type: Extended event type, meaningless for us.
+ * @event: Event data words.  Max count is %EC_ACPI_MAX_EVENT_WORDS.
+ */
+struct ec_event {
+       u16 size;
+       u16 type;
+       u16 event[0];
+} __packed;
+
+#define ec_event_num_words(ev) (ev->size - 1)
+#define ec_event_size(ev) (sizeof(*ev) + (ec_event_num_words(ev) * sizeof(u16)))
+
+/**
+ * struct ec_event_queue - Circular queue for events.
+ * @capacity: Number of elements the queue can hold.
+ * @head: Next index to write to.
+ * @tail: Next index to read from.
+ * @entries: Array of events.
+ */
+struct ec_event_queue {
+       int capacity;
+       int head;
+       int tail;
+       struct ec_event *entries[0];
+};
+
+/* Maximum number of events to store in ec_event_queue */
+static int queue_size = 64;
+module_param(queue_size, int, 0644);
+
+static struct ec_event_queue *event_queue_new(int capacity)
+{
+       struct ec_event_queue *q;
+
+       q = kzalloc(struct_size(q, entries, capacity), GFP_KERNEL);
+       if (!q)
+               return NULL;
+
+       q->capacity = capacity;
+
+       return q;
+}
+
+static inline bool event_queue_empty(struct ec_event_queue *q)
+{
+       /* head==tail when both full and empty, but head==NULL when empty */
+       return q->head == q->tail && !q->entries[q->head];
+}
+
+static inline bool event_queue_full(struct ec_event_queue *q)
+{
+       /* head==tail when both full and empty, but head!=NULL when full */
+       return q->head == q->tail && q->entries[q->head];
+}
+
+static struct ec_event *event_queue_pop(struct ec_event_queue *q)
+{
+       struct ec_event *ev;
+
+       if (event_queue_empty(q))
+               return NULL;
+
+       ev = q->entries[q->tail];
+       q->entries[q->tail] = NULL;
+       q->tail = (q->tail + 1) % q->capacity;
+
+       return ev;
+}
+
+/*
+ * If full, overwrite the oldest event and return it so the caller
+ * can kfree it. If not full, return NULL.
+ */
+static struct ec_event *event_queue_push(struct ec_event_queue *q,
+                                        struct ec_event *ev)
+{
+       struct ec_event *popped = NULL;
+
+       if (event_queue_full(q))
+               popped = event_queue_pop(q);
+       q->entries[q->head] = ev;
+       q->head = (q->head + 1) % q->capacity;
+
+       return popped;
+}
+
+static void event_queue_free(struct ec_event_queue *q)
+{
+       struct ec_event *event;
+
+       while ((event = event_queue_pop(q)) != NULL)
+               kfree(event);
+
+       kfree(q);
+}
+
+/**
+ * struct event_device_data - Data for a Wilco EC device that responds to ACPI.
+ * @events: Circular queue of EC events to be provided to userspace.
+ * @queue_lock: Protect the queue from simultaneous read/writes.
+ * @wq: Wait queue to notify processes when events are available or the
+ *     device has been removed.
+ * @cdev: Char dev that userspace reads() and polls() from.
+ * @dev: Device associated with the %cdev.
+ * @exist: Has the device been not been removed? Once a device has been removed,
+ *        writes, reads, and new opens will fail.
+ * @available: Guarantee only one client can open() file and read from queue.
+ *
+ * There will be one of these structs for each ACPI device registered. This data
+ * is the queue of events received from ACPI that still need to be read from
+ * userspace, the device and char device that userspace is using, a wait queue
+ * used to notify different threads when something has changed, plus a flag
+ * on whether the ACPI device has been removed.
+ */
+struct event_device_data {
+       struct ec_event_queue *events;
+       spinlock_t queue_lock;
+       wait_queue_head_t wq;
+       struct device dev;
+       struct cdev cdev;
+       bool exist;
+       atomic_t available;
+};
+
+/**
+ * enqueue_events() - Place EC events in queue to be read by userspace.
+ * @adev: Device the events came from.
+ * @buf: Buffer of event data.
+ * @length: Length of event data buffer.
+ *
+ * %buf contains a number of ec_event's, packed one after the other.
+ * Each ec_event is of variable length. Start with the first event, copy it
+ * into a persistent ec_event, store that entry in the queue, move on
+ * to the next ec_event in buf, and repeat.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+static int enqueue_events(struct acpi_device *adev, const u8 *buf, u32 length)
+{
+       struct event_device_data *dev_data = adev->driver_data;
+       struct ec_event *event, *queue_event, *old_event;
+       size_t num_words, event_size;
+       u32 offset = 0;
+
+       while (offset < length) {
+               event = (struct ec_event *)(buf + offset);
+
+               num_words = ec_event_num_words(event);
+               event_size = ec_event_size(event);
+               if (num_words > EC_ACPI_MAX_EVENT_WORDS) {
+                       dev_err(&adev->dev, "Too many event words: %zu > %d\n",
+                               num_words, EC_ACPI_MAX_EVENT_WORDS);
+                       return -EOVERFLOW;
+               }
+
+               /* Ensure event does not overflow the available buffer */
+               if ((offset + event_size) > length) {
+                       dev_err(&adev->dev, "Event exceeds buffer: %zu > %d\n",
+                               offset + event_size, length);
+                       return -EOVERFLOW;
+               }
+
+               /* Point to the next event in the buffer */
+               offset += event_size;
+
+               /* Copy event into the queue */
+               queue_event = kmemdup(event, event_size, GFP_KERNEL);
+               if (!queue_event)
+                       return -ENOMEM;
+               spin_lock(&dev_data->queue_lock);
+               old_event = event_queue_push(dev_data->events, queue_event);
+               spin_unlock(&dev_data->queue_lock);
+               kfree(old_event);
+               wake_up_interruptible(&dev_data->wq);
+       }
+
+       return 0;
+}
+
+/**
+ * event_device_notify() - Callback when EC generates an event over ACPI.
+ * @adev: The device that the event is coming from.
+ * @value: Value passed to Notify() in ACPI.
+ *
+ * This function will read the events from the device and enqueue them.
+ */
+static void event_device_notify(struct acpi_device *adev, u32 value)
+{
+       struct acpi_buffer event_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *obj;
+       acpi_status status;
+
+       if (value != EC_ACPI_NOTIFY_EVENT) {
+               dev_err(&adev->dev, "Invalid event: 0x%08x\n", value);
+               return;
+       }
+
+       /* Execute ACPI method to get event data buffer. */
+       status = acpi_evaluate_object(adev->handle, EC_ACPI_GET_EVENT,
+                                     NULL, &event_buffer);
+       if (ACPI_FAILURE(status)) {
+               dev_err(&adev->dev, "Error executing ACPI method %s()\n",
+                       EC_ACPI_GET_EVENT);
+               return;
+       }
+
+       obj = (union acpi_object *)event_buffer.pointer;
+       if (!obj) {
+               dev_err(&adev->dev, "Nothing returned from %s()\n",
+                       EC_ACPI_GET_EVENT);
+               return;
+       }
+       if (obj->type != ACPI_TYPE_BUFFER) {
+               dev_err(&adev->dev, "Invalid object returned from %s()\n",
+                       EC_ACPI_GET_EVENT);
+               kfree(obj);
+               return;
+       }
+       if (obj->buffer.length < sizeof(struct ec_event)) {
+               dev_err(&adev->dev, "Invalid buffer length %d from %s()\n",
+                       obj->buffer.length, EC_ACPI_GET_EVENT);
+               kfree(obj);
+               return;
+       }
+
+       enqueue_events(adev, obj->buffer.pointer, obj->buffer.length);
+       kfree(obj);
+}
+
+static int event_open(struct inode *inode, struct file *filp)
+{
+       struct event_device_data *dev_data;
+
+       dev_data = container_of(inode->i_cdev, struct event_device_data, cdev);
+       if (!dev_data->exist)
+               return -ENODEV;
+
+       if (atomic_cmpxchg(&dev_data->available, 1, 0) == 0)
+               return -EBUSY;
+
+       /* Increase refcount on device so dev_data is not freed */
+       get_device(&dev_data->dev);
+       stream_open(inode, filp);
+       filp->private_data = dev_data;
+
+       return 0;
+}
+
+static __poll_t event_poll(struct file *filp, poll_table *wait)
+{
+       struct event_device_data *dev_data = filp->private_data;
+       __poll_t mask = 0;
+
+       poll_wait(filp, &dev_data->wq, wait);
+       if (!dev_data->exist)
+               return EPOLLHUP;
+       if (!event_queue_empty(dev_data->events))
+               mask |= EPOLLIN | EPOLLRDNORM | EPOLLPRI;
+       return mask;
+}
+
+/**
+ * event_read() - Callback for passing event data to userspace via read().
+ * @filp: The file we are reading from.
+ * @buf: Pointer to userspace buffer to fill with one event.
+ * @count: Number of bytes requested. Must be at least EC_ACPI_MAX_EVENT_SIZE.
+ * @pos: File position pointer, irrelevant since we don't support seeking.
+ *
+ * Removes the first event from the queue, places it in the passed buffer.
+ *
+ * If there are no events in the the queue, then one of two things happens,
+ * depending on if the file was opened in nonblocking mode: If in nonblocking
+ * mode, then return -EAGAIN to say there's no data. If in blocking mode, then
+ * block until an event is available.
+ *
+ * Return: Number of bytes placed in buffer, negative error code on failure.
+ */
+static ssize_t event_read(struct file *filp, char __user *buf, size_t count,
+                         loff_t *pos)
+{
+       struct event_device_data *dev_data = filp->private_data;
+       struct ec_event *event;
+       ssize_t n_bytes_written = 0;
+       int err;
+
+       /* We only will give them the entire event at once */
+       if (count != 0 && count < EC_ACPI_MAX_EVENT_SIZE)
+               return -EINVAL;
+
+       spin_lock(&dev_data->queue_lock);
+       while (event_queue_empty(dev_data->events)) {
+               spin_unlock(&dev_data->queue_lock);
+               if (filp->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+
+               err = wait_event_interruptible(dev_data->wq,
+                                       !event_queue_empty(dev_data->events) ||
+                                       !dev_data->exist);
+               if (err)
+                       return err;
+
+               /* Device was removed as we waited? */
+               if (!dev_data->exist)
+                       return -ENODEV;
+               spin_lock(&dev_data->queue_lock);
+       }
+       event = event_queue_pop(dev_data->events);
+       spin_unlock(&dev_data->queue_lock);
+       n_bytes_written = ec_event_size(event);
+       if (copy_to_user(buf, event, n_bytes_written))
+               n_bytes_written = -EFAULT;
+       kfree(event);
+
+       return n_bytes_written;
+}
+
+static int event_release(struct inode *inode, struct file *filp)
+{
+       struct event_device_data *dev_data = filp->private_data;
+
+       atomic_set(&dev_data->available, 1);
+       put_device(&dev_data->dev);
+
+       return 0;
+}
+
+static const struct file_operations event_fops = {
+       .open = event_open,
+       .poll  = event_poll,
+       .read = event_read,
+       .release = event_release,
+       .llseek = no_llseek,
+       .owner = THIS_MODULE,
+};
+
+/**
+ * free_device_data() - Callback to free the event_device_data structure.
+ * @d: The device embedded in our device data, which we have been ref counting.
+ *
+ * This is called only after event_device_remove() has been called and all
+ * userspace programs have called event_release() on all the open file
+ * descriptors.
+ */
+static void free_device_data(struct device *d)
+{
+       struct event_device_data *dev_data;
+
+       dev_data = container_of(d, struct event_device_data, dev);
+       event_queue_free(dev_data->events);
+       kfree(dev_data);
+}
+
+static void hangup_device(struct event_device_data *dev_data)
+{
+       dev_data->exist = false;
+       /* Wake up the waiting processes so they can close. */
+       wake_up_interruptible(&dev_data->wq);
+       put_device(&dev_data->dev);
+}
+
+/**
+ * event_device_add() - Callback when creating a new device.
+ * @adev: ACPI device that we will be receiving events from.
+ *
+ * This finds a free minor number for the device, allocates and initializes
+ * some device data, and creates a new device and char dev node.
+ *
+ * The device data is freed in free_device_data(), which is called when
+ * %dev_data->dev is release()ed. This happens after all references to
+ * %dev_data->dev are dropped, which happens once both event_device_remove()
+ * has been called and every open()ed file descriptor has been release()ed.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+static int event_device_add(struct acpi_device *adev)
+{
+       struct event_device_data *dev_data;
+       int error, minor;
+
+       minor = ida_alloc_max(&event_ida, EVENT_MAX_DEV-1, GFP_KERNEL);
+       if (minor < 0) {
+               error = minor;
+               dev_err(&adev->dev, "Failed to find minor number: %d\n", error);
+               return error;
+       }
+
+       dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL);
+       if (!dev_data) {
+               error = -ENOMEM;
+               goto free_minor;
+       }
+
+       /* Initialize the device data. */
+       adev->driver_data = dev_data;
+       dev_data->events = event_queue_new(queue_size);
+       if (!dev_data->events) {
+               kfree(dev_data);
+               error = -ENOMEM;
+               goto free_minor;
+       }
+       spin_lock_init(&dev_data->queue_lock);
+       init_waitqueue_head(&dev_data->wq);
+       dev_data->exist = true;
+       atomic_set(&dev_data->available, 1);
+
+       /* Initialize the device. */
+       dev_data->dev.devt = MKDEV(event_major, minor);
+       dev_data->dev.class = &event_class;
+       dev_data->dev.release = free_device_data;
+       dev_set_name(&dev_data->dev, EVENT_DEV_NAME_FMT, minor);
+       device_initialize(&dev_data->dev);
+
+       /* Initialize the character device, and add it to userspace. */
+       cdev_init(&dev_data->cdev, &event_fops);
+       error = cdev_device_add(&dev_data->cdev, &dev_data->dev);
+       if (error)
+               goto free_dev_data;
+
+       return 0;
+
+free_dev_data:
+       hangup_device(dev_data);
+free_minor:
+       ida_simple_remove(&event_ida, minor);
+       return error;
+}
+
+static int event_device_remove(struct acpi_device *adev)
+{
+       struct event_device_data *dev_data = adev->driver_data;
+
+       cdev_device_del(&dev_data->cdev, &dev_data->dev);
+       ida_simple_remove(&event_ida, MINOR(dev_data->dev.devt));
+       hangup_device(dev_data);
+
+       return 0;
+}
+
+static const struct acpi_device_id event_acpi_ids[] = {
+       { "GOOG000D", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, event_acpi_ids);
+
+static struct acpi_driver event_driver = {
+       .name = DRV_NAME,
+       .class = DRV_NAME,
+       .ids = event_acpi_ids,
+       .ops = {
+               .add = event_device_add,
+               .notify = event_device_notify,
+               .remove = event_device_remove,
+       },
+       .owner = THIS_MODULE,
+};
+
+static int __init event_module_init(void)
+{
+       dev_t dev_num = 0;
+       int ret;
+
+       ret = class_register(&event_class);
+       if (ret) {
+               pr_err(DRV_NAME ": Failed registering class: %d\n", ret);
+               return ret;
+       }
+
+       /* Request device numbers, starting with minor=0. Save the major num. */
+       ret = alloc_chrdev_region(&dev_num, 0, EVENT_MAX_DEV, EVENT_DEV_NAME);
+       if (ret) {
+               pr_err(DRV_NAME ": Failed allocating dev numbers: %d\n", ret);
+               goto destroy_class;
+       }
+       event_major = MAJOR(dev_num);
+
+       ret = acpi_bus_register_driver(&event_driver);
+       if (ret < 0) {
+               pr_err(DRV_NAME ": Failed registering driver: %d\n", ret);
+               goto unregister_region;
+       }
+
+       return 0;
+
+unregister_region:
+       unregister_chrdev_region(MKDEV(event_major, 0), EVENT_MAX_DEV);
+destroy_class:
+       class_unregister(&event_class);
+       ida_destroy(&event_ida);
+       return ret;
+}
+
+static void __exit event_module_exit(void)
+{
+       acpi_bus_unregister_driver(&event_driver);
+       unregister_chrdev_region(MKDEV(event_major, 0), EVENT_MAX_DEV);
+       class_unregister(&event_class);
+       ida_destroy(&event_ida);
+}
+
+module_init(event_module_init);
+module_exit(event_module_exit);
+
+MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>");
+MODULE_DESCRIPTION("Wilco EC ACPI event driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
index 7fb58b4..ced1f9f 100644 (file)
@@ -119,7 +119,6 @@ static int wilco_ec_transfer(struct wilco_ec_device *ec,
        struct wilco_ec_response *rs;
        u8 checksum;
        u8 flag;
-       size_t size;
 
        /* Write request header, then data */
        cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE, 0, sizeof(*rq), (u8 *)rq);
@@ -148,21 +147,11 @@ static int wilco_ec_transfer(struct wilco_ec_device *ec,
                return -EIO;
        }
 
-       /*
-        * The EC always returns either EC_MAILBOX_DATA_SIZE or
-        * EC_MAILBOX_DATA_SIZE_EXTENDED bytes of data, so we need to
-        * calculate the checksum on **all** of this data, even if we
-        * won't use all of it.
-        */
-       if (msg->flags & WILCO_EC_FLAG_EXTENDED_DATA)
-               size = EC_MAILBOX_DATA_SIZE_EXTENDED;
-       else
-               size = EC_MAILBOX_DATA_SIZE;
-
        /* Read back response */
        rs = ec->data_buffer;
        checksum = cros_ec_lpc_io_bytes_mec(MEC_IO_READ, 0,
-                                           sizeof(*rs) + size, (u8 *)rs);
+                                           sizeof(*rs) + EC_MAILBOX_DATA_SIZE,
+                                           (u8 *)rs);
        if (checksum) {
                dev_dbg(ec->dev, "bad packet checksum 0x%02x\n", rs->checksum);
                return -EBADMSG;
@@ -173,9 +162,9 @@ static int wilco_ec_transfer(struct wilco_ec_device *ec,
                return -EBADMSG;
        }
 
-       if (rs->data_size != size) {
-               dev_dbg(ec->dev, "unexpected packet size (%u != %zu)",
-                       rs->data_size, size);
+       if (rs->data_size != EC_MAILBOX_DATA_SIZE) {
+               dev_dbg(ec->dev, "unexpected packet size (%u != %u)",
+                       rs->data_size, EC_MAILBOX_DATA_SIZE);
                return -EMSGSIZE;
        }
 
diff --git a/drivers/platform/chrome/wilco_ec/properties.c b/drivers/platform/chrome/wilco_ec/properties.c
new file mode 100644 (file)
index 0000000..e69682c
--- /dev/null
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#include <linux/platform_data/wilco-ec.h>
+#include <linux/string.h>
+#include <linux/unaligned/le_memmove.h>
+
+/* Operation code; what the EC should do with the property */
+enum ec_property_op {
+       EC_OP_GET = 0,
+       EC_OP_SET = 1,
+};
+
+struct ec_property_request {
+       u8 op; /* One of enum ec_property_op */
+       u8 property_id[4]; /* The 32 bit PID is stored Little Endian */
+       u8 length;
+       u8 data[WILCO_EC_PROPERTY_MAX_SIZE];
+} __packed;
+
+struct ec_property_response {
+       u8 reserved[2];
+       u8 op; /* One of enum ec_property_op */
+       u8 property_id[4]; /* The 32 bit PID is stored Little Endian */
+       u8 length;
+       u8 data[WILCO_EC_PROPERTY_MAX_SIZE];
+} __packed;
+
+static int send_property_msg(struct wilco_ec_device *ec,
+                            struct ec_property_request *rq,
+                            struct ec_property_response *rs)
+{
+       struct wilco_ec_message ec_msg;
+       int ret;
+
+       memset(&ec_msg, 0, sizeof(ec_msg));
+       ec_msg.type = WILCO_EC_MSG_PROPERTY;
+       ec_msg.request_data = rq;
+       ec_msg.request_size = sizeof(*rq);
+       ec_msg.response_data = rs;
+       ec_msg.response_size = sizeof(*rs);
+
+       ret = wilco_ec_mailbox(ec, &ec_msg);
+       if (ret < 0)
+               return ret;
+       if (rs->op != rq->op)
+               return -EBADMSG;
+       if (memcmp(rq->property_id, rs->property_id, sizeof(rs->property_id)))
+               return -EBADMSG;
+
+       return 0;
+}
+
+int wilco_ec_get_property(struct wilco_ec_device *ec,
+                         struct wilco_ec_property_msg *prop_msg)
+{
+       struct ec_property_request rq;
+       struct ec_property_response rs;
+       int ret;
+
+       memset(&rq, 0, sizeof(rq));
+       rq.op = EC_OP_GET;
+       put_unaligned_le32(prop_msg->property_id, rq.property_id);
+
+       ret = send_property_msg(ec, &rq, &rs);
+       if (ret < 0)
+               return ret;
+
+       prop_msg->length = rs.length;
+       memcpy(prop_msg->data, rs.data, rs.length);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wilco_ec_get_property);
+
+int wilco_ec_set_property(struct wilco_ec_device *ec,
+                         struct wilco_ec_property_msg *prop_msg)
+{
+       struct ec_property_request rq;
+       struct ec_property_response rs;
+       int ret;
+
+       memset(&rq, 0, sizeof(rq));
+       rq.op = EC_OP_SET;
+       put_unaligned_le32(prop_msg->property_id, rq.property_id);
+       rq.length = prop_msg->length;
+       memcpy(rq.data, prop_msg->data, prop_msg->length);
+
+       ret = send_property_msg(ec, &rq, &rs);
+       if (ret < 0)
+               return ret;
+       if (rs.length != prop_msg->length)
+               return -EBADMSG;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wilco_ec_set_property);
+
+int wilco_ec_get_byte_property(struct wilco_ec_device *ec, u32 property_id,
+                              u8 *val)
+{
+       struct wilco_ec_property_msg msg;
+       int ret;
+
+       msg.property_id = property_id;
+
+       ret = wilco_ec_get_property(ec, &msg);
+       if (ret < 0)
+               return ret;
+       if (msg.length != 1)
+               return -EBADMSG;
+
+       *val = msg.data[0];
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wilco_ec_get_byte_property);
+
+int wilco_ec_set_byte_property(struct wilco_ec_device *ec, u32 property_id,
+                              u8 val)
+{
+       struct wilco_ec_property_msg msg;
+
+       msg.property_id = property_id;
+       msg.data[0] = val;
+       msg.length = 1;
+
+       return wilco_ec_set_property(ec, &msg);
+}
+EXPORT_SYMBOL_GPL(wilco_ec_set_byte_property);
diff --git a/drivers/platform/chrome/wilco_ec/sysfs.c b/drivers/platform/chrome/wilco_ec/sysfs.c
new file mode 100644 (file)
index 0000000..3b86a21
--- /dev/null
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Sysfs properties to view and modify EC-controlled features on Wilco devices.
+ * The entries will appear under /sys/bus/platform/devices/GOOG000C:00/
+ *
+ * See Documentation/ABI/testing/sysfs-platform-wilco-ec for more information.
+ */
+
+#include <linux/platform_data/wilco-ec.h>
+#include <linux/sysfs.h>
+
+#define CMD_KB_CMOS                    0x7C
+#define SUB_CMD_KB_CMOS_AUTO_ON                0x03
+
+struct boot_on_ac_request {
+       u8 cmd;                 /* Always CMD_KB_CMOS */
+       u8 reserved1;
+       u8 sub_cmd;             /* Always SUB_CMD_KB_CMOS_AUTO_ON */
+       u8 reserved3to5[3];
+       u8 val;                 /* Either 0 or 1 */
+       u8 reserved7;
+} __packed;
+
+#define CMD_EC_INFO                    0x38
+enum get_ec_info_op {
+       CMD_GET_EC_LABEL        = 0,
+       CMD_GET_EC_REV          = 1,
+       CMD_GET_EC_MODEL        = 2,
+       CMD_GET_EC_BUILD_DATE   = 3,
+};
+
+struct get_ec_info_req {
+       u8 cmd;                 /* Always CMD_EC_INFO */
+       u8 reserved;
+       u8 op;                  /* One of enum get_ec_info_op */
+} __packed;
+
+struct get_ec_info_resp {
+       u8 reserved[2];
+       char value[9]; /* __nonstring: might not be null terminated */
+} __packed;
+
+static ssize_t boot_on_ac_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct wilco_ec_device *ec = dev_get_drvdata(dev);
+       struct boot_on_ac_request rq;
+       struct wilco_ec_message msg;
+       int ret;
+       u8 val;
+
+       ret = kstrtou8(buf, 10, &val);
+       if (ret < 0)
+               return ret;
+       if (val > 1)
+               return -EINVAL;
+
+       memset(&rq, 0, sizeof(rq));
+       rq.cmd = CMD_KB_CMOS;
+       rq.sub_cmd = SUB_CMD_KB_CMOS_AUTO_ON;
+       rq.val = val;
+
+       memset(&msg, 0, sizeof(msg));
+       msg.type = WILCO_EC_MSG_LEGACY;
+       msg.request_data = &rq;
+       msg.request_size = sizeof(rq);
+       ret = wilco_ec_mailbox(ec, &msg);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static DEVICE_ATTR_WO(boot_on_ac);
+
+static ssize_t get_info(struct device *dev, char *buf, enum get_ec_info_op op)
+{
+       struct wilco_ec_device *ec = dev_get_drvdata(dev);
+       struct get_ec_info_req req = { .cmd = CMD_EC_INFO, .op = op };
+       struct get_ec_info_resp resp;
+       int ret;
+
+       struct wilco_ec_message msg = {
+               .type = WILCO_EC_MSG_LEGACY,
+               .request_data = &req,
+               .request_size = sizeof(req),
+               .response_data = &resp,
+               .response_size = sizeof(resp),
+       };
+
+       ret = wilco_ec_mailbox(ec, &msg);
+       if (ret < 0)
+               return ret;
+
+       return scnprintf(buf, PAGE_SIZE, "%.*s\n", (int)sizeof(resp.value),
+                        (char *)&resp.value);
+}
+
+static ssize_t version_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       return get_info(dev, buf, CMD_GET_EC_LABEL);
+}
+
+static DEVICE_ATTR_RO(version);
+
+static ssize_t build_revision_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       return get_info(dev, buf, CMD_GET_EC_REV);
+}
+
+static DEVICE_ATTR_RO(build_revision);
+
+static ssize_t build_date_show(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       return get_info(dev, buf, CMD_GET_EC_BUILD_DATE);
+}
+
+static DEVICE_ATTR_RO(build_date);
+
+static ssize_t model_number_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       return get_info(dev, buf, CMD_GET_EC_MODEL);
+}
+
+static DEVICE_ATTR_RO(model_number);
+
+
+static struct attribute *wilco_dev_attrs[] = {
+       &dev_attr_boot_on_ac.attr,
+       &dev_attr_build_date.attr,
+       &dev_attr_build_revision.attr,
+       &dev_attr_model_number.attr,
+       &dev_attr_version.attr,
+       NULL,
+};
+
+static struct attribute_group wilco_dev_attr_group = {
+       .attrs = wilco_dev_attrs,
+};
+
+int wilco_ec_add_sysfs(struct wilco_ec_device *ec)
+{
+       return sysfs_create_group(&ec->dev->kobj, &wilco_dev_attr_group);
+}
+
+void wilco_ec_remove_sysfs(struct wilco_ec_device *ec)
+{
+       sysfs_remove_group(&ec->dev->kobj, &wilco_dev_attr_group);
+}
diff --git a/drivers/platform/chrome/wilco_ec/telemetry.c b/drivers/platform/chrome/wilco_ec/telemetry.c
new file mode 100644 (file)
index 0000000..94cdc16
--- /dev/null
@@ -0,0 +1,450 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Telemetry communication for Wilco EC
+ *
+ * Copyright 2019 Google LLC
+ *
+ * The Wilco Embedded Controller is able to send telemetry data
+ * which is useful for enterprise applications. A daemon running on
+ * the OS sends a command to the EC via a write() to a char device,
+ * and can read the response with a read(). The write() request is
+ * verified by the driver to ensure that it is performing only one
+ * of the whitelisted commands, and that no extraneous data is
+ * being transmitted to the EC. The response is passed directly
+ * back to the reader with no modification.
+ *
+ * The character device will appear as /dev/wilco_telemN, where N
+ * is some small non-negative integer, starting with 0. Only one
+ * process may have the file descriptor open at a time. The calling
+ * userspace program needs to keep the device file descriptor open
+ * between the calls to write() and read() in order to preserve the
+ * response. Up to 32 bytes will be available for reading.
+ *
+ * For testing purposes, try requesting the EC's firmware build
+ * date, by sending the WILCO_EC_TELEM_GET_VERSION command with
+ * argument index=3. i.e. write [0x38, 0x00, 0x03]
+ * to the device node. An ASCII string of the build date is
+ * returned.
+ */
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/platform_data/wilco-ec.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+
+#define TELEM_DEV_NAME         "wilco_telem"
+#define TELEM_CLASS_NAME       TELEM_DEV_NAME
+#define DRV_NAME               TELEM_DEV_NAME
+#define TELEM_DEV_NAME_FMT     (TELEM_DEV_NAME "%d")
+static struct class telem_class = {
+       .owner  = THIS_MODULE,
+       .name   = TELEM_CLASS_NAME,
+};
+
+/* Keep track of all the device numbers used. */
+#define TELEM_MAX_DEV 128
+static int telem_major;
+static DEFINE_IDA(telem_ida);
+
+/* EC telemetry command codes */
+#define WILCO_EC_TELEM_GET_LOG                 0x99
+#define WILCO_EC_TELEM_GET_VERSION             0x38
+#define WILCO_EC_TELEM_GET_FAN_INFO            0x2E
+#define WILCO_EC_TELEM_GET_DIAG_INFO           0xFA
+#define WILCO_EC_TELEM_GET_TEMP_INFO           0x95
+#define WILCO_EC_TELEM_GET_TEMP_READ           0x2C
+#define WILCO_EC_TELEM_GET_BATT_EXT_INFO       0x07
+
+#define TELEM_ARGS_SIZE_MAX    30
+
+/**
+ * struct wilco_ec_telem_request - Telemetry command and arguments sent to EC.
+ * @command: One of WILCO_EC_TELEM_GET_* command codes.
+ * @reserved: Must be 0.
+ * @args: The first N bytes are one of telem_args_get_* structs, the rest is 0.
+ */
+struct wilco_ec_telem_request {
+       u8 command;
+       u8 reserved;
+       u8 args[TELEM_ARGS_SIZE_MAX];
+} __packed;
+
+/*
+ * The following telem_args_get_* structs are embedded within the |args| field
+ * of wilco_ec_telem_request.
+ */
+
+struct telem_args_get_log {
+       u8 log_type;
+       u8 log_index;
+} __packed;
+
+/*
+ * Get a piece of info about the EC firmware version:
+ * 0 = label
+ * 1 = svn_rev
+ * 2 = model_no
+ * 3 = build_date
+ * 4 = frio_version
+ */
+struct telem_args_get_version {
+       u8 index;
+} __packed;
+
+struct telem_args_get_fan_info {
+       u8 command;
+       u8 fan_number;
+       u8 arg;
+} __packed;
+
+struct telem_args_get_diag_info {
+       u8 type;
+       u8 sub_type;
+} __packed;
+
+struct telem_args_get_temp_info {
+       u8 command;
+       u8 index;
+       u8 field;
+       u8 zone;
+} __packed;
+
+struct telem_args_get_temp_read {
+       u8 sensor_index;
+} __packed;
+
+struct telem_args_get_batt_ext_info {
+       u8 var_args[5];
+} __packed;
+
+/**
+ * check_telem_request() - Ensure that a request from userspace is valid.
+ * @rq: Request buffer copied from userspace.
+ * @size: Number of bytes copied from userspace.
+ *
+ * Return: 0 if valid, -EINVAL if bad command or reserved byte is non-zero,
+ *         -EMSGSIZE if the request is too long.
+ *
+ * We do not want to allow userspace to send arbitrary telemetry commands to
+ * the EC. Therefore we check to ensure that
+ * 1. The request follows the format of struct wilco_ec_telem_request.
+ * 2. The supplied command code is one of the whitelisted commands.
+ * 3. The request only contains the necessary data for the header and arguments.
+ */
+static int check_telem_request(struct wilco_ec_telem_request *rq,
+                              size_t size)
+{
+       size_t max_size = offsetof(struct wilco_ec_telem_request, args);
+
+       if (rq->reserved)
+               return -EINVAL;
+
+       switch (rq->command) {
+       case WILCO_EC_TELEM_GET_LOG:
+               max_size += sizeof(struct telem_args_get_log);
+               break;
+       case WILCO_EC_TELEM_GET_VERSION:
+               max_size += sizeof(struct telem_args_get_version);
+               break;
+       case WILCO_EC_TELEM_GET_FAN_INFO:
+               max_size += sizeof(struct telem_args_get_fan_info);
+               break;
+       case WILCO_EC_TELEM_GET_DIAG_INFO:
+               max_size += sizeof(struct telem_args_get_diag_info);
+               break;
+       case WILCO_EC_TELEM_GET_TEMP_INFO:
+               max_size += sizeof(struct telem_args_get_temp_info);
+               break;
+       case WILCO_EC_TELEM_GET_TEMP_READ:
+               max_size += sizeof(struct telem_args_get_temp_read);
+               break;
+       case WILCO_EC_TELEM_GET_BATT_EXT_INFO:
+               max_size += sizeof(struct telem_args_get_batt_ext_info);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return (size <= max_size) ? 0 : -EMSGSIZE;
+}
+
+/**
+ * struct telem_device_data - Data for a Wilco EC device that queries telemetry.
+ * @cdev: Char dev that userspace reads and polls from.
+ * @dev: Device associated with the %cdev.
+ * @ec: Wilco EC that we will be communicating with using the mailbox interface.
+ * @available: Boolean of if the device can be opened.
+ */
+struct telem_device_data {
+       struct device dev;
+       struct cdev cdev;
+       struct wilco_ec_device *ec;
+       atomic_t available;
+};
+
+#define TELEM_RESPONSE_SIZE    EC_MAILBOX_DATA_SIZE
+
+/**
+ * struct telem_session_data - Data that exists between open() and release().
+ * @dev_data: Pointer to get back to the device data and EC.
+ * @request: Command and arguments sent to EC.
+ * @response: Response buffer of data from EC.
+ * @has_msg: Is there data available to read from a previous write?
+ */
+struct telem_session_data {
+       struct telem_device_data *dev_data;
+       struct wilco_ec_telem_request request;
+       u8 response[TELEM_RESPONSE_SIZE];
+       bool has_msg;
+};
+
+/**
+ * telem_open() - Callback for when the device node is opened.
+ * @inode: inode for this char device node.
+ * @filp: file for this char device node.
+ *
+ * We need to ensure that after writing a command to the device,
+ * the same userspace process reads the corresponding result.
+ * Therefore, we increment a refcount on opening the device, so that
+ * only one process can communicate with the EC at a time.
+ *
+ * Return: 0 on success, or negative error code on failure.
+ */
+static int telem_open(struct inode *inode, struct file *filp)
+{
+       struct telem_device_data *dev_data;
+       struct telem_session_data *sess_data;
+
+       /* Ensure device isn't already open */
+       dev_data = container_of(inode->i_cdev, struct telem_device_data, cdev);
+       if (atomic_cmpxchg(&dev_data->available, 1, 0) == 0)
+               return -EBUSY;
+
+       get_device(&dev_data->dev);
+
+       sess_data = kzalloc(sizeof(*sess_data), GFP_KERNEL);
+       if (!sess_data) {
+               atomic_set(&dev_data->available, 1);
+               return -ENOMEM;
+       }
+       sess_data->dev_data = dev_data;
+       sess_data->has_msg = false;
+
+       nonseekable_open(inode, filp);
+       filp->private_data = sess_data;
+
+       return 0;
+}
+
+static ssize_t telem_write(struct file *filp, const char __user *buf,
+                          size_t count, loff_t *pos)
+{
+       struct telem_session_data *sess_data = filp->private_data;
+       struct wilco_ec_message msg = {};
+       int ret;
+
+       if (count > sizeof(sess_data->request))
+               return -EMSGSIZE;
+       if (copy_from_user(&sess_data->request, buf, count))
+               return -EFAULT;
+       ret = check_telem_request(&sess_data->request, count);
+       if (ret < 0)
+               return ret;
+
+       memset(sess_data->response, 0, sizeof(sess_data->response));
+       msg.type = WILCO_EC_MSG_TELEMETRY;
+       msg.request_data = &sess_data->request;
+       msg.request_size = sizeof(sess_data->request);
+       msg.response_data = sess_data->response;
+       msg.response_size = sizeof(sess_data->response);
+
+       ret = wilco_ec_mailbox(sess_data->dev_data->ec, &msg);
+       if (ret < 0)
+               return ret;
+       if (ret != sizeof(sess_data->response))
+               return -EMSGSIZE;
+
+       sess_data->has_msg = true;
+
+       return count;
+}
+
+static ssize_t telem_read(struct file *filp, char __user *buf, size_t count,
+                         loff_t *pos)
+{
+       struct telem_session_data *sess_data = filp->private_data;
+
+       if (!sess_data->has_msg)
+               return -ENODATA;
+       if (count > sizeof(sess_data->response))
+               return -EINVAL;
+
+       if (copy_to_user(buf, sess_data->response, count))
+               return -EFAULT;
+
+       sess_data->has_msg = false;
+
+       return count;
+}
+
+static int telem_release(struct inode *inode, struct file *filp)
+{
+       struct telem_session_data *sess_data = filp->private_data;
+
+       atomic_set(&sess_data->dev_data->available, 1);
+       put_device(&sess_data->dev_data->dev);
+       kfree(sess_data);
+
+       return 0;
+}
+
+static const struct file_operations telem_fops = {
+       .open = telem_open,
+       .write = telem_write,
+       .read = telem_read,
+       .release = telem_release,
+       .llseek = no_llseek,
+       .owner = THIS_MODULE,
+};
+
+/**
+ * telem_device_free() - Callback to free the telem_device_data structure.
+ * @d: The device embedded in our device data, which we have been ref counting.
+ *
+ * Once all open file descriptors are closed and the device has been removed,
+ * the refcount of the device will fall to 0 and this will be called.
+ */
+static void telem_device_free(struct device *d)
+{
+       struct telem_device_data *dev_data;
+
+       dev_data = container_of(d, struct telem_device_data, dev);
+       kfree(dev_data);
+}
+
+/**
+ * telem_device_probe() - Callback when creating a new device.
+ * @pdev: platform device that we will be receiving telems from.
+ *
+ * This finds a free minor number for the device, allocates and initializes
+ * some device data, and creates a new device and char dev node.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+static int telem_device_probe(struct platform_device *pdev)
+{
+       struct telem_device_data *dev_data;
+       int error, minor;
+
+       /* Get the next available device number */
+       minor = ida_alloc_max(&telem_ida, TELEM_MAX_DEV-1, GFP_KERNEL);
+       if (minor < 0) {
+               error = minor;
+               dev_err(&pdev->dev, "Failed to find minor number: %d", error);
+               return error;
+       }
+
+       dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL);
+       if (!dev_data) {
+               ida_simple_remove(&telem_ida, minor);
+               return -ENOMEM;
+       }
+
+       /* Initialize the device data */
+       dev_data->ec = dev_get_platdata(&pdev->dev);
+       atomic_set(&dev_data->available, 1);
+       platform_set_drvdata(pdev, dev_data);
+
+       /* Initialize the device */
+       dev_data->dev.devt = MKDEV(telem_major, minor);
+       dev_data->dev.class = &telem_class;
+       dev_data->dev.release = telem_device_free;
+       dev_set_name(&dev_data->dev, TELEM_DEV_NAME_FMT, minor);
+       device_initialize(&dev_data->dev);
+
+       /* Initialize the character device and add it to userspace */;
+       cdev_init(&dev_data->cdev, &telem_fops);
+       error = cdev_device_add(&dev_data->cdev, &dev_data->dev);
+       if (error) {
+               put_device(&dev_data->dev);
+               ida_simple_remove(&telem_ida, minor);
+               return error;
+       }
+
+       return 0;
+}
+
+static int telem_device_remove(struct platform_device *pdev)
+{
+       struct telem_device_data *dev_data = platform_get_drvdata(pdev);
+
+       cdev_device_del(&dev_data->cdev, &dev_data->dev);
+       put_device(&dev_data->dev);
+       ida_simple_remove(&telem_ida, MINOR(dev_data->dev.devt));
+
+       return 0;
+}
+
+static struct platform_driver telem_driver = {
+       .probe = telem_device_probe,
+       .remove = telem_device_remove,
+       .driver = {
+               .name = DRV_NAME,
+       },
+};
+
+static int __init telem_module_init(void)
+{
+       dev_t dev_num = 0;
+       int ret;
+
+       ret = class_register(&telem_class);
+       if (ret) {
+               pr_err(DRV_NAME ": Failed registering class: %d", ret);
+               return ret;
+       }
+
+       /* Request the kernel for device numbers, starting with minor=0 */
+       ret = alloc_chrdev_region(&dev_num, 0, TELEM_MAX_DEV, TELEM_DEV_NAME);
+       if (ret) {
+               pr_err(DRV_NAME ": Failed allocating dev numbers: %d", ret);
+               goto destroy_class;
+       }
+       telem_major = MAJOR(dev_num);
+
+       ret = platform_driver_register(&telem_driver);
+       if (ret < 0) {
+               pr_err(DRV_NAME ": Failed registering driver: %d\n", ret);
+               goto unregister_region;
+       }
+
+       return 0;
+
+unregister_region:
+       unregister_chrdev_region(MKDEV(telem_major, 0), TELEM_MAX_DEV);
+destroy_class:
+       class_unregister(&telem_class);
+       ida_destroy(&telem_ida);
+       return ret;
+}
+
+static void __exit telem_module_exit(void)
+{
+       platform_driver_unregister(&telem_driver);
+       unregister_chrdev_region(MKDEV(telem_major, 0), TELEM_MAX_DEV);
+       class_unregister(&telem_class);
+       ida_destroy(&telem_ida);
+}
+
+module_init(telem_module_init);
+module_exit(telem_module_exit);
+
+MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>");
+MODULE_DESCRIPTION("Wilco EC telemetry driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
index b7e5cee..6053d01 100644 (file)
@@ -341,7 +341,7 @@ config HP_ACCEL
 
          Support for a led indicating disk protection will be provided as
          hp::hddprotect. For more information on the feature, refer to
-         Documentation/misc-devices/lis3lv02d.
+         Documentation/misc-devices/lis3lv02d.rst.
 
          To compile this driver as a module, choose M here: the module will
          be called hp_accel.
index e03304f..6cca727 100644 (file)
@@ -70,7 +70,6 @@ MODULE_LICENSE("GPL");
  * SECTION: prototypes for static functions of dasd.c
  */
 static int  dasd_alloc_queue(struct dasd_block *);
-static void dasd_setup_queue(struct dasd_block *);
 static void dasd_free_queue(struct dasd_block *);
 static int dasd_flush_block_queue(struct dasd_block *);
 static void dasd_device_tasklet(unsigned long);
@@ -120,9 +119,18 @@ struct dasd_device *dasd_alloc_device(void)
                kfree(device);
                return ERR_PTR(-ENOMEM);
        }
+       /* Get two pages for ese format. */
+       device->ese_mem = (void *)__get_free_pages(GFP_ATOMIC | GFP_DMA, 1);
+       if (!device->ese_mem) {
+               free_page((unsigned long) device->erp_mem);
+               free_pages((unsigned long) device->ccw_mem, 1);
+               kfree(device);
+               return ERR_PTR(-ENOMEM);
+       }
 
        dasd_init_chunklist(&device->ccw_chunks, device->ccw_mem, PAGE_SIZE*2);
        dasd_init_chunklist(&device->erp_chunks, device->erp_mem, PAGE_SIZE);
+       dasd_init_chunklist(&device->ese_chunks, device->ese_mem, PAGE_SIZE * 2);
        spin_lock_init(&device->mem_lock);
        atomic_set(&device->tasklet_scheduled, 0);
        tasklet_init(&device->tasklet, dasd_device_tasklet,
@@ -146,6 +154,7 @@ struct dasd_device *dasd_alloc_device(void)
 void dasd_free_device(struct dasd_device *device)
 {
        kfree(device->private);
+       free_pages((unsigned long) device->ese_mem, 1);
        free_page((unsigned long) device->erp_mem);
        free_pages((unsigned long) device->ccw_mem, 1);
        kfree(device);
@@ -348,7 +357,8 @@ static int dasd_state_basic_to_ready(struct dasd_device *device)
                        }
                        return rc;
                }
-               dasd_setup_queue(block);
+               if (device->discipline->setup_blk_queue)
+                       device->discipline->setup_blk_queue(block);
                set_capacity(block->gdp,
                             block->blocks << block->s2b_shift);
                device->state = DASD_STATE_READY;
@@ -1258,6 +1268,49 @@ struct dasd_ccw_req *dasd_smalloc_request(int magic, int cplength, int datasize,
 }
 EXPORT_SYMBOL(dasd_smalloc_request);
 
+struct dasd_ccw_req *dasd_fmalloc_request(int magic, int cplength,
+                                         int datasize,
+                                         struct dasd_device *device)
+{
+       struct dasd_ccw_req *cqr;
+       unsigned long flags;
+       int size, cqr_size;
+       char *data;
+
+       cqr_size = (sizeof(*cqr) + 7L) & -8L;
+       size = cqr_size;
+       if (cplength > 0)
+               size += cplength * sizeof(struct ccw1);
+       if (datasize > 0)
+               size += datasize;
+
+       spin_lock_irqsave(&device->mem_lock, flags);
+       cqr = dasd_alloc_chunk(&device->ese_chunks, size);
+       spin_unlock_irqrestore(&device->mem_lock, flags);
+       if (!cqr)
+               return ERR_PTR(-ENOMEM);
+       memset(cqr, 0, sizeof(*cqr));
+       data = (char *)cqr + cqr_size;
+       cqr->cpaddr = NULL;
+       if (cplength > 0) {
+               cqr->cpaddr = data;
+               data += cplength * sizeof(struct ccw1);
+               memset(cqr->cpaddr, 0, cplength * sizeof(struct ccw1));
+       }
+       cqr->data = NULL;
+       if (datasize > 0) {
+               cqr->data = data;
+               memset(cqr->data, 0, datasize);
+       }
+
+       cqr->magic = magic;
+       set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+       dasd_get_device(device);
+
+       return cqr;
+}
+EXPORT_SYMBOL(dasd_fmalloc_request);
+
 void dasd_sfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
 {
        unsigned long flags;
@@ -1269,6 +1322,17 @@ void dasd_sfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
 }
 EXPORT_SYMBOL(dasd_sfree_request);
 
+void dasd_ffree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&device->mem_lock, flags);
+       dasd_free_chunk(&device->ese_chunks, cqr);
+       spin_unlock_irqrestore(&device->mem_lock, flags);
+       dasd_put_device(device);
+}
+EXPORT_SYMBOL(dasd_ffree_request);
+
 /*
  * Check discipline magic in cqr.
  */
@@ -1573,13 +1637,43 @@ static int dasd_check_hpf_error(struct irb *irb)
             irb->scsw.tm.sesq == SCSW_SESQ_PATH_NOFCX));
 }
 
+static int dasd_ese_needs_format(struct dasd_block *block, struct irb *irb)
+{
+       struct dasd_device *device = NULL;
+       u8 *sense = NULL;
+
+       if (!block)
+               return 0;
+       device = block->base;
+       if (!device || !device->discipline->is_ese)
+               return 0;
+       if (!device->discipline->is_ese(device))
+               return 0;
+
+       sense = dasd_get_sense(irb);
+       if (!sense)
+               return 0;
+
+       return !!(sense[1] & SNS1_NO_REC_FOUND) ||
+               !!(sense[1] & SNS1_FILE_PROTECTED) ||
+               scsw_cstat(&irb->scsw) == SCHN_STAT_INCORR_LEN;
+}
+
+static int dasd_ese_oos_cond(u8 *sense)
+{
+       return sense[0] & SNS0_EQUIPMENT_CHECK &&
+               sense[1] & SNS1_PERM_ERR &&
+               sense[1] & SNS1_WRITE_INHIBITED &&
+               sense[25] == 0x01;
+}
+
 /*
  * Interrupt handler for "normal" ssch-io based dasd devices.
  */
 void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
                      struct irb *irb)
 {
-       struct dasd_ccw_req *cqr, *next;
+       struct dasd_ccw_req *cqr, *next, *fcqr;
        struct dasd_device *device;
        unsigned long now;
        int nrf_suppressed = 0;
@@ -1641,6 +1735,17 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
                                test_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags);
                        nrf_suppressed = (sense[1] & SNS1_NO_REC_FOUND) &&
                                test_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags);
+
+                       /*
+                        * Extent pool probably out-of-space.
+                        * Stop device and check exhaust level.
+                        */
+                       if (dasd_ese_oos_cond(sense)) {
+                               dasd_generic_space_exhaust(device, cqr);
+                               device->discipline->ext_pool_exhaust(device, cqr);
+                               dasd_put_device(device);
+                               return;
+                       }
                }
                if (!(fp_suppressed || nrf_suppressed))
                        device->discipline->dump_sense_dbf(device, irb, "int");
@@ -1672,6 +1777,31 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
                return;
        }
 
+       if (dasd_ese_needs_format(cqr->block, irb)) {
+               if (rq_data_dir((struct request *)cqr->callback_data) == READ) {
+                       device->discipline->ese_read(cqr);
+                       cqr->status = DASD_CQR_SUCCESS;
+                       cqr->stopclk = now;
+                       dasd_device_clear_timer(device);
+                       dasd_schedule_device_bh(device);
+                       return;
+               }
+               fcqr = device->discipline->ese_format(device, cqr);
+               if (IS_ERR(fcqr)) {
+                       /*
+                        * If we can't format now, let the request go
+                        * one extra round. Maybe we can format later.
+                        */
+                       cqr->status = DASD_CQR_QUEUED;
+               } else {
+                       fcqr->status = DASD_CQR_QUEUED;
+                       cqr->status = DASD_CQR_QUEUED;
+                       list_add(&fcqr->devlist, &device->ccw_queue);
+                       dasd_schedule_device_bh(device);
+                       return;
+               }
+       }
+
        /* Check for clear pending */
        if (cqr->status == DASD_CQR_CLEAR_PENDING &&
            scsw_fctl(&irb->scsw) & SCSW_FCTL_CLEAR_FUNC) {
@@ -1910,7 +2040,7 @@ static void __dasd_device_check_expire(struct dasd_device *device)
 static int __dasd_device_is_unusable(struct dasd_device *device,
                                     struct dasd_ccw_req *cqr)
 {
-       int mask = ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM);
+       int mask = ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM | DASD_STOPPED_NOSPC);
 
        if (test_bit(DASD_FLAG_OFFLINE, &device->flags) &&
            !test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) {
@@ -2411,6 +2541,15 @@ int dasd_sleep_on_queue(struct list_head *ccw_queue)
 }
 EXPORT_SYMBOL(dasd_sleep_on_queue);
 
+/*
+ * Start requests from a ccw_queue and wait interruptible for their completion.
+ */
+int dasd_sleep_on_queue_interruptible(struct list_head *ccw_queue)
+{
+       return _dasd_sleep_on_queue(ccw_queue, 1);
+}
+EXPORT_SYMBOL(dasd_sleep_on_queue_interruptible);
+
 /*
  * Queue a request to the tail of the device ccw_queue and wait
  * interruptible for it's completion.
@@ -3129,55 +3268,6 @@ static int dasd_alloc_queue(struct dasd_block *block)
        return 0;
 }
 
-/*
- * Allocate and initialize request queue.
- */
-static void dasd_setup_queue(struct dasd_block *block)
-{
-       unsigned int logical_block_size = block->bp_block;
-       struct request_queue *q = block->request_queue;
-       unsigned int max_bytes, max_discard_sectors;
-       int max;
-
-       if (block->base->features & DASD_FEATURE_USERAW) {
-               /*
-                * the max_blocks value for raw_track access is 256
-                * it is higher than the native ECKD value because we
-                * only need one ccw per track
-                * so the max_hw_sectors are
-                * 2048 x 512B = 1024kB = 16 tracks
-                */
-               max = 2048;
-       } else {
-               max = block->base->discipline->max_blocks << block->s2b_shift;
-       }
-       blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
-       q->limits.max_dev_sectors = max;
-       blk_queue_logical_block_size(q, logical_block_size);
-       blk_queue_max_hw_sectors(q, max);
-       blk_queue_max_segments(q, USHRT_MAX);
-       /* with page sized segments we can translate each segement into
-        * one idaw/tidaw
-        */
-       blk_queue_max_segment_size(q, PAGE_SIZE);
-       blk_queue_segment_boundary(q, PAGE_SIZE - 1);
-
-       /* Only activate blocklayer discard support for devices that support it */
-       if (block->base->features & DASD_FEATURE_DISCARD) {
-               q->limits.discard_granularity = logical_block_size;
-               q->limits.discard_alignment = PAGE_SIZE;
-
-               /* Calculate max_discard_sectors and make it PAGE aligned */
-               max_bytes = USHRT_MAX * logical_block_size;
-               max_bytes = ALIGN(max_bytes, PAGE_SIZE) - PAGE_SIZE;
-               max_discard_sectors = max_bytes / logical_block_size;
-
-               blk_queue_max_discard_sectors(q, max_discard_sectors);
-               blk_queue_max_write_zeroes_sectors(q, max_discard_sectors);
-               blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
-       }
-}
-
 /*
  * Deactivate and free request queue.
  */
@@ -3806,6 +3896,43 @@ int dasd_generic_verify_path(struct dasd_device *device, __u8 lpm)
 }
 EXPORT_SYMBOL_GPL(dasd_generic_verify_path);
 
+void dasd_generic_space_exhaust(struct dasd_device *device,
+                               struct dasd_ccw_req *cqr)
+{
+       dasd_eer_write(device, NULL, DASD_EER_NOSPC);
+
+       if (device->state < DASD_STATE_BASIC)
+               return;
+
+       if (cqr->status == DASD_CQR_IN_IO ||
+           cqr->status == DASD_CQR_CLEAR_PENDING) {
+               cqr->status = DASD_CQR_QUEUED;
+               cqr->retries++;
+       }
+       dasd_device_set_stop_bits(device, DASD_STOPPED_NOSPC);
+       dasd_device_clear_timer(device);
+       dasd_schedule_device_bh(device);
+}
+EXPORT_SYMBOL_GPL(dasd_generic_space_exhaust);
+
+void dasd_generic_space_avail(struct dasd_device *device)
+{
+       dev_info(&device->cdev->dev, "Extent pool space is available\n");
+       DBF_DEV_EVENT(DBF_WARNING, device, "%s", "space available");
+
+       dasd_device_remove_stop_bits(device, DASD_STOPPED_NOSPC);
+       dasd_schedule_device_bh(device);
+
+       if (device->block) {
+               dasd_schedule_block_bh(device->block);
+               if (device->block->request_queue)
+                       blk_mq_run_hw_queues(device->block->request_queue, true);
+       }
+       if (!device->stopped)
+               wake_up(&generic_waitq);
+}
+EXPORT_SYMBOL_GPL(dasd_generic_space_avail);
+
 /*
  * clear active requests and requeue them to block layer if possible
  */
index 245f33c..32fc513 100644 (file)
@@ -1642,6 +1642,35 @@ static DEVICE_ATTR(path_interval, 0644, dasd_path_interval_show,
                   dasd_path_interval_store);
 
 
+#define DASD_DEFINE_ATTR(_name, _func)                                 \
+static ssize_t dasd_##_name##_show(struct device *dev,                 \
+                                  struct device_attribute *attr,       \
+                                  char *buf)                           \
+{                                                                      \
+       struct ccw_device *cdev = to_ccwdev(dev);                       \
+       struct dasd_device *device = dasd_device_from_cdev(cdev);       \
+       int val = 0;                                                    \
+                                                                       \
+       if (IS_ERR(device))                                             \
+               return -ENODEV;                                         \
+       if (device->discipline && _func)                                \
+               val = _func(device);                                    \
+       dasd_put_device(device);                                        \
+                                                                       \
+       return snprintf(buf, PAGE_SIZE, "%d\n", val);                   \
+}                                                                      \
+static DEVICE_ATTR(_name, 0444, dasd_##_name##_show, NULL);            \
+
+DASD_DEFINE_ATTR(ese, device->discipline->is_ese);
+DASD_DEFINE_ATTR(extent_size, device->discipline->ext_size);
+DASD_DEFINE_ATTR(pool_id, device->discipline->ext_pool_id);
+DASD_DEFINE_ATTR(space_configured, device->discipline->space_configured);
+DASD_DEFINE_ATTR(space_allocated, device->discipline->space_allocated);
+DASD_DEFINE_ATTR(logical_capacity, device->discipline->logical_capacity);
+DASD_DEFINE_ATTR(warn_threshold, device->discipline->ext_pool_warn_thrshld);
+DASD_DEFINE_ATTR(cap_at_warnlevel, device->discipline->ext_pool_cap_at_warnlevel);
+DASD_DEFINE_ATTR(pool_oos, device->discipline->ext_pool_oos);
+
 static struct attribute * dasd_attrs[] = {
        &dev_attr_readonly.attr,
        &dev_attr_discipline.attr,
@@ -1667,6 +1696,7 @@ static struct attribute * dasd_attrs[] = {
        &dev_attr_path_interval.attr,
        &dev_attr_path_reset.attr,
        &dev_attr_hpf.attr,
+       &dev_attr_ese.attr,
        NULL,
 };
 
@@ -1674,6 +1704,39 @@ static const struct attribute_group dasd_attr_group = {
        .attrs = dasd_attrs,
 };
 
+static struct attribute *capacity_attrs[] = {
+       &dev_attr_space_configured.attr,
+       &dev_attr_space_allocated.attr,
+       &dev_attr_logical_capacity.attr,
+       NULL,
+};
+
+static const struct attribute_group capacity_attr_group = {
+       .name = "capacity",
+       .attrs = capacity_attrs,
+};
+
+static struct attribute *ext_pool_attrs[] = {
+       &dev_attr_pool_id.attr,
+       &dev_attr_extent_size.attr,
+       &dev_attr_warn_threshold.attr,
+       &dev_attr_cap_at_warnlevel.attr,
+       &dev_attr_pool_oos.attr,
+       NULL,
+};
+
+static const struct attribute_group ext_pool_attr_group = {
+       .name = "extent_pool",
+       .attrs = ext_pool_attrs,
+};
+
+static const struct attribute_group *dasd_attr_groups[] = {
+       &dasd_attr_group,
+       &capacity_attr_group,
+       &ext_pool_attr_group,
+       NULL,
+};
+
 /*
  * Return value of the specified feature.
  */
@@ -1715,16 +1778,15 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag)
 EXPORT_SYMBOL(dasd_set_feature);
 
 
-int
-dasd_add_sysfs_files(struct ccw_device *cdev)
+int dasd_add_sysfs_files(struct ccw_device *cdev)
 {
-       return sysfs_create_group(&cdev->dev.kobj, &dasd_attr_group);
+       return sysfs_create_groups(&cdev->dev.kobj, dasd_attr_groups);
 }
 
 void
 dasd_remove_sysfs_files(struct ccw_device *cdev)
 {
-       sysfs_remove_group(&cdev->dev.kobj, &dasd_attr_group);
+       sysfs_remove_groups(&cdev->dev.kobj, dasd_attr_groups);
 }
 
 
index e1fe024..8d49716 100644 (file)
@@ -615,14 +615,34 @@ dasd_diag_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
                    "dump sense not available for DIAG data");
 }
 
+/*
+ * Initialize block layer request queue.
+ */
+static void dasd_diag_setup_blk_queue(struct dasd_block *block)
+{
+       unsigned int logical_block_size = block->bp_block;
+       struct request_queue *q = block->request_queue;
+       int max;
+
+       max = DIAG_MAX_BLOCKS << block->s2b_shift;
+       blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
+       q->limits.max_dev_sectors = max;
+       blk_queue_logical_block_size(q, logical_block_size);
+       blk_queue_max_hw_sectors(q, max);
+       blk_queue_max_segments(q, USHRT_MAX);
+       /* With page sized segments each segment can be translated into one idaw/tidaw */
+       blk_queue_max_segment_size(q, PAGE_SIZE);
+       blk_queue_segment_boundary(q, PAGE_SIZE - 1);
+}
+
 static struct dasd_discipline dasd_diag_discipline = {
        .owner = THIS_MODULE,
        .name = "DIAG",
        .ebcname = "DIAG",
-       .max_blocks = DIAG_MAX_BLOCKS,
        .check_device = dasd_diag_check_device,
        .verify_path = dasd_generic_verify_path,
        .fill_geometry = dasd_diag_fill_geometry,
+       .setup_blk_queue = dasd_diag_setup_blk_queue,
        .start_IO = dasd_start_diag,
        .term_IO = dasd_diag_term_IO,
        .handle_terminated_request = dasd_diag_handle_terminated_request,
index c09039e..fc53e1e 100644 (file)
 #endif                         /* PRINTK_HEADER */
 #define PRINTK_HEADER "dasd(eckd):"
 
-#define ECKD_C0(i) (i->home_bytes)
-#define ECKD_F(i) (i->formula)
-#define ECKD_F1(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f1):\
-                   (i->factors.f_0x02.f1))
-#define ECKD_F2(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f2):\
-                   (i->factors.f_0x02.f2))
-#define ECKD_F3(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f3):\
-                   (i->factors.f_0x02.f3))
-#define ECKD_F4(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f4):0)
-#define ECKD_F5(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f5):0)
-#define ECKD_F6(i) (i->factor6)
-#define ECKD_F7(i) (i->factor7)
-#define ECKD_F8(i) (i->factor8)
-
 /*
  * raw track access always map to 64k in memory
  * so it maps to 16 blocks of 4k per track
@@ -103,6 +89,19 @@ static struct {
 } *dasd_reserve_req;
 static DEFINE_MUTEX(dasd_reserve_mutex);
 
+static struct {
+       struct dasd_ccw_req cqr;
+       struct ccw1 ccw[2];
+       char data[40];
+} *dasd_vol_info_req;
+static DEFINE_MUTEX(dasd_vol_info_mutex);
+
+struct ext_pool_exhaust_work_data {
+       struct work_struct worker;
+       struct dasd_device *device;
+       struct dasd_device *base;
+};
+
 /* definitions for the path verification worker */
 struct path_verification_work_data {
        struct work_struct worker;
@@ -122,6 +121,7 @@ struct check_attention_work_data {
        __u8 lpum;
 };
 
+static int dasd_eckd_ext_pool_id(struct dasd_device *);
 static int prepare_itcw(struct itcw *, unsigned int, unsigned int, int,
                        struct dasd_device *, struct dasd_device *,
                        unsigned int, int, unsigned int, unsigned int,
@@ -157,16 +157,9 @@ static const int sizes_trk0[] = { 28, 148, 84 };
 #define LABEL_SIZE 140
 
 /* head and record addresses of count_area read in analysis ccw */
-static const int count_area_head[] = { 0, 0, 0, 0, 2 };
+static const int count_area_head[] = { 0, 0, 0, 0, 1 };
 static const int count_area_rec[] = { 1, 2, 3, 4, 1 };
 
-static inline unsigned int
-round_up_multiple(unsigned int no, unsigned int mult)
-{
-       int rem = no % mult;
-       return (rem ? no - rem + mult : no);
-}
-
 static inline unsigned int
 ceil_quot(unsigned int d1, unsigned int d2)
 {
@@ -1491,6 +1484,311 @@ static int dasd_eckd_read_features(struct dasd_device *device)
        return rc;
 }
 
+/* Read Volume Information - Volume Storage Query */
+static int dasd_eckd_read_vol_info(struct dasd_device *device)
+{
+       struct dasd_eckd_private *private = device->private;
+       struct dasd_psf_prssd_data *prssdp;
+       struct dasd_rssd_vsq *vsq;
+       struct dasd_ccw_req *cqr;
+       struct ccw1 *ccw;
+       int useglobal;
+       int rc;
+
+       /* This command cannot be executed on an alias device */
+       if (private->uid.type == UA_BASE_PAV_ALIAS ||
+           private->uid.type == UA_HYPER_PAV_ALIAS)
+               return 0;
+
+       useglobal = 0;
+       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 2 /* PSF + RSSD */,
+                                  sizeof(*prssdp) + sizeof(*vsq), device, NULL);
+       if (IS_ERR(cqr)) {
+               DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
+                               "Could not allocate initialization request");
+               mutex_lock(&dasd_vol_info_mutex);
+               useglobal = 1;
+               cqr = &dasd_vol_info_req->cqr;
+               memset(cqr, 0, sizeof(*cqr));
+               memset(dasd_vol_info_req, 0, sizeof(*dasd_vol_info_req));
+               cqr->cpaddr = &dasd_vol_info_req->ccw;
+               cqr->data = &dasd_vol_info_req->data;
+               cqr->magic = DASD_ECKD_MAGIC;
+       }
+
+       /* Prepare for Read Subsystem Data */
+       prssdp = cqr->data;
+       prssdp->order = PSF_ORDER_PRSSD;
+       prssdp->suborder = PSF_SUBORDER_VSQ;    /* Volume Storage Query */
+       prssdp->lss = private->ned->ID;
+       prssdp->volume = private->ned->unit_addr;
+
+       ccw = cqr->cpaddr;
+       ccw->cmd_code = DASD_ECKD_CCW_PSF;
+       ccw->count = sizeof(*prssdp);
+       ccw->flags |= CCW_FLAG_CC;
+       ccw->cda = (__u32)(addr_t)prssdp;
+
+       /* Read Subsystem Data - Volume Storage Query */
+       vsq = (struct dasd_rssd_vsq *)(prssdp + 1);
+       memset(vsq, 0, sizeof(*vsq));
+
+       ccw++;
+       ccw->cmd_code = DASD_ECKD_CCW_RSSD;
+       ccw->count = sizeof(*vsq);
+       ccw->flags |= CCW_FLAG_SLI;
+       ccw->cda = (__u32)(addr_t)vsq;
+
+       cqr->buildclk = get_tod_clock();
+       cqr->status = DASD_CQR_FILLED;
+       cqr->startdev = device;
+       cqr->memdev = device;
+       cqr->block = NULL;
+       cqr->retries = 256;
+       cqr->expires = device->default_expires * HZ;
+       /* The command might not be supported. Suppress the error output */
+       __set_bit(DASD_CQR_SUPPRESS_CR, &cqr->flags);
+
+       rc = dasd_sleep_on_interruptible(cqr);
+       if (rc == 0) {
+               memcpy(&private->vsq, vsq, sizeof(*vsq));
+       } else {
+               dev_warn(&device->cdev->dev,
+                        "Reading the volume storage information failed with rc=%d\n", rc);
+       }
+
+       if (useglobal)
+               mutex_unlock(&dasd_vol_info_mutex);
+       else
+               dasd_sfree_request(cqr, cqr->memdev);
+
+       return rc;
+}
+
+static int dasd_eckd_is_ese(struct dasd_device *device)
+{
+       struct dasd_eckd_private *private = device->private;
+
+       return private->vsq.vol_info.ese;
+}
+
+static int dasd_eckd_ext_pool_id(struct dasd_device *device)
+{
+       struct dasd_eckd_private *private = device->private;
+
+       return private->vsq.extent_pool_id;
+}
+
+/*
+ * This value represents the total amount of available space. As more space is
+ * allocated by ESE volumes, this value will decrease.
+ * The data for this value is therefore updated on any call.
+ */
+static int dasd_eckd_space_configured(struct dasd_device *device)
+{
+       struct dasd_eckd_private *private = device->private;
+       int rc;
+
+       rc = dasd_eckd_read_vol_info(device);
+
+       return rc ? : private->vsq.space_configured;
+}
+
+/*
+ * The value of space allocated by an ESE volume may have changed and is
+ * therefore updated on any call.
+ */
+static int dasd_eckd_space_allocated(struct dasd_device *device)
+{
+       struct dasd_eckd_private *private = device->private;
+       int rc;
+
+       rc = dasd_eckd_read_vol_info(device);
+
+       return rc ? : private->vsq.space_allocated;
+}
+
+static int dasd_eckd_logical_capacity(struct dasd_device *device)
+{
+       struct dasd_eckd_private *private = device->private;
+
+       return private->vsq.logical_capacity;
+}
+
+static void dasd_eckd_ext_pool_exhaust_work(struct work_struct *work)
+{
+       struct ext_pool_exhaust_work_data *data;
+       struct dasd_device *device;
+       struct dasd_device *base;
+
+       data = container_of(work, struct ext_pool_exhaust_work_data, worker);
+       device = data->device;
+       base = data->base;
+
+       if (!base)
+               base = device;
+       if (dasd_eckd_space_configured(base) != 0) {
+               dasd_generic_space_avail(device);
+       } else {
+               dev_warn(&device->cdev->dev, "No space left in the extent pool\n");
+               DBF_DEV_EVENT(DBF_WARNING, device, "%s", "out of space");
+       }
+
+       dasd_put_device(device);
+       kfree(data);
+}
+
+static int dasd_eckd_ext_pool_exhaust(struct dasd_device *device,
+                                     struct dasd_ccw_req *cqr)
+{
+       struct ext_pool_exhaust_work_data *data;
+
+       data = kzalloc(sizeof(*data), GFP_ATOMIC);
+       if (!data)
+               return -ENOMEM;
+       INIT_WORK(&data->worker, dasd_eckd_ext_pool_exhaust_work);
+       dasd_get_device(device);
+       data->device = device;
+
+       if (cqr->block)
+               data->base = cqr->block->base;
+       else if (cqr->basedev)
+               data->base = cqr->basedev;
+       else
+               data->base = NULL;
+
+       schedule_work(&data->worker);
+
+       return 0;
+}
+
+static void dasd_eckd_cpy_ext_pool_data(struct dasd_device *device,
+                                       struct dasd_rssd_lcq *lcq)
+{
+       struct dasd_eckd_private *private = device->private;
+       int pool_id = dasd_eckd_ext_pool_id(device);
+       struct dasd_ext_pool_sum eps;
+       int i;
+
+       for (i = 0; i < lcq->pool_count; i++) {
+               eps = lcq->ext_pool_sum[i];
+               if (eps.pool_id == pool_id) {
+                       memcpy(&private->eps, &eps,
+                              sizeof(struct dasd_ext_pool_sum));
+               }
+       }
+}
+
+/* Read Extent Pool Information - Logical Configuration Query */
+static int dasd_eckd_read_ext_pool_info(struct dasd_device *device)
+{
+       struct dasd_eckd_private *private = device->private;
+       struct dasd_psf_prssd_data *prssdp;
+       struct dasd_rssd_lcq *lcq;
+       struct dasd_ccw_req *cqr;
+       struct ccw1 *ccw;
+       int rc;
+
+       /* This command cannot be executed on an alias device */
+       if (private->uid.type == UA_BASE_PAV_ALIAS ||
+           private->uid.type == UA_HYPER_PAV_ALIAS)
+               return 0;
+
+       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 2 /* PSF + RSSD */,
+                                  sizeof(*prssdp) + sizeof(*lcq), device, NULL);
+       if (IS_ERR(cqr)) {
+               DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
+                               "Could not allocate initialization request");
+               return PTR_ERR(cqr);
+       }
+
+       /* Prepare for Read Subsystem Data */
+       prssdp = cqr->data;
+       memset(prssdp, 0, sizeof(*prssdp));
+       prssdp->order = PSF_ORDER_PRSSD;
+       prssdp->suborder = PSF_SUBORDER_LCQ;    /* Logical Configuration Query */
+
+       ccw = cqr->cpaddr;
+       ccw->cmd_code = DASD_ECKD_CCW_PSF;
+       ccw->count = sizeof(*prssdp);
+       ccw->flags |= CCW_FLAG_CC;
+       ccw->cda = (__u32)(addr_t)prssdp;
+
+       lcq = (struct dasd_rssd_lcq *)(prssdp + 1);
+       memset(lcq, 0, sizeof(*lcq));
+
+       ccw++;
+       ccw->cmd_code = DASD_ECKD_CCW_RSSD;
+       ccw->count = sizeof(*lcq);
+       ccw->flags |= CCW_FLAG_SLI;
+       ccw->cda = (__u32)(addr_t)lcq;
+
+       cqr->buildclk = get_tod_clock();
+       cqr->status = DASD_CQR_FILLED;
+       cqr->startdev = device;
+       cqr->memdev = device;
+       cqr->block = NULL;
+       cqr->retries = 256;
+       cqr->expires = device->default_expires * HZ;
+       /* The command might not be supported. Suppress the error output */
+       __set_bit(DASD_CQR_SUPPRESS_CR, &cqr->flags);
+
+       rc = dasd_sleep_on_interruptible(cqr);
+       if (rc == 0) {
+               dasd_eckd_cpy_ext_pool_data(device, lcq);
+       } else {
+               dev_warn(&device->cdev->dev,
+                        "Reading the logical configuration failed with rc=%d\n", rc);
+       }
+
+       dasd_sfree_request(cqr, cqr->memdev);
+
+       return rc;
+}
+
+/*
+ * Depending on the device type, the extent size is specified either as
+ * cylinders per extent (CKD) or size per extent (FBA)
+ * A 1GB size corresponds to 1113cyl, and 16MB to 21cyl.
+ */
+static int dasd_eckd_ext_size(struct dasd_device *device)
+{
+       struct dasd_eckd_private *private = device->private;
+       struct dasd_ext_pool_sum eps = private->eps;
+
+       if (!eps.flags.extent_size_valid)
+               return 0;
+       if (eps.extent_size.size_1G)
+               return 1113;
+       if (eps.extent_size.size_16M)
+               return 21;
+
+       return 0;
+}
+
+static int dasd_eckd_ext_pool_warn_thrshld(struct dasd_device *device)
+{
+       struct dasd_eckd_private *private = device->private;
+
+       return private->eps.warn_thrshld;
+}
+
+static int dasd_eckd_ext_pool_cap_at_warnlevel(struct dasd_device *device)
+{
+       struct dasd_eckd_private *private = device->private;
+
+       return private->eps.flags.capacity_at_warnlevel;
+}
+
+/*
+ * Extent Pool out of space
+ */
+static int dasd_eckd_ext_pool_oos(struct dasd_device *device)
+{
+       struct dasd_eckd_private *private = device->private;
+
+       return private->eps.flags.pool_oos;
+}
 
 /*
  * Build CP for Perform Subsystem Function - SSC.
@@ -1721,6 +2019,16 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
        /* Read Feature Codes */
        dasd_eckd_read_features(device);
 
+       /* Read Volume Information */
+       rc = dasd_eckd_read_vol_info(device);
+       if (rc)
+               goto out_err3;
+
+       /* Read Extent Pool Information */
+       rc = dasd_eckd_read_ext_pool_info(device);
+       if (rc)
+               goto out_err3;
+
        /* Read Device Characteristics */
        rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC,
                                         &private->rdc_data, 64);
@@ -1751,6 +2059,9 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
        if (readonly)
                set_bit(DASD_FLAG_DEVICE_RO, &device->flags);
 
+       if (dasd_eckd_is_ese(device))
+               dasd_set_feature(device->cdev, DASD_FEATURE_DISCARD, 1);
+
        dev_info(&device->cdev->dev, "New DASD %04X/%02X (CU %04X/%02X) "
                 "with %d cylinders, %d heads, %d sectors%s\n",
                 private->rdc_data.dev_type,
@@ -1823,8 +2134,8 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
        if (IS_ERR(cqr))
                return cqr;
        ccw = cqr->cpaddr;
-       /* Define extent for the first 3 tracks. */
-       define_extent(ccw++, cqr->data, 0, 2,
+       /* Define extent for the first 2 tracks. */
+       define_extent(ccw++, cqr->data, 0, 1,
                      DASD_ECKD_CCW_READ_COUNT, device, 0);
        LO_data = cqr->data + sizeof(struct DE_eckd_data);
        /* Locate record for the first 4 records on track 0. */
@@ -1843,9 +2154,9 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
                count_data++;
        }
 
-       /* Locate record for the first record on track 2. */
+       /* Locate record for the first record on track 1. */
        ccw[-1].flags |= CCW_FLAG_CC;
-       locate_record(ccw++, LO_data++, 2, 0, 1,
+       locate_record(ccw++, LO_data++, 1, 0, 1,
                      DASD_ECKD_CCW_READ_COUNT, device, 0);
        /* Read count ccw. */
        ccw[-1].flags |= CCW_FLAG_CC;
@@ -1860,6 +2171,9 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
        cqr->retries = 255;
        cqr->buildclk = get_tod_clock();
        cqr->status = DASD_CQR_FILLED;
+       /* Set flags to suppress output for expected errors */
+       set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags);
+
        return cqr;
 }
 
@@ -1967,7 +2281,7 @@ static int dasd_eckd_end_analysis(struct dasd_block *block)
                }
        }
        if (i == 3)
-               count_area = &private->count_area[4];
+               count_area = &private->count_area[3];
 
        if (private->uses_cdl == 0) {
                for (i = 0; i < 5; i++) {
@@ -2099,8 +2413,7 @@ dasd_eckd_build_check_tcw(struct dasd_device *base, struct format_data_t *fdata,
         */
        itcw_size = itcw_calc_size(0, count, 0);
 
-       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 0, itcw_size, startdev,
-                                  NULL);
+       cqr = dasd_fmalloc_request(DASD_ECKD_MAGIC, 0, itcw_size, startdev);
        if (IS_ERR(cqr))
                return cqr;
 
@@ -2193,8 +2506,7 @@ dasd_eckd_build_check(struct dasd_device *base, struct format_data_t *fdata,
        }
        cplength += count;
 
-       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize,
-                                  startdev, NULL);
+       cqr = dasd_fmalloc_request(DASD_ECKD_MAGIC, cplength, datasize, startdev);
        if (IS_ERR(cqr))
                return cqr;
 
@@ -2241,13 +2553,11 @@ dasd_eckd_build_check(struct dasd_device *base, struct format_data_t *fdata,
 }
 
 static struct dasd_ccw_req *
-dasd_eckd_build_format(struct dasd_device *base,
-                      struct format_data_t *fdata,
-                      int enable_pav)
+dasd_eckd_build_format(struct dasd_device *base, struct dasd_device *startdev,
+                      struct format_data_t *fdata, int enable_pav)
 {
        struct dasd_eckd_private *base_priv;
        struct dasd_eckd_private *start_priv;
-       struct dasd_device *startdev = NULL;
        struct dasd_ccw_req *fcp;
        struct eckd_count *ect;
        struct ch_t address;
@@ -2338,9 +2648,8 @@ dasd_eckd_build_format(struct dasd_device *base,
                         fdata->intensity);
                return ERR_PTR(-EINVAL);
        }
-       /* Allocate the format ccw request. */
-       fcp = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength,
-                                  datasize, startdev, NULL);
+
+       fcp = dasd_fmalloc_request(DASD_ECKD_MAGIC, cplength, datasize, startdev);
        if (IS_ERR(fcp))
                return fcp;
 
@@ -2513,7 +2822,7 @@ dasd_eckd_format_build_ccw_req(struct dasd_device *base,
        struct dasd_ccw_req *ccw_req;
 
        if (!fmt_buffer) {
-               ccw_req = dasd_eckd_build_format(base, fdata, enable_pav);
+               ccw_req = dasd_eckd_build_format(base, NULL, fdata, enable_pav);
        } else {
                if (tpm)
                        ccw_req = dasd_eckd_build_check_tcw(base, fdata,
@@ -2659,7 +2968,7 @@ out_err:
                                rc = -EIO;
                        }
                        list_del_init(&cqr->blocklist);
-                       dasd_sfree_request(cqr, device);
+                       dasd_ffree_request(cqr, device);
                        private->count--;
                }
 
@@ -2698,6 +3007,96 @@ static int dasd_eckd_format_device(struct dasd_device *base,
                                             0, NULL);
 }
 
+/*
+ * Callback function to free ESE format requests.
+ */
+static void dasd_eckd_ese_format_cb(struct dasd_ccw_req *cqr, void *data)
+{
+       struct dasd_device *device = cqr->startdev;
+       struct dasd_eckd_private *private = device->private;
+
+       private->count--;
+       dasd_ffree_request(cqr, device);
+}
+
+static struct dasd_ccw_req *
+dasd_eckd_ese_format(struct dasd_device *startdev, struct dasd_ccw_req *cqr)
+{
+       struct dasd_eckd_private *private;
+       struct format_data_t fdata;
+       unsigned int recs_per_trk;
+       struct dasd_ccw_req *fcqr;
+       struct dasd_device *base;
+       struct dasd_block *block;
+       unsigned int blksize;
+       struct request *req;
+       sector_t first_trk;
+       sector_t last_trk;
+       int rc;
+
+       req = cqr->callback_data;
+       base = cqr->block->base;
+       private = base->private;
+       block = base->block;
+       blksize = block->bp_block;
+       recs_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
+
+       first_trk = blk_rq_pos(req) >> block->s2b_shift;
+       sector_div(first_trk, recs_per_trk);
+       last_trk =
+               (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift;
+       sector_div(last_trk, recs_per_trk);
+
+       fdata.start_unit = first_trk;
+       fdata.stop_unit = last_trk;
+       fdata.blksize = blksize;
+       fdata.intensity = private->uses_cdl ? DASD_FMT_INT_COMPAT : 0;
+
+       rc = dasd_eckd_format_sanity_checks(base, &fdata);
+       if (rc)
+               return ERR_PTR(-EINVAL);
+
+       /*
+        * We're building the request with PAV disabled as we're reusing
+        * the former startdev.
+        */
+       fcqr = dasd_eckd_build_format(base, startdev, &fdata, 0);
+       if (IS_ERR(fcqr))
+               return fcqr;
+
+       fcqr->callback = dasd_eckd_ese_format_cb;
+
+       return fcqr;
+}
+
+/*
+ * When data is read from an unformatted area of an ESE volume, this function
+ * returns zeroed data and thereby mimics a read of zero data.
+ */
+static void dasd_eckd_ese_read(struct dasd_ccw_req *cqr)
+{
+       unsigned int blksize, off;
+       struct dasd_device *base;
+       struct req_iterator iter;
+       struct request *req;
+       struct bio_vec bv;
+       char *dst;
+
+       req = (struct request *) cqr->callback_data;
+       base = cqr->block->base;
+       blksize = base->block->bp_block;
+
+       rq_for_each_segment(bv, req, iter) {
+               dst = page_address(bv.bv_page) + bv.bv_offset;
+               for (off = 0; off < bv.bv_len; off += blksize) {
+                       if (dst && rq_data_dir(req) == READ) {
+                               dst += off;
+                               memset(dst, 0, blksize);
+                       }
+               }
+       }
+}
+
 /*
  * Helper function to count consecutive records of a single track.
  */
@@ -3033,6 +3432,277 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device,
        }
 }
 
+static int dasd_eckd_ras_sanity_checks(struct dasd_device *device,
+                                      unsigned int first_trk,
+                                      unsigned int last_trk)
+{
+       struct dasd_eckd_private *private = device->private;
+       unsigned int trks_per_vol;
+       int rc = 0;
+
+       trks_per_vol = private->real_cyl * private->rdc_data.trk_per_cyl;
+
+       if (first_trk >= trks_per_vol) {
+               dev_warn(&device->cdev->dev,
+                        "Start track number %u used in the space release command is too big\n",
+                        first_trk);
+               rc = -EINVAL;
+       } else if (last_trk >= trks_per_vol) {
+               dev_warn(&device->cdev->dev,
+                        "Stop track number %u used in the space release command is too big\n",
+                        last_trk);
+               rc = -EINVAL;
+       } else if (first_trk > last_trk) {
+               dev_warn(&device->cdev->dev,
+                        "Start track %u used in the space release command exceeds the end track\n",
+                        first_trk);
+               rc = -EINVAL;
+       }
+       return rc;
+}
+
+/*
+ * Helper function to count the amount of involved extents within a given range
+ * with extent alignment in mind.
+ */
+static int count_exts(unsigned int from, unsigned int to, int trks_per_ext)
+{
+       int cur_pos = 0;
+       int count = 0;
+       int tmp;
+
+       if (from == to)
+               return 1;
+
+       /* Count first partial extent */
+       if (from % trks_per_ext != 0) {
+               tmp = from + trks_per_ext - (from % trks_per_ext) - 1;
+               if (tmp > to)
+                       tmp = to;
+               cur_pos = tmp - from + 1;
+               count++;
+       }
+       /* Count full extents */
+       if (to - (from + cur_pos) + 1 >= trks_per_ext) {
+               tmp = to - ((to - trks_per_ext + 1) % trks_per_ext);
+               count += (tmp - (from + cur_pos) + 1) / trks_per_ext;
+               cur_pos = tmp;
+       }
+       /* Count last partial extent */
+       if (cur_pos < to)
+               count++;
+
+       return count;
+}
+
+/*
+ * Release allocated space for a given range or an entire volume.
+ */
+static struct dasd_ccw_req *
+dasd_eckd_dso_ras(struct dasd_device *device, struct dasd_block *block,
+                 struct request *req, unsigned int first_trk,
+                 unsigned int last_trk, int by_extent)
+{
+       struct dasd_eckd_private *private = device->private;
+       struct dasd_dso_ras_ext_range *ras_range;
+       struct dasd_rssd_features *features;
+       struct dasd_dso_ras_data *ras_data;
+       u16 heads, beg_head, end_head;
+       int cur_to_trk, cur_from_trk;
+       struct dasd_ccw_req *cqr;
+       u32 beg_cyl, end_cyl;
+       struct ccw1 *ccw;
+       int trks_per_ext;
+       size_t ras_size;
+       size_t size;
+       int nr_exts;
+       void *rq;
+       int i;
+
+       if (dasd_eckd_ras_sanity_checks(device, first_trk, last_trk))
+               return ERR_PTR(-EINVAL);
+
+       rq = req ? blk_mq_rq_to_pdu(req) : NULL;
+
+       features = &private->features;
+
+       trks_per_ext = dasd_eckd_ext_size(device) * private->rdc_data.trk_per_cyl;
+       nr_exts = 0;
+       if (by_extent)
+               nr_exts = count_exts(first_trk, last_trk, trks_per_ext);
+       ras_size = sizeof(*ras_data);
+       size = ras_size + (nr_exts * sizeof(*ras_range));
+
+       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, size, device, rq);
+       if (IS_ERR(cqr)) {
+               DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
+                               "Could not allocate RAS request");
+               return cqr;
+       }
+
+       ras_data = cqr->data;
+       memset(ras_data, 0, size);
+
+       ras_data->order = DSO_ORDER_RAS;
+       ras_data->flags.vol_type = 0; /* CKD volume */
+       /* Release specified extents or entire volume */
+       ras_data->op_flags.by_extent = by_extent;
+       /*
+        * This bit guarantees initialisation of tracks within an extent that is
+        * not fully specified, but is only supported with a certain feature
+        * subset.
+        */
+       ras_data->op_flags.guarantee_init = !!(features->feature[56] & 0x01);
+       ras_data->lss = private->ned->ID;
+       ras_data->dev_addr = private->ned->unit_addr;
+       ras_data->nr_exts = nr_exts;
+
+       if (by_extent) {
+               heads = private->rdc_data.trk_per_cyl;
+               cur_from_trk = first_trk;
+               cur_to_trk = first_trk + trks_per_ext -
+                       (first_trk % trks_per_ext) - 1;
+               if (cur_to_trk > last_trk)
+                       cur_to_trk = last_trk;
+               ras_range = (struct dasd_dso_ras_ext_range *)(cqr->data + ras_size);
+
+               for (i = 0; i < nr_exts; i++) {
+                       beg_cyl = cur_from_trk / heads;
+                       beg_head = cur_from_trk % heads;
+                       end_cyl = cur_to_trk / heads;
+                       end_head = cur_to_trk % heads;
+
+                       set_ch_t(&ras_range->beg_ext, beg_cyl, beg_head);
+                       set_ch_t(&ras_range->end_ext, end_cyl, end_head);
+
+                       cur_from_trk = cur_to_trk + 1;
+                       cur_to_trk = cur_from_trk + trks_per_ext - 1;
+                       if (cur_to_trk > last_trk)
+                               cur_to_trk = last_trk;
+                       ras_range++;
+               }
+       }
+
+       ccw = cqr->cpaddr;
+       ccw->cda = (__u32)(addr_t)cqr->data;
+       ccw->cmd_code = DASD_ECKD_CCW_DSO;
+       ccw->count = size;
+
+       cqr->startdev = device;
+       cqr->memdev = device;
+       cqr->block = block;
+       cqr->retries = 256;
+       cqr->expires = device->default_expires * HZ;
+       cqr->buildclk = get_tod_clock();
+       cqr->status = DASD_CQR_FILLED;
+
+       return cqr;
+}
+
+static int dasd_eckd_release_space_full(struct dasd_device *device)
+{
+       struct dasd_ccw_req *cqr;
+       int rc;
+
+       cqr = dasd_eckd_dso_ras(device, NULL, NULL, 0, 0, 0);
+       if (IS_ERR(cqr))
+               return PTR_ERR(cqr);
+
+       rc = dasd_sleep_on_interruptible(cqr);
+
+       dasd_sfree_request(cqr, cqr->memdev);
+
+       return rc;
+}
+
+static int dasd_eckd_release_space_trks(struct dasd_device *device,
+                                       unsigned int from, unsigned int to)
+{
+       struct dasd_eckd_private *private = device->private;
+       struct dasd_block *block = device->block;
+       struct dasd_ccw_req *cqr, *n;
+       struct list_head ras_queue;
+       unsigned int device_exts;
+       int trks_per_ext;
+       int stop, step;
+       int cur_pos;
+       int rc = 0;
+       int retry;
+
+       INIT_LIST_HEAD(&ras_queue);
+
+       device_exts = private->real_cyl / dasd_eckd_ext_size(device);
+       trks_per_ext = dasd_eckd_ext_size(device) * private->rdc_data.trk_per_cyl;
+
+       /* Make sure device limits are not exceeded */
+       step = trks_per_ext * min(device_exts, DASD_ECKD_RAS_EXTS_MAX);
+       cur_pos = from;
+
+       do {
+               retry = 0;
+               while (cur_pos < to) {
+                       stop = cur_pos + step -
+                               ((cur_pos + step) % trks_per_ext) - 1;
+                       if (stop > to)
+                               stop = to;
+
+                       cqr = dasd_eckd_dso_ras(device, NULL, NULL, cur_pos, stop, 1);
+                       if (IS_ERR(cqr)) {
+                               rc = PTR_ERR(cqr);
+                               if (rc == -ENOMEM) {
+                                       if (list_empty(&ras_queue))
+                                               goto out;
+                                       retry = 1;
+                                       break;
+                               }
+                               goto err_out;
+                       }
+
+                       spin_lock_irq(&block->queue_lock);
+                       list_add_tail(&cqr->blocklist, &ras_queue);
+                       spin_unlock_irq(&block->queue_lock);
+                       cur_pos = stop + 1;
+               }
+
+               rc = dasd_sleep_on_queue_interruptible(&ras_queue);
+
+err_out:
+               list_for_each_entry_safe(cqr, n, &ras_queue, blocklist) {
+                       device = cqr->startdev;
+                       private = device->private;
+
+                       spin_lock_irq(&block->queue_lock);
+                       list_del_init(&cqr->blocklist);
+                       spin_unlock_irq(&block->queue_lock);
+                       dasd_sfree_request(cqr, device);
+                       private->count--;
+               }
+       } while (retry);
+
+out:
+       return rc;
+}
+
+static int dasd_eckd_release_space(struct dasd_device *device,
+                                  struct format_data_t *rdata)
+{
+       if (rdata->intensity & DASD_FMT_INT_ESE_FULL)
+               return dasd_eckd_release_space_full(device);
+       else if (rdata->intensity == 0)
+               return dasd_eckd_release_space_trks(device, rdata->start_unit,
+                                                   rdata->stop_unit);
+       else
+               return -EINVAL;
+}
+
+static struct dasd_ccw_req *
+dasd_eckd_build_cp_discard(struct dasd_device *device, struct dasd_block *block,
+                          struct request *req, sector_t first_trk,
+                          sector_t last_trk)
+{
+       return dasd_eckd_dso_ras(device, block, req, first_trk, last_trk, 1);
+}
+
 static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
                                               struct dasd_device *startdev,
                                               struct dasd_block *block,
@@ -3214,6 +3884,14 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
        cqr->retries = startdev->default_retries;
        cqr->buildclk = get_tod_clock();
        cqr->status = DASD_CQR_FILLED;
+
+       /* Set flags to suppress output for expected errors */
+       if (dasd_eckd_is_ese(basedev)) {
+               set_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags);
+               set_bit(DASD_CQR_SUPPRESS_IL, &cqr->flags);
+               set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags);
+       }
+
        return cqr;
 }
 
@@ -3385,6 +4063,11 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
        cqr->retries = startdev->default_retries;
        cqr->buildclk = get_tod_clock();
        cqr->status = DASD_CQR_FILLED;
+
+       /* Set flags to suppress output for expected errors */
+       if (dasd_eckd_is_ese(basedev))
+               set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags);
+
        return cqr;
 }
 
@@ -3704,6 +4387,14 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
        cqr->retries = startdev->default_retries;
        cqr->buildclk = get_tod_clock();
        cqr->status = DASD_CQR_FILLED;
+
+       /* Set flags to suppress output for expected errors */
+       if (dasd_eckd_is_ese(basedev)) {
+               set_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags);
+               set_bit(DASD_CQR_SUPPRESS_IL, &cqr->flags);
+               set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags);
+       }
+
        return cqr;
 out_error:
        dasd_sfree_request(cqr, startdev);
@@ -3756,6 +4447,10 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
        cmdwtd = private->features.feature[12] & 0x40;
        use_prefix = private->features.feature[8] & 0x01;
 
+       if (req_op(req) == REQ_OP_DISCARD)
+               return dasd_eckd_build_cp_discard(startdev, block, req,
+                                                 first_trk, last_trk);
+
        cqr = NULL;
        if (cdlspecial || dasd_page_cache) {
                /* do nothing, just fall through to the cmd mode single case */
@@ -4034,12 +4729,14 @@ static struct dasd_ccw_req *dasd_eckd_build_alias_cp(struct dasd_device *base,
                                                     struct dasd_block *block,
                                                     struct request *req)
 {
+       struct dasd_device *startdev = NULL;
        struct dasd_eckd_private *private;
-       struct dasd_device *startdev;
-       unsigned long flags;
        struct dasd_ccw_req *cqr;
+       unsigned long flags;
 
-       startdev = dasd_alias_get_start_dev(base);
+       /* Discard requests can only be processed on base devices */
+       if (req_op(req) != REQ_OP_DISCARD)
+               startdev = dasd_alias_get_start_dev(base);
        if (!startdev)
                startdev = base;
        private = startdev->private;
@@ -4965,6 +5662,16 @@ static int dasd_eckd_restore_device(struct dasd_device *device)
        /* Read Feature Codes */
        dasd_eckd_read_features(device);
 
+       /* Read Volume Information */
+       rc = dasd_eckd_read_vol_info(device);
+       if (rc)
+               goto out_err2;
+
+       /* Read Extent Pool Information */
+       rc = dasd_eckd_read_ext_pool_info(device);
+       if (rc)
+               goto out_err2;
+
        /* Read Device Characteristics */
        rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC,
                                         &temp_rdc_data, 64);
@@ -5635,6 +6342,73 @@ static void dasd_eckd_handle_cuir(struct dasd_device *device, void *messages,
        device->discipline->check_attention(device, lpum);
 }
 
+static void dasd_eckd_oos_resume(struct dasd_device *device)
+{
+       struct dasd_eckd_private *private = device->private;
+       struct alias_pav_group *pavgroup, *tempgroup;
+       struct dasd_device *dev, *n;
+       unsigned long flags;
+
+       spin_lock_irqsave(&private->lcu->lock, flags);
+       list_for_each_entry_safe(dev, n, &private->lcu->active_devices,
+                                alias_list) {
+               if (dev->stopped & DASD_STOPPED_NOSPC)
+                       dasd_generic_space_avail(dev);
+       }
+       list_for_each_entry_safe(dev, n, &private->lcu->inactive_devices,
+                                alias_list) {
+               if (dev->stopped & DASD_STOPPED_NOSPC)
+                       dasd_generic_space_avail(dev);
+       }
+       /* devices in PAV groups */
+       list_for_each_entry_safe(pavgroup, tempgroup,
+                                &private->lcu->grouplist,
+                                group) {
+               list_for_each_entry_safe(dev, n, &pavgroup->baselist,
+                                        alias_list) {
+                       if (dev->stopped & DASD_STOPPED_NOSPC)
+                               dasd_generic_space_avail(dev);
+               }
+               list_for_each_entry_safe(dev, n, &pavgroup->aliaslist,
+                                        alias_list) {
+                       if (dev->stopped & DASD_STOPPED_NOSPC)
+                               dasd_generic_space_avail(dev);
+               }
+       }
+       spin_unlock_irqrestore(&private->lcu->lock, flags);
+}
+
+static void dasd_eckd_handle_oos(struct dasd_device *device, void *messages,
+                                __u8 lpum)
+{
+       struct dasd_oos_message *oos = messages;
+
+       switch (oos->code) {
+       case REPO_WARN:
+       case POOL_WARN:
+               dev_warn(&device->cdev->dev,
+                        "Extent pool usage has reached a critical value\n");
+               dasd_eckd_oos_resume(device);
+               break;
+       case REPO_EXHAUST:
+       case POOL_EXHAUST:
+               dev_warn(&device->cdev->dev,
+                        "Extent pool is exhausted\n");
+               break;
+       case REPO_RELIEVE:
+       case POOL_RELIEVE:
+               dev_info(&device->cdev->dev,
+                        "Extent pool physical space constraint has been relieved\n");
+               break;
+       }
+
+       /* In any case, update related data */
+       dasd_eckd_read_ext_pool_info(device);
+
+       /* to make sure there is no attention left schedule work again */
+       device->discipline->check_attention(device, lpum);
+}
+
 static void dasd_eckd_check_attention_work(struct work_struct *work)
 {
        struct check_attention_work_data *data;
@@ -5653,9 +6427,14 @@ static void dasd_eckd_check_attention_work(struct work_struct *work)
        rc = dasd_eckd_read_message_buffer(device, messages, data->lpum);
        if (rc)
                goto out;
+
        if (messages->length == ATTENTION_LENGTH_CUIR &&
            messages->format == ATTENTION_FORMAT_CUIR)
                dasd_eckd_handle_cuir(device, messages, data->lpum);
+       if (messages->length == ATTENTION_LENGTH_OOS &&
+           messages->format == ATTENTION_FORMAT_OOS)
+               dasd_eckd_handle_oos(device, messages, data->lpum);
+
 out:
        dasd_put_device(device);
        kfree(messages);
@@ -5734,6 +6513,72 @@ static void dasd_eckd_handle_hpf_error(struct dasd_device *device,
        dasd_schedule_requeue(device);
 }
 
+/*
+ * Initialize block layer request queue.
+ */
+static void dasd_eckd_setup_blk_queue(struct dasd_block *block)
+{
+       unsigned int logical_block_size = block->bp_block;
+       struct request_queue *q = block->request_queue;
+       struct dasd_device *device = block->base;
+       struct dasd_eckd_private *private;
+       unsigned int max_discard_sectors;
+       unsigned int max_bytes;
+       unsigned int ext_bytes; /* Extent Size in Bytes */
+       int recs_per_trk;
+       int trks_per_cyl;
+       int ext_limit;
+       int ext_size; /* Extent Size in Cylinders */
+       int max;
+
+       private = device->private;
+       trks_per_cyl = private->rdc_data.trk_per_cyl;
+       recs_per_trk = recs_per_track(&private->rdc_data, 0, logical_block_size);
+
+       if (device->features & DASD_FEATURE_USERAW) {
+               /*
+                * the max_blocks value for raw_track access is 256
+                * it is higher than the native ECKD value because we
+                * only need one ccw per track
+                * so the max_hw_sectors are
+                * 2048 x 512B = 1024kB = 16 tracks
+                */
+               max = DASD_ECKD_MAX_BLOCKS_RAW << block->s2b_shift;
+       } else {
+               max = DASD_ECKD_MAX_BLOCKS << block->s2b_shift;
+       }
+       blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
+       q->limits.max_dev_sectors = max;
+       blk_queue_logical_block_size(q, logical_block_size);
+       blk_queue_max_hw_sectors(q, max);
+       blk_queue_max_segments(q, USHRT_MAX);
+       /* With page sized segments each segment can be translated into one idaw/tidaw */
+       blk_queue_max_segment_size(q, PAGE_SIZE);
+       blk_queue_segment_boundary(q, PAGE_SIZE - 1);
+
+       if (dasd_eckd_is_ese(device)) {
+               /*
+                * Depending on the extent size, up to UINT_MAX bytes can be
+                * accepted. However, neither DASD_ECKD_RAS_EXTS_MAX nor the
+                * device limits should be exceeded.
+                */
+               ext_size = dasd_eckd_ext_size(device);
+               ext_limit = min(private->real_cyl / ext_size, DASD_ECKD_RAS_EXTS_MAX);
+               ext_bytes = ext_size * trks_per_cyl * recs_per_trk *
+                       logical_block_size;
+               max_bytes = UINT_MAX - (UINT_MAX % ext_bytes);
+               if (max_bytes / ext_bytes > ext_limit)
+                       max_bytes = ext_bytes * ext_limit;
+
+               max_discard_sectors = max_bytes / 512;
+
+               blk_queue_max_discard_sectors(q, max_discard_sectors);
+               blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
+               q->limits.discard_granularity = ext_bytes;
+               q->limits.discard_alignment = ext_bytes;
+       }
+}
+
 static struct ccw_driver dasd_eckd_driver = {
        .driver = {
                .name   = "dasd-eckd",
@@ -5754,24 +6599,10 @@ static struct ccw_driver dasd_eckd_driver = {
        .int_class   = IRQIO_DAS,
 };
 
-/*
- * max_blocks is dependent on the amount of storage that is available
- * in the static io buffer for each device. Currently each device has
- * 8192 bytes (=2 pages). For 64 bit one dasd_mchunkt_t structure has
- * 24 bytes, the struct dasd_ccw_req has 136 bytes and each block can use
- * up to 16 bytes (8 for the ccw and 8 for the idal pointer). In
- * addition we have one define extent ccw + 16 bytes of data and one
- * locate record ccw + 16 bytes of data. That makes:
- * (8192 - 24 - 136 - 8 - 16 - 8 - 16) / 16 = 499 blocks at maximum.
- * We want to fit two into the available memory so that we can immediately
- * start the next request if one finishes off. That makes 249.5 blocks
- * for one request. Give a little safety and the result is 240.
- */
 static struct dasd_discipline dasd_eckd_discipline = {
        .owner = THIS_MODULE,
        .name = "ECKD",
        .ebcname = "ECKD",
-       .max_blocks = 190,
        .check_device = dasd_eckd_check_characteristics,
        .uncheck_device = dasd_eckd_uncheck_device,
        .do_analysis = dasd_eckd_do_analysis,
@@ -5779,6 +6610,7 @@ static struct dasd_discipline dasd_eckd_discipline = {
        .basic_to_ready = dasd_eckd_basic_to_ready,
        .online_to_ready = dasd_eckd_online_to_ready,
        .basic_to_known = dasd_eckd_basic_to_known,
+       .setup_blk_queue = dasd_eckd_setup_blk_queue,
        .fill_geometry = dasd_eckd_fill_geometry,
        .start_IO = dasd_start_IO,
        .term_IO = dasd_term_IO,
@@ -5806,6 +6638,19 @@ static struct dasd_discipline dasd_eckd_discipline = {
        .disable_hpf = dasd_eckd_disable_hpf_device,
        .hpf_enabled = dasd_eckd_hpf_enabled,
        .reset_path = dasd_eckd_reset_path,
+       .is_ese = dasd_eckd_is_ese,
+       .space_allocated = dasd_eckd_space_allocated,
+       .space_configured = dasd_eckd_space_configured,
+       .logical_capacity = dasd_eckd_logical_capacity,
+       .release_space = dasd_eckd_release_space,
+       .ext_pool_id = dasd_eckd_ext_pool_id,
+       .ext_size = dasd_eckd_ext_size,
+       .ext_pool_cap_at_warnlevel = dasd_eckd_ext_pool_cap_at_warnlevel,
+       .ext_pool_warn_thrshld = dasd_eckd_ext_pool_warn_thrshld,
+       .ext_pool_oos = dasd_eckd_ext_pool_oos,
+       .ext_pool_exhaust = dasd_eckd_ext_pool_exhaust,
+       .ese_format = dasd_eckd_ese_format,
+       .ese_read = dasd_eckd_ese_read,
 };
 
 static int __init
@@ -5818,16 +6663,22 @@ dasd_eckd_init(void)
                                   GFP_KERNEL | GFP_DMA);
        if (!dasd_reserve_req)
                return -ENOMEM;
+       dasd_vol_info_req = kmalloc(sizeof(*dasd_vol_info_req),
+                                   GFP_KERNEL | GFP_DMA);
+       if (!dasd_vol_info_req)
+               return -ENOMEM;
        path_verification_worker = kmalloc(sizeof(*path_verification_worker),
                                   GFP_KERNEL | GFP_DMA);
        if (!path_verification_worker) {
                kfree(dasd_reserve_req);
+               kfree(dasd_vol_info_req);
                return -ENOMEM;
        }
        rawpadpage = (void *)__get_free_page(GFP_KERNEL);
        if (!rawpadpage) {
                kfree(path_verification_worker);
                kfree(dasd_reserve_req);
+               kfree(dasd_vol_info_req);
                return -ENOMEM;
        }
        ret = ccw_driver_register(&dasd_eckd_driver);
@@ -5836,6 +6687,7 @@ dasd_eckd_init(void)
        else {
                kfree(path_verification_worker);
                kfree(dasd_reserve_req);
+               kfree(dasd_vol_info_req);
                free_page((unsigned long)rawpadpage);
        }
        return ret;
index 5869d2f..6943508 100644 (file)
 #define DASD_ECKD_CCW_PFX_READ          0xEA
 #define DASD_ECKD_CCW_RSCK              0xF9
 #define DASD_ECKD_CCW_RCD               0xFA
+#define DASD_ECKD_CCW_DSO               0xF7
+
+/* Define Subssystem Function / Orders */
+#define DSO_ORDER_RAS                   0x81
 
 /*
- * Perform Subsystem Function / Sub-Orders
+ * Perform Subsystem Function / Orders
  */
 #define PSF_ORDER_PRSSD                         0x18
 #define PSF_ORDER_CUIR_RESPONSE                 0x1A
-#define PSF_SUBORDER_QHA                0x1C
 #define PSF_ORDER_SSC                   0x1D
 
+/*
+ * Perform Subsystem Function / Sub-Orders
+ */
+#define PSF_SUBORDER_QHA                0x1C /* Query Host Access */
+#define PSF_SUBORDER_VSQ                0x52 /* Volume Storage Query */
+#define PSF_SUBORDER_LCQ                0x53 /* Logical Configuration Query */
+
 /*
  * CUIR response condition codes
  */
 #define CUIR_QUIESCE                    0x01
 #define CUIR_RESUME                     0x02
 
+/*
+ * Out-of-space (OOS) Codes
+ */
+#define REPO_WARN                       0x01
+#define REPO_EXHAUST                    0x02
+#define POOL_WARN                       0x03
+#define POOL_EXHAUST                    0x04
+#define REPO_RELIEVE                    0x05
+#define POOL_RELIEVE                    0x06
+
 /*
  * attention message definitions
  */
 #define ATTENTION_LENGTH_CUIR           0x0e
 #define ATTENTION_FORMAT_CUIR           0x01
+#define ATTENTION_LENGTH_OOS            0x10
+#define ATTENTION_FORMAT_OOS            0x06
 
 #define DASD_ECKD_PG_GROUPED            0x10
 
 #define DASD_ECKD_PATH_THRHLD           256
 #define DASD_ECKD_PATH_INTERVAL                 300
 
+/*
+ * Maximum number of blocks to be chained
+ */
+#define DASD_ECKD_MAX_BLOCKS            190
+#define DASD_ECKD_MAX_BLOCKS_RAW        256
+
 /*****************************************************************************
  * SECTION: Type Definitions
  ****************************************************************************/
@@ -116,35 +144,12 @@ struct ch_t {
        __u16 head;
 } __attribute__ ((packed));
 
-struct chs_t {
-       __u16 cyl;
-       __u16 head;
-       __u32 sector;
-} __attribute__ ((packed));
-
 struct chr_t {
        __u16 cyl;
        __u16 head;
        __u8 record;
 } __attribute__ ((packed));
 
-struct geom_t {
-       __u16 cyl;
-       __u16 head;
-       __u32 sector;
-} __attribute__ ((packed));
-
-struct eckd_home {
-       __u8 skip_control[14];
-       __u16 cell_number;
-       __u8 physical_addr[3];
-       __u8 flag;
-       struct ch_t track_addr;
-       __u8 reserved;
-       __u8 key_length;
-       __u8 reserved2[2];
-} __attribute__ ((packed));
-
 struct DE_eckd_data {
        struct {
                unsigned char perm:2;   /* Permissions on this extent */
@@ -387,6 +392,86 @@ struct dasd_rssd_messages {
        char messages[4087];
 } __packed;
 
+/*
+ * Read Subsystem Data - Volume Storage Query
+ */
+struct dasd_rssd_vsq {
+       struct {
+               __u8 tse:1;
+               __u8 space_not_available:1;
+               __u8 ese:1;
+               __u8 unused:5;
+       } __packed vol_info;
+       __u8 unused1;
+       __u16 extent_pool_id;
+       __u8 warn_cap_limit;
+       __u8 warn_cap_guaranteed;
+       __u16 unused2;
+       __u32 limit_capacity;
+       __u32 guaranteed_capacity;
+       __u32 space_allocated;
+       __u32 space_configured;
+       __u32 logical_capacity;
+} __packed;
+
+/*
+ * Extent Pool Summary
+ */
+struct dasd_ext_pool_sum {
+       __u16 pool_id;
+       __u8 repo_warn_thrshld;
+       __u8 warn_thrshld;
+       struct {
+               __u8 type:1;                    /* 0 - CKD / 1 - FB */
+               __u8 track_space_efficient:1;
+               __u8 extent_space_efficient:1;
+               __u8 standard_volume:1;
+               __u8 extent_size_valid:1;
+               __u8 capacity_at_warnlevel:1;
+               __u8 pool_oos:1;
+               __u8 unused0:1;
+               __u8 unused1;
+       } __packed flags;
+       struct {
+               __u8 reserved0:1;
+               __u8 size_1G:1;
+               __u8 reserved1:5;
+               __u8 size_16M:1;
+       } __packed extent_size;
+       __u8 unused;
+} __packed;
+
+/*
+ * Read Subsystem Data-Response - Logical Configuration Query - Header
+ */
+struct dasd_rssd_lcq {
+       __u16 data_length;              /* Length of data returned */
+       __u16 pool_count;               /* Count of extent pools returned - Max: 448 */
+       struct {
+               __u8 pool_info_valid:1; /* Detailed Information valid */
+               __u8 pool_id_volume:1;
+               __u8 pool_id_cec:1;
+               __u8 unused0:5;
+               __u8 unused1;
+       } __packed header_flags;
+       char sfi_type[6];               /* Storage Facility Image Type (EBCDIC) */
+       char sfi_model[3];              /* Storage Facility Image Model (EBCDIC) */
+       __u8 sfi_seq_num[10];           /* Storage Facility Image Sequence Number */
+       __u8 reserved[7];
+       struct dasd_ext_pool_sum ext_pool_sum[448];
+} __packed;
+
+struct dasd_oos_message {
+       __u16 length;
+       __u8 format;
+       __u8 code;
+       __u8 percentage_empty;
+       __u8 reserved;
+       __u16 ext_pool_id;
+       __u16 token;
+       __u8 unused[6];
+} __packed;
+
 struct dasd_cuir_message {
        __u16 length;
        __u8 format;
@@ -461,6 +546,42 @@ struct dasd_psf_ssc_data {
        unsigned char reserved[59];
 } __attribute__((packed));
 
+/* Maximum number of extents for a single Release Allocated Space command */
+#define DASD_ECKD_RAS_EXTS_MAX         110U
+
+struct dasd_dso_ras_ext_range {
+       struct ch_t beg_ext;
+       struct ch_t end_ext;
+} __packed;
+
+/*
+ * Define Subsytem Operation - Release Allocated Space
+ */
+struct dasd_dso_ras_data {
+       __u8 order;
+       struct {
+               __u8 message:1;         /* Must be zero */
+               __u8 reserved1:2;
+               __u8 vol_type:1;        /* 0 - CKD/FBA, 1 - FB */
+               __u8 reserved2:4;
+       } __packed flags;
+       /* Operation Flags to specify scope */
+       struct {
+               __u8 reserved1:2;
+               /* Release Space by Extent */
+               __u8 by_extent:1;       /* 0 - entire volume, 1 - specified extents */
+               __u8 guarantee_init:1;
+               __u8 force_release:1;   /* Internal - will be ignored */
+               __u16 reserved2:11;
+       } __packed op_flags;
+       __u8 lss;
+       __u8 dev_addr;
+       __u32 reserved1;
+       __u8 reserved2[10];
+       __u16 nr_exts;                  /* Defines number of ext_scope - max 110 */
+       __u16 reserved3;
+} __packed;
+
 
 /*
  * some structures and definitions for alias handling
@@ -551,6 +672,8 @@ struct dasd_eckd_private {
        int uses_cdl;
        struct attrib_data_t attrib;    /* e.g. cache operations */
        struct dasd_rssd_features features;
+       struct dasd_rssd_vsq vsq;
+       struct dasd_ext_pool_sum eps;
        u32 real_cyl;
 
        /* alias managemnet */
@@ -572,7 +695,5 @@ int dasd_alias_remove_device(struct dasd_device *);
 struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *);
 void dasd_alias_handle_summary_unit_check(struct work_struct *);
 void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *);
-void dasd_alias_lcu_setup_complete(struct dasd_device *);
-void dasd_alias_wait_for_lcu_setup(struct dasd_device *);
 int dasd_alias_update_add_device(struct dasd_device *);
 #endif                         /* DASD_ECKD_H */
index 93bb09d..5ae64af 100644 (file)
@@ -386,6 +386,7 @@ void dasd_eer_write(struct dasd_device *device, struct dasd_ccw_req *cqr,
                dasd_eer_write_standard_trigger(device, cqr, id);
                break;
        case DASD_EER_NOPATH:
+       case DASD_EER_NOSPC:
                dasd_eer_write_standard_trigger(device, NULL, id);
                break;
        case DASD_EER_STATECHANGE:
index 56007a3..cbb7708 100644 (file)
@@ -770,27 +770,46 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
 }
 
 /*
- * max_blocks is dependent on the amount of storage that is available
- * in the static io buffer for each device. Currently each device has
- * 8192 bytes (=2 pages). For 64 bit one dasd_mchunkt_t structure has
- * 24 bytes, the struct dasd_ccw_req has 136 bytes and each block can use
- * up to 16 bytes (8 for the ccw and 8 for the idal pointer). In
- * addition we have one define extent ccw + 16 bytes of data and a
- * locate record ccw for each block (stupid devices!) + 16 bytes of data.
- * That makes:
- * (8192 - 24 - 136 - 8 - 16) / 40 = 200.2 blocks at maximum.
- * We want to fit two into the available memory so that we can immediately
- * start the next request if one finishes off. That makes 100.1 blocks
- * for one request. Give a little safety and the result is 96.
+ * Initialize block layer request queue.
  */
+static void dasd_fba_setup_blk_queue(struct dasd_block *block)
+{
+       unsigned int logical_block_size = block->bp_block;
+       struct request_queue *q = block->request_queue;
+       unsigned int max_bytes, max_discard_sectors;
+       int max;
+
+       max = DASD_FBA_MAX_BLOCKS << block->s2b_shift;
+       blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
+       q->limits.max_dev_sectors = max;
+       blk_queue_logical_block_size(q, logical_block_size);
+       blk_queue_max_hw_sectors(q, max);
+       blk_queue_max_segments(q, USHRT_MAX);
+       /* With page sized segments each segment can be translated into one idaw/tidaw */
+       blk_queue_max_segment_size(q, PAGE_SIZE);
+       blk_queue_segment_boundary(q, PAGE_SIZE - 1);
+
+       q->limits.discard_granularity = logical_block_size;
+       q->limits.discard_alignment = PAGE_SIZE;
+
+       /* Calculate max_discard_sectors and make it PAGE aligned */
+       max_bytes = USHRT_MAX * logical_block_size;
+       max_bytes = ALIGN_DOWN(max_bytes, PAGE_SIZE);
+       max_discard_sectors = max_bytes / logical_block_size;
+
+       blk_queue_max_discard_sectors(q, max_discard_sectors);
+       blk_queue_max_write_zeroes_sectors(q, max_discard_sectors);
+       blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
+}
+
 static struct dasd_discipline dasd_fba_discipline = {
        .owner = THIS_MODULE,
        .name = "FBA ",
        .ebcname = "FBA ",
-       .max_blocks = 96,
        .check_device = dasd_fba_check_characteristics,
        .do_analysis = dasd_fba_do_analysis,
        .verify_path = dasd_generic_verify_path,
+       .setup_blk_queue = dasd_fba_setup_blk_queue,
        .fill_geometry = dasd_fba_fill_geometry,
        .start_IO = dasd_start_IO,
        .term_IO = dasd_term_IO,
index b14bf1b..8f75df0 100644 (file)
@@ -9,6 +9,11 @@
 #ifndef DASD_FBA_H
 #define DASD_FBA_H
 
+/*
+ * Maximum number of blocks to be chained
+ */
+#define DASD_FBA_MAX_BLOCKS            96
+
 struct DE_fba_data {
        struct {
                unsigned char perm:2;   /* Permissions on this extent */
index de6b960..91c9f95 100644 (file)
@@ -268,7 +268,6 @@ struct dasd_discipline {
        struct module *owner;
        char ebcname[8];        /* a name used for tagging and printks */
        char name[8];           /* a name used for tagging and printks */
-       int max_blocks;         /* maximum number of blocks to be chained */
 
        struct list_head list;  /* used for list of disciplines */
 
@@ -307,6 +306,10 @@ struct dasd_discipline {
        int (*online_to_ready) (struct dasd_device *);
        int (*basic_to_known)(struct dasd_device *);
 
+       /*
+        * Initialize block layer request queue.
+        */
+       void (*setup_blk_queue)(struct dasd_block *);
        /* (struct dasd_device *);
         * Device operation functions. build_cp creates a ccw chain for
         * a block device request, start_io starts the request and
@@ -367,6 +370,25 @@ struct dasd_discipline {
        void (*disable_hpf)(struct dasd_device *);
        int (*hpf_enabled)(struct dasd_device *);
        void (*reset_path)(struct dasd_device *, __u8);
+
+       /*
+        * Extent Space Efficient (ESE) relevant functions
+        */
+       int (*is_ese)(struct dasd_device *);
+       /* Capacity */
+       int (*space_allocated)(struct dasd_device *);
+       int (*space_configured)(struct dasd_device *);
+       int (*logical_capacity)(struct dasd_device *);
+       int (*release_space)(struct dasd_device *, struct format_data_t *);
+       /* Extent Pool */
+       int (*ext_pool_id)(struct dasd_device *);
+       int (*ext_size)(struct dasd_device *);
+       int (*ext_pool_cap_at_warnlevel)(struct dasd_device *);
+       int (*ext_pool_warn_thrshld)(struct dasd_device *);
+       int (*ext_pool_oos)(struct dasd_device *);
+       int (*ext_pool_exhaust)(struct dasd_device *, struct dasd_ccw_req *);
+       struct dasd_ccw_req *(*ese_format)(struct dasd_device *, struct dasd_ccw_req *);
+       void (*ese_read)(struct dasd_ccw_req *);
 };
 
 extern struct dasd_discipline *dasd_diag_discipline_pointer;
@@ -386,6 +408,7 @@ extern struct dasd_discipline *dasd_diag_discipline_pointer;
 #define DASD_EER_NOPATH      2
 #define DASD_EER_STATECHANGE 3
 #define DASD_EER_PPRCSUSPEND 4
+#define DASD_EER_NOSPC      5
 
 /* DASD path handling */
 
@@ -482,8 +505,10 @@ struct dasd_device {
        spinlock_t mem_lock;
        void *ccw_mem;
        void *erp_mem;
+       void *ese_mem;
        struct list_head ccw_chunks;
        struct list_head erp_chunks;
+       struct list_head ese_chunks;
 
        atomic_t tasklet_scheduled;
         struct tasklet_struct tasklet;
@@ -558,6 +583,7 @@ struct dasd_queue {
 #define DASD_STOPPED_SU      16        /* summary unit check handling */
 #define DASD_STOPPED_PM      32        /* pm state transition */
 #define DASD_UNRESUMED_PM    64        /* pm resume failed state */
+#define DASD_STOPPED_NOSPC   128       /* no space left */
 
 /* per device flags */
 #define DASD_FLAG_OFFLINE      3       /* device is in offline processing */
@@ -700,7 +726,9 @@ extern struct kmem_cache *dasd_page_cache;
 
 struct dasd_ccw_req *
 dasd_smalloc_request(int, int, int, struct dasd_device *, struct dasd_ccw_req *);
+struct dasd_ccw_req *dasd_fmalloc_request(int, int, int, struct dasd_device *);
 void dasd_sfree_request(struct dasd_ccw_req *, struct dasd_device *);
+void dasd_ffree_request(struct dasd_ccw_req *, struct dasd_device *);
 void dasd_wakeup_cb(struct dasd_ccw_req *, void *);
 
 struct dasd_device *dasd_alloc_device(void);
@@ -727,6 +755,7 @@ void dasd_schedule_block_bh(struct dasd_block *);
 int  dasd_sleep_on(struct dasd_ccw_req *);
 int  dasd_sleep_on_queue(struct list_head *);
 int  dasd_sleep_on_immediatly(struct dasd_ccw_req *);
+int  dasd_sleep_on_queue_interruptible(struct list_head *);
 int  dasd_sleep_on_interruptible(struct dasd_ccw_req *);
 void dasd_device_set_timer(struct dasd_device *, int);
 void dasd_device_clear_timer(struct dasd_device *);
@@ -750,6 +779,8 @@ int dasd_generic_restore_device(struct ccw_device *);
 enum uc_todo dasd_generic_uc_handler(struct ccw_device *, struct irb *);
 void dasd_generic_path_event(struct ccw_device *, int *);
 int dasd_generic_verify_path(struct dasd_device *, __u8);
+void dasd_generic_space_exhaust(struct dasd_device *, struct dasd_ccw_req *);
+void dasd_generic_space_avail(struct dasd_device *);
 
 int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int);
 char *dasd_get_sense(struct irb *);
index 8e26001..9a5f3ad 100644 (file)
@@ -333,6 +333,59 @@ out_err:
        return rc;
 }
 
+static int dasd_release_space(struct dasd_device *device,
+                             struct format_data_t *rdata)
+{
+       if (!device->discipline->is_ese && !device->discipline->is_ese(device))
+               return -ENOTSUPP;
+       if (!device->discipline->release_space)
+               return -ENOTSUPP;
+
+       return device->discipline->release_space(device, rdata);
+}
+
+/*
+ * Release allocated space
+ */
+static int dasd_ioctl_release_space(struct block_device *bdev, void __user *argp)
+{
+       struct format_data_t rdata;
+       struct dasd_device *base;
+       int rc = 0;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+       if (!argp)
+               return -EINVAL;
+
+       base = dasd_device_from_gendisk(bdev->bd_disk);
+       if (!base)
+               return -ENODEV;
+       if (base->features & DASD_FEATURE_READONLY ||
+           test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) {
+               rc = -EROFS;
+               goto out_err;
+       }
+       if (bdev != bdev->bd_contains) {
+               pr_warn("%s: The specified DASD is a partition and tracks cannot be released\n",
+                       dev_name(&base->cdev->dev));
+               rc = -EINVAL;
+               goto out_err;
+       }
+
+       if (copy_from_user(&rdata, argp, sizeof(rdata))) {
+               rc = -EFAULT;
+               goto out_err;
+       }
+
+       rc = dasd_release_space(base, &rdata);
+
+out_err:
+       dasd_put_device(base);
+
+       return rc;
+}
+
 #ifdef CONFIG_DASD_PROFILE
 /*
  * Reset device profile information
@@ -595,6 +648,9 @@ int dasd_ioctl(struct block_device *bdev, fmode_t mode,
        case BIODASDREADALLCMB:
                rc = dasd_ioctl_readall_cmb(block, cmd, argp);
                break;
+       case BIODASDRAS:
+               rc = dasd_ioctl_release_space(bdev, argp);
+               break;
        default:
                /* if the discipline has an ioctl method try it. */
                rc = -ENOTTY;
index 6c90aa7..e71992a 100644 (file)
@@ -41,7 +41,6 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
        sclp.has_hvs = !!(sccb->fac119 & 0x80);
        sclp.has_kss = !!(sccb->fac98 & 0x01);
        sclp.has_sipl = !!(sccb->cbl & 0x02);
-       sclp.has_sipl_g2 = !!(sccb->cbl & 0x04);
        if (sccb->fac85 & 0x02)
                S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP;
        if (sccb->fac91 & 0x40)
index 4ebf6d4..c522e93 100644 (file)
@@ -581,7 +581,7 @@ int ccwgroup_driver_register(struct ccwgroup_driver *cdriver)
 }
 EXPORT_SYMBOL(ccwgroup_driver_register);
 
-static int __ccwgroup_match_all(struct device *dev, void *data)
+static int __ccwgroup_match_all(struct device *dev, const void *data)
 {
        return 1;
 }
@@ -608,9 +608,9 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
 }
 EXPORT_SYMBOL(ccwgroup_driver_unregister);
 
-static int __ccwgroupdev_check_busid(struct device *dev, void *id)
+static int __ccwgroupdev_check_busid(struct device *dev, const void *id)
 {
-       char *bus_id = id;
+       const char *bus_id = id;
 
        return (strcmp(bus_id, dev_name(dev)) == 0);
 }
index 8d9f366..8f080d3 100644 (file)
@@ -203,7 +203,7 @@ static void chsc_cleanup_sch_driver(void)
 
 static DEFINE_SPINLOCK(chsc_lock);
 
-static int chsc_subchannel_match_next_free(struct device *dev, void *data)
+static int chsc_subchannel_match_next_free(struct device *dev, const void *data)
 {
        struct subchannel *sch = to_subchannel(dev);
 
index e1f2d0e..22c5581 100644 (file)
@@ -491,10 +491,10 @@ static int css_probe_device(struct subchannel_id schid, struct schib *schib)
 }
 
 static int
-check_subchannel(struct device * dev, void * data)
+check_subchannel(struct device *dev, const void *data)
 {
        struct subchannel *sch;
-       struct subchannel_id *schid = data;
+       struct subchannel_id *schid = (void *)data;
 
        sch = to_subchannel(dev);
        return schid_equal(&sch->schid, schid);
index 9985b74..c421899 100644 (file)
@@ -643,10 +643,10 @@ static int ccw_device_add(struct ccw_device *cdev)
        return device_add(dev);
 }
 
-static int match_dev_id(struct device *dev, void *data)
+static int match_dev_id(struct device *dev, const void *data)
 {
        struct ccw_device *cdev = to_ccwdev(dev);
-       struct ccw_dev_id *dev_id = data;
+       struct ccw_dev_id *dev_id = (void *)data;
 
        return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id);
 }
@@ -1699,11 +1699,9 @@ EXPORT_SYMBOL_GPL(ccw_device_force_console);
  * get ccw_device matching the busid, but only if owned by cdrv
  */
 static int
-__ccwdev_check_busid(struct device *dev, void *id)
+__ccwdev_check_busid(struct device *dev, const void *id)
 {
-       char *bus_id;
-
-       bus_id = id;
+       const char *bus_id = id;
 
        return (strcmp(bus_id, dev_name(dev)) == 0);
 }
index 6bca1d5..9f26d43 100644 (file)
@@ -174,10 +174,10 @@ out:
                kobject_uevent(&scmdev->dev.kobj, KOBJ_CHANGE);
 }
 
-static int check_address(struct device *dev, void *data)
+static int check_address(struct device *dev, const void *data)
 {
        struct scm_device *scmdev = to_scm_dev(dev);
-       struct sale *sale = data;
+       const struct sale *sale = data;
 
        return scmdev->address == sale->sa;
 }
index b9fc502..a76b8a8 100644 (file)
@@ -208,7 +208,6 @@ static inline int ap_query_configuration(struct ap_config_info *info)
                return -EINVAL;
        return ap_qci(info);
 }
-EXPORT_SYMBOL(ap_query_configuration);
 
 /**
  * ap_init_configuration(): Allocate and query configuration array.
@@ -1356,16 +1355,16 @@ static int ap_get_compatible_type(ap_qid_t qid, int rawtype, unsigned int func)
  * Helper function to be used with bus_find_dev
  * matches for the card device with the given id
  */
-static int __match_card_device_with_id(struct device *dev, void *data)
+static int __match_card_device_with_id(struct device *dev, const void *data)
 {
-       return is_card_dev(dev) && to_ap_card(dev)->id == (int)(long) data;
+       return is_card_dev(dev) && to_ap_card(dev)->id == (int)(long)(void *) data;
 }
 
 /*
  * Helper function to be used with bus_find_dev
  * matches for the queue device with a given qid
  */
-static int __match_queue_device_with_qid(struct device *dev, void *data)
+static int __match_queue_device_with_qid(struct device *dev, const void *data)
 {
        return is_queue_dev(dev) && to_ap_queue(dev)->qid == (int)(long) data;
 }
@@ -1374,7 +1373,7 @@ static int __match_queue_device_with_qid(struct device *dev, void *data)
  * Helper function to be used with bus_find_dev
  * matches any queue device with given queue id
  */
-static int __match_queue_device_with_queue_id(struct device *dev, void *data)
+static int __match_queue_device_with_queue_id(struct device *dev, const void *data)
 {
        return is_queue_dev(dev)
                && AP_QID_QUEUE(to_ap_queue(dev)->qid) == (int)(long) data;
index 2c9fb14..0604b49 100644 (file)
@@ -26,7 +26,7 @@
 
 static int vfio_ap_mdev_reset_queues(struct mdev_device *mdev);
 
-static int match_apqn(struct device *dev, void *data)
+static int match_apqn(struct device *dev, const void *data)
 {
        struct vfio_ap_queue *q = dev_get_drvdata(dev);
 
@@ -115,7 +115,6 @@ static void vfio_ap_wait_for_irqclear(int apqn)
  * Unregisters the ISC in the GIB when the saved ISC not invalid.
  * Unpin the guest's page holding the NIB when it exist.
  * Reset the saved_pfn and saved_isc to invalid values.
- * Clear the pointer to the matrix mediated device.
  *
  */
 static void vfio_ap_free_aqic_resources(struct vfio_ap_queue *q)
@@ -127,7 +126,6 @@ static void vfio_ap_free_aqic_resources(struct vfio_ap_queue *q)
                                 &q->saved_pfn, 1);
        q->saved_pfn = 0;
        q->saved_isc = VFIO_AP_ISC_INVALID;
-       q->matrix_mdev = NULL;
 }
 
 /**
@@ -179,6 +177,7 @@ struct ap_queue_status vfio_ap_irq_disable(struct vfio_ap_queue *q)
                  status.response_code);
 end_free:
        vfio_ap_free_aqic_resources(q);
+       q->matrix_mdev = NULL;
        return status;
 }
 
index 33eddb0..b018b61 100644 (file)
@@ -620,7 +620,7 @@ static void zfcp_fc_sg_free_table(struct scatterlist *sg, int count)
 {
        int i;
 
-       for (i = 0; i < count; i++, sg++)
+       for (i = 0; i < count; i++, sg = sg_next(sg))
                if (sg)
                        free_page((unsigned long) sg_virt(sg));
                else
@@ -641,7 +641,7 @@ static int zfcp_fc_sg_setup_table(struct scatterlist *sg, int count)
        int i;
 
        sg_init_table(sg, count);
-       for (i = 0; i < count; i++, sg++) {
+       for (i = 0; i < count; i++, sg = sg_next(sg)) {
                addr = (void *) get_zeroed_page(GFP_KERNEL);
                if (!addr) {
                        zfcp_fc_sg_free_table(sg, i);
index f31b6b7..75f66f8 100644 (file)
@@ -99,28 +99,6 @@ config CHR_DEV_ST
          To compile this driver as a module, choose M here and read
          <file:Documentation/scsi/scsi.txt>. The module will be called st.
 
-config CHR_DEV_OSST
-       tristate "SCSI OnStream SC-x0 tape support"
-       depends on SCSI
-       ---help---
-         The OnStream SC-x0 SCSI tape drives cannot be driven by the
-         standard st driver, but instead need this special osst driver and
-         use the  /dev/osstX char device nodes (major 206).  Via usb-storage,
-         you may be able to drive the USB-x0 and DI-x0 drives as well.
-         Note that there is also a second generation of OnStream
-         tape drives (ADR-x0) that supports the standard SCSI-2 commands for
-         tapes (QIC-157) and can be driven by the standard driver st.
-         For more information, you may have a look at the SCSI-HOWTO
-         <http://www.tldp.org/docs.html#howto>  and
-         <file:Documentation/scsi/osst.txt>  in the kernel source.
-         More info on the OnStream driver may be found on
-         <http://sourceforge.net/projects/osst/>
-         Please also have a look at the standard st docu, as most of it
-         applies to osst as well.
-
-         To compile this driver as a module, choose M here and read
-         <file:Documentation/scsi/scsi.txt>. The module will be called osst.
-
 config BLK_DEV_SR
        tristate "SCSI CDROM support"
        depends on SCSI && BLK_DEV
@@ -664,6 +642,41 @@ config SCSI_DMX3191D
          To compile this driver as a module, choose M here: the
          module will be called dmx3191d.
 
+config SCSI_FDOMAIN
+       tristate
+       depends on SCSI
+
+config SCSI_FDOMAIN_PCI
+       tristate "Future Domain TMC-3260/AHA-2920A PCI SCSI support"
+       depends on PCI && SCSI
+       select SCSI_FDOMAIN
+       help
+         This is support for Future Domain's PCI SCSI host adapters (TMC-3260)
+         and other adapters with PCI bus based on the Future Domain chipsets
+         (Adaptec AHA-2920A).
+
+         NOTE: Newer Adaptec AHA-2920C boards use the Adaptec AIC-7850 chip
+         and should use the aic7xxx driver ("Adaptec AIC7xxx chipset SCSI
+         controller support"). This Future Domain driver works with the older
+         Adaptec AHA-2920A boards with a Future Domain chip on them.
+
+         To compile this driver as a module, choose M here: the
+         module will be called fdomain_pci.
+
+config SCSI_FDOMAIN_ISA
+       tristate "Future Domain 16xx ISA SCSI support"
+       depends on ISA && SCSI
+       select CHECK_SIGNATURE
+       select SCSI_FDOMAIN
+       help
+         This is support for Future Domain's 16-bit SCSI host adapters
+         (TMC-1660/1680, TMC-1650/1670, TMC-1610M/MER/MEX) and other adapters
+         with ISA bus based on the Future Domain chipsets (Quantum ISA-200S,
+         ISA-250MG; and at least one IBM board).
+
+         To compile this driver as a module, choose M here: the
+         module will be called fdomain_isa.
+
 config SCSI_GDTH
        tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support"
        depends on PCI && SCSI
index 8826111..aeda539 100644 (file)
@@ -76,6 +76,9 @@ obj-$(CONFIG_SCSI_AIC94XX)    += aic94xx/
 obj-$(CONFIG_SCSI_PM8001)      += pm8001/
 obj-$(CONFIG_SCSI_ISCI)                += isci/
 obj-$(CONFIG_SCSI_IPS)         += ips.o
+obj-$(CONFIG_SCSI_FDOMAIN)     += fdomain.o
+obj-$(CONFIG_SCSI_FDOMAIN_PCI) += fdomain_pci.o
+obj-$(CONFIG_SCSI_FDOMAIN_ISA) += fdomain_isa.o
 obj-$(CONFIG_SCSI_GENERIC_NCR5380) += g_NCR5380.o
 obj-$(CONFIG_SCSI_QLOGIC_FAS)  += qlogicfas408.o       qlogicfas.o
 obj-$(CONFIG_PCMCIA_QLOGIC)    += qlogicfas408.o
@@ -143,7 +146,6 @@ obj-$(CONFIG_SCSI_WD719X)   += wd719x.o
 obj-$(CONFIG_ARM)              += arm/
 
 obj-$(CONFIG_CHR_DEV_ST)       += st.o
-obj-$(CONFIG_CHR_DEV_OSST)     += osst.o
 obj-$(CONFIG_BLK_DEV_SD)       += sd_mod.o
 obj-$(CONFIG_BLK_DEV_SR)       += sr_mod.o
 obj-$(CONFIG_CHR_DEV_SG)       += sg.o
index fe0535a..536426f 100644 (file)
@@ -149,12 +149,10 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd)
 
        if (scsi_bufflen(cmd)) {
                cmd->SCp.buffer = scsi_sglist(cmd);
-               cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
                cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
                cmd->SCp.this_residual = cmd->SCp.buffer->length;
        } else {
                cmd->SCp.buffer = NULL;
-               cmd->SCp.buffers_residual = 0;
                cmd->SCp.ptr = NULL;
                cmd->SCp.this_residual = 0;
        }
@@ -163,6 +161,17 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd)
        cmd->SCp.Message = 0;
 }
 
+static inline void advance_sg_buffer(struct scsi_cmnd *cmd)
+{
+       struct scatterlist *s = cmd->SCp.buffer;
+
+       if (!cmd->SCp.this_residual && s && !sg_is_last(s)) {
+               cmd->SCp.buffer = sg_next(s);
+               cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
+               cmd->SCp.this_residual = cmd->SCp.buffer->length;
+       }
+}
+
 /**
  * NCR5380_poll_politely2 - wait for two chip register values
  * @hostdata: host private data
@@ -709,6 +718,8 @@ static void NCR5380_main(struct work_struct *work)
                        NCR5380_information_transfer(instance);
                        done = 0;
                }
+               if (!hostdata->connected)
+                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
                spin_unlock_irq(&hostdata->lock);
                if (!done)
                        cond_resched();
@@ -1110,8 +1121,6 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
                spin_lock_irq(&hostdata->lock);
                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
                NCR5380_reselect(instance);
-               if (!hostdata->connected)
-                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
                shost_printk(KERN_ERR, instance, "reselection after won arbitration?\n");
                goto out;
        }
@@ -1119,7 +1128,6 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
        if (err < 0) {
                spin_lock_irq(&hostdata->lock);
                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-               NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
 
                /* Can't touch cmd if it has been reclaimed by the scsi ML */
                if (!hostdata->selecting)
@@ -1157,7 +1165,6 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
        if (err < 0) {
                shost_printk(KERN_ERR, instance, "select: REQ timeout\n");
                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-               NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
                goto out;
        }
        if (!hostdata->selecting) {
@@ -1672,12 +1679,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                            sun3_dma_setup_done != cmd) {
                                int count;
 
-                               if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
-                                       ++cmd->SCp.buffer;
-                                       --cmd->SCp.buffers_residual;
-                                       cmd->SCp.this_residual = cmd->SCp.buffer->length;
-                                       cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
-                               }
+                               advance_sg_buffer(cmd);
 
                                count = sun3scsi_dma_xfer_len(hostdata, cmd);
 
@@ -1727,15 +1729,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                 * scatter-gather list, move onto the next one.
                                 */
 
-                               if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
-                                       ++cmd->SCp.buffer;
-                                       --cmd->SCp.buffers_residual;
-                                       cmd->SCp.this_residual = cmd->SCp.buffer->length;
-                                       cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
-                                       dsprintk(NDEBUG_INFORMATION, instance, "%d bytes and %d buffers left\n",
-                                                cmd->SCp.this_residual,
-                                                cmd->SCp.buffers_residual);
-                               }
+                               advance_sg_buffer(cmd);
+                               dsprintk(NDEBUG_INFORMATION, instance,
+                                       "this residual %d, sg ents %d\n",
+                                       cmd->SCp.this_residual,
+                                       sg_nents(cmd->SCp.buffer));
 
                                /*
                                 * The preferred transfer method is going to be
@@ -1763,10 +1761,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                                scmd_printk(KERN_INFO, cmd,
                                                        "switching to slow handshake\n");
                                                cmd->device->borken = 1;
-                                               sink = 1;
-                                               do_abort(instance);
-                                               cmd->result = DID_ERROR << 16;
-                                               /* XXX - need to source or sink data here, as appropriate */
+                                               do_reset(instance);
+                                               bus_reset_cleanup(instance);
                                        }
                                } else {
                                        /* Transfer a small chunk so that the
@@ -1826,9 +1822,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                         */
                                        NCR5380_write(TARGET_COMMAND_REG, 0);
 
-                                       /* Enable reselect interrupts */
-                                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-
                                        maybe_release_dma_irq(instance);
                                        return;
                                case MESSAGE_REJECT:
@@ -1860,8 +1853,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                         */
                                        NCR5380_write(TARGET_COMMAND_REG, 0);
 
-                                       /* Enable reselect interrupts */
-                                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
 #ifdef SUN3_SCSI_VME
                                        dregs->csr |= CSR_DMA_ENABLE;
 #endif
@@ -1964,7 +1955,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                        cmd->result = DID_ERROR << 16;
                                        complete_cmd(instance, cmd);
                                        maybe_release_dma_irq(instance);
-                                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
                                        return;
                                }
                                msgout = NOP;
@@ -2136,12 +2126,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
        if (sun3_dma_setup_done != tmp) {
                int count;
 
-               if (!tmp->SCp.this_residual && tmp->SCp.buffers_residual) {
-                       ++tmp->SCp.buffer;
-                       --tmp->SCp.buffers_residual;
-                       tmp->SCp.this_residual = tmp->SCp.buffer->length;
-                       tmp->SCp.ptr = sg_virt(tmp->SCp.buffer);
-               }
+               advance_sg_buffer(tmp);
 
                count = sun3scsi_dma_xfer_len(hostdata, tmp);
 
index efca509..5935fd6 100644 (file)
@@ -235,7 +235,7 @@ struct NCR5380_cmd {
 #define NCR5380_PIO_CHUNK_SIZE         256
 
 /* Time limit (ms) to poll registers when IRQs are disabled, e.g. during PDMA */
-#define NCR5380_REG_POLL_TIME          15
+#define NCR5380_REG_POLL_TIME          10
 
 static inline struct scsi_cmnd *NCR5380_to_scmd(struct NCR5380_cmd *ncmd_ptr)
 {
index 926311c..a242a62 100644 (file)
@@ -7710,7 +7710,7 @@ adv_get_sglist(struct asc_board *boardp, adv_req_t *reqp,
                                sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
                                return ADV_SUCCESS;
                        }
-                       slp++;
+                       slp = sg_next(slp);
                }
                sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
                prev_sg_block = sg_block;
index 88c649b..eb466c2 100644 (file)
@@ -937,7 +937,6 @@ static int aha152x_internal_queue(struct scsi_cmnd *SCpnt,
           SCp.ptr              : buffer pointer
           SCp.this_residual    : buffer length
           SCp.buffer           : next buffer
-          SCp.buffers_residual : left buffers in list
           SCp.phase            : current state of the command */
 
        if ((phase & resetting) || !scsi_sglist(SCpnt)) {
@@ -945,13 +944,11 @@ static int aha152x_internal_queue(struct scsi_cmnd *SCpnt,
                SCpnt->SCp.this_residual = 0;
                scsi_set_resid(SCpnt, 0);
                SCpnt->SCp.buffer           = NULL;
-               SCpnt->SCp.buffers_residual = 0;
        } else {
                scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
                SCpnt->SCp.buffer           = scsi_sglist(SCpnt);
                SCpnt->SCp.ptr              = SG_ADDRESS(SCpnt->SCp.buffer);
                SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
-               SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1;
        }
 
        DO_LOCK(flags);
@@ -2019,10 +2016,9 @@ static void datai_run(struct Scsi_Host *shpnt)
                                }
 
                                if (CURRENT_SC->SCp.this_residual == 0 &&
-                                   CURRENT_SC->SCp.buffers_residual > 0) {
+                                   !sg_is_last(CURRENT_SC->SCp.buffer)) {
                                        /* advance to next buffer */
-                                       CURRENT_SC->SCp.buffers_residual--;
-                                       CURRENT_SC->SCp.buffer++;
+                                       CURRENT_SC->SCp.buffer = sg_next(CURRENT_SC->SCp.buffer);
                                        CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer);
                                        CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
                                }
@@ -2125,10 +2121,10 @@ static void datao_run(struct Scsi_Host *shpnt)
                        CMD_INC_RESID(CURRENT_SC, -2 * data_count);
                }
 
-               if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) {
+               if (CURRENT_SC->SCp.this_residual == 0 &&
+                   !sg_is_last(CURRENT_SC->SCp.buffer)) {
                        /* advance to next buffer */
-                       CURRENT_SC->SCp.buffers_residual--;
-                       CURRENT_SC->SCp.buffer++;
+                       CURRENT_SC->SCp.buffer = sg_next(CURRENT_SC->SCp.buffer);
                        CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer);
                        CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
                }
@@ -2147,22 +2143,26 @@ static void datao_run(struct Scsi_Host *shpnt)
 static void datao_end(struct Scsi_Host *shpnt)
 {
        if(TESTLO(DMASTAT, DFIFOEMP)) {
-               int data_count = (DATA_LEN - scsi_get_resid(CURRENT_SC)) -
-                       GETSTCNT();
+               u32 datao_cnt = GETSTCNT();
+               int datao_out = DATA_LEN - scsi_get_resid(CURRENT_SC);
+               int done;
+               struct scatterlist *sg = scsi_sglist(CURRENT_SC);
 
-               CMD_INC_RESID(CURRENT_SC, data_count);
+               CMD_INC_RESID(CURRENT_SC, datao_out - datao_cnt);
 
-               data_count -= CURRENT_SC->SCp.ptr -
-                       SG_ADDRESS(CURRENT_SC->SCp.buffer);
-               while(data_count>0) {
-                       CURRENT_SC->SCp.buffer--;
-                       CURRENT_SC->SCp.buffers_residual++;
-                       data_count -= CURRENT_SC->SCp.buffer->length;
+               done = scsi_bufflen(CURRENT_SC) - scsi_get_resid(CURRENT_SC);
+               /* Locate the first SG entry not yet sent */
+               while (done > 0 && !sg_is_last(sg)) {
+                       if (done < sg->length)
+                               break;
+                       done -= sg->length;
+                       sg = sg_next(sg);
                }
-               CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) -
-                       data_count;
-               CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length +
-                       data_count;
+
+               CURRENT_SC->SCp.buffer = sg;
+               CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) + done;
+               CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length -
+                       done;
        }
 
        SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
@@ -2490,7 +2490,7 @@ static void get_command(struct seq_file *m, struct scsi_cmnd * ptr)
 
        seq_printf(m, "); resid=%d; residual=%d; buffers=%d; phase |",
                scsi_get_resid(ptr), ptr->SCp.this_residual,
-               ptr->SCp.buffers_residual);
+               sg_nents(ptr->SCp.buffer) - 1);
 
        if (ptr->SCp.phase & not_issued)
                seq_puts(m, "not issued|");
index ba0b411..00fde22 100644 (file)
@@ -1666,7 +1666,7 @@ scratch_ram {
        size            6
        /*
         * These are reserved registers in the card's scratch ram on the 2742.
-        * The EISA configuraiton chip is mapped here.  On Rev E. of the
+        * The EISA configuration chip is mapped here.  On Rev E. of the
         * aic7770, the sequencer can use this area for scratch, but the
         * host cannot directly access these registers.  On later chips, this
         * area can be read and written by both the host and the sequencer.
index 730b35e..604a533 100644 (file)
@@ -170,9 +170,7 @@ static int asd_init_target_ddb(struct domain_device *dev)
                        }
                } else {
                        flags |= CONCURRENT_CONN_SUPP;
-                       if (!dev->parent &&
-                           (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE ||
-                            dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE))
+                       if (!dev->parent && dev_is_expander(dev->dev_type))
                                asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN,
                                                       4);
                        else
index 901a316..3b84db8 100644 (file)
@@ -66,7 +66,7 @@
 #include "bnx2fc_constants.h"
 
 #define BNX2FC_NAME            "bnx2fc"
-#define BNX2FC_VERSION         "2.11.8"
+#define BNX2FC_VERSION         "2.12.10"
 
 #define PFX                    "bnx2fc: "
 
@@ -75,8 +75,9 @@
 #define BNX2X_DOORBELL_PCI_BAR         2
 
 #define BNX2FC_MAX_BD_LEN              0xffff
-#define BNX2FC_BD_SPLIT_SZ             0x8000
-#define BNX2FC_MAX_BDS_PER_CMD         256
+#define BNX2FC_BD_SPLIT_SZ             0xffff
+#define BNX2FC_MAX_BDS_PER_CMD         255
+#define BNX2FC_FW_MAX_BDS_PER_CMD      255
 
 #define BNX2FC_SQ_WQES_MAX     256
 
@@ -433,8 +434,10 @@ struct bnx2fc_cmd {
        void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg);
        struct bnx2fc_els_cb_arg *cb_arg;
        struct delayed_work timeout_work; /* timer for ULP timeouts */
-       struct completion tm_done;
-       int wait_for_comp;
+       struct completion abts_done;
+       struct completion cleanup_done;
+       int wait_for_abts_comp;
+       int wait_for_cleanup_comp;
        u16 xid;
        struct fcoe_err_report_entry err_entry;
        struct fcoe_task_ctx_entry *task;
@@ -455,6 +458,7 @@ struct bnx2fc_cmd {
 #define BNX2FC_FLAG_ELS_TIMEOUT                0xb
 #define BNX2FC_FLAG_CMD_LOST           0xc
 #define BNX2FC_FLAG_SRR_SENT           0xd
+#define BNX2FC_FLAG_ISSUE_CLEANUP_REQ  0xe
        u8 rec_retry;
        u8 srr_retry;
        u32 srr_offset;
index 76e65a3..754f2e8 100644 (file)
@@ -610,7 +610,6 @@ int bnx2fc_send_rec(struct bnx2fc_cmd *orig_io_req)
        rc = bnx2fc_initiate_els(tgt, ELS_REC, &rec, sizeof(rec),
                                 bnx2fc_rec_compl, cb_arg,
                                 r_a_tov);
-rec_err:
        if (rc) {
                BNX2FC_IO_DBG(orig_io_req, "REC failed - release\n");
                spin_lock_bh(&tgt->tgt_lock);
@@ -618,6 +617,7 @@ rec_err:
                spin_unlock_bh(&tgt->tgt_lock);
                kfree(cb_arg);
        }
+rec_err:
        return rc;
 }
 
@@ -654,7 +654,6 @@ int bnx2fc_send_srr(struct bnx2fc_cmd *orig_io_req, u32 offset, u8 r_ctl)
        rc = bnx2fc_initiate_els(tgt, ELS_SRR, &srr, sizeof(srr),
                                 bnx2fc_srr_compl, cb_arg,
                                 r_a_tov);
-srr_err:
        if (rc) {
                BNX2FC_IO_DBG(orig_io_req, "SRR failed - release\n");
                spin_lock_bh(&tgt->tgt_lock);
@@ -664,6 +663,7 @@ srr_err:
        } else
                set_bit(BNX2FC_FLAG_SRR_SENT, &orig_io_req->req_flags);
 
+srr_err:
        return rc;
 }
 
@@ -854,33 +854,57 @@ void bnx2fc_process_els_compl(struct bnx2fc_cmd *els_req,
        kref_put(&els_req->refcount, bnx2fc_cmd_release);
 }
 
+#define                BNX2FC_FCOE_MAC_METHOD_GRANGED_MAC      1
+#define                BNX2FC_FCOE_MAC_METHOD_FCF_MAP          2
+#define                BNX2FC_FCOE_MAC_METHOD_FCOE_SET_MAC     3
 static void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp,
                              void *arg)
 {
        struct fcoe_ctlr *fip = arg;
        struct fc_exch *exch = fc_seq_exch(seq);
        struct fc_lport *lport = exch->lp;
-       u8 *mac;
-       u8 op;
+
+       struct fc_frame_header *fh;
+       u8 *granted_mac;
+       u8 fcoe_mac[6];
+       u8 fc_map[3];
+       int method;
 
        if (IS_ERR(fp))
                goto done;
 
-       mac = fr_cb(fp)->granted_mac;
-       if (is_zero_ether_addr(mac)) {
-               op = fc_frame_payload_op(fp);
-               if (lport->vport) {
-                       if (op == ELS_LS_RJT) {
-                               printk(KERN_ERR PFX "bnx2fc_flogi_resp is LS_RJT\n");
-                               fc_vport_terminate(lport->vport);
-                               fc_frame_free(fp);
-                               return;
-                       }
-               }
-               fcoe_ctlr_recv_flogi(fip, lport, fp);
+       fh = fc_frame_header_get(fp);
+       granted_mac = fr_cb(fp)->granted_mac;
+
+       /*
+        * We set the source MAC for FCoE traffic based on the Granted MAC
+        * address from the switch.
+        *
+        * If granted_mac is non-zero, we use that.
+        * If the granted_mac is zeroed out, create the FCoE MAC based on
+        * the sel_fcf->fc_map and the d_id fo the FLOGI frame.
+        * If sel_fcf->fc_map is 0, then we use the default FCF-MAC plus the
+        * d_id of the FLOGI frame.
+        */
+       if (!is_zero_ether_addr(granted_mac)) {
+               ether_addr_copy(fcoe_mac, granted_mac);
+               method = BNX2FC_FCOE_MAC_METHOD_GRANGED_MAC;
+       } else if (fip->sel_fcf && fip->sel_fcf->fc_map != 0) {
+               hton24(fc_map, fip->sel_fcf->fc_map);
+               fcoe_mac[0] = fc_map[0];
+               fcoe_mac[1] = fc_map[1];
+               fcoe_mac[2] = fc_map[2];
+               fcoe_mac[3] = fh->fh_d_id[0];
+               fcoe_mac[4] = fh->fh_d_id[1];
+               fcoe_mac[5] = fh->fh_d_id[2];
+               method = BNX2FC_FCOE_MAC_METHOD_FCF_MAP;
+       } else {
+               fc_fcoe_set_mac(fcoe_mac, fh->fh_d_id);
+               method = BNX2FC_FCOE_MAC_METHOD_FCOE_SET_MAC;
        }
-       if (!is_zero_ether_addr(mac))
-               fip->update_mac(lport, mac);
+
+       BNX2FC_HBA_DBG(lport, "fcoe_mac=%pM method=%d\n", fcoe_mac, method);
+       fip->update_mac(lport, fcoe_mac);
 done:
        fc_lport_flogi_resp(seq, fp, lport);
 }
index a75e74a..7796799 100644 (file)
@@ -2971,7 +2971,8 @@ static struct scsi_host_template bnx2fc_shost_template = {
        .this_id                = -1,
        .cmd_per_lun            = 3,
        .sg_tablesize           = BNX2FC_MAX_BDS_PER_CMD,
-       .max_sectors            = 1024,
+       .dma_boundary           = 0x7fff,
+       .max_sectors            = 0x3fbf,
        .track_queue_depth      = 1,
        .slave_configure        = bnx2fc_slave_configure,
        .shost_attrs            = bnx2fc_host_attrs,
index 8def63c..9e50e5b 100644 (file)
@@ -70,7 +70,7 @@ static void bnx2fc_cmd_timeout(struct work_struct *work)
                                                        &io_req->req_flags)) {
                        /* Handle eh_abort timeout */
                        BNX2FC_IO_DBG(io_req, "eh_abort timed out\n");
-                       complete(&io_req->tm_done);
+                       complete(&io_req->abts_done);
                } else if (test_bit(BNX2FC_FLAG_ISSUE_ABTS,
                                    &io_req->req_flags)) {
                        /* Handle internally generated ABTS timeout */
@@ -775,31 +775,32 @@ retry_tmf:
        io_req->on_tmf_queue = 1;
        list_add_tail(&io_req->link, &tgt->active_tm_queue);
 
-       init_completion(&io_req->tm_done);
-       io_req->wait_for_comp = 1;
+       init_completion(&io_req->abts_done);
+       io_req->wait_for_abts_comp = 1;
 
        /* Ring doorbell */
        bnx2fc_ring_doorbell(tgt);
        spin_unlock_bh(&tgt->tgt_lock);
 
-       rc = wait_for_completion_timeout(&io_req->tm_done,
+       rc = wait_for_completion_timeout(&io_req->abts_done,
                                         interface->tm_timeout * HZ);
        spin_lock_bh(&tgt->tgt_lock);
 
-       io_req->wait_for_comp = 0;
+       io_req->wait_for_abts_comp = 0;
        if (!(test_bit(BNX2FC_FLAG_TM_COMPL, &io_req->req_flags))) {
                set_bit(BNX2FC_FLAG_TM_TIMEOUT, &io_req->req_flags);
                if (io_req->on_tmf_queue) {
                        list_del_init(&io_req->link);
                        io_req->on_tmf_queue = 0;
                }
-               io_req->wait_for_comp = 1;
+               io_req->wait_for_cleanup_comp = 1;
+               init_completion(&io_req->cleanup_done);
                bnx2fc_initiate_cleanup(io_req);
                spin_unlock_bh(&tgt->tgt_lock);
-               rc = wait_for_completion_timeout(&io_req->tm_done,
+               rc = wait_for_completion_timeout(&io_req->cleanup_done,
                                                 BNX2FC_FW_TIMEOUT);
                spin_lock_bh(&tgt->tgt_lock);
-               io_req->wait_for_comp = 0;
+               io_req->wait_for_cleanup_comp = 0;
                if (!rc)
                        kref_put(&io_req->refcount, bnx2fc_cmd_release);
        }
@@ -1047,6 +1048,9 @@ int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req)
        /* Obtain free SQ entry */
        bnx2fc_add_2_sq(tgt, xid);
 
+       /* Set flag that cleanup request is pending with the firmware */
+       set_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, &io_req->req_flags);
+
        /* Ring doorbell */
        bnx2fc_ring_doorbell(tgt);
 
@@ -1085,7 +1089,8 @@ static int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req)
        struct bnx2fc_rport *tgt = io_req->tgt;
        unsigned int time_left;
 
-       io_req->wait_for_comp = 1;
+       init_completion(&io_req->cleanup_done);
+       io_req->wait_for_cleanup_comp = 1;
        bnx2fc_initiate_cleanup(io_req);
 
        spin_unlock_bh(&tgt->tgt_lock);
@@ -1094,21 +1099,21 @@ static int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req)
         * Can't wait forever on cleanup response lest we let the SCSI error
         * handler wait forever
         */
-       time_left = wait_for_completion_timeout(&io_req->tm_done,
+       time_left = wait_for_completion_timeout(&io_req->cleanup_done,
                                                BNX2FC_FW_TIMEOUT);
-       io_req->wait_for_comp = 0;
-       if (!time_left)
+       if (!time_left) {
                BNX2FC_IO_DBG(io_req, "%s(): Wait for cleanup timed out.\n",
                              __func__);
 
-       /*
-        * Release reference held by SCSI command the cleanup completion
-        * hits the BNX2FC_CLEANUP case in bnx2fc_process_cq_compl() and
-        * thus the SCSI command is not returnedi by bnx2fc_scsi_done().
-        */
-       kref_put(&io_req->refcount, bnx2fc_cmd_release);
+               /*
+                * Put the extra reference to the SCSI command since it would
+                * not have been returned in this case.
+                */
+               kref_put(&io_req->refcount, bnx2fc_cmd_release);
+       }
 
        spin_lock_bh(&tgt->tgt_lock);
+       io_req->wait_for_cleanup_comp = 0;
        return SUCCESS;
 }
 
@@ -1197,7 +1202,8 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
        /* Move IO req to retire queue */
        list_add_tail(&io_req->link, &tgt->io_retire_queue);
 
-       init_completion(&io_req->tm_done);
+       init_completion(&io_req->abts_done);
+       init_completion(&io_req->cleanup_done);
 
        if (test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) {
                printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) "
@@ -1225,26 +1231,28 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
                kref_put(&io_req->refcount,
                         bnx2fc_cmd_release); /* drop timer hold */
        set_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags);
-       io_req->wait_for_comp = 1;
+       io_req->wait_for_abts_comp = 1;
        rc = bnx2fc_initiate_abts(io_req);
        if (rc == FAILED) {
+               io_req->wait_for_cleanup_comp = 1;
                bnx2fc_initiate_cleanup(io_req);
                spin_unlock_bh(&tgt->tgt_lock);
-               wait_for_completion(&io_req->tm_done);
+               wait_for_completion(&io_req->cleanup_done);
                spin_lock_bh(&tgt->tgt_lock);
-               io_req->wait_for_comp = 0;
+               io_req->wait_for_cleanup_comp = 0;
                goto done;
        }
        spin_unlock_bh(&tgt->tgt_lock);
 
        /* Wait 2 * RA_TOV + 1 to be sure timeout function hasn't fired */
-       time_left = wait_for_completion_timeout(&io_req->tm_done,
-           (2 * rp->r_a_tov + 1) * HZ);
+       time_left = wait_for_completion_timeout(&io_req->abts_done,
+                                               (2 * rp->r_a_tov + 1) * HZ);
        if (time_left)
-               BNX2FC_IO_DBG(io_req, "Timed out in eh_abort waiting for tm_done");
+               BNX2FC_IO_DBG(io_req,
+                             "Timed out in eh_abort waiting for abts_done");
 
        spin_lock_bh(&tgt->tgt_lock);
-       io_req->wait_for_comp = 0;
+       io_req->wait_for_abts_comp = 0;
        if (test_bit(BNX2FC_FLAG_IO_COMPL, &io_req->req_flags)) {
                BNX2FC_IO_DBG(io_req, "IO completed in a different context\n");
                rc = SUCCESS;
@@ -1319,10 +1327,29 @@ void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req,
        BNX2FC_IO_DBG(io_req, "Entered process_cleanup_compl "
                              "refcnt = %d, cmd_type = %d\n",
                   kref_read(&io_req->refcount), io_req->cmd_type);
+       /*
+        * Test whether there is a cleanup request pending. If not just
+        * exit.
+        */
+       if (!test_and_clear_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ,
+                               &io_req->req_flags))
+               return;
+       /*
+        * If we receive a cleanup completion for this request then the
+        * firmware will not give us an abort completion for this request
+        * so clear any ABTS pending flags.
+        */
+       if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags) &&
+           !test_bit(BNX2FC_FLAG_ABTS_DONE, &io_req->req_flags)) {
+               set_bit(BNX2FC_FLAG_ABTS_DONE, &io_req->req_flags);
+               if (io_req->wait_for_abts_comp)
+                       complete(&io_req->abts_done);
+       }
+
        bnx2fc_scsi_done(io_req, DID_ERROR);
        kref_put(&io_req->refcount, bnx2fc_cmd_release);
-       if (io_req->wait_for_comp)
-               complete(&io_req->tm_done);
+       if (io_req->wait_for_cleanup_comp)
+               complete(&io_req->cleanup_done);
 }
 
 void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req,
@@ -1346,6 +1373,16 @@ void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req,
                return;
        }
 
+       /*
+        * If we receive an ABTS completion here then we will not receive
+        * a cleanup completion so clear any cleanup pending flags.
+        */
+       if (test_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, &io_req->req_flags)) {
+               clear_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, &io_req->req_flags);
+               if (io_req->wait_for_cleanup_comp)
+                       complete(&io_req->cleanup_done);
+       }
+
        /* Do not issue RRQ as this IO is already cleanedup */
        if (test_and_set_bit(BNX2FC_FLAG_IO_CLEANUP,
                                &io_req->req_flags))
@@ -1390,10 +1427,10 @@ void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req,
        bnx2fc_cmd_timer_set(io_req, r_a_tov);
 
 io_compl:
-       if (io_req->wait_for_comp) {
+       if (io_req->wait_for_abts_comp) {
                if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT,
                                       &io_req->req_flags))
-                       complete(&io_req->tm_done);
+                       complete(&io_req->abts_done);
        } else {
                /*
                 * We end up here when ABTS is issued as
@@ -1577,9 +1614,9 @@ void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req,
        sc_cmd->scsi_done(sc_cmd);
 
        kref_put(&io_req->refcount, bnx2fc_cmd_release);
-       if (io_req->wait_for_comp) {
+       if (io_req->wait_for_abts_comp) {
                BNX2FC_IO_DBG(io_req, "tm_compl - wake up the waiter\n");
-               complete(&io_req->tm_done);
+               complete(&io_req->abts_done);
        }
 }
 
@@ -1623,6 +1660,7 @@ static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req)
        u64 addr;
        int i;
 
+       WARN_ON(scsi_sg_count(sc) > BNX2FC_MAX_BDS_PER_CMD);
        /*
         * Use dma_map_sg directly to ensure we're using the correct
         * dev struct off of pcidev.
@@ -1670,6 +1708,16 @@ static int bnx2fc_build_bd_list_from_sg(struct bnx2fc_cmd *io_req)
        }
        io_req->bd_tbl->bd_valid = bd_count;
 
+       /*
+        * Return the command to ML if BD count exceeds the max number
+        * that can be handled by FW.
+        */
+       if (bd_count > BNX2FC_FW_MAX_BDS_PER_CMD) {
+               pr_err("bd_count = %d exceeded FW supported max BD(255), task_id = 0x%x\n",
+                      bd_count, io_req->xid);
+               return -ENOMEM;
+       }
+
        return 0;
 }
 
@@ -1926,10 +1974,10 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
                 * between command abort and (late) completion.
                 */
                BNX2FC_IO_DBG(io_req, "xid not on active_cmd_queue\n");
-               if (io_req->wait_for_comp)
+               if (io_req->wait_for_abts_comp)
                        if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT,
                                               &io_req->req_flags))
-                               complete(&io_req->tm_done);
+                               complete(&io_req->abts_done);
        }
 
        bnx2fc_unmap_sg_list(io_req);
index d735e87..50384b4 100644 (file)
@@ -187,7 +187,7 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
                                /* Handle eh_abort timeout */
                                BNX2FC_IO_DBG(io_req, "eh_abort for IO "
                                              "cleaned up\n");
-                               complete(&io_req->tm_done);
+                               complete(&io_req->abts_done);
                        }
                        kref_put(&io_req->refcount,
                                 bnx2fc_cmd_release); /* drop timer hold */
@@ -210,8 +210,8 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
                list_del_init(&io_req->link);
                io_req->on_tmf_queue = 0;
                BNX2FC_IO_DBG(io_req, "tm_queue cleanup\n");
-               if (io_req->wait_for_comp)
-                       complete(&io_req->tm_done);
+               if (io_req->wait_for_abts_comp)
+                       complete(&io_req->abts_done);
        }
 
        list_for_each_entry_safe(io_req, tmp, &tgt->els_queue, link) {
@@ -251,8 +251,8 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
                                /* Handle eh_abort timeout */
                                BNX2FC_IO_DBG(io_req, "eh_abort for IO "
                                              "in retire_q\n");
-                               if (io_req->wait_for_comp)
-                                       complete(&io_req->tm_done);
+                               if (io_req->wait_for_abts_comp)
+                                       complete(&io_req->abts_done);
                        }
                        kref_put(&io_req->refcount, bnx2fc_cmd_release);
                }
index 66d6e1f..da50e87 100644 (file)
@@ -1665,8 +1665,12 @@ static u8 get_iscsi_dcb_priority(struct net_device *ndev)
                return 0;
 
        if (caps & DCB_CAP_DCBX_VER_IEEE) {
-               iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_ANY;
+               iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_STREAM;
                rv = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app);
+               if (!rv) {
+                       iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_ANY;
+                       rv = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app);
+               }
        } else if (caps & DCB_CAP_DCBX_VER_CEE) {
                iscsi_dcb_app.selector = DCB_APP_IDTYPE_PORTNUM;
                rv = dcb_getapp(ndev, &iscsi_dcb_app);
@@ -2260,7 +2264,8 @@ cxgb4_dcb_change_notify(struct notifier_block *self, unsigned long val,
        u8 priority;
 
        if (iscsi_app->dcbx & DCB_CAP_DCBX_VER_IEEE) {
-               if (iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_ANY)
+               if ((iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_STREAM) &&
+                   (iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_ANY))
                        return NOTIFY_DONE;
 
                priority = iscsi_app->app.priority;
index 76e7ca8..bb88995 100644 (file)
@@ -371,6 +371,7 @@ static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd)
        struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
        struct scatterlist *sg = scsi_sglist(cmd);
        int total = 0, i;
+       struct scatterlist *s;
 
        if (cmd->sc_data_direction == DMA_NONE)
                return;
@@ -381,16 +382,18 @@ static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd)
                 * a dma address, so perform an identity mapping.
                 */
                spriv->num_sg = scsi_sg_count(cmd);
-               for (i = 0; i < spriv->num_sg; i++) {
-                       sg[i].dma_address = (uintptr_t)sg_virt(&sg[i]);
-                       total += sg_dma_len(&sg[i]);
+
+               scsi_for_each_sg(cmd, s, spriv->num_sg, i) {
+                       s->dma_address = (uintptr_t)sg_virt(s);
+                       total += sg_dma_len(s);
                }
        } else {
                spriv->num_sg = scsi_dma_map(cmd);
-               for (i = 0; i < spriv->num_sg; i++)
-                       total += sg_dma_len(&sg[i]);
+               scsi_for_each_sg(cmd, s, spriv->num_sg, i)
+                       total += sg_dma_len(s);
        }
        spriv->cur_residue = sg_dma_len(sg);
+       spriv->prv_sg = NULL;
        spriv->cur_sg = sg;
        spriv->tot_residue = total;
 }
@@ -444,7 +447,8 @@ static void esp_advance_dma(struct esp *esp, struct esp_cmd_entry *ent,
                p->tot_residue = 0;
        }
        if (!p->cur_residue && p->tot_residue) {
-               p->cur_sg++;
+               p->prv_sg = p->cur_sg;
+               p->cur_sg = sg_next(p->cur_sg);
                p->cur_residue = sg_dma_len(p->cur_sg);
        }
 }
@@ -465,6 +469,7 @@ static void esp_save_pointers(struct esp *esp, struct esp_cmd_entry *ent)
                return;
        }
        ent->saved_cur_residue = spriv->cur_residue;
+       ent->saved_prv_sg = spriv->prv_sg;
        ent->saved_cur_sg = spriv->cur_sg;
        ent->saved_tot_residue = spriv->tot_residue;
 }
@@ -479,6 +484,7 @@ static void esp_restore_pointers(struct esp *esp, struct esp_cmd_entry *ent)
                return;
        }
        spriv->cur_residue = ent->saved_cur_residue;
+       spriv->prv_sg = ent->saved_prv_sg;
        spriv->cur_sg = ent->saved_cur_sg;
        spriv->tot_residue = ent->saved_tot_residue;
 }
@@ -1647,7 +1653,7 @@ static int esp_msgin_process(struct esp *esp)
                spriv = ESP_CMD_PRIV(ent->cmd);
 
                if (spriv->cur_residue == sg_dma_len(spriv->cur_sg)) {
-                       spriv->cur_sg--;
+                       spriv->cur_sg = spriv->prv_sg;
                        spriv->cur_residue = 1;
                } else
                        spriv->cur_residue++;
index aa87a6b..91b32f2 100644 (file)
 struct esp_cmd_priv {
        int                     num_sg;
        int                     cur_residue;
+       struct scatterlist      *prv_sg;
        struct scatterlist      *cur_sg;
        int                     tot_residue;
 };
@@ -273,6 +274,7 @@ struct esp_cmd_entry {
        struct scsi_cmnd        *cmd;
 
        unsigned int            saved_cur_residue;
+       struct scatterlist      *saved_prv_sg;
        struct scatterlist      *saved_cur_sg;
        unsigned int            saved_tot_residue;
 
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
new file mode 100644 (file)
index 0000000..b5e6697
--- /dev/null
@@ -0,0 +1,597 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Future Domain TMC-16x0 and TMC-3260 SCSI host adapters
+ * Copyright 2019 Ondrej Zary
+ *
+ * Original driver by
+ * Rickard E. Faith, faith@cs.unc.edu
+ *
+ * Future Domain BIOS versions supported for autodetect:
+ *    2.0, 3.0, 3.2, 3.4 (1.0), 3.5 (2.0), 3.6, 3.61
+ * Chips supported:
+ *    TMC-1800, TMC-18C50, TMC-18C30, TMC-36C70
+ * Boards supported:
+ *    Future Domain TMC-1650, TMC-1660, TMC-1670, TMC-1680, TMC-1610M/MER/MEX
+ *    Future Domain TMC-3260 (PCI)
+ *    Quantum ISA-200S, ISA-250MG
+ *    Adaptec AHA-2920A (PCI) [BUT *NOT* AHA-2920C -- use aic7xxx instead]
+ *    IBM ?
+ *
+ * NOTE:
+ *
+ * The Adaptec AHA-2920C has an Adaptec AIC-7850 chip on it.
+ * Use the aic7xxx driver for this board.
+ *
+ * The Adaptec AHA-2920A has a Future Domain chip on it, so this is the right
+ * driver for that card.  Unfortunately, the boxes will probably just say
+ * "2920", so you'll have to look on the card for a Future Domain logo, or a
+ * letter after the 2920.
+ *
+ * If you have a TMC-8xx or TMC-9xx board, then this is not the driver for
+ * your board.
+ *
+ * DESCRIPTION:
+ *
+ * This is the Linux low-level SCSI driver for Future Domain TMC-1660/1680
+ * TMC-1650/1670, and TMC-3260 SCSI host adapters.  The 1650 and 1670 have a
+ * 25-pin external connector, whereas the 1660 and 1680 have a SCSI-2 50-pin
+ * high-density external connector.  The 1670 and 1680 have floppy disk
+ * controllers built in.  The TMC-3260 is a PCI bus card.
+ *
+ * Future Domain's older boards are based on the TMC-1800 chip, and this
+ * driver was originally written for a TMC-1680 board with the TMC-1800 chip.
+ * More recently, boards are being produced with the TMC-18C50 and TMC-18C30
+ * chips.
+ *
+ * Please note that the drive ordering that Future Domain implemented in BIOS
+ * versions 3.4 and 3.5 is the opposite of the order (currently) used by the
+ * rest of the SCSI industry.
+ *
+ *
+ * REFERENCES USED:
+ *
+ * "TMC-1800 SCSI Chip Specification (FDC-1800T)", Future Domain Corporation,
+ * 1990.
+ *
+ * "Technical Reference Manual: 18C50 SCSI Host Adapter Chip", Future Domain
+ * Corporation, January 1992.
+ *
+ * "LXT SCSI Products: Specifications and OEM Technical Manual (Revision
+ * B/September 1991)", Maxtor Corporation, 1991.
+ *
+ * "7213S product Manual (Revision P3)", Maxtor Corporation, 1992.
+ *
+ * "Draft Proposed American National Standard: Small Computer System
+ * Interface - 2 (SCSI-2)", Global Engineering Documents. (X3T9.2/86-109,
+ * revision 10h, October 17, 1991)
+ *
+ * Private communications, Drew Eckhardt (drew@cs.colorado.edu) and Eric
+ * Youngdale (ericy@cais.com), 1992.
+ *
+ * Private communication, Tuong Le (Future Domain Engineering department),
+ * 1994. (Disk geometry computations for Future Domain BIOS version 3.4, and
+ * TMC-18C30 detection.)
+ *
+ * Hogan, Thom. The Programmer's PC Sourcebook. Microsoft Press, 1988. Page
+ * 60 (2.39: Disk Partition Table Layout).
+ *
+ * "18C30 Technical Reference Manual", Future Domain Corporation, 1993, page
+ * 6-1.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/workqueue.h>
+#include <scsi/scsicam.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include "fdomain.h"
+
+/*
+ * FIFO_COUNT: The host adapter has an 8K cache (host adapters based on the
+ * 18C30 chip have a 2k cache).  When this many 512 byte blocks are filled by
+ * the SCSI device, an interrupt will be raised.  Therefore, this could be as
+ * low as 0, or as high as 16.  Note, however, that values which are too high
+ * or too low seem to prevent any interrupts from occurring, and thereby lock
+ * up the machine.
+ */
+#define FIFO_COUNT     2       /* Number of 512 byte blocks before INTR */
+#define PARITY_MASK    ACTL_PAREN      /* Parity enabled, 0 = disabled */
+
+enum chip_type {
+       unknown         = 0x00,
+       tmc1800         = 0x01,
+       tmc18c50        = 0x02,
+       tmc18c30        = 0x03,
+};
+
+struct fdomain {
+       int base;
+       struct scsi_cmnd *cur_cmd;
+       enum chip_type chip;
+       struct work_struct work;
+};
+
+static inline void fdomain_make_bus_idle(struct fdomain *fd)
+{
+       outb(0, fd->base + REG_BCTL);
+       outb(0, fd->base + REG_MCTL);
+       if (fd->chip == tmc18c50 || fd->chip == tmc18c30)
+               /* Clear forced intr. */
+               outb(ACTL_RESET | ACTL_CLRFIRQ | PARITY_MASK,
+                    fd->base + REG_ACTL);
+       else
+               outb(ACTL_RESET | PARITY_MASK, fd->base + REG_ACTL);
+}
+
+static enum chip_type fdomain_identify(int port)
+{
+       u16 id = inb(port + REG_ID_LSB) | inb(port + REG_ID_MSB) << 8;
+
+       switch (id) {
+       case 0x6127:
+               return tmc1800;
+       case 0x60e9: /* 18c50 or 18c30 */
+               break;
+       default:
+               return unknown;
+       }
+
+       /* Try to toggle 32-bit mode. This only works on an 18c30 chip. */
+       outb(CFG2_32BIT, port + REG_CFG2);
+       if ((inb(port + REG_CFG2) & CFG2_32BIT)) {
+               outb(0, port + REG_CFG2);
+               if ((inb(port + REG_CFG2) & CFG2_32BIT) == 0)
+                       return tmc18c30;
+       }
+       /* If that failed, we are an 18c50. */
+       return tmc18c50;
+}
+
+static int fdomain_test_loopback(int base)
+{
+       int i;
+
+       for (i = 0; i < 255; i++) {
+               outb(i, base + REG_LOOPBACK);
+               if (inb(base + REG_LOOPBACK) != i)
+                       return 1;
+       }
+
+       return 0;
+}
+
+static void fdomain_reset(int base)
+{
+       outb(1, base + REG_BCTL);
+       mdelay(20);
+       outb(0, base + REG_BCTL);
+       mdelay(1150);
+       outb(0, base + REG_MCTL);
+       outb(PARITY_MASK, base + REG_ACTL);
+}
+
+static int fdomain_select(struct Scsi_Host *sh, int target)
+{
+       int status;
+       unsigned long timeout;
+       struct fdomain *fd = shost_priv(sh);
+
+       outb(BCTL_BUSEN | BCTL_SEL, fd->base + REG_BCTL);
+       outb(BIT(sh->this_id) | BIT(target), fd->base + REG_SCSI_DATA_NOACK);
+
+       /* Stop arbitration and enable parity */
+       outb(PARITY_MASK, fd->base + REG_ACTL);
+
+       timeout = 350;  /* 350 msec */
+
+       do {
+               status = inb(fd->base + REG_BSTAT);
+               if (status & BSTAT_BSY) {
+                       /* Enable SCSI Bus */
+                       /* (on error, should make bus idle with 0) */
+                       outb(BCTL_BUSEN, fd->base + REG_BCTL);
+                       return 0;
+               }
+               mdelay(1);
+       } while (--timeout);
+       fdomain_make_bus_idle(fd);
+       return 1;
+}
+
+static void fdomain_finish_cmd(struct fdomain *fd, int result)
+{
+       outb(0, fd->base + REG_ICTL);
+       fdomain_make_bus_idle(fd);
+       fd->cur_cmd->result = result;
+       fd->cur_cmd->scsi_done(fd->cur_cmd);
+       fd->cur_cmd = NULL;
+}
+
+static void fdomain_read_data(struct scsi_cmnd *cmd)
+{
+       struct fdomain *fd = shost_priv(cmd->device->host);
+       unsigned char *virt, *ptr;
+       size_t offset, len;
+
+       while ((len = inw(fd->base + REG_FIFO_COUNT)) > 0) {
+               offset = scsi_bufflen(cmd) - scsi_get_resid(cmd);
+               virt = scsi_kmap_atomic_sg(scsi_sglist(cmd), scsi_sg_count(cmd),
+                                          &offset, &len);
+               ptr = virt + offset;
+               if (len & 1)
+                       *ptr++ = inb(fd->base + REG_FIFO);
+               if (len > 1)
+                       insw(fd->base + REG_FIFO, ptr, len >> 1);
+               scsi_set_resid(cmd, scsi_get_resid(cmd) - len);
+               scsi_kunmap_atomic_sg(virt);
+       }
+}
+
+static void fdomain_write_data(struct scsi_cmnd *cmd)
+{
+       struct fdomain *fd = shost_priv(cmd->device->host);
+       /* 8k FIFO for pre-tmc18c30 chips, 2k FIFO for tmc18c30 */
+       int FIFO_Size = fd->chip == tmc18c30 ? 0x800 : 0x2000;
+       unsigned char *virt, *ptr;
+       size_t offset, len;
+
+       while ((len = FIFO_Size - inw(fd->base + REG_FIFO_COUNT)) > 512) {
+               offset = scsi_bufflen(cmd) - scsi_get_resid(cmd);
+               if (len + offset > scsi_bufflen(cmd)) {
+                       len = scsi_bufflen(cmd) - offset;
+                       if (len == 0)
+                               break;
+               }
+               virt = scsi_kmap_atomic_sg(scsi_sglist(cmd), scsi_sg_count(cmd),
+                                          &offset, &len);
+               ptr = virt + offset;
+               if (len & 1)
+                       outb(*ptr++, fd->base + REG_FIFO);
+               if (len > 1)
+                       outsw(fd->base + REG_FIFO, ptr, len >> 1);
+               scsi_set_resid(cmd, scsi_get_resid(cmd) - len);
+               scsi_kunmap_atomic_sg(virt);
+       }
+}
+
+static void fdomain_work(struct work_struct *work)
+{
+       struct fdomain *fd = container_of(work, struct fdomain, work);
+       struct Scsi_Host *sh = container_of((void *)fd, struct Scsi_Host,
+                                           hostdata);
+       struct scsi_cmnd *cmd = fd->cur_cmd;
+       unsigned long flags;
+       int status;
+       int done = 0;
+
+       spin_lock_irqsave(sh->host_lock, flags);
+
+       if (cmd->SCp.phase & in_arbitration) {
+               status = inb(fd->base + REG_ASTAT);
+               if (!(status & ASTAT_ARB)) {
+                       fdomain_finish_cmd(fd, DID_BUS_BUSY << 16);
+                       goto out;
+               }
+               cmd->SCp.phase = in_selection;
+
+               outb(ICTL_SEL | FIFO_COUNT, fd->base + REG_ICTL);
+               outb(BCTL_BUSEN | BCTL_SEL, fd->base + REG_BCTL);
+               outb(BIT(cmd->device->host->this_id) | BIT(scmd_id(cmd)),
+                    fd->base + REG_SCSI_DATA_NOACK);
+               /* Stop arbitration and enable parity */
+               outb(ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL);
+               goto out;
+       } else if (cmd->SCp.phase & in_selection) {
+               status = inb(fd->base + REG_BSTAT);
+               if (!(status & BSTAT_BSY)) {
+                       /* Try again, for slow devices */
+                       if (fdomain_select(cmd->device->host, scmd_id(cmd))) {
+                               fdomain_finish_cmd(fd, DID_NO_CONNECT << 16);
+                               goto out;
+                       }
+                       /* Stop arbitration and enable parity */
+                       outb(ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL);
+               }
+               cmd->SCp.phase = in_other;
+               outb(ICTL_FIFO | ICTL_REQ | FIFO_COUNT, fd->base + REG_ICTL);
+               outb(BCTL_BUSEN, fd->base + REG_BCTL);
+               goto out;
+       }
+
+       /* cur_cmd->SCp.phase == in_other: this is the body of the routine */
+       status = inb(fd->base + REG_BSTAT);
+
+       if (status & BSTAT_REQ) {
+               switch (status & 0x0e) {
+               case BSTAT_CMD: /* COMMAND OUT */
+                       outb(cmd->cmnd[cmd->SCp.sent_command++],
+                            fd->base + REG_SCSI_DATA);
+                       break;
+               case 0: /* DATA OUT -- tmc18c50/tmc18c30 only */
+                       if (fd->chip != tmc1800 && !cmd->SCp.have_data_in) {
+                               cmd->SCp.have_data_in = -1;
+                               outb(ACTL_IRQEN | ACTL_FIFOWR | ACTL_FIFOEN |
+                                    PARITY_MASK, fd->base + REG_ACTL);
+                       }
+                       break;
+               case BSTAT_IO:  /* DATA IN -- tmc18c50/tmc18c30 only */
+                       if (fd->chip != tmc1800 && !cmd->SCp.have_data_in) {
+                               cmd->SCp.have_data_in = 1;
+                               outb(ACTL_IRQEN | ACTL_FIFOEN | PARITY_MASK,
+                                    fd->base + REG_ACTL);
+                       }
+                       break;
+               case BSTAT_CMD | BSTAT_IO:      /* STATUS IN */
+                       cmd->SCp.Status = inb(fd->base + REG_SCSI_DATA);
+                       break;
+               case BSTAT_MSG | BSTAT_CMD:     /* MESSAGE OUT */
+                       outb(MESSAGE_REJECT, fd->base + REG_SCSI_DATA);
+                       break;
+               case BSTAT_MSG | BSTAT_IO | BSTAT_CMD:  /* MESSAGE IN */
+                       cmd->SCp.Message = inb(fd->base + REG_SCSI_DATA);
+                       if (!cmd->SCp.Message)
+                               ++done;
+                       break;
+               }
+       }
+
+       if (fd->chip == tmc1800 && !cmd->SCp.have_data_in &&
+           cmd->SCp.sent_command >= cmd->cmd_len) {
+               if (cmd->sc_data_direction == DMA_TO_DEVICE) {
+                       cmd->SCp.have_data_in = -1;
+                       outb(ACTL_IRQEN | ACTL_FIFOWR | ACTL_FIFOEN |
+                            PARITY_MASK, fd->base + REG_ACTL);
+               } else {
+                       cmd->SCp.have_data_in = 1;
+                       outb(ACTL_IRQEN | ACTL_FIFOEN | PARITY_MASK,
+                            fd->base + REG_ACTL);
+               }
+       }
+
+       if (cmd->SCp.have_data_in == -1) /* DATA OUT */
+               fdomain_write_data(cmd);
+
+       if (cmd->SCp.have_data_in == 1) /* DATA IN */
+               fdomain_read_data(cmd);
+
+       if (done) {
+               fdomain_finish_cmd(fd, (cmd->SCp.Status & 0xff) |
+                                  ((cmd->SCp.Message & 0xff) << 8) |
+                                  (DID_OK << 16));
+       } else {
+               if (cmd->SCp.phase & disconnect) {
+                       outb(ICTL_FIFO | ICTL_SEL | ICTL_REQ | FIFO_COUNT,
+                            fd->base + REG_ICTL);
+                       outb(0, fd->base + REG_BCTL);
+               } else
+                       outb(ICTL_FIFO | ICTL_REQ | FIFO_COUNT,
+                            fd->base + REG_ICTL);
+       }
+out:
+       spin_unlock_irqrestore(sh->host_lock, flags);
+}
+
+static irqreturn_t fdomain_irq(int irq, void *dev_id)
+{
+       struct fdomain *fd = dev_id;
+
+       /* Is it our IRQ? */
+       if ((inb(fd->base + REG_ASTAT) & ASTAT_IRQ) == 0)
+               return IRQ_NONE;
+
+       outb(0, fd->base + REG_ICTL);
+
+       /* We usually have one spurious interrupt after each command. */
+       if (!fd->cur_cmd)       /* Spurious interrupt */
+               return IRQ_NONE;
+
+       schedule_work(&fd->work);
+
+       return IRQ_HANDLED;
+}
+
+static int fdomain_queue(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
+{
+       struct fdomain *fd = shost_priv(cmd->device->host);
+       unsigned long flags;
+
+       cmd->SCp.Status         = 0;
+       cmd->SCp.Message        = 0;
+       cmd->SCp.have_data_in   = 0;
+       cmd->SCp.sent_command   = 0;
+       cmd->SCp.phase          = in_arbitration;
+       scsi_set_resid(cmd, scsi_bufflen(cmd));
+
+       spin_lock_irqsave(sh->host_lock, flags);
+
+       fd->cur_cmd = cmd;
+
+       fdomain_make_bus_idle(fd);
+
+       /* Start arbitration */
+       outb(0, fd->base + REG_ICTL);
+       outb(0, fd->base + REG_BCTL);   /* Disable data drivers */
+       /* Set our id bit */
+       outb(BIT(cmd->device->host->this_id), fd->base + REG_SCSI_DATA_NOACK);
+       outb(ICTL_ARB, fd->base + REG_ICTL);
+       /* Start arbitration */
+       outb(ACTL_ARB | ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL);
+
+       spin_unlock_irqrestore(sh->host_lock, flags);
+
+       return 0;
+}
+
+static int fdomain_abort(struct scsi_cmnd *cmd)
+{
+       struct Scsi_Host *sh = cmd->device->host;
+       struct fdomain *fd = shost_priv(sh);
+       unsigned long flags;
+
+       if (!fd->cur_cmd)
+               return FAILED;
+
+       spin_lock_irqsave(sh->host_lock, flags);
+
+       fdomain_make_bus_idle(fd);
+       fd->cur_cmd->SCp.phase |= aborted;
+       fd->cur_cmd->result = DID_ABORT << 16;
+
+       /* Aborts are not done well. . . */
+       fdomain_finish_cmd(fd, DID_ABORT << 16);
+       spin_unlock_irqrestore(sh->host_lock, flags);
+       return SUCCESS;
+}
+
+static int fdomain_host_reset(struct scsi_cmnd *cmd)
+{
+       struct Scsi_Host *sh = cmd->device->host;
+       struct fdomain *fd = shost_priv(sh);
+       unsigned long flags;
+
+       spin_lock_irqsave(sh->host_lock, flags);
+       fdomain_reset(fd->base);
+       spin_unlock_irqrestore(sh->host_lock, flags);
+       return SUCCESS;
+}
+
+static int fdomain_biosparam(struct scsi_device *sdev,
+                            struct block_device *bdev, sector_t capacity,
+                            int geom[])
+{
+       unsigned char *p = scsi_bios_ptable(bdev);
+
+       if (p && p[65] == 0xaa && p[64] == 0x55 /* Partition table valid */
+           && p[4]) {   /* Partition type */
+               geom[0] = p[5] + 1;     /* heads */
+               geom[1] = p[6] & 0x3f;  /* sectors */
+       } else {
+               if (capacity >= 0x7e0000) {
+                       geom[0] = 255;  /* heads */
+                       geom[1] = 63;   /* sectors */
+               } else if (capacity >= 0x200000) {
+                       geom[0] = 128;  /* heads */
+                       geom[1] = 63;   /* sectors */
+               } else {
+                       geom[0] = 64;   /* heads */
+                       geom[1] = 32;   /* sectors */
+               }
+       }
+       geom[2] = sector_div(capacity, geom[0] * geom[1]);
+       kfree(p);
+
+       return 0;
+}
+
+static struct scsi_host_template fdomain_template = {
+       .module                 = THIS_MODULE,
+       .name                   = "Future Domain TMC-16x0",
+       .proc_name              = "fdomain",
+       .queuecommand           = fdomain_queue,
+       .eh_abort_handler       = fdomain_abort,
+       .eh_host_reset_handler  = fdomain_host_reset,
+       .bios_param             = fdomain_biosparam,
+       .can_queue              = 1,
+       .this_id                = 7,
+       .sg_tablesize           = 64,
+       .dma_boundary           = PAGE_SIZE - 1,
+};
+
+struct Scsi_Host *fdomain_create(int base, int irq, int this_id,
+                                struct device *dev)
+{
+       struct Scsi_Host *sh;
+       struct fdomain *fd;
+       enum chip_type chip;
+       static const char * const chip_names[] = {
+               "Unknown", "TMC-1800", "TMC-18C50", "TMC-18C30"
+       };
+       unsigned long irq_flags = 0;
+
+       chip = fdomain_identify(base);
+       if (!chip)
+               return NULL;
+
+       fdomain_reset(base);
+
+       if (fdomain_test_loopback(base))
+               return NULL;
+
+       if (!irq) {
+               dev_err(dev, "card has no IRQ assigned");
+               return NULL;
+       }
+
+       sh = scsi_host_alloc(&fdomain_template, sizeof(struct fdomain));
+       if (!sh)
+               return NULL;
+
+       if (this_id)
+               sh->this_id = this_id & 0x07;
+
+       sh->irq = irq;
+       sh->io_port = base;
+       sh->n_io_port = FDOMAIN_REGION_SIZE;
+
+       fd = shost_priv(sh);
+       fd->base = base;
+       fd->chip = chip;
+       INIT_WORK(&fd->work, fdomain_work);
+
+       if (dev_is_pci(dev) || !strcmp(dev->bus->name, "pcmcia"))
+               irq_flags = IRQF_SHARED;
+
+       if (request_irq(irq, fdomain_irq, irq_flags, "fdomain", fd))
+               goto fail_put;
+
+       shost_printk(KERN_INFO, sh, "%s chip at 0x%x irq %d SCSI ID %d\n",
+                    dev_is_pci(dev) ? "TMC-36C70 (PCI bus)" : chip_names[chip],
+                    base, irq, sh->this_id);
+
+       if (scsi_add_host(sh, dev))
+               goto fail_free_irq;
+
+       scsi_scan_host(sh);
+
+       return sh;
+
+fail_free_irq:
+       free_irq(irq, fd);
+fail_put:
+       scsi_host_put(sh);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(fdomain_create);
+
+int fdomain_destroy(struct Scsi_Host *sh)
+{
+       struct fdomain *fd = shost_priv(sh);
+
+       cancel_work_sync(&fd->work);
+       scsi_remove_host(sh);
+       if (sh->irq)
+               free_irq(sh->irq, fd);
+       scsi_host_put(sh);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(fdomain_destroy);
+
+#ifdef CONFIG_PM_SLEEP
+static int fdomain_resume(struct device *dev)
+{
+       struct fdomain *fd = shost_priv(dev_get_drvdata(dev));
+
+       fdomain_reset(fd->base);
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(fdomain_pm_ops, NULL, fdomain_resume);
+#endif /* CONFIG_PM_SLEEP */
+
+MODULE_AUTHOR("Ondrej Zary, Rickard E. Faith");
+MODULE_DESCRIPTION("Future Domain TMC-16x0/TMC-3260 SCSI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/fdomain.h b/drivers/scsi/fdomain.h
new file mode 100644 (file)
index 0000000..6f63fc6
--- /dev/null
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#define FDOMAIN_REGION_SIZE    0x10
+#define FDOMAIN_BIOS_SIZE      0x2000
+
+enum {
+       in_arbitration  = 0x02,
+       in_selection    = 0x04,
+       in_other        = 0x08,
+       disconnect      = 0x10,
+       aborted         = 0x20,
+       sent_ident      = 0x40,
+};
+
+/* (@) = not present on TMC1800, (#) = not present on TMC1800 and TMC18C50 */
+#define REG_SCSI_DATA          0       /* R/W: SCSI Data (with ACK) */
+#define REG_BSTAT              1       /* R: SCSI Bus Status */
+#define                BSTAT_BSY       BIT(0)   /* Busy */
+#define                BSTAT_MSG       BIT(1)   /* Message */
+#define                BSTAT_IO        BIT(2)   /* Input/Output */
+#define                BSTAT_CMD       BIT(3)   /* Command/Data */
+#define                BSTAT_REQ       BIT(4)   /* Request and Not Ack */
+#define                BSTAT_SEL       BIT(5)   /* Select */
+#define                BSTAT_ACK       BIT(6)   /* Acknowledge and Request */
+#define                BSTAT_ATN       BIT(7)   /* Attention */
+#define REG_BCTL               1       /* W: SCSI Bus Control */
+#define                BCTL_RST        BIT(0)   /* Bus Reset */
+#define                BCTL_SEL        BIT(1)   /* Select */
+#define                BCTL_BSY        BIT(2)   /* Busy */
+#define                BCTL_ATN        BIT(3)   /* Attention */
+#define                BCTL_IO         BIT(4)   /* Input/Output */
+#define                BCTL_CMD        BIT(5)   /* Command/Data */
+#define                BCTL_MSG        BIT(6)   /* Message */
+#define                BCTL_BUSEN      BIT(7)   /* Enable bus drivers */
+#define REG_ASTAT              2       /* R: Adapter Status 1 */
+#define                ASTAT_IRQ       BIT(0)   /* Interrupt active */
+#define                ASTAT_ARB       BIT(1)   /* Arbitration complete */
+#define                ASTAT_PARERR    BIT(2)   /* Parity error */
+#define                ASTAT_RST       BIT(3)   /* SCSI reset occurred */
+#define                ASTAT_FIFODIR   BIT(4)   /* FIFO direction */
+#define                ASTAT_FIFOEN    BIT(5)   /* FIFO enabled */
+#define                ASTAT_PAREN     BIT(6)   /* Parity enabled */
+#define                ASTAT_BUSEN     BIT(7)   /* Bus drivers enabled */
+#define REG_ICTL               2       /* W: Interrupt Control */
+#define                ICTL_FIFO_MASK  0x0f     /* FIFO threshold, 1/16 FIFO size */
+#define                ICTL_FIFO       BIT(4)   /* Int. on FIFO count */
+#define                ICTL_ARB        BIT(5)   /* Int. on Arbitration complete */
+#define                ICTL_SEL        BIT(6)   /* Int. on SCSI Select */
+#define                ICTL_REQ        BIT(7)   /* Int. on SCSI Request */
+#define REG_FSTAT              3       /* R: Adapter Status 2 (FIFO) - (@) */
+#define                FSTAT_ONOTEMPTY BIT(0)   /* Output FIFO not empty */
+#define                FSTAT_INOTEMPTY BIT(1)   /* Input FIFO not empty */
+#define                FSTAT_NOTEMPTY  BIT(2)   /* Main FIFO not empty */
+#define                FSTAT_NOTFULL   BIT(3)   /* Main FIFO not full */
+#define REG_MCTL               3       /* W: SCSI Data Mode Control */
+#define                MCTL_ACK_MASK   0x0f     /* Acknowledge period */
+#define                MCTL_ACTDEASS   BIT(4)   /* Active deassert of REQ and ACK */
+#define                MCTL_TARGET     BIT(5)   /* Enable target mode */
+#define                MCTL_FASTSYNC   BIT(6)   /* Enable Fast Synchronous */
+#define                MCTL_SYNC       BIT(7)   /* Enable Synchronous */
+#define REG_INTCOND            4       /* R: Interrupt Condition - (@) */
+#define                IRQ_FIFO        BIT(1)   /* FIFO interrupt */
+#define                IRQ_REQ         BIT(2)   /* SCSI Request interrupt */
+#define                IRQ_SEL         BIT(3)   /* SCSI Select interrupt */
+#define                IRQ_ARB         BIT(4)   /* SCSI Arbitration interrupt */
+#define                IRQ_RST         BIT(5)   /* SCSI Reset interrupt */
+#define                IRQ_FORCED      BIT(6)   /* Forced interrupt */
+#define                IRQ_TIMEOUT     BIT(7)   /* Bus timeout */
+#define REG_ACTL               4       /* W: Adapter Control 1 */
+#define                ACTL_RESET      BIT(0)   /* Reset FIFO, parity, reset int. */
+#define                ACTL_FIRQ       BIT(1)   /* Set Forced interrupt */
+#define                ACTL_ARB        BIT(2)   /* Initiate Bus Arbitration */
+#define                ACTL_PAREN      BIT(3)   /* Enable SCSI Parity */
+#define                ACTL_IRQEN      BIT(4)   /* Enable interrupts */
+#define                ACTL_CLRFIRQ    BIT(5)   /* Clear Forced interrupt */
+#define                ACTL_FIFOWR     BIT(6)   /* FIFO Direction (1=write) */
+#define                ACTL_FIFOEN     BIT(7)   /* Enable FIFO */
+#define REG_ID_LSB             5       /* R: ID Code (LSB) */
+#define REG_ACTL2              5       /* Adapter Control 2 - (@) */
+#define                ACTL2_RAMOVRLY  BIT(0)   /* Enable RAM overlay */
+#define                ACTL2_SLEEP     BIT(7)   /* Sleep mode */
+#define REG_ID_MSB             6       /* R: ID Code (MSB) */
+#define REG_LOOPBACK           7       /* R/W: Loopback */
+#define REG_SCSI_DATA_NOACK    8       /* R/W: SCSI Data (no ACK) */
+#define REG_ASTAT3             9       /* R: Adapter Status 3 */
+#define                ASTAT3_ACTDEASS BIT(0)   /* Active deassert enabled */
+#define                ASTAT3_RAMOVRLY BIT(1)   /* RAM overlay enabled */
+#define                ASTAT3_TARGERR  BIT(2)   /* Target error */
+#define                ASTAT3_IRQEN    BIT(3)   /* Interrupts enabled */
+#define                ASTAT3_IRQMASK  0xf0     /* Enabled interrupts mask */
+#define REG_CFG1               10      /* R: Configuration Register 1 */
+#define                CFG1_BUS        BIT(0)   /* 0 = ISA */
+#define                CFG1_IRQ_MASK   0x0e     /* IRQ jumpers */
+#define                CFG1_IO_MASK    0x30     /* I/O base jumpers */
+#define                CFG1_BIOS_MASK  0xc0     /* BIOS base jumpers */
+#define REG_CFG2               11      /* R/W: Configuration Register 2 (@) */
+#define                CFG2_ROMDIS     BIT(0)   /* ROM disabled */
+#define                CFG2_RAMDIS     BIT(1)   /* RAM disabled */
+#define                CFG2_IRQEDGE    BIT(2)   /* Edge-triggered interrupts */
+#define                CFG2_NOWS       BIT(3)   /* No wait states */
+#define                CFG2_32BIT      BIT(7)   /* 32-bit mode */
+#define REG_FIFO               12      /* R/W: FIFO */
+#define REG_FIFO_COUNT         14      /* R: FIFO Data Count */
+
+#ifdef CONFIG_PM_SLEEP
+static const struct dev_pm_ops fdomain_pm_ops;
+#define FDOMAIN_PM_OPS (&fdomain_pm_ops)
+#else
+#define FDOMAIN_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
+struct Scsi_Host *fdomain_create(int base, int irq, int this_id,
+                                struct device *dev);
+int fdomain_destroy(struct Scsi_Host *sh);
diff --git a/drivers/scsi/fdomain_isa.c b/drivers/scsi/fdomain_isa.c
new file mode 100644 (file)
index 0000000..28639ad
--- /dev/null
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/isa.h>
+#include <scsi/scsi_host.h>
+#include "fdomain.h"
+
+#define MAXBOARDS_PARAM 4
+static int io[MAXBOARDS_PARAM] = { 0, 0, 0, 0 };
+module_param_hw_array(io, int, ioport, NULL, 0);
+MODULE_PARM_DESC(io, "base I/O address of controller (0x140, 0x150, 0x160, 0x170)");
+
+static int irq[MAXBOARDS_PARAM] = { 0, 0, 0, 0 };
+module_param_hw_array(irq, int, irq, NULL, 0);
+MODULE_PARM_DESC(irq, "IRQ of controller (0=auto [default])");
+
+static int scsi_id[MAXBOARDS_PARAM] = { 0, 0, 0, 0 };
+module_param_hw_array(scsi_id, int, other, NULL, 0);
+MODULE_PARM_DESC(scsi_id, "SCSI ID of controller (default = 7)");
+
+static unsigned long addresses[] = {
+       0xc8000,
+       0xca000,
+       0xce000,
+       0xde000,
+};
+#define ADDRESS_COUNT ARRAY_SIZE(addresses)
+
+static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
+#define PORT_COUNT ARRAY_SIZE(ports)
+
+static unsigned short irqs[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
+
+/* This driver works *ONLY* for Future Domain cards using the TMC-1800,
+ * TMC-18C50, or TMC-18C30 chip.  This includes models TMC-1650, 1660, 1670,
+ * and 1680. These are all 16-bit cards.
+ * BIOS versions prior to 3.2 assigned SCSI ID 6 to SCSI adapter.
+ *
+ * The following BIOS signature signatures are for boards which do *NOT*
+ * work with this driver (these TMC-8xx and TMC-9xx boards may work with the
+ * Seagate driver):
+ *
+ * FUTURE DOMAIN CORP. (C) 1986-1988 V4.0I 03/16/88
+ * FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89
+ * FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89
+ * FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90
+ * FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90
+ * FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90
+ * FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92
+ *
+ * (The cards which do *NOT* work are all 8-bit cards -- although some of
+ * them have a 16-bit form-factor, the upper 8-bits are used only for IRQs
+ * and are *NOT* used for data. You can tell the difference by following
+ * the tracings on the circuit board -- if only the IRQ lines are involved,
+ * you have a "8-bit" card, and should *NOT* use this driver.)
+ */
+
+static struct signature {
+       const char *signature;
+       int offset;
+       int length;
+       int this_id;
+       int base_offset;
+} signatures[] = {
+/*          1         2         3         4         5         6 */
+/* 123456789012345678901234567890123456789012345678901234567890 */
+{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89",         5, 50,  6, 0x1fcc },
+{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V1.07/28/89",         5, 50,  6, 0x1fcc },
+{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 72, 50,  6, 0x1fa2 },
+{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.0",       73, 43,  6, 0x1fa2 },
+{ "FUTURE DOMAIN CORP. (C) 1991 1800-V2.0.",           72, 39,  6, 0x1fa3 },
+{ "FUTURE DOMAIN CORP. (C) 1992 V3.00.004/02/92",       5, 44,  6, 0 },
+{ "FUTURE DOMAIN TMC-18XX (C) 1993 V3.203/12/93",       5, 44,  7, 0 },
+{ "IBM F1 P2 BIOS v1.0011/09/92",                       5, 28,  7, 0x1ff3 },
+{ "IBM F1 P2 BIOS v1.0104/29/93",                       5, 28,  7, 0 },
+{ "Future Domain Corp. V1.0008/18/93",                  5, 33,  7, 0 },
+{ "Future Domain Corp. V2.0108/18/93",                  5, 33,  7, 0 },
+{ "FUTURE DOMAIN CORP.  V3.5008/18/93",                         5, 34,  7, 0 },
+{ "FUTURE DOMAIN 18c30/18c50/1800 (C) 1994 V3.5",       5, 44,  7, 0 },
+{ "FUTURE DOMAIN CORP.  V3.6008/18/93",                         5, 34,  7, 0 },
+{ "FUTURE DOMAIN CORP.  V3.6108/18/93",                         5, 34,  7, 0 },
+};
+#define SIGNATURE_COUNT ARRAY_SIZE(signatures)
+
+static int fdomain_isa_match(struct device *dev, unsigned int ndev)
+{
+       struct Scsi_Host *sh;
+       int i, base = 0, irq = 0;
+       unsigned long bios_base = 0;
+       struct signature *sig = NULL;
+       void __iomem *p;
+       static struct signature *saved_sig;
+       int this_id = 7;
+
+       if (ndev < ADDRESS_COUNT) {     /* scan supported ISA BIOS addresses */
+               p = ioremap(addresses[ndev], FDOMAIN_BIOS_SIZE);
+               if (!p)
+                       return 0;
+               for (i = 0; i < SIGNATURE_COUNT; i++)
+                       if (check_signature(p + signatures[i].offset,
+                                           signatures[i].signature,
+                                           signatures[i].length))
+                               break;
+               if (i == SIGNATURE_COUNT)       /* no signature found */
+                       goto fail_unmap;
+               sig = &signatures[i];
+               bios_base = addresses[ndev];
+               /* read I/O base from BIOS area */
+               if (sig->base_offset)
+                       base = readb(p + sig->base_offset) +
+                             (readb(p + sig->base_offset + 1) << 8);
+               iounmap(p);
+               if (base)
+                       dev_info(dev, "BIOS at 0x%lx specifies I/O base 0x%x\n",
+                                bios_base, base);
+               else
+                       dev_info(dev, "BIOS at 0x%lx\n", bios_base);
+               if (!base) {    /* no I/O base in BIOS area */
+                       /* save BIOS signature for later use in port probing */
+                       saved_sig = sig;
+                       return 0;
+               }
+       } else  /* scan supported I/O ports */
+               base = ports[ndev - ADDRESS_COUNT];
+
+       /* use saved BIOS signature if present */
+       if (!sig && saved_sig)
+               sig = saved_sig;
+
+       if (!request_region(base, FDOMAIN_REGION_SIZE, "fdomain_isa"))
+               return 0;
+
+       irq = irqs[(inb(base + REG_CFG1) & 0x0e) >> 1];
+
+
+       if (sig)
+               this_id = sig->this_id;
+
+       sh = fdomain_create(base, irq, this_id, dev);
+       if (!sh) {
+               release_region(base, FDOMAIN_REGION_SIZE);
+               return 0;
+       }
+
+       dev_set_drvdata(dev, sh);
+       return 1;
+fail_unmap:
+       iounmap(p);
+       return 0;
+}
+
+static int fdomain_isa_param_match(struct device *dev, unsigned int ndev)
+{
+       struct Scsi_Host *sh;
+       int irq_ = irq[ndev];
+
+       if (!io[ndev])
+               return 0;
+
+       if (!request_region(io[ndev], FDOMAIN_REGION_SIZE, "fdomain_isa")) {
+               dev_err(dev, "base 0x%x already in use", io[ndev]);
+               return 0;
+       }
+
+       if (irq_ <= 0)
+               irq_ = irqs[(inb(io[ndev] + REG_CFG1) & 0x0e) >> 1];
+
+       sh = fdomain_create(io[ndev], irq_, scsi_id[ndev], dev);
+       if (!sh) {
+               dev_err(dev, "controller not found at base 0x%x", io[ndev]);
+               release_region(io[ndev], FDOMAIN_REGION_SIZE);
+               return 0;
+       }
+
+       dev_set_drvdata(dev, sh);
+       return 1;
+}
+
+static int fdomain_isa_remove(struct device *dev, unsigned int ndev)
+{
+       struct Scsi_Host *sh = dev_get_drvdata(dev);
+       int base = sh->io_port;
+
+       fdomain_destroy(sh);
+       release_region(base, FDOMAIN_REGION_SIZE);
+       dev_set_drvdata(dev, NULL);
+       return 0;
+}
+
+static struct isa_driver fdomain_isa_driver = {
+       .match          = fdomain_isa_match,
+       .remove         = fdomain_isa_remove,
+       .driver = {
+               .name   = "fdomain_isa",
+               .pm     = FDOMAIN_PM_OPS,
+       },
+};
+
+static int __init fdomain_isa_init(void)
+{
+       int isa_probe_count = ADDRESS_COUNT + PORT_COUNT;
+
+       if (io[0]) {    /* use module parameters if present */
+               fdomain_isa_driver.match = fdomain_isa_param_match;
+               isa_probe_count = MAXBOARDS_PARAM;
+       }
+
+       return isa_register_driver(&fdomain_isa_driver, isa_probe_count);
+}
+
+static void __exit fdomain_isa_exit(void)
+{
+       isa_unregister_driver(&fdomain_isa_driver);
+}
+
+module_init(fdomain_isa_init);
+module_exit(fdomain_isa_exit);
+
+MODULE_AUTHOR("Ondrej Zary, Rickard E. Faith");
+MODULE_DESCRIPTION("Future Domain TMC-16x0 ISA SCSI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/fdomain_pci.c b/drivers/scsi/fdomain_pci.c
new file mode 100644 (file)
index 0000000..3e05ce7
--- /dev/null
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include "fdomain.h"
+
+static int fdomain_pci_probe(struct pci_dev *pdev,
+                            const struct pci_device_id *d)
+{
+       int err;
+       struct Scsi_Host *sh;
+
+       err = pci_enable_device(pdev);
+       if (err)
+               goto fail;
+
+       err = pci_request_regions(pdev, "fdomain_pci");
+       if (err)
+               goto disable_device;
+
+       err = -ENODEV;
+       if (pci_resource_len(pdev, 0) == 0)
+               goto release_region;
+
+       sh = fdomain_create(pci_resource_start(pdev, 0), pdev->irq, 7,
+                           &pdev->dev);
+       if (!sh)
+               goto release_region;
+
+       pci_set_drvdata(pdev, sh);
+       return 0;
+
+release_region:
+       pci_release_regions(pdev);
+disable_device:
+       pci_disable_device(pdev);
+fail:
+       return err;
+}
+
+static void fdomain_pci_remove(struct pci_dev *pdev)
+{
+       struct Scsi_Host *sh = pci_get_drvdata(pdev);
+
+       fdomain_destroy(sh);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+}
+
+static struct pci_device_id fdomain_pci_table[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70) },
+       {}
+};
+MODULE_DEVICE_TABLE(pci, fdomain_pci_table);
+
+static struct pci_driver fdomain_pci_driver = {
+       .name           = "fdomain_pci",
+       .id_table       = fdomain_pci_table,
+       .probe          = fdomain_pci_probe,
+       .remove         = fdomain_pci_remove,
+       .driver.pm      = FDOMAIN_PM_OPS,
+};
+
+module_pci_driver(fdomain_pci_driver);
+
+MODULE_AUTHOR("Ondrej Zary, Rickard E. Faith");
+MODULE_DESCRIPTION("Future Domain TMC-3260 PCI SCSI driver");
+MODULE_LICENSE("GPL");
index 8d9a8fb..42a02cc 100644 (file)
 #define HISI_SAS_MAX_SMP_RESP_SZ 1028
 #define HISI_SAS_MAX_STP_RESP_SZ 28
 
-#define DEV_IS_EXPANDER(type) \
-       ((type == SAS_EDGE_EXPANDER_DEVICE) || \
-       (type == SAS_FANOUT_EXPANDER_DEVICE))
-
 #define HISI_SAS_SATA_PROTOCOL_NONDATA         0x1
 #define HISI_SAS_SATA_PROTOCOL_PIO                     0x2
 #define HISI_SAS_SATA_PROTOCOL_DMA                     0x4
@@ -479,12 +475,12 @@ struct hisi_sas_command_table_stp {
        u8      atapi_cdb[ATAPI_CDB_LEN];
 };
 
-#define HISI_SAS_SGE_PAGE_CNT SG_CHUNK_SIZE
+#define HISI_SAS_SGE_PAGE_CNT (124)
 struct hisi_sas_sge_page {
        struct hisi_sas_sge sge[HISI_SAS_SGE_PAGE_CNT];
 }  __aligned(16);
 
-#define HISI_SAS_SGE_DIF_PAGE_CNT   SG_CHUNK_SIZE
+#define HISI_SAS_SGE_DIF_PAGE_CNT   HISI_SAS_SGE_PAGE_CNT
 struct hisi_sas_sge_dif_page {
        struct hisi_sas_sge sge[HISI_SAS_SGE_DIF_PAGE_CNT];
 }  __aligned(16);
index 5879771..cb746cf 100644 (file)
@@ -803,7 +803,7 @@ static int hisi_sas_dev_found(struct domain_device *device)
        device->lldd_dev = sas_dev;
        hisi_hba->hw->setup_itct(hisi_hba, sas_dev);
 
-       if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
+       if (parent_dev && dev_is_expander(parent_dev->dev_type)) {
                int phy_no;
                u8 phy_num = parent_dev->ex_dev.num_phys;
                struct ex_phy *phy;
@@ -1446,7 +1446,7 @@ static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state,
 
                                _sas_port = sas_port;
 
-                               if (DEV_IS_EXPANDER(dev->dev_type))
+                               if (dev_is_expander(dev->dev_type))
                                        sas_ha->notify_port_event(sas_phy,
                                                        PORTE_BROADCAST_RCVD);
                        }
@@ -1533,7 +1533,7 @@ static void hisi_sas_terminate_stp_reject(struct hisi_hba *hisi_hba)
                struct domain_device *port_dev = sas_port->port_dev;
                struct domain_device *device;
 
-               if (!port_dev || !DEV_IS_EXPANDER(port_dev->dev_type))
+               if (!port_dev || !dev_is_expander(port_dev->dev_type))
                        continue;
 
                /* Try to find a SATA device */
@@ -1903,7 +1903,7 @@ static int hisi_sas_clear_nexus_ha(struct sas_ha_struct *sas_ha)
                struct domain_device *device = sas_dev->sas_device;
 
                if ((sas_dev->dev_type == SAS_PHY_UNUSED) || !device ||
-                   DEV_IS_EXPANDER(device->dev_type))
+                   dev_is_expander(device->dev_type))
                        continue;
 
                rc = hisi_sas_debug_I_T_nexus_reset(device);
@@ -2475,6 +2475,14 @@ EXPORT_SYMBOL_GPL(hisi_sas_alloc);
 
 void hisi_sas_free(struct hisi_hba *hisi_hba)
 {
+       int i;
+
+       for (i = 0; i < hisi_hba->n_phy; i++) {
+               struct hisi_sas_phy *phy = &hisi_hba->phy[i];
+
+               del_timer_sync(&phy->timer);
+       }
+
        if (hisi_hba->wq)
                destroy_workqueue(hisi_hba->wq);
 }
index d99086e..e9b15d4 100644 (file)
@@ -422,70 +422,70 @@ static const struct hisi_sas_hw_error one_bit_ecc_errors[] = {
                .irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_1B_OFF),
                .msk = HGC_DQE_ECC_1B_ADDR_MSK,
                .shift = HGC_DQE_ECC_1B_ADDR_OFF,
-               .msg = "hgc_dqe_acc1b_intr found: Ram address is 0x%08X\n",
+               .msg = "hgc_dqe_ecc1b_intr",
                .reg = HGC_DQE_ECC_ADDR,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_1B_OFF),
                .msk = HGC_IOST_ECC_1B_ADDR_MSK,
                .shift = HGC_IOST_ECC_1B_ADDR_OFF,
-               .msg = "hgc_iost_acc1b_intr found: Ram address is 0x%08X\n",
+               .msg = "hgc_iost_ecc1b_intr",
                .reg = HGC_IOST_ECC_ADDR,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_1B_OFF),
                .msk = HGC_ITCT_ECC_1B_ADDR_MSK,
                .shift = HGC_ITCT_ECC_1B_ADDR_OFF,
-               .msg = "hgc_itct_acc1b_intr found: am address is 0x%08X\n",
+               .msg = "hgc_itct_ecc1b_intr",
                .reg = HGC_ITCT_ECC_ADDR,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_1B_OFF),
                .msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK,
                .shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF,
-               .msg = "hgc_iostl_acc1b_intr found: memory address is 0x%08X\n",
+               .msg = "hgc_iostl_ecc1b_intr",
                .reg = HGC_LM_DFX_STATUS2,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_1B_OFF),
                .msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK,
                .shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF,
-               .msg = "hgc_itctl_acc1b_intr found: memory address is 0x%08X\n",
+               .msg = "hgc_itctl_ecc1b_intr",
                .reg = HGC_LM_DFX_STATUS2,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_1B_OFF),
                .msk = HGC_CQE_ECC_1B_ADDR_MSK,
                .shift = HGC_CQE_ECC_1B_ADDR_OFF,
-               .msg = "hgc_cqe_acc1b_intr found: Ram address is 0x%08X\n",
+               .msg = "hgc_cqe_ecc1b_intr",
                .reg = HGC_CQE_ECC_ADDR,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_1B_OFF),
                .msk = HGC_RXM_DFX_STATUS14_MEM0_MSK,
                .shift = HGC_RXM_DFX_STATUS14_MEM0_OFF,
-               .msg = "rxm_mem0_acc1b_intr found: memory address is 0x%08X\n",
+               .msg = "rxm_mem0_ecc1b_intr",
                .reg = HGC_RXM_DFX_STATUS14,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_1B_OFF),
                .msk = HGC_RXM_DFX_STATUS14_MEM1_MSK,
                .shift = HGC_RXM_DFX_STATUS14_MEM1_OFF,
-               .msg = "rxm_mem1_acc1b_intr found: memory address is 0x%08X\n",
+               .msg = "rxm_mem1_ecc1b_intr",
                .reg = HGC_RXM_DFX_STATUS14,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_1B_OFF),
                .msk = HGC_RXM_DFX_STATUS14_MEM2_MSK,
                .shift = HGC_RXM_DFX_STATUS14_MEM2_OFF,
-               .msg = "rxm_mem2_acc1b_intr found: memory address is 0x%08X\n",
+               .msg = "rxm_mem2_ecc1b_intr",
                .reg = HGC_RXM_DFX_STATUS14,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_1B_OFF),
                .msk = HGC_RXM_DFX_STATUS15_MEM3_MSK,
                .shift = HGC_RXM_DFX_STATUS15_MEM3_OFF,
-               .msg = "rxm_mem3_acc1b_intr found: memory address is 0x%08X\n",
+               .msg = "rxm_mem3_ecc1b_intr",
                .reg = HGC_RXM_DFX_STATUS15,
        },
 };
@@ -495,70 +495,70 @@ static const struct hisi_sas_hw_error multi_bit_ecc_errors[] = {
                .irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_MB_OFF),
                .msk = HGC_DQE_ECC_MB_ADDR_MSK,
                .shift = HGC_DQE_ECC_MB_ADDR_OFF,
-               .msg = "hgc_dqe_accbad_intr (0x%x) found: Ram address is 0x%08X\n",
+               .msg = "hgc_dqe_eccbad_intr",
                .reg = HGC_DQE_ECC_ADDR,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_MB_OFF),
                .msk = HGC_IOST_ECC_MB_ADDR_MSK,
                .shift = HGC_IOST_ECC_MB_ADDR_OFF,
-               .msg = "hgc_iost_accbad_intr (0x%x) found: Ram address is 0x%08X\n",
+               .msg = "hgc_iost_eccbad_intr",
                .reg = HGC_IOST_ECC_ADDR,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_MB_OFF),
                .msk = HGC_ITCT_ECC_MB_ADDR_MSK,
                .shift = HGC_ITCT_ECC_MB_ADDR_OFF,
-               .msg = "hgc_itct_accbad_intr (0x%x) found: Ram address is 0x%08X\n",
+               .msg = "hgc_itct_eccbad_intr",
                .reg = HGC_ITCT_ECC_ADDR,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF),
                .msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK,
                .shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF,
-               .msg = "hgc_iostl_accbad_intr (0x%x) found: memory address is 0x%08X\n",
+               .msg = "hgc_iostl_eccbad_intr",
                .reg = HGC_LM_DFX_STATUS2,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF),
                .msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK,
                .shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF,
-               .msg = "hgc_itctl_accbad_intr (0x%x) found: memory address is 0x%08X\n",
+               .msg = "hgc_itctl_eccbad_intr",
                .reg = HGC_LM_DFX_STATUS2,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_MB_OFF),
                .msk = HGC_CQE_ECC_MB_ADDR_MSK,
                .shift = HGC_CQE_ECC_MB_ADDR_OFF,
-               .msg = "hgc_cqe_accbad_intr (0x%x) found: Ram address is 0x%08X\n",
+               .msg = "hgc_cqe_eccbad_intr",
                .reg = HGC_CQE_ECC_ADDR,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF),
                .msk = HGC_RXM_DFX_STATUS14_MEM0_MSK,
                .shift = HGC_RXM_DFX_STATUS14_MEM0_OFF,
-               .msg = "rxm_mem0_accbad_intr (0x%x) found: memory address is 0x%08X\n",
+               .msg = "rxm_mem0_eccbad_intr",
                .reg = HGC_RXM_DFX_STATUS14,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF),
                .msk = HGC_RXM_DFX_STATUS14_MEM1_MSK,
                .shift = HGC_RXM_DFX_STATUS14_MEM1_OFF,
-               .msg = "rxm_mem1_accbad_intr (0x%x) found: memory address is 0x%08X\n",
+               .msg = "rxm_mem1_eccbad_intr",
                .reg = HGC_RXM_DFX_STATUS14,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF),
                .msk = HGC_RXM_DFX_STATUS14_MEM2_MSK,
                .shift = HGC_RXM_DFX_STATUS14_MEM2_OFF,
-               .msg = "rxm_mem2_accbad_intr (0x%x) found: memory address is 0x%08X\n",
+               .msg = "rxm_mem2_eccbad_intr",
                .reg = HGC_RXM_DFX_STATUS14,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF),
                .msk = HGC_RXM_DFX_STATUS15_MEM3_MSK,
                .shift = HGC_RXM_DFX_STATUS15_MEM3_OFF,
-               .msg = "rxm_mem3_accbad_intr (0x%x) found: memory address is 0x%08X\n",
+               .msg = "rxm_mem3_eccbad_intr",
                .reg = HGC_RXM_DFX_STATUS15,
        },
 };
@@ -944,7 +944,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
                break;
        case SAS_SATA_DEV:
        case SAS_SATA_PENDING:
-               if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+               if (parent_dev && dev_is_expander(parent_dev->dev_type))
                        qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF;
                else
                        qw0 = HISI_SAS_DEV_TYPE_SATA << ITCT_HDR_DEV_TYPE_OFF;
@@ -2526,7 +2526,7 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba,
        /* create header */
        /* dw0 */
        dw0 = port->id << CMD_HDR_PORT_OFF;
-       if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+       if (parent_dev && dev_is_expander(parent_dev->dev_type))
                dw0 |= 3 << CMD_HDR_CMD_OFF;
        else
                dw0 |= 4 << CMD_HDR_CMD_OFF;
@@ -2973,7 +2973,8 @@ one_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba, u32 irq_value)
                        val = hisi_sas_read32(hisi_hba, ecc_error->reg);
                        val &= ecc_error->msk;
                        val >>= ecc_error->shift;
-                       dev_warn(dev, ecc_error->msg, val);
+                       dev_warn(dev, "%s found: mem addr is 0x%08X\n",
+                                ecc_error->msg, val);
                }
        }
 }
@@ -2992,7 +2993,8 @@ static void multi_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba,
                        val = hisi_sas_read32(hisi_hba, ecc_error->reg);
                        val &= ecc_error->msk;
                        val >>= ecc_error->shift;
-                       dev_err(dev, ecc_error->msg, irq_value, val);
+                       dev_err(dev, "%s (0x%x) found: mem addr is 0x%08X\n",
+                               ecc_error->msg, irq_value, val);
                        queue_work(hisi_hba->wq, &hisi_hba->rst_work);
                }
        }
index 0efd55b..5f0f6df 100644 (file)
@@ -23,6 +23,7 @@
 #define ITCT_CLR_EN_MSK                        (0x1 << ITCT_CLR_EN_OFF)
 #define ITCT_DEV_OFF                   0
 #define ITCT_DEV_MSK                   (0x7ff << ITCT_DEV_OFF)
+#define SAS_AXI_USER3                  0x50
 #define IO_SATA_BROKEN_MSG_ADDR_LO     0x58
 #define IO_SATA_BROKEN_MSG_ADDR_HI     0x5c
 #define SATA_INITI_D2H_STORE_ADDR_LO   0x60
@@ -549,6 +550,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
        /* Global registers init */
        hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE,
                         (u32)((1ULL << hisi_hba->queue_count) - 1));
+       hisi_sas_write32(hisi_hba, SAS_AXI_USER3, 0);
        hisi_sas_write32(hisi_hba, CFG_MAX_TAG, 0xfff0400);
        hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x108);
        hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x1);
@@ -752,7 +754,7 @@ static void setup_itct_v3_hw(struct hisi_hba *hisi_hba,
                break;
        case SAS_SATA_DEV:
        case SAS_SATA_PENDING:
-               if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+               if (parent_dev && dev_is_expander(parent_dev->dev_type))
                        qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF;
                else
                        qw0 = HISI_SAS_DEV_TYPE_SATA << ITCT_HDR_DEV_TYPE_OFF;
@@ -906,8 +908,14 @@ static void enable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
 static void disable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
 {
        u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+       u32 irq_msk = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2_MSK);
+       static const u32 msk = BIT(CHL_INT2_RX_DISP_ERR_OFF) |
+                              BIT(CHL_INT2_RX_CODE_ERR_OFF) |
+                              BIT(CHL_INT2_RX_INVLD_DW_OFF);
        u32 state;
 
+       hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2_MSK, msk | irq_msk);
+
        cfg &= ~PHY_CFG_ENA_MSK;
        hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
 
@@ -918,6 +926,15 @@ static void disable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
                cfg |= PHY_CFG_PHY_RST_MSK;
                hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
        }
+
+       udelay(1);
+
+       hisi_sas_phy_read32(hisi_hba, phy_no, ERR_CNT_INVLD_DW);
+       hisi_sas_phy_read32(hisi_hba, phy_no, ERR_CNT_DISP_ERR);
+       hisi_sas_phy_read32(hisi_hba, phy_no, ERR_CNT_CODE_ERR);
+
+       hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2, msk);
+       hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2_MSK, irq_msk);
 }
 
 static void start_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
@@ -1336,10 +1353,10 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba,
        u32 dw1 = 0, dw2 = 0;
 
        hdr->dw0 = cpu_to_le32(port->id << CMD_HDR_PORT_OFF);
-       if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+       if (parent_dev && dev_is_expander(parent_dev->dev_type))
                hdr->dw0 |= cpu_to_le32(3 << CMD_HDR_CMD_OFF);
        else
-               hdr->dw0 |= cpu_to_le32(4 << CMD_HDR_CMD_OFF);
+               hdr->dw0 |= cpu_to_le32(4U << CMD_HDR_CMD_OFF);
 
        switch (task->data_dir) {
        case DMA_TO_DEVICE:
@@ -1407,7 +1424,7 @@ static void prep_abort_v3_hw(struct hisi_hba *hisi_hba,
        struct hisi_sas_port *port = slot->port;
 
        /* dw0 */
-       hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/
+       hdr->dw0 = cpu_to_le32((5U << CMD_HDR_CMD_OFF) | /*abort*/
                               (port->id << CMD_HDR_PORT_OFF) |
                                   (dev_is_sata(dev)
                                        << CMD_HDR_ABORT_DEVICE_TYPE_OFF) |
@@ -1826,77 +1843,77 @@ static const struct hisi_sas_hw_error multi_bit_ecc_errors[] = {
                .irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_MB_OFF),
                .msk = HGC_DQE_ECC_MB_ADDR_MSK,
                .shift = HGC_DQE_ECC_MB_ADDR_OFF,
-               .msg = "hgc_dqe_eccbad_intr found: ram addr is 0x%08X\n",
+               .msg = "hgc_dqe_eccbad_intr",
                .reg = HGC_DQE_ECC_ADDR,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_MB_OFF),
                .msk = HGC_IOST_ECC_MB_ADDR_MSK,
                .shift = HGC_IOST_ECC_MB_ADDR_OFF,
-               .msg = "hgc_iost_eccbad_intr found: ram addr is 0x%08X\n",
+               .msg = "hgc_iost_eccbad_intr",
                .reg = HGC_IOST_ECC_ADDR,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_MB_OFF),
                .msk = HGC_ITCT_ECC_MB_ADDR_MSK,
                .shift = HGC_ITCT_ECC_MB_ADDR_OFF,
-               .msg = "hgc_itct_eccbad_intr found: ram addr is 0x%08X\n",
+               .msg = "hgc_itct_eccbad_intr",
                .reg = HGC_ITCT_ECC_ADDR,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF),
                .msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK,
                .shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF,
-               .msg = "hgc_iostl_eccbad_intr found: mem addr is 0x%08X\n",
+               .msg = "hgc_iostl_eccbad_intr",
                .reg = HGC_LM_DFX_STATUS2,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF),
                .msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK,
                .shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF,
-               .msg = "hgc_itctl_eccbad_intr found: mem addr is 0x%08X\n",
+               .msg = "hgc_itctl_eccbad_intr",
                .reg = HGC_LM_DFX_STATUS2,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_MB_OFF),
                .msk = HGC_CQE_ECC_MB_ADDR_MSK,
                .shift = HGC_CQE_ECC_MB_ADDR_OFF,
-               .msg = "hgc_cqe_eccbad_intr found: ram address is 0x%08X\n",
+               .msg = "hgc_cqe_eccbad_intr",
                .reg = HGC_CQE_ECC_ADDR,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF),
                .msk = HGC_RXM_DFX_STATUS14_MEM0_MSK,
                .shift = HGC_RXM_DFX_STATUS14_MEM0_OFF,
-               .msg = "rxm_mem0_eccbad_intr found: mem addr is 0x%08X\n",
+               .msg = "rxm_mem0_eccbad_intr",
                .reg = HGC_RXM_DFX_STATUS14,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF),
                .msk = HGC_RXM_DFX_STATUS14_MEM1_MSK,
                .shift = HGC_RXM_DFX_STATUS14_MEM1_OFF,
-               .msg = "rxm_mem1_eccbad_intr found: mem addr is 0x%08X\n",
+               .msg = "rxm_mem1_eccbad_intr",
                .reg = HGC_RXM_DFX_STATUS14,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF),
                .msk = HGC_RXM_DFX_STATUS14_MEM2_MSK,
                .shift = HGC_RXM_DFX_STATUS14_MEM2_OFF,
-               .msg = "rxm_mem2_eccbad_intr found: mem addr is 0x%08X\n",
+               .msg = "rxm_mem2_eccbad_intr",
                .reg = HGC_RXM_DFX_STATUS14,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF),
                .msk = HGC_RXM_DFX_STATUS15_MEM3_MSK,
                .shift = HGC_RXM_DFX_STATUS15_MEM3_OFF,
-               .msg = "rxm_mem3_eccbad_intr found: mem addr is 0x%08X\n",
+               .msg = "rxm_mem3_eccbad_intr",
                .reg = HGC_RXM_DFX_STATUS15,
        },
        {
                .irq_msk = BIT(SAS_ECC_INTR_OOO_RAM_ECC_MB_OFF),
                .msk = AM_ROB_ECC_ERR_ADDR_MSK,
                .shift = AM_ROB_ECC_ERR_ADDR_OFF,
-               .msg = "ooo_ram_eccbad_intr found: ROB_ECC_ERR_ADDR=0x%08X\n",
+               .msg = "ooo_ram_eccbad_intr",
                .reg = AM_ROB_ECC_ERR_ADDR,
        },
 };
@@ -1915,7 +1932,8 @@ static void multi_bit_ecc_error_process_v3_hw(struct hisi_hba *hisi_hba,
                        val = hisi_sas_read32(hisi_hba, ecc_error->reg);
                        val &= ecc_error->msk;
                        val >>= ecc_error->shift;
-                       dev_err(dev, ecc_error->msg, irq_value, val);
+                       dev_err(dev, "%s (0x%x) found: mem addr is 0x%08X\n",
+                               ecc_error->msg, irq_value, val);
                        queue_work(hisi_hba->wq, &hisi_hba->rst_work);
                }
        }
index ffd7e95..43a6b53 100644 (file)
@@ -60,7 +60,7 @@
  * HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.'
  * with an optional trailing '-' followed by a byte value (0-255).
  */
-#define HPSA_DRIVER_VERSION "3.4.20-160"
+#define HPSA_DRIVER_VERSION "3.4.20-170"
 #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")"
 #define HPSA "hpsa"
 
@@ -73,6 +73,8 @@
 
 /*define how many times we will try a command because of bus resets */
 #define MAX_CMD_RETRIES 3
+/* How long to wait before giving up on a command */
+#define HPSA_EH_PTRAID_TIMEOUT (240 * HZ)
 
 /* Embedded module documentation macros - see modules.h */
 MODULE_AUTHOR("Hewlett-Packard Company");
@@ -344,11 +346,6 @@ static inline bool hpsa_is_cmd_idle(struct CommandList *c)
        return c->scsi_cmd == SCSI_CMD_IDLE;
 }
 
-static inline bool hpsa_is_pending_event(struct CommandList *c)
-{
-       return c->reset_pending;
-}
-
 /* extract sense key, asc, and ascq from sense data.  -1 means invalid. */
 static void decode_sense_data(const u8 *sense_data, int sense_data_len,
                        u8 *sense_key, u8 *asc, u8 *ascq)
@@ -1144,6 +1141,8 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h,
 {
        dial_down_lockup_detection_during_fw_flash(h, c);
        atomic_inc(&h->commands_outstanding);
+       if (c->device)
+               atomic_inc(&c->device->commands_outstanding);
 
        reply_queue = h->reply_map[raw_smp_processor_id()];
        switch (c->cmd_type) {
@@ -1167,9 +1166,6 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h,
 
 static void enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c)
 {
-       if (unlikely(hpsa_is_pending_event(c)))
-               return finish_cmd(c);
-
        __enqueue_cmd_and_start_io(h, c, DEFAULT_REPLY_QUEUE);
 }
 
@@ -1842,25 +1838,33 @@ static int hpsa_find_outstanding_commands_for_dev(struct ctlr_info *h,
        return count;
 }
 
+#define NUM_WAIT 20
 static void hpsa_wait_for_outstanding_commands_for_dev(struct ctlr_info *h,
                                                struct hpsa_scsi_dev_t *device)
 {
        int cmds = 0;
        int waits = 0;
+       int num_wait = NUM_WAIT;
+
+       if (device->external)
+               num_wait = HPSA_EH_PTRAID_TIMEOUT;
 
        while (1) {
                cmds = hpsa_find_outstanding_commands_for_dev(h, device);
                if (cmds == 0)
                        break;
-               if (++waits > 20)
+               if (++waits > num_wait)
                        break;
                msleep(1000);
        }
 
-       if (waits > 20)
+       if (waits > num_wait) {
                dev_warn(&h->pdev->dev,
-                       "%s: removing device with %d outstanding commands!\n",
-                       __func__, cmds);
+                       "%s: removing device [%d:%d:%d:%d] with %d outstanding commands!\n",
+                       __func__,
+                       h->scsi_host->host_no,
+                       device->bus, device->target, device->lun, cmds);
+       }
 }
 
 static void hpsa_remove_device(struct ctlr_info *h,
@@ -2131,11 +2135,16 @@ static int hpsa_slave_configure(struct scsi_device *sdev)
        sdev->no_uld_attach = !sd || !sd->expose_device;
 
        if (sd) {
-               if (sd->external)
+               sd->was_removed = 0;
+               if (sd->external) {
                        queue_depth = EXTERNAL_QD;
-               else
+                       sdev->eh_timeout = HPSA_EH_PTRAID_TIMEOUT;
+                       blk_queue_rq_timeout(sdev->request_queue,
+                                               HPSA_EH_PTRAID_TIMEOUT);
+               } else {
                        queue_depth = sd->queue_depth != 0 ?
                                        sd->queue_depth : sdev->host->can_queue;
+               }
        } else
                queue_depth = sdev->host->can_queue;
 
@@ -2146,7 +2155,12 @@ static int hpsa_slave_configure(struct scsi_device *sdev)
 
 static void hpsa_slave_destroy(struct scsi_device *sdev)
 {
-       /* nothing to do. */
+       struct hpsa_scsi_dev_t *hdev = NULL;
+
+       hdev = sdev->hostdata;
+
+       if (hdev)
+               hdev->was_removed = 1;
 }
 
 static void hpsa_free_ioaccel2_sg_chain_blocks(struct ctlr_info *h)
@@ -2414,13 +2428,16 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h,
                break;
        }
 
+       if (dev->in_reset)
+               retry = 0;
+
        return retry;   /* retry on raid path? */
 }
 
 static void hpsa_cmd_resolve_events(struct ctlr_info *h,
                struct CommandList *c)
 {
-       bool do_wake = false;
+       struct hpsa_scsi_dev_t *dev = c->device;
 
        /*
         * Reset c->scsi_cmd here so that the reset handler will know
@@ -2429,25 +2446,12 @@ static void hpsa_cmd_resolve_events(struct ctlr_info *h,
         */
        c->scsi_cmd = SCSI_CMD_IDLE;
        mb();   /* Declare command idle before checking for pending events. */
-       if (c->reset_pending) {
-               unsigned long flags;
-               struct hpsa_scsi_dev_t *dev;
-
-               /*
-                * There appears to be a reset pending; lock the lock and
-                * reconfirm.  If so, then decrement the count of outstanding
-                * commands and wake the reset command if this is the last one.
-                */
-               spin_lock_irqsave(&h->lock, flags);
-               dev = c->reset_pending;         /* Re-fetch under the lock. */
-               if (dev && atomic_dec_and_test(&dev->reset_cmds_out))
-                       do_wake = true;
-               c->reset_pending = NULL;
-               spin_unlock_irqrestore(&h->lock, flags);
+       if (dev) {
+               atomic_dec(&dev->commands_outstanding);
+               if (dev->in_reset &&
+                       atomic_read(&dev->commands_outstanding) <= 0)
+                       wake_up_all(&h->event_sync_wait_queue);
        }
-
-       if (do_wake)
-               wake_up_all(&h->event_sync_wait_queue);
 }
 
 static void hpsa_cmd_resolve_and_free(struct ctlr_info *h,
@@ -2496,6 +2500,11 @@ static void process_ioaccel2_completion(struct ctlr_info *h,
                        dev->offload_to_be_enabled = 0;
                }
 
+               if (dev->in_reset) {
+                       cmd->result = DID_RESET << 16;
+                       return hpsa_cmd_free_and_done(h, c, cmd);
+               }
+
                return hpsa_retry_cmd(h, c);
        }
 
@@ -2574,6 +2583,12 @@ static void complete_scsi_command(struct CommandList *cp)
        cmd->result = (DID_OK << 16);           /* host byte */
        cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
 
+       /* SCSI command has already been cleaned up in SML */
+       if (dev->was_removed) {
+               hpsa_cmd_resolve_and_free(h, cp);
+               return;
+       }
+
        if (cp->cmd_type == CMD_IOACCEL2 || cp->cmd_type == CMD_IOACCEL1) {
                if (dev->physical_device && dev->expose_device &&
                        dev->removed) {
@@ -2595,10 +2610,6 @@ static void complete_scsi_command(struct CommandList *cp)
                return hpsa_cmd_free_and_done(h, cp, cmd);
        }
 
-       if ((unlikely(hpsa_is_pending_event(cp))))
-               if (cp->reset_pending)
-                       return hpsa_cmd_free_and_done(h, cp, cmd);
-
        if (cp->cmd_type == CMD_IOACCEL2)
                return process_ioaccel2_completion(h, cp, cmd, dev);
 
@@ -3048,7 +3059,7 @@ out:
        return rc;
 }
 
-static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr,
+static int hpsa_send_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev,
        u8 reset_type, int reply_queue)
 {
        int rc = IO_OK;
@@ -3056,11 +3067,10 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr,
        struct ErrorInfo *ei;
 
        c = cmd_alloc(h);
-
+       c->device = dev;
 
        /* fill_cmd can't fail here, no data buffer to map. */
-       (void) fill_cmd(c, reset_type, h, NULL, 0, 0,
-                       scsi3addr, TYPE_MSG);
+       (void) fill_cmd(c, reset_type, h, NULL, 0, 0, dev->scsi3addr, TYPE_MSG);
        rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT);
        if (rc) {
                dev_warn(&h->pdev->dev, "Failed to send reset command\n");
@@ -3138,9 +3148,8 @@ static bool hpsa_cmd_dev_match(struct ctlr_info *h, struct CommandList *c,
 }
 
 static int hpsa_do_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev,
-       unsigned char *scsi3addr, u8 reset_type, int reply_queue)
+       u8 reset_type, int reply_queue)
 {
-       int i;
        int rc = 0;
 
        /* We can really only handle one reset at a time */
@@ -3149,38 +3158,14 @@ static int hpsa_do_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev,
                return -EINTR;
        }
 
-       BUG_ON(atomic_read(&dev->reset_cmds_out) != 0);
-
-       for (i = 0; i < h->nr_cmds; i++) {
-               struct CommandList *c = h->cmd_pool + i;
-               int refcount = atomic_inc_return(&c->refcount);
-
-               if (refcount > 1 && hpsa_cmd_dev_match(h, c, dev, scsi3addr)) {
-                       unsigned long flags;
-
-                       /*
-                        * Mark the target command as having a reset pending,
-                        * then lock a lock so that the command cannot complete
-                        * while we're considering it.  If the command is not
-                        * idle then count it; otherwise revoke the event.
-                        */
-                       c->reset_pending = dev;
-                       spin_lock_irqsave(&h->lock, flags);     /* Implied MB */
-                       if (!hpsa_is_cmd_idle(c))
-                               atomic_inc(&dev->reset_cmds_out);
-                       else
-                               c->reset_pending = NULL;
-                       spin_unlock_irqrestore(&h->lock, flags);
-               }
-
-               cmd_free(h, c);
-       }
-
-       rc = hpsa_send_reset(h, scsi3addr, reset_type, reply_queue);
-       if (!rc)
+       rc = hpsa_send_reset(h, dev, reset_type, reply_queue);
+       if (!rc) {
+               /* incremented by sending the reset request */
+               atomic_dec(&dev->commands_outstanding);
                wait_event(h->event_sync_wait_queue,
-                       atomic_read(&dev->reset_cmds_out) == 0 ||
+                       atomic_read(&dev->commands_outstanding) <= 0 ||
                        lockup_detected(h));
+       }
 
        if (unlikely(lockup_detected(h))) {
                dev_warn(&h->pdev->dev,
@@ -3188,10 +3173,8 @@ static int hpsa_do_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev,
                rc = -ENODEV;
        }
 
-       if (unlikely(rc))
-               atomic_set(&dev->reset_cmds_out, 0);
-       else
-               rc = wait_for_device_to_become_ready(h, scsi3addr, 0);
+       if (!rc)
+               rc = wait_for_device_to_become_ready(h, dev->scsi3addr, 0);
 
        mutex_unlock(&h->reset_mutex);
        return rc;
@@ -4820,6 +4803,9 @@ static int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h,
 
        c->phys_disk = dev;
 
+       if (dev->in_reset)
+               return -1;
+
        return hpsa_scsi_ioaccel_queue_command(h, c, dev->ioaccel_handle,
                cmd->cmnd, cmd->cmd_len, dev->scsi3addr, dev);
 }
@@ -5010,6 +4996,11 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
        } else
                cp->sg_count = (u8) use_sg;
 
+       if (phys_disk->in_reset) {
+               cmd->result = DID_RESET << 16;
+               return -1;
+       }
+
        enqueue_cmd_and_start_io(h, c);
        return 0;
 }
@@ -5027,6 +5018,9 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
        if (!c->scsi_cmd->device->hostdata)
                return -1;
 
+       if (phys_disk->in_reset)
+               return -1;
+
        /* Try to honor the device's queue depth */
        if (atomic_inc_return(&phys_disk->ioaccel_cmds_out) >
                                        phys_disk->queue_depth) {
@@ -5110,6 +5104,9 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
        if (!dev)
                return -1;
 
+       if (dev->in_reset)
+               return -1;
+
        /* check for valid opcode, get LBA and block count */
        switch (cmd->cmnd[0]) {
        case WRITE_6:
@@ -5414,13 +5411,13 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
  */
 static int hpsa_ciss_submit(struct ctlr_info *h,
        struct CommandList *c, struct scsi_cmnd *cmd,
-       unsigned char scsi3addr[])
+       struct hpsa_scsi_dev_t *dev)
 {
        cmd->host_scribble = (unsigned char *) c;
        c->cmd_type = CMD_SCSI;
        c->scsi_cmd = cmd;
        c->Header.ReplyQueue = 0;  /* unused in simple mode */
-       memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8);
+       memcpy(&c->Header.LUN.LunAddrBytes[0], &dev->scsi3addr[0], 8);
        c->Header.tag = cpu_to_le64((c->cmdindex << DIRECT_LOOKUP_SHIFT));
 
        /* Fill in the request block... */
@@ -5471,6 +5468,12 @@ static int hpsa_ciss_submit(struct ctlr_info *h,
                hpsa_cmd_resolve_and_free(h, c);
                return SCSI_MLQUEUE_HOST_BUSY;
        }
+
+       if (dev->in_reset) {
+               hpsa_cmd_resolve_and_free(h, c);
+               return SCSI_MLQUEUE_HOST_BUSY;
+       }
+
        enqueue_cmd_and_start_io(h, c);
        /* the cmd'll come back via intr handler in complete_scsi_command()  */
        return 0;
@@ -5522,8 +5525,7 @@ static inline void hpsa_cmd_partial_init(struct ctlr_info *h, int index,
 }
 
 static int hpsa_ioaccel_submit(struct ctlr_info *h,
-               struct CommandList *c, struct scsi_cmnd *cmd,
-               unsigned char *scsi3addr)
+               struct CommandList *c, struct scsi_cmnd *cmd)
 {
        struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
        int rc = IO_ACCEL_INELIGIBLE;
@@ -5531,6 +5533,12 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h,
        if (!dev)
                return SCSI_MLQUEUE_HOST_BUSY;
 
+       if (dev->in_reset)
+               return SCSI_MLQUEUE_HOST_BUSY;
+
+       if (hpsa_simple_mode)
+               return IO_ACCEL_INELIGIBLE;
+
        cmd->host_scribble = (unsigned char *) c;
 
        if (dev->offload_enabled) {
@@ -5563,8 +5571,12 @@ static void hpsa_command_resubmit_worker(struct work_struct *work)
                cmd->result = DID_NO_CONNECT << 16;
                return hpsa_cmd_free_and_done(c->h, c, cmd);
        }
-       if (c->reset_pending)
+
+       if (dev->in_reset) {
+               cmd->result = DID_RESET << 16;
                return hpsa_cmd_free_and_done(c->h, c, cmd);
+       }
+
        if (c->cmd_type == CMD_IOACCEL2) {
                struct ctlr_info *h = c->h;
                struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex];
@@ -5572,7 +5584,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work)
 
                if (c2->error_data.serv_response ==
                                IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL) {
-                       rc = hpsa_ioaccel_submit(h, c, cmd, dev->scsi3addr);
+                       rc = hpsa_ioaccel_submit(h, c, cmd);
                        if (rc == 0)
                                return;
                        if (rc == SCSI_MLQUEUE_HOST_BUSY) {
@@ -5588,7 +5600,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work)
                }
        }
        hpsa_cmd_partial_init(c->h, c->cmdindex, c);
-       if (hpsa_ciss_submit(c->h, c, cmd, dev->scsi3addr)) {
+       if (hpsa_ciss_submit(c->h, c, cmd, dev)) {
                /*
                 * If we get here, it means dma mapping failed. Try
                 * again via scsi mid layer, which will then get
@@ -5607,7 +5619,6 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
 {
        struct ctlr_info *h;
        struct hpsa_scsi_dev_t *dev;
-       unsigned char scsi3addr[8];
        struct CommandList *c;
        int rc = 0;
 
@@ -5629,14 +5640,18 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
                return 0;
        }
 
-       memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr));
-
        if (unlikely(lockup_detected(h))) {
                cmd->result = DID_NO_CONNECT << 16;
                cmd->scsi_done(cmd);
                return 0;
        }
+
+       if (dev->in_reset)
+               return SCSI_MLQUEUE_DEVICE_BUSY;
+
        c = cmd_tagged_alloc(h, cmd);
+       if (c == NULL)
+               return SCSI_MLQUEUE_DEVICE_BUSY;
 
        /*
         * Call alternate submit routine for I/O accelerated commands.
@@ -5645,7 +5660,7 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
        if (likely(cmd->retries == 0 &&
                        !blk_rq_is_passthrough(cmd->request) &&
                        h->acciopath_status)) {
-               rc = hpsa_ioaccel_submit(h, c, cmd, scsi3addr);
+               rc = hpsa_ioaccel_submit(h, c, cmd);
                if (rc == 0)
                        return 0;
                if (rc == SCSI_MLQUEUE_HOST_BUSY) {
@@ -5653,7 +5668,7 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
                        return SCSI_MLQUEUE_HOST_BUSY;
                }
        }
-       return hpsa_ciss_submit(h, c, cmd, scsi3addr);
+       return hpsa_ciss_submit(h, c, cmd, dev);
 }
 
 static void hpsa_scan_complete(struct ctlr_info *h)
@@ -5935,8 +5950,9 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h,
 static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
 {
        int rc = SUCCESS;
+       int i;
        struct ctlr_info *h;
-       struct hpsa_scsi_dev_t *dev;
+       struct hpsa_scsi_dev_t *dev = NULL;
        u8 reset_type;
        char msg[48];
        unsigned long flags;
@@ -6002,9 +6018,19 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
                reset_type == HPSA_DEVICE_RESET_MSG ? "logical " : "physical ");
        hpsa_show_dev_msg(KERN_WARNING, h, dev, msg);
 
+       /*
+        * wait to see if any commands will complete before sending reset
+        */
+       dev->in_reset = true; /* block any new cmds from OS for this device */
+       for (i = 0; i < 10; i++) {
+               if (atomic_read(&dev->commands_outstanding) > 0)
+                       msleep(1000);
+               else
+                       break;
+       }
+
        /* send a reset to the SCSI LUN which the command was sent to */
-       rc = hpsa_do_reset(h, dev, dev->scsi3addr, reset_type,
-                          DEFAULT_REPLY_QUEUE);
+       rc = hpsa_do_reset(h, dev, reset_type, DEFAULT_REPLY_QUEUE);
        if (rc == 0)
                rc = SUCCESS;
        else
@@ -6018,6 +6044,8 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
 return_reset_status:
        spin_lock_irqsave(&h->reset_lock, flags);
        h->reset_in_progress = 0;
+       if (dev)
+               dev->in_reset = false;
        spin_unlock_irqrestore(&h->reset_lock, flags);
        return rc;
 }
@@ -6043,7 +6071,6 @@ static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h,
                BUG();
        }
 
-       atomic_inc(&c->refcount);
        if (unlikely(!hpsa_is_cmd_idle(c))) {
                /*
                 * We expect that the SCSI layer will hand us a unique tag
@@ -6051,14 +6078,20 @@ static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h,
                 * two requests...because if the selected command isn't idle
                 * then someone is going to be very disappointed.
                 */
-               dev_err(&h->pdev->dev,
-                       "tag collision (tag=%d) in cmd_tagged_alloc().\n",
-                       idx);
-               if (c->scsi_cmd != NULL)
-                       scsi_print_command(c->scsi_cmd);
-               scsi_print_command(scmd);
+               if (idx != h->last_collision_tag) { /* Print once per tag */
+                       dev_warn(&h->pdev->dev,
+                               "%s: tag collision (tag=%d)\n", __func__, idx);
+                       if (c->scsi_cmd != NULL)
+                               scsi_print_command(c->scsi_cmd);
+                       if (scmd)
+                               scsi_print_command(scmd);
+                       h->last_collision_tag = idx;
+               }
+               return NULL;
        }
 
+       atomic_inc(&c->refcount);
+
        hpsa_cmd_partial_init(h, idx, c);
        return c;
 }
@@ -6126,6 +6159,7 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h)
                break; /* it's ours now. */
        }
        hpsa_cmd_partial_init(h, i, c);
+       c->device = NULL;
        return c;
 }
 
@@ -6579,8 +6613,7 @@ static int hpsa_ioctl(struct scsi_device *dev, unsigned int cmd,
        }
 }
 
-static void hpsa_send_host_reset(struct ctlr_info *h, unsigned char *scsi3addr,
-                               u8 reset_type)
+static void hpsa_send_host_reset(struct ctlr_info *h, u8 reset_type)
 {
        struct CommandList *c;
 
@@ -7983,10 +8016,15 @@ clean_up:
 static void hpsa_free_irqs(struct ctlr_info *h)
 {
        int i;
+       int irq_vector = 0;
+
+       if (hpsa_simple_mode)
+               irq_vector = h->intr_mode;
 
        if (!h->msix_vectors || h->intr_mode != PERF_MODE_INT) {
                /* Single reply queue, only one irq to free */
-               free_irq(pci_irq_vector(h->pdev, 0), &h->q[h->intr_mode]);
+               free_irq(pci_irq_vector(h->pdev, irq_vector),
+                               &h->q[h->intr_mode]);
                h->q[h->intr_mode] = 0;
                return;
        }
@@ -8005,6 +8043,10 @@ static int hpsa_request_irqs(struct ctlr_info *h,
        irqreturn_t (*intxhandler)(int, void *))
 {
        int rc, i;
+       int irq_vector = 0;
+
+       if (hpsa_simple_mode)
+               irq_vector = h->intr_mode;
 
        /*
         * initialize h->q[x] = x so that interrupt handlers know which
@@ -8040,14 +8082,14 @@ static int hpsa_request_irqs(struct ctlr_info *h,
                if (h->msix_vectors > 0 || h->pdev->msi_enabled) {
                        sprintf(h->intrname[0], "%s-msi%s", h->devname,
                                h->msix_vectors ? "x" : "");
-                       rc = request_irq(pci_irq_vector(h->pdev, 0),
+                       rc = request_irq(pci_irq_vector(h->pdev, irq_vector),
                                msixhandler, 0,
                                h->intrname[0],
                                &h->q[h->intr_mode]);
                } else {
                        sprintf(h->intrname[h->intr_mode],
                                "%s-intx", h->devname);
-                       rc = request_irq(pci_irq_vector(h->pdev, 0),
+                       rc = request_irq(pci_irq_vector(h->pdev, irq_vector),
                                intxhandler, IRQF_SHARED,
                                h->intrname[0],
                                &h->q[h->intr_mode]);
@@ -8055,7 +8097,7 @@ static int hpsa_request_irqs(struct ctlr_info *h,
        }
        if (rc) {
                dev_err(&h->pdev->dev, "failed to get irq %d for %s\n",
-                      pci_irq_vector(h->pdev, 0), h->devname);
+                      pci_irq_vector(h->pdev, irq_vector), h->devname);
                hpsa_free_irqs(h);
                return -ENODEV;
        }
@@ -8065,7 +8107,7 @@ static int hpsa_request_irqs(struct ctlr_info *h,
 static int hpsa_kdump_soft_reset(struct ctlr_info *h)
 {
        int rc;
-       hpsa_send_host_reset(h, RAID_CTLR_LUNID, HPSA_RESET_TYPE_CONTROLLER);
+       hpsa_send_host_reset(h, HPSA_RESET_TYPE_CONTROLLER);
 
        dev_info(&h->pdev->dev, "Waiting for board to soft reset.\n");
        rc = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY);
@@ -8121,6 +8163,11 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h)
                destroy_workqueue(h->rescan_ctlr_wq);
                h->rescan_ctlr_wq = NULL;
        }
+       if (h->monitor_ctlr_wq) {
+               destroy_workqueue(h->monitor_ctlr_wq);
+               h->monitor_ctlr_wq = NULL;
+       }
+
        kfree(h);                               /* init_one 1 */
 }
 
@@ -8456,8 +8503,8 @@ static void hpsa_event_monitor_worker(struct work_struct *work)
 
        spin_lock_irqsave(&h->lock, flags);
        if (!h->remove_in_progress)
-               schedule_delayed_work(&h->event_monitor_work,
-                                       HPSA_EVENT_MONITOR_INTERVAL);
+               queue_delayed_work(h->monitor_ctlr_wq, &h->event_monitor_work,
+                               HPSA_EVENT_MONITOR_INTERVAL);
        spin_unlock_irqrestore(&h->lock, flags);
 }
 
@@ -8502,7 +8549,7 @@ static void hpsa_monitor_ctlr_worker(struct work_struct *work)
 
        spin_lock_irqsave(&h->lock, flags);
        if (!h->remove_in_progress)
-               schedule_delayed_work(&h->monitor_ctlr_work,
+               queue_delayed_work(h->monitor_ctlr_wq, &h->monitor_ctlr_work,
                                h->heartbeat_sample_interval);
        spin_unlock_irqrestore(&h->lock, flags);
 }
@@ -8670,6 +8717,12 @@ reinit_after_soft_reset:
                goto clean7;    /* aer/h */
        }
 
+       h->monitor_ctlr_wq = hpsa_create_controller_wq(h, "monitor");
+       if (!h->monitor_ctlr_wq) {
+               rc = -ENOMEM;
+               goto clean7;
+       }
+
        /*
         * At this point, the controller is ready to take commands.
         * Now, if reset_devices and the hard reset didn't work, try
@@ -8799,6 +8852,10 @@ clean1:  /* wq/aer/h */
                destroy_workqueue(h->rescan_ctlr_wq);
                h->rescan_ctlr_wq = NULL;
        }
+       if (h->monitor_ctlr_wq) {
+               destroy_workqueue(h->monitor_ctlr_wq);
+               h->monitor_ctlr_wq = NULL;
+       }
        kfree(h);
        return rc;
 }
@@ -8946,6 +9003,7 @@ static void hpsa_remove_one(struct pci_dev *pdev)
        cancel_delayed_work_sync(&h->event_monitor_work);
        destroy_workqueue(h->rescan_ctlr_wq);
        destroy_workqueue(h->resubmit_wq);
+       destroy_workqueue(h->monitor_ctlr_wq);
 
        hpsa_delete_sas_host(h);
 
index 59e0236..f8c88fc 100644 (file)
@@ -65,6 +65,7 @@ struct hpsa_scsi_dev_t {
        u8 physical_device : 1;
        u8 expose_device;
        u8 removed : 1;                 /* device is marked for death */
+       u8 was_removed : 1;             /* device actually removed */
 #define RAID_CTLR_LUNID "\0\0\0\0\0\0\0\0"
        unsigned char device_id[16];    /* from inquiry pg. 0x83 */
        u64 sas_address;
@@ -75,11 +76,12 @@ struct hpsa_scsi_dev_t {
        unsigned char raid_level;       /* from inquiry page 0xC1 */
        unsigned char volume_offline;   /* discovered via TUR or VPD */
        u16 queue_depth;                /* max queue_depth for this device */
-       atomic_t reset_cmds_out;        /* Count of commands to-be affected */
+       atomic_t commands_outstanding;  /* track commands sent to device */
        atomic_t ioaccel_cmds_out;      /* Only used for physical devices
                                         * counts commands sent to physical
                                         * device via "ioaccel" path.
                                         */
+       bool in_reset;
        u32 ioaccel_handle;
        u8 active_path_index;
        u8 path_map;
@@ -174,6 +176,7 @@ struct ctlr_info {
        struct CfgTable __iomem *cfgtable;
        int     interrupts_enabled;
        int     max_commands;
+       int     last_collision_tag; /* tags are global */
        atomic_t commands_outstanding;
 #      define PERF_MODE_INT    0
 #      define DOORBELL_INT     1
@@ -300,6 +303,7 @@ struct ctlr_info {
        int     needs_abort_tags_swizzled;
        struct workqueue_struct *resubmit_wq;
        struct workqueue_struct *rescan_ctlr_wq;
+       struct workqueue_struct *monitor_ctlr_wq;
        atomic_t abort_cmds_available;
        wait_queue_head_t event_sync_wait_queue;
        struct mutex reset_mutex;
index f6afca4..7825cbf 100644 (file)
@@ -448,7 +448,7 @@ struct CommandList {
        struct hpsa_scsi_dev_t *phys_disk;
 
        int abort_pending;
-       struct hpsa_scsi_dev_t *reset_pending;
+       struct hpsa_scsi_dev_t *device;
        atomic_t refcount; /* Must be last to avoid memset in hpsa_cmd_init() */
 } __aligned(COMMANDLIST_ALIGNMENT);
 
index 4aea97e..7f66a77 100644 (file)
@@ -814,7 +814,7 @@ static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
        atomic_set(&hostdata->request_limit, 0);
 
        purge_requests(hostdata, DID_ERROR);
-       hostdata->reset_crq = 1;
+       hostdata->action = IBMVSCSI_HOST_ACTION_RESET;
        wake_up(&hostdata->work_wait_q);
 }
 
@@ -1165,7 +1165,8 @@ static void login_rsp(struct srp_event_struct *evt_struct)
                   be32_to_cpu(evt_struct->xfer_iu->srp.login_rsp.req_lim_delta));
 
        /* If we had any pending I/Os, kick them */
-       scsi_unblock_requests(hostdata->host);
+       hostdata->action = IBMVSCSI_HOST_ACTION_UNBLOCK;
+       wake_up(&hostdata->work_wait_q);
 }
 
 /**
@@ -1783,7 +1784,7 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq,
                        /* We need to re-setup the interpartition connection */
                        dev_info(hostdata->dev, "Re-enabling adapter!\n");
                        hostdata->client_migrated = 1;
-                       hostdata->reenable_crq = 1;
+                       hostdata->action = IBMVSCSI_HOST_ACTION_REENABLE;
                        purge_requests(hostdata, DID_REQUEUE);
                        wake_up(&hostdata->work_wait_q);
                } else {
@@ -2036,6 +2037,16 @@ static struct device_attribute ibmvscsi_host_config = {
        .show = show_host_config,
 };
 
+static int ibmvscsi_host_reset(struct Scsi_Host *shost, int reset_type)
+{
+       struct ibmvscsi_host_data *hostdata = shost_priv(shost);
+
+       dev_info(hostdata->dev, "Initiating adapter reset!\n");
+       ibmvscsi_reset_host(hostdata);
+
+       return 0;
+}
+
 static struct device_attribute *ibmvscsi_attrs[] = {
        &ibmvscsi_host_vhost_loc,
        &ibmvscsi_host_vhost_name,
@@ -2062,6 +2073,7 @@ static struct scsi_host_template driver_template = {
        .eh_host_reset_handler = ibmvscsi_eh_host_reset_handler,
        .slave_configure = ibmvscsi_slave_configure,
        .change_queue_depth = ibmvscsi_change_queue_depth,
+       .host_reset = ibmvscsi_host_reset,
        .cmd_per_lun = IBMVSCSI_CMDS_PER_LUN_DEFAULT,
        .can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT,
        .this_id = -1,
@@ -2091,48 +2103,75 @@ static unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev)
 
 static void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata)
 {
+       unsigned long flags;
        int rc;
        char *action = "reset";
 
-       if (hostdata->reset_crq) {
-               smp_rmb();
-               hostdata->reset_crq = 0;
-
+       spin_lock_irqsave(hostdata->host->host_lock, flags);
+       switch (hostdata->action) {
+       case IBMVSCSI_HOST_ACTION_UNBLOCK:
+               rc = 0;
+               break;
+       case IBMVSCSI_HOST_ACTION_RESET:
+               spin_unlock_irqrestore(hostdata->host->host_lock, flags);
                rc = ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata);
+               spin_lock_irqsave(hostdata->host->host_lock, flags);
                if (!rc)
                        rc = ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0);
                vio_enable_interrupts(to_vio_dev(hostdata->dev));
-       } else if (hostdata->reenable_crq) {
-               smp_rmb();
+               break;
+       case IBMVSCSI_HOST_ACTION_REENABLE:
                action = "enable";
+               spin_unlock_irqrestore(hostdata->host->host_lock, flags);
                rc = ibmvscsi_reenable_crq_queue(&hostdata->queue, hostdata);
-               hostdata->reenable_crq = 0;
+               spin_lock_irqsave(hostdata->host->host_lock, flags);
                if (!rc)
                        rc = ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0);
-       } else
+               break;
+       case IBMVSCSI_HOST_ACTION_NONE:
+       default:
+               spin_unlock_irqrestore(hostdata->host->host_lock, flags);
                return;
+       }
+
+       hostdata->action = IBMVSCSI_HOST_ACTION_NONE;
 
        if (rc) {
                atomic_set(&hostdata->request_limit, -1);
                dev_err(hostdata->dev, "error after %s\n", action);
        }
+       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
 
        scsi_unblock_requests(hostdata->host);
 }
 
-static int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata)
+static int __ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata)
 {
        if (kthread_should_stop())
                return 1;
-       else if (hostdata->reset_crq) {
-               smp_rmb();
-               return 1;
-       } else if (hostdata->reenable_crq) {
-               smp_rmb();
-               return 1;
+       switch (hostdata->action) {
+       case IBMVSCSI_HOST_ACTION_NONE:
+               return 0;
+       case IBMVSCSI_HOST_ACTION_RESET:
+       case IBMVSCSI_HOST_ACTION_REENABLE:
+       case IBMVSCSI_HOST_ACTION_UNBLOCK:
+       default:
+               break;
        }
 
-       return 0;
+       return 1;
+}
+
+static int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata)
+{
+       unsigned long flags;
+       int rc;
+
+       spin_lock_irqsave(hostdata->host->host_lock, flags);
+       rc = __ibmvscsi_work_to_do(hostdata);
+       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+
+       return rc;
 }
 
 static int ibmvscsi_work(void *data)
index 6ebd141..e60916e 100644 (file)
@@ -74,13 +74,19 @@ struct event_pool {
        dma_addr_t iu_token;
 };
 
+enum ibmvscsi_host_action {
+       IBMVSCSI_HOST_ACTION_NONE = 0,
+       IBMVSCSI_HOST_ACTION_RESET,
+       IBMVSCSI_HOST_ACTION_REENABLE,
+       IBMVSCSI_HOST_ACTION_UNBLOCK,
+};
+
 /* all driver data associated with a host adapter */
 struct ibmvscsi_host_data {
        struct list_head host_list;
        atomic_t request_limit;
        int client_migrated;
-       int reset_crq;
-       int reenable_crq;
+       enum ibmvscsi_host_action action;
        struct device *dev;
        struct event_pool pool;
        struct crq_queue queue;
index 9751309..2519fb7 100644 (file)
@@ -687,7 +687,7 @@ static int imm_completion(struct scsi_cmnd *cmd)
                if (cmd->SCp.buffer && !cmd->SCp.this_residual) {
                        /* if scatter/gather, advance to the next segment */
                        if (cmd->SCp.buffers_residual--) {
-                               cmd->SCp.buffer++;
+                               cmd->SCp.buffer = sg_next(cmd->SCp.buffer);
                                cmd->SCp.this_residual =
                                    cmd->SCp.buffer->length;
                                cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
index d06bc1a..079c04b 100644 (file)
@@ -3901,22 +3901,23 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist,
                                 u8 *buffer, u32 len)
 {
        int bsize_elem, i, result = 0;
-       struct scatterlist *scatterlist;
+       struct scatterlist *sg;
        void *kaddr;
 
        /* Determine the actual number of bytes per element */
        bsize_elem = PAGE_SIZE * (1 << sglist->order);
 
-       scatterlist = sglist->scatterlist;
+       sg = sglist->scatterlist;
 
-       for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) {
-               struct page *page = sg_page(&scatterlist[i]);
+       for (i = 0; i < (len / bsize_elem); i++, sg = sg_next(sg),
+                       buffer += bsize_elem) {
+               struct page *page = sg_page(sg);
 
                kaddr = kmap(page);
                memcpy(kaddr, buffer, bsize_elem);
                kunmap(page);
 
-               scatterlist[i].length = bsize_elem;
+               sg->length = bsize_elem;
 
                if (result != 0) {
                        ipr_trace;
@@ -3925,13 +3926,13 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist,
        }
 
        if (len % bsize_elem) {
-               struct page *page = sg_page(&scatterlist[i]);
+               struct page *page = sg_page(sg);
 
                kaddr = kmap(page);
                memcpy(kaddr, buffer, len % bsize_elem);
                kunmap(page);
 
-               scatterlist[i].length = len % bsize_elem;
+               sg->length = len % bsize_elem;
        }
 
        sglist->buffer_len = len;
@@ -3952,6 +3953,7 @@ static void ipr_build_ucode_ioadl64(struct ipr_cmnd *ipr_cmd,
        struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
        struct ipr_ioadl64_desc *ioadl64 = ipr_cmd->i.ioadl64;
        struct scatterlist *scatterlist = sglist->scatterlist;
+       struct scatterlist *sg;
        int i;
 
        ipr_cmd->dma_use_sg = sglist->num_dma_sg;
@@ -3960,10 +3962,10 @@ static void ipr_build_ucode_ioadl64(struct ipr_cmnd *ipr_cmd,
 
        ioarcb->ioadl_len =
                cpu_to_be32(sizeof(struct ipr_ioadl64_desc) * ipr_cmd->dma_use_sg);
-       for (i = 0; i < ipr_cmd->dma_use_sg; i++) {
+       for_each_sg(scatterlist, sg, ipr_cmd->dma_use_sg, i) {
                ioadl64[i].flags = cpu_to_be32(IPR_IOADL_FLAGS_WRITE);
-               ioadl64[i].data_len = cpu_to_be32(sg_dma_len(&scatterlist[i]));
-               ioadl64[i].address = cpu_to_be64(sg_dma_address(&scatterlist[i]));
+               ioadl64[i].data_len = cpu_to_be32(sg_dma_len(sg));
+               ioadl64[i].address = cpu_to_be64(sg_dma_address(sg));
        }
 
        ioadl64[i-1].flags |= cpu_to_be32(IPR_IOADL_FLAGS_LAST);
@@ -3983,6 +3985,7 @@ static void ipr_build_ucode_ioadl(struct ipr_cmnd *ipr_cmd,
        struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
        struct ipr_ioadl_desc *ioadl = ipr_cmd->i.ioadl;
        struct scatterlist *scatterlist = sglist->scatterlist;
+       struct scatterlist *sg;
        int i;
 
        ipr_cmd->dma_use_sg = sglist->num_dma_sg;
@@ -3992,11 +3995,11 @@ static void ipr_build_ucode_ioadl(struct ipr_cmnd *ipr_cmd,
        ioarcb->ioadl_len =
                cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
 
-       for (i = 0; i < ipr_cmd->dma_use_sg; i++) {
+       for_each_sg(scatterlist, sg, ipr_cmd->dma_use_sg, i) {
                ioadl[i].flags_and_data_len =
-                       cpu_to_be32(IPR_IOADL_FLAGS_WRITE | sg_dma_len(&scatterlist[i]));
+                       cpu_to_be32(IPR_IOADL_FLAGS_WRITE | sg_dma_len(sg));
                ioadl[i].address =
-                       cpu_to_be32(sg_dma_address(&scatterlist[i]));
+                       cpu_to_be32(sg_dma_address(sg));
        }
 
        ioadl[i-1].flags_and_data_len |=
index 9d29edb..49aa4e6 100644 (file)
@@ -1087,7 +1087,7 @@ static void sci_remote_device_ready_state_enter(struct sci_base_state_machine *s
 
        if (dev->dev_type == SAS_SATA_DEV || (dev->tproto & SAS_PROTOCOL_SATA)) {
                sci_change_state(&idev->sm, SCI_STP_DEV_IDLE);
-       } else if (dev_is_expander(dev)) {
+       } else if (dev_is_expander(dev->dev_type)) {
                sci_change_state(&idev->sm, SCI_SMP_DEV_IDLE);
        } else
                isci_remote_device_ready(ihost, idev);
@@ -1478,7 +1478,7 @@ static enum sci_status isci_remote_device_construct(struct isci_port *iport,
        struct domain_device *dev = idev->domain_dev;
        enum sci_status status;
 
-       if (dev->parent && dev_is_expander(dev->parent))
+       if (dev->parent && dev_is_expander(dev->parent->dev_type))
                status = sci_remote_device_ea_construct(iport, idev);
        else
                status = sci_remote_device_da_construct(iport, idev);
index 47a013f..3ad681c 100644 (file)
@@ -295,11 +295,6 @@ static inline struct isci_remote_device *rnc_to_dev(struct sci_remote_node_conte
        return idev;
 }
 
-static inline bool dev_is_expander(struct domain_device *dev)
-{
-       return dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE;
-}
-
 static inline void sci_remote_device_decrement_request_count(struct isci_remote_device *idev)
 {
        /* XXX delete this voodoo when converting to the top-level device
index 1b18cf5..343d24c 100644 (file)
@@ -224,7 +224,7 @@ static void scu_ssp_request_construct_task_context(
        idev = ireq->target_device;
        iport = idev->owning_port;
 
-       /* Fill in the TC with the its required data */
+       /* Fill in the TC with its required data */
        task_context->abort = 0;
        task_context->priority = 0;
        task_context->initiator_request = 1;
@@ -506,7 +506,7 @@ static void scu_sata_request_construct_task_context(
        idev = ireq->target_device;
        iport = idev->owning_port;
 
-       /* Fill in the TC with the its required data */
+       /* Fill in the TC with its required data */
        task_context->abort = 0;
        task_context->priority = SCU_TASK_PRIORITY_NORMAL;
        task_context->initiator_request = 1;
@@ -3101,7 +3101,7 @@ sci_io_request_construct(struct isci_host *ihost,
                /* pass */;
        else if (dev_is_sata(dev))
                memset(&ireq->stp.cmd, 0, sizeof(ireq->stp.cmd));
-       else if (dev_is_expander(dev))
+       else if (dev_is_expander(dev->dev_type))
                /* pass */;
        else
                return SCI_FAILURE_UNSUPPORTED_PROTOCOL;
@@ -3235,7 +3235,7 @@ sci_io_request_construct_smp(struct device *dev,
        iport = idev->owning_port;
 
        /*
-        * Fill in the TC with the its required data
+        * Fill in the TC with its required data
         * 00h
         */
        task_context->priority = 0;
index fb6eba3..26fa1a4 100644 (file)
@@ -511,7 +511,7 @@ int isci_task_abort_task(struct sas_task *task)
                 "%s: dev = %p (%s%s), task = %p, old_request == %p\n",
                 __func__, idev,
                 (dev_is_sata(task->dev) ? "STP/SATA"
-                                        : ((dev_is_expander(task->dev))
+                                        : ((dev_is_expander(task->dev->dev_type))
                                                ? "SMP"
                                                : "SSP")),
                 ((idev) ? ((test_bit(IDEV_GONE, &idev->flags))
index 719e576..6ef93c7 100644 (file)
@@ -8,8 +8,6 @@
  * Copyright (C) 2006 Red Hat, Inc.  All rights reserved.
  * maintained by open-iscsi@googlegroups.com
  *
- * See the file COPYING included with this distribution for more details.
- *
  * Credits:
  *     Christoph Hellwig
  *     FUJITA Tomonori
index 726ada9..abcad09 100644 (file)
@@ -1,25 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Serial Attached SCSI (SAS) Discover process
  *
  * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
  * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
  */
 
 #include <linux/scatterlist.h>
@@ -309,7 +293,7 @@ void sas_free_device(struct kref *kref)
        dev->phy = NULL;
 
        /* remove the phys and ports, everything else should be gone */
-       if (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
+       if (dev_is_expander(dev->dev_type))
                kfree(dev->ex_dev.ex_phy);
 
        if (dev_is_sata(dev) && dev->sata_dev.ap) {
@@ -519,8 +503,7 @@ static void sas_revalidate_domain(struct work_struct *work)
        pr_debug("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id,
                 task_pid_nr(current));
 
-       if (ddev && (ddev->dev_type == SAS_FANOUT_EXPANDER_DEVICE ||
-                    ddev->dev_type == SAS_EDGE_EXPANDER_DEVICE))
+       if (ddev && dev_is_expander(ddev->dev_type))
                res = sas_ex_revalidate_domain(ddev);
 
        pr_debug("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n",
index b1e0f7d..a1852f6 100644 (file)
@@ -1,25 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Serial Attached SCSI (SAS) Event processing
  *
  * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
  * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
  */
 
 #include <linux/export.h>
index 9f7e245..9fdb9c9 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Serial Attached SCSI (SAS) Expander discovery and configuration
  *
@@ -5,21 +6,6 @@
  * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
  *
  * This file is licensed under GPLv2.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
  */
 
 #include <linux/scatterlist.h>
@@ -1106,7 +1092,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
                                 SAS_ADDR(dev->sas_addr),
                                 phy_id);
                        sas_ex_disable_phy(dev, phy_id);
-                       break;
+                       return res;
                } else
                        memcpy(dev->port->disc.fanout_sas_addr,
                               ex_phy->attached_sas_addr, SAS_ADDR_SIZE);
@@ -1118,27 +1104,9 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
                break;
        }
 
-       if (child) {
-               int i;
-
-               for (i = 0; i < ex->num_phys; i++) {
-                       if (ex->ex_phy[i].phy_state == PHY_VACANT ||
-                           ex->ex_phy[i].phy_state == PHY_NOT_PRESENT)
-                               continue;
-                       /*
-                        * Due to races, the phy might not get added to the
-                        * wide port, so we add the phy to the wide port here.
-                        */
-                       if (SAS_ADDR(ex->ex_phy[i].attached_sas_addr) ==
-                           SAS_ADDR(child->sas_addr)) {
-                               ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED;
-                               if (sas_ex_join_wide_port(dev, i))
-                                       pr_debug("Attaching ex phy%02d to wide port %016llx\n",
-                                                i, SAS_ADDR(ex->ex_phy[i].attached_sas_addr));
-                       }
-               }
-       }
-
+       if (!child)
+               pr_notice("ex %016llx phy%02d failed to discover\n",
+                         SAS_ADDR(dev->sas_addr), phy_id);
        return res;
 }
 
@@ -1154,8 +1122,7 @@ static int sas_find_sub_addr(struct domain_device *dev, u8 *sub_addr)
                    phy->phy_state == PHY_NOT_PRESENT)
                        continue;
 
-               if ((phy->attached_dev_type == SAS_EDGE_EXPANDER_DEVICE ||
-                    phy->attached_dev_type == SAS_FANOUT_EXPANDER_DEVICE) &&
+               if (dev_is_expander(phy->attached_dev_type) &&
                    phy->routing_attr == SUBTRACTIVE_ROUTING) {
 
                        memcpy(sub_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
@@ -1173,8 +1140,7 @@ static int sas_check_level_subtractive_boundary(struct domain_device *dev)
        u8 sub_addr[SAS_ADDR_SIZE] = {0, };
 
        list_for_each_entry(child, &ex->children, siblings) {
-               if (child->dev_type != SAS_EDGE_EXPANDER_DEVICE &&
-                   child->dev_type != SAS_FANOUT_EXPANDER_DEVICE)
+               if (!dev_is_expander(child->dev_type))
                        continue;
                if (sub_addr[0] == 0) {
                        sas_find_sub_addr(child, sub_addr);
@@ -1259,8 +1225,7 @@ static int sas_check_ex_subtractive_boundary(struct domain_device *dev)
                    phy->phy_state == PHY_NOT_PRESENT)
                        continue;
 
-               if ((phy->attached_dev_type == SAS_FANOUT_EXPANDER_DEVICE ||
-                    phy->attached_dev_type == SAS_EDGE_EXPANDER_DEVICE) &&
+               if (dev_is_expander(phy->attached_dev_type) &&
                    phy->routing_attr == SUBTRACTIVE_ROUTING) {
 
                        if (!sub_sas_addr)
@@ -1356,8 +1321,7 @@ static int sas_check_parent_topology(struct domain_device *child)
        if (!child->parent)
                return 0;
 
-       if (child->parent->dev_type != SAS_EDGE_EXPANDER_DEVICE &&
-           child->parent->dev_type != SAS_FANOUT_EXPANDER_DEVICE)
+       if (!dev_is_expander(child->parent->dev_type))
                return 0;
 
        parent_ex = &child->parent->ex_dev;
@@ -1653,8 +1617,7 @@ static int sas_ex_level_discovery(struct asd_sas_port *port, const int level)
        struct domain_device *dev;
 
        list_for_each_entry(dev, &port->dev_list, dev_list_node) {
-               if (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE ||
-                   dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE) {
+               if (dev_is_expander(dev->dev_type)) {
                        struct sas_expander_device *ex =
                                rphy_to_expander_device(dev->rphy);
 
@@ -1886,7 +1849,7 @@ static int sas_find_bcast_dev(struct domain_device *dev,
                                SAS_ADDR(dev->sas_addr));
        }
        list_for_each_entry(ch, &ex->children, siblings) {
-               if (ch->dev_type == SAS_EDGE_EXPANDER_DEVICE || ch->dev_type == SAS_FANOUT_EXPANDER_DEVICE) {
+               if (dev_is_expander(ch->dev_type)) {
                        res = sas_find_bcast_dev(ch, src_dev);
                        if (*src_dev)
                                return res;
@@ -1903,8 +1866,7 @@ static void sas_unregister_ex_tree(struct asd_sas_port *port, struct domain_devi
 
        list_for_each_entry_safe(child, n, &ex->children, siblings) {
                set_bit(SAS_DEV_GONE, &child->state);
-               if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE ||
-                   child->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
+               if (dev_is_expander(child->dev_type))
                        sas_unregister_ex_tree(port, child);
                else
                        sas_unregister_dev(port, child);
@@ -1924,8 +1886,7 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent,
                        if (SAS_ADDR(child->sas_addr) ==
                            SAS_ADDR(phy->attached_sas_addr)) {
                                set_bit(SAS_DEV_GONE, &child->state);
-                               if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE ||
-                                   child->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
+                               if (dev_is_expander(child->dev_type))
                                        sas_unregister_ex_tree(parent->port, child);
                                else
                                        sas_unregister_dev(parent->port, child);
@@ -1954,8 +1915,7 @@ static int sas_discover_bfs_by_root_level(struct domain_device *root,
        int res = 0;
 
        list_for_each_entry(child, &ex_root->children, siblings) {
-               if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE ||
-                   child->dev_type == SAS_FANOUT_EXPANDER_DEVICE) {
+               if (dev_is_expander(child->dev_type)) {
                        struct sas_expander_device *ex =
                                rphy_to_expander_device(child->rphy);
 
@@ -2008,8 +1968,7 @@ static int sas_discover_new(struct domain_device *dev, int phy_id)
        list_for_each_entry(child, &dev->ex_dev.children, siblings) {
                if (SAS_ADDR(child->sas_addr) ==
                    SAS_ADDR(ex_phy->attached_sas_addr)) {
-                       if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE ||
-                           child->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
+                       if (dev_is_expander(child->dev_type))
                                res = sas_discover_bfs_by_root(child);
                        break;
                }
index d50810d..21c43b1 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Serial Attached SCSI (SAS) Transport Layer initialization
  *
index 1f1e07e..01f1738 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Serial Attached SCSI (SAS) class internal header file
  *
index b71f5ac..4ca4b1f 100644 (file)
@@ -1,25 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Serial Attached SCSI (SAS) Phy class
  *
  * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
  * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
  */
 
 #include "sas_internal.h"
index 38a1047..7c86fd2 100644 (file)
@@ -1,25 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Serial Attached SCSI (SAS) Port class
  *
  * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
  * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
  */
 
 #include "sas_internal.h"
@@ -70,7 +54,7 @@ static void sas_resume_port(struct asd_sas_phy *phy)
                        continue;
                }
 
-               if (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE) {
+               if (dev_is_expander(dev->dev_type)) {
                        dev->ex_dev.ex_change_count = -1;
                        for (i = 0; i < dev->ex_dev.num_phys; i++) {
                                struct ex_phy *phy = &dev->ex_dev.ex_phy[i];
@@ -195,7 +179,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
 
        sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN);
        /* Only insert a revalidate event after initial discovery */
-       if (port_dev && sas_dev_type_is_expander(port_dev->dev_type)) {
+       if (port_dev && dev_is_expander(port_dev->dev_type)) {
                struct expander_device *ex_dev = &port_dev->ex_dev;
 
                ex_dev->ex_change_count = -1;
@@ -264,7 +248,7 @@ void sas_deform_port(struct asd_sas_phy *phy, int gone)
        spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags);
 
        /* Only insert revalidate event if the port still has members */
-       if (port->port && dev && sas_dev_type_is_expander(dev->dev_type)) {
+       if (port->port && dev && dev_is_expander(dev->dev_type)) {
                struct expander_device *ex_dev = &dev->ex_dev;
 
                ex_dev->ex_change_count = -1;
index ede0674..4f339f9 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Serial Attached SCSI (SAS) class SCSI Host glue.
  *
index 2bd1e01..ea62322 100644 (file)
@@ -4097,9 +4097,9 @@ lpfc_topology_store(struct device *dev, struct device_attribute *attr,
                }
                if ((phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC ||
                     phba->pcidev->device == PCI_DEVICE_ID_LANCER_G7_FC) &&
-                   val != FLAGS_TOPOLOGY_MODE_PT_PT) {
+                   val == 4) {
                        lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
-                               "3114 Only non-FC-AL mode is supported\n");
+                               "3114 Loop mode not supported\n");
                        return -EINVAL;
                }
                phba->cfg_topology = val;
@@ -5180,7 +5180,8 @@ lpfc_cq_max_proc_limit_store(struct device *dev, struct device_attribute *attr,
 
        /* set the values on the cq's */
        for (i = 0; i < phba->cfg_irq_chann; i++) {
-               eq = phba->sli4_hba.hdwq[i].hba_eq;
+               /* Get the EQ corresponding to the IRQ vector */
+               eq = phba->sli4_hba.hba_eq_hdl[i].eq;
                if (!eq)
                        continue;
 
@@ -5301,35 +5302,44 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr,
                                len += scnprintf(
                                        buf + len, PAGE_SIZE - len,
                                        "CPU %02d hdwq None "
-                                       "physid %d coreid %d ht %d\n",
+                                       "physid %d coreid %d ht %d ua %d\n",
                                        phba->sli4_hba.curr_disp_cpu,
-                                       cpup->phys_id,
-                                       cpup->core_id, cpup->hyper);
+                                       cpup->phys_id, cpup->core_id,
+                                       (cpup->flag & LPFC_CPU_MAP_HYPER),
+                                       (cpup->flag & LPFC_CPU_MAP_UNASSIGN));
                        else
                                len += scnprintf(
                                        buf + len, PAGE_SIZE - len,
                                        "CPU %02d EQ %04d hdwq %04d "
-                                       "physid %d coreid %d ht %d\n",
+                                       "physid %d coreid %d ht %d ua %d\n",
                                        phba->sli4_hba.curr_disp_cpu,
                                        cpup->eq, cpup->hdwq, cpup->phys_id,
-                                       cpup->core_id, cpup->hyper);
+                                       cpup->core_id,
+                                       (cpup->flag & LPFC_CPU_MAP_HYPER),
+                                       (cpup->flag & LPFC_CPU_MAP_UNASSIGN));
                } else {
                        if (cpup->hdwq == LPFC_VECTOR_MAP_EMPTY)
                                len += scnprintf(
                                        buf + len, PAGE_SIZE - len,
                                        "CPU %02d hdwq None "
-                                       "physid %d coreid %d ht %d IRQ %d\n",
+                                       "physid %d coreid %d ht %d ua %d IRQ %d\n",
                                        phba->sli4_hba.curr_disp_cpu,
                                        cpup->phys_id,
-                                       cpup->core_id, cpup->hyper, cpup->irq);
+                                       cpup->core_id,
+                                       (cpup->flag & LPFC_CPU_MAP_HYPER),
+                                       (cpup->flag & LPFC_CPU_MAP_UNASSIGN),
+                                       cpup->irq);
                        else
                                len += scnprintf(
                                        buf + len, PAGE_SIZE - len,
                                        "CPU %02d EQ %04d hdwq %04d "
-                                       "physid %d coreid %d ht %d IRQ %d\n",
+                                       "physid %d coreid %d ht %d ua %d IRQ %d\n",
                                        phba->sli4_hba.curr_disp_cpu,
                                        cpup->eq, cpup->hdwq, cpup->phys_id,
-                                       cpup->core_id, cpup->hyper, cpup->irq);
+                                       cpup->core_id,
+                                       (cpup->flag & LPFC_CPU_MAP_HYPER),
+                                       (cpup->flag & LPFC_CPU_MAP_UNASSIGN),
+                                       cpup->irq);
                }
 
                phba->sli4_hba.curr_disp_cpu++;
index b0202bc..b7216d6 100644 (file)
@@ -5741,7 +5741,7 @@ lpfc_get_trunk_info(struct bsg_job *job)
 
        event_reply->port_speed = phba->sli4_hba.link_state.speed / 1000;
        event_reply->logical_speed =
-                               phba->sli4_hba.link_state.logical_speed / 100;
+                               phba->sli4_hba.link_state.logical_speed / 1000;
 job_error:
        bsg_reply->result = rc;
        bsg_job_done(job, bsg_reply->result,
index 8663748..68e9f96 100644 (file)
@@ -572,7 +572,8 @@ void lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba);
 void lpfc_nvmet_unsol_ls_event(struct lpfc_hba *phba,
                        struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocb);
 void lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba, uint32_t idx,
-                               struct rqb_dmabuf *nvmebuf, uint64_t isr_ts);
+                               struct rqb_dmabuf *nvmebuf, uint64_t isr_ts,
+                               uint8_t cqflag);
 void lpfc_nvme_mod_param_dep(struct lpfc_hba *phba);
 void lpfc_nvme_abort_fcreq_cmpl(struct lpfc_hba *phba,
                                struct lpfc_iocbq *cmdiocb,
index 4812bbb..ec72c39 100644 (file)
@@ -2358,6 +2358,7 @@ static int
 lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport,
                            struct lpfc_fdmi_attr_def *ad)
 {
+       struct lpfc_hba   *phba = vport->phba;
        struct lpfc_fdmi_attr_entry *ae;
        uint32_t size;
 
@@ -2366,9 +2367,13 @@ lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport,
 
        ae->un.AttrTypes[3] = 0x02; /* Type 0x1 - ELS */
        ae->un.AttrTypes[2] = 0x01; /* Type 0x8 - FCP */
-       if (vport->nvmei_support || vport->phba->nvmet_support)
-               ae->un.AttrTypes[6] = 0x01; /* Type 0x28 - NVME */
        ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */
+
+       /* Check to see if Firmware supports NVME and on physical port */
+       if ((phba->sli_rev == LPFC_SLI_REV4) && (vport == phba->pport) &&
+           phba->sli4_hba.pc_sli4_params.nvme)
+               ae->un.AttrTypes[6] = 0x01; /* Type 0x28 - NVME */
+
        size = FOURBYTES + 32;
        ad->AttrLen = cpu_to_be16(size);
        ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_FC4_TYPES);
@@ -2680,9 +2685,12 @@ lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport,
 
        ae->un.AttrTypes[3] = 0x02; /* Type 0x1 - ELS */
        ae->un.AttrTypes[2] = 0x01; /* Type 0x8 - FCP */
+       ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */
+
+       /* Check to see if NVME is configured or not */
        if (vport->phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)
                ae->un.AttrTypes[6] = 0x1; /* Type 0x28 - NVME */
-       ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */
+
        size = FOURBYTES + 32;
        ad->AttrLen = cpu_to_be16(size);
        ad->AttrType = cpu_to_be16(RPRT_ACTIVE_FC4_TYPES);
index 968ed0f..f12780f 100644 (file)
@@ -4308,6 +4308,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                if ((rspiocb->iocb.ulpStatus == 0)
                    && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
                        if (!lpfc_unreg_rpi(vport, ndlp) &&
+                           (!(vport->fc_flag & FC_PT2PT)) &&
                            (ndlp->nlp_state ==  NLP_STE_PLOGI_ISSUE ||
                             ndlp->nlp_state == NLP_STE_REG_LOGIN_ISSUE)) {
                                lpfc_printf_vlog(vport, KERN_INFO,
index eaaef68..faf43b1 100644 (file)
@@ -72,7 +72,7 @@ unsigned long _dump_buf_dif_order;
 spinlock_t _dump_buf_lock;
 
 /* Used when mapping IRQ vectors in a driver centric manner */
-uint32_t lpfc_present_cpu;
+static uint32_t lpfc_present_cpu;
 
 static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *);
 static int lpfc_post_rcv_buf(struct lpfc_hba *);
@@ -93,8 +93,8 @@ 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 uint16_t lpfc_find_eq_handle(struct lpfc_hba *, uint16_t);
 static uint16_t lpfc_find_cpu_handle(struct lpfc_hba *, uint16_t, int);
+static void lpfc_setup_bg(struct lpfc_hba *, struct Scsi_Host *);
 
 static struct scsi_transport_template *lpfc_transport_template = NULL;
 static struct scsi_transport_template *lpfc_vport_transport_template = NULL;
@@ -1274,8 +1274,10 @@ lpfc_hb_eq_delay_work(struct work_struct *work)
        if (!eqcnt)
                goto requeue;
 
+       /* Loop thru all IRQ vectors */
        for (i = 0; i < phba->cfg_irq_chann; i++) {
-               eq = phba->sli4_hba.hdwq[i].hba_eq;
+               /* Get the EQ corresponding to the IRQ vector */
+               eq = phba->sli4_hba.hba_eq_hdl[i].eq;
                if (eq && eqcnt[eq->last_cpu] < 2)
                        eqcnt[eq->last_cpu]++;
                continue;
@@ -2963,7 +2965,7 @@ lpfc_stop_hba_timers(struct lpfc_hba *phba)
                del_timer_sync(&phba->fcp_poll_timer);
                break;
        case LPFC_PCI_DEV_OC:
-               /* Stop any OneConnect device sepcific driver timers */
+               /* Stop any OneConnect device specific driver timers */
                lpfc_sli4_stop_fcf_redisc_wait_timer(phba);
                break;
        default:
@@ -4114,14 +4116,13 @@ lpfc_new_io_buf(struct lpfc_hba *phba, int num_to_alloc)
                 * pci bus space for an I/O. The DMA buffer includes the
                 * number of SGE's necessary to support the sg_tablesize.
                 */
-               lpfc_ncmd->data = dma_pool_alloc(phba->lpfc_sg_dma_buf_pool,
-                               GFP_KERNEL,
-                               &lpfc_ncmd->dma_handle);
+               lpfc_ncmd->data = dma_pool_zalloc(phba->lpfc_sg_dma_buf_pool,
+                                                 GFP_KERNEL,
+                                                 &lpfc_ncmd->dma_handle);
                if (!lpfc_ncmd->data) {
                        kfree(lpfc_ncmd);
                        break;
                }
-               memset(lpfc_ncmd->data, 0, phba->cfg_sg_dma_buf_size);
 
                /*
                 * 4K Page alignment is CRITICAL to BlockGuard, double check
@@ -4347,6 +4348,9 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
 
        timer_setup(&vport->delayed_disc_tmo, lpfc_delayed_disc_tmo, 0);
 
+       if (phba->sli3_options & LPFC_SLI3_BG_ENABLED)
+               lpfc_setup_bg(phba, shost);
+
        error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev);
        if (error)
                goto out_put_shost;
@@ -5055,7 +5059,7 @@ lpfc_update_trunk_link_status(struct lpfc_hba *phba,
                                bf_get(lpfc_acqe_fc_la_speed, acqe_fc));
 
        phba->sli4_hba.link_state.logical_speed =
-                               bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc);
+                               bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc) * 10;
        /* We got FC link speed, convert to fc_linkspeed (READ_TOPOLOGY) */
        phba->fc_linkspeed =
                 lpfc_async_link_speed_to_read_top(
@@ -5158,8 +5162,14 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc)
                                bf_get(lpfc_acqe_fc_la_port_number, acqe_fc);
        phba->sli4_hba.link_state.fault =
                                bf_get(lpfc_acqe_link_fault, acqe_fc);
-       phba->sli4_hba.link_state.logical_speed =
+
+       if (bf_get(lpfc_acqe_fc_la_att_type, acqe_fc) ==
+           LPFC_FC_LA_TYPE_LINK_DOWN)
+               phba->sli4_hba.link_state.logical_speed = 0;
+       else if (!phba->sli4_hba.conf_trunk)
+               phba->sli4_hba.link_state.logical_speed =
                                bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc) * 10;
+
        lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
                        "2896 Async FC event - Speed:%dGBaud Topology:x%x "
                        "LA Type:x%x Port Type:%d Port Number:%d Logical speed:"
@@ -6551,6 +6561,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                spin_lock_init(&phba->sli4_hba.abts_nvmet_buf_list_lock);
                INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_nvmet_ctx_list);
                INIT_LIST_HEAD(&phba->sli4_hba.lpfc_nvmet_io_wait_list);
+               spin_lock_init(&phba->sli4_hba.t_active_list_lock);
+               INIT_LIST_HEAD(&phba->sli4_hba.t_active_ctx_list);
        }
 
        /* This abort list used by worker thread */
@@ -7660,8 +7672,6 @@ lpfc_post_init_setup(struct lpfc_hba *phba)
         */
        shost = pci_get_drvdata(phba->pcidev);
        shost->can_queue = phba->cfg_hba_queue_depth - 10;
-       if (phba->sli3_options & LPFC_SLI3_BG_ENABLED)
-               lpfc_setup_bg(phba, shost);
 
        lpfc_host_attrib_init(shost);
 
@@ -8740,8 +8750,10 @@ int
 lpfc_sli4_queue_create(struct lpfc_hba *phba)
 {
        struct lpfc_queue *qdesc;
-       int idx, eqidx, cpu;
+       int idx, cpu, eqcpu;
        struct lpfc_sli4_hdw_queue *qp;
+       struct lpfc_vector_map_info *cpup;
+       struct lpfc_vector_map_info *eqcpup;
        struct lpfc_eq_intr_info *eqi;
 
        /*
@@ -8826,40 +8838,60 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
        INIT_LIST_HEAD(&phba->sli4_hba.lpfc_wq_list);
 
        /* Create HBA Event Queues (EQs) */
-       for (idx = 0; idx < phba->cfg_hdw_queue; idx++) {
-               /* determine EQ affinity */
-               eqidx = lpfc_find_eq_handle(phba, idx);
-               cpu = lpfc_find_cpu_handle(phba, eqidx, LPFC_FIND_BY_EQ);
-               /*
-                * If there are more Hardware Queues than available
-                * EQs, multiple Hardware Queues may share a common EQ.
+       for_each_present_cpu(cpu) {
+               /* We only want to create 1 EQ per vector, even though
+                * multiple CPUs might be using that vector. so only
+                * selects the CPUs that are LPFC_CPU_FIRST_IRQ.
                 */
-               if (idx >= phba->cfg_irq_chann) {
-                       /* Share an existing EQ */
-                       phba->sli4_hba.hdwq[idx].hba_eq =
-                               phba->sli4_hba.hdwq[eqidx].hba_eq;
+               cpup = &phba->sli4_hba.cpu_map[cpu];
+               if (!(cpup->flag & LPFC_CPU_FIRST_IRQ))
                        continue;
-               }
-               /* Create an EQ */
+
+               /* Get a ptr to the Hardware Queue associated with this CPU */
+               qp = &phba->sli4_hba.hdwq[cpup->hdwq];
+
+               /* Allocate an EQ */
                qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
                                              phba->sli4_hba.eq_esize,
                                              phba->sli4_hba.eq_ecount, cpu);
                if (!qdesc) {
                        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                                       "0497 Failed allocate EQ (%d)\n", idx);
+                                       "0497 Failed allocate EQ (%d)\n",
+                                       cpup->hdwq);
                        goto out_error;
                }
                qdesc->qe_valid = 1;
-               qdesc->hdwq = idx;
-
-               /* Save the CPU this EQ is affinitised to */
-               qdesc->chann = cpu;
-               phba->sli4_hba.hdwq[idx].hba_eq = qdesc;
+               qdesc->hdwq = cpup->hdwq;
+               qdesc->chann = cpu; /* First CPU this EQ is affinitised to */
                qdesc->last_cpu = qdesc->chann;
+
+               /* Save the allocated EQ in the Hardware Queue */
+               qp->hba_eq = qdesc;
+
                eqi = per_cpu_ptr(phba->sli4_hba.eq_info, qdesc->last_cpu);
                list_add(&qdesc->cpu_list, &eqi->list);
        }
 
+       /* Now we need to populate the other Hardware Queues, that share
+        * an IRQ vector, with the associated EQ ptr.
+        */
+       for_each_present_cpu(cpu) {
+               cpup = &phba->sli4_hba.cpu_map[cpu];
+
+               /* Check for EQ already allocated in previous loop */
+               if (cpup->flag & LPFC_CPU_FIRST_IRQ)
+                       continue;
+
+               /* Check for multiple CPUs per hdwq */
+               qp = &phba->sli4_hba.hdwq[cpup->hdwq];
+               if (qp->hba_eq)
+                       continue;
+
+               /* We need to share an EQ for this hdwq */
+               eqcpu = lpfc_find_cpu_handle(phba, cpup->eq, LPFC_FIND_BY_EQ);
+               eqcpup = &phba->sli4_hba.cpu_map[eqcpu];
+               qp->hba_eq = phba->sli4_hba.hdwq[eqcpup->hdwq].hba_eq;
+       }
 
        /* Allocate SCSI SLI4 CQ/WQs */
        for (idx = 0; idx < phba->cfg_hdw_queue; idx++) {
@@ -9122,23 +9154,31 @@ static inline void
 lpfc_sli4_release_hdwq(struct lpfc_hba *phba)
 {
        struct lpfc_sli4_hdw_queue *hdwq;
+       struct lpfc_queue *eq;
        uint32_t idx;
 
        hdwq = phba->sli4_hba.hdwq;
-       for (idx = 0; idx < phba->cfg_hdw_queue; idx++) {
-               if (idx < phba->cfg_irq_chann)
-                       lpfc_sli4_queue_free(hdwq[idx].hba_eq);
-               hdwq[idx].hba_eq = NULL;
 
+       /* Loop thru all Hardware Queues */
+       for (idx = 0; idx < phba->cfg_hdw_queue; idx++) {
+               /* Free the CQ/WQ corresponding to the Hardware Queue */
                lpfc_sli4_queue_free(hdwq[idx].fcp_cq);
                lpfc_sli4_queue_free(hdwq[idx].nvme_cq);
                lpfc_sli4_queue_free(hdwq[idx].fcp_wq);
                lpfc_sli4_queue_free(hdwq[idx].nvme_wq);
+               hdwq[idx].hba_eq = NULL;
                hdwq[idx].fcp_cq = NULL;
                hdwq[idx].nvme_cq = NULL;
                hdwq[idx].fcp_wq = NULL;
                hdwq[idx].nvme_wq = NULL;
        }
+       /* Loop thru all IRQ vectors */
+       for (idx = 0; idx < phba->cfg_irq_chann; idx++) {
+               /* Free the EQ corresponding to the IRQ vector */
+               eq = phba->sli4_hba.hba_eq_hdl[idx].eq;
+               lpfc_sli4_queue_free(eq);
+               phba->sli4_hba.hba_eq_hdl[idx].eq = NULL;
+       }
 }
 
 /**
@@ -9316,16 +9356,17 @@ static void
 lpfc_setup_cq_lookup(struct lpfc_hba *phba)
 {
        struct lpfc_queue *eq, *childq;
-       struct lpfc_sli4_hdw_queue *qp;
        int qidx;
 
-       qp = phba->sli4_hba.hdwq;
        memset(phba->sli4_hba.cq_lookup, 0,
               (sizeof(struct lpfc_queue *) * (phba->sli4_hba.cq_max + 1)));
+       /* Loop thru all IRQ vectors */
        for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) {
-               eq = qp[qidx].hba_eq;
+               /* Get the EQ corresponding to the IRQ vector */
+               eq = phba->sli4_hba.hba_eq_hdl[qidx].eq;
                if (!eq)
                        continue;
+               /* Loop through all CQs associated with that EQ */
                list_for_each_entry(childq, &eq->child_list, list) {
                        if (childq->queue_id > phba->sli4_hba.cq_max)
                                continue;
@@ -9354,9 +9395,10 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
 {
        uint32_t shdr_status, shdr_add_status;
        union lpfc_sli4_cfg_shdr *shdr;
+       struct lpfc_vector_map_info *cpup;
        struct lpfc_sli4_hdw_queue *qp;
        LPFC_MBOXQ_t *mboxq;
-       int qidx;
+       int qidx, cpu;
        uint32_t length, usdelay;
        int rc = -ENOMEM;
 
@@ -9417,32 +9459,55 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
                rc = -ENOMEM;
                goto out_error;
        }
+
+       /* Loop thru all IRQ vectors */
        for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) {
-               if (!qp[qidx].hba_eq) {
-                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                                       "0522 Fast-path EQ (%d) not "
-                                       "allocated\n", qidx);
-                       rc = -ENOMEM;
-                       goto out_destroy;
-               }
-               rc = lpfc_eq_create(phba, qp[qidx].hba_eq,
-                                   phba->cfg_fcp_imax);
-               if (rc) {
-                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                                       "0523 Failed setup of fast-path EQ "
-                                       "(%d), rc = 0x%x\n", qidx,
-                                       (uint32_t)rc);
-                       goto out_destroy;
+               /* Create HBA Event Queues (EQs) in order */
+               for_each_present_cpu(cpu) {
+                       cpup = &phba->sli4_hba.cpu_map[cpu];
+
+                       /* Look for the CPU thats using that vector with
+                        * LPFC_CPU_FIRST_IRQ set.
+                        */
+                       if (!(cpup->flag & LPFC_CPU_FIRST_IRQ))
+                               continue;
+                       if (qidx != cpup->eq)
+                               continue;
+
+                       /* Create an EQ for that vector */
+                       rc = lpfc_eq_create(phba, qp[cpup->hdwq].hba_eq,
+                                           phba->cfg_fcp_imax);
+                       if (rc) {
+                               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                               "0523 Failed setup of fast-path"
+                                               " EQ (%d), rc = 0x%x\n",
+                                               cpup->eq, (uint32_t)rc);
+                               goto out_destroy;
+                       }
+
+                       /* Save the EQ for that vector in the hba_eq_hdl */
+                       phba->sli4_hba.hba_eq_hdl[cpup->eq].eq =
+                               qp[cpup->hdwq].hba_eq;
+
+                       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                                       "2584 HBA EQ setup: queue[%d]-id=%d\n",
+                                       cpup->eq,
+                                       qp[cpup->hdwq].hba_eq->queue_id);
                }
-               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-                               "2584 HBA EQ setup: queue[%d]-id=%d\n", qidx,
-                               qp[qidx].hba_eq->queue_id);
        }
 
+       /* Loop thru all Hardware Queues */
        if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) {
                for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
+                       cpu = lpfc_find_cpu_handle(phba, qidx,
+                                                  LPFC_FIND_BY_HDWQ);
+                       cpup = &phba->sli4_hba.cpu_map[cpu];
+
+                       /* Create the CQ/WQ corresponding to the
+                        * Hardware Queue
+                        */
                        rc = lpfc_create_wq_cq(phba,
-                                       qp[qidx].hba_eq,
+                                       phba->sli4_hba.hdwq[cpup->hdwq].hba_eq,
                                        qp[qidx].nvme_cq,
                                        qp[qidx].nvme_wq,
                                        &phba->sli4_hba.hdwq[qidx].nvme_cq_map,
@@ -9458,8 +9523,12 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
        }
 
        for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
+               cpu = lpfc_find_cpu_handle(phba, qidx, LPFC_FIND_BY_HDWQ);
+               cpup = &phba->sli4_hba.cpu_map[cpu];
+
+               /* Create the CQ/WQ corresponding to the Hardware Queue */
                rc = lpfc_create_wq_cq(phba,
-                                      qp[qidx].hba_eq,
+                                      phba->sli4_hba.hdwq[cpup->hdwq].hba_eq,
                                       qp[qidx].fcp_cq,
                                       qp[qidx].fcp_wq,
                                       &phba->sli4_hba.hdwq[qidx].fcp_cq_map,
@@ -9711,6 +9780,7 @@ void
 lpfc_sli4_queue_unset(struct lpfc_hba *phba)
 {
        struct lpfc_sli4_hdw_queue *qp;
+       struct lpfc_queue *eq;
        int qidx;
 
        /* Unset mailbox command work queue */
@@ -9762,14 +9832,20 @@ lpfc_sli4_queue_unset(struct lpfc_hba *phba)
 
        /* Unset fast-path SLI4 queues */
        if (phba->sli4_hba.hdwq) {
+               /* Loop thru all Hardware Queues */
                for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
+                       /* Destroy the CQ/WQ corresponding to Hardware Queue */
                        qp = &phba->sli4_hba.hdwq[qidx];
                        lpfc_wq_destroy(phba, qp->fcp_wq);
                        lpfc_wq_destroy(phba, qp->nvme_wq);
                        lpfc_cq_destroy(phba, qp->fcp_cq);
                        lpfc_cq_destroy(phba, qp->nvme_cq);
-                       if (qidx < phba->cfg_irq_chann)
-                               lpfc_eq_destroy(phba, qp->hba_eq);
+               }
+               /* Loop thru all IRQ vectors */
+               for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) {
+                       /* Destroy the EQ corresponding to the IRQ vector */
+                       eq = phba->sli4_hba.hba_eq_hdl[qidx].eq;
+                       lpfc_eq_destroy(phba, eq);
                }
        }
 
@@ -10559,11 +10635,12 @@ lpfc_sli_disable_intr(struct lpfc_hba *phba)
 }
 
 /**
- * lpfc_find_cpu_handle - Find the CPU that corresponds to the specified EQ
+ * lpfc_find_cpu_handle - Find the CPU that corresponds to the specified Queue
  * @phba: pointer to lpfc hba data structure.
  * @id: EQ vector index or Hardware Queue index
  * @match: LPFC_FIND_BY_EQ = match by EQ
  *         LPFC_FIND_BY_HDWQ = match by Hardware Queue
+ * Return the CPU that matches the selection criteria
  */
 static uint16_t
 lpfc_find_cpu_handle(struct lpfc_hba *phba, uint16_t id, int match)
@@ -10571,40 +10648,27 @@ lpfc_find_cpu_handle(struct lpfc_hba *phba, uint16_t id, int match)
        struct lpfc_vector_map_info *cpup;
        int cpu;
 
-       /* Find the desired phys_id for the specified EQ */
+       /* Loop through all CPUs */
        for_each_present_cpu(cpu) {
                cpup = &phba->sli4_hba.cpu_map[cpu];
+
+               /* If we are matching by EQ, there may be multiple CPUs using
+                * using the same vector, so select the one with
+                * LPFC_CPU_FIRST_IRQ set.
+                */
                if ((match == LPFC_FIND_BY_EQ) &&
+                   (cpup->flag & LPFC_CPU_FIRST_IRQ) &&
                    (cpup->irq != LPFC_VECTOR_MAP_EMPTY) &&
                    (cpup->eq == id))
                        return cpu;
+
+               /* If matching by HDWQ, select the first CPU that matches */
                if ((match == LPFC_FIND_BY_HDWQ) && (cpup->hdwq == id))
                        return cpu;
        }
        return 0;
 }
 
-/**
- * lpfc_find_eq_handle - Find the EQ that corresponds to the specified
- *                       Hardware Queue
- * @phba: pointer to lpfc hba data structure.
- * @hdwq: Hardware Queue index
- */
-static uint16_t
-lpfc_find_eq_handle(struct lpfc_hba *phba, uint16_t hdwq)
-{
-       struct lpfc_vector_map_info *cpup;
-       int cpu;
-
-       /* Find the desired phys_id for the specified EQ */
-       for_each_present_cpu(cpu) {
-               cpup = &phba->sli4_hba.cpu_map[cpu];
-               if (cpup->hdwq == hdwq)
-                       return cpup->eq;
-       }
-       return 0;
-}
-
 #ifdef CONFIG_X86
 /**
  * lpfc_find_hyper - Determine if the CPU map entry is hyper-threaded
@@ -10645,24 +10709,31 @@ lpfc_find_hyper(struct lpfc_hba *phba, int cpu,
 static void
 lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
 {
-       int i, cpu, idx;
+       int i, cpu, idx, new_cpu, start_cpu, first_cpu;
        int max_phys_id, min_phys_id;
        int max_core_id, min_core_id;
        struct lpfc_vector_map_info *cpup;
+       struct lpfc_vector_map_info *new_cpup;
        const struct cpumask *maskp;
 #ifdef CONFIG_X86
        struct cpuinfo_x86 *cpuinfo;
 #endif
 
        /* Init cpu_map array */
-       memset(phba->sli4_hba.cpu_map, 0xff,
-              (sizeof(struct lpfc_vector_map_info) *
-              phba->sli4_hba.num_possible_cpu));
+       for_each_possible_cpu(cpu) {
+               cpup = &phba->sli4_hba.cpu_map[cpu];
+               cpup->phys_id = LPFC_VECTOR_MAP_EMPTY;
+               cpup->core_id = LPFC_VECTOR_MAP_EMPTY;
+               cpup->hdwq = LPFC_VECTOR_MAP_EMPTY;
+               cpup->eq = LPFC_VECTOR_MAP_EMPTY;
+               cpup->irq = LPFC_VECTOR_MAP_EMPTY;
+               cpup->flag = 0;
+       }
 
        max_phys_id = 0;
-       min_phys_id = 0xffff;
+       min_phys_id = LPFC_VECTOR_MAP_EMPTY;
        max_core_id = 0;
-       min_core_id = 0xffff;
+       min_core_id = LPFC_VECTOR_MAP_EMPTY;
 
        /* Update CPU map with physical id and core id of each CPU */
        for_each_present_cpu(cpu) {
@@ -10671,13 +10742,12 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
                cpuinfo = &cpu_data(cpu);
                cpup->phys_id = cpuinfo->phys_proc_id;
                cpup->core_id = cpuinfo->cpu_core_id;
-               cpup->hyper = lpfc_find_hyper(phba, cpu,
-                                             cpup->phys_id, cpup->core_id);
+               if (lpfc_find_hyper(phba, cpu, cpup->phys_id, cpup->core_id))
+                       cpup->flag |= LPFC_CPU_MAP_HYPER;
 #else
                /* No distinction between CPUs for other platforms */
                cpup->phys_id = 0;
                cpup->core_id = cpu;
-               cpup->hyper = 0;
 #endif
 
                lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
@@ -10703,23 +10773,216 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
                eqi->icnt = 0;
        }
 
+       /* This loop sets up all CPUs that are affinitized with a
+        * irq vector assigned to the driver. All affinitized CPUs
+        * will get a link to that vectors IRQ and EQ.
+        */
        for (idx = 0; idx <  phba->cfg_irq_chann; idx++) {
+               /* Get a CPU mask for all CPUs affinitized to this vector */
                maskp = pci_irq_get_affinity(phba->pcidev, idx);
                if (!maskp)
                        continue;
 
+               i = 0;
+               /* Loop through all CPUs associated with vector idx */
                for_each_cpu_and(cpu, maskp, cpu_present_mask) {
+                       /* Set the EQ index and IRQ for that vector */
                        cpup = &phba->sli4_hba.cpu_map[cpu];
                        cpup->eq = idx;
-                       cpup->hdwq = idx;
                        cpup->irq = pci_irq_vector(phba->pcidev, idx);
 
-                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
                                        "3336 Set Affinity: CPU %d "
-                                       "hdwq %d irq %d\n",
-                                       cpu, cpup->hdwq, cpup->irq);
+                                       "irq %d eq %d\n",
+                                       cpu, cpup->irq, cpup->eq);
+
+                       /* If this is the first CPU thats assigned to this
+                        * vector, set LPFC_CPU_FIRST_IRQ.
+                        */
+                       if (!i)
+                               cpup->flag |= LPFC_CPU_FIRST_IRQ;
+                       i++;
                }
        }
+
+       /* After looking at each irq vector assigned to this pcidev, its
+        * possible to see that not ALL CPUs have been accounted for.
+        * Next we will set any unassigned (unaffinitized) cpu map
+        * entries to a IRQ on the same phys_id.
+        */
+       first_cpu = cpumask_first(cpu_present_mask);
+       start_cpu = first_cpu;
+
+       for_each_present_cpu(cpu) {
+               cpup = &phba->sli4_hba.cpu_map[cpu];
+
+               /* Is this CPU entry unassigned */
+               if (cpup->eq == LPFC_VECTOR_MAP_EMPTY) {
+                       /* Mark CPU as IRQ not assigned by the kernel */
+                       cpup->flag |= LPFC_CPU_MAP_UNASSIGN;
+
+                       /* If so, find a new_cpup thats on the the SAME
+                        * phys_id as cpup. start_cpu will start where we
+                        * left off so all unassigned entries don't get assgined
+                        * the IRQ of the first entry.
+                        */
+                       new_cpu = start_cpu;
+                       for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) {
+                               new_cpup = &phba->sli4_hba.cpu_map[new_cpu];
+                               if (!(new_cpup->flag & LPFC_CPU_MAP_UNASSIGN) &&
+                                   (new_cpup->irq != LPFC_VECTOR_MAP_EMPTY) &&
+                                   (new_cpup->phys_id == cpup->phys_id))
+                                       goto found_same;
+                               new_cpu = cpumask_next(
+                                       new_cpu, cpu_present_mask);
+                               if (new_cpu == nr_cpumask_bits)
+                                       new_cpu = first_cpu;
+                       }
+                       /* At this point, we leave the CPU as unassigned */
+                       continue;
+found_same:
+                       /* We found a matching phys_id, so copy the IRQ info */
+                       cpup->eq = new_cpup->eq;
+                       cpup->irq = new_cpup->irq;
+
+                       /* Bump start_cpu to the next slot to minmize the
+                        * chance of having multiple unassigned CPU entries
+                        * selecting the same IRQ.
+                        */
+                       start_cpu = cpumask_next(new_cpu, cpu_present_mask);
+                       if (start_cpu == nr_cpumask_bits)
+                               start_cpu = first_cpu;
+
+                       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                                       "3337 Set Affinity: CPU %d "
+                                       "irq %d from id %d same "
+                                       "phys_id (%d)\n",
+                                       cpu, cpup->irq, new_cpu, cpup->phys_id);
+               }
+       }
+
+       /* Set any unassigned cpu map entries to a IRQ on any phys_id */
+       start_cpu = first_cpu;
+
+       for_each_present_cpu(cpu) {
+               cpup = &phba->sli4_hba.cpu_map[cpu];
+
+               /* Is this entry unassigned */
+               if (cpup->eq == LPFC_VECTOR_MAP_EMPTY) {
+                       /* Mark it as IRQ not assigned by the kernel */
+                       cpup->flag |= LPFC_CPU_MAP_UNASSIGN;
+
+                       /* If so, find a new_cpup thats on ANY phys_id
+                        * as the cpup. start_cpu will start where we
+                        * left off so all unassigned entries don't get
+                        * assigned the IRQ of the first entry.
+                        */
+                       new_cpu = start_cpu;
+                       for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) {
+                               new_cpup = &phba->sli4_hba.cpu_map[new_cpu];
+                               if (!(new_cpup->flag & LPFC_CPU_MAP_UNASSIGN) &&
+                                   (new_cpup->irq != LPFC_VECTOR_MAP_EMPTY))
+                                       goto found_any;
+                               new_cpu = cpumask_next(
+                                       new_cpu, cpu_present_mask);
+                               if (new_cpu == nr_cpumask_bits)
+                                       new_cpu = first_cpu;
+                       }
+                       /* We should never leave an entry unassigned */
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "3339 Set Affinity: CPU %d "
+                                       "irq %d UNASSIGNED\n",
+                                       cpup->hdwq, cpup->irq);
+                       continue;
+found_any:
+                       /* We found an available entry, copy the IRQ info */
+                       cpup->eq = new_cpup->eq;
+                       cpup->irq = new_cpup->irq;
+
+                       /* Bump start_cpu to the next slot to minmize the
+                        * chance of having multiple unassigned CPU entries
+                        * selecting the same IRQ.
+                        */
+                       start_cpu = cpumask_next(new_cpu, cpu_present_mask);
+                       if (start_cpu == nr_cpumask_bits)
+                               start_cpu = first_cpu;
+
+                       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                                       "3338 Set Affinity: CPU %d "
+                                       "irq %d from id %d (%d/%d)\n",
+                                       cpu, cpup->irq, new_cpu,
+                                       new_cpup->phys_id, new_cpup->core_id);
+               }
+       }
+
+       /* Finally we need to associate a hdwq with each cpu_map entry
+        * This will be 1 to 1 - hdwq to cpu, unless there are less
+        * hardware queues then CPUs. For that case we will just round-robin
+        * the available hardware queues as they get assigned to CPUs.
+        */
+       idx = 0;
+       start_cpu = 0;
+       for_each_present_cpu(cpu) {
+               cpup = &phba->sli4_hba.cpu_map[cpu];
+               if (idx >=  phba->cfg_hdw_queue) {
+                       /* We need to reuse a Hardware Queue for another CPU,
+                        * so be smart about it and pick one that has its
+                        * IRQ/EQ mapped to the same phys_id (CPU package).
+                        * and core_id.
+                        */
+                       new_cpu = start_cpu;
+                       for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) {
+                               new_cpup = &phba->sli4_hba.cpu_map[new_cpu];
+                               if ((new_cpup->hdwq != LPFC_VECTOR_MAP_EMPTY) &&
+                                   (new_cpup->phys_id == cpup->phys_id) &&
+                                   (new_cpup->core_id == cpup->core_id))
+                                       goto found_hdwq;
+                               new_cpu = cpumask_next(
+                                       new_cpu, cpu_present_mask);
+                               if (new_cpu == nr_cpumask_bits)
+                                       new_cpu = first_cpu;
+                       }
+
+                       /* If we can't match both phys_id and core_id,
+                        * settle for just a phys_id match.
+                        */
+                       new_cpu = start_cpu;
+                       for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) {
+                               new_cpup = &phba->sli4_hba.cpu_map[new_cpu];
+                               if ((new_cpup->hdwq != LPFC_VECTOR_MAP_EMPTY) &&
+                                   (new_cpup->phys_id == cpup->phys_id))
+                                       goto found_hdwq;
+                               new_cpu = cpumask_next(
+                                       new_cpu, cpu_present_mask);
+                               if (new_cpu == nr_cpumask_bits)
+                                       new_cpu = first_cpu;
+                       }
+
+                       /* Otherwise just round robin on cfg_hdw_queue */
+                       cpup->hdwq = idx % phba->cfg_hdw_queue;
+                       goto logit;
+found_hdwq:
+                       /* We found an available entry, copy the IRQ info */
+                       start_cpu = cpumask_next(new_cpu, cpu_present_mask);
+                       if (start_cpu == nr_cpumask_bits)
+                               start_cpu = first_cpu;
+                       cpup->hdwq = new_cpup->hdwq;
+               } else {
+                       /* 1 to 1, CPU to hdwq */
+                       cpup->hdwq = idx;
+               }
+logit:
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "3335 Set Affinity: CPU %d (phys %d core %d): "
+                               "hdwq %d eq %d irq %d flg x%x\n",
+                               cpu, cpup->phys_id, cpup->core_id,
+                               cpup->hdwq, cpup->eq, cpup->irq, cpup->flag);
+               idx++;
+       }
+
+       /* The cpu_map array will be used later during initialization
+        * when EQ / CQ / WQs are allocated and configured.
+        */
        return;
 }
 
@@ -11331,24 +11594,43 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                                           mbx_sli4_parameters);
        phba->sli4_hba.extents_in_use = bf_get(cfg_ext, mbx_sli4_parameters);
        phba->sli4_hba.rpi_hdrs_in_use = bf_get(cfg_hdrr, mbx_sli4_parameters);
-       phba->nvme_support = (bf_get(cfg_nvme, mbx_sli4_parameters) &&
-                             bf_get(cfg_xib, mbx_sli4_parameters));
-
-       if ((phba->cfg_enable_fc4_type == LPFC_ENABLE_FCP) ||
-           !phba->nvme_support) {
-               phba->nvme_support = 0;
-               phba->nvmet_support = 0;
-               phba->cfg_nvmet_mrq = 0;
-               lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_NVME,
-                               "6101 Disabling NVME support: "
-                               "Not supported by firmware: %d %d\n",
-                               bf_get(cfg_nvme, mbx_sli4_parameters),
-                               bf_get(cfg_xib, mbx_sli4_parameters));
-
-               /* If firmware doesn't support NVME, just use SCSI support */
-               if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP))
-                       return -ENODEV;
-               phba->cfg_enable_fc4_type = LPFC_ENABLE_FCP;
+
+       /* Check for firmware nvme support */
+       rc = (bf_get(cfg_nvme, mbx_sli4_parameters) &&
+                    bf_get(cfg_xib, mbx_sli4_parameters));
+
+       if (rc) {
+               /* Save this to indicate the Firmware supports NVME */
+               sli4_params->nvme = 1;
+
+               /* Firmware NVME support, check driver FC4 NVME support */
+               if (phba->cfg_enable_fc4_type == LPFC_ENABLE_FCP) {
+                       lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_NVME,
+                                       "6133 Disabling NVME support: "
+                                       "FC4 type not supported: x%x\n",
+                                       phba->cfg_enable_fc4_type);
+                       goto fcponly;
+               }
+       } else {
+               /* No firmware NVME support, check driver FC4 NVME support */
+               sli4_params->nvme = 0;
+               if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_NVME,
+                                       "6101 Disabling NVME support: Not "
+                                       "supported by firmware (%d %d) x%x\n",
+                                       bf_get(cfg_nvme, mbx_sli4_parameters),
+                                       bf_get(cfg_xib, mbx_sli4_parameters),
+                                       phba->cfg_enable_fc4_type);
+fcponly:
+                       phba->nvme_support = 0;
+                       phba->nvmet_support = 0;
+                       phba->cfg_nvmet_mrq = 0;
+
+                       /* If no FC4 type support, move to just SCSI support */
+                       if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP))
+                               return -ENODEV;
+                       phba->cfg_enable_fc4_type = LPFC_ENABLE_FCP;
+               }
        }
 
        /* Only embed PBDE for if_type 6, PBDE support requires xib be set */
index fdd16d9..946642c 100644 (file)
@@ -2143,7 +2143,9 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport,
                           struct completion *lport_unreg_cmp)
 {
        u32 wait_tmo;
-       int ret;
+       int ret, i, pending = 0;
+       struct lpfc_sli_ring  *pring;
+       struct lpfc_hba  *phba = vport->phba;
 
        /* Host transport has to clean up and confirm requiring an indefinite
         * wait. Print a message if a 10 second wait expires and renew the
@@ -2153,10 +2155,18 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport,
        while (true) {
                ret = wait_for_completion_timeout(lport_unreg_cmp, wait_tmo);
                if (unlikely(!ret)) {
+                       pending = 0;
+                       for (i = 0; i < phba->cfg_hdw_queue; i++) {
+                               pring = phba->sli4_hba.hdwq[i].nvme_wq->pring;
+                               if (!pring)
+                                       continue;
+                               if (pring->txcmplq_cnt)
+                                       pending += pring->txcmplq_cnt;
+                       }
                        lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_IOERR,
                                         "6176 Lport %p Localport %p wait "
-                                        "timed out. Renewing.\n",
-                                        lport, vport->localport);
+                                        "timed out. Pending %d. Renewing.\n",
+                                        lport, vport->localport, pending);
                        continue;
                }
                break;
index 0617082..faa596f 100644 (file)
@@ -220,19 +220,68 @@ lpfc_nvmet_cmd_template(void)
        /* Word 12, 13, 14, 15 - is zero */
 }
 
+#if (IS_ENABLED(CONFIG_NVME_TARGET_FC))
+static struct lpfc_nvmet_rcv_ctx *
+lpfc_nvmet_get_ctx_for_xri(struct lpfc_hba *phba, u16 xri)
+{
+       struct lpfc_nvmet_rcv_ctx *ctxp;
+       unsigned long iflag;
+       bool found = false;
+
+       spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag);
+       list_for_each_entry(ctxp, &phba->sli4_hba.t_active_ctx_list, list) {
+               if (ctxp->ctxbuf->sglq->sli4_xritag != xri)
+                       continue;
+
+               found = true;
+               break;
+       }
+       spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag);
+       if (found)
+               return ctxp;
+
+       return NULL;
+}
+
+static struct lpfc_nvmet_rcv_ctx *
+lpfc_nvmet_get_ctx_for_oxid(struct lpfc_hba *phba, u16 oxid, u32 sid)
+{
+       struct lpfc_nvmet_rcv_ctx *ctxp;
+       unsigned long iflag;
+       bool found = false;
+
+       spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag);
+       list_for_each_entry(ctxp, &phba->sli4_hba.t_active_ctx_list, list) {
+               if (ctxp->oxid != oxid || ctxp->sid != sid)
+                       continue;
+
+               found = true;
+               break;
+       }
+       spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag);
+       if (found)
+               return ctxp;
+
+       return NULL;
+}
+#endif
+
 static void
 lpfc_nvmet_defer_release(struct lpfc_hba *phba, struct lpfc_nvmet_rcv_ctx *ctxp)
 {
        lockdep_assert_held(&ctxp->ctxlock);
 
        lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
-                       "6313 NVMET Defer ctx release xri x%x flg x%x\n",
+                       "6313 NVMET Defer ctx release oxid x%x flg x%x\n",
                        ctxp->oxid, ctxp->flag);
 
        if (ctxp->flag & LPFC_NVMET_CTX_RLS)
                return;
 
        ctxp->flag |= LPFC_NVMET_CTX_RLS;
+       spin_lock(&phba->sli4_hba.t_active_list_lock);
+       list_del(&ctxp->list);
+       spin_unlock(&phba->sli4_hba.t_active_list_lock);
        spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
        list_add_tail(&ctxp->list, &phba->sli4_hba.lpfc_abts_nvmet_ctx_list);
        spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
@@ -343,16 +392,23 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
        }
 
        if (ctxp->rqb_buffer) {
-               nvmebuf = ctxp->rqb_buffer;
                spin_lock_irqsave(&ctxp->ctxlock, iflag);
-               ctxp->rqb_buffer = NULL;
-               if (ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) {
-                       ctxp->flag &= ~LPFC_NVMET_CTX_REUSE_WQ;
-                       spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
-                       nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf);
+               nvmebuf = ctxp->rqb_buffer;
+               /* check if freed in another path whilst acquiring lock */
+               if (nvmebuf) {
+                       ctxp->rqb_buffer = NULL;
+                       if (ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) {
+                               ctxp->flag &= ~LPFC_NVMET_CTX_REUSE_WQ;
+                               spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
+                               nvmebuf->hrq->rqbp->rqb_free_buffer(phba,
+                                                                   nvmebuf);
+                       } else {
+                               spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
+                               /* repost */
+                               lpfc_rq_buf_free(phba, &nvmebuf->hbuf);
+                       }
                } else {
                        spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
-                       lpfc_rq_buf_free(phba, &nvmebuf->hbuf); /* repost */
                }
        }
        ctxp->state = LPFC_NVMET_STE_FREE;
@@ -388,8 +444,9 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
                spin_lock_init(&ctxp->ctxlock);
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-               if (ctxp->ts_cmd_nvme) {
-                       ctxp->ts_cmd_nvme = ktime_get_ns();
+               /* NOTE: isr time stamp is stale when context is re-assigned*/
+               if (ctxp->ts_isr_cmd) {
+                       ctxp->ts_cmd_nvme = 0;
                        ctxp->ts_nvme_data = 0;
                        ctxp->ts_data_wqput = 0;
                        ctxp->ts_isr_data = 0;
@@ -402,9 +459,7 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
 #endif
                atomic_inc(&tgtp->rcv_fcp_cmd_in);
 
-               /*  flag new work queued, replacement buffer has already
-                *  been reposted
-                */
+               /* Indicate that a replacement buffer has been posted */
                spin_lock_irqsave(&ctxp->ctxlock, iflag);
                ctxp->flag |= LPFC_NVMET_CTX_REUSE_WQ;
                spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
@@ -433,6 +488,9 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
         * Use the CPU context list, from the MRQ the IO was received on
         * (ctxp->idx), to save context structure.
         */
+       spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag);
+       list_del_init(&ctxp->list);
+       spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag);
        cpu = raw_smp_processor_id();
        infop = lpfc_get_ctx_list(phba, cpu, ctxp->idx);
        spin_lock_irqsave(&infop->nvmet_ctx_list_lock, iflag);
@@ -700,8 +758,10 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
                }
 
                lpfc_printf_log(phba, KERN_INFO, logerr,
-                               "6315 IO Error Cmpl xri x%x: %x/%x XBUSY:x%x\n",
-                               ctxp->oxid, status, result, ctxp->flag);
+                               "6315 IO Error Cmpl oxid: x%x xri: x%x %x/%x "
+                               "XBUSY:x%x\n",
+                               ctxp->oxid, ctxp->ctxbuf->sglq->sli4_xritag,
+                               status, result, ctxp->flag);
 
        } else {
                rsp->fcp_error = NVME_SC_SUCCESS;
@@ -849,7 +909,6 @@ lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport,
                 * before freeing ctxp and iocbq.
                 */
                lpfc_in_buf_free(phba, &nvmebuf->dbuf);
-               ctxp->rqb_buffer = 0;
                atomic_inc(&nvmep->xmt_ls_rsp);
                return 0;
        }
@@ -922,7 +981,7 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport,
            (ctxp->state == LPFC_NVMET_STE_ABORT)) {
                atomic_inc(&lpfc_nvmep->xmt_fcp_drop);
                lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
-                               "6102 IO xri x%x aborted\n",
+                               "6102 IO oxid x%x aborted\n",
                                ctxp->oxid);
                rc = -ENXIO;
                goto aerr;
@@ -1022,7 +1081,7 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport,
                ctxp->hdwq = &phba->sli4_hba.hdwq[0];
 
        lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
-                       "6103 NVMET Abort op: oxri x%x flg x%x ste %d\n",
+                       "6103 NVMET Abort op: oxid x%x flg x%x ste %d\n",
                        ctxp->oxid, ctxp->flag, ctxp->state);
 
        lpfc_nvmeio_data(phba, "NVMET FCP ABRT: xri x%x flg x%x ste x%x\n",
@@ -1035,7 +1094,7 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport,
        /* Since iaab/iaar are NOT set, we need to check
         * if the firmware is in process of aborting IO
         */
-       if (ctxp->flag & LPFC_NVMET_XBUSY) {
+       if (ctxp->flag & (LPFC_NVMET_XBUSY | LPFC_NVMET_ABORT_OP)) {
                spin_unlock_irqrestore(&ctxp->ctxlock, flags);
                return;
        }
@@ -1098,6 +1157,7 @@ lpfc_nvmet_xmt_fcp_release(struct nvmet_fc_target_port *tgtport,
                         ctxp->state, aborting);
 
        atomic_inc(&lpfc_nvmep->xmt_fcp_release);
+       ctxp->flag &= ~LPFC_NVMET_TNOTIFY;
 
        if (aborting)
                return;
@@ -1122,7 +1182,7 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport,
 
        if (!nvmebuf) {
                lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR,
-                               "6425 Defer rcv: no buffer xri x%x: "
+                               "6425 Defer rcv: no buffer oxid x%x: "
                                "flg %x ste %x\n",
                                ctxp->oxid, ctxp->flag, ctxp->state);
                return;
@@ -1514,10 +1574,12 @@ void
 lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba,
                            struct sli4_wcqe_xri_aborted *axri)
 {
+#if (IS_ENABLED(CONFIG_NVME_TARGET_FC))
        uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
        uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri);
        struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp;
        struct lpfc_nvmet_tgtport *tgtp;
+       struct nvmefc_tgt_fcp_req *req = NULL;
        struct lpfc_nodelist *ndlp;
        unsigned long iflag = 0;
        int rrq_empty = 0;
@@ -1548,7 +1610,7 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba,
                 */
                if (ctxp->flag & LPFC_NVMET_CTX_RLS &&
                    !(ctxp->flag & LPFC_NVMET_ABORT_OP)) {
-                       list_del(&ctxp->list);
+                       list_del_init(&ctxp->list);
                        released = true;
                }
                ctxp->flag &= ~LPFC_NVMET_XBUSY;
@@ -1568,7 +1630,7 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba,
                }
 
                lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
-                               "6318 XB aborted oxid %x flg x%x (%x)\n",
+                               "6318 XB aborted oxid x%x flg x%x (%x)\n",
                                ctxp->oxid, ctxp->flag, released);
                if (released)
                        lpfc_nvmet_ctxbuf_post(phba, ctxp->ctxbuf);
@@ -1579,6 +1641,33 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba,
        }
        spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
        spin_unlock_irqrestore(&phba->hbalock, iflag);
+
+       ctxp = lpfc_nvmet_get_ctx_for_xri(phba, xri);
+       if (ctxp) {
+               /*
+                *  Abort already done by FW, so BA_ACC sent.
+                *  However, the transport may be unaware.
+                */
+               lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
+                               "6323 NVMET Rcv ABTS xri x%x ctxp state x%x "
+                               "flag x%x oxid x%x rxid x%x\n",
+                               xri, ctxp->state, ctxp->flag, ctxp->oxid,
+                               rxid);
+
+               spin_lock_irqsave(&ctxp->ctxlock, iflag);
+               ctxp->flag |= LPFC_NVMET_ABTS_RCV;
+               ctxp->state = LPFC_NVMET_STE_ABORT;
+               spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
+
+               lpfc_nvmeio_data(phba,
+                                "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n",
+                                xri, raw_smp_processor_id(), 0);
+
+               req = &ctxp->ctx.fcp_req;
+               if (req)
+                       nvmet_fc_rcv_fcp_abort(phba->targetport, req);
+       }
+#endif
 }
 
 int
@@ -1589,19 +1678,23 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport,
        struct lpfc_hba *phba = vport->phba;
        struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp;
        struct nvmefc_tgt_fcp_req *rsp;
-       uint16_t xri;
+       uint32_t sid;
+       uint16_t oxid, xri;
        unsigned long iflag = 0;
 
-       xri = be16_to_cpu(fc_hdr->fh_ox_id);
+       sid = sli4_sid_from_fc_hdr(fc_hdr);
+       oxid = be16_to_cpu(fc_hdr->fh_ox_id);
 
        spin_lock_irqsave(&phba->hbalock, iflag);
        spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
        list_for_each_entry_safe(ctxp, next_ctxp,
                                 &phba->sli4_hba.lpfc_abts_nvmet_ctx_list,
                                 list) {
-               if (ctxp->ctxbuf->sglq->sli4_xritag != xri)
+               if (ctxp->oxid != oxid || ctxp->sid != sid)
                        continue;
 
+               xri = ctxp->ctxbuf->sglq->sli4_xritag;
+
                spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
                spin_unlock_irqrestore(&phba->hbalock, iflag);
 
@@ -1626,11 +1719,93 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport,
        spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
        spin_unlock_irqrestore(&phba->hbalock, iflag);
 
-       lpfc_nvmeio_data(phba, "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n",
-                        xri, raw_smp_processor_id(), 1);
+       /* check the wait list */
+       if (phba->sli4_hba.nvmet_io_wait_cnt) {
+               struct rqb_dmabuf *nvmebuf;
+               struct fc_frame_header *fc_hdr_tmp;
+               u32 sid_tmp;
+               u16 oxid_tmp;
+               bool found = false;
+
+               spin_lock_irqsave(&phba->sli4_hba.nvmet_io_wait_lock, iflag);
+
+               /* match by oxid and s_id */
+               list_for_each_entry(nvmebuf,
+                                   &phba->sli4_hba.lpfc_nvmet_io_wait_list,
+                                   hbuf.list) {
+                       fc_hdr_tmp = (struct fc_frame_header *)
+                                       (nvmebuf->hbuf.virt);
+                       oxid_tmp = be16_to_cpu(fc_hdr_tmp->fh_ox_id);
+                       sid_tmp = sli4_sid_from_fc_hdr(fc_hdr_tmp);
+                       if (oxid_tmp != oxid || sid_tmp != sid)
+                               continue;
+
+                       lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
+                                       "6321 NVMET Rcv ABTS oxid x%x from x%x "
+                                       "is waiting for a ctxp\n",
+                                       oxid, sid);
+
+                       list_del_init(&nvmebuf->hbuf.list);
+                       phba->sli4_hba.nvmet_io_wait_cnt--;
+                       found = true;
+                       break;
+               }
+               spin_unlock_irqrestore(&phba->sli4_hba.nvmet_io_wait_lock,
+                                      iflag);
+
+               /* free buffer since already posted a new DMA buffer to RQ */
+               if (found) {
+                       nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf);
+                       /* Respond with BA_ACC accordingly */
+                       lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 1);
+                       return 0;
+               }
+       }
+
+       /* check active list */
+       ctxp = lpfc_nvmet_get_ctx_for_oxid(phba, oxid, sid);
+       if (ctxp) {
+               xri = ctxp->ctxbuf->sglq->sli4_xritag;
+
+               spin_lock_irqsave(&ctxp->ctxlock, iflag);
+               ctxp->flag |= (LPFC_NVMET_ABTS_RCV | LPFC_NVMET_ABORT_OP);
+               spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
+
+               lpfc_nvmeio_data(phba,
+                                "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n",
+                                xri, raw_smp_processor_id(), 0);
+
+               lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
+                               "6322 NVMET Rcv ABTS:acc oxid x%x xri x%x "
+                               "flag x%x state x%x\n",
+                               ctxp->oxid, xri, ctxp->flag, ctxp->state);
+
+               if (ctxp->flag & LPFC_NVMET_TNOTIFY) {
+                       /* Notify the transport */
+                       nvmet_fc_rcv_fcp_abort(phba->targetport,
+                                              &ctxp->ctx.fcp_req);
+               } else {
+                       cancel_work_sync(&ctxp->ctxbuf->defer_work);
+                       spin_lock_irqsave(&ctxp->ctxlock, iflag);
+                       lpfc_nvmet_defer_release(phba, ctxp);
+                       spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
+               }
+               if (ctxp->state == LPFC_NVMET_STE_RCV)
+                       lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, ctxp->sid,
+                                                        ctxp->oxid);
+               else
+                       lpfc_nvmet_sol_fcp_issue_abort(phba, ctxp, ctxp->sid,
+                                                      ctxp->oxid);
+
+               lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 1);
+               return 0;
+       }
+
+       lpfc_nvmeio_data(phba, "NVMET ABTS RCV: oxid x%x CPU %02x rjt %d\n",
+                        oxid, raw_smp_processor_id(), 1);
 
        lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
-                       "6320 NVMET Rcv ABTS:rjt xri x%x\n", xri);
+                       "6320 NVMET Rcv ABTS:rjt oxid x%x\n", oxid);
 
        /* Respond with BA_RJT accordingly */
        lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 0);
@@ -1714,6 +1889,18 @@ lpfc_nvmet_wqfull_process(struct lpfc_hba *phba,
                        spin_unlock_irqrestore(&pring->ring_lock, iflags);
                        return;
                }
+               if (rc == WQE_SUCCESS) {
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+                       if (ctxp->ts_cmd_nvme) {
+                               if (ctxp->ctx.fcp_req.op == NVMET_FCOP_RSP)
+                                       ctxp->ts_status_wqput = ktime_get_ns();
+                               else
+                                       ctxp->ts_data_wqput = ktime_get_ns();
+                       }
+#endif
+               } else {
+                       WARN_ON(rc);
+               }
        }
        wq->q_flag &= ~HBA_NVMET_WQFULL;
        spin_unlock_irqrestore(&pring->ring_lock, iflags);
@@ -1879,8 +2066,20 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf)
                return;
        }
 
+       if (ctxp->flag & LPFC_NVMET_ABTS_RCV) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
+                               "6324 IO oxid x%x aborted\n",
+                               ctxp->oxid);
+               return;
+       }
+
        payload = (uint32_t *)(nvmebuf->dbuf.virt);
        tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
+       ctxp->flag |= LPFC_NVMET_TNOTIFY;
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       if (ctxp->ts_isr_cmd)
+               ctxp->ts_cmd_nvme = ktime_get_ns();
+#endif
        /*
         * The calling sequence should be:
         * nvmet_fc_rcv_fcp_req->lpfc_nvmet_xmt_fcp_op/cmp- req->done
@@ -1930,6 +2129,7 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf)
                        phba->sli4_hba.nvmet_mrq_data[qno], 1, qno);
                return;
        }
+       ctxp->flag &= ~LPFC_NVMET_TNOTIFY;
        atomic_inc(&tgtp->rcv_fcp_cmd_drop);
        lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
                        "2582 FCP Drop IO x%x: err x%x: x%x x%x x%x\n",
@@ -2019,6 +2219,8 @@ lpfc_nvmet_replenish_context(struct lpfc_hba *phba,
  * @phba: pointer to lpfc hba data structure.
  * @idx: relative index of MRQ vector
  * @nvmebuf: pointer to lpfc nvme command HBQ data structure.
+ * @isr_timestamp: in jiffies.
+ * @cqflag: cq processing information regarding workload.
  *
  * This routine is used for processing the WQE associated with a unsolicited
  * event. It first determines whether there is an existing ndlp that matches
@@ -2031,7 +2233,8 @@ static void
 lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
                            uint32_t idx,
                            struct rqb_dmabuf *nvmebuf,
-                           uint64_t isr_timestamp)
+                           uint64_t isr_timestamp,
+                           uint8_t cqflag)
 {
        struct lpfc_nvmet_rcv_ctx *ctxp;
        struct lpfc_nvmet_tgtport *tgtp;
@@ -2118,6 +2321,9 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
        sid = sli4_sid_from_fc_hdr(fc_hdr);
 
        ctxp = (struct lpfc_nvmet_rcv_ctx *)ctx_buf->context;
+       spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag);
+       list_add_tail(&ctxp->list, &phba->sli4_hba.t_active_ctx_list);
+       spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag);
        if (ctxp->state != LPFC_NVMET_STE_FREE) {
                lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
                                "6414 NVMET Context corrupt %d %d oxid x%x\n",
@@ -2140,24 +2346,41 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
        spin_lock_init(&ctxp->ctxlock);
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-       if (isr_timestamp) {
+       if (isr_timestamp)
                ctxp->ts_isr_cmd = isr_timestamp;
-               ctxp->ts_cmd_nvme = ktime_get_ns();
-               ctxp->ts_nvme_data = 0;
-               ctxp->ts_data_wqput = 0;
-               ctxp->ts_isr_data = 0;
-               ctxp->ts_data_nvme = 0;
-               ctxp->ts_nvme_status = 0;
-               ctxp->ts_status_wqput = 0;
-               ctxp->ts_isr_status = 0;
-               ctxp->ts_status_nvme = 0;
-       } else {
-               ctxp->ts_cmd_nvme = 0;
-       }
+       ctxp->ts_cmd_nvme = 0;
+       ctxp->ts_nvme_data = 0;
+       ctxp->ts_data_wqput = 0;
+       ctxp->ts_isr_data = 0;
+       ctxp->ts_data_nvme = 0;
+       ctxp->ts_nvme_status = 0;
+       ctxp->ts_status_wqput = 0;
+       ctxp->ts_isr_status = 0;
+       ctxp->ts_status_nvme = 0;
 #endif
 
        atomic_inc(&tgtp->rcv_fcp_cmd_in);
-       lpfc_nvmet_process_rcv_fcp_req(ctx_buf);
+       /* check for cq processing load */
+       if (!cqflag) {
+               lpfc_nvmet_process_rcv_fcp_req(ctx_buf);
+               return;
+       }
+
+       if (!queue_work(phba->wq, &ctx_buf->defer_work)) {
+               atomic_inc(&tgtp->rcv_fcp_cmd_drop);
+               lpfc_printf_log(phba, KERN_ERR, LOG_NVME,
+                               "6325 Unable to queue work for oxid x%x. "
+                               "FCP Drop IO [x%x x%x x%x]\n",
+                               ctxp->oxid,
+                               atomic_read(&tgtp->rcv_fcp_cmd_in),
+                               atomic_read(&tgtp->rcv_fcp_cmd_out),
+                               atomic_read(&tgtp->xmt_fcp_release));
+
+               spin_lock_irqsave(&ctxp->ctxlock, iflag);
+               lpfc_nvmet_defer_release(phba, ctxp);
+               spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
+               lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, sid, oxid);
+       }
 }
 
 /**
@@ -2194,6 +2417,8 @@ lpfc_nvmet_unsol_ls_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
  * @phba: pointer to lpfc hba data structure.
  * @idx: relative index of MRQ vector
  * @nvmebuf: pointer to received nvme data structure.
+ * @isr_timestamp: in jiffies.
+ * @cqflag: cq processing information regarding workload.
  *
  * This routine is used to process an unsolicited event received from a SLI
  * (Service Level Interface) ring. The actual processing of the data buffer
@@ -2205,14 +2430,14 @@ void
 lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba,
                           uint32_t idx,
                           struct rqb_dmabuf *nvmebuf,
-                          uint64_t isr_timestamp)
+                          uint64_t isr_timestamp,
+                          uint8_t cqflag)
 {
        if (phba->nvmet_support == 0) {
                lpfc_rq_buf_free(phba, &nvmebuf->hbuf);
                return;
        }
-       lpfc_nvmet_unsol_fcp_buffer(phba, idx, nvmebuf,
-                                   isr_timestamp);
+       lpfc_nvmet_unsol_fcp_buffer(phba, idx, nvmebuf, isr_timestamp, cqflag);
 }
 
 /**
@@ -2679,8 +2904,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
        nvmewqe->drvrTimeout = (phba->fc_ratov * 3) + LPFC_DRVR_TIMEOUT;
        nvmewqe->context1 = ndlp;
 
-       for (i = 0; i < rsp->sg_cnt; i++) {
-               sgel = &rsp->sg[i];
+       for_each_sg(rsp->sg, sgel, rsp->sg_cnt, i) {
                physaddr = sg_dma_address(sgel);
                cnt = sg_dma_len(sgel);
                sgl->addr_hi = putPaddrHigh(physaddr);
@@ -2750,7 +2974,7 @@ lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
        if ((ctxp->flag & LPFC_NVMET_CTX_RLS) &&
            !(ctxp->flag & LPFC_NVMET_XBUSY)) {
                spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
-               list_del(&ctxp->list);
+               list_del_init(&ctxp->list);
                spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
                released = true;
        }
@@ -2759,7 +2983,7 @@ lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
        atomic_inc(&tgtp->xmt_abort_rsp);
 
        lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
-                       "6165 ABORT cmpl: xri x%x flg x%x (%d) "
+                       "6165 ABORT cmpl: oxid x%x flg x%x (%d) "
                        "WCQE: %08x %08x %08x %08x\n",
                        ctxp->oxid, ctxp->flag, released,
                        wcqe->word0, wcqe->total_data_placed,
@@ -2834,7 +3058,7 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
        if ((ctxp->flag & LPFC_NVMET_CTX_RLS) &&
            !(ctxp->flag & LPFC_NVMET_XBUSY)) {
                spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
-               list_del(&ctxp->list);
+               list_del_init(&ctxp->list);
                spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
                released = true;
        }
@@ -2843,7 +3067,7 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
        atomic_inc(&tgtp->xmt_abort_rsp);
 
        lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
-                       "6316 ABTS cmpl xri x%x flg x%x (%x) "
+                       "6316 ABTS cmpl oxid x%x flg x%x (%x) "
                        "WCQE: %08x %08x %08x %08x\n",
                        ctxp->oxid, ctxp->flag, released,
                        wcqe->word0, wcqe->total_data_placed,
@@ -3214,7 +3438,7 @@ aerr:
        spin_lock_irqsave(&ctxp->ctxlock, flags);
        if (ctxp->flag & LPFC_NVMET_CTX_RLS) {
                spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
-               list_del(&ctxp->list);
+               list_del_init(&ctxp->list);
                spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
                released = true;
        }
@@ -3223,8 +3447,9 @@ aerr:
 
        atomic_inc(&tgtp->xmt_abort_rsp_error);
        lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS,
-                       "6135 Failed to Issue ABTS for oxid x%x. Status x%x\n",
-                       ctxp->oxid, rc);
+                       "6135 Failed to Issue ABTS for oxid x%x. Status x%x "
+                       "(%x)\n",
+                       ctxp->oxid, rc, released);
        if (released)
                lpfc_nvmet_ctxbuf_post(phba, ctxp->ctxbuf);
        return 1;
index 2f3f603..8ff67de 100644 (file)
@@ -140,6 +140,7 @@ struct lpfc_nvmet_rcv_ctx {
 #define LPFC_NVMET_ABTS_RCV            0x10  /* ABTS received on exchange */
 #define LPFC_NVMET_CTX_REUSE_WQ                0x20  /* ctx reused via WQ */
 #define LPFC_NVMET_DEFER_WQFULL                0x40  /* Waiting on a free WQE */
+#define LPFC_NVMET_TNOTIFY             0x80  /* notify transport of abts */
        struct rqb_dmabuf *rqb_buffer;
        struct lpfc_nvmet_ctxbuf *ctxbuf;
        struct lpfc_sli4_hdw_queue *hdwq;
index ba996fb..f9df800 100644 (file)
@@ -3879,10 +3879,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
         */
        spin_lock(&lpfc_cmd->buf_lock);
        lpfc_cmd->cur_iocbq.iocb_flag &= ~LPFC_DRIVER_ABORTED;
-       if (lpfc_cmd->waitq) {
+       if (lpfc_cmd->waitq)
                wake_up(lpfc_cmd->waitq);
-               lpfc_cmd->waitq = NULL;
-       }
        spin_unlock(&lpfc_cmd->buf_lock);
 
        lpfc_release_scsi_buf(phba, lpfc_cmd);
@@ -4718,6 +4716,9 @@ wait_for_cmpl:
                                 iocb->sli4_xritag, ret,
                                 cmnd->device->id, cmnd->device->lun);
        }
+
+       lpfc_cmd->waitq = NULL;
+
        spin_unlock(&lpfc_cmd->buf_lock);
        goto out;
 
@@ -4797,7 +4798,12 @@ lpfc_check_fcp_rsp(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd)
                                 rsp_info,
                                 rsp_len, rsp_info_code);
 
-               if ((fcprsp->rspStatus2&RSP_LEN_VALID) && (rsp_len == 8)) {
+               /* If FCP_RSP_LEN_VALID bit is one, then the FCP_RSP_LEN
+                * field specifies the number of valid bytes of FCP_RSP_INFO.
+                * The FCP_RSP_LEN field shall be set to 0x04 or 0x08
+                */
+               if ((fcprsp->rspStatus2 & RSP_LEN_VALID) &&
+                   ((rsp_len == 8) || (rsp_len == 4))) {
                        switch (rsp_info_code) {
                        case RSP_NO_FAILURE:
                                lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
@@ -5741,7 +5747,7 @@ lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
 
        /* Create an lun info structure and add to list of luns */
        lun_info = lpfc_create_device_data(phba, vport_wwpn, target_wwpn, lun,
-                                          pri, false);
+                                          pri, true);
        if (lun_info) {
                lun_info->oas_enabled = true;
                lun_info->priority = pri;
index 4329cc4..f9e6a13 100644 (file)
@@ -108,7 +108,7 @@ lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq)
  * endianness. This function can be called with or without
  * lock.
  **/
-void
+static void
 lpfc_sli4_pcimem_bcopy(void *srcp, void *destp, uint32_t cnt)
 {
        uint64_t *src = srcp;
@@ -5571,6 +5571,7 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)
        int qidx;
        struct lpfc_sli4_hba *sli4_hba = &phba->sli4_hba;
        struct lpfc_sli4_hdw_queue *qp;
+       struct lpfc_queue *eq;
 
        sli4_hba->sli4_write_cq_db(phba, sli4_hba->mbx_cq, 0, LPFC_QUEUE_REARM);
        sli4_hba->sli4_write_cq_db(phba, sli4_hba->els_cq, 0, LPFC_QUEUE_REARM);
@@ -5578,18 +5579,24 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)
                sli4_hba->sli4_write_cq_db(phba, sli4_hba->nvmels_cq, 0,
                                           LPFC_QUEUE_REARM);
 
-       qp = sli4_hba->hdwq;
        if (sli4_hba->hdwq) {
+               /* Loop thru all Hardware Queues */
                for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
-                       sli4_hba->sli4_write_cq_db(phba, qp[qidx].fcp_cq, 0,
+                       qp = &sli4_hba->hdwq[qidx];
+                       /* ARM the corresponding CQ */
+                       sli4_hba->sli4_write_cq_db(phba, qp->fcp_cq, 0,
                                                   LPFC_QUEUE_REARM);
-                       sli4_hba->sli4_write_cq_db(phba, qp[qidx].nvme_cq, 0,
+                       sli4_hba->sli4_write_cq_db(phba, qp->nvme_cq, 0,
                                                   LPFC_QUEUE_REARM);
                }
 
-               for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++)
-                       sli4_hba->sli4_write_eq_db(phba, qp[qidx].hba_eq,
-                                               0, LPFC_QUEUE_REARM);
+               /* Loop thru all IRQ vectors */
+               for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) {
+                       eq = sli4_hba->hba_eq_hdl[qidx].eq;
+                       /* ARM the corresponding EQ */
+                       sli4_hba->sli4_write_eq_db(phba, eq,
+                                                  0, LPFC_QUEUE_REARM);
+               }
        }
 
        if (phba->nvmet_support) {
@@ -7875,26 +7882,28 @@ lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba)
  * and will process all the completions associated with the eq for the
  * mailbox completion queue.
  **/
-bool
+static bool
 lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba)
 {
        struct lpfc_sli4_hba *sli4_hba = &phba->sli4_hba;
        uint32_t eqidx;
        struct lpfc_queue *fpeq = NULL;
+       struct lpfc_queue *eq;
        bool mbox_pending;
 
        if (unlikely(!phba) || (phba->sli_rev != LPFC_SLI_REV4))
                return false;
 
-       /* Find the eq associated with the mcq */
-
-       if (sli4_hba->hdwq)
-               for (eqidx = 0; eqidx < phba->cfg_irq_chann; eqidx++)
-                       if (sli4_hba->hdwq[eqidx].hba_eq->queue_id ==
-                           sli4_hba->mbx_cq->assoc_qid) {
-                               fpeq = sli4_hba->hdwq[eqidx].hba_eq;
+       /* Find the EQ associated with the mbox CQ */
+       if (sli4_hba->hdwq) {
+               for (eqidx = 0; eqidx < phba->cfg_irq_chann; eqidx++) {
+                       eq = phba->sli4_hba.hba_eq_hdl[eqidx].eq;
+                       if (eq->queue_id == sli4_hba->mbx_cq->assoc_qid) {
+                               fpeq = eq;
                                break;
                        }
+               }
+       }
        if (!fpeq)
                return false;
 
@@ -13605,14 +13614,9 @@ __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq,
                goto rearm_and_exit;
 
        /* Process all the entries to the CQ */
+       cq->q_flag = 0;
        cqe = lpfc_sli4_cq_get(cq);
        while (cqe) {
-#if defined(CONFIG_SCSI_LPFC_DEBUG_FS) && defined(BUILD_NVME)
-               if (phba->ktime_on)
-                       cq->isr_timestamp = ktime_get_ns();
-               else
-                       cq->isr_timestamp = 0;
-#endif
                workposted |= handler(phba, cq, cqe);
                __lpfc_sli4_consume_cqe(phba, cq, cqe);
 
@@ -13626,6 +13630,9 @@ __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq,
                        consumed = 0;
                }
 
+               if (count == LPFC_NVMET_CQ_NOTIFY)
+                       cq->q_flag |= HBA_NVMET_CQ_NOTIFY;
+
                cqe = lpfc_sli4_cq_get(cq);
        }
        if (count >= phba->cfg_cq_poll_threshold) {
@@ -13941,10 +13948,10 @@ lpfc_sli4_nvmet_handle_rcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
                        goto drop;
 
                if (fc_hdr->fh_type == FC_TYPE_FCP) {
-                       dma_buf->bytes_recv = bf_get(lpfc_rcqe_length,  rcqe);
+                       dma_buf->bytes_recv = bf_get(lpfc_rcqe_length, rcqe);
                        lpfc_nvmet_unsol_fcp_event(
-                               phba, idx, dma_buf,
-                               cq->isr_timestamp);
+                               phba, idx, dma_buf, cq->isr_timestamp,
+                               cq->q_flag & HBA_NVMET_CQ_NOTIFY);
                        return false;
                }
 drop:
@@ -14110,6 +14117,12 @@ process_cq:
        }
 
 work_cq:
+#if defined(CONFIG_SCSI_LPFC_DEBUG_FS)
+       if (phba->ktime_on)
+               cq->isr_timestamp = ktime_get_ns();
+       else
+               cq->isr_timestamp = 0;
+#endif
        if (!queue_work_on(cq->chann, phba->wq, &cq->irqwork))
                lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
                                "0363 Cannot schedule soft IRQ "
@@ -14236,7 +14249,7 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id)
                return IRQ_NONE;
 
        /* Get to the EQ struct associated with this vector */
-       fpeq = phba->sli4_hba.hdwq[hba_eqidx].hba_eq;
+       fpeq = phba->sli4_hba.hba_eq_hdl[hba_eqidx].eq;
        if (unlikely(!fpeq))
                return IRQ_NONE;
 
@@ -14521,7 +14534,7 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq,
        /* set values by EQ_DELAY register if supported */
        if (phba->sli.sli_flag & LPFC_SLI_USE_EQDR) {
                for (qidx = startq; qidx < phba->cfg_irq_chann; qidx++) {
-                       eq = phba->sli4_hba.hdwq[qidx].hba_eq;
+                       eq = phba->sli4_hba.hba_eq_hdl[qidx].eq;
                        if (!eq)
                                continue;
 
@@ -14530,7 +14543,6 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq,
                        if (++cnt >= numq)
                                break;
                }
-
                return;
        }
 
@@ -14558,7 +14570,7 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq,
                dmult = LPFC_DMULT_MAX;
 
        for (qidx = startq; qidx < phba->cfg_irq_chann; qidx++) {
-               eq = phba->sli4_hba.hdwq[qidx].hba_eq;
+               eq = phba->sli4_hba.hba_eq_hdl[qidx].eq;
                if (!eq)
                        continue;
                eq->q_mode = usdelay;
@@ -14660,8 +14672,10 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax)
                lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
                                "0360 Unsupported EQ count. (%d)\n",
                                eq->entry_count);
-               if (eq->entry_count < 256)
-                       return -EINVAL;
+               if (eq->entry_count < 256) {
+                       status = -EINVAL;
+                       goto out;
+               }
                /* fall through - otherwise default to smallest count */
        case 256:
                bf_set(lpfc_eq_context_count, &eq_create->u.request.context,
@@ -14713,7 +14727,7 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax)
        eq->host_index = 0;
        eq->notify_interval = LPFC_EQ_NOTIFY_INTRVL;
        eq->max_proc_limit = LPFC_EQ_MAX_PROC_LIMIT;
-
+out:
        mempool_free(mbox, phba->mbox_mem_pool);
        return status;
 }
index 8e4fd1a..3aeca38 100644 (file)
@@ -197,6 +197,8 @@ struct lpfc_queue {
 #define LPFC_DB_LIST_FORMAT    0x02
        uint8_t q_flag;
 #define HBA_NVMET_WQFULL       0x1 /* We hit WQ Full condition for NVMET */
+#define HBA_NVMET_CQ_NOTIFY    0x1 /* LPFC_NVMET_CQ_NOTIFY CQEs this EQE */
+#define LPFC_NVMET_CQ_NOTIFY   4
        void __iomem *db_regaddr;
        uint16_t dpp_enable;
        uint16_t dpp_id;
@@ -450,6 +452,7 @@ struct lpfc_hba_eq_hdl {
        uint32_t idx;
        char handler_name[LPFC_SLI4_HANDLER_NAME_SZ];
        struct lpfc_hba *phba;
+       struct lpfc_queue *eq;
 };
 
 /*BB Credit recovery value*/
@@ -512,6 +515,7 @@ struct lpfc_pc_sli4_params {
 #define LPFC_WQ_SZ64_SUPPORT   1
 #define LPFC_WQ_SZ128_SUPPORT  2
        uint8_t wqpcnt;
+       uint8_t nvme;
 };
 
 #define LPFC_CQ_4K_PAGE_SZ     0x1
@@ -546,7 +550,10 @@ struct lpfc_vector_map_info {
        uint16_t        irq;
        uint16_t        eq;
        uint16_t        hdwq;
-       uint16_t        hyper;
+       uint16_t        flag;
+#define LPFC_CPU_MAP_HYPER     0x1
+#define LPFC_CPU_MAP_UNASSIGN  0x2
+#define LPFC_CPU_FIRST_IRQ     0x4
 };
 #define LPFC_VECTOR_MAP_EMPTY  0xffff
 
@@ -843,6 +850,8 @@ struct lpfc_sli4_hba {
        struct list_head lpfc_nvmet_sgl_list;
        spinlock_t abts_nvmet_buf_list_lock; /* list of aborted NVMET IOs */
        struct list_head lpfc_abts_nvmet_ctx_list;
+       spinlock_t t_active_list_lock; /* list of active NVMET IOs */
+       struct list_head t_active_ctx_list;
        struct list_head lpfc_nvmet_io_wait_list;
        struct lpfc_nvmet_ctx_info *nvmet_ctx_info;
        struct lpfc_sglq **lpfc_sglq_active_list;
index 220a932..f7e93aa 100644 (file)
@@ -20,7 +20,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "12.2.0.2"
+#define LPFC_DRIVER_VERSION "12.2.0.3"
 #define LPFC_DRIVER_NAME               "lpfc"
 
 /* Used for SLI 2/3 */
index dba9517..9c55662 100644 (file)
@@ -4,6 +4,8 @@
  *
  * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>
  *
+ * Copyright 2019 Finn Thain
+ *
  * derived in part from:
  */
 /*
@@ -12,6 +14,7 @@
  * Copyright 1995, Russell King
  */
 
+#include <linux/delay.h>
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
@@ -22,6 +25,7 @@
 
 #include <asm/hwtest.h>
 #include <asm/io.h>
+#include <asm/macintosh.h>
 #include <asm/macints.h>
 #include <asm/setup.h>
 
@@ -53,7 +57,7 @@ static int setup_cmd_per_lun = -1;
 module_param(setup_cmd_per_lun, int, 0);
 static int setup_sg_tablesize = -1;
 module_param(setup_sg_tablesize, int, 0);
-static int setup_use_pdma = -1;
+static int setup_use_pdma = 512;
 module_param(setup_use_pdma, int, 0);
 static int setup_hostid = -1;
 module_param(setup_hostid, int, 0);
@@ -90,223 +94,318 @@ static int __init mac_scsi_setup(char *str)
 __setup("mac5380=", mac_scsi_setup);
 #endif /* !MODULE */
 
-/* Pseudo DMA asm originally by Ove Edlund */
-
-#define CP_IO_TO_MEM(s,d,n)                            \
-__asm__ __volatile__                                   \
-    ("    cmp.w  #4,%2\n"                              \
-     "    bls    8f\n"                                 \
-     "    move.w %1,%%d0\n"                            \
-     "    neg.b  %%d0\n"                               \
-     "    and.w  #3,%%d0\n"                            \
-     "    sub.w  %%d0,%2\n"                            \
-     "    bra    2f\n"                                 \
-     " 1: move.b (%0),(%1)+\n"                         \
-     " 2: dbf    %%d0,1b\n"                            \
-     "    move.w %2,%%d0\n"                            \
-     "    lsr.w  #5,%%d0\n"                            \
-     "    bra    4f\n"                                 \
-     " 3: move.l (%0),(%1)+\n"                         \
-     "31: move.l (%0),(%1)+\n"                         \
-     "32: move.l (%0),(%1)+\n"                         \
-     "33: move.l (%0),(%1)+\n"                         \
-     "34: move.l (%0),(%1)+\n"                         \
-     "35: move.l (%0),(%1)+\n"                         \
-     "36: move.l (%0),(%1)+\n"                         \
-     "37: move.l (%0),(%1)+\n"                         \
-     " 4: dbf    %%d0,3b\n"                            \
-     "    move.w %2,%%d0\n"                            \
-     "    lsr.w  #2,%%d0\n"                            \
-     "    and.w  #7,%%d0\n"                            \
-     "    bra    6f\n"                                 \
-     " 5: move.l (%0),(%1)+\n"                         \
-     " 6: dbf    %%d0,5b\n"                            \
-     "    and.w  #3,%2\n"                              \
-     "    bra    8f\n"                                 \
-     " 7: move.b (%0),(%1)+\n"                         \
-     " 8: dbf    %2,7b\n"                              \
-     "    moveq.l #0, %2\n"                            \
-     " 9: \n"                                          \
-     ".section .fixup,\"ax\"\n"                                \
-     "    .even\n"                                     \
-     "91: moveq.l #1, %2\n"                            \
-     "    jra 9b\n"                                    \
-     "94: moveq.l #4, %2\n"                            \
-     "    jra 9b\n"                                    \
-     ".previous\n"                                     \
-     ".section __ex_table,\"a\"\n"                     \
-     "   .align 4\n"                                   \
-     "   .long  1b,91b\n"                              \
-     "   .long  3b,94b\n"                              \
-     "   .long 31b,94b\n"                              \
-     "   .long 32b,94b\n"                              \
-     "   .long 33b,94b\n"                              \
-     "   .long 34b,94b\n"                              \
-     "   .long 35b,94b\n"                              \
-     "   .long 36b,94b\n"                              \
-     "   .long 37b,94b\n"                              \
-     "   .long  5b,94b\n"                              \
-     "   .long  7b,91b\n"                              \
-     ".previous"                                       \
-     : "=a"(s), "=a"(d), "=d"(n)                       \
-     : "0"(s), "1"(d), "2"(n)                          \
-     : "d0")
+/*
+ * According to "Inside Macintosh: Devices", Mac OS requires disk drivers to
+ * specify the number of bytes between the delays expected from a SCSI target.
+ * This allows the operating system to "prevent bus errors when a target fails
+ * to deliver the next byte within the processor bus error timeout period."
+ * Linux SCSI drivers lack knowledge of the timing behaviour of SCSI targets
+ * so bus errors are unavoidable.
+ *
+ * If a MOVE.B instruction faults, we assume that zero bytes were transferred
+ * and simply retry. That assumption probably depends on target behaviour but
+ * seems to hold up okay. The NOP provides synchronization: without it the
+ * fault can sometimes occur after the program counter has moved past the
+ * offending instruction. Post-increment addressing can't be used.
+ */
+
+#define MOVE_BYTE(operands) \
+       asm volatile ( \
+               "1:     moveb " operands "     \n" \
+               "11:    nop                    \n" \
+               "       addq #1,%0             \n" \
+               "       subq #1,%1             \n" \
+               "40:                           \n" \
+               "                              \n" \
+               ".section .fixup,\"ax\"        \n" \
+               ".even                         \n" \
+               "90:    movel #1, %2           \n" \
+               "       jra 40b                \n" \
+               ".previous                     \n" \
+               "                              \n" \
+               ".section __ex_table,\"a\"     \n" \
+               ".align  4                     \n" \
+               ".long   1b,90b                \n" \
+               ".long  11b,90b                \n" \
+               ".previous                     \n" \
+               : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
+
+/*
+ * If a MOVE.W (or MOVE.L) instruction faults, it cannot be retried because
+ * the residual byte count would be uncertain. In that situation the MOVE_WORD
+ * macro clears n in the fixup section to abort the transfer.
+ */
+
+#define MOVE_WORD(operands) \
+       asm volatile ( \
+               "1:     movew " operands "     \n" \
+               "11:    nop                    \n" \
+               "       subq #2,%1             \n" \
+               "40:                           \n" \
+               "                              \n" \
+               ".section .fixup,\"ax\"        \n" \
+               ".even                         \n" \
+               "90:    movel #0, %1           \n" \
+               "       movel #2, %2           \n" \
+               "       jra 40b                \n" \
+               ".previous                     \n" \
+               "                              \n" \
+               ".section __ex_table,\"a\"     \n" \
+               ".align  4                     \n" \
+               ".long   1b,90b                \n" \
+               ".long  11b,90b                \n" \
+               ".previous                     \n" \
+               : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
+
+#define MOVE_16_WORDS(operands) \
+       asm volatile ( \
+               "1:     movew " operands "     \n" \
+               "2:     movew " operands "     \n" \
+               "3:     movew " operands "     \n" \
+               "4:     movew " operands "     \n" \
+               "5:     movew " operands "     \n" \
+               "6:     movew " operands "     \n" \
+               "7:     movew " operands "     \n" \
+               "8:     movew " operands "     \n" \
+               "9:     movew " operands "     \n" \
+               "10:    movew " operands "     \n" \
+               "11:    movew " operands "     \n" \
+               "12:    movew " operands "     \n" \
+               "13:    movew " operands "     \n" \
+               "14:    movew " operands "     \n" \
+               "15:    movew " operands "     \n" \
+               "16:    movew " operands "     \n" \
+               "17:    nop                    \n" \
+               "       subl  #32,%1           \n" \
+               "40:                           \n" \
+               "                              \n" \
+               ".section .fixup,\"ax\"        \n" \
+               ".even                         \n" \
+               "90:    movel #0, %1           \n" \
+               "       movel #2, %2           \n" \
+               "       jra 40b                \n" \
+               ".previous                     \n" \
+               "                              \n" \
+               ".section __ex_table,\"a\"     \n" \
+               ".align  4                     \n" \
+               ".long   1b,90b                \n" \
+               ".long   2b,90b                \n" \
+               ".long   3b,90b                \n" \
+               ".long   4b,90b                \n" \
+               ".long   5b,90b                \n" \
+               ".long   6b,90b                \n" \
+               ".long   7b,90b                \n" \
+               ".long   8b,90b                \n" \
+               ".long   9b,90b                \n" \
+               ".long  10b,90b                \n" \
+               ".long  11b,90b                \n" \
+               ".long  12b,90b                \n" \
+               ".long  13b,90b                \n" \
+               ".long  14b,90b                \n" \
+               ".long  15b,90b                \n" \
+               ".long  16b,90b                \n" \
+               ".long  17b,90b                \n" \
+               ".previous                     \n" \
+               : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
+
+#define MAC_PDMA_DELAY         32
+
+static inline int mac_pdma_recv(void __iomem *io, unsigned char *start, int n)
+{
+       unsigned char *addr = start;
+       int result = 0;
+
+       if (n >= 1) {
+               MOVE_BYTE("%3@,%0@");
+               if (result)
+                       goto out;
+       }
+       if (n >= 1 && ((unsigned long)addr & 1)) {
+               MOVE_BYTE("%3@,%0@");
+               if (result)
+                       goto out;
+       }
+       while (n >= 32)
+               MOVE_16_WORDS("%3@,%0@+");
+       while (n >= 2)
+               MOVE_WORD("%3@,%0@+");
+       if (result)
+               return start - addr; /* Negated to indicate uncertain length */
+       if (n == 1)
+               MOVE_BYTE("%3@,%0@");
+out:
+       return addr - start;
+}
+
+static inline int mac_pdma_send(unsigned char *start, void __iomem *io, int n)
+{
+       unsigned char *addr = start;
+       int result = 0;
+
+       if (n >= 1) {
+               MOVE_BYTE("%0@,%3@");
+               if (result)
+                       goto out;
+       }
+       if (n >= 1 && ((unsigned long)addr & 1)) {
+               MOVE_BYTE("%0@,%3@");
+               if (result)
+                       goto out;
+       }
+       while (n >= 32)
+               MOVE_16_WORDS("%0@+,%3@");
+       while (n >= 2)
+               MOVE_WORD("%0@+,%3@");
+       if (result)
+               return start - addr; /* Negated to indicate uncertain length */
+       if (n == 1)
+               MOVE_BYTE("%0@,%3@");
+out:
+       return addr - start;
+}
+
+/* The "SCSI DMA" chip on the IIfx implements this register. */
+#define CTRL_REG                0x8
+#define CTRL_INTERRUPTS_ENABLE  BIT(1)
+#define CTRL_HANDSHAKE_MODE     BIT(3)
+
+static inline void write_ctrl_reg(struct NCR5380_hostdata *hostdata, u32 value)
+{
+       out_be32(hostdata->io + (CTRL_REG << 4), value);
+}
 
 static inline int macscsi_pread(struct NCR5380_hostdata *hostdata,
                                 unsigned char *dst, int len)
 {
        u8 __iomem *s = hostdata->pdma_io + (INPUT_DATA_REG << 4);
        unsigned char *d = dst;
-       int n = len;
-       int transferred;
+       int result = 0;
+
+       hostdata->pdma_residual = len;
 
        while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
                                      BASR_DRQ | BASR_PHASE_MATCH,
                                      BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) {
-               CP_IO_TO_MEM(s, d, n);
+               int bytes;
+
+               if (macintosh_config->ident == MAC_MODEL_IIFX)
+                       write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE |
+                                                CTRL_INTERRUPTS_ENABLE);
 
-               transferred = d - dst - n;
-               hostdata->pdma_residual = len - transferred;
+               bytes = mac_pdma_recv(s, d, min(hostdata->pdma_residual, 512));
 
-               /* No bus error. */
-               if (n == 0)
-                       return 0;
+               if (bytes > 0) {
+                       d += bytes;
+                       hostdata->pdma_residual -= bytes;
+               }
+
+               if (hostdata->pdma_residual == 0)
+                       goto out;
 
-               /* Target changed phase early? */
                if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
-                                          BUS_AND_STATUS_REG, BASR_ACK, BASR_ACK, HZ / 64) < 0)
-                       scmd_printk(KERN_ERR, hostdata->connected,
+                                          BUS_AND_STATUS_REG, BASR_ACK,
+                                          BASR_ACK, HZ / 64) < 0)
+                       scmd_printk(KERN_DEBUG, hostdata->connected,
                                    "%s: !REQ and !ACK\n", __func__);
                if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
-                       return 0;
+                       goto out;
+
+               if (bytes == 0)
+                       udelay(MAC_PDMA_DELAY);
+
+               if (bytes >= 0)
+                       continue;
 
                dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,
-                        "%s: bus error (%d/%d)\n", __func__, transferred, len);
+                        "%s: bus error (%d/%d)\n", __func__, d - dst, len);
                NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
-               d = dst + transferred;
-               n = len - transferred;
+               result = -1;
+               goto out;
        }
 
        scmd_printk(KERN_ERR, hostdata->connected,
                    "%s: phase mismatch or !DRQ\n", __func__);
        NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
-       return -1;
+       result = -1;
+out:
+       if (macintosh_config->ident == MAC_MODEL_IIFX)
+               write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE);
+       return result;
 }
 
-
-#define CP_MEM_TO_IO(s,d,n)                            \
-__asm__ __volatile__                                   \
-    ("    cmp.w  #4,%2\n"                              \
-     "    bls    8f\n"                                 \
-     "    move.w %0,%%d0\n"                            \
-     "    neg.b  %%d0\n"                               \
-     "    and.w  #3,%%d0\n"                            \
-     "    sub.w  %%d0,%2\n"                            \
-     "    bra    2f\n"                                 \
-     " 1: move.b (%0)+,(%1)\n"                         \
-     " 2: dbf    %%d0,1b\n"                            \
-     "    move.w %2,%%d0\n"                            \
-     "    lsr.w  #5,%%d0\n"                            \
-     "    bra    4f\n"                                 \
-     " 3: move.l (%0)+,(%1)\n"                         \
-     "31: move.l (%0)+,(%1)\n"                         \
-     "32: move.l (%0)+,(%1)\n"                         \
-     "33: move.l (%0)+,(%1)\n"                         \
-     "34: move.l (%0)+,(%1)\n"                         \
-     "35: move.l (%0)+,(%1)\n"                         \
-     "36: move.l (%0)+,(%1)\n"                         \
-     "37: move.l (%0)+,(%1)\n"                         \
-     " 4: dbf    %%d0,3b\n"                            \
-     "    move.w %2,%%d0\n"                            \
-     "    lsr.w  #2,%%d0\n"                            \
-     "    and.w  #7,%%d0\n"                            \
-     "    bra    6f\n"                                 \
-     " 5: move.l (%0)+,(%1)\n"                         \
-     " 6: dbf    %%d0,5b\n"                            \
-     "    and.w  #3,%2\n"                              \
-     "    bra    8f\n"                                 \
-     " 7: move.b (%0)+,(%1)\n"                         \
-     " 8: dbf    %2,7b\n"                              \
-     "    moveq.l #0, %2\n"                            \
-     " 9: \n"                                          \
-     ".section .fixup,\"ax\"\n"                                \
-     "    .even\n"                                     \
-     "91: moveq.l #1, %2\n"                            \
-     "    jra 9b\n"                                    \
-     "94: moveq.l #4, %2\n"                            \
-     "    jra 9b\n"                                    \
-     ".previous\n"                                     \
-     ".section __ex_table,\"a\"\n"                     \
-     "   .align 4\n"                                   \
-     "   .long  1b,91b\n"                              \
-     "   .long  3b,94b\n"                              \
-     "   .long 31b,94b\n"                              \
-     "   .long 32b,94b\n"                              \
-     "   .long 33b,94b\n"                              \
-     "   .long 34b,94b\n"                              \
-     "   .long 35b,94b\n"                              \
-     "   .long 36b,94b\n"                              \
-     "   .long 37b,94b\n"                              \
-     "   .long  5b,94b\n"                              \
-     "   .long  7b,91b\n"                              \
-     ".previous"                                       \
-     : "=a"(s), "=a"(d), "=d"(n)                       \
-     : "0"(s), "1"(d), "2"(n)                          \
-     : "d0")
-
 static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata,
                                  unsigned char *src, int len)
 {
        unsigned char *s = src;
        u8 __iomem *d = hostdata->pdma_io + (OUTPUT_DATA_REG << 4);
-       int n = len;
-       int transferred;
+       int result = 0;
+
+       hostdata->pdma_residual = len;
 
        while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
                                      BASR_DRQ | BASR_PHASE_MATCH,
                                      BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) {
-               CP_MEM_TO_IO(s, d, n);
+               int bytes;
 
-               transferred = s - src - n;
-               hostdata->pdma_residual = len - transferred;
+               if (macintosh_config->ident == MAC_MODEL_IIFX)
+                       write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE |
+                                                CTRL_INTERRUPTS_ENABLE);
 
-               /* Target changed phase early? */
-               if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
-                                          BUS_AND_STATUS_REG, BASR_ACK, BASR_ACK, HZ / 64) < 0)
-                       scmd_printk(KERN_ERR, hostdata->connected,
-                                   "%s: !REQ and !ACK\n", __func__);
-               if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
-                       return 0;
+               bytes = mac_pdma_send(s, d, min(hostdata->pdma_residual, 512));
+
+               if (bytes > 0) {
+                       s += bytes;
+                       hostdata->pdma_residual -= bytes;
+               }
 
-               /* No bus error. */
-               if (n == 0) {
+               if (hostdata->pdma_residual == 0) {
                        if (NCR5380_poll_politely(hostdata, TARGET_COMMAND_REG,
                                                  TCR_LAST_BYTE_SENT,
-                                                 TCR_LAST_BYTE_SENT, HZ / 64) < 0)
+                                                 TCR_LAST_BYTE_SENT,
+                                                 HZ / 64) < 0) {
                                scmd_printk(KERN_ERR, hostdata->connected,
                                            "%s: Last Byte Sent timeout\n", __func__);
-                       return 0;
+                               result = -1;
+                       }
+                       goto out;
                }
 
+               if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
+                                          BUS_AND_STATUS_REG, BASR_ACK,
+                                          BASR_ACK, HZ / 64) < 0)
+                       scmd_printk(KERN_DEBUG, hostdata->connected,
+                                   "%s: !REQ and !ACK\n", __func__);
+               if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
+                       goto out;
+
+               if (bytes == 0)
+                       udelay(MAC_PDMA_DELAY);
+
+               if (bytes >= 0)
+                       continue;
+
                dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,
-                        "%s: bus error (%d/%d)\n", __func__, transferred, len);
+                        "%s: bus error (%d/%d)\n", __func__, s - src, len);
                NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
-               s = src + transferred;
-               n = len - transferred;
+               result = -1;
+               goto out;
        }
 
        scmd_printk(KERN_ERR, hostdata->connected,
                    "%s: phase mismatch or !DRQ\n", __func__);
        NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
-
-       return -1;
+       result = -1;
+out:
+       if (macintosh_config->ident == MAC_MODEL_IIFX)
+               write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE);
+       return result;
 }
 
 static int macscsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
                                 struct scsi_cmnd *cmd)
 {
        if (hostdata->flags & FLAG_NO_PSEUDO_DMA ||
-           cmd->SCp.this_residual < 16)
+           cmd->SCp.this_residual < setup_use_pdma)
                return 0;
 
        return cmd->SCp.this_residual;
index e630e41..2adc2af 100644 (file)
@@ -79,6 +79,7 @@ config MEGARAID_LEGACY
 config MEGARAID_SAS
        tristate "LSI Logic MegaRAID SAS RAID Module"
        depends on PCI && SCSI
+       select IRQ_POLL
        help
        Module for LSI Logic's SAS based RAID controllers.
        To compile this driver as a module, choose 'm' here.
index 6e74d21..12177e4 100644 (file)
@@ -3,4 +3,4 @@ obj-$(CONFIG_MEGARAID_MM)       += megaraid_mm.o
 obj-$(CONFIG_MEGARAID_MAILBOX) += megaraid_mbox.o
 obj-$(CONFIG_MEGARAID_SAS)     += megaraid_sas.o
 megaraid_sas-objs := megaraid_sas_base.o megaraid_sas_fusion.o \
-       megaraid_sas_fp.o
+       megaraid_sas_fp.o megaraid_sas_debugfs.o
index fe9a785..ca724fe 100644 (file)
@@ -21,8 +21,8 @@
 /*
  * MegaRAID SAS Driver meta data
  */
-#define MEGASAS_VERSION                                "07.707.51.00-rc1"
-#define MEGASAS_RELDATE                                "February 7, 2019"
+#define MEGASAS_VERSION                                "07.710.06.00-rc1"
+#define MEGASAS_RELDATE                                "June 18, 2019"
 
 /*
  * Device IDs
 #define PCI_DEVICE_ID_LSI_AERO_10E2            0x10e2
 #define PCI_DEVICE_ID_LSI_AERO_10E5            0x10e5
 #define PCI_DEVICE_ID_LSI_AERO_10E6            0x10e6
+#define PCI_DEVICE_ID_LSI_AERO_10E0            0x10e0
+#define PCI_DEVICE_ID_LSI_AERO_10E3            0x10e3
+#define PCI_DEVICE_ID_LSI_AERO_10E4            0x10e4
+#define PCI_DEVICE_ID_LSI_AERO_10E7            0x10e7
 
 /*
  * Intel HBA SSDIDs
 #define MFI_RESET_ADAPTER                      0x00000002
 #define MEGAMFI_FRAME_SIZE                     64
 
+#define MFI_STATE_FAULT_CODE                   0x0FFF0000
+#define MFI_STATE_FAULT_SUBCODE                        0x0000FF00
 /*
  * During FW init, clear pending cmds & reset state using inbound_msg_0
  *
@@ -190,6 +196,7 @@ enum MFI_CMD_OP {
        MFI_CMD_SMP             = 0x7,
        MFI_CMD_STP             = 0x8,
        MFI_CMD_NVME            = 0x9,
+       MFI_CMD_TOOLBOX         = 0xa,
        MFI_CMD_OP_COUNT,
        MFI_CMD_INVALID         = 0xff
 };
@@ -1449,7 +1456,39 @@ struct megasas_ctrl_info {
 
        u8 reserved6[64];
 
-       u32 rsvdForAdptOp[64];
+       struct {
+       #if defined(__BIG_ENDIAN_BITFIELD)
+               u32 reserved:19;
+               u32 support_pci_lane_margining: 1;
+               u32 support_psoc_update:1;
+               u32 support_force_personality_change:1;
+               u32 support_fde_type_mix:1;
+               u32 support_snap_dump:1;
+               u32 support_nvme_tm:1;
+               u32 support_oce_only:1;
+               u32 support_ext_mfg_vpd:1;
+               u32 support_pcie:1;
+               u32 support_cvhealth_info:1;
+               u32 support_profile_change:2;
+               u32 mr_config_ext2_supported:1;
+       #else
+               u32 mr_config_ext2_supported:1;
+               u32 support_profile_change:2;
+               u32 support_cvhealth_info:1;
+               u32 support_pcie:1;
+               u32 support_ext_mfg_vpd:1;
+               u32 support_oce_only:1;
+               u32 support_nvme_tm:1;
+               u32 support_snap_dump:1;
+               u32 support_fde_type_mix:1;
+               u32 support_force_personality_change:1;
+               u32 support_psoc_update:1;
+               u32 support_pci_lane_margining: 1;
+               u32 reserved:19;
+       #endif
+       } adapter_operations5;
+
+       u32 rsvdForAdptOp[63];
 
        u8 reserved7[3];
 
@@ -1483,7 +1522,9 @@ struct megasas_ctrl_info {
 #define MEGASAS_FW_BUSY                                1
 
 /* Driver's internal Logging levels*/
-#define OCR_LOGS    (1 << 0)
+#define OCR_DEBUG    (1 << 0)
+#define TM_DEBUG     (1 << 1)
+#define LD_PD_DEBUG    (1 << 2)
 
 #define SCAN_PD_CHANNEL        0x1
 #define SCAN_VD_CHANNEL        0x2
@@ -1559,6 +1600,7 @@ enum FW_BOOT_CONTEXT {
 #define MFI_IO_TIMEOUT_SECS                    180
 #define MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF    (5 * HZ)
 #define MEGASAS_OCR_SETTLE_TIME_VF             (1000 * 30)
+#define MEGASAS_SRIOV_MAX_RESET_TRIES_VF       1
 #define MEGASAS_ROUTINE_WAIT_TIME_VF           300
 #define MFI_REPLY_1078_MESSAGE_INTERRUPT       0x80000000
 #define MFI_REPLY_GEN2_MESSAGE_INTERRUPT       0x00000001
@@ -1583,7 +1625,10 @@ enum FW_BOOT_CONTEXT {
 
 #define MR_CAN_HANDLE_SYNC_CACHE_OFFSET                0X01000000
 
+#define MR_ATOMIC_DESCRIPTOR_SUPPORT_OFFSET    (1 << 24)
+
 #define MR_CAN_HANDLE_64_BIT_DMA_OFFSET                (1 << 25)
+#define MR_INTR_COALESCING_SUPPORT_OFFSET      (1 << 26)
 
 #define MEGASAS_WATCHDOG_THREAD_INTERVAL       1000
 #define MEGASAS_WAIT_FOR_NEXT_DMA_MSECS                20
@@ -1762,7 +1807,7 @@ struct megasas_init_frame {
        __le32 pad_0;           /*0Ch */
 
        __le16 flags;           /*10h */
-       __le16 reserved_3;              /*12h */
+       __le16 replyqueue_mask;         /*12h */
        __le32 data_xfer_len;   /*14h */
 
        __le32 queue_info_new_phys_addr_lo;     /*18h */
@@ -2160,6 +2205,10 @@ struct megasas_aen_event {
 struct megasas_irq_context {
        struct megasas_instance *instance;
        u32 MSIxIndex;
+       u32 os_irq;
+       struct irq_poll irqpoll;
+       bool irq_poll_scheduled;
+       bool irq_line_enable;
 };
 
 struct MR_DRV_SYSTEM_INFO {
@@ -2190,6 +2239,23 @@ enum MR_PD_TYPE {
 #define MR_DEFAULT_NVME_MDTS_KB                128
 #define MR_NVME_PAGE_SIZE_MASK         0x000000FF
 
+/*Aero performance parameters*/
+#define MR_HIGH_IOPS_QUEUE_COUNT       8
+#define MR_DEVICE_HIGH_IOPS_DEPTH      8
+#define MR_HIGH_IOPS_BATCH_COUNT       16
+
+enum MR_PERF_MODE {
+       MR_BALANCED_PERF_MODE           = 0,
+       MR_IOPS_PERF_MODE               = 1,
+       MR_LATENCY_PERF_MODE            = 2,
+};
+
+#define MEGASAS_PERF_MODE_2STR(mode) \
+               ((mode) == MR_BALANCED_PERF_MODE ? "Balanced" : \
+                (mode) == MR_IOPS_PERF_MODE ? "IOPS" : \
+                (mode) == MR_LATENCY_PERF_MODE ? "Latency" : \
+                "Unknown")
+
 struct megasas_instance {
 
        unsigned int *reply_map;
@@ -2246,6 +2312,7 @@ struct megasas_instance {
        u32 secure_jbod_support;
        u32 support_morethan256jbod; /* FW support for more than 256 PD/JBOD */
        bool use_seqnum_jbod_fp;   /* Added for PD sequence */
+       bool smp_affinity_enable;
        spinlock_t crashdump_lock;
 
        struct megasas_register_set __iomem *reg_set;
@@ -2263,6 +2330,7 @@ struct megasas_instance {
        u16 ldio_threshold;
        u16 cur_can_queue;
        u32 max_sectors_per_req;
+       bool msix_load_balance;
        struct megasas_aen_event *ev;
 
        struct megasas_cmd **cmd_list;
@@ -2290,15 +2358,13 @@ struct megasas_instance {
        struct pci_dev *pdev;
        u32 unique_id;
        u32 fw_support_ieee;
+       u32 threshold_reply_count;
 
        atomic_t fw_outstanding;
        atomic_t ldio_outstanding;
        atomic_t fw_reset_no_pci_access;
-       atomic_t ieee_sgl;
-       atomic_t prp_sgl;
-       atomic_t sge_holes_type1;
-       atomic_t sge_holes_type2;
-       atomic_t sge_holes_type3;
+       atomic64_t total_io_count;
+       atomic64_t high_iops_outstanding;
 
        struct megasas_instance_template *instancet;
        struct tasklet_struct isr_tasklet;
@@ -2366,8 +2432,18 @@ struct megasas_instance {
        u8 task_abort_tmo;
        u8 max_reset_tmo;
        u8 snapdump_wait_time;
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *debugfs_root;
+       struct dentry *raidmap_dump;
+#endif
        u8 enable_fw_dev_list;
+       bool atomic_desc_support;
+       bool support_seqnum_jbod_fp;
+       bool support_pci_lane_margining;
+       u8  low_latency_index_start;
+       int perf_mode;
 };
+
 struct MR_LD_VF_MAP {
        u32 size;
        union MR_LD_REF ref;
@@ -2623,4 +2699,9 @@ void megasas_fusion_stop_watchdog(struct megasas_instance *instance);
 void megasas_set_dma_settings(struct megasas_instance *instance,
                              struct megasas_dcmd_frame *dcmd,
                              dma_addr_t dma_addr, u32 dma_len);
+int megasas_adp_reset_wait_for_ready(struct megasas_instance *instance,
+                                    bool do_adp_reset,
+                                    int ocr_context);
+int megasas_irqpoll(struct irq_poll *irqpoll, int budget);
+void megasas_dump_fusion_io(struct scsi_cmnd *scmd);
 #endif                         /*LSI_MEGARAID_SAS_H */
index 3dd1df4..80ab970 100644 (file)
 #include <linux/mutex.h>
 #include <linux/poll.h>
 #include <linux/vmalloc.h>
+#include <linux/irq_poll.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
+#include <scsi/scsi_dbg.h>
 #include "megaraid_sas_fusion.h"
 #include "megaraid_sas.h"
 
  * Will be set in megasas_init_mfi if user does not provide
  */
 static unsigned int max_sectors;
-module_param_named(max_sectors, max_sectors, int, 0);
+module_param_named(max_sectors, max_sectors, int, 0444);
 MODULE_PARM_DESC(max_sectors,
        "Maximum number of sectors per IO command");
 
 static int msix_disable;
-module_param(msix_disable, int, S_IRUGO);
+module_param(msix_disable, int, 0444);
 MODULE_PARM_DESC(msix_disable, "Disable MSI-X interrupt handling. Default: 0");
 
 static unsigned int msix_vectors;
-module_param(msix_vectors, int, S_IRUGO);
+module_param(msix_vectors, int, 0444);
 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_param(allow_vf_ioctls, int, 0444);
 MODULE_PARM_DESC(allow_vf_ioctls, "Allow ioctls in SR-IOV VF mode. Default: 0");
 
 static unsigned int throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH;
-module_param(throttlequeuedepth, int, S_IRUGO);
+module_param(throttlequeuedepth, int, 0444);
 MODULE_PARM_DESC(throttlequeuedepth,
        "Adapter queue depth when throttled due to I/O timeout. Default: 16");
 
 unsigned int resetwaittime = MEGASAS_RESET_WAIT_TIME;
-module_param(resetwaittime, int, S_IRUGO);
+module_param(resetwaittime, int, 0444);
 MODULE_PARM_DESC(resetwaittime, "Wait time in (1-180s) after I/O timeout before resetting adapter. Default: 180s");
 
 int smp_affinity_enable = 1;
-module_param(smp_affinity_enable, int, S_IRUGO);
+module_param(smp_affinity_enable, int, 0444);
 MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disable Default: enable(1)");
 
 int rdpq_enable = 1;
-module_param(rdpq_enable, int, S_IRUGO);
+module_param(rdpq_enable, int, 0444);
 MODULE_PARM_DESC(rdpq_enable, "Allocate reply queue in chunks for large queue depth enable/disable Default: enable(1)");
 
 unsigned int dual_qdepth_disable;
-module_param(dual_qdepth_disable, int, S_IRUGO);
+module_param(dual_qdepth_disable, int, 0444);
 MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth feature. Default: 0");
 
 unsigned int scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT;
-module_param(scmd_timeout, int, S_IRUGO);
+module_param(scmd_timeout, int, 0444);
 MODULE_PARM_DESC(scmd_timeout, "scsi command timeout (10-90s), default 90s. See megasas_reset_timer.");
 
+int perf_mode = -1;
+module_param(perf_mode, int, 0444);
+MODULE_PARM_DESC(perf_mode, "Performance mode (only for Aero adapters), options:\n\t\t"
+               "0 - balanced: High iops and low latency queues are allocated &\n\t\t"
+               "interrupt coalescing is enabled only on high iops queues\n\t\t"
+               "1 - iops: High iops queues are not allocated &\n\t\t"
+               "interrupt coalescing is enabled on all queues\n\t\t"
+               "2 - latency: High iops queues are not allocated &\n\t\t"
+               "interrupt coalescing is disabled on all queues\n\t\t"
+               "default mode is 'balanced'"
+               );
+
 MODULE_LICENSE("GPL");
 MODULE_VERSION(MEGASAS_VERSION);
 MODULE_AUTHOR("megaraidlinux.pdl@broadcom.com");
@@ -154,6 +168,10 @@ static struct pci_device_id megasas_pci_table[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E2)},
        {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E5)},
        {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E6)},
+       {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E0)},
+       {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E3)},
+       {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E4)},
+       {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E7)},
        {}
 };
 
@@ -170,10 +188,17 @@ static u32 support_poll_for_event;
 u32 megasas_dbg_lvl;
 static u32 support_device_change;
 static bool support_nvme_encapsulation;
+static bool support_pci_lane_margining;
 
 /* define lock for aen poll */
 spinlock_t poll_aen_lock;
 
+extern struct dentry *megasas_debugfs_root;
+extern void megasas_init_debugfs(void);
+extern void megasas_exit_debugfs(void);
+extern void megasas_setup_debugfs(struct megasas_instance *instance);
+extern void megasas_destroy_debugfs(struct megasas_instance *instance);
+
 void
 megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
                     u8 alt_status);
@@ -1098,8 +1123,9 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
                ret = wait_event_timeout(instance->int_cmd_wait_q,
                                cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ);
                if (!ret) {
-                       dev_err(&instance->pdev->dev, "Failed from %s %d DCMD Timed out\n",
-                               __func__, __LINE__);
+                       dev_err(&instance->pdev->dev,
+                               "DCMD(opcode: 0x%x) is timed out, func:%s\n",
+                               cmd->frame->dcmd.opcode, __func__);
                        return DCMD_TIMEOUT;
                }
        } else
@@ -1128,6 +1154,7 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
        struct megasas_cmd *cmd;
        struct megasas_abort_frame *abort_fr;
        int ret = 0;
+       u32 opcode;
 
        cmd = megasas_get_cmd(instance);
 
@@ -1163,8 +1190,10 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
                ret = wait_event_timeout(instance->abort_cmd_wait_q,
                                cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ);
                if (!ret) {
-                       dev_err(&instance->pdev->dev, "Failed from %s %d Abort Timed out\n",
-                               __func__, __LINE__);
+                       opcode = cmd_to_abort->frame->dcmd.opcode;
+                       dev_err(&instance->pdev->dev,
+                               "Abort(to be aborted DCMD opcode: 0x%x) is timed out func:%s\n",
+                               opcode,  __func__);
                        return DCMD_TIMEOUT;
                }
        } else
@@ -1918,7 +1947,6 @@ megasas_set_nvme_device_properties(struct scsi_device *sdev, u32 max_io_size)
 static void megasas_set_static_target_properties(struct scsi_device *sdev,
                                                 bool is_target_prop)
 {
-       u16     target_index = 0;
        u8 interface_type;
        u32 device_qd = MEGASAS_DEFAULT_CMD_PER_LUN;
        u32 max_io_size_kb = MR_DEFAULT_NVME_MDTS_KB;
@@ -1935,8 +1963,6 @@ static void megasas_set_static_target_properties(struct scsi_device *sdev,
         */
        blk_queue_rq_timeout(sdev->request_queue, scmd_timeout * HZ);
 
-       target_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
-
        switch (interface_type) {
        case SAS_PD:
                device_qd = MEGASAS_SAS_QD;
@@ -2822,21 +2848,108 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
 }
 
 /**
- * megasas_dump_frame -        This function will dump MPT/MFI frame
+ * megasas_dump -      This function will print hexdump of provided buffer.
+ * @buf:               Buffer to be dumped
+ * @sz:                Size in bytes
+ * @format:            Different formats of dumping e.g. format=n will
+ *                     cause only 'n' 32 bit words to be dumped in a single
+ *                     line.
  */
-static inline void
-megasas_dump_frame(void *mpi_request, int sz)
+inline void
+megasas_dump(void *buf, int sz, int format)
 {
        int i;
-       __le32 *mfp = (__le32 *)mpi_request;
+       __le32 *buf_loc = (__le32 *)buf;
+
+       for (i = 0; i < (sz / sizeof(__le32)); i++) {
+               if ((i % format) == 0) {
+                       if (i != 0)
+                               printk(KERN_CONT "\n");
+                       printk(KERN_CONT "%08x: ", (i * 4));
+               }
+               printk(KERN_CONT "%08x ", le32_to_cpu(buf_loc[i]));
+       }
+       printk(KERN_CONT "\n");
+}
+
+/**
+ * megasas_dump_reg_set -      This function will print hexdump of register set
+ * @buf:                       Buffer to be dumped
+ * @sz:                                Size in bytes
+ * @format:                    Different formats of dumping e.g. format=n will
+ *                             cause only 'n' 32 bit words to be dumped in a
+ *                             single line.
+ */
+inline void
+megasas_dump_reg_set(void __iomem *reg_set)
+{
+       unsigned int i, sz = 256;
+       u32 __iomem *reg = (u32 __iomem *)reg_set;
+
+       for (i = 0; i < (sz / sizeof(u32)); i++)
+               printk("%08x: %08x\n", (i * 4), readl(&reg[i]));
+}
+
+/**
+ * megasas_dump_fusion_io -    This function will print key details
+ *                             of SCSI IO
+ * @scmd:                      SCSI command pointer of SCSI IO
+ */
+void
+megasas_dump_fusion_io(struct scsi_cmnd *scmd)
+{
+       struct megasas_cmd_fusion *cmd;
+       union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+       struct megasas_instance *instance;
+
+       cmd = (struct megasas_cmd_fusion *)scmd->SCp.ptr;
+       instance = (struct megasas_instance *)scmd->device->host->hostdata;
+
+       scmd_printk(KERN_INFO, scmd,
+                   "scmd: (0x%p)  retries: 0x%x  allowed: 0x%x\n",
+                   scmd, scmd->retries, scmd->allowed);
+       scsi_print_command(scmd);
+
+       if (cmd) {
+               req_desc = (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)cmd->request_desc;
+               scmd_printk(KERN_INFO, scmd, "Request descriptor details:\n");
+               scmd_printk(KERN_INFO, scmd,
+                           "RequestFlags:0x%x  MSIxIndex:0x%x  SMID:0x%x  LMID:0x%x  DevHandle:0x%x\n",
+                           req_desc->SCSIIO.RequestFlags,
+                           req_desc->SCSIIO.MSIxIndex, req_desc->SCSIIO.SMID,
+                           req_desc->SCSIIO.LMID, req_desc->SCSIIO.DevHandle);
+
+               printk(KERN_INFO "IO request frame:\n");
+               megasas_dump(cmd->io_request,
+                            MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE, 8);
+               printk(KERN_INFO "Chain frame:\n");
+               megasas_dump(cmd->sg_frame,
+                            instance->max_chain_frame_sz, 8);
+       }
+
+}
+
+/*
+ * megasas_dump_sys_regs - This function will dump system registers through
+ *                         sysfs.
+ * @reg_set:               Pointer to System register set.
+ * @buf:                   Buffer to which output is to be written.
+ * @return:                Number of bytes written to buffer.
+ */
+static inline ssize_t
+megasas_dump_sys_regs(void __iomem *reg_set, char *buf)
+{
+       unsigned int i, sz = 256;
+       int bytes_wrote = 0;
+       char *loc = (char *)buf;
+       u32 __iomem *reg = (u32 __iomem *)reg_set;
 
-       printk(KERN_INFO "IO request frame:\n\t");
-       for (i = 0; i < sz / sizeof(__le32); i++) {
-               if (i && ((i % 8) == 0))
-                       printk("\n\t");
-               printk("%08x ", le32_to_cpu(mfp[i]));
+       for (i = 0; i < sz / sizeof(u32); i++) {
+               bytes_wrote += snprintf(loc + bytes_wrote, PAGE_SIZE,
+                                       "%08x: %08x\n", (i * 4),
+                                       readl(&reg[i]));
        }
-       printk("\n");
+       return bytes_wrote;
 }
 
 /**
@@ -2850,24 +2963,20 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
        instance = (struct megasas_instance *)scmd->device->host->hostdata;
 
        scmd_printk(KERN_INFO, scmd,
-               "Controller reset is requested due to IO timeout\n"
-               "SCSI command pointer: (%p)\t SCSI host state: %d\t"
-               " SCSI host busy: %d\t FW outstanding: %d\n",
-               scmd, scmd->device->host->shost_state,
+               "OCR is requested due to IO timeout!!\n");
+
+       scmd_printk(KERN_INFO, scmd,
+               "SCSI host state: %d  SCSI host busy: %d  FW outstanding: %d\n",
+               scmd->device->host->shost_state,
                scsi_host_busy(scmd->device->host),
                atomic_read(&instance->fw_outstanding));
-
        /*
         * First wait for all commands to complete
         */
        if (instance->adapter_type == MFI_SERIES) {
                ret = megasas_generic_reset(scmd);
        } else {
-               struct megasas_cmd_fusion *cmd;
-               cmd = (struct megasas_cmd_fusion *)scmd->SCp.ptr;
-               if (cmd)
-                       megasas_dump_frame(cmd->io_request,
-                               MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE);
+               megasas_dump_fusion_io(scmd);
                ret = megasas_reset_fusion(scmd->device->host,
                                SCSIIO_TIMEOUT_OCR);
        }
@@ -3017,7 +3126,7 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
 }
 
 static ssize_t
-megasas_fw_crash_buffer_store(struct device *cdev,
+fw_crash_buffer_store(struct device *cdev,
        struct device_attribute *attr, const char *buf, size_t count)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3036,14 +3145,13 @@ megasas_fw_crash_buffer_store(struct device *cdev,
 }
 
 static ssize_t
-megasas_fw_crash_buffer_show(struct device *cdev,
+fw_crash_buffer_show(struct device *cdev,
        struct device_attribute *attr, char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
        struct megasas_instance *instance =
                (struct megasas_instance *) shost->hostdata;
        u32 size;
-       unsigned long buff_addr;
        unsigned long dmachunk = CRASH_DMA_BUF_SIZE;
        unsigned long src_addr;
        unsigned long flags;
@@ -3060,8 +3168,6 @@ megasas_fw_crash_buffer_show(struct device *cdev,
                return -EINVAL;
        }
 
-       buff_addr = (unsigned long) buf;
-
        if (buff_offset > (instance->fw_crash_buffer_size * dmachunk)) {
                dev_err(&instance->pdev->dev,
                        "Firmware crash dump offset is out of range\n");
@@ -3081,7 +3187,7 @@ megasas_fw_crash_buffer_show(struct device *cdev,
 }
 
 static ssize_t
-megasas_fw_crash_buffer_size_show(struct device *cdev,
+fw_crash_buffer_size_show(struct device *cdev,
        struct device_attribute *attr, char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3093,7 +3199,7 @@ megasas_fw_crash_buffer_size_show(struct device *cdev,
 }
 
 static ssize_t
-megasas_fw_crash_state_store(struct device *cdev,
+fw_crash_state_store(struct device *cdev,
        struct device_attribute *attr, const char *buf, size_t count)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3128,7 +3234,7 @@ megasas_fw_crash_state_store(struct device *cdev,
 }
 
 static ssize_t
-megasas_fw_crash_state_show(struct device *cdev,
+fw_crash_state_show(struct device *cdev,
        struct device_attribute *attr, char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3139,14 +3245,14 @@ megasas_fw_crash_state_show(struct device *cdev,
 }
 
 static ssize_t
-megasas_page_size_show(struct device *cdev,
+page_size_show(struct device *cdev,
        struct device_attribute *attr, char *buf)
 {
        return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)PAGE_SIZE - 1);
 }
 
 static ssize_t
-megasas_ldio_outstanding_show(struct device *cdev, struct device_attribute *attr,
+ldio_outstanding_show(struct device *cdev, struct device_attribute *attr,
        char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3156,7 +3262,7 @@ megasas_ldio_outstanding_show(struct device *cdev, struct device_attribute *attr
 }
 
 static ssize_t
-megasas_fw_cmds_outstanding_show(struct device *cdev,
+fw_cmds_outstanding_show(struct device *cdev,
                                 struct device_attribute *attr, char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3165,18 +3271,37 @@ megasas_fw_cmds_outstanding_show(struct device *cdev,
        return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&instance->fw_outstanding));
 }
 
-static DEVICE_ATTR(fw_crash_buffer, S_IRUGO | S_IWUSR,
-       megasas_fw_crash_buffer_show, megasas_fw_crash_buffer_store);
-static DEVICE_ATTR(fw_crash_buffer_size, S_IRUGO,
-       megasas_fw_crash_buffer_size_show, NULL);
-static DEVICE_ATTR(fw_crash_state, S_IRUGO | S_IWUSR,
-       megasas_fw_crash_state_show, megasas_fw_crash_state_store);
-static DEVICE_ATTR(page_size, S_IRUGO,
-       megasas_page_size_show, NULL);
-static DEVICE_ATTR(ldio_outstanding, S_IRUGO,
-       megasas_ldio_outstanding_show, NULL);
-static DEVICE_ATTR(fw_cmds_outstanding, S_IRUGO,
-       megasas_fw_cmds_outstanding_show, NULL);
+static ssize_t
+dump_system_regs_show(struct device *cdev,
+                              struct device_attribute *attr, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct megasas_instance *instance =
+                       (struct megasas_instance *)shost->hostdata;
+
+       return megasas_dump_sys_regs(instance->reg_set, buf);
+}
+
+static ssize_t
+raid_map_id_show(struct device *cdev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct megasas_instance *instance =
+                       (struct megasas_instance *)shost->hostdata;
+
+       return snprintf(buf, PAGE_SIZE, "%ld\n",
+                       (unsigned long)instance->map_id);
+}
+
+static DEVICE_ATTR_RW(fw_crash_buffer);
+static DEVICE_ATTR_RO(fw_crash_buffer_size);
+static DEVICE_ATTR_RW(fw_crash_state);
+static DEVICE_ATTR_RO(page_size);
+static DEVICE_ATTR_RO(ldio_outstanding);
+static DEVICE_ATTR_RO(fw_cmds_outstanding);
+static DEVICE_ATTR_RO(dump_system_regs);
+static DEVICE_ATTR_RO(raid_map_id);
 
 struct device_attribute *megaraid_host_attrs[] = {
        &dev_attr_fw_crash_buffer_size,
@@ -3185,6 +3310,8 @@ struct device_attribute *megaraid_host_attrs[] = {
        &dev_attr_page_size,
        &dev_attr_ldio_outstanding,
        &dev_attr_fw_cmds_outstanding,
+       &dev_attr_dump_system_regs,
+       &dev_attr_raid_map_id,
        NULL,
 };
 
@@ -3368,6 +3495,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
        case MFI_CMD_SMP:
        case MFI_CMD_STP:
        case MFI_CMD_NVME:
+       case MFI_CMD_TOOLBOX:
                megasas_complete_int_cmd(instance, cmd);
                break;
 
@@ -3776,7 +3904,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
        int i;
        u8 max_wait;
        u32 fw_state;
-       u32 cur_state;
        u32 abs_state, curr_abs_state;
 
        abs_state = instance->instancet->read_fw_status_reg(instance);
@@ -3791,13 +3918,18 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
                switch (fw_state) {
 
                case MFI_STATE_FAULT:
-                       dev_printk(KERN_DEBUG, &instance->pdev->dev, "FW in FAULT state!!\n");
+                       dev_printk(KERN_ERR, &instance->pdev->dev,
+                                  "FW in FAULT state, Fault code:0x%x subcode:0x%x func:%s\n",
+                                  abs_state & MFI_STATE_FAULT_CODE,
+                                  abs_state & MFI_STATE_FAULT_SUBCODE, __func__);
                        if (ocr) {
                                max_wait = MEGASAS_RESET_WAIT_TIME;
-                               cur_state = MFI_STATE_FAULT;
                                break;
-                       } else
+                       } else {
+                               dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n");
+                               megasas_dump_reg_set(instance->reg_set);
                                return -ENODEV;
+                       }
 
                case MFI_STATE_WAIT_HANDSHAKE:
                        /*
@@ -3817,7 +3949,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
                                        &instance->reg_set->inbound_doorbell);
 
                        max_wait = MEGASAS_RESET_WAIT_TIME;
-                       cur_state = MFI_STATE_WAIT_HANDSHAKE;
                        break;
 
                case MFI_STATE_BOOT_MESSAGE_PENDING:
@@ -3833,7 +3964,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
                                        &instance->reg_set->inbound_doorbell);
 
                        max_wait = MEGASAS_RESET_WAIT_TIME;
-                       cur_state = MFI_STATE_BOOT_MESSAGE_PENDING;
                        break;
 
                case MFI_STATE_OPERATIONAL:
@@ -3866,7 +3996,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
                                        &instance->reg_set->inbound_doorbell);
 
                        max_wait = MEGASAS_RESET_WAIT_TIME;
-                       cur_state = MFI_STATE_OPERATIONAL;
                        break;
 
                case MFI_STATE_UNDEFINED:
@@ -3874,37 +4003,33 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
                         * This state should not last for more than 2 seconds
                         */
                        max_wait = MEGASAS_RESET_WAIT_TIME;
-                       cur_state = MFI_STATE_UNDEFINED;
                        break;
 
                case MFI_STATE_BB_INIT:
                        max_wait = MEGASAS_RESET_WAIT_TIME;
-                       cur_state = MFI_STATE_BB_INIT;
                        break;
 
                case MFI_STATE_FW_INIT:
                        max_wait = MEGASAS_RESET_WAIT_TIME;
-                       cur_state = MFI_STATE_FW_INIT;
                        break;
 
                case MFI_STATE_FW_INIT_2:
                        max_wait = MEGASAS_RESET_WAIT_TIME;
-                       cur_state = MFI_STATE_FW_INIT_2;
                        break;
 
                case MFI_STATE_DEVICE_SCAN:
                        max_wait = MEGASAS_RESET_WAIT_TIME;
-                       cur_state = MFI_STATE_DEVICE_SCAN;
                        break;
 
                case MFI_STATE_FLUSH_CACHE:
                        max_wait = MEGASAS_RESET_WAIT_TIME;
-                       cur_state = MFI_STATE_FLUSH_CACHE;
                        break;
 
                default:
                        dev_printk(KERN_DEBUG, &instance->pdev->dev, "Unknown state 0x%x\n",
                               fw_state);
+                       dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n");
+                       megasas_dump_reg_set(instance->reg_set);
                        return -ENODEV;
                }
 
@@ -3927,6 +4052,8 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
                if (curr_abs_state == abs_state) {
                        dev_printk(KERN_DEBUG, &instance->pdev->dev, "FW state [%d] hasn't changed "
                               "in %d secs\n", fw_state, max_wait);
+                       dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n");
+                       megasas_dump_reg_set(instance->reg_set);
                        return -ENODEV;
                }
 
@@ -3990,22 +4117,11 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
 {
        int i;
        u16 max_cmd;
-       u32 sge_sz;
        u32 frame_count;
        struct megasas_cmd *cmd;
 
        max_cmd = instance->max_mfi_cmds;
 
-       /*
-        * Size of our frame is 64 bytes for MFI frame, followed by max SG
-        * elements and finally SCSI_SENSE_BUFFERSIZE bytes for sense buffer
-        */
-       sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
-           sizeof(struct megasas_sge32);
-
-       if (instance->flag_ieee)
-               sge_sz = sizeof(struct megasas_sge_skinny);
-
        /*
         * For MFI controllers.
         * max_num_sge = 60
@@ -4255,8 +4371,10 @@ megasas_get_pd_info(struct megasas_instance *instance, struct scsi_device *sdev)
                switch (dcmd_timeout_ocr_possible(instance)) {
                case INITIATE_OCR:
                        cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+                       mutex_unlock(&instance->reset_mutex);
                        megasas_reset_fusion(instance->host,
                                MFI_IO_TIMEOUT_OCR);
+                       mutex_lock(&instance->reset_mutex);
                        break;
                case KILL_ADAPTER:
                        megaraid_sas_kill_hba(instance);
@@ -4292,7 +4410,6 @@ megasas_get_pd_list(struct megasas_instance *instance)
        struct megasas_dcmd_frame *dcmd;
        struct MR_PD_LIST *ci;
        struct MR_PD_ADDRESS *pd_addr;
-       dma_addr_t ci_h = 0;
 
        if (instance->pd_list_not_supported) {
                dev_info(&instance->pdev->dev, "MR_DCMD_PD_LIST_QUERY "
@@ -4301,7 +4418,6 @@ megasas_get_pd_list(struct megasas_instance *instance)
        }
 
        ci = instance->pd_list_buf;
-       ci_h = instance->pd_list_buf_h;
 
        cmd = megasas_get_cmd(instance);
 
@@ -4374,6 +4490,9 @@ megasas_get_pd_list(struct megasas_instance *instance)
 
        case DCMD_SUCCESS:
                pd_addr = ci->addr;
+               if (megasas_dbg_lvl & LD_PD_DEBUG)
+                       dev_info(&instance->pdev->dev, "%s, sysPD count: 0x%x\n",
+                                __func__, le32_to_cpu(ci->count));
 
                if ((le32_to_cpu(ci->count) >
                        (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL)))
@@ -4389,6 +4508,11 @@ megasas_get_pd_list(struct megasas_instance *instance)
                                        pd_addr->scsiDevType;
                        instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveState      =
                                        MR_PD_STATE_SYSTEM;
+                       if (megasas_dbg_lvl & LD_PD_DEBUG)
+                               dev_info(&instance->pdev->dev,
+                                        "PD%d: targetID: 0x%03x deviceType:0x%x\n",
+                                        pd_index, le16_to_cpu(pd_addr->deviceId),
+                                        pd_addr->scsiDevType);
                        pd_addr++;
                }
 
@@ -4492,6 +4616,10 @@ megasas_get_ld_list(struct megasas_instance *instance)
                break;
 
        case DCMD_SUCCESS:
+               if (megasas_dbg_lvl & LD_PD_DEBUG)
+                       dev_info(&instance->pdev->dev, "%s, LD count: 0x%x\n",
+                                __func__, ld_count);
+
                if (ld_count > instance->fw_supported_vd_count)
                        break;
 
@@ -4501,6 +4629,10 @@ megasas_get_ld_list(struct megasas_instance *instance)
                        if (ci->ldList[ld_index].state != 0) {
                                ids = ci->ldList[ld_index].ref.targetId;
                                instance->ld_ids[ids] = ci->ldList[ld_index].ref.targetId;
+                               if (megasas_dbg_lvl & LD_PD_DEBUG)
+                                       dev_info(&instance->pdev->dev,
+                                                "LD%d: targetID: 0x%03x\n",
+                                                ld_index, ids);
                        }
                }
 
@@ -4604,6 +4736,10 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
        case DCMD_SUCCESS:
                tgtid_count = le32_to_cpu(ci->count);
 
+               if (megasas_dbg_lvl & LD_PD_DEBUG)
+                       dev_info(&instance->pdev->dev, "%s, LD count: 0x%x\n",
+                                __func__, tgtid_count);
+
                if ((tgtid_count > (instance->fw_supported_vd_count)))
                        break;
 
@@ -4611,6 +4747,9 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
                for (ld_index = 0; ld_index < tgtid_count; ld_index++) {
                        ids = ci->targetId[ld_index];
                        instance->ld_ids[ids] = ci->targetId[ld_index];
+                       if (megasas_dbg_lvl & LD_PD_DEBUG)
+                               dev_info(&instance->pdev->dev, "LD%d: targetID: 0x%03x\n",
+                                        ld_index, ci->targetId[ld_index]);
                }
 
                break;
@@ -4690,6 +4829,13 @@ megasas_host_device_list_query(struct megasas_instance *instance,
                 */
                count = le32_to_cpu(ci->count);
 
+               if (count > (MEGASAS_MAX_PD + MAX_LOGICAL_DRIVES_EXT))
+                       break;
+
+               if (megasas_dbg_lvl & LD_PD_DEBUG)
+                       dev_info(&instance->pdev->dev, "%s, Device count: 0x%x\n",
+                                __func__, count);
+
                memset(instance->local_pd_list, 0,
                       MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
                memset(instance->ld_ids, 0xff, MAX_LOGICAL_DRIVES_EXT);
@@ -4701,8 +4847,16 @@ megasas_host_device_list_query(struct megasas_instance *instance,
                                                ci->host_device_list[i].scsi_type;
                                instance->local_pd_list[target_id].driveState =
                                                MR_PD_STATE_SYSTEM;
+                               if (megasas_dbg_lvl & LD_PD_DEBUG)
+                                       dev_info(&instance->pdev->dev,
+                                                "Device %d: PD targetID: 0x%03x deviceType:0x%x\n",
+                                                i, target_id, ci->host_device_list[i].scsi_type);
                        } else {
                                instance->ld_ids[target_id] = target_id;
+                               if (megasas_dbg_lvl & LD_PD_DEBUG)
+                                       dev_info(&instance->pdev->dev,
+                                                "Device %d: LD targetID: 0x%03x\n",
+                                                i, target_id);
                        }
                }
 
@@ -4714,8 +4868,10 @@ megasas_host_device_list_query(struct megasas_instance *instance,
                switch (dcmd_timeout_ocr_possible(instance)) {
                case INITIATE_OCR:
                        cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+                       mutex_unlock(&instance->reset_mutex);
                        megasas_reset_fusion(instance->host,
                                MFI_IO_TIMEOUT_OCR);
+                       mutex_lock(&instance->reset_mutex);
                        break;
                case KILL_ADAPTER:
                        megaraid_sas_kill_hba(instance);
@@ -4863,8 +5019,10 @@ void megasas_get_snapdump_properties(struct megasas_instance *instance)
                switch (dcmd_timeout_ocr_possible(instance)) {
                case INITIATE_OCR:
                        cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+                       mutex_unlock(&instance->reset_mutex);
                        megasas_reset_fusion(instance->host,
                                MFI_IO_TIMEOUT_OCR);
+                       mutex_lock(&instance->reset_mutex);
                        break;
                case KILL_ADAPTER:
                        megaraid_sas_kill_hba(instance);
@@ -4943,6 +5101,7 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
                le32_to_cpus((u32 *)&ci->adapterOperations2);
                le32_to_cpus((u32 *)&ci->adapterOperations3);
                le16_to_cpus((u16 *)&ci->adapter_operations4);
+               le32_to_cpus((u32 *)&ci->adapter_operations5);
 
                /* Update the latest Ext VD info.
                 * From Init path, store current firmware details.
@@ -4950,12 +5109,14 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
                 * in case of Firmware upgrade without system reboot.
                 */
                megasas_update_ext_vd_details(instance);
-               instance->use_seqnum_jbod_fp =
+               instance->support_seqnum_jbod_fp =
                        ci->adapterOperations3.useSeqNumJbodFP;
                instance->support_morethan256jbod =
                        ci->adapter_operations4.support_pd_map_target_id;
                instance->support_nvme_passthru =
                        ci->adapter_operations4.support_nvme_passthru;
+               instance->support_pci_lane_margining =
+                       ci->adapter_operations5.support_pci_lane_margining;
                instance->task_abort_tmo = ci->TaskAbortTO;
                instance->max_reset_tmo = ci->MaxResetTO;
 
@@ -4987,6 +5148,10 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
                dev_info(&instance->pdev->dev,
                         "FW provided TM TaskAbort/Reset timeout\t: %d secs/%d secs\n",
                         instance->task_abort_tmo, instance->max_reset_tmo);
+               dev_info(&instance->pdev->dev, "JBOD sequence map support\t: %s\n",
+                        instance->support_seqnum_jbod_fp ? "Yes" : "No");
+               dev_info(&instance->pdev->dev, "PCI Lane Margining support\t: %s\n",
+                        instance->support_pci_lane_margining ? "Yes" : "No");
 
                break;
 
@@ -4994,8 +5159,10 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
                switch (dcmd_timeout_ocr_possible(instance)) {
                case INITIATE_OCR:
                        cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+                       mutex_unlock(&instance->reset_mutex);
                        megasas_reset_fusion(instance->host,
                                MFI_IO_TIMEOUT_OCR);
+                       mutex_lock(&instance->reset_mutex);
                        break;
                case KILL_ADAPTER:
                        megaraid_sas_kill_hba(instance);
@@ -5262,6 +5429,25 @@ fail_alloc_cmds:
        return 1;
 }
 
+static
+void megasas_setup_irq_poll(struct megasas_instance *instance)
+{
+       struct megasas_irq_context *irq_ctx;
+       u32 count, i;
+
+       count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+
+       /* Initialize IRQ poll */
+       for (i = 0; i < count; i++) {
+               irq_ctx = &instance->irq_context[i];
+               irq_ctx->os_irq = pci_irq_vector(instance->pdev, i);
+               irq_ctx->irq_poll_scheduled = false;
+               irq_poll_init(&irq_ctx->irqpoll,
+                             instance->threshold_reply_count,
+                             megasas_irqpoll);
+       }
+}
+
 /*
  * megasas_setup_irqs_ioapic -         register legacy interrupts.
  * @instance:                          Adapter soft state
@@ -5286,6 +5472,8 @@ megasas_setup_irqs_ioapic(struct megasas_instance *instance)
                                __func__, __LINE__);
                return -1;
        }
+       instance->perf_mode = MR_LATENCY_PERF_MODE;
+       instance->low_latency_index_start = 0;
        return 0;
 }
 
@@ -5320,6 +5508,7 @@ megasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe)
                                         &instance->irq_context[j]);
                        /* Retry irq register for IO_APIC*/
                        instance->msix_vectors = 0;
+                       instance->msix_load_balance = false;
                        if (is_probe) {
                                pci_free_irq_vectors(instance->pdev);
                                return megasas_setup_irqs_ioapic(instance);
@@ -5328,6 +5517,7 @@ megasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe)
                        }
                }
        }
+
        return 0;
 }
 
@@ -5340,6 +5530,16 @@ static void
 megasas_destroy_irqs(struct megasas_instance *instance) {
 
        int i;
+       int count;
+       struct megasas_irq_context *irq_ctx;
+
+       count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+       if (instance->adapter_type != MFI_SERIES) {
+               for (i = 0; i < count; i++) {
+                       irq_ctx = &instance->irq_context[i];
+                       irq_poll_disable(&irq_ctx->irqpoll);
+               }
+       }
 
        if (instance->msix_vectors)
                for (i = 0; i < instance->msix_vectors; i++) {
@@ -5368,10 +5568,12 @@ megasas_setup_jbod_map(struct megasas_instance *instance)
        pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) +
                (sizeof(struct MR_PD_CFG_SEQ) * (MAX_PHYSICAL_DEVICES - 1));
 
+       instance->use_seqnum_jbod_fp =
+               instance->support_seqnum_jbod_fp;
        if (reset_devices || !fusion ||
-               !instance->ctrl_info_buf->adapterOperations3.useSeqNumJbodFP) {
+               !instance->support_seqnum_jbod_fp) {
                dev_info(&instance->pdev->dev,
-                       "Jbod map is not supported %s %d\n",
+                       "JBOD sequence map is disabled %s %d\n",
                        __func__, __LINE__);
                instance->use_seqnum_jbod_fp = false;
                return;
@@ -5410,9 +5612,11 @@ skip_alloc:
 static void megasas_setup_reply_map(struct megasas_instance *instance)
 {
        const struct cpumask *mask;
-       unsigned int queue, cpu;
+       unsigned int queue, cpu, low_latency_index_start;
 
-       for (queue = 0; queue < instance->msix_vectors; queue++) {
+       low_latency_index_start = instance->low_latency_index_start;
+
+       for (queue = low_latency_index_start; queue < instance->msix_vectors; queue++) {
                mask = pci_irq_get_affinity(instance->pdev, queue);
                if (!mask)
                        goto fallback;
@@ -5423,8 +5627,14 @@ static void megasas_setup_reply_map(struct megasas_instance *instance)
        return;
 
 fallback:
-       for_each_possible_cpu(cpu)
-               instance->reply_map[cpu] = cpu % instance->msix_vectors;
+       queue = low_latency_index_start;
+       for_each_possible_cpu(cpu) {
+               instance->reply_map[cpu] = queue;
+               if (queue == (instance->msix_vectors - 1))
+                       queue = low_latency_index_start;
+               else
+                       queue++;
+       }
 }
 
 /**
@@ -5461,6 +5671,89 @@ int megasas_get_device_list(struct megasas_instance *instance)
 
        return SUCCESS;
 }
+
+/**
+ * megasas_set_high_iops_queue_affinity_hint - Set affinity hint for high IOPS queues
+ * @instance:                                  Adapter soft state
+ * return:                                     void
+ */
+static inline void
+megasas_set_high_iops_queue_affinity_hint(struct megasas_instance *instance)
+{
+       int i;
+       int local_numa_node;
+
+       if (instance->perf_mode == MR_BALANCED_PERF_MODE) {
+               local_numa_node = dev_to_node(&instance->pdev->dev);
+
+               for (i = 0; i < instance->low_latency_index_start; i++)
+                       irq_set_affinity_hint(pci_irq_vector(instance->pdev, i),
+                               cpumask_of_node(local_numa_node));
+       }
+}
+
+static int
+__megasas_alloc_irq_vectors(struct megasas_instance *instance)
+{
+       int i, irq_flags;
+       struct irq_affinity desc = { .pre_vectors = instance->low_latency_index_start };
+       struct irq_affinity *descp = &desc;
+
+       irq_flags = PCI_IRQ_MSIX;
+
+       if (instance->smp_affinity_enable)
+               irq_flags |= PCI_IRQ_AFFINITY;
+       else
+               descp = NULL;
+
+       i = pci_alloc_irq_vectors_affinity(instance->pdev,
+               instance->low_latency_index_start,
+               instance->msix_vectors, irq_flags, descp);
+
+       return i;
+}
+
+/**
+ * megasas_alloc_irq_vectors - Allocate IRQ vectors/enable MSI-x vectors
+ * @instance:                  Adapter soft state
+ * return:                     void
+ */
+static void
+megasas_alloc_irq_vectors(struct megasas_instance *instance)
+{
+       int i;
+       unsigned int num_msix_req;
+
+       i = __megasas_alloc_irq_vectors(instance);
+
+       if ((instance->perf_mode == MR_BALANCED_PERF_MODE) &&
+           (i != instance->msix_vectors)) {
+               if (instance->msix_vectors)
+                       pci_free_irq_vectors(instance->pdev);
+               /* Disable Balanced IOPS mode and try realloc vectors */
+               instance->perf_mode = MR_LATENCY_PERF_MODE;
+               instance->low_latency_index_start = 1;
+               num_msix_req = num_online_cpus() + instance->low_latency_index_start;
+
+               instance->msix_vectors = min(num_msix_req,
+                               instance->msix_vectors);
+
+               i = __megasas_alloc_irq_vectors(instance);
+
+       }
+
+       dev_info(&instance->pdev->dev,
+               "requested/available msix %d/%d\n", instance->msix_vectors, i);
+
+       if (i > 0)
+               instance->msix_vectors = i;
+       else
+               instance->msix_vectors = 0;
+
+       if (instance->smp_affinity_enable)
+               megasas_set_high_iops_queue_affinity_hint(instance);
+}
+
 /**
  * megasas_init_fw -   Initializes the FW
  * @instance:          Adapter soft state
@@ -5474,12 +5767,15 @@ static int megasas_init_fw(struct megasas_instance *instance)
        u32 max_sectors_2, tmp_sectors, msix_enable;
        u32 scratch_pad_1, scratch_pad_2, scratch_pad_3, status_reg;
        resource_size_t base_addr;
+       void *base_addr_phys;
        struct megasas_ctrl_info *ctrl_info = NULL;
        unsigned long bar_list;
-       int i, j, loop, fw_msix_count = 0;
+       int i, j, loop;
        struct IOV_111 *iovPtr;
        struct fusion_context *fusion;
-       bool do_adp_reset = true;
+       bool intr_coalescing;
+       unsigned int num_msix_req;
+       u16 lnksta, speed;
 
        fusion = instance->ctrl_context;
 
@@ -5500,6 +5796,11 @@ static int megasas_init_fw(struct megasas_instance *instance)
                goto fail_ioremap;
        }
 
+       base_addr_phys = &base_addr;
+       dev_printk(KERN_DEBUG, &instance->pdev->dev,
+                  "BAR:0x%lx  BAR's base_addr(phys):%pa  mapped virt_addr:0x%p\n",
+                  instance->bar, base_addr_phys, instance->reg_set);
+
        if (instance->adapter_type != MFI_SERIES)
                instance->instancet = &megasas_instance_template_fusion;
        else {
@@ -5526,29 +5827,35 @@ static int megasas_init_fw(struct megasas_instance *instance)
        }
 
        if (megasas_transition_to_ready(instance, 0)) {
-               if (instance->adapter_type >= INVADER_SERIES) {
+               dev_info(&instance->pdev->dev,
+                        "Failed to transition controller to ready from %s!\n",
+                        __func__);
+               if (instance->adapter_type != MFI_SERIES) {
                        status_reg = instance->instancet->read_fw_status_reg(
                                        instance);
-                       do_adp_reset = status_reg & MFI_RESET_ADAPTER;
-               }
-
-               if (do_adp_reset) {
+                       if (status_reg & MFI_RESET_ADAPTER) {
+                               if (megasas_adp_reset_wait_for_ready
+                                       (instance, true, 0) == FAILED)
+                                       goto fail_ready_state;
+                       } else {
+                               goto fail_ready_state;
+                       }
+               } else {
                        atomic_set(&instance->fw_reset_no_pci_access, 1);
                        instance->instancet->adp_reset
                                (instance, instance->reg_set);
                        atomic_set(&instance->fw_reset_no_pci_access, 0);
-                       dev_info(&instance->pdev->dev,
-                                "FW restarted successfully from %s!\n",
-                                __func__);
 
                        /*waiting for about 30 second before retry*/
                        ssleep(30);
 
                        if (megasas_transition_to_ready(instance, 0))
                                goto fail_ready_state;
-               } else {
-                       goto fail_ready_state;
                }
+
+               dev_info(&instance->pdev->dev,
+                        "FW restarted successfully from %s!\n",
+                        __func__);
        }
 
        megasas_init_ctrl_params(instance);
@@ -5573,11 +5880,21 @@ static int megasas_init_fw(struct megasas_instance *instance)
                        MR_MAX_RAID_MAP_SIZE_MASK);
        }
 
+       switch (instance->adapter_type) {
+       case VENTURA_SERIES:
+               fusion->pcie_bw_limitation = true;
+               break;
+       case AERO_SERIES:
+               fusion->r56_div_offload = true;
+               break;
+       default:
+               break;
+       }
+
        /* Check if MSI-X is supported while in ready state */
        msix_enable = (instance->instancet->read_fw_status_reg(instance) &
                       0x4000000) >> 0x1a;
        if (msix_enable && !msix_disable) {
-               int irq_flags = PCI_IRQ_MSIX;
 
                scratch_pad_1 = megasas_readl
                        (instance, &instance->reg_set->outbound_scratch_pad_1);
@@ -5587,7 +5904,6 @@ static int megasas_init_fw(struct megasas_instance *instance)
                                /* Thunderbolt Series*/
                                instance->msix_vectors = (scratch_pad_1
                                        & MR_MAX_REPLY_QUEUES_OFFSET) + 1;
-                               fw_msix_count = instance->msix_vectors;
                        } else {
                                instance->msix_vectors = ((scratch_pad_1
                                        & MR_MAX_REPLY_QUEUES_EXT_OFFSET)
@@ -5616,7 +5932,12 @@ static int megasas_init_fw(struct megasas_instance *instance)
                                if (rdpq_enable)
                                        instance->is_rdpq = (scratch_pad_1 & MR_RDPQ_MODE_OFFSET) ?
                                                                1 : 0;
-                               fw_msix_count = instance->msix_vectors;
+
+                               if (!instance->msix_combined) {
+                                       instance->msix_load_balance = true;
+                                       instance->smp_affinity_enable = false;
+                               }
+
                                /* Save 1-15 reply post index address to local memory
                                 * Index 0 is already saved from reg offset
                                 * MPI2_REPLY_POST_HOST_INDEX_OFFSET
@@ -5629,22 +5950,91 @@ static int megasas_init_fw(struct megasas_instance *instance)
                                                + (loop * 0x10));
                                }
                        }
+
+                       dev_info(&instance->pdev->dev,
+                                "firmware supports msix\t: (%d)",
+                                instance->msix_vectors);
                        if (msix_vectors)
                                instance->msix_vectors = min(msix_vectors,
                                        instance->msix_vectors);
                } else /* MFI adapters */
                        instance->msix_vectors = 1;
-               /* Don't bother allocating more MSI-X vectors than cpus */
-               instance->msix_vectors = min(instance->msix_vectors,
-                                            (unsigned int)num_online_cpus());
-               if (smp_affinity_enable)
-                       irq_flags |= PCI_IRQ_AFFINITY;
-               i = pci_alloc_irq_vectors(instance->pdev, 1,
-                                         instance->msix_vectors, irq_flags);
-               if (i > 0)
-                       instance->msix_vectors = i;
+
+
+               /*
+                * For Aero (if some conditions are met), driver will configure a
+                * few additional reply queues with interrupt coalescing enabled.
+                * These queues with interrupt coalescing enabled are called
+                * High IOPS queues and rest of reply queues (based on number of
+                * logical CPUs) are termed as Low latency queues.
+                *
+                * Total Number of reply queues = High IOPS queues + low latency queues
+                *
+                * For rest of fusion adapters, 1 additional reply queue will be
+                * reserved for management commands, rest of reply queues
+                * (based on number of logical CPUs) will be used for IOs and
+                * referenced as IO queues.
+                * Total Number of reply queues = 1 + IO queues
+                *
+                * MFI adapters supports single MSI-x so single reply queue
+                * will be used for IO and management commands.
+                */
+
+               intr_coalescing = (scratch_pad_1 & MR_INTR_COALESCING_SUPPORT_OFFSET) ?
+                                                               true : false;
+               if (intr_coalescing &&
+                       (num_online_cpus() >= MR_HIGH_IOPS_QUEUE_COUNT) &&
+                       (instance->msix_vectors == MEGASAS_MAX_MSIX_QUEUES))
+                       instance->perf_mode = MR_BALANCED_PERF_MODE;
                else
-                       instance->msix_vectors = 0;
+                       instance->perf_mode = MR_LATENCY_PERF_MODE;
+
+
+               if (instance->adapter_type == AERO_SERIES) {
+                       pcie_capability_read_word(instance->pdev, PCI_EXP_LNKSTA, &lnksta);
+                       speed = lnksta & PCI_EXP_LNKSTA_CLS;
+
+                       /*
+                        * For Aero, if PCIe link speed is <16 GT/s, then driver should operate
+                        * in latency perf mode and enable R1 PCI bandwidth algorithm
+                        */
+                       if (speed < 0x4) {
+                               instance->perf_mode = MR_LATENCY_PERF_MODE;
+                               fusion->pcie_bw_limitation = true;
+                       }
+
+                       /*
+                        * Performance mode settings provided through module parameter-perf_mode will
+                        * take affect only for:
+                        * 1. Aero family of adapters.
+                        * 2. When user sets module parameter- perf_mode in range of 0-2.
+                        */
+                       if ((perf_mode >= MR_BALANCED_PERF_MODE) &&
+                               (perf_mode <= MR_LATENCY_PERF_MODE))
+                               instance->perf_mode = perf_mode;
+                       /*
+                        * If intr coalescing is not supported by controller FW, then IOPS
+                        * and Balanced modes are not feasible.
+                        */
+                       if (!intr_coalescing)
+                               instance->perf_mode = MR_LATENCY_PERF_MODE;
+
+               }
+
+               if (instance->perf_mode == MR_BALANCED_PERF_MODE)
+                       instance->low_latency_index_start =
+                               MR_HIGH_IOPS_QUEUE_COUNT;
+               else
+                       instance->low_latency_index_start = 1;
+
+               num_msix_req = num_online_cpus() + instance->low_latency_index_start;
+
+               instance->msix_vectors = min(num_msix_req,
+                               instance->msix_vectors);
+
+               megasas_alloc_irq_vectors(instance);
+               if (!instance->msix_vectors)
+                       instance->msix_load_balance = false;
        }
        /*
         * MSI-X host index 0 is common for all adapter.
@@ -5668,8 +6058,6 @@ static int megasas_init_fw(struct megasas_instance *instance)
 
        megasas_setup_reply_map(instance);
 
-       dev_info(&instance->pdev->dev,
-               "firmware supports msix\t: (%d)", fw_msix_count);
        dev_info(&instance->pdev->dev,
                "current msix/online cpus\t: (%d/%d)\n",
                instance->msix_vectors, (unsigned int)num_online_cpus());
@@ -5707,6 +6095,9 @@ static int megasas_init_fw(struct megasas_instance *instance)
                megasas_setup_irqs_ioapic(instance))
                goto fail_init_adapter;
 
+       if (instance->adapter_type != MFI_SERIES)
+               megasas_setup_irq_poll(instance);
+
        instance->instancet->enable_intr(instance);
 
        dev_info(&instance->pdev->dev, "INIT adapter done\n");
@@ -5833,8 +6224,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
                instance->UnevenSpanSupport ? "yes" : "no");
        dev_info(&instance->pdev->dev, "firmware crash dump     : %s\n",
                instance->crash_dump_drv_support ? "yes" : "no");
-       dev_info(&instance->pdev->dev, "jbod sync map           : %s\n",
-               instance->use_seqnum_jbod_fp ? "yes" : "no");
+       dev_info(&instance->pdev->dev, "JBOD sequence map       : %s\n",
+               instance->use_seqnum_jbod_fp ? "enabled" : "disabled");
 
        instance->max_sectors_per_req = instance->max_num_sge *
                                                SGE_BUFFER_SIZE / 512;
@@ -6197,8 +6588,10 @@ megasas_get_target_prop(struct megasas_instance *instance,
                switch (dcmd_timeout_ocr_possible(instance)) {
                case INITIATE_OCR:
                        cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+                       mutex_unlock(&instance->reset_mutex);
                        megasas_reset_fusion(instance->host,
                                             MFI_IO_TIMEOUT_OCR);
+                       mutex_lock(&instance->reset_mutex);
                        break;
                case KILL_ADAPTER:
                        megaraid_sas_kill_hba(instance);
@@ -6748,6 +7141,7 @@ static inline void megasas_init_ctrl_params(struct megasas_instance *instance)
        INIT_LIST_HEAD(&instance->internal_reset_pending_q);
 
        atomic_set(&instance->fw_outstanding, 0);
+       atomic64_set(&instance->total_io_count, 0);
 
        init_waitqueue_head(&instance->int_cmd_wait_q);
        init_waitqueue_head(&instance->abort_cmd_wait_q);
@@ -6770,6 +7164,8 @@ static inline void megasas_init_ctrl_params(struct megasas_instance *instance)
        instance->last_time = 0;
        instance->disableOnlineCtrlReset = 1;
        instance->UnevenSpanSupport = 0;
+       instance->smp_affinity_enable = smp_affinity_enable ? true : false;
+       instance->msix_load_balance = false;
 
        if (instance->adapter_type != MFI_SERIES)
                INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq);
@@ -6791,6 +7187,12 @@ static int megasas_probe_one(struct pci_dev *pdev,
        u16 control = 0;
 
        switch (pdev->device) {
+       case PCI_DEVICE_ID_LSI_AERO_10E0:
+       case PCI_DEVICE_ID_LSI_AERO_10E3:
+       case PCI_DEVICE_ID_LSI_AERO_10E4:
+       case PCI_DEVICE_ID_LSI_AERO_10E7:
+               dev_err(&pdev->dev, "Adapter is in non secure mode\n");
+               return 1;
        case PCI_DEVICE_ID_LSI_AERO_10E1:
        case PCI_DEVICE_ID_LSI_AERO_10E5:
                dev_info(&pdev->dev, "Adapter is in configurable secure mode\n");
@@ -6910,6 +7312,8 @@ static int megasas_probe_one(struct pci_dev *pdev,
                goto fail_start_aen;
        }
 
+       megasas_setup_debugfs(instance);
+
        /* Get current SR-IOV LD/VF affiliation */
        if (instance->requestorId)
                megasas_get_ld_vf_affiliation(instance, 1);
@@ -7041,13 +7445,17 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
 static int
 megasas_suspend(struct pci_dev *pdev, pm_message_t state)
 {
-       struct Scsi_Host *host;
        struct megasas_instance *instance;
 
        instance = pci_get_drvdata(pdev);
-       host = instance->host;
+
+       if (!instance)
+               return 0;
+
        instance->unload = 1;
 
+       dev_info(&pdev->dev, "%s is called\n", __func__);
+
        /* Shutdown SR-IOV heartbeat timer */
        if (instance->requestorId && !instance->skip_heartbeat_timer_del)
                del_timer_sync(&instance->sriov_heartbeat_timer);
@@ -7097,11 +7505,16 @@ megasas_resume(struct pci_dev *pdev)
        int irq_flags = PCI_IRQ_LEGACY;
 
        instance = pci_get_drvdata(pdev);
+
+       if (!instance)
+               return 0;
+
        host = instance->host;
        pci_set_power_state(pdev, PCI_D0);
        pci_enable_wake(pdev, PCI_D0, 0);
        pci_restore_state(pdev);
 
+       dev_info(&pdev->dev, "%s is called\n", __func__);
        /*
         * PCI prepping: enable device set bus mastering and dma mask
         */
@@ -7133,7 +7546,7 @@ megasas_resume(struct pci_dev *pdev)
        /* Now re-enable MSI-X */
        if (instance->msix_vectors) {
                irq_flags = PCI_IRQ_MSIX;
-               if (smp_affinity_enable)
+               if (instance->smp_affinity_enable)
                        irq_flags |= PCI_IRQ_AFFINITY;
        }
        rval = pci_alloc_irq_vectors(instance->pdev, 1,
@@ -7171,6 +7584,9 @@ megasas_resume(struct pci_dev *pdev)
                        megasas_setup_irqs_ioapic(instance))
                goto fail_init_mfi;
 
+       if (instance->adapter_type != MFI_SERIES)
+               megasas_setup_irq_poll(instance);
+
        /* Re-launch SR-IOV heartbeat timer */
        if (instance->requestorId) {
                if (!megasas_sriov_start_heartbeat(instance, 0))
@@ -7261,6 +7677,10 @@ static void megasas_detach_one(struct pci_dev *pdev)
        u32 pd_seq_map_sz;
 
        instance = pci_get_drvdata(pdev);
+
+       if (!instance)
+               return;
+
        host = instance->host;
        fusion = instance->ctrl_context;
 
@@ -7374,6 +7794,8 @@ skip_firing_dcmds:
 
        megasas_free_ctrl_mem(instance);
 
+       megasas_destroy_debugfs(instance);
+
        scsi_host_put(host);
 
        pci_disable_device(pdev);
@@ -7387,6 +7809,9 @@ static void megasas_shutdown(struct pci_dev *pdev)
 {
        struct megasas_instance *instance = pci_get_drvdata(pdev);
 
+       if (!instance)
+               return;
+
        instance->unload = 1;
 
        if (megasas_wait_for_adapter_operational(instance))
@@ -7532,7 +7957,9 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
 
        if ((ioc->frame.hdr.cmd >= MFI_CMD_OP_COUNT) ||
            ((ioc->frame.hdr.cmd == MFI_CMD_NVME) &&
-           !instance->support_nvme_passthru)) {
+           !instance->support_nvme_passthru) ||
+           ((ioc->frame.hdr.cmd == MFI_CMD_TOOLBOX) &&
+           !instance->support_pci_lane_margining)) {
                dev_err(&instance->pdev->dev,
                        "Received invalid ioctl command 0x%x\n",
                        ioc->frame.hdr.cmd);
@@ -7568,10 +7995,13 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
                opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
 
        if (opcode == MR_DCMD_CTRL_SHUTDOWN) {
+               mutex_lock(&instance->reset_mutex);
                if (megasas_get_ctrl_info(instance) != DCMD_SUCCESS) {
                        megasas_return_cmd(instance, cmd);
+                       mutex_unlock(&instance->reset_mutex);
                        return -1;
                }
+               mutex_unlock(&instance->reset_mutex);
        }
 
        if (opcode == MR_DRIVER_SET_APP_CRASHDUMP_MODE) {
@@ -8013,6 +8443,14 @@ support_nvme_encapsulation_show(struct device_driver *dd, char *buf)
 
 static DRIVER_ATTR_RO(support_nvme_encapsulation);
 
+static ssize_t
+support_pci_lane_margining_show(struct device_driver *dd, char *buf)
+{
+       return sprintf(buf, "%u\n", support_pci_lane_margining);
+}
+
+static DRIVER_ATTR_RO(support_pci_lane_margining);
+
 static inline void megasas_remove_scsi_device(struct scsi_device *sdev)
 {
        sdev_printk(KERN_INFO, sdev, "SCSI device is removed\n");
@@ -8161,7 +8599,7 @@ megasas_aen_polling(struct work_struct *work)
        struct megasas_instance *instance = ev->instance;
        union megasas_evt_class_locale class_locale;
        int event_type = 0;
-       u32 seq_num, wait_time = MEGASAS_RESET_WAIT_TIME;
+       u32 seq_num;
        int error;
        u8  dcmd_ret = DCMD_SUCCESS;
 
@@ -8171,10 +8609,6 @@ megasas_aen_polling(struct work_struct *work)
                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 */
        mutex_lock(&instance->reset_mutex);
 
@@ -8286,6 +8720,7 @@ static int __init megasas_init(void)
        support_poll_for_event = 2;
        support_device_change = 1;
        support_nvme_encapsulation = true;
+       support_pci_lane_margining = true;
 
        memset(&megasas_mgmt_info, 0, sizeof(megasas_mgmt_info));
 
@@ -8301,6 +8736,8 @@ static int __init megasas_init(void)
 
        megasas_mgmt_majorno = rval;
 
+       megasas_init_debugfs();
+
        /*
         * Register ourselves as PCI hotplug module
         */
@@ -8340,8 +8777,17 @@ static int __init megasas_init(void)
        if (rval)
                goto err_dcf_support_nvme_encapsulation;
 
+       rval = driver_create_file(&megasas_pci_driver.driver,
+                                 &driver_attr_support_pci_lane_margining);
+       if (rval)
+               goto err_dcf_support_pci_lane_margining;
+
        return rval;
 
+err_dcf_support_pci_lane_margining:
+       driver_remove_file(&megasas_pci_driver.driver,
+                          &driver_attr_support_nvme_encapsulation);
+
 err_dcf_support_nvme_encapsulation:
        driver_remove_file(&megasas_pci_driver.driver,
                           &driver_attr_support_device_change);
@@ -8360,6 +8806,7 @@ err_dcf_rel_date:
 err_dcf_attr_ver:
        pci_unregister_driver(&megasas_pci_driver);
 err_pcidrv:
+       megasas_exit_debugfs();
        unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
        return rval;
 }
@@ -8380,8 +8827,11 @@ static void __exit megasas_exit(void)
        driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
        driver_remove_file(&megasas_pci_driver.driver,
                           &driver_attr_support_nvme_encapsulation);
+       driver_remove_file(&megasas_pci_driver.driver,
+                          &driver_attr_support_pci_lane_margining);
 
        pci_unregister_driver(&megasas_pci_driver);
+       megasas_exit_debugfs();
        unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
 }
 
diff --git a/drivers/scsi/megaraid/megaraid_sas_debugfs.c b/drivers/scsi/megaraid/megaraid_sas_debugfs.c
new file mode 100644 (file)
index 0000000..c697607
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ *  Linux MegaRAID driver for SAS based RAID controllers
+ *
+ *  Copyright (c) 2003-2018  LSI Corporation.
+ *  Copyright (c) 2003-2018  Avago Technologies.
+ *  Copyright (c) 2003-2018  Broadcom 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, see <http://www.gnu.org/licenses/>.
+ *
+ *  Authors: Broadcom Inc.
+ *           Kashyap Desai <kashyap.desai@broadcom.com>
+ *           Sumit Saxena <sumit.saxena@broadcom.com>
+ *           Shivasharan S <shivasharan.srikanteshwara@broadcom.com>
+ *
+ *  Send feedback to: megaraidlinux.pdl@broadcom.com
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/compat.h>
+#include <linux/irq_poll.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "megaraid_sas_fusion.h"
+#include "megaraid_sas.h"
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+
+struct dentry *megasas_debugfs_root;
+
+static ssize_t
+megasas_debugfs_read(struct file *filp, char __user *ubuf, size_t cnt,
+                     loff_t *ppos)
+{
+       struct megasas_debugfs_buffer *debug = filp->private_data;
+
+       if (!debug || !debug->buf)
+               return 0;
+
+       return simple_read_from_buffer(ubuf, cnt, ppos, debug->buf, debug->len);
+}
+
+static int
+megasas_debugfs_raidmap_open(struct inode *inode, struct file *file)
+{
+       struct megasas_instance *instance = inode->i_private;
+       struct megasas_debugfs_buffer *debug;
+       struct fusion_context *fusion;
+
+       fusion = instance->ctrl_context;
+
+       debug = kzalloc(sizeof(struct megasas_debugfs_buffer), GFP_KERNEL);
+       if (!debug)
+               return -ENOMEM;
+
+       debug->buf = (void *)fusion->ld_drv_map[(instance->map_id & 1)];
+       debug->len = fusion->drv_map_sz;
+       file->private_data = debug;
+
+       return 0;
+}
+
+static int
+megasas_debugfs_release(struct inode *inode, struct file *file)
+{
+       struct megasas_debug_buffer *debug = file->private_data;
+
+       if (!debug)
+               return 0;
+
+       file->private_data = NULL;
+       kfree(debug);
+       return 0;
+}
+
+static const struct file_operations megasas_debugfs_raidmap_fops = {
+       .owner          = THIS_MODULE,
+       .open           = megasas_debugfs_raidmap_open,
+       .read           = megasas_debugfs_read,
+       .release        = megasas_debugfs_release,
+};
+
+/*
+ * megasas_init_debugfs :      Create debugfs root for megaraid_sas driver
+ */
+void megasas_init_debugfs(void)
+{
+       megasas_debugfs_root = debugfs_create_dir("megaraid_sas", NULL);
+       if (!megasas_debugfs_root)
+               pr_info("Cannot create debugfs root\n");
+}
+
+/*
+ * megasas_exit_debugfs :      Remove debugfs root for megaraid_sas driver
+ */
+void megasas_exit_debugfs(void)
+{
+       debugfs_remove_recursive(megasas_debugfs_root);
+}
+
+/*
+ * megasas_setup_debugfs :     Setup debugfs per Fusion adapter
+ * instance:                           Soft instance of adapter
+ */
+void
+megasas_setup_debugfs(struct megasas_instance *instance)
+{
+       char name[64];
+       struct fusion_context *fusion;
+
+       fusion = instance->ctrl_context;
+
+       if (fusion) {
+               snprintf(name, sizeof(name),
+                        "scsi_host%d", instance->host->host_no);
+               if (!instance->debugfs_root) {
+                       instance->debugfs_root =
+                               debugfs_create_dir(name, megasas_debugfs_root);
+                       if (!instance->debugfs_root) {
+                               dev_err(&instance->pdev->dev,
+                                       "Cannot create per adapter debugfs directory\n");
+                               return;
+                       }
+               }
+
+               snprintf(name, sizeof(name), "raidmap_dump");
+               instance->raidmap_dump =
+                       debugfs_create_file(name, S_IRUGO,
+                                           instance->debugfs_root, instance,
+                                           &megasas_debugfs_raidmap_fops);
+               if (!instance->raidmap_dump) {
+                       dev_err(&instance->pdev->dev,
+                               "Cannot create raidmap debugfs file\n");
+                       debugfs_remove(instance->debugfs_root);
+                       return;
+               }
+       }
+
+}
+
+/*
+ * megasas_destroy_debugfs :   Destroy debugfs per Fusion adapter
+ * instance:                                   Soft instance of adapter
+ */
+void megasas_destroy_debugfs(struct megasas_instance *instance)
+{
+       debugfs_remove_recursive(instance->debugfs_root);
+}
+
+#else
+void megasas_init_debugfs(void)
+{
+}
+void megasas_exit_debugfs(void)
+{
+}
+void megasas_setup_debugfs(struct megasas_instance *instance)
+{
+}
+void megasas_destroy_debugfs(struct megasas_instance *instance)
+{
+}
+#endif /*CONFIG_DEBUG_FS*/
index 1263760..50b8c1b 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/compat.h>
 #include <linux/blkdev.h>
 #include <linux/poll.h>
+#include <linux/irq_poll.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -45,7 +46,7 @@
 
 #define LB_PENDING_CMDS_DEFAULT 4
 static unsigned int lb_pending_cmds = LB_PENDING_CMDS_DEFAULT;
-module_param(lb_pending_cmds, int, S_IRUGO);
+module_param(lb_pending_cmds, int, 0444);
 MODULE_PARM_DESC(lb_pending_cmds, "Change raid-1 load balancing outstanding "
        "threshold. Valid Values are 1-128. Default: 4");
 
@@ -888,6 +889,77 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
        return retval;
 }
 
+/*
+ * mr_get_phy_params_r56_rmw -  Calculate parameters for R56 CTIO write operation
+ * @instance:                  Adapter soft state
+ * @ld:                                LD index
+ * @stripNo:                   Strip Number
+ * @io_info:                   IO info structure pointer
+ * pRAID_Context:              RAID context pointer
+ * map:                                RAID map pointer
+ *
+ * This routine calculates the logical arm, data Arm, row number and parity arm
+ * for R56 CTIO write operation.
+ */
+static void mr_get_phy_params_r56_rmw(struct megasas_instance *instance,
+                           u32 ld, u64 stripNo,
+                           struct IO_REQUEST_INFO *io_info,
+                           struct RAID_CONTEXT_G35 *pRAID_Context,
+                           struct MR_DRV_RAID_MAP_ALL *map)
+{
+       struct MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
+       u8          span, dataArms, arms, dataArm, logArm;
+       s8          rightmostParityArm, PParityArm;
+       u64         rowNum;
+       u64 *pdBlock = &io_info->pdBlock;
+
+       dataArms = raid->rowDataSize;
+       arms = raid->rowSize;
+
+       rowNum =  mega_div64_32(stripNo, dataArms);
+       /* parity disk arm, first arm is 0 */
+       rightmostParityArm = (arms - 1) - mega_mod64(rowNum, arms);
+
+       /* logical arm within row */
+       logArm =  mega_mod64(stripNo, dataArms);
+       /* physical arm for data */
+       dataArm = mega_mod64((rightmostParityArm + 1 + logArm), arms);
+
+       if (raid->spanDepth == 1) {
+               span = 0;
+       } else {
+               span = (u8)MR_GetSpanBlock(ld, rowNum, pdBlock, map);
+               if (span == SPAN_INVALID)
+                       return;
+       }
+
+       if (raid->level == 6) {
+               /* P Parity arm, note this can go negative adjust if negative */
+               PParityArm = (arms - 2) - mega_mod64(rowNum, arms);
+
+               if (PParityArm < 0)
+                       PParityArm += arms;
+
+               /* rightmostParityArm is P-Parity for RAID 5 and Q-Parity for RAID */
+               pRAID_Context->flow_specific.r56_arm_map = rightmostParityArm;
+               pRAID_Context->flow_specific.r56_arm_map |=
+                                   (u16)(PParityArm << RAID_CTX_R56_P_ARM_SHIFT);
+       } else {
+               pRAID_Context->flow_specific.r56_arm_map |=
+                                   (u16)(rightmostParityArm << RAID_CTX_R56_P_ARM_SHIFT);
+       }
+
+       pRAID_Context->reg_lock_row_lba = cpu_to_le64(rowNum);
+       pRAID_Context->flow_specific.r56_arm_map |=
+                                  (u16)(logArm << RAID_CTX_R56_LOG_ARM_SHIFT);
+       cpu_to_le16s(&pRAID_Context->flow_specific.r56_arm_map);
+       pRAID_Context->span_arm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | dataArm;
+       pRAID_Context->raid_flags = (MR_RAID_FLAGS_IO_SUB_TYPE_R56_DIV_OFFLOAD <<
+                                   MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT);
+
+       return;
+}
+
 /*
 ******************************************************************************
 *
@@ -954,6 +1026,7 @@ MR_BuildRaidContext(struct megasas_instance *instance,
        stripSize = 1 << raid->stripeShift;
        stripe_mask = stripSize-1;
 
+       io_info->data_arms = raid->rowDataSize;
 
        /*
         * calculate starting row and stripe, and number of strips and rows
@@ -1095,6 +1168,13 @@ MR_BuildRaidContext(struct megasas_instance *instance,
        /* save pointer to raid->LUN array */
        *raidLUN = raid->LUN;
 
+       /* Aero R5/6 Division Offload for WRITE */
+       if (fusion->r56_div_offload && (raid->level >= 5) && !isRead) {
+               mr_get_phy_params_r56_rmw(instance, ld, start_strip, io_info,
+                                      (struct RAID_CONTEXT_G35 *)pRAID_Context,
+                                      map);
+               return true;
+       }
 
        /*Get Phy Params only if FP capable, or else leave it to MR firmware
          to do the calculation.*/
index 4dfa068..a32b3f0 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/poll.h>
 #include <linux/vmalloc.h>
 #include <linux/workqueue.h>
+#include <linux/irq_poll.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -86,6 +87,62 @@ static void megasas_fusion_crash_dump(struct megasas_instance *instance);
 extern u32 megasas_readl(struct megasas_instance *instance,
                         const volatile void __iomem *addr);
 
+/**
+ * megasas_adp_reset_wait_for_ready -  initiate chip reset and wait for
+ *                                     controller to come to ready state
+ * @instance -                         adapter's soft state
+ * @do_adp_reset -                     If true, do a chip reset
+ * @ocr_context -                      If called from OCR context this will
+ *                                     be set to 1, else 0
+ *
+ * This function initates a chip reset followed by a wait for controller to
+ * transition to ready state.
+ * During this, driver will block all access to PCI config space from userspace
+ */
+int
+megasas_adp_reset_wait_for_ready(struct megasas_instance *instance,
+                                bool do_adp_reset,
+                                int ocr_context)
+{
+       int ret = FAILED;
+
+       /*
+        * Block access to PCI config space from userspace
+        * when diag reset is initiated from driver
+        */
+       if (megasas_dbg_lvl & OCR_DEBUG)
+               dev_info(&instance->pdev->dev,
+                        "Block access to PCI config space %s %d\n",
+                        __func__, __LINE__);
+
+       pci_cfg_access_lock(instance->pdev);
+
+       if (do_adp_reset) {
+               if (instance->instancet->adp_reset
+                       (instance, instance->reg_set))
+                       goto out;
+       }
+
+       /* Wait for FW to become ready */
+       if (megasas_transition_to_ready(instance, ocr_context)) {
+               dev_warn(&instance->pdev->dev,
+                        "Failed to transition controller to ready for scsi%d.\n",
+                        instance->host->host_no);
+               goto out;
+       }
+
+       ret = SUCCESS;
+out:
+       if (megasas_dbg_lvl & OCR_DEBUG)
+               dev_info(&instance->pdev->dev,
+                        "Unlock access to PCI config space %s %d\n",
+                        __func__, __LINE__);
+
+       pci_cfg_access_unlock(instance->pdev);
+
+       return ret;
+}
+
 /**
  * megasas_check_same_4gb_region -     check if allocation
  *                                     crosses same 4GB boundary or not
@@ -133,7 +190,8 @@ megasas_enable_intr_fusion(struct megasas_instance *instance)
        writel(~MFI_FUSION_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
 
        /* Dummy readl to force pci flush */
-       readl(&regs->outbound_intr_mask);
+       dev_info(&instance->pdev->dev, "%s is called outbound_intr_mask:0x%08x\n",
+                __func__, readl(&regs->outbound_intr_mask));
 }
 
 /**
@@ -144,14 +202,14 @@ void
 megasas_disable_intr_fusion(struct megasas_instance *instance)
 {
        u32 mask = 0xFFFFFFFF;
-       u32 status;
        struct megasas_register_set __iomem *regs;
        regs = instance->reg_set;
        instance->mask_interrupts = 1;
 
        writel(mask, &regs->outbound_intr_mask);
        /* Dummy readl to force pci flush */
-       status = readl(&regs->outbound_intr_mask);
+       dev_info(&instance->pdev->dev, "%s is called outbound_intr_mask:0x%08x\n",
+                __func__, readl(&regs->outbound_intr_mask));
 }
 
 int
@@ -207,21 +265,17 @@ inline void megasas_return_cmd_fusion(struct megasas_instance *instance,
 }
 
 /**
- * megasas_fire_cmd_fusion -   Sends command to the FW
- * @instance:                  Adapter soft state
- * @req_desc:                  64bit Request descriptor
- *
- * Perform PCI Write.
+ * megasas_write_64bit_req_desc -      PCI writes 64bit request descriptor
+ * @instance:                          Adapter soft state
+ * @req_desc:                          64bit Request descriptor
  */
-
 static void
-megasas_fire_cmd_fusion(struct megasas_instance *instance,
+megasas_write_64bit_req_desc(struct megasas_instance *instance,
                union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc)
 {
 #if defined(writeq) && defined(CONFIG_64BIT)
        u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) |
                le32_to_cpu(req_desc->u.low));
-
        writeq(req_data, &instance->reg_set->inbound_low_queue_port);
 #else
        unsigned long flags;
@@ -234,6 +288,25 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance,
 #endif
 }
 
+/**
+ * megasas_fire_cmd_fusion -   Sends command to the FW
+ * @instance:                  Adapter soft state
+ * @req_desc:                  32bit or 64bit Request descriptor
+ *
+ * Perform PCI Write. AERO SERIES supports 32 bit Descriptor.
+ * Prior to AERO_SERIES support 64 bit Descriptor.
+ */
+static void
+megasas_fire_cmd_fusion(struct megasas_instance *instance,
+               union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc)
+{
+       if (instance->atomic_desc_support)
+               writel(le32_to_cpu(req_desc->u.low),
+                       &instance->reg_set->inbound_single_queue_port);
+       else
+               megasas_write_64bit_req_desc(instance, req_desc);
+}
+
 /**
  * megasas_fusion_update_can_queue -   Do all Adapter Queue depth related calculations here
  * @instance:                                                  Adapter soft state
@@ -924,6 +997,7 @@ wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
 {
        int i;
        struct megasas_header *frame_hdr = &cmd->frame->hdr;
+       u32 status_reg;
 
        u32 msecs = seconds * 1000;
 
@@ -933,6 +1007,12 @@ wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
        for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i += 20) {
                rmb();
                msleep(20);
+               if (!(i % 5000)) {
+                       status_reg = instance->instancet->read_fw_status_reg(instance)
+                                       & MFI_STATE_MASK;
+                       if (status_reg == MFI_STATE_FAULT)
+                               break;
+               }
        }
 
        if (frame_hdr->cmd_status == MFI_STAT_INVALID_STATUS)
@@ -966,6 +1046,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
        u32 scratch_pad_1;
        ktime_t time;
        bool cur_fw_64bit_dma_capable;
+       bool cur_intr_coalescing;
 
        fusion = instance->ctrl_context;
 
@@ -999,6 +1080,16 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
                goto fail_fw_init;
        }
 
+       cur_intr_coalescing = (scratch_pad_1 & MR_INTR_COALESCING_SUPPORT_OFFSET) ?
+                                                       true : false;
+
+       if ((instance->low_latency_index_start ==
+               MR_HIGH_IOPS_QUEUE_COUNT) && cur_intr_coalescing)
+               instance->perf_mode = MR_BALANCED_PERF_MODE;
+
+       dev_info(&instance->pdev->dev, "Performance mode :%s\n",
+               MEGASAS_PERF_MODE_2STR(instance->perf_mode));
+
        instance->fw_sync_cache_support = (scratch_pad_1 &
                MR_CAN_HANDLE_SYNC_CACHE_OFFSET) ? 1 : 0;
        dev_info(&instance->pdev->dev, "FW supports sync cache\t: %s\n",
@@ -1083,6 +1174,22 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
                cpu_to_le32(lower_32_bits(ioc_init_handle));
        init_frame->data_xfer_len = cpu_to_le32(sizeof(struct MPI2_IOC_INIT_REQUEST));
 
+       /*
+        * Each bit in replyqueue_mask represents one group of MSI-x vectors
+        * (each group has 8 vectors)
+        */
+       switch (instance->perf_mode) {
+       case MR_BALANCED_PERF_MODE:
+               init_frame->replyqueue_mask =
+                      cpu_to_le16(~(~0 << instance->low_latency_index_start/8));
+               break;
+       case MR_IOPS_PERF_MODE:
+               init_frame->replyqueue_mask =
+                      cpu_to_le16(~(~0 << instance->msix_vectors/8));
+               break;
+       }
+
+
        req_desc.u.low = cpu_to_le32(lower_32_bits(cmd->frame_phys_addr));
        req_desc.u.high = cpu_to_le32(upper_32_bits(cmd->frame_phys_addr));
        req_desc.MFAIo.RequestFlags =
@@ -1101,7 +1208,8 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
                        break;
        }
 
-       megasas_fire_cmd_fusion(instance, &req_desc);
+       /* For AERO also, IOC_INIT requires 64 bit descriptor write */
+       megasas_write_64bit_req_desc(instance, &req_desc);
 
        wait_and_poll(instance, cmd, MFI_IO_TIMEOUT_SECS);
 
@@ -1111,6 +1219,17 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
                goto fail_fw_init;
        }
 
+       if (instance->adapter_type >= AERO_SERIES) {
+               scratch_pad_1 = megasas_readl
+                       (instance, &instance->reg_set->outbound_scratch_pad_1);
+
+               instance->atomic_desc_support =
+                       (scratch_pad_1 & MR_ATOMIC_DESCRIPTOR_SUPPORT_OFFSET) ? 1 : 0;
+
+               dev_info(&instance->pdev->dev, "FW supports atomic descriptor\t: %s\n",
+                       instance->atomic_desc_support ? "Yes" : "No");
+       }
+
        return 0;
 
 fail_fw_init:
@@ -1133,7 +1252,7 @@ fail_fw_init:
 int
 megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) {
        int ret = 0;
-       u32 pd_seq_map_sz;
+       size_t pd_seq_map_sz;
        struct megasas_cmd *cmd;
        struct megasas_dcmd_frame *dcmd;
        struct fusion_context *fusion = instance->ctrl_context;
@@ -1142,9 +1261,7 @@ megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) {
 
        pd_sync = (void *)fusion->pd_seq_sync[(instance->pd_seq_map_id & 1)];
        pd_seq_h = fusion->pd_seq_phys[(instance->pd_seq_map_id & 1)];
-       pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) +
-                       (sizeof(struct MR_PD_CFG_SEQ) *
-                       (MAX_PHYSICAL_DEVICES - 1));
+       pd_seq_map_sz = struct_size(pd_sync, seq, MAX_PHYSICAL_DEVICES - 1);
 
        cmd = megasas_get_cmd(instance);
        if (!cmd) {
@@ -1625,6 +1742,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
        struct fusion_context *fusion;
        u32 scratch_pad_1;
        int i = 0, count;
+       u32 status_reg;
 
        fusion = instance->ctrl_context;
 
@@ -1707,8 +1825,21 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
        if (megasas_alloc_cmds_fusion(instance))
                goto fail_alloc_cmds;
 
-       if (megasas_ioc_init_fusion(instance))
-               goto fail_ioc_init;
+       if (megasas_ioc_init_fusion(instance)) {
+               status_reg = instance->instancet->read_fw_status_reg(instance);
+               if (((status_reg & MFI_STATE_MASK) == MFI_STATE_FAULT) &&
+                   (status_reg & MFI_RESET_ADAPTER)) {
+                       /* Do a chip reset and then retry IOC INIT once */
+                       if (megasas_adp_reset_wait_for_ready
+                               (instance, true, 0) == FAILED)
+                               goto fail_ioc_init;
+
+                       if (megasas_ioc_init_fusion(instance))
+                               goto fail_ioc_init;
+               } else {
+                       goto fail_ioc_init;
+               }
+       }
 
        megasas_display_intel_branding(instance);
        if (megasas_get_ctrl_info(instance)) {
@@ -1720,6 +1851,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
 
        instance->flag_ieee = 1;
        instance->r1_ldio_hint_default =  MR_R1_LDIO_PIGGYBACK_DEFAULT;
+       instance->threshold_reply_count = instance->max_fw_cmds / 4;
        fusion->fast_path_io = 0;
 
        if (megasas_allocate_raid_maps(instance))
@@ -1970,7 +2102,6 @@ megasas_is_prp_possible(struct megasas_instance *instance,
                            mega_mod64(sg_dma_address(sg_scmd),
                                       mr_nvme_pg_size)) {
                                build_prp = false;
-                               atomic_inc(&instance->sge_holes_type1);
                                break;
                        }
                }
@@ -1980,7 +2111,6 @@ megasas_is_prp_possible(struct megasas_instance *instance,
                                        sg_dma_len(sg_scmd)),
                                        mr_nvme_pg_size))) {
                                build_prp = false;
-                               atomic_inc(&instance->sge_holes_type2);
                                break;
                        }
                }
@@ -1989,7 +2119,6 @@ megasas_is_prp_possible(struct megasas_instance *instance,
                        if (mega_mod64(sg_dma_address(sg_scmd),
                                       mr_nvme_pg_size)) {
                                build_prp = false;
-                               atomic_inc(&instance->sge_holes_type3);
                                break;
                        }
                }
@@ -2122,7 +2251,6 @@ megasas_make_prp_nvme(struct megasas_instance *instance, struct scsi_cmnd *scmd,
        main_chain_element->Length =
                        cpu_to_le32(num_prp_in_chain * sizeof(u64));
 
-       atomic_inc(&instance->prp_sgl);
        return build_prp;
 }
 
@@ -2197,7 +2325,6 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
                        memset(sgl_ptr, 0, instance->max_chain_frame_sz);
                }
        }
-       atomic_inc(&instance->ieee_sgl);
 }
 
 /**
@@ -2509,9 +2636,10 @@ static void megasas_stream_detect(struct megasas_instance *instance,
  *
  */
 static void
-megasas_set_raidflag_cpu_affinity(union RAID_CONTEXT_UNION *praid_context,
-                                 struct MR_LD_RAID *raid, bool fp_possible,
-                                 u8 is_read, u32 scsi_buff_len)
+megasas_set_raidflag_cpu_affinity(struct fusion_context *fusion,
+                               union RAID_CONTEXT_UNION *praid_context,
+                               struct MR_LD_RAID *raid, bool fp_possible,
+                               u8 is_read, u32 scsi_buff_len)
 {
        u8 cpu_sel = MR_RAID_CTX_CPUSEL_0;
        struct RAID_CONTEXT_G35 *rctx_g35;
@@ -2569,11 +2697,11 @@ megasas_set_raidflag_cpu_affinity(union RAID_CONTEXT_UNION *praid_context,
         * vs MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS.
         * IO Subtype is not bitmap.
         */
-       if ((raid->level == 1) && (!is_read)) {
-               if (scsi_buff_len > MR_LARGE_IO_MIN_SIZE)
-                       praid_context->raid_context_g35.raid_flags =
-                               (MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT
-                               << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT);
+       if ((fusion->pcie_bw_limitation) && (raid->level == 1) && (!is_read) &&
+                       (scsi_buff_len > MR_LARGE_IO_MIN_SIZE)) {
+               praid_context->raid_context_g35.raid_flags =
+                       (MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT
+                       << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT);
        }
 }
 
@@ -2679,6 +2807,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
        io_info.r1_alt_dev_handle = MR_DEVHANDLE_INVALID;
        scsi_buff_len = scsi_bufflen(scp);
        io_request->DataLength = cpu_to_le32(scsi_buff_len);
+       io_info.data_arms = 1;
 
        if (scp->sc_data_direction == DMA_FROM_DEVICE)
                io_info.isRead = 1;
@@ -2698,8 +2827,19 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
                        fp_possible = (io_info.fpOkForIo > 0) ? true : false;
        }
 
-       cmd->request_desc->SCSIIO.MSIxIndex =
-               instance->reply_map[raw_smp_processor_id()];
+       if ((instance->perf_mode == MR_BALANCED_PERF_MODE) &&
+               atomic_read(&scp->device->device_busy) >
+               (io_info.data_arms * MR_DEVICE_HIGH_IOPS_DEPTH))
+               cmd->request_desc->SCSIIO.MSIxIndex =
+                       mega_mod64((atomic64_add_return(1, &instance->high_iops_outstanding) /
+                               MR_HIGH_IOPS_BATCH_COUNT), instance->low_latency_index_start);
+       else if (instance->msix_load_balance)
+               cmd->request_desc->SCSIIO.MSIxIndex =
+                       (mega_mod64(atomic64_add_return(1, &instance->total_io_count),
+                                   instance->msix_vectors));
+       else
+               cmd->request_desc->SCSIIO.MSIxIndex =
+                       instance->reply_map[raw_smp_processor_id()];
 
        if (instance->adapter_type >= VENTURA_SERIES) {
                /* FP for Optimal raid level 1.
@@ -2717,8 +2857,9 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
                                (instance->host->can_queue)) {
                                fp_possible = false;
                                atomic_dec(&instance->fw_outstanding);
-                       } else if ((scsi_buff_len > MR_LARGE_IO_MIN_SIZE) ||
-                                  (atomic_dec_if_positive(&mrdev_priv->r1_ldio_hint) > 0)) {
+                       } else if (fusion->pcie_bw_limitation &&
+                               ((scsi_buff_len > MR_LARGE_IO_MIN_SIZE) ||
+                                  (atomic_dec_if_positive(&mrdev_priv->r1_ldio_hint) > 0))) {
                                fp_possible = false;
                                atomic_dec(&instance->fw_outstanding);
                                if (scsi_buff_len > MR_LARGE_IO_MIN_SIZE)
@@ -2743,7 +2884,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
 
                /* If raid is NULL, set CPU affinity to default CPU0 */
                if (raid)
-                       megasas_set_raidflag_cpu_affinity(&io_request->RaidContext,
+                       megasas_set_raidflag_cpu_affinity(fusion, &io_request->RaidContext,
                                raid, fp_possible, io_info.isRead,
                                scsi_buff_len);
                else
@@ -2759,10 +2900,6 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
                        (MPI2_REQ_DESCRIPT_FLAGS_FP_IO
                         << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
                if (instance->adapter_type == INVADER_SERIES) {
-                       if (rctx->reg_lock_flags == REGION_TYPE_UNUSED)
-                               cmd->request_desc->SCSIIO.RequestFlags =
-                                       (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK <<
-                                       MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
                        rctx->type = MPI2_TYPE_CUDA;
                        rctx->nseg = 0x1;
                        io_request->IoFlags |= cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
@@ -2970,50 +3107,71 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
                << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT;
 
        /* If FW supports PD sequence number */
-       if (instance->use_seqnum_jbod_fp &&
-               instance->pd_list[pd_index].driveType == TYPE_DISK) {
-               /* TgtId must be incremented by 255 as jbod seq number is index
-                * below raid map
-                */
-                /* More than 256 PD/JBOD support for Ventura */
-               if (instance->support_morethan256jbod)
-                       pRAID_Context->virtual_disk_tgt_id =
-                               pd_sync->seq[pd_index].pd_target_id;
-               else
-                       pRAID_Context->virtual_disk_tgt_id =
-                               cpu_to_le16(device_id + (MAX_PHYSICAL_DEVICES - 1));
-               pRAID_Context->config_seq_num = pd_sync->seq[pd_index].seqNum;
-               io_request->DevHandle = pd_sync->seq[pd_index].devHandle;
-               if (instance->adapter_type >= VENTURA_SERIES) {
-                       io_request->RaidContext.raid_context_g35.routing_flags |=
-                               (1 << MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT);
-                       io_request->RaidContext.raid_context_g35.nseg_type |=
-                                                       (1 << RAID_CONTEXT_NSEG_SHIFT);
-                       io_request->RaidContext.raid_context_g35.nseg_type |=
-                                                       (MPI2_TYPE_CUDA << RAID_CONTEXT_TYPE_SHIFT);
+       if (instance->support_seqnum_jbod_fp) {
+               if (instance->use_seqnum_jbod_fp &&
+                       instance->pd_list[pd_index].driveType == TYPE_DISK) {
+
+                       /* More than 256 PD/JBOD support for Ventura */
+                       if (instance->support_morethan256jbod)
+                               pRAID_Context->virtual_disk_tgt_id =
+                                       pd_sync->seq[pd_index].pd_target_id;
+                       else
+                               pRAID_Context->virtual_disk_tgt_id =
+                                       cpu_to_le16(device_id +
+                                       (MAX_PHYSICAL_DEVICES - 1));
+                       pRAID_Context->config_seq_num =
+                               pd_sync->seq[pd_index].seqNum;
+                       io_request->DevHandle =
+                               pd_sync->seq[pd_index].devHandle;
+                       if (instance->adapter_type >= VENTURA_SERIES) {
+                               io_request->RaidContext.raid_context_g35.routing_flags |=
+                                       (1 << MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT);
+                               io_request->RaidContext.raid_context_g35.nseg_type |=
+                                       (1 << RAID_CONTEXT_NSEG_SHIFT);
+                               io_request->RaidContext.raid_context_g35.nseg_type |=
+                                       (MPI2_TYPE_CUDA << RAID_CONTEXT_TYPE_SHIFT);
+                       } else {
+                               pRAID_Context->type = MPI2_TYPE_CUDA;
+                               pRAID_Context->nseg = 0x1;
+                               pRAID_Context->reg_lock_flags |=
+                                       (MR_RL_FLAGS_SEQ_NUM_ENABLE |
+                                        MR_RL_FLAGS_GRANT_DESTINATION_CUDA);
+                       }
                } else {
-                       pRAID_Context->type = MPI2_TYPE_CUDA;
-                       pRAID_Context->nseg = 0x1;
-                       pRAID_Context->reg_lock_flags |=
-                               (MR_RL_FLAGS_SEQ_NUM_ENABLE|MR_RL_FLAGS_GRANT_DESTINATION_CUDA);
+                       pRAID_Context->virtual_disk_tgt_id =
+                               cpu_to_le16(device_id +
+                               (MAX_PHYSICAL_DEVICES - 1));
+                       pRAID_Context->config_seq_num = 0;
+                       io_request->DevHandle = cpu_to_le16(0xFFFF);
                }
-       } else if (fusion->fast_path_io) {
-               pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id);
-               pRAID_Context->config_seq_num = 0;
-               local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
-               io_request->DevHandle =
-                       local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
        } else {
-               /* Want to send all IO via FW path */
                pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id);
                pRAID_Context->config_seq_num = 0;
-               io_request->DevHandle = cpu_to_le16(0xFFFF);
+
+               if (fusion->fast_path_io) {
+                       local_map_ptr =
+                               fusion->ld_drv_map[(instance->map_id & 1)];
+                       io_request->DevHandle =
+                               local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
+               } else {
+                       io_request->DevHandle = cpu_to_le16(0xFFFF);
+               }
        }
 
        cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle;
 
-       cmd->request_desc->SCSIIO.MSIxIndex =
-               instance->reply_map[raw_smp_processor_id()];
+       if ((instance->perf_mode == MR_BALANCED_PERF_MODE) &&
+               atomic_read(&scmd->device->device_busy) > MR_DEVICE_HIGH_IOPS_DEPTH)
+               cmd->request_desc->SCSIIO.MSIxIndex =
+                       mega_mod64((atomic64_add_return(1, &instance->high_iops_outstanding) /
+                               MR_HIGH_IOPS_BATCH_COUNT), instance->low_latency_index_start);
+       else if (instance->msix_load_balance)
+               cmd->request_desc->SCSIIO.MSIxIndex =
+                       (mega_mod64(atomic64_add_return(1, &instance->total_io_count),
+                                   instance->msix_vectors));
+       else
+               cmd->request_desc->SCSIIO.MSIxIndex =
+                       instance->reply_map[raw_smp_processor_id()];
 
        if (!fp_possible) {
                /* system pd firmware path */
@@ -3193,9 +3351,9 @@ void megasas_prepare_secondRaid1_IO(struct megasas_instance *instance,
        r1_cmd->request_desc->SCSIIO.DevHandle = cmd->r1_alt_dev_handle;
        r1_cmd->io_request->DevHandle = cmd->r1_alt_dev_handle;
        r1_cmd->r1_alt_dev_handle = cmd->io_request->DevHandle;
-       cmd->io_request->RaidContext.raid_context_g35.smid.peer_smid =
+       cmd->io_request->RaidContext.raid_context_g35.flow_specific.peer_smid =
                        cpu_to_le16(r1_cmd->index);
-       r1_cmd->io_request->RaidContext.raid_context_g35.smid.peer_smid =
+       r1_cmd->io_request->RaidContext.raid_context_g35.flow_specific.peer_smid =
                        cpu_to_le16(cmd->index);
        /*MSIxIndex of both commands request descriptors should be same*/
        r1_cmd->request_desc->SCSIIO.MSIxIndex =
@@ -3313,7 +3471,7 @@ megasas_complete_r1_command(struct megasas_instance *instance,
 
        rctx_g35 = &cmd->io_request->RaidContext.raid_context_g35;
        fusion = instance->ctrl_context;
-       peer_smid = le16_to_cpu(rctx_g35->smid.peer_smid);
+       peer_smid = le16_to_cpu(rctx_g35->flow_specific.peer_smid);
 
        r1_cmd = fusion->cmd_list[peer_smid - 1];
        scmd_local = cmd->scmd;
@@ -3353,7 +3511,8 @@ megasas_complete_r1_command(struct megasas_instance *instance,
  * Completes all commands that is in reply descriptor queue
  */
 int
-complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
+complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex,
+                   struct megasas_irq_context *irq_context)
 {
        union MPI2_REPLY_DESCRIPTORS_UNION *desc;
        struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *reply_desc;
@@ -3486,7 +3645,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
                 * number of reply counts and still there are more replies in reply queue
                 * pending to be completed
                 */
-               if (threshold_reply_count >= THRESHOLD_REPLY_COUNT) {
+               if (threshold_reply_count >= instance->threshold_reply_count) {
                        if (instance->msix_combined)
                                writel(((MSIxIndex & 0x7) << 24) |
                                        fusion->last_reply_idx[MSIxIndex],
@@ -3496,23 +3655,46 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
                                        fusion->last_reply_idx[MSIxIndex],
                                        instance->reply_post_host_index_addr[0]);
                        threshold_reply_count = 0;
+                       if (irq_context) {
+                               if (!irq_context->irq_poll_scheduled) {
+                                       irq_context->irq_poll_scheduled = true;
+                                       irq_context->irq_line_enable = true;
+                                       irq_poll_sched(&irq_context->irqpoll);
+                               }
+                               return num_completed;
+                       }
                }
        }
 
-       if (!num_completed)
-               return IRQ_NONE;
+       if (num_completed) {
+               wmb();
+               if (instance->msix_combined)
+                       writel(((MSIxIndex & 0x7) << 24) |
+                               fusion->last_reply_idx[MSIxIndex],
+                               instance->reply_post_host_index_addr[MSIxIndex/8]);
+               else
+                       writel((MSIxIndex << 24) |
+                               fusion->last_reply_idx[MSIxIndex],
+                               instance->reply_post_host_index_addr[0]);
+               megasas_check_and_restore_queue_depth(instance);
+       }
+       return num_completed;
+}
 
-       wmb();
-       if (instance->msix_combined)
-               writel(((MSIxIndex & 0x7) << 24) |
-                       fusion->last_reply_idx[MSIxIndex],
-                       instance->reply_post_host_index_addr[MSIxIndex/8]);
-       else
-               writel((MSIxIndex << 24) |
-                       fusion->last_reply_idx[MSIxIndex],
-                       instance->reply_post_host_index_addr[0]);
-       megasas_check_and_restore_queue_depth(instance);
-       return IRQ_HANDLED;
+/**
+ * megasas_enable_irq_poll() - enable irqpoll
+ */
+static void megasas_enable_irq_poll(struct megasas_instance *instance)
+{
+       u32 count, i;
+       struct megasas_irq_context *irq_ctx;
+
+       count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+
+       for (i = 0; i < count; i++) {
+               irq_ctx = &instance->irq_context[i];
+               irq_poll_enable(&irq_ctx->irqpoll);
+       }
 }
 
 /**
@@ -3524,11 +3706,51 @@ void megasas_sync_irqs(unsigned long instance_addr)
        u32 count, i;
        struct megasas_instance *instance =
                (struct megasas_instance *)instance_addr;
+       struct megasas_irq_context *irq_ctx;
 
        count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
 
-       for (i = 0; i < count; i++)
+       for (i = 0; i < count; i++) {
                synchronize_irq(pci_irq_vector(instance->pdev, i));
+               irq_ctx = &instance->irq_context[i];
+               irq_poll_disable(&irq_ctx->irqpoll);
+               if (irq_ctx->irq_poll_scheduled) {
+                       irq_ctx->irq_poll_scheduled = false;
+                       enable_irq(irq_ctx->os_irq);
+               }
+       }
+}
+
+/**
+ * megasas_irqpoll() - process a queue for completed reply descriptors
+ * @irqpoll:   IRQ poll structure associated with queue to poll.
+ * @budget:    Threshold of reply descriptors to process per poll.
+ *
+ * Return: The number of entries processed.
+ */
+
+int megasas_irqpoll(struct irq_poll *irqpoll, int budget)
+{
+       struct megasas_irq_context *irq_ctx;
+       struct megasas_instance *instance;
+       int num_entries;
+
+       irq_ctx = container_of(irqpoll, struct megasas_irq_context, irqpoll);
+       instance = irq_ctx->instance;
+
+       if (irq_ctx->irq_line_enable) {
+               disable_irq(irq_ctx->os_irq);
+               irq_ctx->irq_line_enable = false;
+       }
+
+       num_entries = complete_cmd_fusion(instance, irq_ctx->MSIxIndex, irq_ctx);
+       if (num_entries < budget) {
+               irq_poll_complete(irqpoll);
+               irq_ctx->irq_poll_scheduled = false;
+               enable_irq(irq_ctx->os_irq);
+       }
+
+       return num_entries;
 }
 
 /**
@@ -3551,7 +3773,7 @@ megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
                return;
 
        for (MSIxIndex = 0 ; MSIxIndex < count; MSIxIndex++)
-               complete_cmd_fusion(instance, MSIxIndex);
+               complete_cmd_fusion(instance, MSIxIndex, NULL);
 }
 
 /**
@@ -3566,6 +3788,11 @@ irqreturn_t megasas_isr_fusion(int irq, void *devp)
        if (instance->mask_interrupts)
                return IRQ_NONE;
 
+#if defined(ENABLE_IRQ_POLL)
+       if (irq_context->irq_poll_scheduled)
+               return IRQ_HANDLED;
+#endif
+
        if (!instance->msix_vectors) {
                mfiStatus = instance->instancet->clear_intr(instance);
                if (!mfiStatus)
@@ -3578,7 +3805,8 @@ irqreturn_t megasas_isr_fusion(int irq, void *devp)
                return IRQ_HANDLED;
        }
 
-       return complete_cmd_fusion(instance, irq_context->MSIxIndex);
+       return complete_cmd_fusion(instance, irq_context->MSIxIndex, irq_context)
+                       ? IRQ_HANDLED : IRQ_NONE;
 }
 
 /**
@@ -3843,7 +4071,7 @@ megasas_check_reset_fusion(struct megasas_instance *instance,
 static inline void megasas_trigger_snap_dump(struct megasas_instance *instance)
 {
        int j;
-       u32 fw_state;
+       u32 fw_state, abs_state;
 
        if (!instance->disableOnlineCtrlReset) {
                dev_info(&instance->pdev->dev, "Trigger snap dump\n");
@@ -3853,11 +4081,13 @@ static inline void megasas_trigger_snap_dump(struct megasas_instance *instance)
        }
 
        for (j = 0; j < instance->snapdump_wait_time; j++) {
-               fw_state = instance->instancet->read_fw_status_reg(instance) &
-                               MFI_STATE_MASK;
+               abs_state = instance->instancet->read_fw_status_reg(instance);
+               fw_state = abs_state & MFI_STATE_MASK;
                if (fw_state == MFI_STATE_FAULT) {
-                       dev_err(&instance->pdev->dev,
-                               "Found FW in FAULT state, after snap dump trigger\n");
+                       dev_printk(KERN_ERR, &instance->pdev->dev,
+                                  "FW in FAULT state Fault code:0x%x subcode:0x%x func:%s\n",
+                                  abs_state & MFI_STATE_FAULT_CODE,
+                                  abs_state & MFI_STATE_FAULT_SUBCODE, __func__);
                        return;
                }
                msleep(1000);
@@ -3869,7 +4099,7 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
                                        int reason, int *convert)
 {
        int i, outstanding, retval = 0, hb_seconds_missed = 0;
-       u32 fw_state;
+       u32 fw_state, abs_state;
        u32 waittime_for_io_completion;
 
        waittime_for_io_completion =
@@ -3888,12 +4118,13 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
 
        for (i = 0; i < waittime_for_io_completion; i++) {
                /* Check if firmware is in fault state */
-               fw_state = instance->instancet->read_fw_status_reg(instance) &
-                               MFI_STATE_MASK;
+               abs_state = instance->instancet->read_fw_status_reg(instance);
+               fw_state = abs_state & MFI_STATE_MASK;
                if (fw_state == MFI_STATE_FAULT) {
-                       dev_warn(&instance->pdev->dev, "Found FW in FAULT state,"
-                              " will reset adapter scsi%d.\n",
-                               instance->host->host_no);
+                       dev_printk(KERN_ERR, &instance->pdev->dev,
+                                  "FW in FAULT state Fault code:0x%x subcode:0x%x func:%s\n",
+                                  abs_state & MFI_STATE_FAULT_CODE,
+                                  abs_state & MFI_STATE_FAULT_SUBCODE, __func__);
                        megasas_complete_cmd_dpc_fusion((unsigned long)instance);
                        if (instance->requestorId && reason) {
                                dev_warn(&instance->pdev->dev, "SR-IOV Found FW in FAULT"
@@ -4041,6 +4272,13 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
                                result = COMPLETE_CMD;
                        }
 
+                       break;
+               case MFI_CMD_TOOLBOX:
+                       if (!instance->support_pci_lane_margining) {
+                               cmd_mfi->frame->hdr.cmd_status = MFI_STAT_INVALID_CMD;
+                               result = COMPLETE_CMD;
+                       }
+
                        break;
                default:
                        break;
@@ -4265,6 +4503,7 @@ megasas_issue_tm(struct megasas_instance *instance, u16 device_handle,
                        instance->instancet->disable_intr(instance);
                        megasas_sync_irqs((unsigned long)instance);
                        instance->instancet->enable_intr(instance);
+                       megasas_enable_irq_poll(instance);
                        if (scsi_lookup->scmd == NULL)
                                break;
                }
@@ -4278,6 +4517,7 @@ megasas_issue_tm(struct megasas_instance *instance, u16 device_handle,
                megasas_sync_irqs((unsigned long)instance);
                rc = megasas_track_scsiio(instance, id, channel);
                instance->instancet->enable_intr(instance);
+               megasas_enable_irq_poll(instance);
 
                break;
        case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
@@ -4376,9 +4616,6 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd)
 
        instance = (struct megasas_instance *)scmd->device->host->hostdata;
 
-       scmd_printk(KERN_INFO, scmd, "task abort called for scmd(%p)\n", scmd);
-       scsi_print_command(scmd);
-
        if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
                dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
                "SCSI host:%d\n", instance->host->host_no);
@@ -4421,7 +4658,7 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd)
                goto out;
        }
        sdev_printk(KERN_INFO, scmd->device,
-               "attempting task abort! scmd(%p) tm_dev_handle 0x%x\n",
+               "attempting task abort! scmd(0x%p) tm_dev_handle 0x%x\n",
                scmd, devhandle);
 
        mr_device_priv_data->tm_busy = 1;
@@ -4432,9 +4669,12 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd)
        mr_device_priv_data->tm_busy = 0;
 
        mutex_unlock(&instance->reset_mutex);
-out:
-       sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n",
+       scmd_printk(KERN_INFO, scmd, "task abort %s!! scmd(0x%p)\n",
                        ((ret == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+out:
+       scsi_print_command(scmd);
+       if (megasas_dbg_lvl & TM_DEBUG)
+               megasas_dump_fusion_io(scmd);
 
        return ret;
 }
@@ -4457,9 +4697,6 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
 
        instance = (struct megasas_instance *)scmd->device->host->hostdata;
 
-       sdev_printk(KERN_INFO, scmd->device,
-                   "target reset called for scmd(%p)\n", scmd);
-
        if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
                dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
                "SCSI host:%d\n", instance->host->host_no);
@@ -4468,8 +4705,8 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
        }
 
        if (!mr_device_priv_data) {
-               sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
-                       "scmd(%p)\n", scmd);
+               sdev_printk(KERN_INFO, scmd->device,
+                           "device been deleted! scmd: (0x%p)\n", scmd);
                scmd->result = DID_NO_CONNECT << 16;
                ret = SUCCESS;
                goto out;
@@ -4492,7 +4729,7 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
        }
 
        sdev_printk(KERN_INFO, scmd->device,
-               "attempting target reset! scmd(%p) tm_dev_handle 0x%x\n",
+               "attempting target reset! scmd(0x%p) tm_dev_handle: 0x%x\n",
                scmd, devhandle);
        mr_device_priv_data->tm_busy = 1;
        ret = megasas_issue_tm(instance, devhandle,
@@ -4501,10 +4738,10 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
                        mr_device_priv_data);
        mr_device_priv_data->tm_busy = 0;
        mutex_unlock(&instance->reset_mutex);
-out:
-       scmd_printk(KERN_NOTICE, scmd, "megasas: target reset %s!!\n",
+       scmd_printk(KERN_NOTICE, scmd, "target reset %s!!\n",
                (ret == SUCCESS) ? "SUCCESS" : "FAILED");
 
+out:
        return ret;
 }
 
@@ -4549,12 +4786,14 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
        struct megasas_instance *instance;
        struct megasas_cmd_fusion *cmd_fusion, *r1_cmd;
        struct fusion_context *fusion;
-       u32 abs_state, status_reg, reset_adapter;
+       u32 abs_state, status_reg, reset_adapter, fpio_count = 0;
        u32 io_timeout_in_crash_mode = 0;
        struct scsi_cmnd *scmd_local = NULL;
        struct scsi_device *sdev;
        int ret_target_prop = DCMD_FAILED;
        bool is_target_prop = false;
+       bool do_adp_reset = true;
+       int max_reset_tries = MEGASAS_FUSION_MAX_RESET_TRIES;
 
        instance = (struct megasas_instance *)shost->hostdata;
        fusion = instance->ctrl_context;
@@ -4621,7 +4860,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
                if (convert)
                        reason = 0;
 
-               if (megasas_dbg_lvl & OCR_LOGS)
+               if (megasas_dbg_lvl & OCR_DEBUG)
                        dev_info(&instance->pdev->dev, "\nPending SCSI commands:\n");
 
                /* Now return commands back to the OS */
@@ -4634,13 +4873,17 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
                        }
                        scmd_local = cmd_fusion->scmd;
                        if (cmd_fusion->scmd) {
-                               if (megasas_dbg_lvl & OCR_LOGS) {
+                               if (megasas_dbg_lvl & OCR_DEBUG) {
                                        sdev_printk(KERN_INFO,
                                                cmd_fusion->scmd->device, "SMID: 0x%x\n",
                                                cmd_fusion->index);
-                                       scsi_print_command(cmd_fusion->scmd);
+                                       megasas_dump_fusion_io(cmd_fusion->scmd);
                                }
 
+                               if (cmd_fusion->io_request->Function ==
+                                       MPI2_FUNCTION_SCSI_IO_REQUEST)
+                                       fpio_count++;
+
                                scmd_local->result =
                                        megasas_check_mpio_paths(instance,
                                                        scmd_local);
@@ -4653,6 +4896,9 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
                        }
                }
 
+               dev_info(&instance->pdev->dev, "Outstanding fastpath IOs: %d\n",
+                       fpio_count);
+
                atomic_set(&instance->fw_outstanding, 0);
 
                status_reg = instance->instancet->read_fw_status_reg(instance);
@@ -4664,52 +4910,45 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
                        dev_warn(&instance->pdev->dev, "Reset not supported"
                               ", killing adapter scsi%d.\n",
                                instance->host->host_no);
-                       megaraid_sas_kill_hba(instance);
-                       instance->skip_heartbeat_timer_del = 1;
-                       retval = FAILED;
-                       goto out;
+                       goto kill_hba;
                }
 
                /* Let SR-IOV VF & PF sync up if there was a HB failure */
                if (instance->requestorId && !reason) {
                        msleep(MEGASAS_OCR_SETTLE_TIME_VF);
-                       goto transition_to_ready;
+                       do_adp_reset = false;
+                       max_reset_tries = MEGASAS_SRIOV_MAX_RESET_TRIES_VF;
                }
 
                /* Now try to reset the chip */
-               for (i = 0; i < MEGASAS_FUSION_MAX_RESET_TRIES; i++) {
-
-                       if (instance->instancet->adp_reset
-                               (instance, instance->reg_set))
+               for (i = 0; i < max_reset_tries; i++) {
+                       /*
+                        * Do adp reset and wait for
+                        * controller to transition to ready
+                        */
+                       if (megasas_adp_reset_wait_for_ready(instance,
+                               do_adp_reset, 1) == FAILED)
                                continue;
-transition_to_ready:
+
                        /* Wait for FW to become ready */
                        if (megasas_transition_to_ready(instance, 1)) {
                                dev_warn(&instance->pdev->dev,
                                        "Failed to transition controller to ready for "
                                        "scsi%d.\n", instance->host->host_no);
-                               if (instance->requestorId && !reason)
-                                       goto fail_kill_adapter;
-                               else
-                                       continue;
+                               continue;
                        }
                        megasas_reset_reply_desc(instance);
                        megasas_fusion_update_can_queue(instance, OCR_CONTEXT);
 
                        if (megasas_ioc_init_fusion(instance)) {
-                               if (instance->requestorId && !reason)
-                                       goto fail_kill_adapter;
-                               else
-                                       continue;
+                               continue;
                        }
 
                        if (megasas_get_ctrl_info(instance)) {
                                dev_info(&instance->pdev->dev,
                                        "Failed from %s %d\n",
                                        __func__, __LINE__);
-                               megaraid_sas_kill_hba(instance);
-                               retval = FAILED;
-                               goto out;
+                               goto kill_hba;
                        }
 
                        megasas_refire_mgmt_cmd(instance);
@@ -4738,7 +4977,7 @@ transition_to_ready:
                        clear_bit(MEGASAS_FUSION_IN_RESET,
                                  &instance->reset_flags);
                        instance->instancet->enable_intr(instance);
-
+                       megasas_enable_irq_poll(instance);
                        shost_for_each_device(sdev, shost) {
                                if ((instance->tgt_prop) &&
                                    (instance->nvme_page_size))
@@ -4750,9 +4989,9 @@ transition_to_ready:
 
                        atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
 
-                       dev_info(&instance->pdev->dev, "Interrupts are enabled and"
-                               " controller is OPERATIONAL for scsi:%d\n",
-                               instance->host->host_no);
+                       dev_info(&instance->pdev->dev,
+                                "Adapter is OPERATIONAL for scsi:%d\n",
+                                instance->host->host_no);
 
                        /* Restart SR-IOV heartbeat */
                        if (instance->requestorId) {
@@ -4786,13 +5025,10 @@ transition_to_ready:
 
                        goto out;
                }
-fail_kill_adapter:
                /* Reset failed, kill the adapter */
                dev_warn(&instance->pdev->dev, "Reset failed, killing "
                       "adapter scsi%d.\n", instance->host->host_no);
-               megaraid_sas_kill_hba(instance);
-               instance->skip_heartbeat_timer_del = 1;
-               retval = FAILED;
+               goto kill_hba;
        } else {
                /* For VF: Restart HB timer if we didn't OCR */
                if (instance->requestorId) {
@@ -4800,8 +5036,15 @@ fail_kill_adapter:
                }
                clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
                instance->instancet->enable_intr(instance);
+               megasas_enable_irq_poll(instance);
                atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
+               goto out;
        }
+kill_hba:
+       megaraid_sas_kill_hba(instance);
+       megasas_enable_irq_poll(instance);
+       instance->skip_heartbeat_timer_del = 1;
+       retval = FAILED;
 out:
        clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
        mutex_unlock(&instance->reset_mutex);
index 7fa73ea..c013c80 100644 (file)
@@ -75,7 +75,8 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE {
        MR_RAID_FLAGS_IO_SUB_TYPE_RMW_P        = 3,
        MR_RAID_FLAGS_IO_SUB_TYPE_RMW_Q        = 4,
        MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS = 6,
-       MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT = 7
+       MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT = 7,
+       MR_RAID_FLAGS_IO_SUB_TYPE_R56_DIV_OFFLOAD = 8
 };
 
 /*
@@ -88,7 +89,6 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE {
 
 #define MEGASAS_FP_CMD_LEN     16
 #define MEGASAS_FUSION_IN_RESET 0
-#define THRESHOLD_REPLY_COUNT 50
 #define RAID_1_PEER_CMDS 2
 #define JBOD_MAPS_COUNT        2
 #define MEGASAS_REDUCE_QD_COUNT 64
@@ -140,12 +140,15 @@ struct RAID_CONTEXT_G35 {
        u16 timeout_value; /* 0x02 -0x03 */
        u16             routing_flags;  // 0x04 -0x05 routing flags
        u16 virtual_disk_tgt_id;   /* 0x06 -0x07 */
-       u64 reg_lock_row_lba;      /* 0x08 - 0x0F */
+       __le64 reg_lock_row_lba;      /* 0x08 - 0x0F */
        u32 reg_lock_length;      /* 0x10 - 0x13 */
-       union {
-               u16 next_lmid; /* 0x14 - 0x15 */
-               u16     peer_smid;      /* used for the raid 1/10 fp writes */
-       } smid;
+       union {                     // flow specific
+               u16 rmw_op_index;   /* 0x14 - 0x15, R5/6 RMW: rmw operation index*/
+               u16 peer_smid;      /* 0x14 - 0x15, R1 Write: peer smid*/
+               u16 r56_arm_map;    /* 0x14 - 0x15, Unused [15], LogArm[14:10], P-Arm[9:5], Q-Arm[4:0] */
+
+       } flow_specific;
+
        u8 ex_status;       /* 0x16 : OUT */
        u8 status;          /* 0x17 status */
        u8 raid_flags;          /* 0x18 resvd[7:6], ioSubType[5:4],
@@ -236,6 +239,13 @@ union RAID_CONTEXT_UNION {
 #define RAID_CTX_SPANARM_SPAN_SHIFT    (5)
 #define RAID_CTX_SPANARM_SPAN_MASK     (0xE0)
 
+/* LogArm[14:10], P-Arm[9:5], Q-Arm[4:0] */
+#define RAID_CTX_R56_Q_ARM_MASK                (0x1F)
+#define RAID_CTX_R56_P_ARM_SHIFT       (5)
+#define RAID_CTX_R56_P_ARM_MASK                (0x3E0)
+#define RAID_CTX_R56_LOG_ARM_SHIFT     (10)
+#define RAID_CTX_R56_LOG_ARM_MASK      (0x7C00)
+
 /* number of bits per index in U32 TrackStream */
 #define BITS_PER_INDEX_STREAM          4
 #define INVALID_STREAM_NUM              16
@@ -940,6 +950,7 @@ struct IO_REQUEST_INFO {
        u8  pd_after_lb;
        u16 r1_alt_dev_handle; /* raid 1/10 only */
        bool ra_capable;
+       u8 data_arms;
 };
 
 struct MR_LD_TARGET_SYNC {
@@ -1324,7 +1335,8 @@ struct fusion_context {
        dma_addr_t ioc_init_request_phys;
        struct MPI2_IOC_INIT_REQUEST *ioc_init_request;
        struct megasas_cmd *ioc_init_cmd;
-
+       bool pcie_bw_limitation;
+       bool r56_div_offload;
 };
 
 union desc_value {
@@ -1349,6 +1361,11 @@ struct  MR_SNAPDUMP_PROPERTIES {
        u8       reserved[12];
 };
 
+struct megasas_debugfs_buffer {
+       void *buf;
+       u32 len;
+};
+
 void megasas_free_cmds_fusion(struct megasas_instance *instance);
 int megasas_ioc_init_fusion(struct megasas_instance *instance);
 u8 megasas_get_map_info(struct megasas_instance *instance);
index a2f4a55..167d79d 100644 (file)
@@ -1398,7 +1398,7 @@ typedef struct _MPI2_CONFIG_PAGE_IOC_1 {
        U8                      PCIBusNum;                  /*0x0E */
        U8                      PCIDomainSegment;           /*0x0F */
        U32                     Reserved1;                  /*0x10 */
-       U32                     Reserved2;                  /*0x14 */
+       U32                     ProductSpecific;            /* 0x14 */
 } MPI2_CONFIG_PAGE_IOC_1,
        *PTR_MPI2_CONFIG_PAGE_IOC_1,
        Mpi2IOCPage1_t, *pMpi2IOCPage1_t;
index 8aacbd1..6846628 100644 (file)
@@ -74,28 +74,28 @@ static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS];
 #define MAX_HBA_QUEUE_DEPTH    30000
 #define MAX_CHAIN_DEPTH                100000
 static int max_queue_depth = -1;
-module_param(max_queue_depth, int, 0);
+module_param(max_queue_depth, int, 0444);
 MODULE_PARM_DESC(max_queue_depth, " max controller queue depth ");
 
 static int max_sgl_entries = -1;
-module_param(max_sgl_entries, int, 0);
+module_param(max_sgl_entries, int, 0444);
 MODULE_PARM_DESC(max_sgl_entries, " max sg entries ");
 
 static int msix_disable = -1;
-module_param(msix_disable, int, 0);
+module_param(msix_disable, int, 0444);
 MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
 
 static int smp_affinity_enable = 1;
-module_param(smp_affinity_enable, int, S_IRUGO);
+module_param(smp_affinity_enable, int, 0444);
 MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disable Default: enable(1)");
 
 static int max_msix_vectors = -1;
-module_param(max_msix_vectors, int, 0);
+module_param(max_msix_vectors, int, 0444);
 MODULE_PARM_DESC(max_msix_vectors,
        " max msix vectors");
 
 static int irqpoll_weight = -1;
-module_param(irqpoll_weight, int, 0);
+module_param(irqpoll_weight, int, 0444);
 MODULE_PARM_DESC(irqpoll_weight,
        "irq poll weight (default= one fourth of HBA queue depth)");
 
@@ -103,6 +103,26 @@ static int mpt3sas_fwfault_debug;
 MODULE_PARM_DESC(mpt3sas_fwfault_debug,
        " enable detection of firmware fault and halt firmware - (default=0)");
 
+static int perf_mode = -1;
+module_param(perf_mode, int, 0444);
+MODULE_PARM_DESC(perf_mode,
+       "Performance mode (only for Aero/Sea Generation), options:\n\t\t"
+       "0 - balanced: high iops mode is enabled &\n\t\t"
+       "interrupt coalescing is enabled only on high iops queues,\n\t\t"
+       "1 - iops: high iops mode is disabled &\n\t\t"
+       "interrupt coalescing is enabled on all queues,\n\t\t"
+       "2 - latency: high iops mode is disabled &\n\t\t"
+       "interrupt coalescing is enabled on all queues with timeout value 0xA,\n"
+       "\t\tdefault - default perf_mode is 'balanced'"
+       );
+
+enum mpt3sas_perf_mode {
+       MPT_PERF_MODE_DEFAULT   = -1,
+       MPT_PERF_MODE_BALANCED  = 0,
+       MPT_PERF_MODE_IOPS      = 1,
+       MPT_PERF_MODE_LATENCY   = 2,
+};
+
 static int
 _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc);
 
@@ -1282,7 +1302,7 @@ _base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
        ack_request->EventContext = mpi_reply->EventContext;
        ack_request->VF_ID = 0;  /* TODO */
        ack_request->VP_ID = 0;
-       mpt3sas_base_put_smid_default(ioc, smid);
+       ioc->put_smid_default(ioc, smid);
 
  out:
 
@@ -2793,6 +2813,9 @@ _base_free_irq(struct MPT3SAS_ADAPTER *ioc)
 
        list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) {
                list_del(&reply_q->list);
+               if (ioc->smp_affinity_enable)
+                       irq_set_affinity_hint(pci_irq_vector(ioc->pdev,
+                           reply_q->msix_index), NULL);
                free_irq(pci_irq_vector(ioc->pdev, reply_q->msix_index),
                         reply_q);
                kfree(reply_q);
@@ -2857,14 +2880,13 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
 {
        unsigned int cpu, nr_cpus, nr_msix, index = 0;
        struct adapter_reply_queue *reply_q;
+       int local_numa_node;
 
        if (!_base_is_controller_msix_enabled(ioc))
                return;
-       ioc->msix_load_balance = false;
-       if (ioc->reply_queue_count < num_online_cpus()) {
-               ioc->msix_load_balance = true;
+
+       if (ioc->msix_load_balance)
                return;
-       }
 
        memset(ioc->cpu_msix_table, 0, ioc->cpu_msix_table_sz);
 
@@ -2874,14 +2896,33 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
        if (!nr_msix)
                return;
 
-       if (smp_affinity_enable) {
+       if (ioc->smp_affinity_enable) {
+
+               /*
+                * set irq affinity to local numa node for those irqs
+                * corresponding to high iops queues.
+                */
+               if (ioc->high_iops_queues) {
+                       local_numa_node = dev_to_node(&ioc->pdev->dev);
+                       for (index = 0; index < ioc->high_iops_queues;
+                           index++) {
+                               irq_set_affinity_hint(pci_irq_vector(ioc->pdev,
+                                   index), cpumask_of_node(local_numa_node));
+                       }
+               }
+
                list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
-                       const cpumask_t *mask = pci_irq_get_affinity(ioc->pdev,
-                                                       reply_q->msix_index);
+                       const cpumask_t *mask;
+
+                       if (reply_q->msix_index < ioc->high_iops_queues)
+                               continue;
+
+                       mask = pci_irq_get_affinity(ioc->pdev,
+                           reply_q->msix_index);
                        if (!mask) {
                                ioc_warn(ioc, "no affinity for msi %x\n",
                                         reply_q->msix_index);
-                               continue;
+                               goto fall_back;
                        }
 
                        for_each_cpu_and(cpu, mask, cpu_online_mask) {
@@ -2892,12 +2933,18 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
                }
                return;
        }
+
+fall_back:
        cpu = cpumask_first(cpu_online_mask);
+       nr_msix -= ioc->high_iops_queues;
+       index = 0;
 
        list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
-
                unsigned int i, group = nr_cpus / nr_msix;
 
+               if (reply_q->msix_index < ioc->high_iops_queues)
+                       continue;
+
                if (cpu >= nr_cpus)
                        break;
 
@@ -2912,6 +2959,52 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
        }
 }
 
+/**
+ * _base_check_and_enable_high_iops_queues - enable high iops mode
+ * @ ioc - per adapter object
+ * @ hba_msix_vector_count - msix vectors supported by HBA
+ *
+ * Enable high iops queues only if
+ *  - HBA is a SEA/AERO controller and
+ *  - MSI-Xs vector supported by the HBA is 128 and
+ *  - total CPU count in the system >=16 and
+ *  - loaded driver with default max_msix_vectors module parameter and
+ *  - system booted in non kdump mode
+ *
+ * returns nothing.
+ */
+static void
+_base_check_and_enable_high_iops_queues(struct MPT3SAS_ADAPTER *ioc,
+               int hba_msix_vector_count)
+{
+       u16 lnksta, speed;
+
+       if (perf_mode == MPT_PERF_MODE_IOPS ||
+           perf_mode == MPT_PERF_MODE_LATENCY) {
+               ioc->high_iops_queues = 0;
+               return;
+       }
+
+       if (perf_mode == MPT_PERF_MODE_DEFAULT) {
+
+               pcie_capability_read_word(ioc->pdev, PCI_EXP_LNKSTA, &lnksta);
+               speed = lnksta & PCI_EXP_LNKSTA_CLS;
+
+               if (speed < 0x4) {
+                       ioc->high_iops_queues = 0;
+                       return;
+               }
+       }
+
+       if (!reset_devices && ioc->is_aero_ioc &&
+           hba_msix_vector_count == MPT3SAS_GEN35_MAX_MSIX_QUEUES &&
+           num_online_cpus() >= MPT3SAS_HIGH_IOPS_REPLY_QUEUES &&
+           max_msix_vectors == -1)
+               ioc->high_iops_queues = MPT3SAS_HIGH_IOPS_REPLY_QUEUES;
+       else
+               ioc->high_iops_queues = 0;
+}
+
 /**
  * _base_disable_msix - disables msix
  * @ioc: per adapter object
@@ -2922,10 +3015,37 @@ _base_disable_msix(struct MPT3SAS_ADAPTER *ioc)
 {
        if (!ioc->msix_enable)
                return;
-       pci_disable_msix(ioc->pdev);
+       pci_free_irq_vectors(ioc->pdev);
        ioc->msix_enable = 0;
 }
 
+/**
+ * _base_alloc_irq_vectors - allocate msix vectors
+ * @ioc: per adapter object
+ *
+ */
+static int
+_base_alloc_irq_vectors(struct MPT3SAS_ADAPTER *ioc)
+{
+       int i, irq_flags = PCI_IRQ_MSIX;
+       struct irq_affinity desc = { .pre_vectors = ioc->high_iops_queues };
+       struct irq_affinity *descp = &desc;
+
+       if (ioc->smp_affinity_enable)
+               irq_flags |= PCI_IRQ_AFFINITY;
+       else
+               descp = NULL;
+
+       ioc_info(ioc, " %d %d\n", ioc->high_iops_queues,
+           ioc->msix_vector_count);
+
+       i = pci_alloc_irq_vectors_affinity(ioc->pdev,
+           ioc->high_iops_queues,
+           ioc->msix_vector_count, irq_flags, descp);
+
+       return i;
+}
+
 /**
  * _base_enable_msix - enables msix, failback to io_apic
  * @ioc: per adapter object
@@ -2937,7 +3057,8 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
        int r;
        int i, local_max_msix_vectors;
        u8 try_msix = 0;
-       unsigned int irq_flags = PCI_IRQ_MSIX;
+
+       ioc->msix_load_balance = false;
 
        if (msix_disable == -1 || msix_disable == 0)
                try_msix = 1;
@@ -2948,12 +3069,16 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
        if (_base_check_enable_msix(ioc) != 0)
                goto try_ioapic;
 
-       ioc->reply_queue_count = min_t(int, ioc->cpu_count,
+       ioc_info(ioc, "MSI-X vectors supported: %d\n", ioc->msix_vector_count);
+       pr_info("\t no of cores: %d, max_msix_vectors: %d\n",
+               ioc->cpu_count, max_msix_vectors);
+       if (ioc->is_aero_ioc)
+               _base_check_and_enable_high_iops_queues(ioc,
+                       ioc->msix_vector_count);
+       ioc->reply_queue_count =
+               min_t(int, ioc->cpu_count + ioc->high_iops_queues,
                ioc->msix_vector_count);
 
-       ioc_info(ioc, "MSI-X vectors supported: %d, no of cores: %d, max_msix_vectors: %d\n",
-                ioc->msix_vector_count, ioc->cpu_count, max_msix_vectors);
-
        if (!ioc->rdpq_array_enable && max_msix_vectors == -1)
                local_max_msix_vectors = (reset_devices) ? 1 : 8;
        else
@@ -2965,14 +3090,23 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
        else if (local_max_msix_vectors == 0)
                goto try_ioapic;
 
-       if (ioc->msix_vector_count < ioc->cpu_count)
-               smp_affinity_enable = 0;
+       /*
+        * Enable msix_load_balance only if combined reply queue mode is
+        * disabled on SAS3 & above generation HBA devices.
+        */
+       if (!ioc->combined_reply_queue &&
+           ioc->hba_mpi_version_belonged != MPI2_VERSION) {
+               ioc->msix_load_balance = true;
+       }
 
-       if (smp_affinity_enable)
-               irq_flags |= PCI_IRQ_AFFINITY;
+       /*
+        * smp affinity setting is not need when msix load balance
+        * is enabled.
+        */
+       if (ioc->msix_load_balance)
+               ioc->smp_affinity_enable = 0;
 
-       r = pci_alloc_irq_vectors(ioc->pdev, 1, ioc->reply_queue_count,
-                                 irq_flags);
+       r = _base_alloc_irq_vectors(ioc);
        if (r < 0) {
                dfailprintk(ioc,
                            ioc_info(ioc, "pci_alloc_irq_vectors failed (r=%d) !!!\n",
@@ -2991,11 +3125,15 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
                }
        }
 
+       ioc_info(ioc, "High IOPs queues : %s\n",
+                       ioc->high_iops_queues ? "enabled" : "disabled");
+
        return 0;
 
 /* failback to io_apic interrupt routing */
  try_ioapic:
-
+       ioc->high_iops_queues = 0;
+       ioc_info(ioc, "High IOPs queues : disabled\n");
        ioc->reply_queue_count = 1;
        r = pci_alloc_irq_vectors(ioc->pdev, 1, 1, PCI_IRQ_LEGACY);
        if (r < 0) {
@@ -3265,8 +3403,18 @@ mpt3sas_base_get_reply_virt_addr(struct MPT3SAS_ADAPTER *ioc, u32 phys_addr)
        return ioc->reply + (phys_addr - (u32)ioc->reply_dma);
 }
 
+/**
+ * _base_get_msix_index - get the msix index
+ * @ioc: per adapter object
+ * @scmd: scsi_cmnd object
+ *
+ * returns msix index of general reply queues,
+ * i.e. reply queue on which IO request's reply
+ * should be posted by the HBA firmware.
+ */
 static inline u8
-_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc)
+_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc,
+       struct scsi_cmnd *scmd)
 {
        /* Enables reply_queue load balancing */
        if (ioc->msix_load_balance)
@@ -3277,6 +3425,35 @@ _base_get_msix_index(struct MPT3SAS_ADAPTER *ioc)
        return ioc->cpu_msix_table[raw_smp_processor_id()];
 }
 
+/**
+ * _base_get_high_iops_msix_index - get the msix index of
+ *                             high iops queues
+ * @ioc: per adapter object
+ * @scmd: scsi_cmnd object
+ *
+ * Returns: msix index of high iops reply queues.
+ * i.e. high iops reply queue on which IO request's
+ * reply should be posted by the HBA firmware.
+ */
+static inline u8
+_base_get_high_iops_msix_index(struct MPT3SAS_ADAPTER *ioc,
+       struct scsi_cmnd *scmd)
+{
+       /**
+        * Round robin the IO interrupts among the high iops
+        * reply queues in terms of batch count 16 when outstanding
+        * IOs on the target device is >=8.
+        */
+       if (atomic_read(&scmd->device->device_busy) >
+           MPT3SAS_DEVICE_HIGH_IOPS_DEPTH)
+               return base_mod64((
+                   atomic64_add_return(1, &ioc->high_iops_outstanding) /
+                   MPT3SAS_HIGH_IOPS_BATCH_COUNT),
+                   MPT3SAS_HIGH_IOPS_REPLY_QUEUES);
+
+       return _base_get_msix_index(ioc, scmd);
+}
+
 /**
  * mpt3sas_base_get_smid - obtain a free smid from internal queue
  * @ioc: per adapter object
@@ -3325,8 +3502,8 @@ mpt3sas_base_get_smid_scsiio(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx,
 
        smid = tag + 1;
        request->cb_idx = cb_idx;
-       request->msix_io = _base_get_msix_index(ioc);
        request->smid = smid;
+       request->scmd = scmd;
        INIT_LIST_HEAD(&request->chain_list);
        return smid;
 }
@@ -3380,6 +3557,7 @@ void mpt3sas_base_clear_st(struct MPT3SAS_ADAPTER *ioc,
                return;
        st->cb_idx = 0xFF;
        st->direct_io = 0;
+       st->scmd = NULL;
        atomic_set(&ioc->chain_lookup[st->smid - 1].chain_offset, 0);
        st->smid = 0;
 }
@@ -3478,6 +3656,29 @@ _base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock)
 }
 #endif
 
+/**
+ * _base_set_and_get_msix_index - get the msix index and assign to msix_io
+ *                                variable of scsi tracker
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * returns msix index.
+ */
+static u8
+_base_set_and_get_msix_index(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+{
+       struct scsiio_tracker *st = NULL;
+
+       if (smid < ioc->hi_priority_smid)
+               st = _get_st_from_smid(ioc, smid);
+
+       if (st == NULL)
+               return  _base_get_msix_index(ioc, NULL);
+
+       st->msix_io = ioc->get_msix_index_for_smlio(ioc, st->scmd);
+       return st->msix_io;
+}
+
 /**
  * _base_put_smid_mpi_ep_scsi_io - send SCSI_IO request to firmware
  * @ioc: per adapter object
@@ -3485,7 +3686,8 @@ _base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock)
  * @handle: device handle
  */
 static void
-_base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle)
+_base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc,
+       u16 smid, u16 handle)
 {
        Mpi2RequestDescriptorUnion_t descriptor;
        u64 *request = (u64 *)&descriptor;
@@ -3498,7 +3700,7 @@ _base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle)
        _base_clone_mpi_to_sys_mem(mpi_req_iomem, (void *)mfp,
                                        ioc->request_sz);
        descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
-       descriptor.SCSIIO.MSIxIndex =  _base_get_msix_index(ioc);
+       descriptor.SCSIIO.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
        descriptor.SCSIIO.SMID = cpu_to_le16(smid);
        descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
        descriptor.SCSIIO.LMID = 0;
@@ -3520,7 +3722,7 @@ _base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle)
 
 
        descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
-       descriptor.SCSIIO.MSIxIndex =  _base_get_msix_index(ioc);
+       descriptor.SCSIIO.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
        descriptor.SCSIIO.SMID = cpu_to_le16(smid);
        descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
        descriptor.SCSIIO.LMID = 0;
@@ -3529,13 +3731,13 @@ _base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle)
 }
 
 /**
- * mpt3sas_base_put_smid_fast_path - send fast path request to firmware
+ * _base_put_smid_fast_path - send fast path request to firmware
  * @ioc: per adapter object
  * @smid: system request message index
  * @handle: device handle
  */
-void
-mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+static void
+_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
        u16 handle)
 {
        Mpi2RequestDescriptorUnion_t descriptor;
@@ -3543,7 +3745,7 @@ mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
 
        descriptor.SCSIIO.RequestFlags =
            MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
-       descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc);
+       descriptor.SCSIIO.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
        descriptor.SCSIIO.SMID = cpu_to_le16(smid);
        descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
        descriptor.SCSIIO.LMID = 0;
@@ -3552,13 +3754,13 @@ mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
 }
 
 /**
- * mpt3sas_base_put_smid_hi_priority - send Task Management request to firmware
+ * _base_put_smid_hi_priority - send Task Management request to firmware
  * @ioc: per adapter object
  * @smid: system request message index
  * @msix_task: msix_task will be same as msix of IO incase of task abort else 0.
  */
-void
-mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+static void
+_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid,
        u16 msix_task)
 {
        Mpi2RequestDescriptorUnion_t descriptor;
@@ -3607,7 +3809,7 @@ mpt3sas_base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid)
 
        descriptor.Default.RequestFlags =
                MPI26_REQ_DESCRIPT_FLAGS_PCIE_ENCAPSULATED;
-       descriptor.Default.MSIxIndex =  _base_get_msix_index(ioc);
+       descriptor.Default.MSIxIndex =  _base_set_and_get_msix_index(ioc, smid);
        descriptor.Default.SMID = cpu_to_le16(smid);
        descriptor.Default.LMID = 0;
        descriptor.Default.DescriptorTypeDependent = 0;
@@ -3616,12 +3818,12 @@ mpt3sas_base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid)
 }
 
 /**
- * mpt3sas_base_put_smid_default - Default, primarily used for config pages
+ * _base_put_smid_default - Default, primarily used for config pages
  * @ioc: per adapter object
  * @smid: system request message index
  */
-void
-mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+static void
+_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid)
 {
        Mpi2RequestDescriptorUnion_t descriptor;
        void *mpi_req_iomem;
@@ -3639,7 +3841,7 @@ mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid)
        }
        request = (u64 *)&descriptor;
        descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
-       descriptor.Default.MSIxIndex =  _base_get_msix_index(ioc);
+       descriptor.Default.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
        descriptor.Default.SMID = cpu_to_le16(smid);
        descriptor.Default.LMID = 0;
        descriptor.Default.DescriptorTypeDependent = 0;
@@ -3652,6 +3854,95 @@ mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid)
                                &ioc->scsi_lookup_lock);
 }
 
+/**
+ * _base_put_smid_scsi_io_atomic - send SCSI_IO request to firmware using
+ *   Atomic Request Descriptor
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @handle: device handle, unused in this function, for function type match
+ *
+ * Return nothing.
+ */
+static void
+_base_put_smid_scsi_io_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+       u16 handle)
+{
+       Mpi26AtomicRequestDescriptor_t descriptor;
+       u32 *request = (u32 *)&descriptor;
+
+       descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
+       descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
+       descriptor.SMID = cpu_to_le16(smid);
+
+       writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
+}
+
+/**
+ * _base_put_smid_fast_path_atomic - send fast path request to firmware
+ * using Atomic Request Descriptor
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @handle: device handle, unused in this function, for function type match
+ * Return nothing
+ */
+static void
+_base_put_smid_fast_path_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+       u16 handle)
+{
+       Mpi26AtomicRequestDescriptor_t descriptor;
+       u32 *request = (u32 *)&descriptor;
+
+       descriptor.RequestFlags = MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
+       descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
+       descriptor.SMID = cpu_to_le16(smid);
+
+       writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
+}
+
+/**
+ * _base_put_smid_hi_priority_atomic - send Task Management request to
+ * firmware using Atomic Request Descriptor
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @msix_task: msix_task will be same as msix of IO incase of task abort else 0
+ *
+ * Return nothing.
+ */
+static void
+_base_put_smid_hi_priority_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+       u16 msix_task)
+{
+       Mpi26AtomicRequestDescriptor_t descriptor;
+       u32 *request = (u32 *)&descriptor;
+
+       descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
+       descriptor.MSIxIndex = msix_task;
+       descriptor.SMID = cpu_to_le16(smid);
+
+       writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
+}
+
+/**
+ * _base_put_smid_default - Default, primarily used for config pages
+ * use Atomic Request Descriptor
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Return nothing.
+ */
+static void
+_base_put_smid_default_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+{
+       Mpi26AtomicRequestDescriptor_t descriptor;
+       u32 *request = (u32 *)&descriptor;
+
+       descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+       descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
+       descriptor.SMID = cpu_to_le16(smid);
+
+       writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
+}
+
 /**
  * _base_display_OEMs_branding - Display branding string
  * @ioc: per adapter object
@@ -3952,7 +4243,7 @@ _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc)
        ioc->build_sg(ioc, &mpi_request->SGL, 0, 0, fwpkg_data_dma,
                        data_length);
        init_completion(&ioc->base_cmds.done);
-       mpt3sas_base_put_smid_default(ioc, smid);
+       ioc->put_smid_default(ioc, smid);
        /* Wait for 15 seconds */
        wait_for_completion_timeout(&ioc->base_cmds.done,
                        FW_IMG_HDR_READ_TIMEOUT*HZ);
@@ -4191,6 +4482,71 @@ out:
        kfree(sas_iounit_pg1);
 }
 
+/**
+ * _base_update_ioc_page1_inlinewith_perf_mode - Update IOC Page1 fields
+ *    according to performance mode.
+ * @ioc : per adapter object
+ *
+ * Return nothing.
+ */
+static void
+_base_update_ioc_page1_inlinewith_perf_mode(struct MPT3SAS_ADAPTER *ioc)
+{
+       Mpi2IOCPage1_t ioc_pg1;
+       Mpi2ConfigReply_t mpi_reply;
+
+       mpt3sas_config_get_ioc_pg1(ioc, &mpi_reply, &ioc->ioc_pg1_copy);
+       memcpy(&ioc_pg1, &ioc->ioc_pg1_copy, sizeof(Mpi2IOCPage1_t));
+
+       switch (perf_mode) {
+       case MPT_PERF_MODE_DEFAULT:
+       case MPT_PERF_MODE_BALANCED:
+               if (ioc->high_iops_queues) {
+                       ioc_info(ioc,
+                               "Enable interrupt coalescing only for first\t"
+                               "%d reply queues\n",
+                               MPT3SAS_HIGH_IOPS_REPLY_QUEUES);
+                       /*
+                        * If 31st bit is zero then interrupt coalescing is
+                        * enabled for all reply descriptor post queues.
+                        * If 31st bit is set to one then user can
+                        * enable/disable interrupt coalescing on per reply
+                        * descriptor post queue group(8) basis. So to enable
+                        * interrupt coalescing only on first reply descriptor
+                        * post queue group 31st bit and zero th bit is enabled.
+                        */
+                       ioc_pg1.ProductSpecific = cpu_to_le32(0x80000000 |
+                           ((1 << MPT3SAS_HIGH_IOPS_REPLY_QUEUES/8) - 1));
+                       mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1);
+                       ioc_info(ioc, "performance mode: balanced\n");
+                       return;
+               }
+               /* Fall through */
+       case MPT_PERF_MODE_LATENCY:
+               /*
+                * Enable interrupt coalescing on all reply queues
+                * with timeout value 0xA
+                */
+               ioc_pg1.CoalescingTimeout = cpu_to_le32(0xa);
+               ioc_pg1.Flags |= cpu_to_le32(MPI2_IOCPAGE1_REPLY_COALESCING);
+               ioc_pg1.ProductSpecific = 0;
+               mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1);
+               ioc_info(ioc, "performance mode: latency\n");
+               break;
+       case MPT_PERF_MODE_IOPS:
+               /*
+                * Enable interrupt coalescing on all reply queues.
+                */
+               ioc_info(ioc,
+                   "performance mode: iops with coalescing timeout: 0x%x\n",
+                   le32_to_cpu(ioc_pg1.CoalescingTimeout));
+               ioc_pg1.Flags |= cpu_to_le32(MPI2_IOCPAGE1_REPLY_COALESCING);
+               ioc_pg1.ProductSpecific = 0;
+               mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1);
+               break;
+       }
+}
+
 /**
  * _base_static_config_pages - static start of day config pages
  * @ioc: per adapter object
@@ -4258,6 +4614,8 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc)
 
        if (ioc->iounit_pg8.NumSensors)
                ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors;
+       if (ioc->is_aero_ioc)
+               _base_update_ioc_page1_inlinewith_perf_mode(ioc);
 }
 
 /**
@@ -5431,7 +5789,7 @@ mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc,
            mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET)
                ioc->ioc_link_reset_in_progress = 1;
        init_completion(&ioc->base_cmds.done);
-       mpt3sas_base_put_smid_default(ioc, smid);
+       ioc->put_smid_default(ioc, smid);
        wait_for_completion_timeout(&ioc->base_cmds.done,
            msecs_to_jiffies(10000));
        if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||
@@ -5510,7 +5868,7 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc,
        ioc->base_cmds.smid = smid;
        memcpy(request, mpi_request, sizeof(Mpi2SepReply_t));
        init_completion(&ioc->base_cmds.done);
-       mpt3sas_base_put_smid_default(ioc, smid);
+       ioc->put_smid_default(ioc, smid);
        wait_for_completion_timeout(&ioc->base_cmds.done,
            msecs_to_jiffies(10000));
        if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -5693,6 +6051,9 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc)
        if ((facts->IOCCapabilities &
              MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE) && (!reset_devices))
                ioc->rdpq_array_capable = 1;
+       if ((facts->IOCCapabilities & MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ)
+           && ioc->is_aero_ioc)
+               ioc->atomic_desc_capable = 1;
        facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
        facts->IOCRequestFrameSize =
            le16_to_cpu(mpi_reply.IOCRequestFrameSize);
@@ -5914,7 +6275,7 @@ _base_send_port_enable(struct MPT3SAS_ADAPTER *ioc)
        mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
 
        init_completion(&ioc->port_enable_cmds.done);
-       mpt3sas_base_put_smid_default(ioc, smid);
+       ioc->put_smid_default(ioc, smid);
        wait_for_completion_timeout(&ioc->port_enable_cmds.done, 300*HZ);
        if (!(ioc->port_enable_cmds.status & MPT3_CMD_COMPLETE)) {
                ioc_err(ioc, "%s: timeout\n", __func__);
@@ -5973,7 +6334,7 @@ mpt3sas_port_enable(struct MPT3SAS_ADAPTER *ioc)
        memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t));
        mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
 
-       mpt3sas_base_put_smid_default(ioc, smid);
+       ioc->put_smid_default(ioc, smid);
        return 0;
 }
 
@@ -6089,7 +6450,7 @@ _base_event_notification(struct MPT3SAS_ADAPTER *ioc)
                mpi_request->EventMasks[i] =
                    cpu_to_le32(ioc->event_masks[i]);
        init_completion(&ioc->base_cmds.done);
-       mpt3sas_base_put_smid_default(ioc, smid);
+       ioc->put_smid_default(ioc, smid);
        wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ);
        if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
                ioc_err(ioc, "%s: timeout\n", __func__);
@@ -6549,6 +6910,8 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
                }
        }
 
+       ioc->smp_affinity_enable = smp_affinity_enable;
+
        ioc->rdpq_array_enable_assigned = 0;
        ioc->dma_mask = 0;
        if (ioc->is_aero_ioc)
@@ -6569,6 +6932,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
                ioc->build_sg_scmd = &_base_build_sg_scmd;
                ioc->build_sg = &_base_build_sg;
                ioc->build_zero_len_sge = &_base_build_zero_len_sge;
+               ioc->get_msix_index_for_smlio = &_base_get_msix_index;
                break;
        case MPI25_VERSION:
        case MPI26_VERSION:
@@ -6583,15 +6947,30 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
                ioc->build_nvme_prp = &_base_build_nvme_prp;
                ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee;
                ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t);
-
+               if (ioc->high_iops_queues)
+                       ioc->get_msix_index_for_smlio =
+                                       &_base_get_high_iops_msix_index;
+               else
+                       ioc->get_msix_index_for_smlio = &_base_get_msix_index;
                break;
        }
-
-       if (ioc->is_mcpu_endpoint)
-               ioc->put_smid_scsi_io = &_base_put_smid_mpi_ep_scsi_io;
-       else
-               ioc->put_smid_scsi_io = &_base_put_smid_scsi_io;
-
+       if (ioc->atomic_desc_capable) {
+               ioc->put_smid_default = &_base_put_smid_default_atomic;
+               ioc->put_smid_scsi_io = &_base_put_smid_scsi_io_atomic;
+               ioc->put_smid_fast_path =
+                               &_base_put_smid_fast_path_atomic;
+               ioc->put_smid_hi_priority =
+                               &_base_put_smid_hi_priority_atomic;
+       } else {
+               ioc->put_smid_default = &_base_put_smid_default;
+               ioc->put_smid_fast_path = &_base_put_smid_fast_path;
+               ioc->put_smid_hi_priority = &_base_put_smid_hi_priority;
+               if (ioc->is_mcpu_endpoint)
+                       ioc->put_smid_scsi_io =
+                               &_base_put_smid_mpi_ep_scsi_io;
+               else
+                       ioc->put_smid_scsi_io = &_base_put_smid_scsi_io;
+       }
        /*
         * These function pointers for other requests that don't
         * the require IEEE scatter gather elements.
index 480219f..6afbdb0 100644 (file)
@@ -76,8 +76,8 @@
 #define MPT3SAS_DRIVER_NAME            "mpt3sas"
 #define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>"
 #define MPT3SAS_DESCRIPTION    "LSI MPT Fusion SAS 3.0 Device Driver"
-#define MPT3SAS_DRIVER_VERSION         "28.100.00.00"
-#define MPT3SAS_MAJOR_VERSION          28
+#define MPT3SAS_DRIVER_VERSION         "29.100.00.00"
+#define MPT3SAS_MAJOR_VERSION          29
 #define MPT3SAS_MINOR_VERSION          100
 #define MPT3SAS_BUILD_VERSION          0
 #define MPT3SAS_RELEASE_VERSION        00
@@ -355,6 +355,12 @@ struct mpt3sas_nvme_cmd {
 
 #define VIRTUAL_IO_FAILED_RETRY                        (0x32010081)
 
+/* High IOPs definitions */
+#define MPT3SAS_DEVICE_HIGH_IOPS_DEPTH         8
+#define MPT3SAS_HIGH_IOPS_REPLY_QUEUES         8
+#define MPT3SAS_HIGH_IOPS_BATCH_COUNT          16
+#define MPT3SAS_GEN35_MAX_MSIX_QUEUES          128
+
 /* OEM Specific Flags will come from OEM specific header files */
 struct Mpi2ManufacturingPage10_t {
        MPI2_CONFIG_PAGE_HEADER Header;         /* 00h */
@@ -824,6 +830,7 @@ struct chain_lookup {
  */
 struct scsiio_tracker {
        u16     smid;
+       struct scsi_cmnd *scmd;
        u8      cb_idx;
        u8      direct_io;
        struct pcie_sg_list pcie_sg_list;
@@ -924,6 +931,12 @@ typedef void (*PUT_SMID_IO_FP_HIP) (struct MPT3SAS_ADAPTER *ioc, u16 smid,
        u16 funcdep);
 typedef void (*PUT_SMID_DEFAULT) (struct MPT3SAS_ADAPTER *ioc, u16 smid);
 typedef u32 (*BASE_READ_REG) (const volatile void __iomem *addr);
+/*
+ * To get high iops reply queue's msix index when high iops mode is enabled
+ * else get the msix index of general reply queues.
+ */
+typedef u8 (*GET_MSIX_INDEX) (struct MPT3SAS_ADAPTER *ioc,
+       struct scsi_cmnd *scmd);
 
 /* IOC Facts and Port Facts converted from little endian to cpu */
 union mpi3_version_union {
@@ -1025,6 +1038,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
  * @cpu_msix_table: table for mapping cpus to msix index
  * @cpu_msix_table_sz: table size
  * @total_io_cnt: Gives total IO count, used to load balance the interrupts
+ * @high_iops_outstanding: used to load balance the interrupts
+ *                             within high iops reply queues
  * @msix_load_balance: Enables load balancing of interrupts across
  * the multiple MSIXs
  * @schedule_dead_ioc_flush_running_cmds: callback to flush pending commands
@@ -1147,6 +1162,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
  *     path functions resulting in Null pointer reference followed by kernel
  *     crash. To avoid the above race condition we use mutex syncrhonization
  *     which ensures the syncrhonization between cli/sysfs_show path.
+ * @atomic_desc_capable: Atomic Request Descriptor support.
+ * @GET_MSIX_INDEX: Get the msix index of high iops queues.
  */
 struct MPT3SAS_ADAPTER {
        struct list_head list;
@@ -1206,8 +1223,10 @@ struct MPT3SAS_ADAPTER {
        MPT3SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds;
        u32             non_operational_loop;
        atomic64_t      total_io_cnt;
+       atomic64_t      high_iops_outstanding;
        bool            msix_load_balance;
        u16             thresh_hold;
+       u8              high_iops_queues;
 
        /* internal commands, callback index */
        u8              scsi_io_cb_idx;
@@ -1267,6 +1286,7 @@ struct MPT3SAS_ADAPTER {
        Mpi2IOUnitPage0_t iounit_pg0;
        Mpi2IOUnitPage1_t iounit_pg1;
        Mpi2IOUnitPage8_t iounit_pg8;
+       Mpi2IOCPage1_t  ioc_pg1_copy;
 
        struct _boot_device req_boot_device;
        struct _boot_device req_alt_boot_device;
@@ -1385,6 +1405,7 @@ struct MPT3SAS_ADAPTER {
 
        u8              combined_reply_queue;
        u8              combined_reply_index_count;
+       u8              smp_affinity_enable;
        /* reply post register index */
        resource_size_t **replyPostRegisterIndex;
 
@@ -1412,6 +1433,7 @@ struct MPT3SAS_ADAPTER {
        u8              hide_drives;
        spinlock_t      diag_trigger_lock;
        u8              diag_trigger_active;
+       u8              atomic_desc_capable;
        BASE_READ_REG   base_readl;
        struct SL_WH_MASTER_TRIGGER_T diag_trigger_master;
        struct SL_WH_EVENT_TRIGGERS_T diag_trigger_event;
@@ -1422,7 +1444,10 @@ struct MPT3SAS_ADAPTER {
        u8              is_gen35_ioc;
        u8              is_aero_ioc;
        PUT_SMID_IO_FP_HIP put_smid_scsi_io;
-
+       PUT_SMID_IO_FP_HIP put_smid_fast_path;
+       PUT_SMID_IO_FP_HIP put_smid_hi_priority;
+       PUT_SMID_DEFAULT put_smid_default;
+       GET_MSIX_INDEX get_msix_index_for_smlio;
 };
 
 typedef u8 (*MPT_CALLBACK)(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
@@ -1611,6 +1636,10 @@ int mpt3sas_config_get_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc,
 int mpt3sas_config_set_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc,
        Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page,
        u16 sz);
+int mpt3sas_config_get_ioc_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+       *mpi_reply, Mpi2IOCPage1_t *config_page);
+int mpt3sas_config_set_ioc_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+       *mpi_reply, Mpi2IOCPage1_t *config_page);
 int mpt3sas_config_get_ioc_pg8(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
        *mpi_reply, Mpi2IOCPage8_t *config_page);
 int mpt3sas_config_get_expander_pg0(struct MPT3SAS_ADAPTER *ioc,
index fb0a172..14a1a27 100644 (file)
@@ -380,7 +380,7 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
        memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t));
        _config_display_some_debug(ioc, smid, "config_request", NULL);
        init_completion(&ioc->config_cmds.done);
-       mpt3sas_base_put_smid_default(ioc, smid);
+       ioc->put_smid_default(ioc, smid);
        wait_for_completion_timeout(&ioc->config_cmds.done, timeout*HZ);
        if (!(ioc->config_cmds.status & MPT3_CMD_COMPLETE)) {
                mpt3sas_base_check_cmd_timeout(ioc,
@@ -949,6 +949,77 @@ mpt3sas_config_get_ioc_pg8(struct MPT3SAS_ADAPTER *ioc,
  out:
        return r;
 }
+/**
+ * mpt3sas_config_get_ioc_pg1 - obtain ioc page 1
+ * @ioc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * Context: sleep.
+ *
+ * Return: 0 for success, non-zero for failure.
+ */
+int
+mpt3sas_config_get_ioc_pg1(struct MPT3SAS_ADAPTER *ioc,
+       Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage1_t *config_page)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
+       mpi_request.Header.PageNumber = 1;
+       mpi_request.Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
+       ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
+       if (r)
+               goto out;
+
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
+           sizeof(*config_page));
+ out:
+       return r;
+}
+
+/**
+ * mpt3sas_config_set_ioc_pg1 - modify ioc page 1
+ * @ioc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * Context: sleep.
+ *
+ * Return: 0 for success, non-zero for failure.
+ */
+int
+mpt3sas_config_set_ioc_pg1(struct MPT3SAS_ADAPTER *ioc,
+       Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage1_t *config_page)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
+       mpi_request.Header.PageNumber = 1;
+       mpi_request.Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
+       ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
+       if (r)
+               goto out;
+
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
+           sizeof(*config_page));
+ out:
+       return r;
+}
 
 /**
  * mpt3sas_config_get_sas_device_pg0 - obtain sas device page 0
index b2bb47c..d4ecfbb 100644 (file)
@@ -822,7 +822,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
                if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)
                        ioc->put_smid_scsi_io(ioc, smid, device_handle);
                else
-                       mpt3sas_base_put_smid_default(ioc, smid);
+                       ioc->put_smid_default(ioc, smid);
                break;
        }
        case MPI2_FUNCTION_SCSI_TASK_MGMT:
@@ -859,7 +859,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
                    tm_request->DevHandle));
                ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
                    data_in_dma, data_in_sz);
-               mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
+               ioc->put_smid_hi_priority(ioc, smid, 0);
                break;
        }
        case MPI2_FUNCTION_SMP_PASSTHROUGH:
@@ -890,7 +890,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
                }
                ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma,
                    data_in_sz);
-               mpt3sas_base_put_smid_default(ioc, smid);
+               ioc->put_smid_default(ioc, smid);
                break;
        }
        case MPI2_FUNCTION_SATA_PASSTHROUGH:
@@ -905,7 +905,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
                }
                ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma,
                    data_in_sz);
-               mpt3sas_base_put_smid_default(ioc, smid);
+               ioc->put_smid_default(ioc, smid);
                break;
        }
        case MPI2_FUNCTION_FW_DOWNLOAD:
@@ -913,7 +913,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
        {
                ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma,
                    data_in_sz);
-               mpt3sas_base_put_smid_default(ioc, smid);
+               ioc->put_smid_default(ioc, smid);
                break;
        }
        case MPI2_FUNCTION_TOOLBOX:
@@ -928,7 +928,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
                        ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
                                data_in_dma, data_in_sz);
                }
-               mpt3sas_base_put_smid_default(ioc, smid);
+               ioc->put_smid_default(ioc, smid);
                break;
        }
        case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
@@ -948,7 +948,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
        default:
                ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
                    data_in_dma, data_in_sz);
-               mpt3sas_base_put_smid_default(ioc, smid);
+               ioc->put_smid_default(ioc, smid);
                break;
        }
 
@@ -1576,7 +1576,7 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
                        cpu_to_le32(ioc->product_specific[buffer_type][i]);
 
        init_completion(&ioc->ctl_cmds.done);
-       mpt3sas_base_put_smid_default(ioc, smid);
+       ioc->put_smid_default(ioc, smid);
        wait_for_completion_timeout(&ioc->ctl_cmds.done,
            MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
 
@@ -1903,7 +1903,7 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type,
        mpi_request->VP_ID = 0;
 
        init_completion(&ioc->ctl_cmds.done);
-       mpt3sas_base_put_smid_default(ioc, smid);
+       ioc->put_smid_default(ioc, smid);
        wait_for_completion_timeout(&ioc->ctl_cmds.done,
            MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
 
@@ -2151,7 +2151,7 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
        mpi_request->VP_ID = 0;
 
        init_completion(&ioc->ctl_cmds.done);
-       mpt3sas_base_put_smid_default(ioc, smid);
+       ioc->put_smid_default(ioc, smid);
        wait_for_completion_timeout(&ioc->ctl_cmds.done,
            MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
 
@@ -2319,6 +2319,10 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
                        break;
                }
 
+               if (karg.hdr.ioc_number != ioctl_header.ioc_number) {
+                       ret = -EINVAL;
+                       break;
+               }
                if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_command)) {
                        uarg = arg;
                        ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf);
@@ -2453,7 +2457,7 @@ _ctl_mpt2_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
 
 /* scsi host attributes */
 /**
- * _ctl_version_fw_show - firmware version
+ * version_fw_show - firmware version
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -2461,7 +2465,7 @@ _ctl_mpt2_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
  * A sysfs 'read-only' shost attribute.
  */
 static ssize_t
-_ctl_version_fw_show(struct device *cdev, struct device_attribute *attr,
+version_fw_show(struct device *cdev, struct device_attribute *attr,
        char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2473,10 +2477,10 @@ _ctl_version_fw_show(struct device *cdev, struct device_attribute *attr,
            (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
            ioc->facts.FWVersion.Word & 0x000000FF);
 }
-static DEVICE_ATTR(version_fw, S_IRUGO, _ctl_version_fw_show, NULL);
+static DEVICE_ATTR_RO(version_fw);
 
 /**
- * _ctl_version_bios_show - bios version
+ * version_bios_show - bios version
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -2484,7 +2488,7 @@ static DEVICE_ATTR(version_fw, S_IRUGO, _ctl_version_fw_show, NULL);
  * A sysfs 'read-only' shost attribute.
  */
 static ssize_t
-_ctl_version_bios_show(struct device *cdev, struct device_attribute *attr,
+version_bios_show(struct device *cdev, struct device_attribute *attr,
        char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2498,10 +2502,10 @@ _ctl_version_bios_show(struct device *cdev, struct device_attribute *attr,
            (version & 0x0000FF00) >> 8,
            version & 0x000000FF);
 }
-static DEVICE_ATTR(version_bios, S_IRUGO, _ctl_version_bios_show, NULL);
+static DEVICE_ATTR_RO(version_bios);
 
 /**
- * _ctl_version_mpi_show - MPI (message passing interface) version
+ * version_mpi_show - MPI (message passing interface) version
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -2509,7 +2513,7 @@ static DEVICE_ATTR(version_bios, S_IRUGO, _ctl_version_bios_show, NULL);
  * A sysfs 'read-only' shost attribute.
  */
 static ssize_t
-_ctl_version_mpi_show(struct device *cdev, struct device_attribute *attr,
+version_mpi_show(struct device *cdev, struct device_attribute *attr,
        char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2518,10 +2522,10 @@ _ctl_version_mpi_show(struct device *cdev, struct device_attribute *attr,
        return snprintf(buf, PAGE_SIZE, "%03x.%02x\n",
            ioc->facts.MsgVersion, ioc->facts.HeaderVersion >> 8);
 }
-static DEVICE_ATTR(version_mpi, S_IRUGO, _ctl_version_mpi_show, NULL);
+static DEVICE_ATTR_RO(version_mpi);
 
 /**
- * _ctl_version_product_show - product name
+ * version_product_show - product name
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -2529,7 +2533,7 @@ static DEVICE_ATTR(version_mpi, S_IRUGO, _ctl_version_mpi_show, NULL);
  * A sysfs 'read-only' shost attribute.
  */
 static ssize_t
-_ctl_version_product_show(struct device *cdev, struct device_attribute *attr,
+version_product_show(struct device *cdev, struct device_attribute *attr,
        char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2537,10 +2541,10 @@ _ctl_version_product_show(struct device *cdev, struct device_attribute *attr,
 
        return snprintf(buf, 16, "%s\n", ioc->manu_pg0.ChipName);
 }
-static DEVICE_ATTR(version_product, S_IRUGO, _ctl_version_product_show, NULL);
+static DEVICE_ATTR_RO(version_product);
 
 /**
- * _ctl_version_nvdata_persistent_show - ndvata persistent version
+ * version_nvdata_persistent_show - ndvata persistent version
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -2548,7 +2552,7 @@ static DEVICE_ATTR(version_product, S_IRUGO, _ctl_version_product_show, NULL);
  * A sysfs 'read-only' shost attribute.
  */
 static ssize_t
-_ctl_version_nvdata_persistent_show(struct device *cdev,
+version_nvdata_persistent_show(struct device *cdev,
        struct device_attribute *attr, char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2557,11 +2561,10 @@ _ctl_version_nvdata_persistent_show(struct device *cdev,
        return snprintf(buf, PAGE_SIZE, "%08xh\n",
            le32_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word));
 }
-static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
-       _ctl_version_nvdata_persistent_show, NULL);
+static DEVICE_ATTR_RO(version_nvdata_persistent);
 
 /**
- * _ctl_version_nvdata_default_show - nvdata default version
+ * version_nvdata_default_show - nvdata default version
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -2569,7 +2572,7 @@ static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
  * A sysfs 'read-only' shost attribute.
  */
 static ssize_t
-_ctl_version_nvdata_default_show(struct device *cdev, struct device_attribute
+version_nvdata_default_show(struct device *cdev, struct device_attribute
        *attr, char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2578,11 +2581,10 @@ _ctl_version_nvdata_default_show(struct device *cdev, struct device_attribute
        return snprintf(buf, PAGE_SIZE, "%08xh\n",
            le32_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word));
 }
-static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
-       _ctl_version_nvdata_default_show, NULL);
+static DEVICE_ATTR_RO(version_nvdata_default);
 
 /**
- * _ctl_board_name_show - board name
+ * board_name_show - board name
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -2590,7 +2592,7 @@ static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
  * A sysfs 'read-only' shost attribute.
  */
 static ssize_t
-_ctl_board_name_show(struct device *cdev, struct device_attribute *attr,
+board_name_show(struct device *cdev, struct device_attribute *attr,
        char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2598,10 +2600,10 @@ _ctl_board_name_show(struct device *cdev, struct device_attribute *attr,
 
        return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardName);
 }
-static DEVICE_ATTR(board_name, S_IRUGO, _ctl_board_name_show, NULL);
+static DEVICE_ATTR_RO(board_name);
 
 /**
- * _ctl_board_assembly_show - board assembly name
+ * board_assembly_show - board assembly name
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -2609,7 +2611,7 @@ static DEVICE_ATTR(board_name, S_IRUGO, _ctl_board_name_show, NULL);
  * A sysfs 'read-only' shost attribute.
  */
 static ssize_t
-_ctl_board_assembly_show(struct device *cdev, struct device_attribute *attr,
+board_assembly_show(struct device *cdev, struct device_attribute *attr,
        char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2617,10 +2619,10 @@ _ctl_board_assembly_show(struct device *cdev, struct device_attribute *attr,
 
        return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardAssembly);
 }
-static DEVICE_ATTR(board_assembly, S_IRUGO, _ctl_board_assembly_show, NULL);
+static DEVICE_ATTR_RO(board_assembly);
 
 /**
- * _ctl_board_tracer_show - board tracer number
+ * board_tracer_show - board tracer number
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -2628,7 +2630,7 @@ static DEVICE_ATTR(board_assembly, S_IRUGO, _ctl_board_assembly_show, NULL);
  * A sysfs 'read-only' shost attribute.
  */
 static ssize_t
-_ctl_board_tracer_show(struct device *cdev, struct device_attribute *attr,
+board_tracer_show(struct device *cdev, struct device_attribute *attr,
        char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2636,10 +2638,10 @@ _ctl_board_tracer_show(struct device *cdev, struct device_attribute *attr,
 
        return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardTracerNumber);
 }
-static DEVICE_ATTR(board_tracer, S_IRUGO, _ctl_board_tracer_show, NULL);
+static DEVICE_ATTR_RO(board_tracer);
 
 /**
- * _ctl_io_delay_show - io missing delay
+ * io_delay_show - io missing delay
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -2650,7 +2652,7 @@ static DEVICE_ATTR(board_tracer, S_IRUGO, _ctl_board_tracer_show, NULL);
  * A sysfs 'read-only' shost attribute.
  */
 static ssize_t
-_ctl_io_delay_show(struct device *cdev, struct device_attribute *attr,
+io_delay_show(struct device *cdev, struct device_attribute *attr,
        char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2658,10 +2660,10 @@ _ctl_io_delay_show(struct device *cdev, struct device_attribute *attr,
 
        return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
 }
-static DEVICE_ATTR(io_delay, S_IRUGO, _ctl_io_delay_show, NULL);
+static DEVICE_ATTR_RO(io_delay);
 
 /**
- * _ctl_device_delay_show - device missing delay
+ * device_delay_show - device missing delay
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -2672,7 +2674,7 @@ static DEVICE_ATTR(io_delay, S_IRUGO, _ctl_io_delay_show, NULL);
  * A sysfs 'read-only' shost attribute.
  */
 static ssize_t
-_ctl_device_delay_show(struct device *cdev, struct device_attribute *attr,
+device_delay_show(struct device *cdev, struct device_attribute *attr,
        char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2680,10 +2682,10 @@ _ctl_device_delay_show(struct device *cdev, struct device_attribute *attr,
 
        return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
 }
-static DEVICE_ATTR(device_delay, S_IRUGO, _ctl_device_delay_show, NULL);
+static DEVICE_ATTR_RO(device_delay);
 
 /**
- * _ctl_fw_queue_depth_show - global credits
+ * fw_queue_depth_show - global credits
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -2693,7 +2695,7 @@ static DEVICE_ATTR(device_delay, S_IRUGO, _ctl_device_delay_show, NULL);
  * A sysfs 'read-only' shost attribute.
  */
 static ssize_t
-_ctl_fw_queue_depth_show(struct device *cdev, struct device_attribute *attr,
+fw_queue_depth_show(struct device *cdev, struct device_attribute *attr,
        char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2701,10 +2703,10 @@ _ctl_fw_queue_depth_show(struct device *cdev, struct device_attribute *attr,
 
        return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->facts.RequestCredit);
 }
-static DEVICE_ATTR(fw_queue_depth, S_IRUGO, _ctl_fw_queue_depth_show, NULL);
+static DEVICE_ATTR_RO(fw_queue_depth);
 
 /**
- * _ctl_sas_address_show - sas address
+ * sas_address_show - sas address
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -2714,7 +2716,7 @@ static DEVICE_ATTR(fw_queue_depth, S_IRUGO, _ctl_fw_queue_depth_show, NULL);
  * A sysfs 'read-only' shost attribute.
  */
 static ssize_t
-_ctl_host_sas_address_show(struct device *cdev, struct device_attribute *attr,
+host_sas_address_show(struct device *cdev, struct device_attribute *attr,
        char *buf)
 
 {
@@ -2724,11 +2726,10 @@ _ctl_host_sas_address_show(struct device *cdev, struct device_attribute *attr,
        return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
            (unsigned long long)ioc->sas_hba.sas_address);
 }
-static DEVICE_ATTR(host_sas_address, S_IRUGO,
-       _ctl_host_sas_address_show, NULL);
+static DEVICE_ATTR_RO(host_sas_address);
 
 /**
- * _ctl_logging_level_show - logging level
+ * logging_level_show - logging level
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -2736,7 +2737,7 @@ static DEVICE_ATTR(host_sas_address, S_IRUGO,
  * A sysfs 'read/write' shost attribute.
  */
 static ssize_t
-_ctl_logging_level_show(struct device *cdev, struct device_attribute *attr,
+logging_level_show(struct device *cdev, struct device_attribute *attr,
        char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2745,7 +2746,7 @@ _ctl_logging_level_show(struct device *cdev, struct device_attribute *attr,
        return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->logging_level);
 }
 static ssize_t
-_ctl_logging_level_store(struct device *cdev, struct device_attribute *attr,
+logging_level_store(struct device *cdev, struct device_attribute *attr,
        const char *buf, size_t count)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2760,11 +2761,10 @@ _ctl_logging_level_store(struct device *cdev, struct device_attribute *attr,
                 ioc->logging_level);
        return strlen(buf);
 }
-static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, _ctl_logging_level_show,
-       _ctl_logging_level_store);
+static DEVICE_ATTR_RW(logging_level);
 
 /**
- * _ctl_fwfault_debug_show - show/store fwfault_debug
+ * fwfault_debug_show - show/store fwfault_debug
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -2773,7 +2773,7 @@ static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, _ctl_logging_level_show,
  * A sysfs 'read/write' shost attribute.
  */
 static ssize_t
-_ctl_fwfault_debug_show(struct device *cdev, struct device_attribute *attr,
+fwfault_debug_show(struct device *cdev, struct device_attribute *attr,
        char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2782,7 +2782,7 @@ _ctl_fwfault_debug_show(struct device *cdev, struct device_attribute *attr,
        return snprintf(buf, PAGE_SIZE, "%d\n", ioc->fwfault_debug);
 }
 static ssize_t
-_ctl_fwfault_debug_store(struct device *cdev, struct device_attribute *attr,
+fwfault_debug_store(struct device *cdev, struct device_attribute *attr,
        const char *buf, size_t count)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2797,11 +2797,10 @@ _ctl_fwfault_debug_store(struct device *cdev, struct device_attribute *attr,
                 ioc->fwfault_debug);
        return strlen(buf);
 }
-static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR,
-       _ctl_fwfault_debug_show, _ctl_fwfault_debug_store);
+static DEVICE_ATTR_RW(fwfault_debug);
 
 /**
- * _ctl_ioc_reset_count_show - ioc reset count
+ * ioc_reset_count_show - ioc reset count
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -2811,7 +2810,7 @@ static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR,
  * A sysfs 'read-only' shost attribute.
  */
 static ssize_t
-_ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr,
+ioc_reset_count_show(struct device *cdev, struct device_attribute *attr,
        char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2819,10 +2818,10 @@ _ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr,
 
        return snprintf(buf, PAGE_SIZE, "%d\n", ioc->ioc_reset_count);
 }
-static DEVICE_ATTR(ioc_reset_count, S_IRUGO, _ctl_ioc_reset_count_show, NULL);
+static DEVICE_ATTR_RO(ioc_reset_count);
 
 /**
- * _ctl_ioc_reply_queue_count_show - number of reply queues
+ * reply_queue_count_show - number of reply queues
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -2832,7 +2831,7 @@ static DEVICE_ATTR(ioc_reset_count, S_IRUGO, _ctl_ioc_reset_count_show, NULL);
  * A sysfs 'read-only' shost attribute.
  */
 static ssize_t
-_ctl_ioc_reply_queue_count_show(struct device *cdev,
+reply_queue_count_show(struct device *cdev,
        struct device_attribute *attr, char *buf)
 {
        u8 reply_queue_count;
@@ -2847,11 +2846,10 @@ _ctl_ioc_reply_queue_count_show(struct device *cdev,
 
        return snprintf(buf, PAGE_SIZE, "%d\n", reply_queue_count);
 }
-static DEVICE_ATTR(reply_queue_count, S_IRUGO, _ctl_ioc_reply_queue_count_show,
-       NULL);
+static DEVICE_ATTR_RO(reply_queue_count);
 
 /**
- * _ctl_BRM_status_show - Backup Rail Monitor Status
+ * BRM_status_show - Backup Rail Monitor Status
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -2861,7 +2859,7 @@ static DEVICE_ATTR(reply_queue_count, S_IRUGO, _ctl_ioc_reply_queue_count_show,
  * A sysfs 'read-only' shost attribute.
  */
 static ssize_t
-_ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr,
+BRM_status_show(struct device *cdev, struct device_attribute *attr,
        char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2923,7 +2921,7 @@ _ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr,
        mutex_unlock(&ioc->pci_access_mutex);
        return rc;
 }
-static DEVICE_ATTR(BRM_status, S_IRUGO, _ctl_BRM_status_show, NULL);
+static DEVICE_ATTR_RO(BRM_status);
 
 struct DIAG_BUFFER_START {
        __le32  Size;
@@ -2936,7 +2934,7 @@ struct DIAG_BUFFER_START {
 };
 
 /**
- * _ctl_host_trace_buffer_size_show - host buffer size (trace only)
+ * host_trace_buffer_size_show - host buffer size (trace only)
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -2944,7 +2942,7 @@ struct DIAG_BUFFER_START {
  * A sysfs 'read-only' shost attribute.
  */
 static ssize_t
-_ctl_host_trace_buffer_size_show(struct device *cdev,
+host_trace_buffer_size_show(struct device *cdev,
        struct device_attribute *attr, char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2976,11 +2974,10 @@ _ctl_host_trace_buffer_size_show(struct device *cdev,
        ioc->ring_buffer_sz = size;
        return snprintf(buf, PAGE_SIZE, "%d\n", size);
 }
-static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO,
-       _ctl_host_trace_buffer_size_show, NULL);
+static DEVICE_ATTR_RO(host_trace_buffer_size);
 
 /**
- * _ctl_host_trace_buffer_show - firmware ring buffer (trace only)
+ * host_trace_buffer_show - firmware ring buffer (trace only)
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -2992,7 +2989,7 @@ static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO,
  * offset to the same attribute, it will move the pointer.
  */
 static ssize_t
-_ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr,
+host_trace_buffer_show(struct device *cdev, struct device_attribute *attr,
        char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3024,7 +3021,7 @@ _ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr,
 }
 
 static ssize_t
-_ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr,
+host_trace_buffer_store(struct device *cdev, struct device_attribute *attr,
        const char *buf, size_t count)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3037,14 +3034,13 @@ _ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr,
        ioc->ring_buffer_offset = val;
        return strlen(buf);
 }
-static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR,
-       _ctl_host_trace_buffer_show, _ctl_host_trace_buffer_store);
+static DEVICE_ATTR_RW(host_trace_buffer);
 
 
 /*****************************************/
 
 /**
- * _ctl_host_trace_buffer_enable_show - firmware ring buffer (trace only)
+ * host_trace_buffer_enable_show - firmware ring buffer (trace only)
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -3054,7 +3050,7 @@ static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR,
  * This is a mechnism to post/release host_trace_buffers
  */
 static ssize_t
-_ctl_host_trace_buffer_enable_show(struct device *cdev,
+host_trace_buffer_enable_show(struct device *cdev,
        struct device_attribute *attr, char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3072,7 +3068,7 @@ _ctl_host_trace_buffer_enable_show(struct device *cdev,
 }
 
 static ssize_t
-_ctl_host_trace_buffer_enable_store(struct device *cdev,
+host_trace_buffer_enable_store(struct device *cdev,
        struct device_attribute *attr, const char *buf, size_t count)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3122,14 +3118,12 @@ _ctl_host_trace_buffer_enable_store(struct device *cdev,
  out:
        return strlen(buf);
 }
-static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR,
-       _ctl_host_trace_buffer_enable_show,
-       _ctl_host_trace_buffer_enable_store);
+static DEVICE_ATTR_RW(host_trace_buffer_enable);
 
 /*********** diagnostic trigger suppport *********************************/
 
 /**
- * _ctl_diag_trigger_master_show - show the diag_trigger_master attribute
+ * diag_trigger_master_show - show the diag_trigger_master attribute
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -3137,7 +3131,7 @@ static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR,
  * A sysfs 'read/write' shost attribute.
  */
 static ssize_t
-_ctl_diag_trigger_master_show(struct device *cdev,
+diag_trigger_master_show(struct device *cdev,
        struct device_attribute *attr, char *buf)
 
 {
@@ -3154,7 +3148,7 @@ _ctl_diag_trigger_master_show(struct device *cdev,
 }
 
 /**
- * _ctl_diag_trigger_master_store - store the diag_trigger_master attribute
+ * diag_trigger_master_store - store the diag_trigger_master attribute
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -3163,7 +3157,7 @@ _ctl_diag_trigger_master_show(struct device *cdev,
  * A sysfs 'read/write' shost attribute.
  */
 static ssize_t
-_ctl_diag_trigger_master_store(struct device *cdev,
+diag_trigger_master_store(struct device *cdev,
        struct device_attribute *attr, const char *buf, size_t count)
 
 {
@@ -3182,12 +3176,11 @@ _ctl_diag_trigger_master_store(struct device *cdev,
        spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
        return rc;
 }
-static DEVICE_ATTR(diag_trigger_master, S_IRUGO | S_IWUSR,
-       _ctl_diag_trigger_master_show, _ctl_diag_trigger_master_store);
+static DEVICE_ATTR_RW(diag_trigger_master);
 
 
 /**
- * _ctl_diag_trigger_event_show - show the diag_trigger_event attribute
+ * diag_trigger_event_show - show the diag_trigger_event attribute
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -3195,7 +3188,7 @@ static DEVICE_ATTR(diag_trigger_master, S_IRUGO | S_IWUSR,
  * A sysfs 'read/write' shost attribute.
  */
 static ssize_t
-_ctl_diag_trigger_event_show(struct device *cdev,
+diag_trigger_event_show(struct device *cdev,
        struct device_attribute *attr, char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3211,7 +3204,7 @@ _ctl_diag_trigger_event_show(struct device *cdev,
 }
 
 /**
- * _ctl_diag_trigger_event_store - store the diag_trigger_event attribute
+ * diag_trigger_event_store - store the diag_trigger_event attribute
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -3220,7 +3213,7 @@ _ctl_diag_trigger_event_show(struct device *cdev,
  * A sysfs 'read/write' shost attribute.
  */
 static ssize_t
-_ctl_diag_trigger_event_store(struct device *cdev,
+diag_trigger_event_store(struct device *cdev,
        struct device_attribute *attr, const char *buf, size_t count)
 
 {
@@ -3239,12 +3232,11 @@ _ctl_diag_trigger_event_store(struct device *cdev,
        spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
        return sz;
 }
-static DEVICE_ATTR(diag_trigger_event, S_IRUGO | S_IWUSR,
-       _ctl_diag_trigger_event_show, _ctl_diag_trigger_event_store);
+static DEVICE_ATTR_RW(diag_trigger_event);
 
 
 /**
- * _ctl_diag_trigger_scsi_show - show the diag_trigger_scsi attribute
+ * diag_trigger_scsi_show - show the diag_trigger_scsi attribute
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -3252,7 +3244,7 @@ static DEVICE_ATTR(diag_trigger_event, S_IRUGO | S_IWUSR,
  * A sysfs 'read/write' shost attribute.
  */
 static ssize_t
-_ctl_diag_trigger_scsi_show(struct device *cdev,
+diag_trigger_scsi_show(struct device *cdev,
        struct device_attribute *attr, char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3268,7 +3260,7 @@ _ctl_diag_trigger_scsi_show(struct device *cdev,
 }
 
 /**
- * _ctl_diag_trigger_scsi_store - store the diag_trigger_scsi attribute
+ * diag_trigger_scsi_store - store the diag_trigger_scsi attribute
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -3277,7 +3269,7 @@ _ctl_diag_trigger_scsi_show(struct device *cdev,
  * A sysfs 'read/write' shost attribute.
  */
 static ssize_t
-_ctl_diag_trigger_scsi_store(struct device *cdev,
+diag_trigger_scsi_store(struct device *cdev,
        struct device_attribute *attr, const char *buf, size_t count)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3295,12 +3287,11 @@ _ctl_diag_trigger_scsi_store(struct device *cdev,
        spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
        return sz;
 }
-static DEVICE_ATTR(diag_trigger_scsi, S_IRUGO | S_IWUSR,
-       _ctl_diag_trigger_scsi_show, _ctl_diag_trigger_scsi_store);
+static DEVICE_ATTR_RW(diag_trigger_scsi);
 
 
 /**
- * _ctl_diag_trigger_scsi_show - show the diag_trigger_mpi attribute
+ * diag_trigger_scsi_show - show the diag_trigger_mpi attribute
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -3308,7 +3299,7 @@ static DEVICE_ATTR(diag_trigger_scsi, S_IRUGO | S_IWUSR,
  * A sysfs 'read/write' shost attribute.
  */
 static ssize_t
-_ctl_diag_trigger_mpi_show(struct device *cdev,
+diag_trigger_mpi_show(struct device *cdev,
        struct device_attribute *attr, char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3324,7 +3315,7 @@ _ctl_diag_trigger_mpi_show(struct device *cdev,
 }
 
 /**
- * _ctl_diag_trigger_mpi_store - store the diag_trigger_mpi attribute
+ * diag_trigger_mpi_store - store the diag_trigger_mpi attribute
  * @cdev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -3333,7 +3324,7 @@ _ctl_diag_trigger_mpi_show(struct device *cdev,
  * A sysfs 'read/write' shost attribute.
  */
 static ssize_t
-_ctl_diag_trigger_mpi_store(struct device *cdev,
+diag_trigger_mpi_store(struct device *cdev,
        struct device_attribute *attr, const char *buf, size_t count)
 {
        struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3352,8 +3343,7 @@ _ctl_diag_trigger_mpi_store(struct device *cdev,
        return sz;
 }
 
-static DEVICE_ATTR(diag_trigger_mpi, S_IRUGO | S_IWUSR,
-       _ctl_diag_trigger_mpi_show, _ctl_diag_trigger_mpi_store);
+static DEVICE_ATTR_RW(diag_trigger_mpi);
 
 /*********** diagnostic trigger suppport *** END ****************************/
 
@@ -3391,7 +3381,7 @@ struct device_attribute *mpt3sas_host_attrs[] = {
 /* device attributes */
 
 /**
- * _ctl_device_sas_address_show - sas address
+ * sas_address_show - sas address
  * @dev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -3401,7 +3391,7 @@ struct device_attribute *mpt3sas_host_attrs[] = {
  * A sysfs 'read-only' shost attribute.
  */
 static ssize_t
-_ctl_device_sas_address_show(struct device *dev, struct device_attribute *attr,
+sas_address_show(struct device *dev, struct device_attribute *attr,
        char *buf)
 {
        struct scsi_device *sdev = to_scsi_device(dev);
@@ -3410,10 +3400,10 @@ _ctl_device_sas_address_show(struct device *dev, struct device_attribute *attr,
        return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
            (unsigned long long)sas_device_priv_data->sas_target->sas_address);
 }
-static DEVICE_ATTR(sas_address, S_IRUGO, _ctl_device_sas_address_show, NULL);
+static DEVICE_ATTR_RO(sas_address);
 
 /**
- * _ctl_device_handle_show - device handle
+ * sas_device_handle_show - device handle
  * @dev: pointer to embedded class device
  * @attr: ?
  * @buf: the buffer returned
@@ -3423,7 +3413,7 @@ static DEVICE_ATTR(sas_address, S_IRUGO, _ctl_device_sas_address_show, NULL);
  * A sysfs 'read-only' shost attribute.
  */
 static ssize_t
-_ctl_device_handle_show(struct device *dev, struct device_attribute *attr,
+sas_device_handle_show(struct device *dev, struct device_attribute *attr,
        char *buf)
 {
        struct scsi_device *sdev = to_scsi_device(dev);
@@ -3432,10 +3422,10 @@ _ctl_device_handle_show(struct device *dev, struct device_attribute *attr,
        return snprintf(buf, PAGE_SIZE, "0x%04x\n",
            sas_device_priv_data->sas_target->handle);
 }
-static DEVICE_ATTR(sas_device_handle, S_IRUGO, _ctl_device_handle_show, NULL);
+static DEVICE_ATTR_RO(sas_device_handle);
 
 /**
- * _ctl_device_ncq_io_prio_show - send prioritized io commands to device
+ * sas_ncq_io_prio_show - send prioritized io commands to device
  * @dev: pointer to embedded device
  * @attr: ?
  * @buf: the buffer returned
@@ -3443,7 +3433,7 @@ static DEVICE_ATTR(sas_device_handle, S_IRUGO, _ctl_device_handle_show, NULL);
  * A sysfs 'read/write' sdev attribute, only works with SATA
  */
 static ssize_t
-_ctl_device_ncq_prio_enable_show(struct device *dev,
+sas_ncq_prio_enable_show(struct device *dev,
                                 struct device_attribute *attr, char *buf)
 {
        struct scsi_device *sdev = to_scsi_device(dev);
@@ -3454,7 +3444,7 @@ _ctl_device_ncq_prio_enable_show(struct device *dev,
 }
 
 static ssize_t
-_ctl_device_ncq_prio_enable_store(struct device *dev,
+sas_ncq_prio_enable_store(struct device *dev,
                                  struct device_attribute *attr,
                                  const char *buf, size_t count)
 {
@@ -3471,9 +3461,7 @@ _ctl_device_ncq_prio_enable_store(struct device *dev,
        sas_device_priv_data->ncq_prio_enable = ncq_prio_enable;
        return strlen(buf);
 }
-static DEVICE_ATTR(sas_ncq_prio_enable, S_IRUGO | S_IWUSR,
-                  _ctl_device_ncq_prio_enable_show,
-                  _ctl_device_ncq_prio_enable_store);
+static DEVICE_ATTR_RW(sas_ncq_prio_enable);
 
 struct device_attribute *mpt3sas_dev_attrs[] = {
        &dev_attr_sas_address,
index 1ccfbc7..27c731a 100644 (file)
@@ -113,22 +113,22 @@ MODULE_PARM_DESC(logging_level,
 
 
 static ushort max_sectors = 0xFFFF;
-module_param(max_sectors, ushort, 0);
+module_param(max_sectors, ushort, 0444);
 MODULE_PARM_DESC(max_sectors, "max sectors, range 64 to 32767  default=32767");
 
 
 static int missing_delay[2] = {-1, -1};
-module_param_array(missing_delay, int, NULL, 0);
+module_param_array(missing_delay, int, NULL, 0444);
 MODULE_PARM_DESC(missing_delay, " device missing delay , io missing delay");
 
 /* scsi-mid layer global parmeter is max_report_luns, which is 511 */
 #define MPT3SAS_MAX_LUN (16895)
 static u64 max_lun = MPT3SAS_MAX_LUN;
-module_param(max_lun, ullong, 0);
+module_param(max_lun, ullong, 0444);
 MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
 
 static ushort hbas_to_enumerate;
-module_param(hbas_to_enumerate, ushort, 0);
+module_param(hbas_to_enumerate, ushort, 0444);
 MODULE_PARM_DESC(hbas_to_enumerate,
                " 0 - enumerates both SAS 2.0 & SAS 3.0 generation HBAs\n \
                  1 - enumerates only SAS 2.0 generation HBAs\n \
@@ -142,17 +142,17 @@ MODULE_PARM_DESC(hbas_to_enumerate,
  * Either bit can be set, or both
  */
 static int diag_buffer_enable = -1;
-module_param(diag_buffer_enable, int, 0);
+module_param(diag_buffer_enable, int, 0444);
 MODULE_PARM_DESC(diag_buffer_enable,
        " post diag buffers (TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)");
 static int disable_discovery = -1;
-module_param(disable_discovery, int, 0);
+module_param(disable_discovery, int, 0444);
 MODULE_PARM_DESC(disable_discovery, " disable discovery ");
 
 
 /* permit overriding the host protection capabilities mask (EEDP/T10 PI) */
 static int prot_mask = -1;
-module_param(prot_mask, int, 0);
+module_param(prot_mask, int, 0444);
 MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=7 ");
 
 
@@ -2685,7 +2685,7 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, u64 lun,
        int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
        mpt3sas_scsih_set_tm_flag(ioc, handle);
        init_completion(&ioc->tm_cmds.done);
-       mpt3sas_base_put_smid_hi_priority(ioc, smid, msix_task);
+       ioc->put_smid_hi_priority(ioc, smid, msix_task);
        wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
        if (!(ioc->tm_cmds.status & MPT3_CMD_COMPLETE)) {
                if (mpt3sas_base_check_cmd_timeout(ioc,
@@ -3659,7 +3659,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
        mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
        mpi_request->MsgFlags = tr_method;
        set_bit(handle, ioc->device_remove_in_progress);
-       mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
+       ioc->put_smid_hi_priority(ioc, smid, 0);
        mpt3sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL);
 
 out:
@@ -3755,7 +3755,7 @@ _scsih_tm_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
        mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
        mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
        mpi_request->DevHandle = mpi_request_tm->DevHandle;
-       mpt3sas_base_put_smid_default(ioc, smid_sas_ctrl);
+       ioc->put_smid_default(ioc, smid_sas_ctrl);
 
        return _scsih_check_for_pending_tm(ioc, smid);
 }
@@ -3881,7 +3881,7 @@ _scsih_tm_tr_volume_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
        mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
        mpi_request->DevHandle = cpu_to_le16(handle);
        mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
-       mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
+       ioc->put_smid_hi_priority(ioc, smid, 0);
 }
 
 /**
@@ -3970,7 +3970,7 @@ _scsih_issue_delayed_event_ack(struct MPT3SAS_ADAPTER *ioc, u16 smid, U16 event,
        ack_request->EventContext = event_context;
        ack_request->VF_ID = 0;  /* TODO */
        ack_request->VP_ID = 0;
-       mpt3sas_base_put_smid_default(ioc, smid);
+       ioc->put_smid_default(ioc, smid);
 }
 
 /**
@@ -4026,7 +4026,7 @@ _scsih_issue_delayed_sas_io_unit_ctrl(struct MPT3SAS_ADAPTER *ioc,
        mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
        mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
        mpi_request->DevHandle = cpu_to_le16(handle);
-       mpt3sas_base_put_smid_default(ioc, smid);
+       ioc->put_smid_default(ioc, smid);
 }
 
 /**
@@ -4734,12 +4734,12 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
                if (sas_target_priv_data->flags & MPT_TARGET_FASTPATH_IO) {
                        mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len |
                            MPI25_SCSIIO_IOFLAGS_FAST_PATH);
-                       mpt3sas_base_put_smid_fast_path(ioc, smid, handle);
+                       ioc->put_smid_fast_path(ioc, smid, handle);
                } else
                        ioc->put_smid_scsi_io(ioc, smid,
                            le16_to_cpu(mpi_request->DevHandle));
        } else
-               mpt3sas_base_put_smid_default(ioc, smid);
+               ioc->put_smid_default(ioc, smid);
        return 0;
 
  out:
@@ -5210,6 +5210,7 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
             ((ioc_status & MPI2_IOCSTATUS_MASK)
              != MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) {
                st->direct_io = 0;
+               st->scmd = scmd;
                memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
                mpi_request->DevHandle =
                    cpu_to_le16(sas_device_priv_data->sas_target->handle);
@@ -7601,7 +7602,7 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num)
                            handle, phys_disk_num));
 
        init_completion(&ioc->scsih_cmds.done);
-       mpt3sas_base_put_smid_default(ioc, smid);
+       ioc->put_smid_default(ioc, smid);
        wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
 
        if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -9633,7 +9634,7 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc)
        if (!ioc->hide_ir_msg)
                ioc_info(ioc, "IR shutdown (sending)\n");
        init_completion(&ioc->scsih_cmds.done);
-       mpt3sas_base_put_smid_default(ioc, smid);
+       ioc->put_smid_default(ioc, smid);
        wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
 
        if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -9670,6 +9671,7 @@ static void scsih_remove(struct pci_dev *pdev)
        struct _pcie_device *pcie_device, *pcienext;
        struct workqueue_struct *wq;
        unsigned long flags;
+       Mpi2ConfigReply_t mpi_reply;
 
        ioc->remove_host = 1;
 
@@ -9684,7 +9686,13 @@ static void scsih_remove(struct pci_dev *pdev)
        spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
        if (wq)
                destroy_workqueue(wq);
-
+       /*
+        * Copy back the unmodified ioc page1. so that on next driver load,
+        * current modified changes on ioc page1 won't take effect.
+        */
+       if (ioc->is_aero_ioc)
+               mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply,
+                               &ioc->ioc_pg1_copy);
        /* release all the volumes */
        _scsih_ir_shutdown(ioc);
        sas_remove_host(shost);
@@ -9747,6 +9755,7 @@ scsih_shutdown(struct pci_dev *pdev)
        struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
        struct workqueue_struct *wq;
        unsigned long flags;
+       Mpi2ConfigReply_t mpi_reply;
 
        ioc->remove_host = 1;
 
@@ -9761,6 +9770,13 @@ scsih_shutdown(struct pci_dev *pdev)
        spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
        if (wq)
                destroy_workqueue(wq);
+       /*
+        * Copy back the unmodified ioc page1 so that on next driver load,
+        * current modified changes on ioc page1 won't take effect.
+        */
+       if (ioc->is_aero_ioc)
+               mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply,
+                               &ioc->ioc_pg1_copy);
 
        _scsih_ir_shutdown(ioc);
        mpt3sas_base_detach(ioc);
index 60ae2d0..5324662 100644 (file)
@@ -367,7 +367,7 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc,
                         ioc_info(ioc, "report_manufacture - send to sas_addr(0x%016llx)\n",
                                  (u64)sas_address));
        init_completion(&ioc->transport_cmds.done);
-       mpt3sas_base_put_smid_default(ioc, smid);
+       ioc->put_smid_default(ioc, smid);
        wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
 
        if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -1139,7 +1139,7 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc,
                                  (u64)phy->identify.sas_address,
                                  phy->number));
        init_completion(&ioc->transport_cmds.done);
-       mpt3sas_base_put_smid_default(ioc, smid);
+       ioc->put_smid_default(ioc, smid);
        wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
 
        if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -1434,7 +1434,7 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc,
                                  (u64)phy->identify.sas_address,
                                  phy->number, phy_operation));
        init_completion(&ioc->transport_cmds.done);
-       mpt3sas_base_put_smid_default(ioc, smid);
+       ioc->put_smid_default(ioc, smid);
        wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
 
        if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -1911,7 +1911,7 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
                         ioc_info(ioc, "%s: sending smp request\n", __func__));
 
        init_completion(&ioc->transport_cmds.done);
-       mpt3sas_base_put_smid_default(ioc, smid);
+       ioc->put_smid_default(ioc, smid);
        wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
 
        if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
index 6dcae0e..3e0b8eb 100644 (file)
@@ -1193,7 +1193,7 @@ static int mvs_dev_found_notify(struct domain_device *dev, int lock)
        mvi_device->dev_type = dev->dev_type;
        mvi_device->mvi_info = mvi;
        mvi_device->sas_device = dev;
-       if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
+       if (parent_dev && dev_is_expander(parent_dev->dev_type)) {
                int phy_id;
                u8 phy_num = parent_dev->ex_dev.num_phys;
                struct ex_phy *phy;
index b7d7ec4..519edc7 100644 (file)
@@ -50,9 +50,6 @@ extern struct mvs_info *tgt_mvi;
 extern const struct mvs_dispatch mvs_64xx_dispatch;
 extern const struct mvs_dispatch mvs_94xx_dispatch;
 
-#define DEV_IS_EXPANDER(type)  \
-       ((type == SAS_EDGE_EXPANDER_DEVICE) || (type == SAS_FANOUT_EXPANDER_DEVICE))
-
 #define bit(n) ((u64)1 << n)
 
 #define for_each_phy(__lseq_mask, __mc, __lseq)                        \
index 1fb6f6c..8906ace 100644 (file)
@@ -195,23 +195,22 @@ static int mvumi_make_sgl(struct mvumi_hba *mhba, struct scsi_cmnd *scmd,
        unsigned int sgnum = scsi_sg_count(scmd);
        dma_addr_t busaddr;
 
-       sg = scsi_sglist(scmd);
-       *sg_count = dma_map_sg(&mhba->pdev->dev, sg, sgnum,
+       *sg_count = dma_map_sg(&mhba->pdev->dev, scsi_sglist(scmd), sgnum,
                               scmd->sc_data_direction);
        if (*sg_count > mhba->max_sge) {
                dev_err(&mhba->pdev->dev,
                        "sg count[0x%x] is bigger than max sg[0x%x].\n",
                        *sg_count, mhba->max_sge);
-               dma_unmap_sg(&mhba->pdev->dev, sg, sgnum,
+               dma_unmap_sg(&mhba->pdev->dev, scsi_sglist(scmd), sgnum,
                             scmd->sc_data_direction);
                return -1;
        }
-       for (i = 0; i < *sg_count; i++) {
-               busaddr = sg_dma_address(&sg[i]);
+       scsi_for_each_sg(scmd, sg, *sg_count, i) {
+               busaddr = sg_dma_address(sg);
                m_sg->baseaddr_l = cpu_to_le32(lower_32_bits(busaddr));
                m_sg->baseaddr_h = cpu_to_le32(upper_32_bits(busaddr));
                m_sg->flags = 0;
-               sgd_setsz(mhba, m_sg, cpu_to_le32(sg_dma_len(&sg[i])));
+               sgd_setsz(mhba, m_sg, cpu_to_le32(sg_dma_len(sg)));
                if ((i + 1) == *sg_count)
                        m_sg->flags |= 1U << mhba->eot_flag;
 
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
deleted file mode 100644 (file)
index 815bb40..0000000
+++ /dev/null
@@ -1,6108 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
-  SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying
-  file Documentation/scsi/st.txt for more information.
-
-  History:
-
-  OnStream SCSI Tape support (osst) cloned from st.c by
-  Willem Riede (osst@riede.org) Feb 2000
-  Fixes ... Kurt Garloff <garloff@suse.de> Mar 2000
-
-  Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
-  Contribution and ideas from several people including (in alphabetical
-  order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer,
-  Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale.
-
-  Copyright 1992 - 2002 Kai Makisara / 2000 - 2006 Willem Riede
-        email osst@riede.org
-
-  $Header: /cvsroot/osst/Driver/osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $
-
-  Microscopic alterations - Rik Ling, 2000/12/21
-  Last st.c sync: Tue Oct 15 22:01:04 2002 by makisara
-  Some small formal changes - aeb, 950809
-*/
-
-static const char * cvsid = "$Id: osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $";
-static const char * osst_version = "0.99.4";
-
-/* The "failure to reconnect" firmware bug */
-#define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/
-#define OSST_FW_NEED_POLL_MAX 10704 /*(108D)*/
-#define OSST_FW_NEED_POLL(x,d) ((x) >= OSST_FW_NEED_POLL_MIN && (x) <= OSST_FW_NEED_POLL_MAX && d->host->this_id != 7)
-
-#include <linux/module.h>
-
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/sched/signal.h>
-#include <linux/proc_fs.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/mtio.h>
-#include <linux/ioctl.h>
-#include <linux/fcntl.h>
-#include <linux/spinlock.h>
-#include <linux/vmalloc.h>
-#include <linux/blkdev.h>
-#include <linux/moduleparam.h>
-#include <linux/delay.h>
-#include <linux/jiffies.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-#include <asm/dma.h>
-
-/* The driver prints some debugging information on the console if DEBUG
-   is defined and non-zero. */
-#define DEBUG 0
-
-/* The message level for the debug messages is currently set to KERN_NOTICE
-   so that people can easily see the messages. Later when the debugging messages
-   in the drivers are more widely classified, this may be changed to KERN_DEBUG. */
-#define OSST_DEB_MSG  KERN_NOTICE
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_driver.h>
-#include <scsi/scsi_eh.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_ioctl.h>
-
-#define ST_KILOBYTE 1024
-
-#include "st.h"
-#include "osst.h"
-#include "osst_options.h"
-#include "osst_detect.h"
-
-static DEFINE_MUTEX(osst_int_mutex);
-static int max_dev = 0;
-static int write_threshold_kbs = 0;
-static int max_sg_segs = 0;
-
-#ifdef MODULE
-MODULE_AUTHOR("Willem Riede");
-MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV_MAJOR(OSST_MAJOR);
-MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE);
-
-module_param(max_dev, int, 0444);
-MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)");
-
-module_param(write_threshold_kbs, int, 0644);
-MODULE_PARM_DESC(write_threshold_kbs, "Asynchronous write threshold (KB; 32)");
-
-module_param(max_sg_segs, int, 0644);
-MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (9)");
-#else
-static struct osst_dev_parm {
-       char   *name;
-       int    *val;
-} parms[] __initdata = {
-       { "max_dev",             &max_dev             },
-       { "write_threshold_kbs", &write_threshold_kbs },
-       { "max_sg_segs",         &max_sg_segs         }
-};
-#endif
-
-/* Some default definitions have been moved to osst_options.h */
-#define OSST_BUFFER_SIZE (OSST_BUFFER_BLOCKS * ST_KILOBYTE)
-#define OSST_WRITE_THRESHOLD (OSST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE)
-
-/* The buffer size should fit into the 24 bits for length in the
-   6-byte SCSI read and write commands. */
-#if OSST_BUFFER_SIZE >= (2 << 24 - 1)
-#error "Buffer size should not exceed (2 << 24 - 1) bytes!"
-#endif
-
-#if DEBUG
-static int debugging = 1;
-/* uncomment define below to test error recovery */
-// #define OSST_INJECT_ERRORS 1 
-#endif
-
-/* Do not retry! The drive firmware already retries when appropriate,
-   and when it tries to tell us something, we had better listen... */
-#define MAX_RETRIES 0
-
-#define NO_TAPE  NOT_READY
-
-#define OSST_WAIT_POSITION_COMPLETE   (HZ > 200 ? HZ / 200 : 1)
-#define OSST_WAIT_WRITE_COMPLETE      (HZ / 12)
-#define OSST_WAIT_LONG_WRITE_COMPLETE (HZ / 2)
-       
-#define OSST_TIMEOUT (200 * HZ)
-#define OSST_LONG_TIMEOUT (1800 * HZ)
-
-#define TAPE_NR(x) (iminor(x) & ((1 << ST_MODE_SHIFT)-1))
-#define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
-#define TAPE_REWIND(x) ((iminor(x) & 0x80) == 0)
-#define TAPE_IS_RAW(x) (TAPE_MODE(x) & (ST_NBR_MODES >> 1))
-
-/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower
-   24 bits) */
-#define SET_DENS_AND_BLK 0x10001
-
-static int osst_buffer_size       = OSST_BUFFER_SIZE;
-static int osst_write_threshold   = OSST_WRITE_THRESHOLD;
-static int osst_max_sg_segs       = OSST_MAX_SG;
-static int osst_max_dev           = OSST_MAX_TAPES;
-static int osst_nr_dev;
-
-static struct osst_tape **os_scsi_tapes = NULL;
-static DEFINE_RWLOCK(os_scsi_tapes_lock);
-
-static int modes_defined = 0;
-
-static struct osst_buffer *new_tape_buffer(int, int, int);
-static int enlarge_buffer(struct osst_buffer *, int);
-static void normalize_buffer(struct osst_buffer *);
-static int append_to_buffer(const char __user *, struct osst_buffer *, int);
-static int from_buffer(struct osst_buffer *, char __user *, int);
-static int osst_zero_buffer_tail(struct osst_buffer *);
-static int osst_copy_to_buffer(struct osst_buffer *, unsigned char *);
-static int osst_copy_from_buffer(struct osst_buffer *, unsigned char *);
-
-static int osst_probe(struct device *);
-static int osst_remove(struct device *);
-
-static struct scsi_driver osst_template = {
-       .gendrv = {
-               .name           =  "osst",
-               .owner          = THIS_MODULE,
-               .probe          = osst_probe,
-               .remove         = osst_remove,
-       }
-};
-
-static int osst_int_ioctl(struct osst_tape *STp, struct osst_request ** aSRpnt,
-                           unsigned int cmd_in, unsigned long arg);
-
-static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int frame, int skip);
-
-static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt);
-
-static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt);
-
-static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending);
-
-static inline char *tape_name(struct osst_tape *tape)
-{
-       return tape->drive->disk_name;
-}
-\f
-/* Routines that handle the interaction with mid-layer SCSI routines */
-
-
-/* Normalize Sense */
-static void osst_analyze_sense(struct osst_request *SRpnt, struct st_cmdstatus *s)
-{
-       const u8 *ucp;
-       const u8 *sense = SRpnt->sense;
-
-       s->have_sense = scsi_normalize_sense(SRpnt->sense,
-                               SCSI_SENSE_BUFFERSIZE, &s->sense_hdr);
-       s->flags = 0;
-
-       if (s->have_sense) {
-               s->deferred = 0;
-               s->remainder_valid =
-                       scsi_get_sense_info_fld(sense, SCSI_SENSE_BUFFERSIZE, &s->uremainder64);
-               switch (sense[0] & 0x7f) {
-               case 0x71:
-                       s->deferred = 1;
-                       /* fall through */
-               case 0x70:
-                       s->fixed_format = 1;
-                       s->flags = sense[2] & 0xe0;
-                       break;
-               case 0x73:
-                       s->deferred = 1;
-                       /* fall through */
-               case 0x72:
-                       s->fixed_format = 0;
-                       ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4);
-                       s->flags = ucp ? (ucp[3] & 0xe0) : 0;
-                       break;
-               }
-       }
-}
-
-/* Convert the result to success code */
-static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt)
-{
-       char *name = tape_name(STp);
-       int result = SRpnt->result;
-       u8 * sense = SRpnt->sense, scode;
-#if DEBUG
-       const char *stp;
-#endif
-       struct st_cmdstatus *cmdstatp;
-
-       if (!result)
-               return 0;
-
-       cmdstatp = &STp->buffer->cmdstat;
-       osst_analyze_sense(SRpnt, cmdstatp);
-
-       if (cmdstatp->have_sense)
-               scode = STp->buffer->cmdstat.sense_hdr.sense_key;
-       else
-               scode = 0;
-#if DEBUG
-       if (debugging) {
-               printk(OSST_DEB_MSG "%s:D: Error: %x, cmd: %x %x %x %x %x %x\n",
-                  name, result,
-                  SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2],
-                  SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]);
-               if (scode) printk(OSST_DEB_MSG "%s:D: Sense: %02x, ASC: %02x, ASCQ: %02x\n",
-                                 name, scode, sense[12], sense[13]);
-               if (cmdstatp->have_sense)
-                       __scsi_print_sense(STp->device, name,
-                                          SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
-       }
-       else
-#endif
-       if (cmdstatp->have_sense && (
-                scode != NO_SENSE &&
-                scode != RECOVERED_ERROR &&
-/*              scode != UNIT_ATTENTION && */
-                scode != BLANK_CHECK &&
-                scode != VOLUME_OVERFLOW &&
-                SRpnt->cmd[0] != MODE_SENSE &&
-                SRpnt->cmd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
-               if (cmdstatp->have_sense) {
-                       printk(KERN_WARNING "%s:W: Command with sense data:\n", name);
-                       __scsi_print_sense(STp->device, name,
-                                          SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
-               }
-               else {
-                       static  int     notyetprinted = 1;
-
-                       printk(KERN_WARNING
-                            "%s:W: Warning %x (driver bt 0x%x, host bt 0x%x).\n",
-                            name, result, driver_byte(result),
-                            host_byte(result));
-                       if (notyetprinted) {
-                               notyetprinted = 0;
-                               printk(KERN_INFO
-                                       "%s:I: This warning may be caused by your scsi controller,\n", name);
-                               printk(KERN_INFO
-                                       "%s:I: it has been reported with some Buslogic cards.\n", name);
-                       }
-               }
-       }
-       STp->pos_unknown |= STp->device->was_reset;
-
-       if (cmdstatp->have_sense && scode == RECOVERED_ERROR) {
-               STp->recover_count++;
-               STp->recover_erreg++;
-#if DEBUG
-               if (debugging) {
-                       if (SRpnt->cmd[0] == READ_6)
-                               stp = "read";
-                       else if (SRpnt->cmd[0] == WRITE_6)
-                               stp = "write";
-                       else
-                               stp = "ioctl";
-                       printk(OSST_DEB_MSG "%s:D: Recovered %s error (%d).\n", name, stp,
-                                            STp->recover_count);
-               }
-#endif
-               if ((sense[2] & 0xe0) == 0)
-                       return 0;
-       }
-       return (-EIO);
-}
-
-
-/* Wakeup from interrupt */
-static void osst_end_async(struct request *req, blk_status_t status)
-{
-       struct scsi_request *rq = scsi_req(req);
-       struct osst_request *SRpnt = req->end_io_data;
-       struct osst_tape *STp = SRpnt->stp;
-       struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data;
-
-       STp->buffer->cmdstat.midlevel_result = SRpnt->result = rq->result;
-#if DEBUG
-       STp->write_pending = 0;
-#endif
-       if (rq->sense_len)
-               memcpy(SRpnt->sense, rq->sense, SCSI_SENSE_BUFFERSIZE);
-       if (SRpnt->waiting)
-               complete(SRpnt->waiting);
-
-       if (SRpnt->bio) {
-               kfree(mdata->pages);
-               blk_rq_unmap_user(SRpnt->bio);
-       }
-
-       blk_put_request(req);
-}
-
-/* osst_request memory management */
-static struct osst_request *osst_allocate_request(void)
-{
-       return kzalloc(sizeof(struct osst_request), GFP_KERNEL);
-}
-
-static void osst_release_request(struct osst_request *streq)
-{
-       kfree(streq);
-}
-
-static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd,
-                       int cmd_len, int data_direction, void *buffer, unsigned bufflen,
-                       int use_sg, int timeout, int retries)
-{
-       struct request *req;
-       struct scsi_request *rq;
-       struct page **pages = NULL;
-       struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data;
-
-       int err = 0;
-       int write = (data_direction == DMA_TO_DEVICE);
-
-       req = blk_get_request(SRpnt->stp->device->request_queue,
-                       write ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0);
-       if (IS_ERR(req))
-               return DRIVER_ERROR << 24;
-
-       rq = scsi_req(req);
-       req->rq_flags |= RQF_QUIET;
-
-       SRpnt->bio = NULL;
-
-       if (use_sg) {
-               struct scatterlist *sg, *sgl = (struct scatterlist *)buffer;
-               int i;
-
-               pages = kcalloc(use_sg, sizeof(struct page *), GFP_KERNEL);
-               if (!pages)
-                       goto free_req;
-
-               for_each_sg(sgl, sg, use_sg, i)
-                       pages[i] = sg_page(sg);
-
-               mdata->null_mapped = 1;
-
-               mdata->page_order = get_order(sgl[0].length);
-               mdata->nr_entries =
-                       DIV_ROUND_UP(bufflen, PAGE_SIZE << mdata->page_order);
-               mdata->offset = 0;
-
-               err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen, GFP_KERNEL);
-               if (err) {
-                       kfree(pages);
-                       goto free_req;
-               }
-               SRpnt->bio = req->bio;
-               mdata->pages = pages;
-
-       } else if (bufflen) {
-               err = blk_rq_map_kern(req->q, req, buffer, bufflen, GFP_KERNEL);
-               if (err)
-                       goto free_req;
-       }
-
-       rq->cmd_len = cmd_len;
-       memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
-       memcpy(rq->cmd, cmd, rq->cmd_len);
-       req->timeout = timeout;
-       rq->retries = retries;
-       req->end_io_data = SRpnt;
-
-       blk_execute_rq_nowait(req->q, NULL, req, 1, osst_end_async);
-       return 0;
-free_req:
-       blk_put_request(req);
-       return DRIVER_ERROR << 24;
-}
-
-/* Do the scsi command. Waits until command performed if do_wait is true.
-   Otherwise osst_write_behind_check() is used to check that the command
-   has finished. */
-static struct osst_request * osst_do_scsi(struct osst_request *SRpnt, struct osst_tape *STp, 
-       unsigned char *cmd, int bytes, int direction, int timeout, int retries, int do_wait)
-{
-       unsigned char *bp;
-       unsigned short use_sg;
-#ifdef OSST_INJECT_ERRORS
-       static   int   inject = 0;
-       static   int   repeat = 0;
-#endif
-       struct completion *waiting;
-
-       /* if async, make sure there's no command outstanding */
-       if (!do_wait && ((STp->buffer)->last_SRpnt)) {
-               printk(KERN_ERR "%s: Async command already active.\n",
-                      tape_name(STp));
-               if (signal_pending(current))
-                       (STp->buffer)->syscall_result = (-EINTR);
-               else
-                       (STp->buffer)->syscall_result = (-EBUSY);
-               return NULL;
-       }
-
-       if (SRpnt == NULL) {
-               SRpnt = osst_allocate_request();
-               if (SRpnt == NULL) {
-                       printk(KERN_ERR "%s: Can't allocate SCSI request.\n",
-                                    tape_name(STp));
-                       if (signal_pending(current))
-                               (STp->buffer)->syscall_result = (-EINTR);
-                       else
-                               (STp->buffer)->syscall_result = (-EBUSY);
-                       return NULL;
-               }
-               SRpnt->stp = STp;
-       }
-
-       /* If async IO, set last_SRpnt. This ptr tells write_behind_check
-          which IO is outstanding. It's nulled out when the IO completes. */
-       if (!do_wait)
-               (STp->buffer)->last_SRpnt = SRpnt;
-
-       waiting = &STp->wait;
-       init_completion(waiting);
-       SRpnt->waiting = waiting;
-
-       use_sg = (bytes > STp->buffer->sg[0].length) ? STp->buffer->use_sg : 0;
-       if (use_sg) {
-               bp = (char *)&(STp->buffer->sg[0]);
-               if (STp->buffer->sg_segs < use_sg)
-                       use_sg = STp->buffer->sg_segs;
-       }
-       else
-               bp = (STp->buffer)->b_data;
-
-       memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd));
-       STp->buffer->cmdstat.have_sense = 0;
-       STp->buffer->syscall_result = 0;
-
-       if (osst_execute(SRpnt, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes,
-                        use_sg, timeout, retries))
-               /* could not allocate the buffer or request was too large */
-               (STp->buffer)->syscall_result = (-EBUSY);
-       else if (do_wait) {
-               wait_for_completion(waiting);
-               SRpnt->waiting = NULL;
-               STp->buffer->syscall_result = osst_chk_result(STp, SRpnt);
-#ifdef OSST_INJECT_ERRORS
-               if (STp->buffer->syscall_result == 0 &&
-                   cmd[0] == READ_6 &&
-                   cmd[4] && 
-                   ( (++ inject % 83) == 29  ||
-                     (STp->first_frame_position == 240 
-                                /* or STp->read_error_frame to fail again on the block calculated above */ &&
-                                ++repeat < 3))) {
-                       printk(OSST_DEB_MSG "%s:D: Injecting read error\n", tape_name(STp));
-                       STp->buffer->last_result_fatal = 1;
-               }
-#endif
-       }
-       return SRpnt;
-}
-
-
-/* Handle the write-behind checking (downs the semaphore) */
-static void osst_write_behind_check(struct osst_tape *STp)
-{
-       struct osst_buffer * STbuffer;
-
-       STbuffer = STp->buffer;
-
-#if DEBUG
-       if (STp->write_pending)
-               STp->nbr_waits++;
-       else
-               STp->nbr_finished++;
-#endif
-       wait_for_completion(&(STp->wait));
-       STp->buffer->last_SRpnt->waiting = NULL;
-
-       STp->buffer->syscall_result = osst_chk_result(STp, STp->buffer->last_SRpnt);
-
-       if (STp->buffer->syscall_result)
-               STp->buffer->syscall_result =
-                       osst_write_error_recovery(STp, &(STp->buffer->last_SRpnt), 1);
-       else
-               STp->first_frame_position++;
-
-       osst_release_request(STp->buffer->last_SRpnt);
-
-       if (STbuffer->writing < STbuffer->buffer_bytes)
-               printk(KERN_WARNING "osst :A: write_behind_check: something left in buffer!\n");
-
-       STbuffer->last_SRpnt = NULL;
-       STbuffer->buffer_bytes -= STbuffer->writing;
-       STbuffer->writing = 0;
-
-       return;
-}
-
-
-\f
-/* Onstream specific Routines */
-/*
- * Initialize the OnStream AUX
- */
-static void osst_init_aux(struct osst_tape * STp, int frame_type, int frame_seq_number,
-                                        int logical_blk_num, int blk_sz, int blk_cnt)
-{
-       os_aux_t       *aux = STp->buffer->aux;
-       os_partition_t *par = &aux->partition;
-       os_dat_t       *dat = &aux->dat;
-
-       if (STp->raw) return;
-
-       memset(aux, 0, sizeof(*aux));
-       aux->format_id = htonl(0);
-       memcpy(aux->application_sig, "LIN4", 4);
-       aux->hdwr = htonl(0);
-       aux->frame_type = frame_type;
-
-       switch (frame_type) {
-         case  OS_FRAME_TYPE_HEADER:
-               aux->update_frame_cntr    = htonl(STp->update_frame_cntr);
-               par->partition_num        = OS_CONFIG_PARTITION;
-               par->par_desc_ver         = OS_PARTITION_VERSION;
-               par->wrt_pass_cntr        = htons(0xffff);
-               /* 0-4 = reserved, 5-9 = header, 2990-2994 = header, 2995-2999 = reserved */
-               par->first_frame_ppos     = htonl(0);
-               par->last_frame_ppos      = htonl(0xbb7);
-               aux->frame_seq_num        = htonl(0);
-               aux->logical_blk_num_high = htonl(0);
-               aux->logical_blk_num      = htonl(0);
-               aux->next_mark_ppos       = htonl(STp->first_mark_ppos);
-               break;
-         case  OS_FRAME_TYPE_DATA:
-         case  OS_FRAME_TYPE_MARKER:
-               dat->dat_sz = 8;
-               dat->reserved1 = 0;
-               dat->entry_cnt = 1;
-               dat->reserved3 = 0;
-               dat->dat_list[0].blk_sz   = htonl(blk_sz);
-               dat->dat_list[0].blk_cnt  = htons(blk_cnt);
-               dat->dat_list[0].flags    = frame_type==OS_FRAME_TYPE_MARKER?
-                                                       OS_DAT_FLAGS_MARK:OS_DAT_FLAGS_DATA;
-               dat->dat_list[0].reserved = 0;
-               /* fall through */
-         case  OS_FRAME_TYPE_EOD:
-               aux->update_frame_cntr    = htonl(0);
-               par->partition_num        = OS_DATA_PARTITION;
-               par->par_desc_ver         = OS_PARTITION_VERSION;
-               par->wrt_pass_cntr        = htons(STp->wrt_pass_cntr);
-               par->first_frame_ppos     = htonl(STp->first_data_ppos);
-               par->last_frame_ppos      = htonl(STp->capacity);
-               aux->frame_seq_num        = htonl(frame_seq_number);
-               aux->logical_blk_num_high = htonl(0);
-               aux->logical_blk_num      = htonl(logical_blk_num);
-               break;
-         default: ; /* probably FILL */
-       }
-       aux->filemark_cnt = htonl(STp->filemark_cnt);
-       aux->phys_fm = htonl(0xffffffff);
-       aux->last_mark_ppos = htonl(STp->last_mark_ppos);
-       aux->last_mark_lbn  = htonl(STp->last_mark_lbn);
-}
-
-/*
- * Verify that we have the correct tape frame
- */
-static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int quiet)
-{
-       char               * name = tape_name(STp);
-       os_aux_t           * aux  = STp->buffer->aux;
-       os_partition_t     * par  = &(aux->partition);
-       struct st_partstat * STps = &(STp->ps[STp->partition]);
-       unsigned int         blk_cnt, blk_sz, i;
-
-       if (STp->raw) {
-               if (STp->buffer->syscall_result) {
-                       for (i=0; i < STp->buffer->sg_segs; i++)
-                               memset(page_address(sg_page(&STp->buffer->sg[i])),
-                                      0, STp->buffer->sg[i].length);
-                       strcpy(STp->buffer->b_data, "READ ERROR ON FRAME");
-                } else
-                       STp->buffer->buffer_bytes = OS_FRAME_SIZE;
-               return 1;
-       }
-       if (STp->buffer->syscall_result) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Skipping frame, read error\n", name);
-#endif
-               return 0;
-       }
-       if (ntohl(aux->format_id) != 0) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Skipping frame, format_id %u\n", name, ntohl(aux->format_id));
-#endif
-               goto err_out;
-       }
-       if (memcmp(aux->application_sig, STp->application_sig, 4) != 0 &&
-           (memcmp(aux->application_sig, "LIN3", 4) != 0 || STp->linux_media_version != 4)) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Skipping frame, incorrect application signature\n", name);
-#endif
-               goto err_out;
-       }
-       if (par->partition_num != OS_DATA_PARTITION) {
-               if (!STp->linux_media || STp->linux_media_version != 2) {
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: Skipping frame, partition num %d\n",
-                                           name, par->partition_num);
-#endif
-                       goto err_out;
-               }
-       }
-       if (par->par_desc_ver != OS_PARTITION_VERSION) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Skipping frame, partition version %d\n", name, par->par_desc_ver);
-#endif
-               goto err_out;
-       }
-       if (ntohs(par->wrt_pass_cntr) != STp->wrt_pass_cntr) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Skipping frame, wrt_pass_cntr %d (expected %d)\n", 
-                                   name, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr);
-#endif
-               goto err_out;
-       }
-       if (aux->frame_type != OS_FRAME_TYPE_DATA &&
-           aux->frame_type != OS_FRAME_TYPE_EOD &&
-           aux->frame_type != OS_FRAME_TYPE_MARKER) {
-               if (!quiet) {
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: Skipping frame, frame type %x\n", name, aux->frame_type);
-#endif
-               }
-               goto err_out;
-       }
-       if (aux->frame_type == OS_FRAME_TYPE_EOD &&
-           STp->first_frame_position < STp->eod_frame_ppos) {
-               printk(KERN_INFO "%s:I: Skipping premature EOD frame %d\n", name,
-                                STp->first_frame_position);
-               goto err_out;
-       }
-        if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) {
-               if (!quiet) {
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: Skipping frame, sequence number %u (expected %d)\n", 
-                                           name, ntohl(aux->frame_seq_num), frame_seq_number);
-#endif
-               }
-               goto err_out;
-       }
-       if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
-               STps->eof = ST_FM_HIT;
-
-               i = ntohl(aux->filemark_cnt);
-               if (STp->header_cache != NULL && i < OS_FM_TAB_MAX && (i > STp->filemark_cnt ||
-                   STp->first_frame_position - 1 != ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i]))) {
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: %s filemark %d at frame pos %d\n", name,
-                                 STp->header_cache->dat_fm_tab.fm_tab_ent[i] == 0?"Learned":"Corrected",
-                                 i, STp->first_frame_position - 1);
-#endif
-                       STp->header_cache->dat_fm_tab.fm_tab_ent[i] = htonl(STp->first_frame_position - 1);
-                       if (i >= STp->filemark_cnt)
-                                STp->filemark_cnt = i+1;
-               }
-       }
-       if (aux->frame_type == OS_FRAME_TYPE_EOD) {
-               STps->eof = ST_EOD_1;
-               STp->frame_in_buffer = 1;
-       }
-       if (aux->frame_type == OS_FRAME_TYPE_DATA) {
-                blk_cnt = ntohs(aux->dat.dat_list[0].blk_cnt);
-               blk_sz  = ntohl(aux->dat.dat_list[0].blk_sz);
-               STp->buffer->buffer_bytes = blk_cnt * blk_sz;
-               STp->buffer->read_pointer = 0;
-               STp->frame_in_buffer = 1;
-
-               /* See what block size was used to write file */
-               if (STp->block_size != blk_sz && blk_sz > 0) {
-                       printk(KERN_INFO
-               "%s:I: File was written with block size %d%c, currently %d%c, adjusted to match.\n",
-                                       name, blk_sz<1024?blk_sz:blk_sz/1024,blk_sz<1024?'b':'k',
-                               STp->block_size<1024?STp->block_size:STp->block_size/1024,
-                               STp->block_size<1024?'b':'k');
-                       STp->block_size            = blk_sz;
-                       STp->buffer->buffer_blocks = OS_DATA_SIZE / blk_sz;
-               }
-               STps->eof = ST_NOEOF;
-       }
-        STp->frame_seq_number = ntohl(aux->frame_seq_num);
-       STp->logical_blk_num  = ntohl(aux->logical_blk_num);
-       return 1;
-
-err_out:
-       if (STp->read_error_frame == 0)
-               STp->read_error_frame = STp->first_frame_position - 1;
-       return 0;
-}
-
-/*
- * Wait for the unit to become Ready
- */
-static int osst_wait_ready(struct osst_tape * STp, struct osst_request ** aSRpnt,
-                                unsigned timeout, int initial_delay)
-{
-       unsigned char           cmd[MAX_COMMAND_SIZE];
-       struct osst_request   * SRpnt;
-       unsigned long           startwait = jiffies;
-#if DEBUG
-       int                     dbg  = debugging;
-       char                  * name = tape_name(STp);
-
-       printk(OSST_DEB_MSG "%s:D: Reached onstream wait ready\n", name);
-#endif
-
-       if (initial_delay > 0)
-               msleep(jiffies_to_msecs(initial_delay));
-
-       memset(cmd, 0, MAX_COMMAND_SIZE);
-       cmd[0] = TEST_UNIT_READY;
-
-       SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
-       *aSRpnt = SRpnt;
-       if (!SRpnt) return (-EBUSY);
-
-       while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
-              (( SRpnt->sense[2]  == 2 && SRpnt->sense[12] == 4    &&
-                (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8)    ) ||
-               ( SRpnt->sense[2]  == 6 && SRpnt->sense[12] == 0x28 &&
-                 SRpnt->sense[13] == 0                                        )  )) {
-#if DEBUG
-           if (debugging) {
-               printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait ready\n", name);
-               printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
-               debugging = 0;
-           }
-#endif
-           msleep(100);
-
-           memset(cmd, 0, MAX_COMMAND_SIZE);
-           cmd[0] = TEST_UNIT_READY;
-
-           SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
-       }
-       *aSRpnt = SRpnt;
-#if DEBUG
-       debugging = dbg;
-#endif
-       if ( STp->buffer->syscall_result &&
-            osst_write_error_recovery(STp, aSRpnt, 0) ) {
-#if DEBUG
-           printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait ready\n", name);
-           printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name,
-                       STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2],
-                       SRpnt->sense[12], SRpnt->sense[13]);
-#endif
-           return (-EIO);
-       }
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait ready\n", name);
-#endif
-       return 0;
-}
-
-/*
- * Wait for a tape to be inserted in the unit
- */
-static int osst_wait_for_medium(struct osst_tape * STp, struct osst_request ** aSRpnt, unsigned timeout)
-{
-       unsigned char           cmd[MAX_COMMAND_SIZE];
-       struct osst_request   * SRpnt;
-       unsigned long           startwait = jiffies;
-#if DEBUG
-       int                     dbg = debugging;
-       char                  * name = tape_name(STp);
-
-       printk(OSST_DEB_MSG "%s:D: Reached onstream wait for medium\n", name);
-#endif
-
-       memset(cmd, 0, MAX_COMMAND_SIZE);
-       cmd[0] = TEST_UNIT_READY;
-
-       SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
-       *aSRpnt = SRpnt;
-       if (!SRpnt) return (-EBUSY);
-
-       while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
-               SRpnt->sense[2] == 2 && SRpnt->sense[12] == 0x3a && SRpnt->sense[13] == 0  ) {
-#if DEBUG
-           if (debugging) {
-               printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait medium\n", name);
-               printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
-               debugging = 0;
-           }
-#endif
-           msleep(100);
-
-           memset(cmd, 0, MAX_COMMAND_SIZE);
-           cmd[0] = TEST_UNIT_READY;
-
-           SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
-       }
-       *aSRpnt = SRpnt;
-#if DEBUG
-       debugging = dbg;
-#endif
-       if ( STp->buffer->syscall_result     && SRpnt->sense[2]  != 2 &&
-            SRpnt->sense[12] != 4 && SRpnt->sense[13] == 1) {
-#if DEBUG
-           printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait medium\n", name);
-           printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name,
-                       STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2],
-                       SRpnt->sense[12], SRpnt->sense[13]);
-#endif
-           return 0;
-       }
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait medium\n", name);
-#endif
-       return 1;
-}
-
-static int osst_position_tape_and_confirm(struct osst_tape * STp, struct osst_request ** aSRpnt, int frame)
-{
-       int     retval;
-
-       osst_wait_ready(STp, aSRpnt, 15 * 60, 0);                       /* TODO - can this catch a write error? */
-       retval = osst_set_frame_position(STp, aSRpnt, frame, 0);
-       if (retval) return (retval);
-       osst_wait_ready(STp, aSRpnt, 15 * 60, OSST_WAIT_POSITION_COMPLETE);
-       return (osst_get_frame_position(STp, aSRpnt));
-}
-
-/*
- * Wait for write(s) to complete
- */
-static int osst_flush_drive_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
-       unsigned char           cmd[MAX_COMMAND_SIZE];
-       struct osst_request   * SRpnt;
-       int                     result = 0;
-       int                     delay  = OSST_WAIT_WRITE_COMPLETE;
-#if DEBUG
-       char                  * name = tape_name(STp);
-
-       printk(OSST_DEB_MSG "%s:D: Reached onstream flush drive buffer (write filemark)\n", name);
-#endif
-
-       memset(cmd, 0, MAX_COMMAND_SIZE);
-       cmd[0] = WRITE_FILEMARKS;
-       cmd[1] = 1;
-
-       SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
-       *aSRpnt = SRpnt;
-       if (!SRpnt) return (-EBUSY);
-       if (STp->buffer->syscall_result) {
-               if ((SRpnt->sense[2] & 0x0f) == 2 && SRpnt->sense[12] == 4) {
-                       if (SRpnt->sense[13] == 8) {
-                               delay = OSST_WAIT_LONG_WRITE_COMPLETE;
-                       }
-               } else
-                       result = osst_write_error_recovery(STp, aSRpnt, 0);
-       }
-       result |= osst_wait_ready(STp, aSRpnt, 5 * 60, delay);
-       STp->ps[STp->partition].rw = OS_WRITING_COMPLETE;
-
-       return (result);
-}
-
-#define OSST_POLL_PER_SEC 10
-static int osst_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int curr, int minlast, int to)
-{
-       unsigned long   startwait = jiffies;
-       char          * name      = tape_name(STp);
-#if DEBUG
-       char       notyetprinted  = 1;
-#endif
-       if (minlast >= 0 && STp->ps[STp->partition].rw != ST_READING)
-               printk(KERN_ERR "%s:A: Waiting for frame without having initialized read!\n", name);
-
-       while (time_before (jiffies, startwait + to*HZ))
-       { 
-               int result;
-               result = osst_get_frame_position(STp, aSRpnt);
-               if (result == -EIO)
-                       if ((result = osst_write_error_recovery(STp, aSRpnt, 0)) == 0)
-                               return 0;       /* successful recovery leaves drive ready for frame */
-               if (result < 0) break;
-               if (STp->first_frame_position == curr &&
-                   ((minlast < 0 &&
-                     (signed)STp->last_frame_position > (signed)curr + minlast) ||
-                    (minlast >= 0 && STp->cur_frames > minlast)
-                   ) && result >= 0)
-               {
-#if DEBUG                      
-                       if (debugging || time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC))
-                               printk (OSST_DEB_MSG
-                                       "%s:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n",
-                                       name, curr, curr+minlast, STp->first_frame_position,
-                                       STp->last_frame_position, STp->cur_frames,
-                                       result, (jiffies-startwait)/HZ, 
-                                       (((jiffies-startwait)%HZ)*10)/HZ);
-#endif
-                       return 0;
-               }
-#if DEBUG
-               if (time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC) && notyetprinted)
-               {
-                       printk (OSST_DEB_MSG "%s:D: Wait for frame %i (>%i): %i-%i %i (%i)\n",
-                               name, curr, curr+minlast, STp->first_frame_position,
-                               STp->last_frame_position, STp->cur_frames, result);
-                       notyetprinted--;
-               }
-#endif
-               msleep(1000 / OSST_POLL_PER_SEC);
-       }
-#if DEBUG
-       printk (OSST_DEB_MSG "%s:D: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n",
-               name, curr, curr+minlast, STp->first_frame_position,
-               STp->last_frame_position, STp->cur_frames,
-               (jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ);
-#endif 
-       return -EBUSY;
-}
-
-static int osst_recover_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int writing)
-{
-       struct osst_request   * SRpnt;
-       unsigned char           cmd[MAX_COMMAND_SIZE];
-       unsigned long           startwait = jiffies;
-       int                     retval    = 1;
-        char                 * name      = tape_name(STp);
-                                                                                                                                
-       if (writing) {
-               char    mybuf[24];
-               char  * olddata = STp->buffer->b_data;
-               int     oldsize = STp->buffer->buffer_size;
-
-               /* write zero fm then read pos - if shows write error, try to recover - if no progress, wait */
-
-               memset(cmd, 0, MAX_COMMAND_SIZE);
-               cmd[0] = WRITE_FILEMARKS;
-               cmd[1] = 1;
-               SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout,
-                                                               MAX_RETRIES, 1);
-
-               while (retval && time_before (jiffies, startwait + 5*60*HZ)) {
-
-                       if (STp->buffer->syscall_result && (SRpnt->sense[2] & 0x0f) != 2) {
-
-                               /* some failure - not just not-ready */
-                               retval = osst_write_error_recovery(STp, aSRpnt, 0);
-                               break;
-                       }
-                       schedule_timeout_interruptible(HZ / OSST_POLL_PER_SEC);
-
-                       STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
-                       memset(cmd, 0, MAX_COMMAND_SIZE);
-                       cmd[0] = READ_POSITION;
-
-                       SRpnt = osst_do_scsi(SRpnt, STp, cmd, 20, DMA_FROM_DEVICE, STp->timeout,
-                                                                               MAX_RETRIES, 1);
-
-                       retval = ( STp->buffer->syscall_result || (STp->buffer)->b_data[15] > 25 );
-                       STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
-               }
-               if (retval)
-                       printk(KERN_ERR "%s:E: Device did not succeed to write buffered data\n", name);
-       } else
-               /* TODO - figure out which error conditions can be handled */
-               if (STp->buffer->syscall_result)
-                       printk(KERN_WARNING
-                               "%s:W: Recover_wait_frame(read) cannot handle %02x:%02x:%02x\n", name,
-                                       (*aSRpnt)->sense[ 2] & 0x0f,
-                                       (*aSRpnt)->sense[12],
-                                       (*aSRpnt)->sense[13]);
-
-       return retval;
-}
-
-/*
- * Read the next OnStream tape frame at the current location
- */
-static int osst_read_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int timeout)
-{
-       unsigned char           cmd[MAX_COMMAND_SIZE];
-       struct osst_request   * SRpnt;
-       int                     retval = 0;
-#if DEBUG
-       os_aux_t              * aux    = STp->buffer->aux;
-       char                  * name   = tape_name(STp);
-#endif
-
-       if (STp->poll)
-               if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, 0, timeout))
-                       retval = osst_recover_wait_frame(STp, aSRpnt, 0);
-
-       memset(cmd, 0, MAX_COMMAND_SIZE);
-       cmd[0] = READ_6;
-       cmd[1] = 1;
-       cmd[4] = 1;
-
-#if DEBUG
-       if (debugging)
-               printk(OSST_DEB_MSG "%s:D: Reading frame from OnStream tape\n", name);
-#endif
-       SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE,
-                                     STp->timeout, MAX_RETRIES, 1);
-       *aSRpnt = SRpnt;
-       if (!SRpnt)
-               return (-EBUSY);
-
-       if ((STp->buffer)->syscall_result) {
-           retval = 1;
-           if (STp->read_error_frame == 0) {
-               STp->read_error_frame = STp->first_frame_position;
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Recording read error at %d\n", name, STp->read_error_frame);
-#endif
-           }
-#if DEBUG
-           if (debugging)
-               printk(OSST_DEB_MSG "%s:D: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
-                  name,
-                  SRpnt->sense[0], SRpnt->sense[1],
-                  SRpnt->sense[2], SRpnt->sense[3],
-                  SRpnt->sense[4], SRpnt->sense[5],
-                  SRpnt->sense[6], SRpnt->sense[7]);
-#endif
-       }
-       else
-           STp->first_frame_position++;
-#if DEBUG
-       if (debugging) {
-          char sig[8]; int i;
-          for (i=0;i<4;i++)
-                  sig[i] = aux->application_sig[i]<32?'^':aux->application_sig[i];
-          sig[4] = '\0';
-          printk(OSST_DEB_MSG 
-               "%s:D: AUX: %s UpdFrCt#%d Wpass#%d %s FrSeq#%d LogBlk#%d Qty=%d Sz=%d\n", name, sig,
-                       ntohl(aux->update_frame_cntr), ntohs(aux->partition.wrt_pass_cntr),
-                       aux->frame_type==1?"EOD":aux->frame_type==2?"MARK":
-                       aux->frame_type==8?"HEADR":aux->frame_type==0x80?"DATA":"FILL", 
-                       ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
-                       ntohs(aux->dat.dat_list[0].blk_cnt), ntohl(aux->dat.dat_list[0].blk_sz) );
-          if (aux->frame_type==2)
-               printk(OSST_DEB_MSG "%s:D: mark_cnt=%d, last_mark_ppos=%d, last_mark_lbn=%d\n", name,
-                       ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->last_mark_lbn));
-          printk(OSST_DEB_MSG "%s:D: Exit read frame from OnStream tape with code %d\n", name, retval);
-       }
-#endif
-       return (retval);
-}
-
-static int osst_initiate_read(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
-       struct st_partstat    * STps   = &(STp->ps[STp->partition]);
-       struct osst_request   * SRpnt  ;
-       unsigned char           cmd[MAX_COMMAND_SIZE];
-       int                     retval = 0;
-       char                  * name   = tape_name(STp);
-
-       if (STps->rw != ST_READING) {         /* Initialize read operation */
-               if (STps->rw == ST_WRITING || STp->dirty) {
-                       STp->write_type = OS_WRITE_DATA;
-                        osst_flush_write_buffer(STp, aSRpnt);
-                       osst_flush_drive_buffer(STp, aSRpnt);
-               }
-               STps->rw = ST_READING;
-               STp->frame_in_buffer = 0;
-
-               /*
-                *      Issue a read 0 command to get the OnStream drive
-                 *      read frames into its buffer.
-                */
-               memset(cmd, 0, MAX_COMMAND_SIZE);
-               cmd[0] = READ_6;
-               cmd[1] = 1;
-
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Start Read Ahead on OnStream tape\n", name);
-#endif
-               SRpnt   = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
-               *aSRpnt = SRpnt;
-               if ((retval = STp->buffer->syscall_result))
-                       printk(KERN_WARNING "%s:W: Error starting read ahead\n", name);
-       }
-
-       return retval;
-}
-
-static int osst_get_logical_frame(struct osst_tape * STp, struct osst_request ** aSRpnt,
-                                               int frame_seq_number, int quiet)
-{
-       struct st_partstat * STps  = &(STp->ps[STp->partition]);
-       char               * name  = tape_name(STp);
-       int                  cnt   = 0,
-                            bad   = 0,
-                            past  = 0,
-                            x,
-                            position;
-
-       /*
-        * If we want just any frame (-1) and there is a frame in the buffer, return it
-        */
-       if (frame_seq_number == -1 && STp->frame_in_buffer) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Frame %d still in buffer\n", name, STp->frame_seq_number);
-#endif
-               return (STps->eof);
-       }
-       /*
-         * Search and wait for the next logical tape frame
-        */
-       while (1) {
-               if (cnt++ > 400) {
-                        printk(KERN_ERR "%s:E: Couldn't find logical frame %d, aborting\n",
-                                           name, frame_seq_number);
-                       if (STp->read_error_frame) {
-                               osst_set_frame_position(STp, aSRpnt, STp->read_error_frame, 0);
-#if DEBUG
-                               printk(OSST_DEB_MSG "%s:D: Repositioning tape to bad frame %d\n",
-                                                   name, STp->read_error_frame);
-#endif
-                               STp->read_error_frame = 0;
-                               STp->abort_count++;
-                       }
-                       return (-EIO);
-               }
-#if DEBUG
-               if (debugging)
-                       printk(OSST_DEB_MSG "%s:D: Looking for frame %d, attempt %d\n",
-                                         name, frame_seq_number, cnt);
-#endif
-               if ( osst_initiate_read(STp, aSRpnt)
-                || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) {
-                       if (STp->raw)
-                               return (-EIO);
-                       position = osst_get_frame_position(STp, aSRpnt);
-                       if (position >= 0xbae && position < 0xbb8)
-                               position = 0xbb8;
-                       else if (position > STp->eod_frame_ppos || ++bad == 10) {
-                               position = STp->read_error_frame - 1;
-                               bad = 0;
-                       }
-                       else {
-                               position += 29;
-                               cnt      += 19;
-                       }
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: Bad frame detected, positioning tape to block %d\n",
-                                        name, position);
-#endif
-                       osst_set_frame_position(STp, aSRpnt, position, 0);
-                       continue;
-               }
-               if (osst_verify_frame(STp, frame_seq_number, quiet))
-                       break;
-               if (osst_verify_frame(STp, -1, quiet)) {
-                       x = ntohl(STp->buffer->aux->frame_seq_num);
-                       if (STp->fast_open) {
-                               printk(KERN_WARNING
-                                      "%s:W: Found logical frame %d instead of %d after fast open\n",
-                                      name, x, frame_seq_number);
-                               STp->header_ok = 0;
-                               STp->read_error_frame = 0;
-                               return (-EIO);
-                       }
-                       if (x > frame_seq_number) {
-                               if (++past > 3) {
-                                       /* positioning backwards did not bring us to the desired frame */
-                                       position = STp->read_error_frame - 1;
-                               }
-                               else {
-                                       position = osst_get_frame_position(STp, aSRpnt)
-                                                + frame_seq_number - x - 1;
-
-                                       if (STp->first_frame_position >= 3000 && position < 3000)
-                                               position -= 10;
-                               }
-#if DEBUG
-                                printk(OSST_DEB_MSG
-                                      "%s:D: Found logical frame %d while looking for %d: back up %d\n",
-                                               name, x, frame_seq_number,
-                                               STp->first_frame_position - position);
-#endif
-                               osst_set_frame_position(STp, aSRpnt, position, 0);
-                               cnt += 10;
-                       }
-                       else
-                               past = 0;
-               }
-               if (osst_get_frame_position(STp, aSRpnt) == 0xbaf) {
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: Skipping config partition\n", name);
-#endif
-                       osst_set_frame_position(STp, aSRpnt, 0xbb8, 0);
-                       cnt--;
-               }
-               STp->frame_in_buffer = 0;
-       }
-       if (cnt > 1) {
-               STp->recover_count++;
-               STp->recover_erreg++;
-               printk(KERN_WARNING "%s:I: Don't worry, Read error at position %d recovered\n", 
-                                       name, STp->read_error_frame);
-       }
-       STp->read_count++;
-
-#if DEBUG
-       if (debugging || STps->eof)
-               printk(OSST_DEB_MSG
-                       "%s:D: Exit get logical frame (%d=>%d) from OnStream tape with code %d\n",
-                       name, frame_seq_number, STp->frame_seq_number, STps->eof);
-#endif
-       STp->fast_open = 0;
-       STp->read_error_frame = 0;
-       return (STps->eof);
-}
-
-static int osst_seek_logical_blk(struct osst_tape * STp, struct osst_request ** aSRpnt, int logical_blk_num)
-{
-        struct st_partstat * STps = &(STp->ps[STp->partition]);
-       char               * name = tape_name(STp);
-       int     retries    = 0;
-       int     frame_seq_estimate, ppos_estimate, move;
-       
-       if (logical_blk_num < 0) logical_blk_num = 0;
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Seeking logical block %d (now at %d, size %d%c)\n",
-                               name, logical_blk_num, STp->logical_blk_num, 
-                               STp->block_size<1024?STp->block_size:STp->block_size/1024,
-                               STp->block_size<1024?'b':'k');
-#endif
-       /* Do we know where we are? */
-       if (STps->drv_block >= 0) {
-               move                = logical_blk_num - STp->logical_blk_num;
-               if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
-               move               /= (OS_DATA_SIZE / STp->block_size);
-               frame_seq_estimate  = STp->frame_seq_number + move;
-       } else
-               frame_seq_estimate  = logical_blk_num * STp->block_size / OS_DATA_SIZE;
-
-       if (frame_seq_estimate < 2980) ppos_estimate = frame_seq_estimate + 10;
-       else                           ppos_estimate = frame_seq_estimate + 20;
-       while (++retries < 10) {
-          if (ppos_estimate > STp->eod_frame_ppos-2) {
-              frame_seq_estimate += STp->eod_frame_ppos - 2 - ppos_estimate;
-              ppos_estimate       = STp->eod_frame_ppos - 2;
-          }
-          if (frame_seq_estimate < 0) {
-              frame_seq_estimate = 0;
-              ppos_estimate      = 10;
-          }
-          osst_set_frame_position(STp, aSRpnt, ppos_estimate, 0);
-          if (osst_get_logical_frame(STp, aSRpnt, frame_seq_estimate, 1) >= 0) {
-             /* we've located the estimated frame, now does it have our block? */
-             if (logical_blk_num <  STp->logical_blk_num ||
-                 logical_blk_num >= STp->logical_blk_num + ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt)) {
-                if (STps->eof == ST_FM_HIT)
-                   move = logical_blk_num < STp->logical_blk_num? -2 : 1;
-                else {
-                   move                = logical_blk_num - STp->logical_blk_num;
-                   if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
-                   move               /= (OS_DATA_SIZE / STp->block_size);
-                }
-                if (!move) move = logical_blk_num > STp->logical_blk_num ? 1 : -1;
-#if DEBUG
-                printk(OSST_DEB_MSG
-                       "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n",
-                               name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate, 
-                               STp->logical_blk_num, logical_blk_num, move);
-#endif
-                frame_seq_estimate += move;
-                ppos_estimate      += move;
-                continue;
-             } else {
-                STp->buffer->read_pointer  = (logical_blk_num - STp->logical_blk_num) * STp->block_size;
-                STp->buffer->buffer_bytes -= STp->buffer->read_pointer;
-                STp->logical_blk_num       =  logical_blk_num;
-#if DEBUG
-                printk(OSST_DEB_MSG 
-                       "%s:D: Seek success at ppos %d fsq %d in_buf %d, bytes %d, ptr %d*%d\n",
-                               name, ppos_estimate, STp->frame_seq_number, STp->frame_in_buffer, 
-                               STp->buffer->buffer_bytes, STp->buffer->read_pointer / STp->block_size, 
-                               STp->block_size);
-#endif
-                STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
-                if (STps->eof == ST_FM_HIT) {
-                    STps->drv_file++;
-                    STps->drv_block = 0;
-                } else {
-                    STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
-                                         STp->logical_blk_num -
-                                            (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
-                                       -1;
-                }
-                STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
-                return 0;
-             }
-          }
-          if (osst_get_logical_frame(STp, aSRpnt, -1, 1) < 0)
-             goto error;
-          /* we are not yet at the estimated frame, adjust our estimate of its physical position */
-#if DEBUG
-          printk(OSST_DEB_MSG "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d)\n", 
-                          name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate, 
-                          STp->logical_blk_num, logical_blk_num);
-#endif
-          if (frame_seq_estimate != STp->frame_seq_number)
-             ppos_estimate += frame_seq_estimate - STp->frame_seq_number;
-          else
-             break;
-       }
-error:
-       printk(KERN_ERR "%s:E: Couldn't seek to logical block %d (at %d), %d retries\n", 
-                           name, logical_blk_num, STp->logical_blk_num, retries);
-       return (-EIO);
-}
-
-/* The values below are based on the OnStream frame payload size of 32K == 2**15,
- * that is, OSST_FRAME_SHIFT + OSST_SECTOR_SHIFT must be 15. With a minimum block
- * size of 512 bytes, we need to be able to resolve 32K/512 == 64 == 2**6 positions
- * inside each frame. Finally, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1.
- */
-#define OSST_FRAME_SHIFT  6
-#define OSST_SECTOR_SHIFT 9
-#define OSST_SECTOR_MASK  0x03F
-
-static int osst_get_sector(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
-       int     sector;
-#if DEBUG
-       char  * name = tape_name(STp);
-       
-       printk(OSST_DEB_MSG 
-               "%s:D: Positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, %cptr %d, eof %d\n",
-               name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
-               STp->ps[STp->partition].drv_file, STp->ps[STp->partition].drv_block, 
-               STp->ps[STp->partition].rw == ST_WRITING?'w':'r',
-               STp->ps[STp->partition].rw == ST_WRITING?STp->buffer->buffer_bytes:
-               STp->buffer->read_pointer, STp->ps[STp->partition].eof);
-#endif
-       /* do we know where we are inside a file? */
-       if (STp->ps[STp->partition].drv_block >= 0) {
-               sector = (STp->frame_in_buffer ? STp->first_frame_position-1 :
-                               STp->first_frame_position) << OSST_FRAME_SHIFT;
-               if (STp->ps[STp->partition].rw == ST_WRITING)
-                       sector |= (STp->buffer->buffer_bytes >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
-               else
-                       sector |= (STp->buffer->read_pointer >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
-       } else {
-               sector = osst_get_frame_position(STp, aSRpnt);
-               if (sector > 0)
-                       sector <<= OSST_FRAME_SHIFT;
-       }
-       return sector;
-}
-
-static int osst_seek_sector(struct osst_tape * STp, struct osst_request ** aSRpnt, int sector)
-{
-        struct st_partstat * STps   = &(STp->ps[STp->partition]);
-       int                  frame  = sector >> OSST_FRAME_SHIFT,
-                            offset = (sector & OSST_SECTOR_MASK) << OSST_SECTOR_SHIFT, 
-                            r;
-#if DEBUG
-       char          * name = tape_name(STp);
-
-       printk(OSST_DEB_MSG "%s:D: Seeking sector %d in frame %d at offset %d\n",
-                               name, sector, frame, offset);
-#endif
-       if (frame < 0 || frame >= STp->capacity) return (-ENXIO);
-
-       if (frame <= STp->first_data_ppos) {
-               STp->frame_seq_number = STp->logical_blk_num = STps->drv_file = STps->drv_block = 0;
-               return (osst_set_frame_position(STp, aSRpnt, frame, 0));
-       }
-       r = osst_set_frame_position(STp, aSRpnt, offset?frame:frame-1, 0);
-       if (r < 0) return r;
-
-       r = osst_get_logical_frame(STp, aSRpnt, -1, 1);
-       if (r < 0) return r;
-
-       if (osst_get_frame_position(STp, aSRpnt) != (offset?frame+1:frame)) return (-EIO);
-
-       if (offset) {
-               STp->logical_blk_num      += offset / STp->block_size;
-               STp->buffer->read_pointer  = offset;
-               STp->buffer->buffer_bytes -= offset;
-       } else {
-               STp->frame_seq_number++;
-               STp->frame_in_buffer       = 0;
-               STp->logical_blk_num      += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
-               STp->buffer->buffer_bytes  = STp->buffer->read_pointer = 0;
-       }
-       STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
-       if (STps->eof == ST_FM_HIT) {
-               STps->drv_file++;
-               STps->drv_block = 0;
-       } else {
-               STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
-                                   STp->logical_blk_num -
-                                       (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
-                                 -1;
-       }
-       STps->eof       = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
-#if DEBUG
-       printk(OSST_DEB_MSG 
-               "%s:D: Now positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, rptr %d, eof %d\n",
-               name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
-               STps->drv_file, STps->drv_block, STp->buffer->read_pointer, STps->eof);
-#endif
-       return 0;
-}
-
-/*
- * Read back the drive's internal buffer contents, as a part
- * of the write error recovery mechanism for old OnStream
- * firmware revisions.
- * Precondition for this function to work: all frames in the
- * drive's buffer must be of one type (DATA, MARK or EOD)!
- */
-static int osst_read_back_buffer_and_rewrite(struct osst_tape * STp, struct osst_request ** aSRpnt,
-                                               unsigned int frame, unsigned int skip, int pending)
-{
-       struct osst_request   * SRpnt = * aSRpnt;
-       unsigned char         * buffer, * p;
-       unsigned char           cmd[MAX_COMMAND_SIZE];
-       int                     flag, new_frame, i;
-       int                     nframes          = STp->cur_frames;
-       int                     blks_per_frame   = ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
-       int                     frame_seq_number = ntohl(STp->buffer->aux->frame_seq_num)
-                                               - (nframes + pending - 1);
-       int                     logical_blk_num  = ntohl(STp->buffer->aux->logical_blk_num) 
-                                               - (nframes + pending - 1) * blks_per_frame;
-       char                  * name             = tape_name(STp);
-       unsigned long           startwait        = jiffies;
-#if DEBUG
-       int                     dbg              = debugging;
-#endif
-
-       if ((buffer = vmalloc(array_size((nframes + 1), OS_DATA_SIZE))) == NULL)
-               return (-EIO);
-
-       printk(KERN_INFO "%s:I: Reading back %d frames from drive buffer%s\n",
-                        name, nframes, pending?" and one that was pending":"");
-
-       osst_copy_from_buffer(STp->buffer, (p = &buffer[nframes * OS_DATA_SIZE]));
-#if DEBUG
-       if (pending && debugging)
-               printk(OSST_DEB_MSG "%s:D: Pending frame %d (lblk %d), data %02x %02x %02x %02x\n",
-                               name, frame_seq_number + nframes,
-                               logical_blk_num + nframes * blks_per_frame,
-                               p[0], p[1], p[2], p[3]);
-#endif
-       for (i = 0, p = buffer; i < nframes; i++, p += OS_DATA_SIZE) {
-
-               memset(cmd, 0, MAX_COMMAND_SIZE);
-               cmd[0] = 0x3C;          /* Buffer Read           */
-               cmd[1] = 6;             /* Retrieve Faulty Block */
-               cmd[7] = 32768 >> 8;
-               cmd[8] = 32768 & 0xff;
-
-               SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE,
-                                           STp->timeout, MAX_RETRIES, 1);
-       
-               if ((STp->buffer)->syscall_result || !SRpnt) {
-                       printk(KERN_ERR "%s:E: Failed to read frame back from OnStream buffer\n", name);
-                       vfree(buffer);
-                       *aSRpnt = SRpnt;
-                       return (-EIO);
-               }
-               osst_copy_from_buffer(STp->buffer, p);
-#if DEBUG
-               if (debugging)
-                       printk(OSST_DEB_MSG "%s:D: Read back logical frame %d, data %02x %02x %02x %02x\n",
-                                         name, frame_seq_number + i, p[0], p[1], p[2], p[3]);
-#endif
-       }
-       *aSRpnt = SRpnt;
-       osst_get_frame_position(STp, aSRpnt);
-
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Frames left in buffer: %d\n", name, STp->cur_frames);
-#endif
-       /* Write synchronously so we can be sure we're OK again and don't have to recover recursively */
-       /* In the header we don't actually re-write the frames that fail, just the ones after them */
-
-       for (flag=1, new_frame=frame, p=buffer, i=0; i < nframes + pending; ) {
-
-               if (flag) {
-                       if (STp->write_type == OS_WRITE_HEADER) {
-                               i += skip;
-                               p += skip * OS_DATA_SIZE;
-                       }
-                       else if (new_frame < 2990 && new_frame+skip+nframes+pending >= 2990)
-                               new_frame = 3000-i;
-                       else
-                               new_frame += skip;
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: Position to frame %d, write fseq %d\n",
-                                               name, new_frame+i, frame_seq_number+i);
-#endif
-                       osst_set_frame_position(STp, aSRpnt, new_frame + i, 0);
-                       osst_wait_ready(STp, aSRpnt, 60, OSST_WAIT_POSITION_COMPLETE);
-                       osst_get_frame_position(STp, aSRpnt);
-                       SRpnt = * aSRpnt;
-
-                       if (new_frame > frame + 1000) {
-                               printk(KERN_ERR "%s:E: Failed to find writable tape media\n", name);
-                               vfree(buffer);
-                               return (-EIO);
-                       }
-                       if ( i >= nframes + pending ) break;
-                       flag = 0;
-               }
-               osst_copy_to_buffer(STp->buffer, p);
-               /*
-                * IMPORTANT: for error recovery to work, _never_ queue frames with mixed frame type!
-                */
-               osst_init_aux(STp, STp->buffer->aux->frame_type, frame_seq_number+i,
-                               logical_blk_num + i*blks_per_frame,
-                               ntohl(STp->buffer->aux->dat.dat_list[0].blk_sz), blks_per_frame);
-               memset(cmd, 0, MAX_COMMAND_SIZE);
-               cmd[0] = WRITE_6;
-               cmd[1] = 1;
-               cmd[4] = 1;
-
-#if DEBUG
-               if (debugging)
-                       printk(OSST_DEB_MSG
-                               "%s:D: About to write frame %d, seq %d, lbn %d, data %02x %02x %02x %02x\n",
-                               name, new_frame+i, frame_seq_number+i, logical_blk_num + i*blks_per_frame,
-                               p[0], p[1], p[2], p[3]);
-#endif
-               SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE,
-                                           STp->timeout, MAX_RETRIES, 1);
-
-               if (STp->buffer->syscall_result)
-                       flag = 1;
-               else {
-                       p += OS_DATA_SIZE; i++;
-
-                       /* if we just sent the last frame, wait till all successfully written */
-                       if ( i == nframes + pending ) {
-#if DEBUG
-                               printk(OSST_DEB_MSG "%s:D: Check re-write successful\n", name);
-#endif
-                               memset(cmd, 0, MAX_COMMAND_SIZE);
-                               cmd[0] = WRITE_FILEMARKS;
-                               cmd[1] = 1;
-                               SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
-                                                           STp->timeout, MAX_RETRIES, 1);
-#if DEBUG
-                               if (debugging) {
-                                       printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
-                                       printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
-                                       debugging = 0;
-                               }
-#endif
-                               flag = STp->buffer->syscall_result;
-                               while ( !flag && time_before(jiffies, startwait + 60*HZ) ) {
-
-                                       memset(cmd, 0, MAX_COMMAND_SIZE);
-                                       cmd[0] = TEST_UNIT_READY;
-
-                                       SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout,
-                                                                                               MAX_RETRIES, 1);
-
-                                       if (SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 &&
-                                           (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8)) {
-                                               /* in the process of becoming ready */
-                                               msleep(100);
-                                               continue;
-                                       }
-                                       if (STp->buffer->syscall_result)
-                                               flag = 1;
-                                       break;
-                               }
-#if DEBUG
-                               debugging = dbg;
-                               printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
-#endif
-                       }
-               }
-               *aSRpnt = SRpnt;
-               if (flag) {
-                       if ((SRpnt->sense[ 2] & 0x0f) == 13 &&
-                            SRpnt->sense[12]         ==  0 &&
-                            SRpnt->sense[13]         ==  2) {
-                               printk(KERN_ERR "%s:E: Volume overflow in write error recovery\n", name);
-                               vfree(buffer);
-                               return (-EIO);                  /* hit end of tape = fail */
-                       }
-                       i = ((SRpnt->sense[3] << 24) |
-                            (SRpnt->sense[4] << 16) |
-                            (SRpnt->sense[5] <<  8) |
-                             SRpnt->sense[6]        ) - new_frame;
-                       p = &buffer[i * OS_DATA_SIZE];
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: Additional write error at %d\n", name, new_frame+i);
-#endif
-                       osst_get_frame_position(STp, aSRpnt);
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d, buffer = %d\n",
-                                         name, STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
-#endif
-               }
-       }
-       if (flag) {
-               /* error recovery did not successfully complete */
-               printk(KERN_ERR "%s:D: Write error recovery failed in %s\n", name,
-                               STp->write_type == OS_WRITE_HEADER?"header":"body");
-       }
-       if (!pending)
-               osst_copy_to_buffer(STp->buffer, p);    /* so buffer content == at entry in all cases */
-       vfree(buffer);
-       return 0;
-}
-
-static int osst_reposition_and_retry(struct osst_tape * STp, struct osst_request ** aSRpnt,
-                                       unsigned int frame, unsigned int skip, int pending)
-{
-       unsigned char           cmd[MAX_COMMAND_SIZE];
-       struct osst_request   * SRpnt;
-       char                  * name      = tape_name(STp);
-       int                     expected  = 0;
-       int                     attempts  = 1000 / skip;
-       int                     flag      = 1;
-       unsigned long           startwait = jiffies;
-#if DEBUG
-       int                     dbg       = debugging;
-#endif
-
-       while (attempts && time_before(jiffies, startwait + 60*HZ)) {
-               if (flag) {
-#if DEBUG
-                       debugging = dbg;
-#endif
-                       if (frame < 2990 && frame+skip+STp->cur_frames+pending >= 2990)
-                               frame = 3000-skip;
-                       expected = frame+skip+STp->cur_frames+pending;
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: Position to fppos %d, re-write from fseq %d\n",
-                                         name, frame+skip, STp->frame_seq_number-STp->cur_frames-pending);
-#endif
-                       osst_set_frame_position(STp, aSRpnt, frame + skip, 1);
-                       flag = 0;
-                       attempts--;
-                       schedule_timeout_interruptible(msecs_to_jiffies(100));
-               }
-               if (osst_get_frame_position(STp, aSRpnt) < 0) {         /* additional write error */
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: Addl error, host %d, tape %d, buffer %d\n",
-                                         name, STp->first_frame_position,
-                                         STp->last_frame_position, STp->cur_frames);
-#endif
-                       frame = STp->last_frame_position;
-                       flag = 1;
-                       continue;
-               }
-               if (pending && STp->cur_frames < 50) {
-
-                       memset(cmd, 0, MAX_COMMAND_SIZE);
-                       cmd[0] = WRITE_6;
-                       cmd[1] = 1;
-                       cmd[4] = 1;
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: About to write pending fseq %d at fppos %d\n",
-                                         name, STp->frame_seq_number-1, STp->first_frame_position);
-#endif
-                       SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE,
-                                                     STp->timeout, MAX_RETRIES, 1);
-                       *aSRpnt = SRpnt;
-
-                       if (STp->buffer->syscall_result) {              /* additional write error */
-                               if ((SRpnt->sense[ 2] & 0x0f) == 13 &&
-                                    SRpnt->sense[12]         ==  0 &&
-                                    SRpnt->sense[13]         ==  2) {
-                                       printk(KERN_ERR
-                                              "%s:E: Volume overflow in write error recovery\n",
-                                              name);
-                                       break;                          /* hit end of tape = fail */
-                               }
-                               flag = 1;
-                       }
-                       else
-                               pending = 0;
-
-                       continue;
-               }
-               if (STp->cur_frames == 0) {
-#if DEBUG
-                       debugging = dbg;
-                       printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
-#endif
-                       if (STp->first_frame_position != expected) {
-                               printk(KERN_ERR "%s:A: Actual position %d - expected %d\n", 
-                                               name, STp->first_frame_position, expected);
-                               return (-EIO);
-                       }
-                       return 0;
-               }
-#if DEBUG
-               if (debugging) {
-                       printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
-                       printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
-                       debugging = 0;
-               }
-#endif
-               schedule_timeout_interruptible(msecs_to_jiffies(100));
-       }
-       printk(KERN_ERR "%s:E: Failed to find valid tape media\n", name);
-#if DEBUG
-       debugging = dbg;
-#endif
-       return (-EIO);
-}
-
-/*
- * Error recovery algorithm for the OnStream tape.
- */
-
-static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending)
-{
-       struct osst_request * SRpnt  = * aSRpnt;
-       struct st_partstat  * STps   = & STp->ps[STp->partition];
-       char                * name   = tape_name(STp);
-       int                   retval = 0;
-       int                   rw_state;
-       unsigned int          frame, skip;
-
-       rw_state = STps->rw;
-
-       if ((SRpnt->sense[ 2] & 0x0f) != 3
-         || SRpnt->sense[12]         != 12
-         || SRpnt->sense[13]         != 0) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Write error recovery cannot handle %02x:%02x:%02x\n", name,
-                       SRpnt->sense[2], SRpnt->sense[12], SRpnt->sense[13]);
-#endif
-               return (-EIO);
-       }
-       frame = (SRpnt->sense[3] << 24) |
-               (SRpnt->sense[4] << 16) |
-               (SRpnt->sense[5] <<  8) |
-                SRpnt->sense[6];
-       skip  =  SRpnt->sense[9];
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Detected physical bad frame at %u, advised to skip %d\n", name, frame, skip);
-#endif
-       osst_get_frame_position(STp, aSRpnt);
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d\n",
-                       name, STp->first_frame_position, STp->last_frame_position);
-#endif
-       switch (STp->write_type) {
-          case OS_WRITE_DATA:
-          case OS_WRITE_EOD:
-          case OS_WRITE_NEW_MARK:
-               printk(KERN_WARNING 
-                       "%s:I: Relocating %d buffered logical frames from position %u to %u\n",
-                       name, STp->cur_frames, frame, (frame + skip > 3000 && frame < 3000)?3000:frame + skip);
-               if (STp->os_fw_rev >= 10600)
-                       retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending);
-               else
-                       retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending);
-               printk(KERN_WARNING "%s:%s: %sWrite error%srecovered\n", name,
-                               retval?"E"    :"I",
-                               retval?""     :"Don't worry, ",
-                               retval?" not ":" ");
-               break;
-          case OS_WRITE_LAST_MARK:
-               printk(KERN_ERR "%s:E: Bad frame in update last marker, fatal\n", name);
-               osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
-               retval = -EIO;
-               break;
-          case OS_WRITE_HEADER:
-               printk(KERN_WARNING "%s:I: Bad frame in header partition, skipped\n", name);
-               retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, 1, pending);
-               break;
-          default:
-               printk(KERN_INFO "%s:I: Bad frame in filler, ignored\n", name);
-               osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
-       }
-       osst_get_frame_position(STp, aSRpnt);
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Positioning complete, cur_frames %d, pos %d, tape pos %d\n", 
-                       name, STp->cur_frames, STp->first_frame_position, STp->last_frame_position);
-       printk(OSST_DEB_MSG "%s:D: next logical frame to write: %d\n", name, STp->logical_blk_num);
-#endif
-       if (retval == 0) {
-               STp->recover_count++;
-               STp->recover_erreg++;
-       } else
-               STp->abort_count++;
-
-       STps->rw = rw_state;
-       return retval;
-}
-
-static int osst_space_over_filemarks_backward(struct osst_tape * STp, struct osst_request ** aSRpnt,
-                                                                int mt_op, int mt_count)
-{
-       char  * name = tape_name(STp);
-       int     cnt;
-       int     last_mark_ppos = -1;
-
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_backwards %d %d\n", name, mt_op, mt_count);
-#endif
-       if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_bwd\n", name);
-#endif
-               return -EIO;
-       }
-       if (STp->linux_media_version >= 4) {
-               /*
-                * direct lookup in header filemark list
-                */
-               cnt = ntohl(STp->buffer->aux->filemark_cnt);
-               if (STp->header_ok                         && 
-                   STp->header_cache != NULL              &&
-                   (cnt - mt_count)  >= 0                 &&
-                   (cnt - mt_count)   < OS_FM_TAB_MAX     &&
-                   (cnt - mt_count)   < STp->filemark_cnt &&
-                   STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == STp->buffer->aux->last_mark_ppos)
-
-                       last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt - mt_count]);
-#if DEBUG
-               if (STp->header_cache == NULL || (cnt - mt_count) < 0 || (cnt - mt_count) >= OS_FM_TAB_MAX)
-                       printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
-                              STp->header_cache == NULL?"lack of header cache":"count out of range");
-               else
-                       printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
-                               name, cnt,
-                               ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
-                                (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] ==
-                                        STp->buffer->aux->last_mark_ppos))?"match":"error",
-                              mt_count, last_mark_ppos);
-#endif
-               if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) {
-                       osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
-                       if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
-                               printk(OSST_DEB_MSG 
-                                       "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
-#endif
-                               return (-EIO);
-                       }
-                       if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-                               printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
-                                                name, last_mark_ppos);
-                               return (-EIO);
-                       }
-                       goto found;
-               }
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Reverting to scan filemark backwards\n", name);
-#endif
-       }
-       cnt = 0;
-       while (cnt != mt_count) {
-               last_mark_ppos = ntohl(STp->buffer->aux->last_mark_ppos);
-               if (last_mark_ppos == -1)
-                       return (-EIO);
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Positioning to last mark at %d\n", name, last_mark_ppos);
-#endif
-               osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
-               cnt++;
-               if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
-#endif
-                       return (-EIO);
-               }
-               if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-                       printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
-                                        name, last_mark_ppos);
-                       return (-EIO);
-               }
-       }
-found:
-       if (mt_op == MTBSFM) {
-               STp->frame_seq_number++;
-               STp->frame_in_buffer      = 0;
-               STp->buffer->buffer_bytes = 0;
-               STp->buffer->read_pointer = 0;
-               STp->logical_blk_num     += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
-       }
-       return 0;
-}
-
-/*
- * ADRL 1.1 compatible "slow" space filemarks fwd version
- *
- * Just scans for the filemark sequentially.
- */
-static int osst_space_over_filemarks_forward_slow(struct osst_tape * STp, struct osst_request ** aSRpnt,
-                                                                    int mt_op, int mt_count)
-{
-       int     cnt = 0;
-#if DEBUG
-       char  * name = tape_name(STp);
-
-       printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_slow %d %d\n", name, mt_op, mt_count);
-#endif
-       if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
-#endif
-               return (-EIO);
-       }
-       while (1) {
-               if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
-#endif
-                       return (-EIO);
-               }
-               if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
-                       cnt++;
-               if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
-#endif
-                       if (STp->first_frame_position > STp->eod_frame_ppos+1) {
-#if DEBUG
-                               printk(OSST_DEB_MSG "%s:D: EOD position corrected (%d=>%d)\n",
-                                               name, STp->eod_frame_ppos, STp->first_frame_position-1);
-#endif
-                               STp->eod_frame_ppos = STp->first_frame_position-1;
-                       }
-                       return (-EIO);
-               }
-               if (cnt == mt_count)
-                       break;
-               STp->frame_in_buffer = 0;
-       }
-       if (mt_op == MTFSF) {
-               STp->frame_seq_number++;
-               STp->frame_in_buffer      = 0;
-               STp->buffer->buffer_bytes = 0;
-               STp->buffer->read_pointer = 0;
-               STp->logical_blk_num     += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
-       }
-       return 0;
-}
-
-/*
- * Fast linux specific version of OnStream FSF
- */
-static int osst_space_over_filemarks_forward_fast(struct osst_tape * STp, struct osst_request ** aSRpnt,
-                                                                    int mt_op, int mt_count)
-{
-       char  * name = tape_name(STp);
-       int     cnt  = 0,
-               next_mark_ppos = -1;
-
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_fast %d %d\n", name, mt_op, mt_count);
-#endif
-       if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
-#endif
-               return (-EIO);
-       }
-
-       if (STp->linux_media_version >= 4) {
-               /*
-                * direct lookup in header filemark list
-                */
-               cnt = ntohl(STp->buffer->aux->filemark_cnt) - 1;
-               if (STp->header_ok                         && 
-                   STp->header_cache != NULL              &&
-                   (cnt + mt_count)   < OS_FM_TAB_MAX     &&
-                   (cnt + mt_count)   < STp->filemark_cnt &&
-                   ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
-                    (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == STp->buffer->aux->last_mark_ppos)))
-
-                       next_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt + mt_count]);
-#if DEBUG
-               if (STp->header_cache == NULL || (cnt + mt_count) >= OS_FM_TAB_MAX)
-                       printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
-                              STp->header_cache == NULL?"lack of header cache":"count out of range");
-               else
-                       printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
-                              name, cnt,
-                              ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
-                               (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] ==
-                                        STp->buffer->aux->last_mark_ppos))?"match":"error",
-                              mt_count, next_mark_ppos);
-#endif
-               if (next_mark_ppos <= 10 || next_mark_ppos > STp->eod_frame_ppos) {
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
-#endif
-                       return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
-               } else {
-                       osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
-                       if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
-                               printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
-                                                name);
-#endif
-                               return (-EIO);
-                       }
-                       if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-                               printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
-                                                name, next_mark_ppos);
-                               return (-EIO);
-                       }
-                       if (ntohl(STp->buffer->aux->filemark_cnt) != cnt + mt_count) {
-                               printk(KERN_WARNING "%s:W: Expected to find marker %d at ppos %d, not %d\n",
-                                                name, cnt+mt_count, next_mark_ppos,
-                                                ntohl(STp->buffer->aux->filemark_cnt));
-                                       return (-EIO);
-                       }
-               }
-       } else {
-               /*
-                * Find nearest (usually previous) marker, then jump from marker to marker
-                */
-               while (1) {
-                       if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
-                               break;
-                       if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
-#if DEBUG
-                               printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
-#endif
-                               return (-EIO);
-                       }
-                       if (ntohl(STp->buffer->aux->filemark_cnt) == 0) {
-                               if (STp->first_mark_ppos == -1) {
-#if DEBUG
-                                       printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
-#endif
-                                       return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
-                               }
-                               osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos);
-                               if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
-                                       printk(OSST_DEB_MSG
-                                              "%s:D: Couldn't get logical blk num in space_filemarks_fwd_fast\n",
-                                              name);
-#endif
-                                       return (-EIO);
-                               }
-                               if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-                                       printk(KERN_WARNING "%s:W: Expected to find filemark at %d\n",
-                                                        name, STp->first_mark_ppos);
-                                       return (-EIO);
-                               }
-                       } else {
-                               if (osst_space_over_filemarks_backward(STp, aSRpnt, MTBSF, 1) < 0)
-                                       return (-EIO);
-                               mt_count++;
-                       }
-               }
-               cnt++;
-               while (cnt != mt_count) {
-                       next_mark_ppos = ntohl(STp->buffer->aux->next_mark_ppos);
-                       if (!next_mark_ppos || next_mark_ppos > STp->eod_frame_ppos) {
-#if DEBUG
-                               printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
-#endif
-                               return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count - cnt);
-                       }
-#if DEBUG
-                       else printk(OSST_DEB_MSG "%s:D: Positioning to next mark at %d\n", name, next_mark_ppos);
-#endif
-                       osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
-                       cnt++;
-                       if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
-                               printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
-                                                name);
-#endif
-                               return (-EIO);
-                       }
-                       if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-                               printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
-                                                name, next_mark_ppos);
-                               return (-EIO);
-                       }
-               }
-       }
-       if (mt_op == MTFSF) {
-               STp->frame_seq_number++;
-               STp->frame_in_buffer      = 0;
-               STp->buffer->buffer_bytes = 0;
-               STp->buffer->read_pointer = 0;
-               STp->logical_blk_num     += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
-       }
-       return 0;
-}
-
-/*
- * In debug mode, we want to see as many errors as possible
- * to test the error recovery mechanism.
- */
-#if DEBUG
-static void osst_set_retries(struct osst_tape * STp, struct osst_request ** aSRpnt, int retries)
-{
-       unsigned char           cmd[MAX_COMMAND_SIZE];
-       struct osst_request   * SRpnt  = * aSRpnt;
-       char                  * name   = tape_name(STp);
-
-       memset(cmd, 0, MAX_COMMAND_SIZE);
-       cmd[0] = MODE_SELECT;
-       cmd[1] = 0x10;
-       cmd[4] = NUMBER_RETRIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
-       (STp->buffer)->b_data[0] = cmd[4] - 1;
-       (STp->buffer)->b_data[1] = 0;                   /* Medium Type - ignoring */
-       (STp->buffer)->b_data[2] = 0;                   /* Reserved */
-       (STp->buffer)->b_data[3] = 0;                   /* Block Descriptor Length */
-       (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = NUMBER_RETRIES_PAGE | (1 << 7);
-       (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 2;
-       (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 4;
-       (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = retries;
-
-       if (debugging)
-           printk(OSST_DEB_MSG "%s:D: Setting number of retries on OnStream tape to %d\n", name, retries);
-
-       SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
-       *aSRpnt = SRpnt;
-
-       if ((STp->buffer)->syscall_result)
-           printk (KERN_ERR "%s:D: Couldn't set retries to %d\n", name, retries);
-}
-#endif
-
-
-static int osst_write_filemark(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
-       int     result;
-       int     this_mark_ppos = STp->first_frame_position;
-       int     this_mark_lbn  = STp->logical_blk_num;
-#if DEBUG
-       char  * name = tape_name(STp);
-#endif
-
-       if (STp->raw) return 0;
-
-       STp->write_type = OS_WRITE_NEW_MARK;
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Writing Filemark %i at fppos %d (fseq %d, lblk %d)\n", 
-              name, STp->filemark_cnt, this_mark_ppos, STp->frame_seq_number, this_mark_lbn);
-#endif
-       STp->dirty = 1;
-       result  = osst_flush_write_buffer(STp, aSRpnt);
-       result |= osst_flush_drive_buffer(STp, aSRpnt);
-       STp->last_mark_ppos = this_mark_ppos;
-       STp->last_mark_lbn  = this_mark_lbn;
-       if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX)
-               STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos);
-       if (STp->filemark_cnt++ == 0)
-               STp->first_mark_ppos = this_mark_ppos;
-       return result;
-}
-
-static int osst_write_eod(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
-       int     result;
-#if DEBUG
-       char  * name = tape_name(STp);
-#endif
-
-       if (STp->raw) return 0;
-
-       STp->write_type = OS_WRITE_EOD;
-       STp->eod_frame_ppos = STp->first_frame_position;
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Writing EOD at fppos %d (fseq %d, lblk %d)\n", name,
-                       STp->eod_frame_ppos, STp->frame_seq_number, STp->logical_blk_num);
-#endif
-       STp->dirty = 1;
-
-       result  = osst_flush_write_buffer(STp, aSRpnt); 
-       result |= osst_flush_drive_buffer(STp, aSRpnt);
-       STp->eod_frame_lfa = --(STp->frame_seq_number);
-       return result;
-}
-
-static int osst_write_filler(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count)
-{
-       char * name = tape_name(STp);
-
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Reached onstream write filler group %d\n", name, where);
-#endif
-       osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
-       osst_set_frame_position(STp, aSRpnt, where, 0);
-       STp->write_type = OS_WRITE_FILLER;
-       while (count--) {
-               memcpy(STp->buffer->b_data, "Filler", 6);
-               STp->buffer->buffer_bytes = 6;
-               STp->dirty = 1;
-               if (osst_flush_write_buffer(STp, aSRpnt)) {
-                       printk(KERN_INFO "%s:I: Couldn't write filler frame\n", name);
-                       return (-EIO);
-               }
-       }
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Exiting onstream write filler group\n", name);
-#endif
-       return osst_flush_drive_buffer(STp, aSRpnt);
-}
-
-static int __osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count)
-{
-       char * name = tape_name(STp);
-       int     result;
-
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Reached onstream write header group %d\n", name, where);
-#endif
-       osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
-       osst_set_frame_position(STp, aSRpnt, where, 0);
-       STp->write_type = OS_WRITE_HEADER;
-       while (count--) {
-               osst_copy_to_buffer(STp->buffer, (unsigned char *)STp->header_cache);
-               STp->buffer->buffer_bytes = sizeof(os_header_t);
-               STp->dirty = 1;
-               if (osst_flush_write_buffer(STp, aSRpnt)) {
-                       printk(KERN_INFO "%s:I: Couldn't write header frame\n", name);
-                       return (-EIO);
-               }
-       }
-       result = osst_flush_drive_buffer(STp, aSRpnt);
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Write onstream header group %s\n", name, result?"failed":"done");
-#endif
-       return result;
-}
-
-static int osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int locate_eod)
-{
-       os_header_t * header;
-       int           result;
-       char        * name = tape_name(STp);
-
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Writing tape header\n", name);
-#endif
-       if (STp->raw) return 0;
-
-       if (STp->header_cache == NULL) {
-               if ((STp->header_cache = vmalloc(sizeof(os_header_t))) == NULL) {
-                       printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
-                       return (-ENOMEM);
-               }
-               memset(STp->header_cache, 0, sizeof(os_header_t));
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Allocated and cleared memory for header cache\n", name);
-#endif
-       }
-       if (STp->header_ok) STp->update_frame_cntr++;
-       else                STp->update_frame_cntr = 0;
-
-       header = STp->header_cache;
-       strcpy(header->ident_str, "ADR_SEQ");
-       header->major_rev      = 1;
-       header->minor_rev      = 4;
-       header->ext_trk_tb_off = htons(17192);
-       header->pt_par_num     = 1;
-       header->partition[0].partition_num              = OS_DATA_PARTITION;
-       header->partition[0].par_desc_ver               = OS_PARTITION_VERSION;
-       header->partition[0].wrt_pass_cntr              = htons(STp->wrt_pass_cntr);
-       header->partition[0].first_frame_ppos           = htonl(STp->first_data_ppos);
-       header->partition[0].last_frame_ppos            = htonl(STp->capacity);
-       header->partition[0].eod_frame_ppos             = htonl(STp->eod_frame_ppos);
-       header->cfg_col_width                           = htonl(20);
-       header->dat_col_width                           = htonl(1500);
-       header->qfa_col_width                           = htonl(0);
-       header->ext_track_tb.nr_stream_part             = 1;
-       header->ext_track_tb.et_ent_sz                  = 32;
-       header->ext_track_tb.dat_ext_trk_ey.et_part_num = 0;
-       header->ext_track_tb.dat_ext_trk_ey.fmt         = 1;
-       header->ext_track_tb.dat_ext_trk_ey.fm_tab_off  = htons(17736);
-       header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi = 0;
-       header->ext_track_tb.dat_ext_trk_ey.last_hlb    = htonl(STp->eod_frame_lfa);
-       header->ext_track_tb.dat_ext_trk_ey.last_pp     = htonl(STp->eod_frame_ppos);
-       header->dat_fm_tab.fm_part_num                  = 0;
-       header->dat_fm_tab.fm_tab_ent_sz                = 4;
-       header->dat_fm_tab.fm_tab_ent_cnt               = htons(STp->filemark_cnt<OS_FM_TAB_MAX?
-                                                               STp->filemark_cnt:OS_FM_TAB_MAX);
-
-       result  = __osst_write_header(STp, aSRpnt, 0xbae, 5);
-       if (STp->update_frame_cntr == 0)
-                   osst_write_filler(STp, aSRpnt, 0xbb3, 5);
-       result &= __osst_write_header(STp, aSRpnt,     5, 5);
-
-       if (locate_eod) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Locating back to eod frame addr %d\n", name, STp->eod_frame_ppos);
-#endif
-               osst_set_frame_position(STp, aSRpnt, STp->eod_frame_ppos, 0);
-       }
-       if (result)
-               printk(KERN_ERR "%s:E: Write header failed\n", name);
-       else {
-               memcpy(STp->application_sig, "LIN4", 4);
-               STp->linux_media         = 1;
-               STp->linux_media_version = 4;
-               STp->header_ok           = 1;
-       }
-       return result;
-}
-
-static int osst_reset_header(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
-       if (STp->header_cache != NULL)
-               memset(STp->header_cache, 0, sizeof(os_header_t));
-
-       STp->logical_blk_num = STp->frame_seq_number = 0;
-       STp->frame_in_buffer = 0;
-       STp->eod_frame_ppos = STp->first_data_ppos = 0x0000000A;
-       STp->filemark_cnt = 0;
-       STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
-       return osst_write_header(STp, aSRpnt, 1);
-}
-
-static int __osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt, int ppos)
-{
-       char        * name = tape_name(STp);
-       os_header_t * header;
-       os_aux_t    * aux;
-       char          id_string[8];
-       int           linux_media_version,
-                     update_frame_cntr;
-
-       if (STp->raw)
-               return 1;
-
-       if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) {
-               if (osst_set_frame_position(STp, aSRpnt, ppos, 0))
-                       printk(KERN_WARNING "%s:W: Couldn't position tape\n", name);
-               osst_wait_ready(STp, aSRpnt, 60 * 15, 0);
-               if (osst_initiate_read (STp, aSRpnt)) {
-                       printk(KERN_WARNING "%s:W: Couldn't initiate read\n", name);
-                       return 0;
-               }
-       }
-       if (osst_read_frame(STp, aSRpnt, 180)) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Couldn't read header frame\n", name);
-#endif
-               return 0;
-       }
-       header = (os_header_t *) STp->buffer->b_data;   /* warning: only first segment addressable */
-       aux = STp->buffer->aux;
-       if (aux->frame_type != OS_FRAME_TYPE_HEADER) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Skipping non-header frame (%d)\n", name, ppos);
-#endif
-               return 0;
-       }
-       if (ntohl(aux->frame_seq_num)              != 0                   ||
-           ntohl(aux->logical_blk_num)            != 0                   ||
-                 aux->partition.partition_num     != OS_CONFIG_PARTITION ||
-           ntohl(aux->partition.first_frame_ppos) != 0                   ||
-           ntohl(aux->partition.last_frame_ppos)  != 0xbb7               ) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Invalid header frame (%d,%d,%d,%d,%d)\n", name,
-                               ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
-                               aux->partition.partition_num, ntohl(aux->partition.first_frame_ppos),
-                               ntohl(aux->partition.last_frame_ppos));
-#endif
-               return 0;
-       }
-       if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0 &&
-           strncmp(header->ident_str, "ADR-SEQ", 7) != 0) {
-               strlcpy(id_string, header->ident_str, 8);
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Invalid header identification string %s\n", name, id_string);
-#endif
-               return 0;
-       }
-       update_frame_cntr = ntohl(aux->update_frame_cntr);
-       if (update_frame_cntr < STp->update_frame_cntr) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Skipping frame %d with update_frame_counter %d<%d\n",
-                                  name, ppos, update_frame_cntr, STp->update_frame_cntr);
-#endif
-               return 0;
-       }
-       if (header->major_rev != 1 || header->minor_rev != 4 ) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: %s revision %d.%d detected (1.4 supported)\n", 
-                                name, (header->major_rev != 1 || header->minor_rev < 2 || 
-                                      header->minor_rev  > 4 )? "Invalid" : "Warning:",
-                                header->major_rev, header->minor_rev);
-#endif
-               if (header->major_rev != 1 || header->minor_rev < 2 || header->minor_rev > 4)
-                       return 0;
-       }
-#if DEBUG
-       if (header->pt_par_num != 1)
-               printk(KERN_INFO "%s:W: %d partitions defined, only one supported\n", 
-                                name, header->pt_par_num);
-#endif
-       memcpy(id_string, aux->application_sig, 4);
-       id_string[4] = 0;
-       if (memcmp(id_string, "LIN", 3) == 0) {
-               STp->linux_media = 1;
-               linux_media_version = id_string[3] - '0';
-               if (linux_media_version != 4)
-                       printk(KERN_INFO "%s:I: Linux media version %d detected (current 4)\n",
-                                        name, linux_media_version);
-       } else {
-               printk(KERN_WARNING "%s:W: Non Linux media detected (%s)\n", name, id_string);
-               return 0;
-       }
-       if (linux_media_version < STp->linux_media_version) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Skipping frame %d with linux_media_version %d\n",
-                                 name, ppos, linux_media_version);
-#endif
-               return 0;
-       }
-       if (linux_media_version > STp->linux_media_version) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Frame %d sets linux_media_version to %d\n",
-                                  name, ppos, linux_media_version);
-#endif
-               memcpy(STp->application_sig, id_string, 5);
-               STp->linux_media_version = linux_media_version;
-               STp->update_frame_cntr = -1;
-       }
-       if (update_frame_cntr > STp->update_frame_cntr) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Frame %d sets update_frame_counter to %d\n",
-                                  name, ppos, update_frame_cntr);
-#endif
-               if (STp->header_cache == NULL) {
-                       if ((STp->header_cache = vmalloc(sizeof(os_header_t))) == NULL) {
-                               printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
-                               return 0;
-                       }
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: Allocated memory for header cache\n", name);
-#endif
-               }
-               osst_copy_from_buffer(STp->buffer, (unsigned char *)STp->header_cache);
-               header = STp->header_cache;     /* further accesses from cached (full) copy */
-
-               STp->wrt_pass_cntr     = ntohs(header->partition[0].wrt_pass_cntr);
-               STp->first_data_ppos   = ntohl(header->partition[0].first_frame_ppos);
-               STp->eod_frame_ppos    = ntohl(header->partition[0].eod_frame_ppos);
-               STp->eod_frame_lfa     = ntohl(header->ext_track_tb.dat_ext_trk_ey.last_hlb);
-               STp->filemark_cnt      = ntohl(aux->filemark_cnt);
-               STp->first_mark_ppos   = ntohl(aux->next_mark_ppos);
-               STp->last_mark_ppos    = ntohl(aux->last_mark_ppos);
-               STp->last_mark_lbn     = ntohl(aux->last_mark_lbn);
-               STp->update_frame_cntr = update_frame_cntr;
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Detected write pass %d, update frame counter %d, filemark counter %d\n",
-                         name, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt);
-       printk(OSST_DEB_MSG "%s:D: first data frame on tape = %d, last = %d, eod frame = %d\n", name,
-                         STp->first_data_ppos,
-                         ntohl(header->partition[0].last_frame_ppos),
-                         ntohl(header->partition[0].eod_frame_ppos));
-       printk(OSST_DEB_MSG "%s:D: first mark on tape = %d, last = %d, eod frame = %d\n", 
-                         name, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos);
-#endif
-               if (header->minor_rev < 4 && STp->linux_media_version == 4) {
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: Moving filemark list to ADR 1.4 location\n", name);
-#endif
-                       memcpy((void *)header->dat_fm_tab.fm_tab_ent, 
-                              (void *)header->old_filemark_list, sizeof(header->dat_fm_tab.fm_tab_ent));
-                       memset((void *)header->old_filemark_list, 0, sizeof(header->old_filemark_list));
-               }
-               if (header->minor_rev == 4   &&
-                   (header->ext_trk_tb_off                          != htons(17192)               ||
-                    header->partition[0].partition_num              != OS_DATA_PARTITION          ||
-                    header->partition[0].par_desc_ver               != OS_PARTITION_VERSION       ||
-                    header->partition[0].last_frame_ppos            != htonl(STp->capacity)       ||
-                    header->cfg_col_width                           != htonl(20)                  ||
-                    header->dat_col_width                           != htonl(1500)                ||
-                    header->qfa_col_width                           != htonl(0)                   ||
-                    header->ext_track_tb.nr_stream_part             != 1                          ||
-                    header->ext_track_tb.et_ent_sz                  != 32                         ||
-                    header->ext_track_tb.dat_ext_trk_ey.et_part_num != OS_DATA_PARTITION          ||
-                    header->ext_track_tb.dat_ext_trk_ey.fmt         != 1                          ||
-                    header->ext_track_tb.dat_ext_trk_ey.fm_tab_off  != htons(17736)               ||
-                    header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi != 0                          ||
-                    header->ext_track_tb.dat_ext_trk_ey.last_pp     != htonl(STp->eod_frame_ppos) ||
-                    header->dat_fm_tab.fm_part_num                  != OS_DATA_PARTITION          ||
-                    header->dat_fm_tab.fm_tab_ent_sz                != 4                          ||
-                    header->dat_fm_tab.fm_tab_ent_cnt               !=
-                            htons(STp->filemark_cnt<OS_FM_TAB_MAX?STp->filemark_cnt:OS_FM_TAB_MAX)))
-                       printk(KERN_WARNING "%s:W: Failed consistency check ADR 1.4 format\n", name);
-
-       }
-
-       return 1;
-}
-
-static int osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
-       int     position, ppos;
-       int     first, last;
-       int     valid = 0;
-       char  * name  = tape_name(STp);
-
-       position = osst_get_frame_position(STp, aSRpnt);
-
-       if (STp->raw) {
-               STp->header_ok = STp->linux_media = 1;
-               STp->linux_media_version = 0;
-               return 1;
-       }
-       STp->header_ok = STp->linux_media = STp->linux_media_version = 0;
-       STp->wrt_pass_cntr = STp->update_frame_cntr = -1;
-       STp->eod_frame_ppos = STp->first_data_ppos = -1;
-       STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Reading header\n", name);
-#endif
-
-       /* optimization for speed - if we are positioned at ppos 10, read second group first  */        
-       /* TODO try the ADR 1.1 locations for the second group if we have no valid one yet... */
-
-       first = position==10?0xbae: 5;
-       last  = position==10?0xbb3:10;
-
-       for (ppos = first; ppos < last; ppos++)
-               if (__osst_analyze_headers(STp, aSRpnt, ppos))
-                       valid = 1;
-
-       first = position==10? 5:0xbae;
-       last  = position==10?10:0xbb3;
-
-       for (ppos = first; ppos < last; ppos++)
-               if (__osst_analyze_headers(STp, aSRpnt, ppos))
-                       valid = 1;
-
-       if (!valid) {
-               printk(KERN_ERR "%s:E: Failed to find valid ADRL header, new media?\n", name);
-               STp->eod_frame_ppos = STp->first_data_ppos = 0;
-               osst_set_frame_position(STp, aSRpnt, 10, 0);
-               return 0;
-       }
-       if (position <= STp->first_data_ppos) {
-               position = STp->first_data_ppos;
-               STp->ps[0].drv_file = STp->ps[0].drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
-       }
-       osst_set_frame_position(STp, aSRpnt, position, 0);
-       STp->header_ok = 1;
-
-       return 1;
-}
-
-static int osst_verify_position(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
-       int     frame_position  = STp->first_frame_position;
-       int     frame_seq_numbr = STp->frame_seq_number;
-       int     logical_blk_num = STp->logical_blk_num;
-               int     halfway_frame   = STp->frame_in_buffer;
-       int     read_pointer    = STp->buffer->read_pointer;
-       int     prev_mark_ppos  = -1;
-       int     actual_mark_ppos, i, n;
-#if DEBUG
-       char  * name = tape_name(STp);
-
-       printk(OSST_DEB_MSG "%s:D: Verify that the tape is really the one we think before writing\n", name);
-#endif
-       osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
-       if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in verify_position\n", name);
-#endif
-               return (-EIO);
-       }
-       if (STp->linux_media_version >= 4) {
-               for (i=0; i<STp->filemark_cnt; i++)
-                       if ((n=ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i])) < frame_position)
-                               prev_mark_ppos = n;
-       } else
-               prev_mark_ppos = frame_position - 1;  /* usually - we don't really know */
-       actual_mark_ppos = STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER ?
-                               frame_position - 1 : ntohl(STp->buffer->aux->last_mark_ppos);
-       if (frame_position  != STp->first_frame_position                   ||
-           frame_seq_numbr != STp->frame_seq_number + (halfway_frame?0:1) ||
-           prev_mark_ppos  != actual_mark_ppos                            ) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Block mismatch: fppos %d-%d, fseq %d-%d, mark %d-%d\n", name,
-                                 STp->first_frame_position, frame_position, 
-                                 STp->frame_seq_number + (halfway_frame?0:1),
-                                 frame_seq_numbr, actual_mark_ppos, prev_mark_ppos);
-#endif
-               return (-EIO);
-       }
-       if (halfway_frame) {
-               /* prepare buffer for append and rewrite on top of original */
-               osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
-               STp->buffer->buffer_bytes  = read_pointer;
-               STp->ps[STp->partition].rw = ST_WRITING;
-               STp->dirty                 = 1;
-       }
-       STp->frame_in_buffer  = halfway_frame;
-       STp->frame_seq_number = frame_seq_numbr;
-       STp->logical_blk_num  = logical_blk_num;
-       return 0;
-}
-
-/* Acc. to OnStream, the vers. numbering is the following:
- * X.XX for released versions (X=digit), 
- * XXXY for unreleased versions (Y=letter)
- * Ordering 1.05 < 106A < 106B < ...  < 106a < ... < 1.06
- * This fn makes monoton numbers out of this scheme ...
- */
-static unsigned int osst_parse_firmware_rev (const char * str)
-{
-       if (str[1] == '.') {
-               return (str[0]-'0')*10000
-                       +(str[2]-'0')*1000
-                       +(str[3]-'0')*100;
-       } else {
-               return (str[0]-'0')*10000
-                       +(str[1]-'0')*1000
-                       +(str[2]-'0')*100 - 100
-                       +(str[3]-'@');
-       }
-}
-
-/*
- * Configure the OnStream SCII tape drive for default operation
- */
-static int osst_configure_onstream(struct osst_tape *STp, struct osst_request ** aSRpnt)
-{
-       unsigned char                  cmd[MAX_COMMAND_SIZE];
-       char                         * name = tape_name(STp);
-       struct osst_request          * SRpnt = * aSRpnt;
-       osst_mode_parameter_header_t * header;
-       osst_block_size_page_t       * bs;
-       osst_capabilities_page_t     * cp;
-       osst_tape_paramtr_page_t     * prm;
-       int                            drive_buffer_size;
-
-       if (STp->ready != ST_READY) {
-#if DEBUG
-           printk(OSST_DEB_MSG "%s:D: Not Ready\n", name);
-#endif
-           return (-EIO);
-       }
-       
-       if (STp->os_fw_rev < 10600) {
-           printk(KERN_INFO "%s:I: Old OnStream firmware revision detected (%s),\n", name, STp->device->rev);
-           printk(KERN_INFO "%s:I: an upgrade to version 1.06 or above is recommended\n", name);
-       }
-
-       /*
-        * Configure 32.5KB (data+aux) frame size.
-         * Get the current frame size from the block size mode page
-        */
-       memset(cmd, 0, MAX_COMMAND_SIZE);
-       cmd[0] = MODE_SENSE;
-       cmd[1] = 8;
-       cmd[2] = BLOCK_SIZE_PAGE;
-       cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
-       SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
-       if (SRpnt == NULL) {
-#if DEBUG
-           printk(OSST_DEB_MSG "osst :D: Busy\n");
-#endif
-           return (-EBUSY);
-       }
-       *aSRpnt = SRpnt;
-       if ((STp->buffer)->syscall_result != 0) {
-           printk (KERN_ERR "%s:E: Can't get tape block size mode page\n", name);
-           return (-EIO);
-       }
-
-       header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
-       bs = (osst_block_size_page_t *) ((STp->buffer)->b_data + sizeof(osst_mode_parameter_header_t) + header->bdl);
-
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: 32KB play back: %s\n",   name, bs->play32     ? "Yes" : "No");
-       printk(OSST_DEB_MSG "%s:D: 32.5KB play back: %s\n", name, bs->play32_5   ? "Yes" : "No");
-       printk(OSST_DEB_MSG "%s:D: 32KB record: %s\n",      name, bs->record32   ? "Yes" : "No");
-       printk(OSST_DEB_MSG "%s:D: 32.5KB record: %s\n",    name, bs->record32_5 ? "Yes" : "No");
-#endif
-
-       /*
-        * Configure default auto columns mode, 32.5KB transfer mode
-        */ 
-       bs->one = 1;
-       bs->play32 = 0;
-       bs->play32_5 = 1;
-       bs->record32 = 0;
-       bs->record32_5 = 1;
-
-       memset(cmd, 0, MAX_COMMAND_SIZE);
-       cmd[0] = MODE_SELECT;
-       cmd[1] = 0x10;
-       cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
-       SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
-       *aSRpnt = SRpnt;
-       if ((STp->buffer)->syscall_result != 0) {
-           printk (KERN_ERR "%s:E: Couldn't set tape block size mode page\n", name);
-           return (-EIO);
-       }
-
-#if DEBUG
-       printk(KERN_INFO "%s:D: Drive Block Size changed to 32.5K\n", name);
-        /*
-        * In debug mode, we want to see as many errors as possible
-        * to test the error recovery mechanism.
-        */
-       osst_set_retries(STp, aSRpnt, 0);
-       SRpnt = * aSRpnt;
-#endif
-
-       /*
-        * Set vendor name to 'LIN4' for "Linux support version 4".
-        */
-
-       memset(cmd, 0, MAX_COMMAND_SIZE);
-       cmd[0] = MODE_SELECT;
-       cmd[1] = 0x10;
-       cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
-       header->mode_data_length = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH - 1;
-       header->medium_type      = 0;   /* Medium Type - ignoring */
-       header->dsp              = 0;   /* Reserved */
-       header->bdl              = 0;   /* Block Descriptor Length */
-       
-       (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = VENDOR_IDENT_PAGE | (1 << 7);
-       (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 6;
-       (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 'L';
-       (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 'I';
-       (STp->buffer)->b_data[MODE_HEADER_LENGTH + 4] = 'N';
-       (STp->buffer)->b_data[MODE_HEADER_LENGTH + 5] = '4';
-       (STp->buffer)->b_data[MODE_HEADER_LENGTH + 6] = 0;
-       (STp->buffer)->b_data[MODE_HEADER_LENGTH + 7] = 0;
-
-       SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
-       *aSRpnt = SRpnt;
-
-       if ((STp->buffer)->syscall_result != 0) {
-           printk (KERN_ERR "%s:E: Couldn't set vendor name to %s\n", name, 
-                       (char *) ((STp->buffer)->b_data + MODE_HEADER_LENGTH + 2));
-           return (-EIO);
-       }
-
-       memset(cmd, 0, MAX_COMMAND_SIZE);
-       cmd[0] = MODE_SENSE;
-       cmd[1] = 8;
-       cmd[2] = CAPABILITIES_PAGE;
-       cmd[4] = CAPABILITIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
-       SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
-       *aSRpnt = SRpnt;
-
-       if ((STp->buffer)->syscall_result != 0) {
-           printk (KERN_ERR "%s:E: Can't get capabilities page\n", name);
-           return (-EIO);
-       }
-
-       header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
-       cp     = (osst_capabilities_page_t    *) ((STp->buffer)->b_data +
-                sizeof(osst_mode_parameter_header_t) + header->bdl);
-
-       drive_buffer_size = ntohs(cp->buffer_size) / 2;
-
-       memset(cmd, 0, MAX_COMMAND_SIZE);
-       cmd[0] = MODE_SENSE;
-       cmd[1] = 8;
-       cmd[2] = TAPE_PARAMTR_PAGE;
-       cmd[4] = TAPE_PARAMTR_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
-       SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
-       *aSRpnt = SRpnt;
-
-       if ((STp->buffer)->syscall_result != 0) {
-           printk (KERN_ERR "%s:E: Can't get tape parameter page\n", name);
-           return (-EIO);
-       }
-
-       header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
-       prm    = (osst_tape_paramtr_page_t    *) ((STp->buffer)->b_data +
-                sizeof(osst_mode_parameter_header_t) + header->bdl);
-
-       STp->density  = prm->density;
-       STp->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Density %d, tape length: %dMB, drive buffer size: %dKB\n",
-                         name, STp->density, STp->capacity / 32, drive_buffer_size);
-#endif
-
-       return 0;
-       
-}
-
-
-/* Step over EOF if it has been inadvertently crossed (ioctl not used because
-   it messes up the block number). */
-static int cross_eof(struct osst_tape *STp, struct osst_request ** aSRpnt, int forward)
-{
-       int     result;
-       char  * name = tape_name(STp);
-
-#if DEBUG
-       if (debugging)
-               printk(OSST_DEB_MSG "%s:D: Stepping over filemark %s.\n",
-                                 name, forward ? "forward" : "backward");
-#endif
-
-       if (forward) {
-          /* assumes that the filemark is already read by the drive, so this is low cost */
-          result = osst_space_over_filemarks_forward_slow(STp, aSRpnt, MTFSF, 1);
-       }
-       else
-          /* assumes this is only called if we just read the filemark! */
-          result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - 1);
-
-       if (result < 0)
-          printk(KERN_WARNING "%s:W: Stepping over filemark %s failed.\n",
-                               name, forward ? "forward" : "backward");
-
-       return result;
-}
-
-
-/* Get the tape position. */
-
-static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt)
-{
-       unsigned char           scmd[MAX_COMMAND_SIZE];
-       struct osst_request   * SRpnt;
-       int                     result = 0;
-       char                  * name   = tape_name(STp);
-
-       /* KG: We want to be able to use it for checking Write Buffer availability
-        *  and thus don't want to risk to overwrite anything. Exchange buffers ... */
-       char            mybuf[24];
-       char          * olddata = STp->buffer->b_data;
-       int             oldsize = STp->buffer->buffer_size;
-
-       if (STp->ready != ST_READY) return (-EIO);
-
-       memset (scmd, 0, MAX_COMMAND_SIZE);
-       scmd[0] = READ_POSITION;
-
-       STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
-       SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 20, DMA_FROM_DEVICE,
-                                     STp->timeout, MAX_RETRIES, 1);
-       if (!SRpnt) {
-               STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
-               return (-EBUSY);
-       }
-       *aSRpnt = SRpnt;
-
-       if (STp->buffer->syscall_result)
-               result = ((SRpnt->sense[2] & 0x0f) == 3) ? -EIO : -EINVAL;      /* 3: Write Error */
-
-       if (result == -EINVAL)
-               printk(KERN_ERR "%s:E: Can't read tape position.\n", name);
-       else {
-               if (result == -EIO) {   /* re-read position - this needs to preserve media errors */
-                       unsigned char mysense[16];
-                       memcpy (mysense, SRpnt->sense, 16);
-                       memset (scmd, 0, MAX_COMMAND_SIZE);
-                       scmd[0] = READ_POSITION;
-                       STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
-                       SRpnt = osst_do_scsi(SRpnt, STp, scmd, 20, DMA_FROM_DEVICE,
-                                                   STp->timeout, MAX_RETRIES, 1);
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: Reread position, reason=[%02x:%02x:%02x], result=[%s%02x:%02x:%02x]\n",
-                                       name, mysense[2], mysense[12], mysense[13], STp->buffer->syscall_result?"":"ok:",
-                                       SRpnt->sense[2],SRpnt->sense[12],SRpnt->sense[13]);
-#endif
-                       if (!STp->buffer->syscall_result)
-                               memcpy (SRpnt->sense, mysense, 16);
-                       else
-                               printk(KERN_WARNING "%s:W: Double error in get position\n", name);
-               }
-               STp->first_frame_position = ((STp->buffer)->b_data[4] << 24)
-                                         + ((STp->buffer)->b_data[5] << 16)
-                                         + ((STp->buffer)->b_data[6] << 8)
-                                         +  (STp->buffer)->b_data[7];
-               STp->last_frame_position  = ((STp->buffer)->b_data[ 8] << 24)
-                                         + ((STp->buffer)->b_data[ 9] << 16)
-                                         + ((STp->buffer)->b_data[10] <<  8)
-                                         +  (STp->buffer)->b_data[11];
-               STp->cur_frames           =  (STp->buffer)->b_data[15];
-#if DEBUG
-               if (debugging) {
-                       printk(OSST_DEB_MSG "%s:D: Drive Positions: host %d, tape %d%s, buffer %d\n", name,
-                                           STp->first_frame_position, STp->last_frame_position,
-                                           ((STp->buffer)->b_data[0]&0x80)?" (BOP)":
-                                           ((STp->buffer)->b_data[0]&0x40)?" (EOP)":"",
-                                           STp->cur_frames);
-               }
-#endif
-               if (STp->cur_frames == 0 && STp->first_frame_position != STp->last_frame_position) {
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: Correcting read position %d, %d, %d\n", name,
-                                       STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
-#endif
-                       STp->first_frame_position = STp->last_frame_position;
-               }
-       }
-       STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
-
-       return (result == 0 ? STp->first_frame_position : result);
-}
-
-
-/* Set the tape block */
-static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int ppos, int skip)
-{
-       unsigned char           scmd[MAX_COMMAND_SIZE];
-       struct osst_request   * SRpnt;
-       struct st_partstat    * STps;
-       int                     result = 0;
-       int                     pp     = (ppos == 3000 && !skip)? 0 : ppos;
-       char                  * name   = tape_name(STp);
-
-       if (STp->ready != ST_READY) return (-EIO);
-
-       STps = &(STp->ps[STp->partition]);
-
-       if (ppos < 0 || ppos > STp->capacity) {
-               printk(KERN_WARNING "%s:W: Reposition request %d out of range\n", name, ppos);
-               pp = ppos = ppos < 0 ? 0 : (STp->capacity - 1);
-               result = (-EINVAL);
-       }
-
-       do {
-#if DEBUG
-               if (debugging)
-                       printk(OSST_DEB_MSG "%s:D: Setting ppos to %d.\n", name, pp);
-#endif
-               memset (scmd, 0, MAX_COMMAND_SIZE);
-               scmd[0] = SEEK_10;
-               scmd[1] = 1;
-               scmd[3] = (pp >> 24);
-               scmd[4] = (pp >> 16);
-               scmd[5] = (pp >> 8);
-               scmd[6] =  pp;
-               if (skip)
-                       scmd[9] = 0x80;
-
-               SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, DMA_NONE, STp->long_timeout,
-                                                               MAX_RETRIES, 1);
-               if (!SRpnt)
-                       return (-EBUSY);
-               *aSRpnt  = SRpnt;
-
-               if ((STp->buffer)->syscall_result != 0) {
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: SEEK command from %d to %d failed.\n",
-                                       name, STp->first_frame_position, pp);
-#endif
-                       result = (-EIO);
-               }
-               if (pp != ppos)
-                       osst_wait_ready(STp, aSRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
-       } while ((pp != ppos) && (pp = ppos));
-       STp->first_frame_position = STp->last_frame_position = ppos;
-       STps->eof = ST_NOEOF;
-       STps->at_sm = 0;
-       STps->rw = ST_IDLE;
-       STp->frame_in_buffer = 0;
-       return result;
-}
-
-static int osst_write_trailer(struct osst_tape *STp, struct osst_request ** aSRpnt, int leave_at_EOT)
-{
-       struct st_partstat * STps = &(STp->ps[STp->partition]);
-       int result = 0;
-
-       if (STp->write_type != OS_WRITE_NEW_MARK) {
-               /* true unless the user wrote the filemark for us */
-               result = osst_flush_drive_buffer(STp, aSRpnt);
-               if (result < 0) goto out;
-               result = osst_write_filemark(STp, aSRpnt);
-               if (result < 0) goto out;
-
-               if (STps->drv_file >= 0)
-                       STps->drv_file++ ;
-               STps->drv_block = 0;
-       }
-       result = osst_write_eod(STp, aSRpnt);
-       osst_write_header(STp, aSRpnt, leave_at_EOT);
-
-       STps->eof = ST_FM;
-out:
-       return result;
-}
-\f
-/* osst versions of st functions - augmented and stripped to suit OnStream only */
-
-/* Flush the write buffer (never need to write if variable blocksize). */
-static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt)
-{
-       int                     offset, transfer, blks = 0;
-       int                     result = 0;
-       unsigned char           cmd[MAX_COMMAND_SIZE];
-       struct osst_request   * SRpnt = *aSRpnt;
-       struct st_partstat    * STps;
-       char                  * name = tape_name(STp);
-
-       if ((STp->buffer)->writing) {
-               if (SRpnt == (STp->buffer)->last_SRpnt)
-#if DEBUG
-                       { printk(OSST_DEB_MSG
-        "%s:D: aSRpnt points to osst_request that write_behind_check will release -- cleared\n", name);
-#endif
-                       *aSRpnt = SRpnt = NULL;
-#if DEBUG
-                       } else if (SRpnt)
-                               printk(OSST_DEB_MSG
-        "%s:D: aSRpnt does not point to osst_request that write_behind_check will release -- strange\n", name);
-#endif 
-               osst_write_behind_check(STp);
-               if ((STp->buffer)->syscall_result) {
-#if DEBUG
-                       if (debugging)
-                               printk(OSST_DEB_MSG "%s:D: Async write error (flush) %x.\n",
-                                      name, (STp->buffer)->midlevel_result);
-#endif
-                       if ((STp->buffer)->midlevel_result == INT_MAX)
-                               return (-ENOSPC);
-                       return (-EIO);
-               }
-       }
-
-       result = 0;
-       if (STp->dirty == 1) {
-
-               STp->write_count++;
-               STps     = &(STp->ps[STp->partition]);
-               STps->rw = ST_WRITING;
-               offset   = STp->buffer->buffer_bytes;
-               blks     = (offset + STp->block_size - 1) / STp->block_size;
-               transfer = OS_FRAME_SIZE;
-               
-               if (offset < OS_DATA_SIZE)
-                       osst_zero_buffer_tail(STp->buffer);
-
-               if (STp->poll)
-                       if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 120))
-                               result = osst_recover_wait_frame(STp, aSRpnt, 1);
-
-               memset(cmd, 0, MAX_COMMAND_SIZE);
-               cmd[0] = WRITE_6;
-               cmd[1] = 1;
-               cmd[4] = 1;
-
-               switch  (STp->write_type) {
-                  case OS_WRITE_DATA:
-#if DEBUG
-                       if (debugging)
-                               printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n",
-                                       name, blks, STp->frame_seq_number, 
-                                       STp->logical_blk_num - blks, STp->logical_blk_num - 1);
-#endif
-                       osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
-                                     STp->logical_blk_num - blks, STp->block_size, blks);
-                       break;
-                  case OS_WRITE_EOD:
-                       osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->frame_seq_number++,
-                                     STp->logical_blk_num, 0, 0);
-                       break;
-                  case OS_WRITE_NEW_MARK:
-                       osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->frame_seq_number++,
-                                     STp->logical_blk_num++, 0, blks=1);
-                       break;
-                  case OS_WRITE_HEADER:
-                       osst_init_aux(STp, OS_FRAME_TYPE_HEADER, 0, 0, 0, blks=0);
-                       break;
-               default: /* probably FILLER */
-                       osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0, 0, 0, 0);
-               }
-#if DEBUG
-               if (debugging)
-                       printk(OSST_DEB_MSG "%s:D: Flushing %d bytes, Transferring %d bytes in %d lblocks.\n",
-                                                name, offset, transfer, blks);
-#endif
-
-               SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, transfer, DMA_TO_DEVICE,
-                                             STp->timeout, MAX_RETRIES, 1);
-               *aSRpnt = SRpnt;
-               if (!SRpnt)
-                       return (-EBUSY);
-
-               if ((STp->buffer)->syscall_result != 0) {
-#if DEBUG
-                       printk(OSST_DEB_MSG
-                               "%s:D: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n",
-                               name, SRpnt->sense[0], SRpnt->sense[2],
-                               SRpnt->sense[12], SRpnt->sense[13]);
-#endif
-                       if ((SRpnt->sense[0] & 0x70) == 0x70 &&
-                           (SRpnt->sense[2] & 0x40) && /* FIXME - SC-30 drive doesn't assert EOM bit */
-                           (SRpnt->sense[2] & 0x0f) == NO_SENSE) {
-                               STp->dirty = 0;
-                               (STp->buffer)->buffer_bytes = 0;
-                               result = (-ENOSPC);
-                       }
-                       else {
-                               if (osst_write_error_recovery(STp, aSRpnt, 1)) {
-                                       printk(KERN_ERR "%s:E: Error on flush write.\n", name);
-                                       result = (-EIO);
-                               }
-                       }
-                       STps->drv_block = (-1);         /* FIXME - even if write recovery succeeds? */
-               }
-               else {
-                       STp->first_frame_position++;
-                       STp->dirty = 0;
-                       (STp->buffer)->buffer_bytes = 0;
-               }
-       }
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Exit flush write buffer with code %d\n", name, result);
-#endif
-       return result;
-}
-
-
-/* Flush the tape buffer. The tape will be positioned correctly unless
-   seek_next is true. */
-static int osst_flush_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt, int seek_next)
-{
-       struct st_partstat * STps;
-       int    backspace = 0, result = 0;
-#if DEBUG
-       char * name = tape_name(STp);
-#endif
-
-       /*
-        * If there was a bus reset, block further access
-        * to this device.
-        */
-       if( STp->pos_unknown)
-               return (-EIO);
-
-       if (STp->ready != ST_READY)
-               return 0;
-
-       STps = &(STp->ps[STp->partition]);
-       if (STps->rw == ST_WRITING || STp->dirty) {     /* Writing */
-               STp->write_type = OS_WRITE_DATA;
-               return osst_flush_write_buffer(STp, aSRpnt);
-       }
-       if (STp->block_size == 0)
-               return 0;
-
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Reached flush (read) buffer\n", name);
-#endif
-
-       if (!STp->can_bsr) {
-               backspace = ((STp->buffer)->buffer_bytes + (STp->buffer)->read_pointer) / STp->block_size -
-                           ((STp->buffer)->read_pointer + STp->block_size - 1        ) / STp->block_size ;
-               (STp->buffer)->buffer_bytes = 0;
-               (STp->buffer)->read_pointer = 0;
-               STp->frame_in_buffer = 0;               /* FIXME is this relevant w. OSST? */
-       }
-
-       if (!seek_next) {
-               if (STps->eof == ST_FM_HIT) {
-                       result = cross_eof(STp, aSRpnt, 0); /* Back over the EOF hit */
-                       if (!result)
-                               STps->eof = ST_NOEOF;
-                       else {
-                               if (STps->drv_file >= 0)
-                                       STps->drv_file++;
-                               STps->drv_block = 0;
-                       }
-               }
-               if (!result && backspace > 0)   /* TODO -- design and run a test case for this */
-                       result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - backspace);
-       }
-       else if (STps->eof == ST_FM_HIT) {
-               if (STps->drv_file >= 0)
-                       STps->drv_file++;
-               STps->drv_block = 0;
-               STps->eof = ST_NOEOF;
-       }
-
-       return result;
-}
-
-static int osst_write_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int synchronous)
-{
-       unsigned char           cmd[MAX_COMMAND_SIZE];
-       struct osst_request   * SRpnt;
-       int                     blks;
-#if DEBUG
-       char                  * name = tape_name(STp);
-#endif
-
-       if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) { /* _must_ preserve buffer! */
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Reaching config partition.\n", name);
-#endif
-               if (osst_flush_drive_buffer(STp, aSRpnt) < 0) {
-                       return (-EIO);
-               }
-               /* error recovery may have bumped us past the header partition */
-               if (osst_get_frame_position(STp, aSRpnt) < 0xbb8) {
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: Skipping over config partition.\n", name);
-#endif
-               osst_position_tape_and_confirm(STp, aSRpnt, 0xbb8);
-               }
-       }
-
-       if (STp->poll)
-               if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -48, 120))
-                       if (osst_recover_wait_frame(STp, aSRpnt, 1))
-                               return (-EIO);
-
-//     osst_build_stats(STp, &SRpnt);
-
-       STp->ps[STp->partition].rw = ST_WRITING;
-       STp->write_type            = OS_WRITE_DATA;
-                       
-       memset(cmd, 0, MAX_COMMAND_SIZE);
-       cmd[0]   = WRITE_6;
-       cmd[1]   = 1;
-       cmd[4]   = 1;                                           /* one frame at a time... */
-       blks     = STp->buffer->buffer_bytes / STp->block_size;
-#if DEBUG
-       if (debugging)
-               printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", name, blks, 
-                       STp->frame_seq_number, STp->logical_blk_num - blks, STp->logical_blk_num - 1);
-#endif
-       osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
-                     STp->logical_blk_num - blks, STp->block_size, blks);
-
-#if DEBUG
-       if (!synchronous)
-               STp->write_pending = 1;
-#endif
-       SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, STp->timeout,
-                                                                       MAX_RETRIES, synchronous);
-       if (!SRpnt)
-               return (-EBUSY);
-       *aSRpnt = SRpnt;
-
-       if (synchronous) {
-               if (STp->buffer->syscall_result != 0) {
-#if DEBUG
-                       if (debugging)
-                               printk(OSST_DEB_MSG "%s:D: Error on write:\n", name);
-#endif
-                       if ((SRpnt->sense[0] & 0x70) == 0x70 &&
-                           (SRpnt->sense[2] & 0x40)) {
-                               if ((SRpnt->sense[2] & 0x0f) == VOLUME_OVERFLOW)
-                                       return (-ENOSPC);
-                       }
-                       else {
-                               if (osst_write_error_recovery(STp, aSRpnt, 1))
-                                       return (-EIO);
-                       }
-               }
-               else
-                       STp->first_frame_position++;
-       }
-
-       STp->write_count++;
-
-       return 0;
-}
-
-/* Lock or unlock the drive door. Don't use when struct osst_request allocated. */
-static int do_door_lock(struct osst_tape * STp, int do_lock)
-{
-       int retval;
-
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: %socking drive door.\n", tape_name(STp), do_lock ? "L" : "Unl");
-#endif
-
-       retval = scsi_set_medium_removal(STp->device,
-                       do_lock ? SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW);
-       if (!retval)
-               STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;
-       else
-               STp->door_locked = ST_LOCK_FAILS;
-       return retval;
-}
-
-/* Set the internal state after reset */
-static void reset_state(struct osst_tape *STp)
-{
-       int i;
-       struct st_partstat *STps;
-
-       STp->pos_unknown = 0;
-       for (i = 0; i < ST_NBR_PARTITIONS; i++) {
-               STps = &(STp->ps[i]);
-               STps->rw = ST_IDLE;
-               STps->eof = ST_NOEOF;
-               STps->at_sm = 0;
-               STps->last_block_valid = 0;
-               STps->drv_block = -1;
-               STps->drv_file = -1;
-       }
-}
-                               
-\f
-/* Entry points to osst */
-
-/* Write command */
-static ssize_t osst_write(struct file * filp, const char __user * buf, size_t count, loff_t *ppos)
-{
-       ssize_t               total, retval = 0;
-       ssize_t               i, do_count, blks, transfer;
-       int                   write_threshold;
-       int                   doing_write = 0;
-       const char   __user * b_point;
-       struct osst_request * SRpnt = NULL;
-       struct st_modedef   * STm;
-       struct st_partstat  * STps;
-       struct osst_tape    * STp  = filp->private_data;
-       char                * name = tape_name(STp);
-
-
-       if (mutex_lock_interruptible(&STp->lock))
-               return (-ERESTARTSYS);
-
-       /*
-        * If we are in the middle of error recovery, don't let anyone
-        * else try and use this device.  Also, if error recovery fails, it
-        * may try and take the device offline, in which case all further
-        * access to the device is prohibited.
-        */
-       if( !scsi_block_when_processing_errors(STp->device) ) {
-               retval = (-ENXIO);
-               goto out;
-       }
-       
-       if (STp->ready != ST_READY) {
-               if (STp->ready == ST_NO_TAPE)
-                       retval = (-ENOMEDIUM);
-               else
-                       retval = (-EIO);
-               goto out;
-       }
-       STm = &(STp->modes[STp->current_mode]);
-       if (!STm->defined) {
-               retval = (-ENXIO);
-               goto out;
-       }
-       if (count == 0)
-               goto out;
-
-       /*
-        * If there was a bus reset, block further access
-        * to this device.
-        */
-       if (STp->pos_unknown) {
-               retval = (-EIO);
-               goto out;
-       }
-
-#if DEBUG
-       if (!STp->in_use) {
-               printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
-               retval = (-EIO);
-               goto out;
-       }
-#endif
-
-       if (STp->write_prot) {
-               retval = (-EACCES);
-               goto out;
-       }
-
-       /* Write must be integral number of blocks */
-       if (STp->block_size != 0 && (count % STp->block_size) != 0) {
-               printk(KERN_ERR "%s:E: Write (%zd bytes) not multiple of tape block size (%d%c).\n",
-                                      name, count, STp->block_size<1024?
-                                      STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
-               retval = (-EINVAL);
-               goto out;
-       }
-
-       if (STp->first_frame_position >= STp->capacity - OSST_EOM_RESERVE) {
-               printk(KERN_ERR "%s:E: Write truncated at EOM early warning (frame %d).\n",
-                                      name, STp->first_frame_position);
-               retval = (-ENOSPC);
-               goto out;
-       }
-
-       if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
-               STp->door_locked = ST_LOCKED_AUTO;
-
-       STps = &(STp->ps[STp->partition]);
-
-       if (STps->rw == ST_READING) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Switching from read to write at file %d, block %d\n", name, 
-                                       STps->drv_file, STps->drv_block);
-#endif
-               retval = osst_flush_buffer(STp, &SRpnt, 0);
-               if (retval)
-                       goto out;
-               STps->rw = ST_IDLE;
-       }
-       if (STps->rw != ST_WRITING) {
-               /* Are we totally rewriting this tape? */
-               if (!STp->header_ok ||
-                   (STp->first_frame_position == STp->first_data_ppos && STps->drv_block < 0) ||
-                   (STps->drv_file == 0 && STps->drv_block == 0)) {
-                       STp->wrt_pass_cntr++;
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: Allocating next write pass counter: %d\n",
-                                                 name, STp->wrt_pass_cntr);
-#endif
-                       osst_reset_header(STp, &SRpnt);
-                       STps->drv_file = STps->drv_block = 0;
-               }
-               /* Do we know where we'll be writing on the tape? */
-               else {
-                       if ((STp->fast_open && osst_verify_position(STp, &SRpnt)) ||
-                                       STps->drv_file < 0 || STps->drv_block < 0) {
-                               if (STp->first_frame_position == STp->eod_frame_ppos) { /* at EOD */
-                                       STps->drv_file = STp->filemark_cnt;
-                                       STps->drv_block = 0;
-                               }
-                               else {
-                                       /* We have no idea where the tape is positioned - give up */
-#if DEBUG
-                                       printk(OSST_DEB_MSG
-                                               "%s:D: Cannot write at indeterminate position.\n", name);
-#endif
-                                       retval = (-EIO);
-                                       goto out;
-                               }
-                       }         
-                       if ((STps->drv_file + STps->drv_block) > 0 && STps->drv_file < STp->filemark_cnt) {
-                               STp->filemark_cnt = STps->drv_file;
-                               STp->last_mark_ppos =
-                                       ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]);
-                               printk(KERN_WARNING
-                                       "%s:W: Overwriting file %d with old write pass counter %d\n",
-                                               name, STps->drv_file, STp->wrt_pass_cntr);
-                               printk(KERN_WARNING
-                                       "%s:W: may lead to stale data being accepted on reading back!\n",
-                                               name);
-#if DEBUG
-                               printk(OSST_DEB_MSG
-                                 "%s:D: resetting filemark count to %d and last mark ppos,lbn to %d,%d\n",
-                                       name, STp->filemark_cnt, STp->last_mark_ppos, STp->last_mark_lbn);
-#endif
-                       }
-               }
-               STp->fast_open = 0;
-       }
-       if (!STp->header_ok) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Write cannot proceed without valid headers\n", name);
-#endif
-               retval = (-EIO);
-               goto out;
-       }
-
-       if ((STp->buffer)->writing) {
-if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name, __LINE__);
-               osst_write_behind_check(STp);
-               if ((STp->buffer)->syscall_result) {
-#if DEBUG
-               if (debugging)
-                       printk(OSST_DEB_MSG "%s:D: Async write error (write) %x.\n", name,
-                                                (STp->buffer)->midlevel_result);
-#endif
-               if ((STp->buffer)->midlevel_result == INT_MAX)
-                       STps->eof = ST_EOM_OK;
-               else
-                       STps->eof = ST_EOM_ERROR;
-               }
-       }
-       if (STps->eof == ST_EOM_OK) {
-               retval = (-ENOSPC);
-               goto out;
-       }
-       else if (STps->eof == ST_EOM_ERROR) {
-               retval = (-EIO);
-               goto out;
-       }
-
-       /* Check the buffer readability in cases where copy_user might catch
-                the problems after some tape movement. */
-       if ((copy_from_user(&i, buf, 1) != 0 ||
-            copy_from_user(&i, buf + count - 1, 1) != 0)) {
-               retval = (-EFAULT);
-               goto out;
-       }
-
-       if (!STm->do_buffer_writes) {
-               write_threshold = 1;
-       }
-       else
-               write_threshold = (STp->buffer)->buffer_blocks * STp->block_size;
-       if (!STm->do_async_writes)
-               write_threshold--;
-
-       total = count;
-#if DEBUG
-       if (debugging)
-               printk(OSST_DEB_MSG "%s:D: Writing %d bytes to file %d block %d lblk %d fseq %d fppos %d\n",
-                               name, (int) count, STps->drv_file, STps->drv_block,
-                               STp->logical_blk_num, STp->frame_seq_number, STp->first_frame_position);
-#endif
-       b_point = buf;
-       while ((STp->buffer)->buffer_bytes + count > write_threshold)
-       {
-               doing_write = 1;
-               do_count = (STp->buffer)->buffer_blocks * STp->block_size -
-                          (STp->buffer)->buffer_bytes;
-               if (do_count > count)
-                       do_count = count;
-
-               i = append_to_buffer(b_point, STp->buffer, do_count);
-               if (i) {
-                       retval = i;
-                       goto out;
-               }
-
-               blks = do_count / STp->block_size;
-               STp->logical_blk_num += blks;  /* logical_blk_num is incremented as data is moved from user */
-  
-               i = osst_write_frame(STp, &SRpnt, 1);
-
-               if (i == (-ENOSPC)) {
-                       transfer = STp->buffer->writing;        /* FIXME -- check this logic */
-                       if (transfer <= do_count) {
-                               *ppos += do_count - transfer;
-                               count -= do_count - transfer;
-                               if (STps->drv_block >= 0) {
-                                       STps->drv_block += (do_count - transfer) / STp->block_size;
-                               }
-                               STps->eof = ST_EOM_OK;
-                               retval = (-ENOSPC);             /* EOM within current request */
-#if DEBUG
-                               if (debugging)
-                                     printk(OSST_DEB_MSG "%s:D: EOM with %d bytes unwritten.\n",
-                                                            name, (int) transfer);
-#endif
-                       }
-                       else {
-                               STps->eof = ST_EOM_ERROR;
-                               STps->drv_block = (-1);         /* Too cautious? */
-                               retval = (-EIO);                /* EOM for old data */
-#if DEBUG
-                               if (debugging)
-                                     printk(OSST_DEB_MSG "%s:D: EOM with lost data.\n", name);
-#endif
-                       }
-               }
-               else
-                       retval = i;
-                       
-               if (retval < 0) {
-                       if (SRpnt != NULL) {
-                               osst_release_request(SRpnt);
-                               SRpnt = NULL;
-                       }
-                       STp->buffer->buffer_bytes = 0;
-                       STp->dirty = 0;
-                       if (count < total)
-                               retval = total - count;
-                       goto out;
-               }
-
-               *ppos += do_count;
-               b_point += do_count;
-               count -= do_count;
-               if (STps->drv_block >= 0) {
-                       STps->drv_block += blks;
-               }
-               STp->buffer->buffer_bytes = 0;
-               STp->dirty = 0;
-       }  /* end while write threshold exceeded */
-
-       if (count != 0) {
-               STp->dirty = 1;
-               i = append_to_buffer(b_point, STp->buffer, count);
-               if (i) {
-                       retval = i;
-                       goto out;
-               }
-               blks = count / STp->block_size;
-               STp->logical_blk_num += blks;
-               if (STps->drv_block >= 0) {
-                       STps->drv_block += blks;
-               }
-               *ppos += count;
-               count = 0;
-       }
-
-       if (doing_write && (STp->buffer)->syscall_result != 0) {
-               retval = (STp->buffer)->syscall_result;
-               goto out;
-       }
-
-       if (STm->do_async_writes && ((STp->buffer)->buffer_bytes >= STp->write_threshold)) { 
-               /* Schedule an asynchronous write */
-               (STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
-                                          STp->block_size) * STp->block_size;
-               STp->dirty = !((STp->buffer)->writing ==
-                                         (STp->buffer)->buffer_bytes);
-
-               i = osst_write_frame(STp, &SRpnt, 0);
-               if (i < 0) {
-                       retval = (-EIO);
-                       goto out;
-               }
-               SRpnt = NULL;                   /* Prevent releasing this request! */
-       }
-       STps->at_sm &= (total == 0);
-       if (total > 0)
-               STps->eof = ST_NOEOF;
-
-       retval = total;
-
-out:
-       if (SRpnt != NULL) osst_release_request(SRpnt);
-
-       mutex_unlock(&STp->lock);
-
-       return retval;
-}
-
-
-/* Read command */
-static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, loff_t *ppos)
-{
-       ssize_t               total, retval = 0;
-       ssize_t               i, transfer;
-       int                   special;
-       struct st_modedef   * STm;
-       struct st_partstat  * STps;
-       struct osst_request * SRpnt = NULL;
-       struct osst_tape    * STp   = filp->private_data;
-       char                * name  = tape_name(STp);
-
-
-       if (mutex_lock_interruptible(&STp->lock))
-               return (-ERESTARTSYS);
-
-       /*
-        * If we are in the middle of error recovery, don't let anyone
-        * else try and use this device.  Also, if error recovery fails, it
-        * may try and take the device offline, in which case all further
-        * access to the device is prohibited.
-        */
-       if( !scsi_block_when_processing_errors(STp->device) ) {
-               retval = (-ENXIO);
-               goto out;
-       }
-       
-       if (STp->ready != ST_READY) {
-               if (STp->ready == ST_NO_TAPE)
-                       retval = (-ENOMEDIUM);
-               else
-                       retval = (-EIO);
-               goto out;
-       }
-       STm = &(STp->modes[STp->current_mode]);
-       if (!STm->defined) {
-               retval = (-ENXIO);
-               goto out;
-       }
-#if DEBUG
-       if (!STp->in_use) {
-               printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
-               retval = (-EIO);
-               goto out;
-       }
-#endif
-       /* Must have initialized medium */
-       if (!STp->header_ok) {
-               retval = (-EIO);
-               goto out;
-       }
-
-       if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
-               STp->door_locked = ST_LOCKED_AUTO;
-
-       STps = &(STp->ps[STp->partition]);
-       if (STps->rw == ST_WRITING) {
-               retval = osst_flush_buffer(STp, &SRpnt, 0);
-               if (retval)
-                       goto out;
-               STps->rw = ST_IDLE;
-               /* FIXME -- this may leave the tape without EOD and up2date headers */
-       }
-
-       if ((count % STp->block_size) != 0) {
-               printk(KERN_WARNING
-                   "%s:W: Read (%zd bytes) not multiple of tape block size (%d%c).\n", name, count,
-                   STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
-       }
-
-#if DEBUG
-       if (debugging && STps->eof != ST_NOEOF)
-               printk(OSST_DEB_MSG "%s:D: EOF/EOM flag up (%d). Bytes %d\n", name,
-                                    STps->eof, (STp->buffer)->buffer_bytes);
-#endif
-       if ((STp->buffer)->buffer_bytes == 0 &&
-            STps->eof >= ST_EOD_1) {
-               if (STps->eof < ST_EOD) {
-                       STps->eof += 1;
-                       retval = 0;
-                       goto out;
-               }
-               retval = (-EIO);  /* EOM or Blank Check */
-               goto out;
-       }
-
-       /* Check the buffer writability before any tape movement. Don't alter
-                buffer data. */
-       if (copy_from_user(&i, buf, 1)             != 0 ||
-           copy_to_user  (buf, &i, 1)             != 0 ||
-           copy_from_user(&i, buf + count - 1, 1) != 0 ||
-           copy_to_user  (buf + count - 1, &i, 1) != 0) {
-               retval = (-EFAULT);
-               goto out;
-       }
-
-       /* Loop until enough data in buffer or a special condition found */
-       for (total = 0, special = 0; total < count - STp->block_size + 1 && !special; ) {
-
-               /* Get new data if the buffer is empty */
-               if ((STp->buffer)->buffer_bytes == 0) {
-                       if (STps->eof == ST_FM_HIT)
-                               break;
-                       special = osst_get_logical_frame(STp, &SRpnt, STp->frame_seq_number, 0);
-                       if (special < 0) {                      /* No need to continue read */
-                               STp->frame_in_buffer = 0;
-                               retval = special;
-                               goto out;
-                       }
-               }
-
-               /* Move the data from driver buffer to user buffer */
-               if ((STp->buffer)->buffer_bytes > 0) {
-#if DEBUG
-                       if (debugging && STps->eof != ST_NOEOF)
-                           printk(OSST_DEB_MSG "%s:D: EOF up (%d). Left %d, needed %d.\n", name,
-                                                STps->eof, (STp->buffer)->buffer_bytes, (int) (count - total));
-#endif
-                       /* force multiple of block size, note block_size may have been adjusted */
-                       transfer = (((STp->buffer)->buffer_bytes < count - total ?
-                                    (STp->buffer)->buffer_bytes : count - total)/
-                                       STp->block_size) * STp->block_size;
-
-                       if (transfer == 0) {
-                               printk(KERN_WARNING
-                                 "%s:W: Nothing can be transferred, requested %zd, tape block size (%d%c).\n",
-                                       name, count, STp->block_size < 1024?
-                                       STp->block_size:STp->block_size/1024,
-                                       STp->block_size<1024?'b':'k');
-                               break;
-                       }
-                       i = from_buffer(STp->buffer, buf, transfer);
-                       if (i)  {
-                               retval = i;
-                               goto out;
-                       }
-                       STp->logical_blk_num += transfer / STp->block_size;
-                       STps->drv_block      += transfer / STp->block_size;
-                       *ppos          += transfer;
-                       buf                  += transfer;
-                       total                += transfer;
-               }
-               if ((STp->buffer)->buffer_bytes == 0) {
-#if DEBUG
-                       if (debugging)
-                               printk(OSST_DEB_MSG "%s:D: Finished with frame %d\n",
-                                               name, STp->frame_seq_number);
-#endif
-                       STp->frame_in_buffer = 0;
-                       STp->frame_seq_number++;              /* frame to look for next time */
-               }
-       } /* for (total = 0, special = 0; total < count && !special; ) */
-
-       /* Change the eof state if no data from tape or buffer */
-       if (total == 0) {
-               if (STps->eof == ST_FM_HIT) {
-                       STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD_2:ST_FM;
-                       STps->drv_block = 0;
-                       if (STps->drv_file >= 0)
-                               STps->drv_file++;
-               }
-               else if (STps->eof == ST_EOD_1) {
-                       STps->eof = ST_EOD_2;
-                       if (STps->drv_block > 0 && STps->drv_file >= 0)
-                               STps->drv_file++;
-                       STps->drv_block = 0;
-               }
-               else if (STps->eof == ST_EOD_2)
-                       STps->eof = ST_EOD;
-       }
-       else if (STps->eof == ST_FM)
-               STps->eof = ST_NOEOF;
-
-       retval = total;
-
-out:
-       if (SRpnt != NULL) osst_release_request(SRpnt);
-
-       mutex_unlock(&STp->lock);
-
-       return retval;
-}
-
-
-/* Set the driver options */
-static void osst_log_options(struct osst_tape *STp, struct st_modedef *STm, char *name)
-{
-  printk(KERN_INFO
-"%s:I: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
-        name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
-        STm->do_read_ahead);
-  printk(KERN_INFO
-"%s:I:    can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
-        name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
-  printk(KERN_INFO
-"%s:I:    defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n",
-        name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
-        STp->scsi2_logical);
-  printk(KERN_INFO
-"%s:I:    sysv: %d\n", name, STm->sysv);
-#if DEBUG
-  printk(KERN_INFO
-        "%s:D:    debugging: %d\n",
-        name, debugging);
-#endif
-}
-
-
-static int osst_set_options(struct osst_tape *STp, long options)
-{
-       int                 value;
-       long                code;
-       struct st_modedef * STm;
-       char              * name = tape_name(STp);
-
-       STm = &(STp->modes[STp->current_mode]);
-       if (!STm->defined) {
-               memcpy(STm, &(STp->modes[0]), sizeof(*STm));
-               modes_defined = 1;
-#if DEBUG
-               if (debugging)
-                       printk(OSST_DEB_MSG "%s:D: Initialized mode %d definition from mode 0\n",
-                                            name, STp->current_mode);
-#endif
-       }
-
-       code = options & MT_ST_OPTIONS;
-       if (code == MT_ST_BOOLEANS) {
-               STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
-               STm->do_async_writes  = (options & MT_ST_ASYNC_WRITES) != 0;
-               STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
-               STm->do_read_ahead    = (options & MT_ST_READ_AHEAD) != 0;
-               STp->two_fm           = (options & MT_ST_TWO_FM) != 0;
-               STp->fast_mteom       = (options & MT_ST_FAST_MTEOM) != 0;
-               STp->do_auto_lock     = (options & MT_ST_AUTO_LOCK) != 0;
-               STp->can_bsr          = (options & MT_ST_CAN_BSR) != 0;
-               STp->omit_blklims     = (options & MT_ST_NO_BLKLIMS) != 0;
-               if ((STp->device)->scsi_level >= SCSI_2)
-                       STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
-               STp->scsi2_logical    = (options & MT_ST_SCSI2LOGICAL) != 0;
-               STm->sysv             = (options & MT_ST_SYSV) != 0;
-#if DEBUG
-               debugging = (options & MT_ST_DEBUGGING) != 0;
-#endif
-               osst_log_options(STp, STm, name);
-       }
-       else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
-               value = (code == MT_ST_SETBOOLEANS);
-               if ((options & MT_ST_BUFFER_WRITES) != 0)
-                       STm->do_buffer_writes = value;
-               if ((options & MT_ST_ASYNC_WRITES) != 0)
-                       STm->do_async_writes = value;
-               if ((options & MT_ST_DEF_WRITES) != 0)
-                       STm->defaults_for_writes = value;
-               if ((options & MT_ST_READ_AHEAD) != 0)
-                       STm->do_read_ahead = value;
-               if ((options & MT_ST_TWO_FM) != 0)
-                       STp->two_fm = value;
-               if ((options & MT_ST_FAST_MTEOM) != 0)
-                       STp->fast_mteom = value;
-               if ((options & MT_ST_AUTO_LOCK) != 0)
-                       STp->do_auto_lock = value;
-               if ((options & MT_ST_CAN_BSR) != 0)
-                       STp->can_bsr = value;
-               if ((options & MT_ST_NO_BLKLIMS) != 0)
-                       STp->omit_blklims = value;
-               if ((STp->device)->scsi_level >= SCSI_2 &&
-                   (options & MT_ST_CAN_PARTITIONS) != 0)
-                       STp->can_partitions = value;
-               if ((options & MT_ST_SCSI2LOGICAL) != 0)
-                       STp->scsi2_logical = value;
-               if ((options & MT_ST_SYSV) != 0)
-                       STm->sysv = value;
-#if DEBUG
-               if ((options & MT_ST_DEBUGGING) != 0)
-                       debugging = value;
-#endif
-               osst_log_options(STp, STm, name);
-       }
-       else if (code == MT_ST_WRITE_THRESHOLD) {
-               value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE;
-               if (value < 1 || value > osst_buffer_size) {
-                       printk(KERN_WARNING "%s:W: Write threshold %d too small or too large.\n",
-                                            name, value);
-                       return (-EIO);
-               }
-               STp->write_threshold = value;
-               printk(KERN_INFO "%s:I: Write threshold set to %d bytes.\n",
-                                 name, value);
-       }
-       else if (code == MT_ST_DEF_BLKSIZE) {
-               value = (options & ~MT_ST_OPTIONS);
-               if (value == ~MT_ST_OPTIONS) {
-                       STm->default_blksize = (-1);
-                       printk(KERN_INFO "%s:I: Default block size disabled.\n", name);
-               }
-               else {
-                       if (value < 512 || value > OS_DATA_SIZE || OS_DATA_SIZE % value) {
-                               printk(KERN_WARNING "%s:W: Default block size cannot be set to %d.\n",
-                                                        name, value);
-                               return (-EINVAL);
-                       }
-                       STm->default_blksize = value;
-                       printk(KERN_INFO "%s:I: Default block size set to %d bytes.\n",
-                                         name, STm->default_blksize);
-               }
-       }
-       else if (code == MT_ST_TIMEOUTS) {
-               value = (options & ~MT_ST_OPTIONS);
-               if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
-                       STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
-                       printk(KERN_INFO "%s:I: Long timeout set to %d seconds.\n", name,
-                                            (value & ~MT_ST_SET_LONG_TIMEOUT));
-               }
-               else {
-                       STp->timeout = value * HZ;
-                       printk(KERN_INFO "%s:I: Normal timeout set to %d seconds.\n", name, value);
-               }
-       }
-       else if (code == MT_ST_DEF_OPTIONS) {
-               code = (options & ~MT_ST_CLEAR_DEFAULT);
-               value = (options & MT_ST_CLEAR_DEFAULT);
-               if (code == MT_ST_DEF_DENSITY) {
-                       if (value == MT_ST_CLEAR_DEFAULT) {
-                               STm->default_density = (-1);
-                               printk(KERN_INFO "%s:I: Density default disabled.\n", name);
-                       }
-                       else {
-                               STm->default_density = value & 0xff;
-                               printk(KERN_INFO "%s:I: Density default set to %x\n",
-                                                 name, STm->default_density);
-                       }
-               }
-               else if (code == MT_ST_DEF_DRVBUFFER) {
-                       if (value == MT_ST_CLEAR_DEFAULT) {
-                               STp->default_drvbuffer = 0xff;
-                               printk(KERN_INFO "%s:I: Drive buffer default disabled.\n", name);
-                       }
-                       else {
-                               STp->default_drvbuffer = value & 7;
-                               printk(KERN_INFO "%s:I: Drive buffer default set to %x\n",
-                                                 name, STp->default_drvbuffer);
-                       }
-               }
-               else if (code == MT_ST_DEF_COMPRESSION) {
-                       if (value == MT_ST_CLEAR_DEFAULT) {
-                               STm->default_compression = ST_DONT_TOUCH;
-                               printk(KERN_INFO "%s:I: Compression default disabled.\n", name);
-                       }
-                       else {
-                               STm->default_compression = (value & 1 ? ST_YES : ST_NO);
-                               printk(KERN_INFO "%s:I: Compression default set to %x\n",
-                                                 name, (value & 1));
-                       }
-               }
-       }
-       else
-               return (-EIO);
-
-       return 0;
-}
-
-
-/* Internal ioctl function */
-static int osst_int_ioctl(struct osst_tape * STp, struct osst_request ** aSRpnt,
-                            unsigned int cmd_in, unsigned long arg)
-{
-       int                     timeout;
-       long                    ltmp;
-       int                     i, ioctl_result;
-       int                     chg_eof = 1;
-       unsigned char           cmd[MAX_COMMAND_SIZE];
-       struct osst_request   * SRpnt = * aSRpnt;
-       struct st_partstat    * STps;
-       int                     fileno, blkno, at_sm, frame_seq_numbr, logical_blk_num;
-       int                     datalen = 0, direction = DMA_NONE;
-       char                  * name = tape_name(STp);
-
-       if (STp->ready != ST_READY && cmd_in != MTLOAD) {
-               if (STp->ready == ST_NO_TAPE)
-                       return (-ENOMEDIUM);
-               else
-                       return (-EIO);
-       }
-       timeout = STp->long_timeout;
-       STps = &(STp->ps[STp->partition]);
-       fileno = STps->drv_file;
-       blkno = STps->drv_block;
-       at_sm = STps->at_sm;
-       frame_seq_numbr = STp->frame_seq_number;
-       logical_blk_num = STp->logical_blk_num;
-
-       memset(cmd, 0, MAX_COMMAND_SIZE);
-       switch (cmd_in) {
-        case MTFSFM:
-               chg_eof = 0; /* Changed from the FSF after this */
-               /* fall through */
-        case MTFSF:
-               if (STp->raw)
-                  return (-EIO);
-               if (STp->linux_media)
-                  ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SRpnt, cmd_in, arg);
-               else
-                  ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SRpnt, cmd_in, arg);
-               if (fileno >= 0)
-                  fileno += arg;
-               blkno = 0;
-               at_sm &= (arg == 0);
-               goto os_bypass;
-
-        case MTBSF:
-               chg_eof = 0; /* Changed from the FSF after this */
-               /* fall through */
-        case MTBSFM:
-               if (STp->raw)
-                  return (-EIO);
-               ioctl_result = osst_space_over_filemarks_backward(STp, &SRpnt, cmd_in, arg);
-               if (fileno >= 0)
-                  fileno -= arg;
-               blkno = (-1);  /* We can't know the block number */
-               at_sm &= (arg == 0);
-               goto os_bypass;
-
-        case MTFSR:
-        case MTBSR:
-#if DEBUG
-               if (debugging)
-                  printk(OSST_DEB_MSG "%s:D: Skipping %lu blocks %s from logical block %d\n",
-                               name, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num);
-#endif
-               if (cmd_in == MTFSR) {
-                  logical_blk_num += arg;
-                  if (blkno >= 0) blkno += arg;
-               }
-               else {
-                  logical_blk_num -= arg;
-                  if (blkno >= 0) blkno -= arg;
-               }
-               ioctl_result = osst_seek_logical_blk(STp, &SRpnt, logical_blk_num);
-               fileno = STps->drv_file;
-               blkno  = STps->drv_block;
-               at_sm &= (arg == 0);
-               goto os_bypass;
-
-        case MTFSS:
-               cmd[0] = SPACE;
-               cmd[1] = 0x04; /* Space Setmarks */   /* FIXME -- OS can't do this? */
-               cmd[2] = (arg >> 16);
-               cmd[3] = (arg >> 8);
-               cmd[4] = arg;
-#if DEBUG
-               if (debugging)
-                       printk(OSST_DEB_MSG "%s:D: Spacing tape forward %d setmarks.\n", name,
-               cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-#endif
-               if (arg != 0) {
-                       blkno = fileno = (-1);
-                       at_sm = 1;
-               }
-               break;
-        case MTBSS:
-               cmd[0] = SPACE;
-               cmd[1] = 0x04; /* Space Setmarks */   /* FIXME -- OS can't do this? */
-               ltmp = (-arg);
-               cmd[2] = (ltmp >> 16);
-               cmd[3] = (ltmp >> 8);
-               cmd[4] = ltmp;
-#if DEBUG
-               if (debugging) {
-                       if (cmd[2] & 0x80)
-                          ltmp = 0xff000000;
-                       ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
-                       printk(OSST_DEB_MSG "%s:D: Spacing tape backward %ld setmarks.\n",
-                                               name, (-ltmp));
-                }
-#endif
-                if (arg != 0) {
-                       blkno = fileno = (-1);
-                       at_sm = 1;
-                }
-                break;
-        case MTWEOF:
-                if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
-                       STp->write_type = OS_WRITE_DATA;
-                       ioctl_result = osst_flush_write_buffer(STp, &SRpnt);
-                } else
-                       ioctl_result = 0;
-#if DEBUG
-                if (debugging) 
-                          printk(OSST_DEB_MSG "%s:D: Writing %ld filemark(s).\n", name, arg);
-#endif
-                for (i=0; i<arg; i++)
-                       ioctl_result |= osst_write_filemark(STp, &SRpnt);
-                if (fileno >= 0) fileno += arg;
-                if (blkno  >= 0) blkno   = 0;
-                goto os_bypass;
-
-        case MTWSM:
-                if (STp->write_prot)
-                       return (-EACCES);
-                if (!STp->raw)
-                       return 0;
-                cmd[0] = WRITE_FILEMARKS;   /* FIXME -- need OS version */
-                if (cmd_in == MTWSM)
-                        cmd[1] = 2;
-                cmd[2] = (arg >> 16);
-                cmd[3] = (arg >> 8);
-                cmd[4] = arg;
-                timeout = STp->timeout;
-#if DEBUG
-                if (debugging) 
-                          printk(OSST_DEB_MSG "%s:D: Writing %d setmark(s).\n", name,
-                                 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-#endif
-                if (fileno >= 0)
-                       fileno += arg;
-                blkno = 0;
-                at_sm = (cmd_in == MTWSM);
-                break;
-        case MTOFFL:
-        case MTLOAD:
-        case MTUNLOAD:
-        case MTRETEN:
-                cmd[0] = START_STOP;
-                cmd[1] = 1;                    /* Don't wait for completion */
-                if (cmd_in == MTLOAD) {
-                    if (STp->ready == ST_NO_TAPE)
-                        cmd[4] = 4;            /* open tray */
-                     else
-                        cmd[4] = 1;            /* load */
-                }
-                if (cmd_in == MTRETEN)
-                        cmd[4] = 3;            /* retension then mount */
-                if (cmd_in == MTOFFL)
-                        cmd[4] = 4;            /* rewind then eject */
-                timeout = STp->timeout;
-#if DEBUG
-                if (debugging) {
-                        switch (cmd_in) {
-                                case MTUNLOAD:
-                                        printk(OSST_DEB_MSG "%s:D: Unloading tape.\n", name);
-                                        break;
-                                case MTLOAD:
-                                        printk(OSST_DEB_MSG "%s:D: Loading tape.\n", name);
-                                        break;
-                                case MTRETEN:
-                                        printk(OSST_DEB_MSG "%s:D: Retensioning tape.\n", name);
-                                        break;
-                                case MTOFFL:
-                                        printk(OSST_DEB_MSG "%s:D: Ejecting tape.\n", name);
-                                        break;
-                        }
-                }
-#endif
-       fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
-                break;
-        case MTNOP:
-#if DEBUG
-                if (debugging)
-                        printk(OSST_DEB_MSG "%s:D: No-op on tape.\n", name);
-#endif
-                return 0;  /* Should do something ? */
-                break;
-        case MTEOM:
-#if DEBUG
-               if (debugging)
-                  printk(OSST_DEB_MSG "%s:D: Spacing to end of recorded medium.\n", name);
-#endif
-               if ((osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) ||
-                           (osst_get_logical_frame(STp, &SRpnt, -1, 0)               < 0)) {
-                  ioctl_result = -EIO;
-                  goto os_bypass;
-               }
-               if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) {
-#if DEBUG
-                  printk(OSST_DEB_MSG "%s:D: No EOD frame found where expected.\n", name);
-#endif
-                  ioctl_result = -EIO;
-                  goto os_bypass;
-               }
-               ioctl_result = osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0);
-               fileno = STp->filemark_cnt;
-               blkno  = at_sm = 0;
-               goto os_bypass;
-
-        case MTERASE:
-               if (STp->write_prot)
-                  return (-EACCES);
-               ioctl_result = osst_reset_header(STp, &SRpnt);
-               i = osst_write_eod(STp, &SRpnt);
-               if (i < ioctl_result) ioctl_result = i;
-               i = osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos);
-               if (i < ioctl_result) ioctl_result = i;
-               fileno = blkno = at_sm = 0 ;
-               goto os_bypass;
-
-        case MTREW:
-               cmd[0] = REZERO_UNIT; /* rewind */
-               cmd[1] = 1;
-#if DEBUG
-               if (debugging)
-                  printk(OSST_DEB_MSG "%s:D: Rewinding tape, Immed=%d.\n", name, cmd[1]);
-#endif
-               fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
-               break;
-
-        case MTSETBLK:           /* Set block length */
-                if ((STps->drv_block == 0 )                      &&
-                    !STp->dirty                                  &&
-                    ((STp->buffer)->buffer_bytes == 0)           &&
-                    ((arg & MT_ST_BLKSIZE_MASK) >= 512 )         && 
-                    ((arg & MT_ST_BLKSIZE_MASK) <= OS_DATA_SIZE) &&
-                    !(OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK))  ) {
-                        /*
-                         * Only allowed to change the block size if you opened the
-                         * device at the beginning of a file before writing anything.
-                         * Note, that when reading, changing block_size is futile,
-                         * as the size used when writing overrides it.
-                         */
-                        STp->block_size = (arg & MT_ST_BLKSIZE_MASK);
-                        printk(KERN_INFO "%s:I: Block size set to %d bytes.\n",
-                                          name, STp->block_size);
-                        return 0;
-                }
-               /* fall through */
-        case MTSETDENSITY:       /* Set tape density */
-        case MTSETDRVBUFFER:     /* Set drive buffering */
-        case SET_DENS_AND_BLK:   /* Set density and block size */
-                chg_eof = 0;
-                if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
-                        return (-EIO);       /* Not allowed if data in buffer */
-                if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
-                    (arg & MT_ST_BLKSIZE_MASK) != 0                    &&
-                    (arg & MT_ST_BLKSIZE_MASK) != STp->block_size       ) {
-                        printk(KERN_WARNING "%s:W: Illegal to set block size to %d%s.\n",
-                                               name, (int)(arg & MT_ST_BLKSIZE_MASK),
-                                               (OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK))?"":" now");
-                        return (-EINVAL);
-                }
-                return 0;  /* FIXME silently ignore if block size didn't change */
-
-        default:
-               return (-ENOSYS);
-       }
-
-       SRpnt = osst_do_scsi(SRpnt, STp, cmd, datalen, direction, timeout, MAX_RETRIES, 1);
-
-       ioctl_result = (STp->buffer)->syscall_result;
-
-       if (!SRpnt) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Couldn't exec scsi cmd for IOCTL\n", name);
-#endif
-               return ioctl_result;
-       }
-
-       if (!ioctl_result) {  /* SCSI command successful */
-               STp->frame_seq_number = frame_seq_numbr;
-               STp->logical_blk_num  = logical_blk_num;
-       }
-
-os_bypass:
-#if DEBUG
-       if (debugging)
-               printk(OSST_DEB_MSG "%s:D: IOCTL (%d) Result=%d\n", name, cmd_in, ioctl_result);
-#endif
-
-       if (!ioctl_result) {                            /* success */
-
-               if (cmd_in == MTFSFM) {
-                        fileno--;
-                        blkno--;
-               }
-               if (cmd_in == MTBSFM) {
-                        fileno++;
-                        blkno++;
-               }
-               STps->drv_block = blkno;
-               STps->drv_file = fileno;
-               STps->at_sm = at_sm;
-
-               if (cmd_in == MTEOM)
-                       STps->eof = ST_EOD;
-               else if ((cmd_in == MTFSFM || cmd_in == MTBSF) && STps->eof == ST_FM_HIT) {
-                       ioctl_result = osst_seek_logical_blk(STp, &SRpnt, STp->logical_blk_num-1);
-                       STps->drv_block++;
-                       STp->logical_blk_num++;
-                       STp->frame_seq_number++;
-                       STp->frame_in_buffer = 0;
-                       STp->buffer->read_pointer = 0;
-               }
-               else if (cmd_in == MTFSF)
-                       STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
-               else if (chg_eof)
-                       STps->eof = ST_NOEOF;
-
-               if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
-                       STp->rew_at_close = 0;
-               else if (cmd_in == MTLOAD) {
-                       for (i=0; i < ST_NBR_PARTITIONS; i++) {
-                           STp->ps[i].rw = ST_IDLE;
-                           STp->ps[i].last_block_valid = 0;/* FIXME - where else is this field maintained? */
-                       }
-                       STp->partition = 0;
-               }
-
-               if (cmd_in == MTREW) {
-                       ioctl_result = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos); 
-                       if (ioctl_result > 0)
-                               ioctl_result = 0;
-               }
-
-       } else if (cmd_in == MTBSF || cmd_in == MTBSFM ) {
-               if (osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos) < 0)
-                       STps->drv_file = STps->drv_block = -1;
-               else
-                       STps->drv_file = STps->drv_block = 0;
-               STps->eof = ST_NOEOF;
-       } else if (cmd_in == MTFSF || cmd_in == MTFSFM) {
-               if (osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0)
-                       STps->drv_file = STps->drv_block = -1;
-               else {
-                       STps->drv_file  = STp->filemark_cnt;
-                       STps->drv_block = 0;
-               }
-               STps->eof = ST_EOD;
-       } else if (cmd_in == MTBSR || cmd_in == MTFSR || cmd_in == MTWEOF || cmd_in == MTEOM) {
-               STps->drv_file = STps->drv_block = (-1);
-               STps->eof = ST_NOEOF;
-               STp->header_ok = 0;
-       } else if (cmd_in == MTERASE) {
-               STp->header_ok = 0;
-       } else if (SRpnt) {  /* SCSI command was not completely successful. */
-               if (SRpnt->sense[2] & 0x40) {
-                       STps->eof = ST_EOM_OK;
-                       STps->drv_block = 0;
-               }
-               if (chg_eof)
-                       STps->eof = ST_NOEOF;
-
-               if ((SRpnt->sense[2] & 0x0f) == BLANK_CHECK)
-                       STps->eof = ST_EOD;
-
-               if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60))
-                       ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
-       }
-       *aSRpnt = SRpnt;
-
-       return ioctl_result;
-}
-
-
-/* Open the device */
-static int __os_scsi_tape_open(struct inode * inode, struct file * filp)
-{
-       unsigned short        flags;
-       int                   i, b_size, new_session = 0, retval = 0;
-       unsigned char         cmd[MAX_COMMAND_SIZE];
-       struct osst_request * SRpnt = NULL;
-       struct osst_tape    * STp;
-       struct st_modedef   * STm;
-       struct st_partstat  * STps;
-       char                * name;
-       int                   dev  = TAPE_NR(inode);
-       int                   mode = TAPE_MODE(inode);
-
-       /*
-        * We really want to do nonseekable_open(inode, filp); here, but some
-        * versions of tar incorrectly call lseek on tapes and bail out if that
-        * fails.  So we disallow pread() and pwrite(), but permit lseeks.
-        */
-       filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
-
-       write_lock(&os_scsi_tapes_lock);
-       if (dev >= osst_max_dev || os_scsi_tapes == NULL ||
-           (STp = os_scsi_tapes[dev]) == NULL || !STp->device) {
-               write_unlock(&os_scsi_tapes_lock);
-               return (-ENXIO);
-       }
-
-       name = tape_name(STp);
-
-       if (STp->in_use) {
-               write_unlock(&os_scsi_tapes_lock);
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Device already in use.\n", name);
-#endif
-               return (-EBUSY);
-       }
-       if (scsi_device_get(STp->device)) {
-               write_unlock(&os_scsi_tapes_lock);
-#if DEBUG
-                printk(OSST_DEB_MSG "%s:D: Failed scsi_device_get.\n", name);
-#endif
-               return (-ENXIO);
-       }
-       filp->private_data = STp;
-       STp->in_use = 1;
-       write_unlock(&os_scsi_tapes_lock);
-       STp->rew_at_close = TAPE_REWIND(inode);
-
-       if( !scsi_block_when_processing_errors(STp->device) ) {
-               return -ENXIO;
-       }
-
-       if (mode != STp->current_mode) {
-#if DEBUG
-               if (debugging)
-                       printk(OSST_DEB_MSG "%s:D: Mode change from %d to %d.\n",
-                                              name, STp->current_mode, mode);
-#endif
-               new_session = 1;
-               STp->current_mode = mode;
-       }
-       STm = &(STp->modes[STp->current_mode]);
-
-       flags = filp->f_flags;
-       STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
-
-       STp->raw = TAPE_IS_RAW(inode);
-       if (STp->raw)
-               STp->header_ok = 0;
-
-       /* Allocate data segments for this device's tape buffer */
-       if (!enlarge_buffer(STp->buffer, STp->restr_dma)) {
-               printk(KERN_ERR "%s:E: Unable to allocate memory segments for tape buffer.\n", name);
-               retval = (-EOVERFLOW);
-               goto err_out;
-       }
-       if (STp->buffer->buffer_size >= OS_FRAME_SIZE) {
-               for (i = 0, b_size = 0; 
-                    (i < STp->buffer->sg_segs) && ((b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE); 
-                    b_size += STp->buffer->sg[i++].length);
-               STp->buffer->aux = (os_aux_t *) (page_address(sg_page(&STp->buffer->sg[i])) + OS_DATA_SIZE - b_size);
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: b_data points to %p in segment 0 at %p\n", name,
-                       STp->buffer->b_data, page_address(STp->buffer->sg[0].page));
-               printk(OSST_DEB_MSG "%s:D: AUX points to %p in segment %d at %p\n", name,
-                        STp->buffer->aux, i, page_address(STp->buffer->sg[i].page));
-#endif
-       } else {
-               STp->buffer->aux = NULL; /* this had better never happen! */
-               printk(KERN_NOTICE "%s:A: Framesize %d too large for buffer.\n", name, OS_FRAME_SIZE);
-               retval = (-EIO);
-               goto err_out;
-       }
-       STp->buffer->writing = 0;
-       STp->buffer->syscall_result = 0;
-       STp->dirty = 0;
-       for (i=0; i < ST_NBR_PARTITIONS; i++) {
-               STps = &(STp->ps[i]);
-               STps->rw = ST_IDLE;
-       }
-       STp->ready = ST_READY;
-#if DEBUG
-       STp->nbr_waits = STp->nbr_finished = 0;
-#endif
-
-       memset (cmd, 0, MAX_COMMAND_SIZE);
-       cmd[0] = TEST_UNIT_READY;
-
-       SRpnt = osst_do_scsi(NULL, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
-       if (!SRpnt) {
-               retval = (STp->buffer)->syscall_result;         /* FIXME - valid? */
-               goto err_out;
-       }
-       if ((SRpnt->sense[0] & 0x70) == 0x70      &&
-           (SRpnt->sense[2] & 0x0f) == NOT_READY &&
-            SRpnt->sense[12]        == 4         ) {
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Unit not ready, cause %x\n", name, SRpnt->sense[13]);
-#endif
-               if (filp->f_flags & O_NONBLOCK) {
-                       retval = -EAGAIN;
-                       goto err_out;
-               }
-               if (SRpnt->sense[13] == 2) {    /* initialize command required (LOAD) */
-                       memset (cmd, 0, MAX_COMMAND_SIZE);
-                       cmd[0] = START_STOP;
-                       cmd[1] = 1;
-                       cmd[4] = 1;
-                       SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
-                                            STp->timeout, MAX_RETRIES, 1);
-               }
-               osst_wait_ready(STp, &SRpnt, (SRpnt->sense[13]==1?15:3) * 60, 0);
-       }
-       if ((SRpnt->sense[0] & 0x70) == 0x70 &&
-           (SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Unit wants attention\n", name);
-#endif
-               STp->header_ok = 0;
-
-               for (i=0; i < 10; i++) {
-
-                       memset (cmd, 0, MAX_COMMAND_SIZE);
-                       cmd[0] = TEST_UNIT_READY;
-
-                       SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
-                                            STp->timeout, MAX_RETRIES, 1);
-                       if ((SRpnt->sense[0] & 0x70) != 0x70 ||
-                           (SRpnt->sense[2] & 0x0f) != UNIT_ATTENTION)
-                               break;
-               }
-
-               STp->pos_unknown = 0;
-               STp->partition = STp->new_partition = 0;
-               if (STp->can_partitions)
-                       STp->nbr_partitions = 1;  /* This guess will be updated later if necessary */
-               for (i=0; i < ST_NBR_PARTITIONS; i++) {
-                       STps = &(STp->ps[i]);
-                       STps->rw = ST_IDLE;             /* FIXME - seems to be redundant... */
-                       STps->eof = ST_NOEOF;
-                       STps->at_sm = 0;
-                       STps->last_block_valid = 0;
-                       STps->drv_block = 0;
-                       STps->drv_file = 0 ;
-               }
-               new_session = 1;
-               STp->recover_count = 0;
-               STp->abort_count = 0;
-       }
-       /*
-        * if we have valid headers from before, and the drive/tape seem untouched,
-        * open without reconfiguring and re-reading the headers
-        */
-       if (!STp->buffer->syscall_result && STp->header_ok &&
-           !SRpnt->result && SRpnt->sense[0] == 0) {
-
-               memset(cmd, 0, MAX_COMMAND_SIZE);
-               cmd[0] = MODE_SENSE;
-               cmd[1] = 8;
-               cmd[2] = VENDOR_IDENT_PAGE;
-               cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
-               SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
-
-               if (STp->buffer->syscall_result                     ||
-                   STp->buffer->b_data[MODE_HEADER_LENGTH + 2] != 'L' ||
-                   STp->buffer->b_data[MODE_HEADER_LENGTH + 3] != 'I' ||
-                   STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' ||
-                   STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4'  ) {
-#if DEBUG
-                       printk(OSST_DEB_MSG "%s:D: Signature was changed to %c%c%c%c\n", name,
-                         STp->buffer->b_data[MODE_HEADER_LENGTH + 2],
-                         STp->buffer->b_data[MODE_HEADER_LENGTH + 3],
-                         STp->buffer->b_data[MODE_HEADER_LENGTH + 4],
-                         STp->buffer->b_data[MODE_HEADER_LENGTH + 5]);
-#endif
-                       STp->header_ok = 0;
-               }
-               i = STp->first_frame_position;
-               if (STp->header_ok && i == osst_get_frame_position(STp, &SRpnt)) {
-                       if (STp->door_locked == ST_UNLOCKED) {
-                               if (do_door_lock(STp, 1))
-                                       printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
-                               else
-                                       STp->door_locked = ST_LOCKED_AUTO;
-                       }
-                       if (!STp->frame_in_buffer) {
-                               STp->block_size = (STm->default_blksize > 0) ?
-                                                       STm->default_blksize : OS_DATA_SIZE;
-                               STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
-                       }
-                       STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
-                       STp->fast_open = 1;
-                       osst_release_request(SRpnt);
-                       return 0;
-               }
-#if DEBUG
-               if (i != STp->first_frame_position)
-                       printk(OSST_DEB_MSG "%s:D: Tape position changed from %d to %d\n",
-                                               name, i, STp->first_frame_position);
-#endif
-               STp->header_ok = 0;
-       }
-       STp->fast_open = 0;
-
-       if ((STp->buffer)->syscall_result != 0 &&   /* in all error conditions except no medium */ 
-           (SRpnt->sense[2] != 2 || SRpnt->sense[12] != 0x3A) ) {
-
-               memset(cmd, 0, MAX_COMMAND_SIZE);
-               cmd[0] = MODE_SELECT;
-               cmd[1] = 0x10;
-               cmd[4] = 4 + MODE_HEADER_LENGTH;
-
-               (STp->buffer)->b_data[0] = cmd[4] - 1;
-               (STp->buffer)->b_data[1] = 0;                   /* Medium Type - ignoring */
-               (STp->buffer)->b_data[2] = 0;                   /* Reserved */
-               (STp->buffer)->b_data[3] = 0;                   /* Block Descriptor Length */
-               (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = 0x3f;
-               (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 1;
-               (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 2;
-               (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3;
-
-#if DEBUG
-               printk(OSST_DEB_MSG "%s:D: Applying soft reset\n", name);
-#endif
-               SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
-
-               STp->header_ok = 0;
-
-               for (i=0; i < 10; i++) {
-
-                       memset (cmd, 0, MAX_COMMAND_SIZE);
-                       cmd[0] = TEST_UNIT_READY;
-
-                       SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
-                                                   STp->timeout, MAX_RETRIES, 1);
-                       if ((SRpnt->sense[0] & 0x70) != 0x70 ||
-                           (SRpnt->sense[2] & 0x0f) == NOT_READY)
-                       break;
-
-                       if ((SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) {
-                               int j;
-
-                               STp->pos_unknown = 0;
-                               STp->partition = STp->new_partition = 0;
-                               if (STp->can_partitions)
-                                       STp->nbr_partitions = 1;  /* This guess will be updated later if necessary */
-                               for (j = 0; j < ST_NBR_PARTITIONS; j++) {
-                                       STps = &(STp->ps[j]);
-                                       STps->rw = ST_IDLE;
-                                       STps->eof = ST_NOEOF;
-                                       STps->at_sm = 0;
-                                       STps->last_block_valid = 0;
-                                       STps->drv_block = 0;
-                                       STps->drv_file = 0 ;
-                               }
-                               new_session = 1;
-                       }
-               }
-       }
-
-       if (osst_wait_ready(STp, &SRpnt, 15 * 60, 0))           /* FIXME - not allowed with NOBLOCK */
-                printk(KERN_INFO "%s:I: Device did not become Ready in open\n", name);
-
-       if ((STp->buffer)->syscall_result != 0) {
-               if ((STp->device)->scsi_level >= SCSI_2 &&
-                   (SRpnt->sense[0] & 0x70) == 0x70 &&
-                   (SRpnt->sense[2] & 0x0f) == NOT_READY &&
-                    SRpnt->sense[12] == 0x3a) { /* Check ASC */
-                       STp->ready = ST_NO_TAPE;
-               } else
-                       STp->ready = ST_NOT_READY;
-               osst_release_request(SRpnt);
-               SRpnt = NULL;
-               STp->density = 0;       /* Clear the erroneous "residue" */
-               STp->write_prot = 0;
-               STp->block_size = 0;
-               STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
-               STp->partition = STp->new_partition = 0;
-               STp->door_locked = ST_UNLOCKED;
-               return 0;
-       }
-
-       osst_configure_onstream(STp, &SRpnt);
-
-       STp->block_size = STp->raw ? OS_FRAME_SIZE : (
-                            (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
-       STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size;
-       STp->buffer->buffer_bytes  =
-       STp->buffer->read_pointer  =
-       STp->frame_in_buffer       = 0;
-
-#if DEBUG
-       if (debugging)
-               printk(OSST_DEB_MSG "%s:D: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n",
-                    name, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size,
-                    (STp->buffer)->buffer_blocks);
-#endif
-
-       if (STp->drv_write_prot) {
-               STp->write_prot = 1;
-#if DEBUG
-               if (debugging)
-                       printk(OSST_DEB_MSG "%s:D: Write protected\n", name);
-#endif
-               if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
-                       retval = (-EROFS);
-                       goto err_out;
-               }
-       }
-
-       if (new_session) {  /* Change the drive parameters for the new mode */
-#if DEBUG
-               if (debugging)
-       printk(OSST_DEB_MSG "%s:D: New Session\n", name);
-#endif
-               STp->density_changed = STp->blksize_changed = 0;
-               STp->compression_changed = 0;
-       }
-
-       /*
-        * properly position the tape and check the ADR headers
-        */
-       if (STp->door_locked == ST_UNLOCKED) {
-                if (do_door_lock(STp, 1))
-                       printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
-                else
-                       STp->door_locked = ST_LOCKED_AUTO;
-       }
-
-       osst_analyze_headers(STp, &SRpnt);
-
-       osst_release_request(SRpnt);
-       SRpnt = NULL;
-
-       return 0;
-
-err_out:
-       if (SRpnt != NULL)
-               osst_release_request(SRpnt);
-       normalize_buffer(STp->buffer);
-       STp->header_ok = 0;
-       STp->in_use = 0;
-       scsi_device_put(STp->device);
-
-       return retval;
-}
-
-/* BKL pushdown: spaghetti avoidance wrapper */
-static int os_scsi_tape_open(struct inode * inode, struct file * filp)
-{
-       int ret;
-
-       mutex_lock(&osst_int_mutex);
-       ret = __os_scsi_tape_open(inode, filp);
-       mutex_unlock(&osst_int_mutex);
-       return ret;
-}
-
-
-
-/* Flush the tape buffer before close */
-static int os_scsi_tape_flush(struct file * filp, fl_owner_t id)
-{
-       int                   result = 0, result2;
-       struct osst_tape    * STp    = filp->private_data;
-       struct st_modedef   * STm    = &(STp->modes[STp->current_mode]);
-       struct st_partstat  * STps   = &(STp->ps[STp->partition]);
-       struct osst_request * SRpnt  = NULL;
-       char                * name   = tape_name(STp);
-
-       if (file_count(filp) > 1)
-               return 0;
-
-       if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
-               STp->write_type = OS_WRITE_DATA;
-               result = osst_flush_write_buffer(STp, &SRpnt);
-               if (result != 0 && result != (-ENOSPC))
-                       goto out;
-       }
-       if ( STps->rw >= ST_WRITING && !STp->pos_unknown) {
-
-#if DEBUG
-               if (debugging) {
-                       printk(OSST_DEB_MSG "%s:D: File length %ld bytes.\n",
-                                              name, (long)(filp->f_pos));
-                       printk(OSST_DEB_MSG "%s:D: Async write waits %d, finished %d.\n",
-                                              name, STp->nbr_waits, STp->nbr_finished);
-               }
-#endif
-               result = osst_write_trailer(STp, &SRpnt, !(STp->rew_at_close));
-#if DEBUG
-               if (debugging)
-                       printk(OSST_DEB_MSG "%s:D: Buffer flushed, %d EOF(s) written\n",
-                                              name, 1+STp->two_fm);
-#endif
-       }
-       else if (!STp->rew_at_close) {
-               STps = &(STp->ps[STp->partition]);
-               if (!STm->sysv || STps->rw != ST_READING) {
-                       if (STp->can_bsr)
-                               result = osst_flush_buffer(STp, &SRpnt, 0); /* this is the default path */
-                       else if (STps->eof == ST_FM_HIT) {
-                               result = cross_eof(STp, &SRpnt, 0);
-                                       if (result) {
-                                               if (STps->drv_file >= 0)
-                                                       STps->drv_file++;
-                                               STps->drv_block = 0;
-                                               STps->eof = ST_FM;
-                                       }
-                                       else
-                                               STps->eof = ST_NOEOF;
-                       }
-               }
-               else if ((STps->eof == ST_NOEOF &&
-                         !(result = cross_eof(STp, &SRpnt, 1))) ||
-                        STps->eof == ST_FM_HIT) {
-                       if (STps->drv_file >= 0)
-                               STps->drv_file++;
-                       STps->drv_block = 0;
-                       STps->eof = ST_FM;
-               }
-       }
-
-out:
-       if (STp->rew_at_close) {
-               result2 = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
-               STps->drv_file = STps->drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
-               if (result == 0 && result2 < 0)
-                       result = result2;
-       }
-       if (SRpnt) osst_release_request(SRpnt);
-
-       if (STp->abort_count || STp->recover_count) {
-               printk(KERN_INFO "%s:I:", name);
-               if (STp->abort_count)
-                       printk(" %d unrecovered errors", STp->abort_count);
-               if (STp->recover_count)
-                       printk(" %d recovered errors", STp->recover_count);
-               if (STp->write_count)
-                       printk(" in %d frames written", STp->write_count);
-               if (STp->read_count)
-                       printk(" in %d frames read", STp->read_count);
-               printk("\n");
-               STp->recover_count = 0;
-               STp->abort_count   = 0;
-       }
-       STp->write_count = 0;
-       STp->read_count  = 0;
-
-       return result;
-}
-
-
-/* Close the device and release it */
-static int os_scsi_tape_close(struct inode * inode, struct file * filp)
-{
-       int                   result = 0;
-       struct osst_tape    * STp    = filp->private_data;
-
-       if (STp->door_locked == ST_LOCKED_AUTO)
-               do_door_lock(STp, 0);
-
-       if (STp->raw)
-               STp->header_ok = 0;
-       
-       normalize_buffer(STp->buffer);
-       write_lock(&os_scsi_tapes_lock);
-       STp->in_use = 0;
-       write_unlock(&os_scsi_tapes_lock);
-
-       scsi_device_put(STp->device);
-
-       return result;
-}
-
-
-/* The ioctl command */
-static long osst_ioctl(struct file * file,
-        unsigned int cmd_in, unsigned long arg)
-{
-       int                   i, cmd_nr, cmd_type, blk, retval = 0;
-       struct st_modedef   * STm;
-       struct st_partstat  * STps;
-       struct osst_request * SRpnt = NULL;
-       struct osst_tape    * STp   = file->private_data;
-       char                * name  = tape_name(STp);
-       void        __user  * p     = (void __user *)arg;
-
-       mutex_lock(&osst_int_mutex);
-       if (mutex_lock_interruptible(&STp->lock)) {
-               mutex_unlock(&osst_int_mutex);
-               return -ERESTARTSYS;
-       }
-
-#if DEBUG
-       if (debugging && !STp->in_use) {
-               printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
-               retval = (-EIO);
-               goto out;
-       }
-#endif
-       STm = &(STp->modes[STp->current_mode]);
-       STps = &(STp->ps[STp->partition]);
-
-       /*
-        * If we are in the middle of error recovery, don't let anyone
-        * else try and use this device.  Also, if error recovery fails, it
-        * may try and take the device offline, in which case all further
-        * access to the device is prohibited.
-        */
-       retval = scsi_ioctl_block_when_processing_errors(STp->device, cmd_in,
-                       file->f_flags & O_NDELAY);
-       if (retval)
-               goto out;
-
-       cmd_type = _IOC_TYPE(cmd_in);
-       cmd_nr   = _IOC_NR(cmd_in);
-#if DEBUG
-       printk(OSST_DEB_MSG "%s:D: Ioctl %d,%d in %s mode\n", name,
-                           cmd_type, cmd_nr, STp->raw?"raw":"normal");
-#endif
-       if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
-               struct mtop mtc;
-               int    auto_weof = 0;
-
-               if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
-                       retval = (-EINVAL);
-                       goto out;
-               }
-
-               i = copy_from_user((char *) &mtc, p, sizeof(struct mtop));
-               if (i) {
-                       retval = (-EFAULT);
-                       goto out;
-               }
-
-               if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
-                       printk(KERN_WARNING "%s:W: MTSETDRVBUFFER only allowed for root.\n", name);
-                       retval = (-EPERM);
-                       goto out;
-               }
-
-               if (!STm->defined && (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) {
-                       retval = (-ENXIO);
-                       goto out;
-               }
-
-               if (!STp->pos_unknown) {
-
-                       if (STps->eof == ST_FM_HIT) {
-                               if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) {
-                                       mtc.mt_count -= 1;
-                                       if (STps->drv_file >= 0)
-                                               STps->drv_file += 1;
-                               }
-                               else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) {
-                                       mtc.mt_count += 1;
-                                       if (STps->drv_file >= 0)
-                                               STps->drv_file += 1;
-                               }
-                       }
-
-                       if (mtc.mt_op == MTSEEK) {
-                               /* Old position must be restored if partition will be changed */
-                               i = !STp->can_partitions || (STp->new_partition != STp->partition);
-                       }
-                       else {
-                               i = mtc.mt_op == MTREW   || mtc.mt_op == MTOFFL ||
-                                   mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM  ||
-                                   mtc.mt_op == MTLOCK  || mtc.mt_op == MTLOAD ||
-                                   mtc.mt_op == MTFSF   || mtc.mt_op == MTFSFM ||
-                                   mtc.mt_op == MTBSF   || mtc.mt_op == MTBSFM ||
-                                   mtc.mt_op == MTCOMPRESSION;
-                       }
-                       i = osst_flush_buffer(STp, &SRpnt, i);
-                       if (i < 0) {
-                               retval = i;
-                               goto out;
-                       }
-               }
-               else {
-                       /*
-                        * If there was a bus reset, block further access
-                        * to this device.  If the user wants to rewind the tape,
-                        * then reset the flag and allow access again.
-                        */
-                       if(mtc.mt_op != MTREW   &&
-                          mtc.mt_op != MTOFFL  &&
-                          mtc.mt_op != MTRETEN &&
-                          mtc.mt_op != MTERASE &&
-                          mtc.mt_op != MTSEEK  &&
-                          mtc.mt_op != MTEOM)   {
-                               retval = (-EIO);
-                               goto out;
-                       }
-                       reset_state(STp);
-                       /* remove this when the midlevel properly clears was_reset */
-                       STp->device->was_reset = 0;
-               }
-
-               if (mtc.mt_op != MTCOMPRESSION  && mtc.mt_op != MTLOCK         &&
-                   mtc.mt_op != MTNOP          && mtc.mt_op != MTSETBLK       &&
-                   mtc.mt_op != MTSETDENSITY   && mtc.mt_op != MTSETDRVBUFFER && 
-                   mtc.mt_op != MTMKPART       && mtc.mt_op != MTSETPART      &&
-                   mtc.mt_op != MTWEOF         && mtc.mt_op != MTWSM           ) {
-
-                       /*
-                        * The user tells us to move to another position on the tape.
-                        * If we were appending to the tape content, that would leave
-                        * the tape without proper end, in that case write EOD and
-                        * update the header to reflect its position.
-                        */
-#if DEBUG
-                       printk(KERN_WARNING "%s:D: auto_weod %s at ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n", name,
-                                       STps->rw >= ST_WRITING ? "write" : STps->rw == ST_READING ? "read" : "idle",
-                                       STp->first_frame_position, STp->eod_frame_ppos, STp->frame_seq_number,
-                                       STp->logical_blk_num, STps->drv_file, STps->drv_block );
-#endif
-                       if (STps->rw >= ST_WRITING && STp->first_frame_position >= STp->eod_frame_ppos) {
-                               auto_weof = ((STp->write_type != OS_WRITE_NEW_MARK) &&
-                                                       !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
-                               i = osst_write_trailer(STp, &SRpnt,
-                                                       !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
-#if DEBUG
-                               printk(KERN_WARNING "%s:D: post trailer xeof=%d,ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n",
-                                               name, auto_weof, STp->first_frame_position, STp->eod_frame_ppos,
-                                               STp->frame_seq_number, STp->logical_blk_num, STps->drv_file, STps->drv_block );
-#endif
-                               if (i < 0) {
-                                       retval = i;
-                                       goto out;
-                               }
-                       }
-                       STps->rw = ST_IDLE;
-               }
-
-               if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
-                       do_door_lock(STp, 0);  /* Ignore result! */
-
-               if (mtc.mt_op == MTSETDRVBUFFER &&
-                  (mtc.mt_count & MT_ST_OPTIONS) != 0) {
-                       retval = osst_set_options(STp, mtc.mt_count);
-                       goto out;
-               }
-
-               if (mtc.mt_op == MTSETPART) {
-                       if (mtc.mt_count >= STp->nbr_partitions)
-                               retval = -EINVAL;
-                       else {
-                               STp->new_partition = mtc.mt_count;
-                               retval = 0;
-                       }
-                       goto out;
-               }
-
-               if (mtc.mt_op == MTMKPART) {
-                       if (!STp->can_partitions) {
-                               retval = (-EINVAL);
-                               goto out;
-                       }
-                       if ((i = osst_int_ioctl(STp, &SRpnt, MTREW, 0)) < 0 /*||
-                           (i = partition_tape(inode, mtc.mt_count)) < 0*/) {
-                               retval = i;
-                               goto out;
-                       }
-                       for (i=0; i < ST_NBR_PARTITIONS; i++) {
-                               STp->ps[i].rw = ST_IDLE;
-                               STp->ps[i].at_sm = 0;
-                               STp->ps[i].last_block_valid = 0;
-                       }
-                       STp->partition = STp->new_partition = 0;
-                       STp->nbr_partitions = 1;  /* Bad guess ?-) */
-                       STps->drv_block = STps->drv_file = 0;
-                       retval = 0;
-                       goto out;
-               }
-
-               if (mtc.mt_op == MTSEEK) {
-                       if (STp->raw)
-                               i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0);
-                       else
-                               i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
-                       if (!STp->can_partitions)
-                               STp->ps[0].rw = ST_IDLE;
-                       retval = i;
-                       goto out;
-               }
-               if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) {
-                       retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));
-                       goto out;
-               }
-
-               if (auto_weof)
-                       cross_eof(STp, &SRpnt, 0);
-
-               if (mtc.mt_op == MTCOMPRESSION)
-                       retval = -EINVAL;       /* OnStream drives don't have compression hardware */
-               else
-                       /* MTBSF MTBSFM MTBSR MTBSS MTEOM MTERASE MTFSF MTFSFB MTFSR MTFSS
-                        * MTLOAD MTOFFL MTRESET MTRETEN MTREW MTUNLOAD MTWEOF MTWSM */
-                       retval = osst_int_ioctl(STp, &SRpnt, mtc.mt_op, mtc.mt_count);
-               goto out;
-       }
-
-       if (!STm->defined) {
-               retval = (-ENXIO);
-               goto out;
-       }
-
-       if ((i = osst_flush_buffer(STp, &SRpnt, 0)) < 0) {
-               retval = i;
-               goto out;
-       }
-
-       if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
-               struct mtget mt_status;
-
-               if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) {
-                        retval = (-EINVAL);
-                        goto out;
-               }
-
-               mt_status.mt_type = MT_ISONSTREAM_SC;
-               mt_status.mt_erreg = STp->recover_erreg << MT_ST_SOFTERR_SHIFT;
-               mt_status.mt_dsreg =
-                       ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
-                       ((STp->density    << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
-               mt_status.mt_blkno = STps->drv_block;
-               mt_status.mt_fileno = STps->drv_file;
-               if (STp->block_size != 0) {
-                       if (STps->rw == ST_WRITING)
-                               mt_status.mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size;
-                       else if (STps->rw == ST_READING)
-                               mt_status.mt_blkno -= ((STp->buffer)->buffer_bytes +
-                                                       STp->block_size - 1) / STp->block_size;
-               }
-
-               mt_status.mt_gstat = 0;
-               if (STp->drv_write_prot)
-                       mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff);
-               if (mt_status.mt_blkno == 0) {
-                       if (mt_status.mt_fileno == 0)
-                               mt_status.mt_gstat |= GMT_BOT(0xffffffff);
-                       else
-                               mt_status.mt_gstat |= GMT_EOF(0xffffffff);
-               }
-               mt_status.mt_resid = STp->partition;
-               if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
-                       mt_status.mt_gstat |= GMT_EOT(0xffffffff);
-               else if (STps->eof >= ST_EOM_OK)
-                       mt_status.mt_gstat |= GMT_EOD(0xffffffff);
-               if (STp->density == 1)
-                       mt_status.mt_gstat |= GMT_D_800(0xffffffff);
-               else if (STp->density == 2)
-                       mt_status.mt_gstat |= GMT_D_1600(0xffffffff);
-               else if (STp->density == 3)
-                       mt_status.mt_gstat |= GMT_D_6250(0xffffffff);
-               if (STp->ready == ST_READY)
-                       mt_status.mt_gstat |= GMT_ONLINE(0xffffffff);
-               if (STp->ready == ST_NO_TAPE)
-                       mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff);
-               if (STps->at_sm)
-                       mt_status.mt_gstat |= GMT_SM(0xffffffff);
-               if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) ||
-                   STp->drv_buffer != 0)
-                       mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
-
-               i = copy_to_user(p, &mt_status, sizeof(struct mtget));
-               if (i) {
-                       retval = (-EFAULT);
-                       goto out;
-               }
-
-               STp->recover_erreg = 0;  /* Clear after read */
-               retval = 0;
-               goto out;
-       } /* End of MTIOCGET */
-
-       if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
-               struct mtpos mt_pos;
-
-               if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) {
-                       retval = (-EINVAL);
-                       goto out;
-               }
-               if (STp->raw)
-                       blk = osst_get_frame_position(STp, &SRpnt);
-               else
-                       blk = osst_get_sector(STp, &SRpnt);
-               if (blk < 0) {
-                       retval = blk;
-                       goto out;
-               }
-               mt_pos.mt_blkno = blk;
-               i = copy_to_user(p, &mt_pos, sizeof(struct mtpos));
-               if (i)
-                       retval = -EFAULT;
-               goto out;
-       }
-       if (SRpnt) osst_release_request(SRpnt);
-
-       mutex_unlock(&STp->lock);
-
-       retval = scsi_ioctl(STp->device, cmd_in, p);
-       mutex_unlock(&osst_int_mutex);
-       return retval;
-
-out:
-       if (SRpnt) osst_release_request(SRpnt);
-
-       mutex_unlock(&STp->lock);
-       mutex_unlock(&osst_int_mutex);
-
-       return retval;
-}
-
-#ifdef CONFIG_COMPAT
-static long osst_compat_ioctl(struct file * file, unsigned int cmd_in, unsigned long arg)
-{
-       struct osst_tape *STp = file->private_data;
-       struct scsi_device *sdev = STp->device;
-       int ret = -ENOIOCTLCMD;
-       if (sdev->host->hostt->compat_ioctl) {
-
-               ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
-
-       }
-       return ret;
-}
-#endif
-
-
-\f
-/* Memory handling routines */
-
-/* Try to allocate a new tape buffer skeleton. Caller must not hold os_scsi_tapes_lock */
-static struct osst_buffer * new_tape_buffer( int from_initialization, int need_dma, int max_sg )
-{
-       int i;
-       gfp_t priority;
-       struct osst_buffer *tb;
-
-       if (from_initialization)
-               priority = GFP_ATOMIC;
-       else
-               priority = GFP_KERNEL;
-
-       i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist);
-       tb = kzalloc(i, priority);
-       if (!tb) {
-               printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n");
-               return NULL;
-       }
-
-       tb->sg_segs = tb->orig_sg_segs = 0;
-       tb->use_sg = max_sg;
-       tb->in_use = 1;
-       tb->dma = need_dma;
-       tb->buffer_size = 0;
-#if DEBUG
-       if (debugging) 
-               printk(OSST_DEB_MSG
-                       "osst :D: Allocated tape buffer skeleton (%d bytes, %d segments, dma: %d).\n",
-                          i, max_sg, need_dma);
-#endif
-       return tb;
-}
-
-/* Try to allocate a temporary (while a user has the device open) enlarged tape buffer */
-static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma)
-{
-       int segs, nbr, max_segs, b_size, order, got;
-       gfp_t priority;
-
-       if (STbuffer->buffer_size >= OS_FRAME_SIZE)
-               return 1;
-
-       if (STbuffer->sg_segs) {
-               printk(KERN_WARNING "osst :A: Buffer not previously normalized.\n");
-               normalize_buffer(STbuffer);
-       }
-       /* See how many segments we can use -- need at least two */
-       nbr = max_segs = STbuffer->use_sg;
-       if (nbr <= 2)
-               return 0;
-
-       priority = GFP_KERNEL /* | __GFP_NOWARN */;
-       if (need_dma)
-               priority |= GFP_DMA;
-
-       /* Try to allocate the first segment up to OS_DATA_SIZE and the others
-          big enough to reach the goal (code assumes no segments in place) */
-       for (b_size = OS_DATA_SIZE, order = OSST_FIRST_ORDER; b_size >= PAGE_SIZE; order--, b_size /= 2) {
-               struct page *page = alloc_pages(priority, order);
-
-               STbuffer->sg[0].offset = 0;
-               if (page != NULL) {
-                   sg_set_page(&STbuffer->sg[0], page, b_size, 0);
-                   STbuffer->b_data = page_address(page);
-                   break;
-               }
-       }
-       if (sg_page(&STbuffer->sg[0]) == NULL) {
-               printk(KERN_NOTICE "osst :I: Can't allocate tape buffer main segment.\n");
-               return 0;
-       }
-       /* Got initial segment of 'bsize,order', continue with same size if possible, except for AUX */
-       for (segs=STbuffer->sg_segs=1, got=b_size;
-            segs < max_segs && got < OS_FRAME_SIZE; ) {
-               struct page *page = alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order);
-               STbuffer->sg[segs].offset = 0;
-               if (page == NULL) {
-                       printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n",
-                                               OS_FRAME_SIZE);
-#if DEBUG
-                       STbuffer->buffer_size = got;
-#endif
-                       normalize_buffer(STbuffer);
-                       return 0;
-               }
-               sg_set_page(&STbuffer->sg[segs], page, (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size, 0);
-               got += STbuffer->sg[segs].length;
-               STbuffer->buffer_size = got;
-               STbuffer->sg_segs = ++segs;
-       }
-#if DEBUG
-       if (debugging) {
-               printk(OSST_DEB_MSG
-                          "osst :D: Expanded tape buffer (%d bytes, %d->%d segments, dma: %d, at: %p).\n",
-                          got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data);
-               printk(OSST_DEB_MSG
-                          "osst :D: segment sizes: first %d at %p, last %d bytes at %p.\n",
-                          STbuffer->sg[0].length, page_address(STbuffer->sg[0].page),
-                          STbuffer->sg[segs-1].length, page_address(STbuffer->sg[segs-1].page));
-       }
-#endif
-
-       return 1;
-}
-
-
-/* Release the segments */
-static void normalize_buffer(struct osst_buffer *STbuffer)
-{
-  int i, order, b_size;
-
-       for (i=0; i < STbuffer->sg_segs; i++) {
-
-               for (b_size = PAGE_SIZE, order = 0;
-                    b_size < STbuffer->sg[i].length;
-                    b_size *= 2, order++);
-
-               __free_pages(sg_page(&STbuffer->sg[i]), order);
-               STbuffer->buffer_size -= STbuffer->sg[i].length;
-       }
-#if DEBUG
-       if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs)
-               printk(OSST_DEB_MSG "osst :D: Buffer at %p normalized to %d bytes (segs %d).\n",
-                            STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
-#endif
-       STbuffer->sg_segs = STbuffer->orig_sg_segs = 0;
-}
-
-
-/* Move data from the user buffer to the tape buffer. Returns zero (success) or
-   negative error code. */
-static int append_to_buffer(const char __user *ubp, struct osst_buffer *st_bp, int do_count)
-{
-       int i, cnt, res, offset;
-
-       for (i=0, offset=st_bp->buffer_bytes;
-            i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
-               offset -= st_bp->sg[i].length;
-       if (i == st_bp->sg_segs) {  /* Should never happen */
-               printk(KERN_WARNING "osst :A: Append_to_buffer offset overflow.\n");
-               return (-EIO);
-       }
-       for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
-               cnt = st_bp->sg[i].length - offset < do_count ?
-                     st_bp->sg[i].length - offset : do_count;
-               res = copy_from_user(page_address(sg_page(&st_bp->sg[i])) + offset, ubp, cnt);
-               if (res)
-                       return (-EFAULT);
-               do_count -= cnt;
-               st_bp->buffer_bytes += cnt;
-               ubp += cnt;
-               offset = 0;
-       }
-       if (do_count) {  /* Should never happen */
-               printk(KERN_WARNING "osst :A: Append_to_buffer overflow (left %d).\n",
-                      do_count);
-               return (-EIO);
-       }
-       return 0;
-}
-
-
-/* Move data from the tape buffer to the user buffer. Returns zero (success) or
-   negative error code. */
-static int from_buffer(struct osst_buffer *st_bp, char __user *ubp, int do_count)
-{
-       int i, cnt, res, offset;
-
-       for (i=0, offset=st_bp->read_pointer;
-            i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
-               offset -= st_bp->sg[i].length;
-       if (i == st_bp->sg_segs) {  /* Should never happen */
-               printk(KERN_WARNING "osst :A: From_buffer offset overflow.\n");
-               return (-EIO);
-       }
-       for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
-               cnt = st_bp->sg[i].length - offset < do_count ?
-                     st_bp->sg[i].length - offset : do_count;
-               res = copy_to_user(ubp, page_address(sg_page(&st_bp->sg[i])) + offset, cnt);
-               if (res)
-                       return (-EFAULT);
-               do_count -= cnt;
-               st_bp->buffer_bytes -= cnt;
-               st_bp->read_pointer += cnt;
-               ubp += cnt;
-               offset = 0;
-       }
-       if (do_count) {  /* Should never happen */
-               printk(KERN_WARNING "osst :A: From_buffer overflow (left %d).\n", do_count);
-               return (-EIO);
-       }
-       return 0;
-}
-
-/* Sets the tail of the buffer after fill point to zero.
-   Returns zero (success) or negative error code.        */
-static int osst_zero_buffer_tail(struct osst_buffer *st_bp)
-{
-       int     i, offset, do_count, cnt;
-
-       for (i = 0, offset = st_bp->buffer_bytes;
-            i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
-               offset -= st_bp->sg[i].length;
-       if (i == st_bp->sg_segs) {  /* Should never happen */
-               printk(KERN_WARNING "osst :A: Zero_buffer offset overflow.\n");
-               return (-EIO);
-       }
-       for (do_count = OS_DATA_SIZE - st_bp->buffer_bytes;
-            i < st_bp->sg_segs && do_count > 0; i++) {
-               cnt = st_bp->sg[i].length - offset < do_count ?
-                     st_bp->sg[i].length - offset : do_count ;
-               memset(page_address(sg_page(&st_bp->sg[i])) + offset, 0, cnt);
-               do_count -= cnt;
-               offset = 0;
-       }
-       if (do_count) {  /* Should never happen */
-               printk(KERN_WARNING "osst :A: Zero_buffer overflow (left %d).\n", do_count);
-               return (-EIO);
-       }
-       return 0;
-}
-
-/* Copy a osst 32K chunk of memory into the buffer.
-   Returns zero (success) or negative error code.  */
-static int osst_copy_to_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
-{
-       int     i, cnt, do_count = OS_DATA_SIZE;
-
-       for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
-               cnt = st_bp->sg[i].length < do_count ?
-                     st_bp->sg[i].length : do_count ;
-               memcpy(page_address(sg_page(&st_bp->sg[i])), ptr, cnt);
-               do_count -= cnt;
-               ptr      += cnt;
-       }
-       if (do_count || i != st_bp->sg_segs-1) {  /* Should never happen */
-               printk(KERN_WARNING "osst :A: Copy_to_buffer overflow (left %d at sg %d).\n",
-                                        do_count, i);
-               return (-EIO);
-       }
-       return 0;
-}
-
-/* Copy a osst 32K chunk of memory from the buffer.
-   Returns zero (success) or negative error code.  */
-static int osst_copy_from_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
-{
-       int     i, cnt, do_count = OS_DATA_SIZE;
-
-       for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
-               cnt = st_bp->sg[i].length < do_count ?
-                     st_bp->sg[i].length : do_count ;
-               memcpy(ptr, page_address(sg_page(&st_bp->sg[i])), cnt);
-               do_count -= cnt;
-               ptr      += cnt;
-       }
-       if (do_count || i != st_bp->sg_segs-1) {  /* Should never happen */
-               printk(KERN_WARNING "osst :A: Copy_from_buffer overflow (left %d at sg %d).\n",
-                                        do_count, i);
-               return (-EIO);
-       }
-       return 0;
-}
-
-\f
-/* Module housekeeping */
-
-static void validate_options (void)
-{
-  if (max_dev > 0)
-               osst_max_dev = max_dev;  
-  if (write_threshold_kbs > 0)
-               osst_write_threshold = write_threshold_kbs * ST_KILOBYTE;
-  if (osst_write_threshold > osst_buffer_size)
-               osst_write_threshold = osst_buffer_size;
-  if (max_sg_segs >= OSST_FIRST_SG)
-               osst_max_sg_segs = max_sg_segs;
-#if DEBUG
-  printk(OSST_DEB_MSG "osst :D: max tapes %d, write threshold %d, max s/g segs %d.\n",
-                          osst_max_dev, osst_write_threshold, osst_max_sg_segs);
-#endif
-}
-       
-#ifndef MODULE
-/* Set the boot options. Syntax: osst=xxx,yyy,...
-   where xxx is write threshold in 1024 byte blocks,
-   and   yyy is number of s/g segments to use. */
-static int __init osst_setup (char *str)
-{
-  int i, ints[5];
-  char *stp;
-
-  stp = get_options(str, ARRAY_SIZE(ints), ints);
-
-  if (ints[0] > 0) {
-       for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++)
-                 *parms[i].val = ints[i + 1];
-  } else {
-       while (stp != NULL) {
-               for (i = 0; i < ARRAY_SIZE(parms); i++) {
-                       int len = strlen(parms[i].name);
-                       if (!strncmp(stp, parms[i].name, len) &&
-                           (*(stp + len) == ':' || *(stp + len) == '=')) {
-                               *parms[i].val =
-                                       simple_strtoul(stp + len + 1, NULL, 0);
-                               break;
-                       }
-               }
-               if (i >= ARRAY_SIZE(parms))
-                       printk(KERN_INFO "osst :I: Illegal parameter in '%s'\n",
-                              stp);
-               stp = strchr(stp, ',');
-               if (stp)
-                       stp++;
-       }
-  }
-
-  return 1;
-}
-
-__setup("osst=", osst_setup);
-
-#endif
-
-static const struct file_operations osst_fops = {
-       .owner =        THIS_MODULE,
-       .read =         osst_read,
-       .write =        osst_write,
-       .unlocked_ioctl = osst_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl = osst_compat_ioctl,
-#endif
-       .open =         os_scsi_tape_open,
-       .flush =        os_scsi_tape_flush,
-       .release =      os_scsi_tape_close,
-       .llseek =       noop_llseek,
-};
-
-static int osst_supports(struct scsi_device * SDp)
-{
-       struct  osst_support_data {
-               char *vendor;
-               char *model;
-               char *rev;
-               char *driver_hint; /* Name of the correct driver, NULL if unknown */
-       };
-
-static struct  osst_support_data support_list[] = {
-               /* {"XXX", "Yy-", "", NULL},  example */
-               SIGS_FROM_OSST,
-               {NULL, }};
-
-       struct  osst_support_data *rp;
-
-       /* We are willing to drive OnStream SC-x0 as well as the
-        *       * IDE, ParPort, FireWire, USB variants, if accessible by
-        *               * emulation layer (ide-scsi, usb-storage, ...) */
-
-       for (rp=&(support_list[0]); rp->vendor != NULL; rp++)
-               if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) &&
-                   !strncmp(rp->model, SDp->model, strlen(rp->model)) &&
-                   !strncmp(rp->rev, SDp->rev, strlen(rp->rev))) 
-                       return 1;
-       return 0;
-}
-
-/*
- * sysfs support for osst driver parameter information
- */
-
-static ssize_t version_show(struct device_driver *ddd, char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, "%s\n", osst_version);
-}
-
-static DRIVER_ATTR_RO(version);
-
-static int osst_create_sysfs_files(struct device_driver *sysfs)
-{
-       return driver_create_file(sysfs, &driver_attr_version);
-}
-
-static void osst_remove_sysfs_files(struct device_driver *sysfs)
-{
-       driver_remove_file(sysfs, &driver_attr_version);
-}
-
-/*
- * sysfs support for accessing ADR header information
- */
-
-static ssize_t osst_adr_rev_show(struct device *dev,
-                                struct device_attribute *attr, char *buf)
-{
-       struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
-       ssize_t l = 0;
-
-       if (STp && STp->header_ok && STp->linux_media)
-               l = snprintf(buf, PAGE_SIZE, "%d.%d\n", STp->header_cache->major_rev, STp->header_cache->minor_rev);
-       return l;
-}
-
-DEVICE_ATTR(ADR_rev, S_IRUGO, osst_adr_rev_show, NULL);
-
-static ssize_t osst_linux_media_version_show(struct device *dev,
-                                            struct device_attribute *attr,
-                                            char *buf)
-{
-       struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
-       ssize_t l = 0;
-
-       if (STp && STp->header_ok && STp->linux_media)
-               l = snprintf(buf, PAGE_SIZE, "LIN%d\n", STp->linux_media_version);
-       return l;
-}
-
-DEVICE_ATTR(media_version, S_IRUGO, osst_linux_media_version_show, NULL);
-
-static ssize_t osst_capacity_show(struct device *dev,
-                                 struct device_attribute *attr, char *buf)
-{
-       struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
-       ssize_t l = 0;
-
-       if (STp && STp->header_ok && STp->linux_media)
-               l = snprintf(buf, PAGE_SIZE, "%d\n", STp->capacity);
-       return l;
-}
-
-DEVICE_ATTR(capacity, S_IRUGO, osst_capacity_show, NULL);
-
-static ssize_t osst_first_data_ppos_show(struct device *dev,
-                                        struct device_attribute *attr,
-                                        char *buf)
-{
-       struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
-       ssize_t l = 0;
-
-       if (STp && STp->header_ok && STp->linux_media)
-               l = snprintf(buf, PAGE_SIZE, "%d\n", STp->first_data_ppos);
-       return l;
-}
-
-DEVICE_ATTR(BOT_frame, S_IRUGO, osst_first_data_ppos_show, NULL);
-
-static ssize_t osst_eod_frame_ppos_show(struct device *dev,
-                                       struct device_attribute *attr,
-                                       char *buf)
-{
-       struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
-       ssize_t l = 0;
-
-       if (STp && STp->header_ok && STp->linux_media)
-               l = snprintf(buf, PAGE_SIZE, "%d\n", STp->eod_frame_ppos);
-       return l;
-}
-
-DEVICE_ATTR(EOD_frame, S_IRUGO, osst_eod_frame_ppos_show, NULL);
-
-static ssize_t osst_filemark_cnt_show(struct device *dev,
-                                     struct device_attribute *attr, char *buf)
-{
-       struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
-       ssize_t l = 0;
-
-       if (STp && STp->header_ok && STp->linux_media)
-               l = snprintf(buf, PAGE_SIZE, "%d\n", STp->filemark_cnt);
-       return l;
-}
-
-DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL);
-
-static struct class *osst_sysfs_class;
-
-static int osst_sysfs_init(void)
-{
-       osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape");
-       if (IS_ERR(osst_sysfs_class)) {
-               printk(KERN_ERR "osst :W: Unable to register sysfs class\n");
-               return PTR_ERR(osst_sysfs_class);
-       }
-
-       return 0;
-}
-
-static void osst_sysfs_destroy(dev_t dev)
-{
-       device_destroy(osst_sysfs_class, dev);
-}
-
-static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name)
-{
-       struct device *osst_member;
-       int err;
-
-       osst_member = device_create(osst_sysfs_class, device, dev, STp,
-                                   "%s", name);
-       if (IS_ERR(osst_member)) {
-               printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name);
-               return PTR_ERR(osst_member);
-       }
-
-       err = device_create_file(osst_member, &dev_attr_ADR_rev);
-       if (err)
-               goto err_out;
-       err = device_create_file(osst_member, &dev_attr_media_version);
-       if (err)
-               goto err_out;
-       err = device_create_file(osst_member, &dev_attr_capacity);
-       if (err)
-               goto err_out;
-       err = device_create_file(osst_member, &dev_attr_BOT_frame);
-       if (err)
-               goto err_out;
-       err = device_create_file(osst_member, &dev_attr_EOD_frame);
-       if (err)
-               goto err_out;
-       err = device_create_file(osst_member, &dev_attr_file_count);
-       if (err)
-               goto err_out;
-
-       return 0;
-
-err_out:
-       osst_sysfs_destroy(dev);
-       return err;
-}
-
-static void osst_sysfs_cleanup(void)
-{
-       class_destroy(osst_sysfs_class);
-}
-
-/*
- * osst startup / cleanup code
- */
-
-static int osst_probe(struct device *dev)
-{
-       struct scsi_device * SDp = to_scsi_device(dev);
-       struct osst_tape   * tpnt;
-       struct st_modedef  * STm;
-       struct st_partstat * STps;
-       struct osst_buffer * buffer;
-       struct gendisk     * drive;
-       int                  i, dev_num, err = -ENODEV;
-
-       if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
-               return -ENODEV;
-
-       drive = alloc_disk(1);
-       if (!drive) {
-               printk(KERN_ERR "osst :E: Out of memory. Device not attached.\n");
-               return -ENODEV;
-       }
-
-       /* if this is the first attach, build the infrastructure */
-       write_lock(&os_scsi_tapes_lock);
-       if (os_scsi_tapes == NULL) {
-               os_scsi_tapes = kmalloc_array(osst_max_dev,
-                                              sizeof(struct osst_tape *),
-                                              GFP_ATOMIC);
-               if (os_scsi_tapes == NULL) {
-                       write_unlock(&os_scsi_tapes_lock);
-                       printk(KERN_ERR "osst :E: Unable to allocate array for OnStream SCSI tapes.\n");
-                       goto out_put_disk;
-               }
-               for (i=0; i < osst_max_dev; ++i) os_scsi_tapes[i] = NULL;
-       }
-       
-       if (osst_nr_dev >= osst_max_dev) {
-               write_unlock(&os_scsi_tapes_lock);
-               printk(KERN_ERR "osst :E: Too many tape devices (max. %d).\n", osst_max_dev);
-               goto out_put_disk;
-       }
-
-       /* find a free minor number */
-       for (i = 0; i < osst_max_dev && os_scsi_tapes[i]; i++)
-               ;
-       if(i >= osst_max_dev) panic ("Scsi_devices corrupt (osst)");
-       dev_num = i;
-
-       /* allocate a struct osst_tape for this device */
-       tpnt = kzalloc(sizeof(struct osst_tape), GFP_ATOMIC);
-       if (!tpnt) {
-               write_unlock(&os_scsi_tapes_lock);
-               printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n");
-               goto out_put_disk;
-       }
-
-       /* allocate a buffer for this device */
-       i = SDp->host->sg_tablesize;
-       if (osst_max_sg_segs < i)
-               i = osst_max_sg_segs;
-       buffer = new_tape_buffer(1, SDp->host->unchecked_isa_dma, i);
-       if (buffer == NULL) {
-               write_unlock(&os_scsi_tapes_lock);
-               printk(KERN_ERR "osst :E: Unable to allocate a tape buffer, device not attached.\n");
-               kfree(tpnt);
-               goto out_put_disk;
-       }
-       os_scsi_tapes[dev_num] = tpnt;
-       tpnt->buffer = buffer;
-       tpnt->device = SDp;
-       drive->private_data = &tpnt->driver;
-       sprintf(drive->disk_name, "osst%d", dev_num);
-       tpnt->driver = &osst_template;
-       tpnt->drive = drive;
-       tpnt->in_use = 0;
-       tpnt->capacity = 0xfffff;
-       tpnt->dirty = 0;
-       tpnt->drv_buffer = 1;  /* Try buffering if no mode sense */
-       tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
-       tpnt->density = 0;
-       tpnt->do_auto_lock = OSST_AUTO_LOCK;
-       tpnt->can_bsr = OSST_IN_FILE_POS;
-       tpnt->can_partitions = 0;
-       tpnt->two_fm = OSST_TWO_FM;
-       tpnt->fast_mteom = OSST_FAST_MTEOM;
-       tpnt->scsi2_logical = OSST_SCSI2LOGICAL; /* FIXME */
-       tpnt->write_threshold = osst_write_threshold;
-       tpnt->default_drvbuffer = 0xff; /* No forced buffering */
-       tpnt->partition = 0;
-       tpnt->new_partition = 0;
-       tpnt->nbr_partitions = 0;
-       tpnt->min_block = 512;
-       tpnt->max_block = OS_DATA_SIZE;
-       tpnt->timeout = OSST_TIMEOUT;
-       tpnt->long_timeout = OSST_LONG_TIMEOUT;
-
-       /* Recognize OnStream tapes */
-       /* We don't need to test for OnStream, as this has been done in detect () */
-       tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev);
-       tpnt->omit_blklims = 1;
-
-       tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) || 
-                    (strncmp(SDp->model, "FW-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp);
-       tpnt->frame_in_buffer = 0;
-       tpnt->header_ok = 0;
-       tpnt->linux_media = 0;
-       tpnt->header_cache = NULL;
-
-       for (i=0; i < ST_NBR_MODES; i++) {
-               STm = &(tpnt->modes[i]);
-               STm->defined = 0;
-               STm->sysv = OSST_SYSV;
-               STm->defaults_for_writes = 0;
-               STm->do_async_writes = OSST_ASYNC_WRITES;
-               STm->do_buffer_writes = OSST_BUFFER_WRITES;
-               STm->do_read_ahead = OSST_READ_AHEAD;
-               STm->default_compression = ST_DONT_TOUCH;
-               STm->default_blksize = 512;
-               STm->default_density = (-1);  /* No forced density */
-       }
-
-       for (i=0; i < ST_NBR_PARTITIONS; i++) {
-               STps = &(tpnt->ps[i]);
-               STps->rw = ST_IDLE;
-               STps->eof = ST_NOEOF;
-               STps->at_sm = 0;
-               STps->last_block_valid = 0;
-               STps->drv_block = (-1);
-               STps->drv_file = (-1);
-       }
-
-       tpnt->current_mode = 0;
-       tpnt->modes[0].defined = 1;
-       tpnt->modes[2].defined = 1;
-       tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = 0;
-
-       mutex_init(&tpnt->lock);
-       osst_nr_dev++;
-       write_unlock(&os_scsi_tapes_lock);
-
-       {
-               char name[8];
-
-               /*  Rewind entry  */
-               err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt));
-               if (err)
-                       goto out_free_buffer;
-
-               /*  No-rewind entry  */
-               snprintf(name, 8, "%s%s", "n", tape_name(tpnt));
-               err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name);
-               if (err)
-                       goto out_free_sysfs1;
-       }
-
-       sdev_printk(KERN_INFO, SDp,
-               "osst :I: Attached OnStream %.5s tape as %s\n",
-               SDp->model, tape_name(tpnt));
-
-       return 0;
-
-out_free_sysfs1:
-       osst_sysfs_destroy(MKDEV(OSST_MAJOR, dev_num));
-out_free_buffer:
-       kfree(buffer);
-out_put_disk:
-        put_disk(drive);
-        return err;
-};
-
-static int osst_remove(struct device *dev)
-{
-       struct scsi_device * SDp = to_scsi_device(dev);
-       struct osst_tape * tpnt;
-       int i;
-
-       if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0))
-               return 0;
-
-       write_lock(&os_scsi_tapes_lock);
-       for(i=0; i < osst_max_dev; i++) {
-               if((tpnt = os_scsi_tapes[i]) && (tpnt->device == SDp)) {
-                       osst_sysfs_destroy(MKDEV(OSST_MAJOR, i));
-                       osst_sysfs_destroy(MKDEV(OSST_MAJOR, i+128));
-                       tpnt->device = NULL;
-                       put_disk(tpnt->drive);
-                       os_scsi_tapes[i] = NULL;
-                       osst_nr_dev--;
-                       write_unlock(&os_scsi_tapes_lock);
-                       vfree(tpnt->header_cache);
-                       if (tpnt->buffer) {
-                               normalize_buffer(tpnt->buffer);
-                               kfree(tpnt->buffer);
-                       }
-                       kfree(tpnt);
-                       return 0;
-               }
-       }
-       write_unlock(&os_scsi_tapes_lock);
-       return 0;
-}
-
-static int __init init_osst(void) 
-{
-       int err;
-
-       printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid);
-
-       validate_options();
-
-       err = osst_sysfs_init();
-       if (err)
-               return err;
-
-       err = register_chrdev(OSST_MAJOR, "osst", &osst_fops);
-       if (err < 0) {
-               printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR);
-               goto err_out;
-       }
-
-       err = scsi_register_driver(&osst_template.gendrv);
-       if (err)
-               goto err_out_chrdev;
-
-       err = osst_create_sysfs_files(&osst_template.gendrv);
-       if (err)
-               goto err_out_scsidrv;
-
-       return 0;
-
-err_out_scsidrv:
-       scsi_unregister_driver(&osst_template.gendrv);
-err_out_chrdev:
-       unregister_chrdev(OSST_MAJOR, "osst");
-err_out:
-       osst_sysfs_cleanup();
-       return err;
-}
-
-static void __exit exit_osst (void)
-{
-       int i;
-       struct osst_tape * STp;
-
-       osst_remove_sysfs_files(&osst_template.gendrv);
-       scsi_unregister_driver(&osst_template.gendrv);
-       unregister_chrdev(OSST_MAJOR, "osst");
-       osst_sysfs_cleanup();
-
-       if (os_scsi_tapes) {
-               for (i=0; i < osst_max_dev; ++i) {
-                       if (!(STp = os_scsi_tapes[i])) continue;
-                       /* This is defensive, supposed to happen during detach */
-                       vfree(STp->header_cache);
-                       if (STp->buffer) {
-                               normalize_buffer(STp->buffer);
-                               kfree(STp->buffer);
-                       }
-                       put_disk(STp->drive);
-                       kfree(STp);
-               }
-               kfree(os_scsi_tapes);
-       }
-       printk(KERN_INFO "osst :I: Unloaded.\n");
-}
-
-module_init(init_osst);
-module_exit(exit_osst);
diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h
deleted file mode 100644 (file)
index b90ae28..0000000
+++ /dev/null
@@ -1,651 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- *     $Header: /cvsroot/osst/Driver/osst.h,v 1.16 2005/01/01 21:13:35 wriede Exp $
- */
-
-#include <asm/byteorder.h>
-#include <linux/completion.h>
-#include <linux/mutex.h>
-
-/*     FIXME - rename and use the following two types or delete them!
- *              and the types really should go to st.h anyway...
- *     INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C)
- */
-typedef struct {
-       unsigned        device_type     :5;     /* Peripheral Device Type */
-       unsigned        reserved0_765   :3;     /* Peripheral Qualifier - Reserved */
-       unsigned        reserved1_6t0   :7;     /* Reserved */
-       unsigned        rmb             :1;     /* Removable Medium Bit */
-       unsigned        ansi_version    :3;     /* ANSI Version */
-       unsigned        ecma_version    :3;     /* ECMA Version */
-       unsigned        iso_version     :2;     /* ISO Version */
-       unsigned        response_format :4;     /* Response Data Format */
-       unsigned        reserved3_45    :2;     /* Reserved */
-       unsigned        reserved3_6     :1;     /* TrmIOP - Reserved */
-       unsigned        reserved3_7     :1;     /* AENC - Reserved */
-       u8              additional_length;      /* Additional Length (total_length-4) */
-       u8              rsv5, rsv6, rsv7;       /* Reserved */
-       u8              vendor_id[8];           /* Vendor Identification */
-       u8              product_id[16];         /* Product Identification */
-       u8              revision_level[4];      /* Revision Level */
-       u8              vendor_specific[20];    /* Vendor Specific - Optional */
-       u8              reserved56t95[40];      /* Reserved - Optional */
-                                               /* Additional information may be returned */
-} idetape_inquiry_result_t;
-
-/*
- *     READ POSITION packet command - Data Format (From Table 6-57)
- */
-typedef struct {
-       unsigned        reserved0_10    :2;     /* Reserved */
-       unsigned        bpu             :1;     /* Block Position Unknown */    
-       unsigned        reserved0_543   :3;     /* Reserved */
-       unsigned        eop             :1;     /* End Of Partition */
-       unsigned        bop             :1;     /* Beginning Of Partition */
-       u8              partition;              /* Partition Number */
-       u8              reserved2, reserved3;   /* Reserved */
-       u32             first_block;            /* First Block Location */
-       u32             last_block;             /* Last Block Location (Optional) */
-       u8              reserved12;             /* Reserved */
-       u8              blocks_in_buffer[3];    /* Blocks In Buffer - (Optional) */
-       u32             bytes_in_buffer;        /* Bytes In Buffer (Optional) */
-} idetape_read_position_result_t;
-
-/*
- *      Follows structures which are related to the SELECT SENSE / MODE SENSE
- *      packet commands. 
- */
-#define COMPRESSION_PAGE           0x0f
-#define COMPRESSION_PAGE_LENGTH    16
-
-#define CAPABILITIES_PAGE          0x2a
-#define CAPABILITIES_PAGE_LENGTH   20
-
-#define TAPE_PARAMTR_PAGE          0x2b
-#define TAPE_PARAMTR_PAGE_LENGTH   16
-
-#define NUMBER_RETRIES_PAGE        0x2f
-#define NUMBER_RETRIES_PAGE_LENGTH 4
-
-#define BLOCK_SIZE_PAGE            0x30
-#define BLOCK_SIZE_PAGE_LENGTH     4
-
-#define BUFFER_FILLING_PAGE        0x33
-#define BUFFER_FILLING_PAGE_LENGTH 4
-
-#define VENDOR_IDENT_PAGE          0x36
-#define VENDOR_IDENT_PAGE_LENGTH   8
-
-#define LOCATE_STATUS_PAGE         0x37
-#define LOCATE_STATUS_PAGE_LENGTH  0
-
-#define MODE_HEADER_LENGTH         4
-
-
-/*
- *     REQUEST SENSE packet command result - Data Format.
- */
-typedef struct {
-       unsigned        error_code      :7;     /* Current of deferred errors */
-       unsigned        valid           :1;     /* The information field conforms to QIC-157C */
-       u8              reserved1       :8;     /* Segment Number - Reserved */
-       unsigned        sense_key       :4;     /* Sense Key */
-       unsigned        reserved2_4     :1;     /* Reserved */
-       unsigned        ili             :1;     /* Incorrect Length Indicator */
-       unsigned        eom             :1;     /* End Of Medium */
-       unsigned        filemark        :1;     /* Filemark */
-       u32             information __attribute__ ((packed));
-       u8              asl;                    /* Additional sense length (n-7) */
-       u32             command_specific;       /* Additional command specific information */
-       u8              asc;                    /* Additional Sense Code */
-       u8              ascq;                   /* Additional Sense Code Qualifier */
-       u8              replaceable_unit_code;  /* Field Replaceable Unit Code */
-       unsigned        sk_specific1    :7;     /* Sense Key Specific */
-       unsigned        sksv            :1;     /* Sense Key Specific information is valid */
-       u8              sk_specific2;           /* Sense Key Specific */
-       u8              sk_specific3;           /* Sense Key Specific */
-       u8              pad[2];                 /* Padding to 20 bytes */
-} idetape_request_sense_result_t;
-
-/*
- *      Mode Parameter Header for the MODE SENSE packet command
- */
-typedef struct {
-        u8              mode_data_length;       /* Length of the following data transfer */
-        u8              medium_type;            /* Medium Type */
-        u8              dsp;                    /* Device Specific Parameter */
-        u8              bdl;                    /* Block Descriptor Length */
-} osst_mode_parameter_header_t;
-
-/*
- *      Mode Parameter Block Descriptor the MODE SENSE packet command
- *
- *      Support for block descriptors is optional.
- */
-typedef struct {
-        u8              density_code;           /* Medium density code */
-        u8              blocks[3];              /* Number of blocks */
-        u8              reserved4;              /* Reserved */
-        u8              length[3];              /* Block Length */
-} osst_parameter_block_descriptor_t;
-
-/*
- *      The Data Compression Page, as returned by the MODE SENSE packet command.
- */
-typedef struct {
-#if   defined(__BIG_ENDIAN_BITFIELD)
-        unsigned        ps              :1;
-        unsigned        reserved0       :1;     /* Reserved */
-       unsigned        page_code       :6;     /* Page Code - Should be 0xf */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       unsigned        page_code       :6;     /* Page Code - Should be 0xf */
-        unsigned        reserved0       :1;     /* Reserved */
-        unsigned        ps              :1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-        u8              page_length;            /* Page Length - Should be 14 */
-#if   defined(__BIG_ENDIAN_BITFIELD)
-        unsigned        dce             :1;     /* Data Compression Enable */
-        unsigned        dcc             :1;     /* Data Compression Capable */
-       unsigned        reserved2       :6;     /* Reserved */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       unsigned        reserved2       :6;     /* Reserved */
-        unsigned        dcc             :1;     /* Data Compression Capable */
-        unsigned        dce             :1;     /* Data Compression Enable */
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-#if   defined(__BIG_ENDIAN_BITFIELD)
-        unsigned        dde             :1;     /* Data Decompression Enable */
-        unsigned        red             :2;     /* Report Exception on Decompression */
-       unsigned        reserved3       :5;     /* Reserved */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       unsigned        reserved3       :5;     /* Reserved */
-        unsigned        red             :2;     /* Report Exception on Decompression */
-        unsigned        dde             :1;     /* Data Decompression Enable */
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-        u32             ca;                     /* Compression Algorithm */
-        u32             da;                     /* Decompression Algorithm */
-        u8              reserved[4];            /* Reserved */
-} osst_data_compression_page_t;
-
-/*
- *      The Medium Partition Page, as returned by the MODE SENSE packet command.
- */
-typedef struct {
-#if   defined(__BIG_ENDIAN_BITFIELD)
-        unsigned        ps              :1;
-        unsigned        reserved1_6     :1;     /* Reserved */
-       unsigned        page_code       :6;     /* Page Code - Should be 0x11 */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       unsigned        page_code       :6;     /* Page Code - Should be 0x11 */
-        unsigned        reserved1_6     :1;     /* Reserved */
-        unsigned        ps              :1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-        u8              page_length;            /* Page Length - Should be 6 */
-        u8              map;                    /* Maximum Additional Partitions - Should be 0 */
-        u8              apd;                    /* Additional Partitions Defined - Should be 0 */
-#if   defined(__BIG_ENDIAN_BITFIELD)
-        unsigned        fdp             :1;     /* Fixed Data Partitions */
-        unsigned        sdp             :1;     /* Should be 0 */
-        unsigned        idp             :1;     /* Should be 0 */
-        unsigned        psum            :2;     /* Should be 0 */
-       unsigned        reserved4_012   :3;     /* Reserved */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       unsigned        reserved4_012   :3;     /* Reserved */
-        unsigned        psum            :2;     /* Should be 0 */
-        unsigned        idp             :1;     /* Should be 0 */
-        unsigned        sdp             :1;     /* Should be 0 */
-        unsigned        fdp             :1;     /* Fixed Data Partitions */
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-        u8              mfr;                    /* Medium Format Recognition */
-        u8              reserved[2];            /* Reserved */
-} osst_medium_partition_page_t;
-
-/*
- *      Capabilities and Mechanical Status Page
- */
-typedef struct {
-#if   defined(__BIG_ENDIAN_BITFIELD)
-        unsigned        reserved1_67    :2;
-       unsigned        page_code       :6;     /* Page code - Should be 0x2a */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       unsigned        page_code       :6;     /* Page code - Should be 0x2a */
-        unsigned        reserved1_67    :2;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-        u8              page_length;            /* Page Length - Should be 0x12 */
-        u8              reserved2, reserved3;
-#if   defined(__BIG_ENDIAN_BITFIELD)
-        unsigned        reserved4_67    :2;
-        unsigned        sprev           :1;     /* Supports SPACE in the reverse direction */
-        unsigned        reserved4_1234  :4;
-       unsigned        ro              :1;     /* Read Only Mode */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       unsigned        ro              :1;     /* Read Only Mode */
-        unsigned        reserved4_1234  :4;
-        unsigned        sprev           :1;     /* Supports SPACE in the reverse direction */
-        unsigned        reserved4_67    :2;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-#if   defined(__BIG_ENDIAN_BITFIELD)
-        unsigned        reserved5_67    :2;
-        unsigned        qfa             :1;     /* Supports the QFA two partition formats */
-        unsigned        reserved5_4     :1;
-        unsigned        efmt            :1;     /* Supports ERASE command initiated formatting */
-       unsigned        reserved5_012   :3;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       unsigned        reserved5_012   :3;
-        unsigned        efmt            :1;     /* Supports ERASE command initiated formatting */
-        unsigned        reserved5_4     :1;
-        unsigned        qfa             :1;     /* Supports the QFA two partition formats */
-        unsigned        reserved5_67    :2;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-#if   defined(__BIG_ENDIAN_BITFIELD)
-        unsigned        cmprs           :1;     /* Supports data compression */
-        unsigned        ecc             :1;     /* Supports error correction */
-       unsigned        reserved6_45    :2;     /* Reserved */  
-        unsigned        eject           :1;     /* The device can eject the volume */
-        unsigned        prevent         :1;     /* The device defaults in the prevent state after power up */
-        unsigned        locked          :1;     /* The volume is locked */
-       unsigned        lock            :1;     /* Supports locking the volume */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       unsigned        lock            :1;     /* Supports locking the volume */
-        unsigned        locked          :1;     /* The volume is locked */
-        unsigned        prevent         :1;     /* The device defaults in the prevent state after power up */
-        unsigned        eject           :1;     /* The device can eject the volume */
-       unsigned        reserved6_45    :2;     /* Reserved */  
-        unsigned        ecc             :1;     /* Supports error correction */
-        unsigned        cmprs           :1;     /* Supports data compression */
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-#if   defined(__BIG_ENDIAN_BITFIELD)
-        unsigned        blk32768        :1;     /* slowb - the device restricts the byte count for PIO */
-                                                /* transfers for slow buffer memory ??? */
-                                                /* Also 32768 block size in some cases */
-        unsigned        reserved7_3_6   :4;
-        unsigned        blk1024         :1;     /* Supports 1024 bytes block size */
-        unsigned        blk512          :1;     /* Supports 512 bytes block size */
-       unsigned        reserved7_0     :1;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       unsigned        reserved7_0     :1;
-        unsigned        blk512          :1;     /* Supports 512 bytes block size */
-        unsigned        blk1024         :1;     /* Supports 1024 bytes block size */
-        unsigned        reserved7_3_6   :4;
-        unsigned        blk32768        :1;     /* slowb - the device restricts the byte count for PIO */
-                                                /* transfers for slow buffer memory ??? */
-                                                /* Also 32768 block size in some cases */
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-        __be16          max_speed;              /* Maximum speed supported in KBps */
-        u8              reserved10, reserved11;
-        __be16          ctl;                    /* Continuous Transfer Limit in blocks */
-        __be16          speed;                  /* Current Speed, in KBps */
-        __be16          buffer_size;            /* Buffer Size, in 512 bytes */
-        u8              reserved18, reserved19;
-} osst_capabilities_page_t;
-
-/*
- *      Block Size Page
- */
-typedef struct {
-#if   defined(__BIG_ENDIAN_BITFIELD)
-        unsigned        ps              :1;
-        unsigned        reserved1_6     :1;
-       unsigned        page_code       :6;     /* Page code - Should be 0x30 */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       unsigned        page_code       :6;     /* Page code - Should be 0x30 */
-        unsigned        reserved1_6     :1;
-        unsigned        ps              :1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-        u8              page_length;            /* Page Length - Should be 2 */
-        u8              reserved2;
-#if   defined(__BIG_ENDIAN_BITFIELD)
-        unsigned        one             :1;
-        unsigned        reserved2_6     :1;
-        unsigned        record32_5      :1;
-        unsigned        record32        :1;
-        unsigned        reserved2_23    :2;
-        unsigned        play32_5        :1;
-       unsigned        play32          :1;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       unsigned        play32          :1;
-        unsigned        play32_5        :1;
-        unsigned        reserved2_23    :2;
-        unsigned        record32        :1;
-        unsigned        record32_5      :1;
-        unsigned        reserved2_6     :1;
-        unsigned        one             :1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-} osst_block_size_page_t;
-
-/*
- *     Tape Parameters Page
- */
-typedef struct {
-#if   defined(__BIG_ENDIAN_BITFIELD)
-        unsigned        ps              :1;
-        unsigned        reserved1_6     :1;
-       unsigned        page_code       :6;     /* Page code - Should be 0x2b */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       unsigned        page_code       :6;     /* Page code - Should be 0x2b */
-        unsigned        reserved1_6     :1;
-        unsigned        ps              :1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-       u8              reserved2;
-       u8              density;
-       u8              reserved3,reserved4;
-       __be16          segtrk;
-       __be16          trks;
-       u8              reserved5,reserved6,reserved7,reserved8,reserved9,reserved10;
-} osst_tape_paramtr_page_t;
-
-/* OnStream definitions */
-
-#define OS_CONFIG_PARTITION     (0xff)
-#define OS_DATA_PARTITION       (0)
-#define OS_PARTITION_VERSION    (1)
-
-/*
- * partition
- */
-typedef struct os_partition_s {
-        __u8    partition_num;
-        __u8    par_desc_ver;
-        __be16  wrt_pass_cntr;
-        __be32  first_frame_ppos;
-        __be32  last_frame_ppos;
-        __be32  eod_frame_ppos;
-} os_partition_t;
-
-/*
- * DAT entry
- */
-typedef struct os_dat_entry_s {
-        __be32  blk_sz;
-        __be16  blk_cnt;
-        __u8    flags;
-        __u8    reserved;
-} os_dat_entry_t;
-
-/*
- * DAT
- */
-#define OS_DAT_FLAGS_DATA       (0xc)
-#define OS_DAT_FLAGS_MARK       (0x1)
-
-typedef struct os_dat_s {
-        __u8            dat_sz;
-        __u8            reserved1;
-        __u8            entry_cnt;
-        __u8            reserved3;
-        os_dat_entry_t  dat_list[16];
-} os_dat_t;
-
-/*
- * Frame types
- */
-#define OS_FRAME_TYPE_FILL      (0)
-#define OS_FRAME_TYPE_EOD       (1 << 0)
-#define OS_FRAME_TYPE_MARKER    (1 << 1)
-#define OS_FRAME_TYPE_HEADER    (1 << 3)
-#define OS_FRAME_TYPE_DATA      (1 << 7)
-
-/*
- * AUX
- */
-typedef struct os_aux_s {
-        __be32          format_id;              /* hardware compatibility AUX is based on */
-        char            application_sig[4];     /* driver used to write this media */
-        __be32          hdwr;                   /* reserved */
-        __be32          update_frame_cntr;      /* for configuration frame */
-        __u8            frame_type;
-        __u8            frame_type_reserved;
-        __u8            reserved_18_19[2];
-        os_partition_t  partition;
-        __u8            reserved_36_43[8];
-        __be32          frame_seq_num;
-        __be32          logical_blk_num_high;
-        __be32          logical_blk_num;
-        os_dat_t        dat;
-        __u8            reserved188_191[4];
-        __be32          filemark_cnt;
-        __be32          phys_fm;
-        __be32          last_mark_ppos;
-        __u8            reserved204_223[20];
-
-        /*
-         * __u8         app_specific[32];
-         *
-         * Linux specific fields:
-         */
-         __be32         next_mark_ppos;         /* when known, points to next marker */
-        __be32         last_mark_lbn;          /* storing log_blk_num of last mark is extends ADR spec */
-         __u8           linux_specific[24];
-
-        __u8            reserved_256_511[256];
-} os_aux_t;
-
-#define OS_FM_TAB_MAX 1024
-
-typedef struct os_fm_tab_s {
-       __u8            fm_part_num;
-       __u8            reserved_1;
-       __u8            fm_tab_ent_sz;
-       __u8            reserved_3;
-       __be16          fm_tab_ent_cnt;
-       __u8            reserved6_15[10];
-       __be32          fm_tab_ent[OS_FM_TAB_MAX];
-} os_fm_tab_t;
-
-typedef struct os_ext_trk_ey_s {
-       __u8            et_part_num;
-       __u8            fmt;
-       __be16          fm_tab_off;
-       __u8            reserved4_7[4];
-       __be32          last_hlb_hi;
-       __be32          last_hlb;
-       __be32          last_pp;
-       __u8            reserved20_31[12];
-} os_ext_trk_ey_t;
-
-typedef struct os_ext_trk_tb_s {
-       __u8            nr_stream_part;
-       __u8            reserved_1;
-       __u8            et_ent_sz;
-       __u8            reserved3_15[13];
-       os_ext_trk_ey_t dat_ext_trk_ey;
-       os_ext_trk_ey_t qfa_ext_trk_ey;
-} os_ext_trk_tb_t;
-
-typedef struct os_header_s {
-        char            ident_str[8];
-        __u8            major_rev;
-        __u8            minor_rev;
-       __be16          ext_trk_tb_off;
-        __u8            reserved12_15[4];
-        __u8            pt_par_num;
-        __u8            pt_reserved1_3[3];
-        os_partition_t  partition[16];
-       __be32          cfg_col_width;
-       __be32          dat_col_width;
-       __be32          qfa_col_width;
-       __u8            cartridge[16];
-       __u8            reserved304_511[208];
-       __be32          old_filemark_list[16680/4];             /* in ADR 1.4 __u8 track_table[16680] */
-       os_ext_trk_tb_t ext_track_tb;
-       __u8            reserved17272_17735[464];
-       os_fm_tab_t     dat_fm_tab;
-       os_fm_tab_t     qfa_fm_tab;
-       __u8            reserved25960_32767[6808];
-} os_header_t;
-
-
-/*
- * OnStream ADRL frame
- */
-#define OS_FRAME_SIZE   (32 * 1024 + 512)
-#define OS_DATA_SIZE    (32 * 1024)
-#define OS_AUX_SIZE     (512)
-//#define OSST_MAX_SG      2
-
-/* The OnStream tape buffer descriptor. */
-struct osst_buffer {
-  unsigned char in_use;
-  unsigned char dma;   /* DMA-able buffer */
-  int buffer_size;
-  int buffer_blocks;
-  int buffer_bytes;
-  int read_pointer;
-  int writing;
-  int midlevel_result;
-  int syscall_result;
-  struct osst_request *last_SRpnt;
-  struct st_cmdstatus cmdstat;
-  struct rq_map_data map_data;
-  unsigned char *b_data;
-  os_aux_t *aux;               /* onstream AUX structure at end of each block     */
-  unsigned short use_sg;       /* zero or number of s/g segments for this adapter */
-  unsigned short sg_segs;      /* number of segments in s/g list                  */
-  unsigned short orig_sg_segs; /* number of segments allocated at first try       */
-  struct scatterlist sg[1];    /* MUST BE last item                               */
-} ;
-
-/* The OnStream tape drive descriptor */
-struct osst_tape {
-  struct scsi_driver *driver;
-  unsigned capacity;
-  struct scsi_device *device;
-  struct mutex lock;           /* for serialization */
-  struct completion wait;      /* for SCSI commands */
-  struct osst_buffer * buffer;
-
-  /* Drive characteristics */
-  unsigned char omit_blklims;
-  unsigned char do_auto_lock;
-  unsigned char can_bsr;
-  unsigned char can_partitions;
-  unsigned char two_fm;
-  unsigned char fast_mteom;
-  unsigned char restr_dma;
-  unsigned char scsi2_logical;
-  unsigned char default_drvbuffer;  /* 0xff = don't touch, value 3 bits */
-  unsigned char pos_unknown;        /* after reset position unknown */
-  int write_threshold;
-  int timeout;                 /* timeout for normal commands */
-  int long_timeout;            /* timeout for commands known to take long time*/
-
-  /* Mode characteristics */
-  struct st_modedef modes[ST_NBR_MODES];
-  int current_mode;
-
-  /* Status variables */
-  int partition;
-  int new_partition;
-  int nbr_partitions;    /* zero until partition support enabled */
-  struct st_partstat ps[ST_NBR_PARTITIONS];
-  unsigned char dirty;
-  unsigned char ready;
-  unsigned char write_prot;
-  unsigned char drv_write_prot;
-  unsigned char in_use;
-  unsigned char blksize_changed;
-  unsigned char density_changed;
-  unsigned char compression_changed;
-  unsigned char drv_buffer;
-  unsigned char density;
-  unsigned char door_locked;
-  unsigned char rew_at_close;
-  unsigned char inited;
-  int block_size;
-  int min_block;
-  int max_block;
-  int recover_count;            /* from tape opening */
-  int abort_count;
-  int write_count;
-  int read_count;
-  int recover_erreg;            /* from last status call */
-  /*
-   * OnStream specific data
-   */
-  int     os_fw_rev;                          /* the firmware revision * 10000 */
-  unsigned char  raw;                          /* flag OnStream raw access (32.5KB block size) */
-  unsigned char  poll;                         /* flag that this drive needs polling (IDE|firmware) */
-  unsigned char  frame_in_buffer;             /* flag that the frame as per frame_seq_number
-                                               * has been read into STp->buffer and is valid */
-  int      frame_seq_number;                   /* logical frame number */
-  int      logical_blk_num;                    /* logical block number */
-  unsigned first_frame_position;               /* physical frame to be transferred to/from host */
-  unsigned last_frame_position;                /* physical frame to be transferd to/from tape */
-  int      cur_frames;                         /* current number of frames in internal buffer */
-  int      max_frames;                         /* max number of frames in internal buffer */
-  char     application_sig[5];                 /* application signature */
-  unsigned char  fast_open;                    /* flag that reminds us we didn't check headers at open */
-  unsigned short wrt_pass_cntr;                /* write pass counter */
-  int      update_frame_cntr;                  /* update frame counter */
-  int      onstream_write_error;               /* write error recovery active */
-  int      header_ok;                          /* header frame verified ok */
-  int      linux_media;                        /* reading linux-specifc media */
-  int      linux_media_version;
-  os_header_t * header_cache;                 /* cache is kept for filemark positions */
-  int      filemark_cnt;
-  int      first_mark_ppos;
-  int      last_mark_ppos;
-  int      last_mark_lbn;                      /* storing log_blk_num of last mark is extends ADR spec */
-  int      first_data_ppos;
-  int      eod_frame_ppos;
-  int      eod_frame_lfa;
-  int      write_type;                         /* used in write error recovery */
-  int      read_error_frame;                   /* used in read error recovery */
-  unsigned long cmd_start_time;
-  unsigned long max_cmd_time;
-
-#if DEBUG
-  unsigned char write_pending;
-  int nbr_finished;
-  int nbr_waits;
-  unsigned char last_cmnd[6];
-  unsigned char last_sense[16];
-#endif
-  struct gendisk *drive;
-} ;
-
-/* scsi tape command */
-struct osst_request {
-       unsigned char cmd[MAX_COMMAND_SIZE];
-       unsigned char sense[SCSI_SENSE_BUFFERSIZE];
-       int result;
-       struct osst_tape *stp;
-       struct completion *waiting;
-       struct bio *bio;
-};
-
-/* Values of write_type */
-#define OS_WRITE_DATA      0
-#define OS_WRITE_EOD       1
-#define OS_WRITE_NEW_MARK  2
-#define OS_WRITE_LAST_MARK 3
-#define OS_WRITE_HEADER    4
-#define OS_WRITE_FILLER    5
-
-/* Additional rw state */
-#define OS_WRITING_COMPLETE 3
diff --git a/drivers/scsi/osst_detect.h b/drivers/scsi/osst_detect.h
deleted file mode 100644 (file)
index 83c1d4f..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#define SIGS_FROM_OSST \
-       {"OnStream", "SC-", "", "osst"}, \
-       {"OnStream", "DI-", "", "osst"}, \
-       {"OnStream", "DP-", "", "osst"}, \
-       {"OnStream", "FW-", "", "osst"}, \
-       {"OnStream", "USB", "", "osst"}
diff --git a/drivers/scsi/osst_options.h b/drivers/scsi/osst_options.h
deleted file mode 100644 (file)
index a6a389b..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
-   The compile-time configurable defaults for the Linux SCSI tape driver.
-
-   Copyright 1995 Kai Makisara.
-   
-   Last modified: Wed Sep  2 21:24:07 1998 by root@home
-   
-   Changed (and renamed) for OnStream SCSI drives garloff@suse.de
-   2000-06-21
-
-   $Header: /cvsroot/osst/Driver/osst_options.h,v 1.6 2003/12/23 14:22:12 wriede Exp $
-*/
-
-#ifndef _OSST_OPTIONS_H
-#define _OSST_OPTIONS_H
-
-/* The minimum limit for the number of SCSI tape devices is determined by
-   OSST_MAX_TAPES. If the number of tape devices and the "slack" defined by
-   OSST_EXTRA_DEVS exceeds OSST_MAX_TAPES, the large number is used. */
-#define OSST_MAX_TAPES 4
-
-/* If OSST_IN_FILE_POS is nonzero, the driver positions the tape after the
-   record been read by the user program even if the tape has moved further
-   because of buffered reads. Should be set to zero to support also drives
-   that can't space backwards over records. NOTE: The tape will be
-   spaced backwards over an "accidentally" crossed filemark in any case. */
-#define OSST_IN_FILE_POS 1
-
-/* The tape driver buffer size in kilobytes. */
-/* Don't change, as this is the HW blocksize */
-#define OSST_BUFFER_BLOCKS 32
-
-/* The number of kilobytes of data in the buffer that triggers an
-   asynchronous write in fixed block mode. See also OSST_ASYNC_WRITES
-   below. */
-#define OSST_WRITE_THRESHOLD_BLOCKS 32
-
-/* OSST_EOM_RESERVE defines the number of frames are kept in reserve for
- *  * write error recovery when writing near end of medium. ENOSPC is returned
- *   * when write() is called and the tape write position is within this number
- *    * of blocks from the tape capacity. */
-#define OSST_EOM_RESERVE 300
-
-/* The maximum number of tape buffers the driver allocates. The number
-   is also constrained by the number of drives detected. Determines the
-   maximum number of concurrently active tape drives. */
-#define OSST_MAX_BUFFERS OSST_MAX_TAPES 
-
-/* Maximum number of scatter/gather segments */
-/* Fit one buffer in pages and add one for the AUX header */
-#define OSST_MAX_SG      (((OSST_BUFFER_BLOCKS*1024) / PAGE_SIZE) + 1)
-
-/* The number of scatter/gather segments to allocate at first try (must be
-   smaller or equal to the maximum). */
-#define OSST_FIRST_SG    ((OSST_BUFFER_BLOCKS*1024) / PAGE_SIZE)
-
-/* The size of the first scatter/gather segments (determines the maximum block
-   size for SCSI adapters not supporting scatter/gather). The default is set
-   to try to allocate the buffer as one chunk. */
-#define OSST_FIRST_ORDER  (15-PAGE_SHIFT)
-
-
-/* The following lines define defaults for properties that can be set
-   separately for each drive using the MTSTOPTIONS ioctl. */
-
-/* If OSST_TWO_FM is non-zero, the driver writes two filemarks after a
-   file being written. Some drives can't handle two filemarks at the
-   end of data. */
-#define OSST_TWO_FM 0
-
-/* If OSST_BUFFER_WRITES is non-zero, writes in fixed block mode are
-   buffered until the driver buffer is full or asynchronous write is
-   triggered. */
-#define OSST_BUFFER_WRITES 1
-
-/* If OSST_ASYNC_WRITES is non-zero, the SCSI write command may be started
-   without waiting for it to finish. May cause problems in multiple
-   tape backups. */
-#define OSST_ASYNC_WRITES 1
-
-/* If OSST_READ_AHEAD is non-zero, blocks are read ahead in fixed block
-   mode. */
-#define OSST_READ_AHEAD 1
-
-/* If OSST_AUTO_LOCK is non-zero, the drive door is locked at the first
-   read or write command after the device is opened. The door is opened
-   when the device is closed. */
-#define OSST_AUTO_LOCK 0
-
-/* If OSST_FAST_MTEOM is non-zero, the MTEOM ioctl is done using the
-   direct SCSI command. The file number status is lost but this method
-   is fast with some drives. Otherwise MTEOM is done by spacing over
-   files and the file number status is retained. */
-#define OSST_FAST_MTEOM 0
-
-/* If OSST_SCSI2LOGICAL is nonzero, the logical block addresses are used for
-   MTIOCPOS and MTSEEK by default. Vendor addresses are used if OSST_SCSI2LOGICAL
-   is zero. */
-#define OSST_SCSI2LOGICAL 0
-
-/* If OSST_SYSV is non-zero, the tape behaves according to the SYS V semantics.
-   The default is BSD semantics. */
-#define OSST_SYSV 0
-
-
-#endif
index c544f48..2368f34 100644 (file)
@@ -20,6 +20,16 @@ config PCMCIA_AHA152X
          To compile this driver as a module, choose M here: the
          module will be called aha152x_cs.
 
+config PCMCIA_FDOMAIN
+       tristate "Future Domain PCMCIA support"
+       select SCSI_FDOMAIN
+       help
+         Say Y here if you intend to attach this type of PCMCIA SCSI host
+         adapter to your computer.
+
+         To compile this driver as a module, choose M here: the
+         module will be called fdomain_cs.
+
 config PCMCIA_NINJA_SCSI
        tristate "NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support"
        depends on !64BIT
index a5a24dd..02f5b44 100644 (file)
@@ -4,6 +4,7 @@ ccflags-y               := -I $(srctree)/drivers/scsi
 
 # 16-bit client drivers
 obj-$(CONFIG_PCMCIA_QLOGIC)    += qlogic_cs.o
+obj-$(CONFIG_PCMCIA_FDOMAIN)   += fdomain_cs.o
 obj-$(CONFIG_PCMCIA_AHA152X)   += aha152x_cs.o
 obj-$(CONFIG_PCMCIA_NINJA_SCSI)        += nsp_cs.o
 obj-$(CONFIG_PCMCIA_SYM53C500) += sym53c500_cs.o
diff --git a/drivers/scsi/pcmcia/fdomain_cs.c b/drivers/scsi/pcmcia/fdomain_cs.c
new file mode 100644 (file)
index 0000000..e42acf3
--- /dev/null
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1)
+/*
+ * Driver for Future Domain-compatible PCMCIA SCSI cards
+ * Copyright 2019 Ondrej Zary
+ *
+ * The initial developer of the original 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <scsi/scsi_host.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include "fdomain.h"
+
+MODULE_AUTHOR("Ondrej Zary, David Hinds");
+MODULE_DESCRIPTION("Future Domain PCMCIA SCSI driver");
+MODULE_LICENSE("Dual MPL/GPL");
+
+static int fdomain_config_check(struct pcmcia_device *p_dev, void *priv_data)
+{
+       p_dev->io_lines = 10;
+       p_dev->resource[0]->end = FDOMAIN_REGION_SIZE;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
+       return pcmcia_request_io(p_dev);
+}
+
+static int fdomain_probe(struct pcmcia_device *link)
+{
+       int ret;
+       struct Scsi_Host *sh;
+
+       link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
+       link->config_regs = PRESENT_OPTION;
+
+       ret = pcmcia_loop_config(link, fdomain_config_check, NULL);
+       if (ret)
+               return ret;
+
+       ret = pcmcia_enable_device(link);
+       if (ret)
+               goto fail_disable;
+
+       if (!request_region(link->resource[0]->start, FDOMAIN_REGION_SIZE,
+                           "fdomain_cs"))
+               goto fail_disable;
+
+       sh = fdomain_create(link->resource[0]->start, link->irq, 7, &link->dev);
+       if (!sh) {
+               dev_err(&link->dev, "Controller initialization failed");
+               ret = -ENODEV;
+               goto fail_release;
+       }
+
+       link->priv = sh;
+
+       return 0;
+
+fail_release:
+       release_region(link->resource[0]->start, FDOMAIN_REGION_SIZE);
+fail_disable:
+       pcmcia_disable_device(link);
+       return ret;
+}
+
+static void fdomain_remove(struct pcmcia_device *link)
+{
+       fdomain_destroy(link->priv);
+       release_region(link->resource[0]->start, FDOMAIN_REGION_SIZE);
+       pcmcia_disable_device(link);
+}
+
+static const struct pcmcia_device_id fdomain_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "SCSI PCMCIA Card", 0xe3736c88,
+                               0x859cad20),
+       PCMCIA_DEVICE_PROD_ID1("SCSI PCMCIA Adapter Card", 0x8dacb57e),
+       PCMCIA_DEVICE_PROD_ID12(" SIMPLE TECHNOLOGY Corporation",
+                               "SCSI PCMCIA Credit Card Controller",
+                               0x182bdafe, 0xc80d106f),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, fdomain_ids);
+
+static struct pcmcia_driver fdomain_cs_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "fdomain_cs",
+       .probe          = fdomain_probe,
+       .remove         = fdomain_remove,
+       .id_table       = fdomain_ids,
+};
+
+module_pcmcia_driver(fdomain_cs_driver);
index a81748e..97416e1 100644 (file)
@@ -789,7 +789,7 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt)
                    SCpnt->SCp.buffers_residual != 0 ) {
                        //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out);
                        SCpnt->SCp.buffers_residual--;
-                       SCpnt->SCp.buffer++;
+                       SCpnt->SCp.buffer = sg_next(SCpnt->SCp.buffer);
                        SCpnt->SCp.ptr           = BUFFER_ADDR;
                        SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
                        time_out = 1000;
@@ -887,7 +887,7 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt)
                    SCpnt->SCp.buffers_residual != 0 ) {
                        //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next");
                        SCpnt->SCp.buffers_residual--;
-                       SCpnt->SCp.buffer++;
+                       SCpnt->SCp.buffer = sg_next(SCpnt->SCp.buffer);
                        SCpnt->SCp.ptr           = BUFFER_ADDR;
                        SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
                        time_out = 1000;
index d193961..6b85016 100644 (file)
@@ -461,6 +461,24 @@ static ssize_t pm8001_ctl_bios_version_show(struct device *cdev,
        return str - buf;
 }
 static DEVICE_ATTR(bios_version, S_IRUGO, pm8001_ctl_bios_version_show, NULL);
+/**
+ * event_log_size_show - event log size
+ * @cdev: pointer to embedded class device
+ * @buf: the buffer returned
+ *
+ * A sysfs read  shost attribute.
+ */
+static ssize_t event_log_size_show(struct device *cdev,
+       struct device_attribute *attr, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+       struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+               pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size);
+}
+static DEVICE_ATTR_RO(event_log_size);
 /**
  * pm8001_ctl_aap_log_show - IOP event log
  * @cdev: pointer to embedded class device
@@ -474,25 +492,26 @@ static ssize_t pm8001_ctl_iop_log_show(struct device *cdev,
        struct Scsi_Host *shost = class_to_shost(cdev);
        struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
        struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
-#define IOP_MEMMAP(r, c) \
-       (*(u32 *)((u8*)pm8001_ha->memoryMap.region[IOP].virt_ptr + (r) * 32 \
-       + (c)))
-       int i;
        char *str = buf;
-       int max = 2;
-       for (i = 0; i < max; i++) {
-               str += sprintf(str, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x"
-                              "0x%08x 0x%08x\n",
-                              IOP_MEMMAP(i, 0),
-                              IOP_MEMMAP(i, 4),
-                              IOP_MEMMAP(i, 8),
-                              IOP_MEMMAP(i, 12),
-                              IOP_MEMMAP(i, 16),
-                              IOP_MEMMAP(i, 20),
-                              IOP_MEMMAP(i, 24),
-                              IOP_MEMMAP(i, 28));
+       u32 read_size =
+               pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size / 1024;
+       static u32 start, end, count;
+       u32 max_read_times = 32;
+       u32 max_count = (read_size * 1024) / (max_read_times * 4);
+       u32 *temp = (u32 *)pm8001_ha->memoryMap.region[IOP].virt_ptr;
+
+       if ((count % max_count) == 0) {
+               start = 0;
+               end = max_read_times;
+               count = 0;
+       } else {
+               start = end;
+               end = end + max_read_times;
        }
 
+       for (; start < end; start++)
+               str += sprintf(str, "%08x ", *(temp+start));
+       count++;
        return str - buf;
 }
 static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL);
@@ -796,6 +815,7 @@ struct device_attribute *pm8001_host_attrs[] = {
        &dev_attr_max_sg_list,
        &dev_attr_sas_spec_support,
        &dev_attr_logging_level,
+       &dev_attr_event_log_size,
        &dev_attr_host_sas_address,
        &dev_attr_bios_version,
        &dev_attr_ib_log,
index 109effd..68a8217 100644 (file)
@@ -2356,7 +2356,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
        if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) &&
                (status != IO_UNDERFLOW)) {
                if (!((t->dev->parent) &&
-                       (DEV_IS_EXPANDER(t->dev->parent->dev_type)))) {
+                       (dev_is_expander(t->dev->parent->dev_type)))) {
                        for (i = 0 , j = 4; j <= 7 && i <= 3; i++ , j++)
                                sata_addr_low[i] = pm8001_ha->sas_addr[j];
                        for (i = 0 , j = 0; j <= 3 && i <= 3; i++ , j++)
@@ -4560,7 +4560,7 @@ static int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha,
                        pm8001_dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
                        stp_sspsmp_sata = 0x01; /*ssp or smp*/
        }
-       if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+       if (parent_dev && dev_is_expander(parent_dev->dev_type))
                phy_id = parent_dev->ex_dev.ex_phy->phy_id;
        else
                phy_id = pm8001_dev->attached_phy;
index 88eef3b..dd38c35 100644 (file)
@@ -634,7 +634,7 @@ static int pm8001_dev_found_notify(struct domain_device *dev)
        dev->lldd_dev = pm8001_device;
        pm8001_device->dev_type = dev->dev_type;
        pm8001_device->dcompletion = &completion;
-       if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
+       if (parent_dev && dev_is_expander(parent_dev->dev_type)) {
                int phy_id;
                struct ex_phy *phy;
                for (phy_id = 0; phy_id < parent_dev->ex_dev.num_phys;
@@ -1181,7 +1181,7 @@ int pm8001_query_task(struct sas_task *task)
        return rc;
 }
 
-/*  mandatory SAM-3, still need free task/ccb info, abord the specified task */
+/*  mandatory SAM-3, still need free task/ccb info, abort the specified task */
 int pm8001_abort_task(struct sas_task *task)
 {
        unsigned long flags;
index ac6d8e3..ff17c6a 100644 (file)
@@ -103,7 +103,6 @@ do {                                                \
 #define PM8001_READ_VPD
 
 
-#define DEV_IS_EXPANDER(type)  ((type == SAS_EDGE_EXPANDER_DEVICE) || (type == SAS_FANOUT_EXPANDER_DEVICE))
 #define IS_SPCV_12G(dev)       ((dev->device == 0X8074)                \
                                || (dev->device == 0X8076)              \
                                || (dev->device == 0X8077)              \
index 301de40..1128d86 100644 (file)
@@ -2066,7 +2066,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
        if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) &&
                (status != IO_UNDERFLOW)) {
                if (!((t->dev->parent) &&
-                       (DEV_IS_EXPANDER(t->dev->parent->dev_type)))) {
+                       (dev_is_expander(t->dev->parent->dev_type)))) {
                        for (i = 0 , j = 4; i <= 3 && j <= 7; i++ , j++)
                                sata_addr_low[i] = pm8001_ha->sas_addr[j];
                        for (i = 0 , j = 0; i <= 3 && j <= 3; i++ , j++)
@@ -4561,7 +4561,7 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha,
                        pm8001_dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
                        stp_sspsmp_sata = 0x01; /*ssp or smp*/
        }
-       if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+       if (parent_dev && dev_is_expander(parent_dev->dev_type))
                phy_id = parent_dev->ex_dev.ex_phy->phy_id;
        else
                phy_id = pm8001_dev->attached_phy;
index ca22526..71ff393 100644 (file)
@@ -3255,7 +3255,7 @@ static int pmcraid_copy_sglist(
        int direction
 )
 {
-       struct scatterlist *scatterlist;
+       struct scatterlist *sg;
        void *kaddr;
        int bsize_elem;
        int i;
@@ -3264,10 +3264,10 @@ static int pmcraid_copy_sglist(
        /* Determine the actual number of bytes per element */
        bsize_elem = PAGE_SIZE * (1 << sglist->order);
 
-       scatterlist = sglist->scatterlist;
+       sg = sglist->scatterlist;
 
-       for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) {
-               struct page *page = sg_page(&scatterlist[i]);
+       for (i = 0; i < (len / bsize_elem); i++, sg = sg_next(sg), buffer += bsize_elem) {
+               struct page *page = sg_page(sg);
 
                kaddr = kmap(page);
                if (direction == DMA_TO_DEVICE)
@@ -3282,11 +3282,11 @@ static int pmcraid_copy_sglist(
                        return -EFAULT;
                }
 
-               scatterlist[i].length = bsize_elem;
+               sg->length = bsize_elem;
        }
 
        if (len % bsize_elem) {
-               struct page *page = sg_page(&scatterlist[i]);
+               struct page *page = sg_page(sg);
 
                kaddr = kmap(page);
 
@@ -3297,7 +3297,7 @@ static int pmcraid_copy_sglist(
 
                kunmap(page);
 
-               scatterlist[i].length = len % bsize_elem;
+               sg->length = len % bsize_elem;
        }
 
        if (rc) {
index 3521308..a406cc8 100644 (file)
@@ -590,7 +590,7 @@ static int ppa_completion(struct scsi_cmnd *cmd)
                if (cmd->SCp.buffer && !cmd->SCp.this_residual) {
                        /* if scatter/gather, advance to the next segment */
                        if (cmd->SCp.buffers_residual--) {
-                               cmd->SCp.buffer++;
+                               cmd->SCp.buffer = sg_next(cmd->SCp.buffer);
                                cmd->SCp.this_residual =
                                    cmd->SCp.buffer->length;
                                cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
index 1a4095c..bad2b12 100644 (file)
@@ -532,6 +532,8 @@ typedef struct srb {
        uint8_t cmd_type;
        uint8_t pad[3];
        atomic_t ref_count;
+       struct kref cmd_kref;   /* need to migrate ref_count over to this */
+       void *priv;
        wait_queue_head_t nvme_ls_waitq;
        struct fc_port *fcport;
        struct scsi_qla_host *vha;
@@ -554,6 +556,7 @@ typedef struct srb {
        } u;
        void (*done)(void *, int);
        void (*free)(void *);
+       void (*put_fn)(struct kref *kref);
 } srb_t;
 
 #define GET_CMD_SP(sp) (sp->u.scmd.cmd)
@@ -2336,7 +2339,6 @@ typedef struct fc_port {
        unsigned int id_changed:1;
        unsigned int scan_needed:1;
 
-       struct work_struct nvme_del_work;
        struct completion nvme_del_done;
        uint32_t nvme_prli_service_param;
 #define NVME_PRLI_SP_CONF       BIT_7
@@ -4376,7 +4378,6 @@ typedef struct scsi_qla_host {
 
        struct          nvme_fc_local_port *nvme_local_port;
        struct completion nvme_del_done;
-       struct list_head nvme_rport_list;
 
        uint16_t        fcoe_vlan_id;
        uint16_t        fcoe_fcf_idx;
index bbe69ab..f9669fd 100644 (file)
@@ -908,4 +908,6 @@ void qlt_clr_qp_table(struct scsi_qla_host *vha);
 void qlt_set_mode(struct scsi_qla_host *);
 int qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode);
 
+/* nvme.c */
+void qla_nvme_unregister_remote_port(struct fc_port *fcport);
 #endif /* _QLA_GBL_H */
index 54772d4..4059655 100644 (file)
@@ -5403,7 +5403,6 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
        fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
        fcport->deleted = 0;
        fcport->logout_on_delete = 1;
-       fcport->login_retry = vha->hw->login_retry_count;
        fcport->n2n_chip_reset = fcport->n2n_link_reset_cnt = 0;
 
        switch (vha->hw->current_topology) {
index 22e3fba..963094b 100644 (file)
@@ -12,8 +12,6 @@
 
 static struct nvme_fc_port_template qla_nvme_fc_transport;
 
-static void qla_nvme_unregister_remote_port(struct work_struct *);
-
 int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport)
 {
        struct qla_nvme_rport *rport;
@@ -38,7 +36,6 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport)
                (fcport->nvme_flag & NVME_FLAG_REGISTERED))
                return 0;
 
-       INIT_WORK(&fcport->nvme_del_work, qla_nvme_unregister_remote_port);
        fcport->nvme_flag &= ~NVME_FLAG_RESETTING;
 
        memset(&req, 0, sizeof(struct nvme_fc_port_info));
@@ -74,7 +71,6 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport)
 
        rport = fcport->nvme_remote_port->private;
        rport->fcport = fcport;
-       list_add_tail(&rport->list, &vha->nvme_rport_list);
 
        fcport->nvme_flag |= NVME_FLAG_REGISTERED;
        return 0;
@@ -124,53 +120,91 @@ static int qla_nvme_alloc_queue(struct nvme_fc_local_port *lport,
        return 0;
 }
 
+static void qla_nvme_release_fcp_cmd_kref(struct kref *kref)
+{
+       struct srb *sp = container_of(kref, struct srb, cmd_kref);
+       struct nvme_private *priv = (struct nvme_private *)sp->priv;
+       struct nvmefc_fcp_req *fd;
+       struct srb_iocb *nvme;
+       unsigned long flags;
+
+       if (!priv)
+               goto out;
+
+       nvme = &sp->u.iocb_cmd;
+       fd = nvme->u.nvme.desc;
+
+       spin_lock_irqsave(&priv->cmd_lock, flags);
+       priv->sp = NULL;
+       sp->priv = NULL;
+       if (priv->comp_status == QLA_SUCCESS) {
+               fd->rcv_rsplen = nvme->u.nvme.rsp_pyld_len;
+       } else {
+               fd->rcv_rsplen = 0;
+               fd->transferred_length = 0;
+       }
+       fd->status = 0;
+       spin_unlock_irqrestore(&priv->cmd_lock, flags);
+
+       fd->done(fd);
+out:
+       qla2xxx_rel_qpair_sp(sp->qpair, sp);
+}
+
+static void qla_nvme_release_ls_cmd_kref(struct kref *kref)
+{
+       struct srb *sp = container_of(kref, struct srb, cmd_kref);
+       struct nvme_private *priv = (struct nvme_private *)sp->priv;
+       struct nvmefc_ls_req *fd;
+       unsigned long flags;
+
+       if (!priv)
+               goto out;
+
+       spin_lock_irqsave(&priv->cmd_lock, flags);
+       priv->sp = NULL;
+       sp->priv = NULL;
+       spin_unlock_irqrestore(&priv->cmd_lock, flags);
+
+       fd = priv->fd;
+       fd->done(fd, priv->comp_status);
+out:
+       qla2x00_rel_sp(sp);
+}
+
+static void qla_nvme_ls_complete(struct work_struct *work)
+{
+       struct nvme_private *priv =
+               container_of(work, struct nvme_private, ls_work);
+
+       kref_put(&priv->sp->cmd_kref, qla_nvme_release_ls_cmd_kref);
+}
+
 static void qla_nvme_sp_ls_done(void *ptr, int res)
 {
        srb_t *sp = ptr;
-       struct srb_iocb *nvme;
-       struct nvmefc_ls_req   *fd;
        struct nvme_private *priv;
 
-       if (WARN_ON_ONCE(atomic_read(&sp->ref_count) == 0))
+       if (WARN_ON_ONCE(kref_read(&sp->cmd_kref) == 0))
                return;
 
-       atomic_dec(&sp->ref_count);
-
        if (res)
                res = -EINVAL;
 
-       nvme = &sp->u.iocb_cmd;
-       fd = nvme->u.nvme.desc;
-       priv = fd->private;
+       priv = (struct nvme_private *)sp->priv;
        priv->comp_status = res;
+       INIT_WORK(&priv->ls_work, qla_nvme_ls_complete);
        schedule_work(&priv->ls_work);
-       /* work schedule doesn't need the sp */
-       qla2x00_rel_sp(sp);
 }
 
+/* it assumed that QPair lock is held. */
 static void qla_nvme_sp_done(void *ptr, int res)
 {
        srb_t *sp = ptr;
-       struct srb_iocb *nvme;
-       struct nvmefc_fcp_req *fd;
-
-       nvme = &sp->u.iocb_cmd;
-       fd = nvme->u.nvme.desc;
-
-       if (WARN_ON_ONCE(atomic_read(&sp->ref_count) == 0))
-               return;
+       struct nvme_private *priv = (struct nvme_private *)sp->priv;
 
-       atomic_dec(&sp->ref_count);
-
-       if (res == QLA_SUCCESS) {
-               fd->rcv_rsplen = nvme->u.nvme.rsp_pyld_len;
-       } else {
-               fd->rcv_rsplen = 0;
-               fd->transferred_length = 0;
-       }
-       fd->status = 0;
-       fd->done(fd);
-       qla2xxx_rel_qpair_sp(sp->qpair, sp);
+       priv->comp_status = res;
+       kref_put(&sp->cmd_kref, qla_nvme_release_fcp_cmd_kref);
 
        return;
 }
@@ -189,44 +223,50 @@ static void qla_nvme_abort_work(struct work_struct *work)
               __func__, sp, sp->handle, fcport, fcport->deleted);
 
        if (!ha->flags.fw_started && (fcport && fcport->deleted))
-               return;
+               goto out;
 
        if (ha->flags.host_shutting_down) {
                ql_log(ql_log_info, sp->fcport->vha, 0xffff,
                    "%s Calling done on sp: %p, type: 0x%x, sp->ref_count: 0x%x\n",
                    __func__, sp, sp->type, atomic_read(&sp->ref_count));
                sp->done(sp, 0);
-               return;
+               goto out;
        }
 
-       if (WARN_ON_ONCE(atomic_read(&sp->ref_count) == 0))
-               return;
-
        rval = ha->isp_ops->abort_command(sp);
 
        ql_dbg(ql_dbg_io, fcport->vha, 0x212b,
            "%s: %s command for sp=%p, handle=%x on fcport=%p rval=%x\n",
            __func__, (rval != QLA_SUCCESS) ? "Failed to abort" : "Aborted",
            sp, sp->handle, fcport, rval);
+
+out:
+       /* kref_get was done before work was schedule. */
+       kref_put(&sp->cmd_kref, sp->put_fn);
 }
 
 static void qla_nvme_ls_abort(struct nvme_fc_local_port *lport,
     struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd)
 {
        struct nvme_private *priv = fd->private;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->cmd_lock, flags);
+       if (!priv->sp) {
+               spin_unlock_irqrestore(&priv->cmd_lock, flags);
+               return;
+       }
+
+       if (!kref_get_unless_zero(&priv->sp->cmd_kref)) {
+               spin_unlock_irqrestore(&priv->cmd_lock, flags);
+               return;
+       }
+       spin_unlock_irqrestore(&priv->cmd_lock, flags);
 
        INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
        schedule_work(&priv->abort_work);
 }
 
-static void qla_nvme_ls_complete(struct work_struct *work)
-{
-       struct nvme_private *priv =
-           container_of(work, struct nvme_private, ls_work);
-       struct nvmefc_ls_req *fd = priv->fd;
-
-       fd->done(fd, priv->comp_status);
-}
 
 static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
     struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd)
@@ -240,8 +280,16 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
        struct qla_hw_data *ha;
        srb_t           *sp;
 
+
+       if (!fcport || (fcport && fcport->deleted))
+               return rval;
+
        vha = fcport->vha;
        ha = vha->hw;
+
+       if (!ha->flags.fw_started)
+               return rval;
+
        /* Alloc SRB structure */
        sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC);
        if (!sp)
@@ -250,11 +298,13 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
        sp->type = SRB_NVME_LS;
        sp->name = "nvme_ls";
        sp->done = qla_nvme_sp_ls_done;
-       atomic_set(&sp->ref_count, 1);
-       nvme = &sp->u.iocb_cmd;
+       sp->put_fn = qla_nvme_release_ls_cmd_kref;
+       sp->priv = (void *)priv;
        priv->sp = sp;
+       kref_init(&sp->cmd_kref);
+       spin_lock_init(&priv->cmd_lock);
+       nvme = &sp->u.iocb_cmd;
        priv->fd = fd;
-       INIT_WORK(&priv->ls_work, qla_nvme_ls_complete);
        nvme->u.nvme.desc = fd;
        nvme->u.nvme.dir = 0;
        nvme->u.nvme.dl = 0;
@@ -271,8 +321,10 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
        if (rval != QLA_SUCCESS) {
                ql_log(ql_log_warn, vha, 0x700e,
                    "qla2x00_start_sp failed = %d\n", rval);
-               atomic_dec(&sp->ref_count);
                wake_up(&sp->nvme_ls_waitq);
+               sp->priv = NULL;
+               priv->sp = NULL;
+               qla2x00_rel_sp(sp);
                return rval;
        }
 
@@ -284,6 +336,18 @@ static void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport,
     struct nvmefc_fcp_req *fd)
 {
        struct nvme_private *priv = fd->private;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->cmd_lock, flags);
+       if (!priv->sp) {
+               spin_unlock_irqrestore(&priv->cmd_lock, flags);
+               return;
+       }
+       if (!kref_get_unless_zero(&priv->sp->cmd_kref)) {
+               spin_unlock_irqrestore(&priv->cmd_lock, flags);
+               return;
+       }
+       spin_unlock_irqrestore(&priv->cmd_lock, flags);
 
        INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
        schedule_work(&priv->abort_work);
@@ -487,11 +551,11 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
 
        fcport = qla_rport->fcport;
 
-       vha = fcport->vha;
-
-       if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))
+       if (!qpair || !fcport || (qpair && !qpair->fw_started) ||
+           (fcport && fcport->deleted))
                return rval;
 
+       vha = fcport->vha;
        /*
         * If we know the dev is going away while the transport is still sending
         * IO's return busy back to stall the IO Q.  This happens when the
@@ -507,12 +571,15 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
        if (!sp)
                return -EBUSY;
 
-       atomic_set(&sp->ref_count, 1);
        init_waitqueue_head(&sp->nvme_ls_waitq);
+       kref_init(&sp->cmd_kref);
+       spin_lock_init(&priv->cmd_lock);
+       sp->priv = (void *)priv;
        priv->sp = sp;
        sp->type = SRB_NVME_CMD;
        sp->name = "nvme_cmd";
        sp->done = qla_nvme_sp_done;
+       sp->put_fn = qla_nvme_release_fcp_cmd_kref;
        sp->qpair = qpair;
        sp->vha = vha;
        nvme = &sp->u.iocb_cmd;
@@ -522,8 +589,10 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
        if (rval != QLA_SUCCESS) {
                ql_log(ql_log_warn, vha, 0x212d,
                    "qla2x00_start_nvme_mq failed = %d\n", rval);
-               atomic_dec(&sp->ref_count);
                wake_up(&sp->nvme_ls_waitq);
+               sp->priv = NULL;
+               priv->sp = NULL;
+               qla2xxx_rel_qpair_sp(sp->qpair, sp);
        }
 
        return rval;
@@ -542,29 +611,16 @@ static void qla_nvme_localport_delete(struct nvme_fc_local_port *lport)
 static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport)
 {
        fc_port_t *fcport;
-       struct qla_nvme_rport *qla_rport = rport->private, *trport;
+       struct qla_nvme_rport *qla_rport = rport->private;
 
        fcport = qla_rport->fcport;
        fcport->nvme_remote_port = NULL;
        fcport->nvme_flag &= ~NVME_FLAG_REGISTERED;
-
-       list_for_each_entry_safe(qla_rport, trport,
-           &fcport->vha->nvme_rport_list, list) {
-               if (qla_rport->fcport == fcport) {
-                       list_del(&qla_rport->list);
-                       break;
-               }
-       }
-       complete(&fcport->nvme_del_done);
-
-       if (!test_bit(UNLOADING, &fcport->vha->dpc_flags)) {
-               INIT_WORK(&fcport->free_work, qlt_free_session_done);
-               schedule_work(&fcport->free_work);
-       }
-
        fcport->nvme_flag &= ~NVME_FLAG_DELETING;
        ql_log(ql_log_info, fcport->vha, 0x2110,
-           "remoteport_delete of %p completed.\n", fcport);
+           "remoteport_delete of %p %8phN completed.\n",
+           fcport, fcport->port_name);
+       complete(&fcport->nvme_del_done);
 }
 
 static struct nvme_fc_port_template qla_nvme_fc_transport = {
@@ -586,35 +642,25 @@ static struct nvme_fc_port_template qla_nvme_fc_transport = {
        .fcprqst_priv_sz = sizeof(struct nvme_private),
 };
 
-static void qla_nvme_unregister_remote_port(struct work_struct *work)
+void qla_nvme_unregister_remote_port(struct fc_port *fcport)
 {
-       struct fc_port *fcport = container_of(work, struct fc_port,
-           nvme_del_work);
-       struct qla_nvme_rport *qla_rport, *trport;
+       int ret;
 
        if (!IS_ENABLED(CONFIG_NVME_FC))
                return;
 
        ql_log(ql_log_warn, NULL, 0x2112,
-           "%s: unregister remoteport on %p\n",__func__, fcport);
-
-       list_for_each_entry_safe(qla_rport, trport,
-           &fcport->vha->nvme_rport_list, list) {
-               if (qla_rport->fcport == fcport) {
-                       ql_log(ql_log_info, fcport->vha, 0x2113,
-                           "%s: fcport=%p\n", __func__, fcport);
-                       nvme_fc_set_remoteport_devloss
-                               (fcport->nvme_remote_port, 0);
-                       init_completion(&fcport->nvme_del_done);
-                       if (nvme_fc_unregister_remoteport
-                           (fcport->nvme_remote_port))
-                               ql_log(ql_log_info, fcport->vha, 0x2114,
-                                   "%s: Failed to unregister nvme_remote_port\n",
-                                   __func__);
-                       wait_for_completion(&fcport->nvme_del_done);
-                       break;
-               }
-       }
+           "%s: unregister remoteport on %p %8phN\n",
+           __func__, fcport, fcport->port_name);
+
+       nvme_fc_set_remoteport_devloss(fcport->nvme_remote_port, 0);
+       init_completion(&fcport->nvme_del_done);
+       ret = nvme_fc_unregister_remoteport(fcport->nvme_remote_port);
+       if (ret)
+               ql_log(ql_log_info, fcport->vha, 0x2114,
+                       "%s: Failed to unregister nvme_remote_port (%d)\n",
+                           __func__, ret);
+       wait_for_completion(&fcport->nvme_del_done);
 }
 
 void qla_nvme_delete(struct scsi_qla_host *vha)
index d3b8a64..67bb4a2 100644 (file)
@@ -34,10 +34,10 @@ struct nvme_private {
        struct work_struct ls_work;
        struct work_struct abort_work;
        int comp_status;
+       spinlock_t cmd_lock;
 };
 
 struct qla_nvme_rport {
-       struct list_head list;
        struct fc_port *fcport;
 };
 
index d056f5e..2e58cff 100644 (file)
@@ -4789,7 +4789,6 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
        INIT_LIST_HEAD(&vha->plogi_ack_list);
        INIT_LIST_HEAD(&vha->qp_list);
        INIT_LIST_HEAD(&vha->gnl.fcports);
-       INIT_LIST_HEAD(&vha->nvme_rport_list);
        INIT_LIST_HEAD(&vha->gpnid_list);
        INIT_WORK(&vha->iocb_work, qla2x00_iocb_work_fn);
 
index 2fd5c09..1c1f63b 100644 (file)
@@ -1004,6 +1004,12 @@ void qlt_free_session_done(struct work_struct *work)
                                else
                                        logout_started = true;
                        }
+               } /* if sess->logout_on_delete */
+
+               if (sess->nvme_flag & NVME_FLAG_REGISTERED &&
+                   !(sess->nvme_flag & NVME_FLAG_DELETING)) {
+                       sess->nvme_flag |= NVME_FLAG_DELETING;
+                       qla_nvme_unregister_remote_port(sess);
                }
        }
 
@@ -1155,14 +1161,8 @@ void qlt_unreg_sess(struct fc_port *sess)
        sess->last_rscn_gen = sess->rscn_gen;
        sess->last_login_gen = sess->login_gen;
 
-       if (sess->nvme_flag & NVME_FLAG_REGISTERED &&
-           !(sess->nvme_flag & NVME_FLAG_DELETING)) {
-               sess->nvme_flag |= NVME_FLAG_DELETING;
-               schedule_work(&sess->nvme_del_work);
-       } else {
-               INIT_WORK(&sess->free_work, qlt_free_session_done);
-               schedule_work(&sess->free_work);
-       }
+       INIT_WORK(&sess->free_work, qlt_free_session_done);
+       schedule_work(&sess->free_work);
 }
 EXPORT_SYMBOL(qlt_unreg_sess);
 
index 653d5ea..1f5b5c8 100644 (file)
@@ -86,15 +86,10 @@ unsigned int scsi_logging_level;
 EXPORT_SYMBOL(scsi_logging_level);
 #endif
 
-/* sd, scsi core and power management need to coordinate flushing async actions */
-ASYNC_DOMAIN(scsi_sd_probe_domain);
-EXPORT_SYMBOL(scsi_sd_probe_domain);
-
 /*
- * Separate domain (from scsi_sd_probe_domain) to maximize the benefit of
- * asynchronous system resume operations.  It is marked 'exclusive' to avoid
- * being included in the async_synchronize_full() that is invoked by
- * dpm_resume()
+ * Domain for asynchronous system resume operations.  It is marked 'exclusive'
+ * to avoid being included in the async_synchronize_full() that is invoked by
+ * dpm_resume().
  */
 ASYNC_DOMAIN_EXCLUSIVE(scsi_sd_pm_domain);
 EXPORT_SYMBOL(scsi_sd_pm_domain);
@@ -821,7 +816,6 @@ static void __exit exit_scsi(void)
        scsi_exit_devinfo();
        scsi_exit_procfs();
        scsi_exit_queue();
-       async_unregister_domain(&scsi_sd_probe_domain);
 }
 
 subsys_initcall(init_scsi);
index 951b043..d125d1b 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 struct request;
 struct seq_file;
 
index bfa569f..1c470e3 100644 (file)
@@ -1055,7 +1055,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
        struct scsi_device *sdev = scmd->device;
        struct Scsi_Host *shost = sdev->host;
        DECLARE_COMPLETION_ONSTACK(done);
-       unsigned long timeleft = timeout;
+       unsigned long timeleft = timeout, delay;
        struct scsi_eh_save ses;
        const unsigned long stall_for = msecs_to_jiffies(100);
        int rtn;
@@ -1066,7 +1066,29 @@ retry:
 
        scsi_log_send(scmd);
        scmd->scsi_done = scsi_eh_done;
-       rtn = shost->hostt->queuecommand(shost, scmd);
+
+       /*
+        * Lock sdev->state_mutex to avoid that scsi_device_quiesce() can
+        * change the SCSI device state after we have examined it and before
+        * .queuecommand() is called.
+        */
+       mutex_lock(&sdev->state_mutex);
+       while (sdev->sdev_state == SDEV_BLOCK && timeleft > 0) {
+               mutex_unlock(&sdev->state_mutex);
+               SCSI_LOG_ERROR_RECOVERY(5, sdev_printk(KERN_DEBUG, sdev,
+                       "%s: state %d <> %d\n", __func__, sdev->sdev_state,
+                       SDEV_BLOCK));
+               delay = min(timeleft, stall_for);
+               timeleft -= delay;
+               msleep(jiffies_to_msecs(delay));
+               mutex_lock(&sdev->state_mutex);
+       }
+       if (sdev->sdev_state != SDEV_BLOCK)
+               rtn = shost->hostt->queuecommand(shost, scmd);
+       else
+               rtn = SCSI_MLQUEUE_DEVICE_BUSY;
+       mutex_unlock(&sdev->state_mutex);
+
        if (rtn) {
                if (timeleft > stall_for) {
                        scsi_eh_restore_cmnd(scmd, &ses);
index 65d0a10..e1da8c7 100644 (file)
 #include "scsi_priv.h"
 #include "scsi_logging.h"
 
+/*
+ * Size of integrity metadata is usually small, 1 inline sg should
+ * cover normal cases.
+ */
+#ifdef CONFIG_ARCH_NO_SG_CHAIN
+#define  SCSI_INLINE_PROT_SG_CNT  0
+#define  SCSI_INLINE_SG_CNT  0
+#else
+#define  SCSI_INLINE_PROT_SG_CNT  1
+#define  SCSI_INLINE_SG_CNT  2
+#endif
+
 static struct kmem_cache *scsi_sdb_cache;
 static struct kmem_cache *scsi_sense_cache;
 static struct kmem_cache *scsi_sense_isadma_cache;
@@ -542,9 +554,11 @@ static void scsi_uninit_cmd(struct scsi_cmnd *cmd)
 static void scsi_mq_free_sgtables(struct scsi_cmnd *cmd)
 {
        if (cmd->sdb.table.nents)
-               sg_free_table_chained(&cmd->sdb.table, true);
+               sg_free_table_chained(&cmd->sdb.table,
+                               SCSI_INLINE_SG_CNT);
        if (scsi_prot_sg_count(cmd))
-               sg_free_table_chained(&cmd->prot_sdb->table, true);
+               sg_free_table_chained(&cmd->prot_sdb->table,
+                               SCSI_INLINE_PROT_SG_CNT);
 }
 
 static void scsi_mq_uninit_cmd(struct scsi_cmnd *cmd)
@@ -977,7 +991,8 @@ static blk_status_t scsi_init_sgtable(struct request *req,
         * If sg table allocation fails, requeue request later.
         */
        if (unlikely(sg_alloc_table_chained(&sdb->table,
-                       blk_rq_nr_phys_segments(req), sdb->table.sgl)))
+                       blk_rq_nr_phys_segments(req), sdb->table.sgl,
+                       SCSI_INLINE_SG_CNT)))
                return BLK_STS_RESOURCE;
 
        /* 
@@ -1031,7 +1046,8 @@ blk_status_t scsi_init_io(struct scsi_cmnd *cmd)
                ivecs = blk_rq_count_integrity_sg(rq->q, rq->bio);
 
                if (sg_alloc_table_chained(&prot_sdb->table, ivecs,
-                               prot_sdb->table.sgl)) {
+                               prot_sdb->table.sgl,
+                               SCSI_INLINE_PROT_SG_CNT)) {
                        ret = BLK_STS_RESOURCE;
                        goto out_free_sgtables;
                }
@@ -1542,9 +1558,9 @@ static int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 }
 
 /* Size in bytes of the sg-list stored in the scsi-mq command-private data. */
-static unsigned int scsi_mq_sgl_size(struct Scsi_Host *shost)
+static unsigned int scsi_mq_inline_sgl_size(struct Scsi_Host *shost)
 {
-       return min_t(unsigned int, shost->sg_tablesize, SG_CHUNK_SIZE) *
+       return min_t(unsigned int, shost->sg_tablesize, SCSI_INLINE_SG_CNT) *
                sizeof(struct scatterlist);
 }
 
@@ -1726,7 +1742,7 @@ static int scsi_mq_init_request(struct blk_mq_tag_set *set, struct request *rq,
        if (scsi_host_get_prot(shost)) {
                sg = (void *)cmd + sizeof(struct scsi_cmnd) +
                        shost->hostt->cmd_size;
-               cmd->prot_sdb = (void *)sg + scsi_mq_sgl_size(shost);
+               cmd->prot_sdb = (void *)sg + scsi_mq_inline_sgl_size(shost);
        }
 
        return 0;
@@ -1820,10 +1836,11 @@ int scsi_mq_setup_tags(struct Scsi_Host *shost)
 {
        unsigned int cmd_size, sgl_size;
 
-       sgl_size = scsi_mq_sgl_size(shost);
+       sgl_size = scsi_mq_inline_sgl_size(shost);
        cmd_size = sizeof(struct scsi_cmnd) + shost->hostt->cmd_size + sgl_size;
        if (scsi_host_get_prot(shost))
-               cmd_size += sizeof(struct scsi_data_buffer) + sgl_size;
+               cmd_size += sizeof(struct scsi_data_buffer) +
+                       sizeof(struct scatterlist) * SCSI_INLINE_PROT_SG_CNT;
 
        memset(&shost->tag_set, 0, sizeof(shost->tag_set));
        shost->tag_set.ops = &scsi_mq_ops;
@@ -2616,10 +2633,6 @@ EXPORT_SYMBOL_GPL(scsi_internal_device_block_nowait);
  * a legal transition). When the device is in this state, command processing
  * is paused until the device leaves the SDEV_BLOCK state. See also
  * scsi_internal_device_unblock().
- *
- * To do: avoid that scsi_send_eh_cmnd() calls queuecommand() after
- * scsi_internal_device_block() has blocked a SCSI device and also
- * remove the rport mutex lock and unlock calls from srp_queuecommand().
  */
 static int scsi_internal_device_block(struct scsi_device *sdev)
 {
index 48ee680..74ded5f 100644 (file)
@@ -176,11 +176,7 @@ static int scsi_bus_resume_common(struct device *dev,
 
 static int scsi_bus_prepare(struct device *dev)
 {
-       if (scsi_is_sdev_device(dev)) {
-               /* sd probing uses async_schedule.  Wait until it finishes. */
-               async_synchronize_full_domain(&scsi_sd_probe_domain);
-
-       } else if (scsi_is_host_device(dev)) {
+       if (scsi_is_host_device(dev)) {
                /* Wait until async scanning is finished */
                scsi_complete_async_scans();
        }
index 5f21547..cc2859d 100644 (file)
@@ -175,7 +175,6 @@ static inline void scsi_autopm_put_host(struct Scsi_Host *h) {}
 #endif /* CONFIG_PM */
 
 extern struct async_domain scsi_sd_pm_domain;
-extern struct async_domain scsi_sd_probe_domain;
 
 /* scsi_dh.c */
 #ifdef CONFIG_SCSI_DH
index 7f0ceb6..c074631 100644 (file)
@@ -372,7 +372,7 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
        return err;
 }
 
-static int always_match(struct device *dev, void *data)
+static int always_match(struct device *dev, const void *data)
 {
        return 1;
 }
index dbb206c..64c96c7 100644 (file)
@@ -767,8 +767,13 @@ store_state_field(struct device *dev, struct device_attribute *attr,
                        break;
                }
        }
-       if (!state)
+       switch (state) {
+       case SDEV_RUNNING:
+       case SDEV_OFFLINE:
+               break;
+       default:
                return -EINVAL;
+       }
 
        mutex_lock(&sdev->state_mutex);
        ret = scsi_device_set_state(sdev, state);
index 118a687..2732fa6 100644 (file)
@@ -3,9 +3,6 @@
  *  FiberChannel transport specific attributes exported to sysfs.
  *
  *  Copyright (c) 2003 Silicon Graphics, Inc.  All rights reserved.
- *
- *  ========
- *
  *  Copyright (C) 2004-2007   James Smart, Emulex Corporation
  *    Rewrite for host, target, device, and remote port attributes,
  *    statistics, and service functions...
index a3406bd..149d406 100644 (file)
@@ -568,6 +568,7 @@ static struct scsi_driver sd_template = {
                .name           = "sd",
                .owner          = THIS_MODULE,
                .probe          = sd_probe,
+               .probe_type     = PROBE_PREFER_ASYNCHRONOUS,
                .remove         = sd_remove,
                .shutdown       = sd_shutdown,
                .pm             = &sd_pm_ops,
@@ -3252,69 +3253,6 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen)
        return 0;
 }
 
-/*
- * The asynchronous part of sd_probe
- */
-static void sd_probe_async(void *data, async_cookie_t cookie)
-{
-       struct scsi_disk *sdkp = data;
-       struct scsi_device *sdp;
-       struct gendisk *gd;
-       u32 index;
-       struct device *dev;
-
-       sdp = sdkp->device;
-       gd = sdkp->disk;
-       index = sdkp->index;
-       dev = &sdp->sdev_gendev;
-
-       gd->major = sd_major((index & 0xf0) >> 4);
-       gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
-
-       gd->fops = &sd_fops;
-       gd->private_data = &sdkp->driver;
-       gd->queue = sdkp->device->request_queue;
-
-       /* defaults, until the device tells us otherwise */
-       sdp->sector_size = 512;
-       sdkp->capacity = 0;
-       sdkp->media_present = 1;
-       sdkp->write_prot = 0;
-       sdkp->cache_override = 0;
-       sdkp->WCE = 0;
-       sdkp->RCD = 0;
-       sdkp->ATO = 0;
-       sdkp->first_scan = 1;
-       sdkp->max_medium_access_timeouts = SD_MAX_MEDIUM_TIMEOUTS;
-
-       sd_revalidate_disk(gd);
-
-       gd->flags = GENHD_FL_EXT_DEVT;
-       if (sdp->removable) {
-               gd->flags |= GENHD_FL_REMOVABLE;
-               gd->events |= DISK_EVENT_MEDIA_CHANGE;
-               gd->event_flags = DISK_EVENT_FLAG_POLL | DISK_EVENT_FLAG_UEVENT;
-       }
-
-       blk_pm_runtime_init(sdp->request_queue, dev);
-       device_add_disk(dev, gd, NULL);
-       if (sdkp->capacity)
-               sd_dif_config_host(sdkp);
-
-       sd_revalidate_disk(gd);
-
-       if (sdkp->security) {
-               sdkp->opal_dev = init_opal_dev(sdp, &sd_sec_submit);
-               if (sdkp->opal_dev)
-                       sd_printk(KERN_NOTICE, sdkp, "supports TCG Opal\n");
-       }
-
-       sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
-                 sdp->removable ? "removable " : "");
-       scsi_autopm_put_device(sdp);
-       put_device(&sdkp->dev);
-}
-
 /**
  *     sd_probe - called during driver initialization and whenever a
  *     new scsi device is attached to the system. It is called once
@@ -3404,8 +3342,50 @@ static int sd_probe(struct device *dev)
        get_device(dev);
        dev_set_drvdata(dev, sdkp);
 
-       get_device(&sdkp->dev); /* prevent release before async_schedule */
-       async_schedule_domain(sd_probe_async, sdkp, &scsi_sd_probe_domain);
+       gd->major = sd_major((index & 0xf0) >> 4);
+       gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
+
+       gd->fops = &sd_fops;
+       gd->private_data = &sdkp->driver;
+       gd->queue = sdkp->device->request_queue;
+
+       /* defaults, until the device tells us otherwise */
+       sdp->sector_size = 512;
+       sdkp->capacity = 0;
+       sdkp->media_present = 1;
+       sdkp->write_prot = 0;
+       sdkp->cache_override = 0;
+       sdkp->WCE = 0;
+       sdkp->RCD = 0;
+       sdkp->ATO = 0;
+       sdkp->first_scan = 1;
+       sdkp->max_medium_access_timeouts = SD_MAX_MEDIUM_TIMEOUTS;
+
+       sd_revalidate_disk(gd);
+
+       gd->flags = GENHD_FL_EXT_DEVT;
+       if (sdp->removable) {
+               gd->flags |= GENHD_FL_REMOVABLE;
+               gd->events |= DISK_EVENT_MEDIA_CHANGE;
+               gd->event_flags = DISK_EVENT_FLAG_POLL | DISK_EVENT_FLAG_UEVENT;
+       }
+
+       blk_pm_runtime_init(sdp->request_queue, dev);
+       device_add_disk(dev, gd, NULL);
+       if (sdkp->capacity)
+               sd_dif_config_host(sdkp);
+
+       sd_revalidate_disk(gd);
+
+       if (sdkp->security) {
+               sdkp->opal_dev = init_opal_dev(sdp, &sd_sec_submit);
+               if (sdkp->opal_dev)
+                       sd_printk(KERN_NOTICE, sdkp, "supports TCG Opal\n");
+       }
+
+       sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
+                 sdp->removable ? "removable " : "");
+       scsi_autopm_put_device(sdp);
 
        return 0;
 
@@ -3441,7 +3421,6 @@ static int sd_remove(struct device *dev)
        scsi_autopm_get_device(sdkp->device);
 
        async_synchronize_full_domain(&scsi_sd_pm_domain);
-       async_synchronize_full_domain(&scsi_sd_probe_domain);
        device_del(&sdkp->dev);
        del_gendisk(sdkp->disk);
        sd_shutdown(dev);
index 60f01a7..c2afba2 100644 (file)
@@ -3,12 +3,7 @@
  * SCSI Enclosure Services
  *
  * Copyright (C) 2008 James Bottomley <James.Bottomley@HansenPartnership.com>
- *
-**-----------------------------------------------------------------------------
-**
-**
-**-----------------------------------------------------------------------------
-*/
+ */
 
 #include <linux/slab.h>
 #include <linux/module.h>
index baada5b..e3266a6 100644 (file)
@@ -228,7 +228,6 @@ static DEFINE_IDR(st_index_idr);
 
 
 \f
-#include "osst_detect.h"
 #ifndef SIGS_FROM_OSST
 #define SIGS_FROM_OSST \
        {"OnStream", "SC-", "", "osst"}, \
@@ -4267,9 +4266,10 @@ static int st_probe(struct device *dev)
        if (SDp->type != TYPE_TAPE)
                return -ENODEV;
        if ((stp = st_incompatible(SDp))) {
-               sdev_printk(KERN_INFO, SDp, "Found incompatible tape\n");
                sdev_printk(KERN_INFO, SDp,
-                           "st: The suggested driver is %s.\n", stp);
+                           "OnStream tapes are no longer supported;\n");
+               sdev_printk(KERN_INFO, SDp,
+                           "please mail to linux-scsi@vger.kernel.org.\n");
                return -ENODEV;
        }
 
index b892691..c2b6a0c 100644 (file)
@@ -375,6 +375,7 @@ enum storvsc_request_type {
 
 static int storvsc_ringbuffer_size = (128 * 1024);
 static u32 max_outstanding_req_per_channel;
+static int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth);
 
 static int storvsc_vcpus_per_sub_channel = 4;
 
@@ -1699,6 +1700,7 @@ static struct scsi_host_template scsi_driver = {
        .dma_boundary =         PAGE_SIZE-1,
        .no_write_same =        1,
        .track_queue_depth =    1,
+       .change_queue_depth =   storvsc_change_queue_depth,
 };
 
 enum {
@@ -1905,6 +1907,15 @@ err_out0:
        return ret;
 }
 
+/* Change a scsi target's queue depth */
+static int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth)
+{
+       if (queue_depth > scsi_driver.can_queue)
+               queue_depth = scsi_driver.can_queue;
+
+       return scsi_change_queue_depth(sdev, queue_depth);
+}
+
 static int storvsc_remove(struct hv_device *dev)
 {
        struct storvsc_device *stor_device = hv_get_drvdata(dev);
index b4d1b5c..ee4b1da 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (c) 2013-2016, Linux Foundation. All rights reserved.
  */
 
+#include <linux/acpi.h>
 #include <linux/time.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
@@ -161,6 +162,9 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host)
        int err = 0;
        struct device *dev = host->hba->dev;
 
+       if (has_acpi_companion(dev))
+               return 0;
+
        err = ufs_qcom_host_clk_get(dev, "rx_lane0_sync_clk",
                                        &host->rx_l0_sync_clk, false);
        if (err)
@@ -1127,9 +1131,13 @@ static int ufs_qcom_init(struct ufs_hba *hba)
                        __func__, err);
                goto out_variant_clear;
        } else if (IS_ERR(host->generic_phy)) {
-               err = PTR_ERR(host->generic_phy);
-               dev_err(dev, "%s: PHY get failed %d\n", __func__, err);
-               goto out_variant_clear;
+               if (has_acpi_companion(dev)) {
+                       host->generic_phy = NULL;
+               } else {
+                       err = PTR_ERR(host->generic_phy);
+                       dev_err(dev, "%s: PHY get failed %d\n", __func__, err);
+                       goto out_variant_clear;
+               }
        }
 
        err = ufs_qcom_bus_register(host);
@@ -1599,6 +1607,14 @@ static const struct of_device_id ufs_qcom_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, ufs_qcom_of_match);
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id ufs_qcom_acpi_match[] = {
+       { "QCOM24A5" },
+       { },
+};
+MODULE_DEVICE_TABLE(acpi, ufs_qcom_acpi_match);
+#endif
+
 static const struct dev_pm_ops ufs_qcom_pm_ops = {
        .suspend        = ufshcd_pltfrm_suspend,
        .resume         = ufshcd_pltfrm_resume,
@@ -1615,6 +1631,7 @@ static struct platform_driver ufs_qcom_pltform = {
                .name   = "ufshcd-qcom",
                .pm     = &ufs_qcom_pm_ops,
                .of_match_table = of_match_ptr(ufs_qcom_of_match),
+               .acpi_match_table = ACPI_PTR(ufs_qcom_acpi_match),
        },
 };
 module_platform_driver(ufs_qcom_pltform);
index 8d9332b..f478685 100644 (file)
@@ -122,7 +122,7 @@ static void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit)
 {
        unsigned long flags;
 
-       if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT))
+       if (!ufshcd_is_auto_hibern8_supported(hba))
                return;
 
        spin_lock_irqsave(hba->host->host_lock, flags);
@@ -164,7 +164,7 @@ static ssize_t auto_hibern8_show(struct device *dev,
 {
        struct ufs_hba *hba = dev_get_drvdata(dev);
 
-       if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT))
+       if (!ufshcd_is_auto_hibern8_supported(hba))
                return -EOPNOTSUPP;
 
        return snprintf(buf, PAGE_SIZE, "%d\n", ufshcd_ahit_to_us(hba->ahit));
@@ -177,7 +177,7 @@ static ssize_t auto_hibern8_store(struct device *dev,
        struct ufs_hba *hba = dev_get_drvdata(dev);
        unsigned int timer;
 
-       if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT))
+       if (!ufshcd_is_auto_hibern8_supported(hba))
                return -EOPNOTSUPP;
 
        if (kstrtouint(buf, 0, &timer))
index 869e71f..a9344eb 100644 (file)
@@ -122,7 +122,7 @@ static int ufs_bsg_request(struct bsg_job *job)
                memcpy(&uc, &bsg_request->upiu_req.uc, UIC_CMD_SIZE);
                ret = ufshcd_send_uic_cmd(hba, &uc);
                if (ret)
-                       dev_dbg(hba->dev,
+                       dev_err(hba->dev,
                                "send uic cmd: error code %d\n", ret);
 
                memcpy(&bsg_reply->upiu_rsp.uc, &uc, UIC_CMD_SIZE);
@@ -149,7 +149,9 @@ static int ufs_bsg_request(struct bsg_job *job)
 out:
        bsg_reply->result = ret;
        job->reply_len = sizeof(struct ufs_bsg_reply);
-       bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len);
+       /* complete the job here only if no error */
+       if (ret == 0)
+               bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len);
 
        return ret;
 }
index ffe6f82..3b19de3 100644 (file)
@@ -200,6 +200,8 @@ static const struct dev_pm_ops ufshcd_pci_pm_ops = {
 static const struct pci_device_id ufshcd_pci_tbl[] = {
        { PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { PCI_VDEVICE(INTEL, 0x9DFA), (kernel_ulong_t)&ufs_intel_cnl_hba_vops },
+       { PCI_VDEVICE(INTEL, 0x4B41), (kernel_ulong_t)&ufs_intel_cnl_hba_vops },
+       { PCI_VDEVICE(INTEL, 0x4B43), (kernel_ulong_t)&ufs_intel_cnl_hba_vops },
        { }     /* terminate list */
 };
 
index 3fe3029..04d3686 100644 (file)
@@ -3908,7 +3908,7 @@ static void ufshcd_auto_hibern8_enable(struct ufs_hba *hba)
 {
        unsigned long flags;
 
-       if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) || !hba->ahit)
+       if (!ufshcd_is_auto_hibern8_supported(hba) || !hba->ahit)
                return;
 
        spin_lock_irqsave(hba->host->host_lock, flags);
@@ -5255,6 +5255,7 @@ static void ufshcd_err_handler(struct work_struct *work)
                        goto skip_err_handling;
        }
        if ((hba->saved_err & INT_FATAL_ERRORS) ||
+           (hba->saved_err & UFSHCD_UIC_HIBERN8_MASK) ||
            ((hba->saved_err & UIC_ERROR) &&
            (hba->saved_uic_err & (UFSHCD_UIC_DL_PA_INIT_ERROR |
                                   UFSHCD_UIC_DL_NAC_RECEIVED_ERROR |
@@ -5414,6 +5415,23 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba)
                        __func__, hba->uic_error);
 }
 
+static bool ufshcd_is_auto_hibern8_error(struct ufs_hba *hba,
+                                        u32 intr_mask)
+{
+       if (!ufshcd_is_auto_hibern8_supported(hba))
+               return false;
+
+       if (!(intr_mask & UFSHCD_UIC_HIBERN8_MASK))
+               return false;
+
+       if (hba->active_uic_cmd &&
+           (hba->active_uic_cmd->command == UIC_CMD_DME_HIBER_ENTER ||
+           hba->active_uic_cmd->command == UIC_CMD_DME_HIBER_EXIT))
+               return false;
+
+       return true;
+}
+
 /**
  * ufshcd_check_errors - Check for errors that need s/w attention
  * @hba: per-adapter instance
@@ -5432,6 +5450,15 @@ static void ufshcd_check_errors(struct ufs_hba *hba)
                        queue_eh_work = true;
        }
 
+       if (hba->errors & UFSHCD_UIC_HIBERN8_MASK) {
+               dev_err(hba->dev,
+                       "%s: Auto Hibern8 %s failed - status: 0x%08x, upmcrs: 0x%08x\n",
+                       __func__, (hba->errors & UIC_HIBERNATE_ENTER) ?
+                       "Enter" : "Exit",
+                       hba->errors, ufshcd_get_upmcrs(hba));
+               queue_eh_work = true;
+       }
+
        if (queue_eh_work) {
                /*
                 * update the transfer error masks to sticky bits, let's do this
@@ -5494,6 +5521,10 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba)
 static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
 {
        hba->errors = UFSHCD_ERROR_MASK & intr_status;
+
+       if (ufshcd_is_auto_hibern8_error(hba, intr_status))
+               hba->errors |= (UFSHCD_UIC_HIBERN8_MASK & intr_status);
+
        if (hba->errors)
                ufshcd_check_errors(hba);
 
@@ -8313,7 +8344,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
                                                UIC_LINK_HIBERN8_STATE);
 
        /* Set the default auto-hiberate idle timer value to 150 ms */
-       if (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) {
+       if (ufshcd_is_auto_hibern8_supported(hba) && !hba->ahit) {
                hba->ahit = FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, 150) |
                            FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, 3);
        }
index ecfa898..994d73d 100644 (file)
@@ -740,6 +740,11 @@ return true;
 #endif
 }
 
+static inline bool ufshcd_is_auto_hibern8_supported(struct ufs_hba *hba)
+{
+       return (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT);
+}
+
 #define ufshcd_writel(hba, val, reg)   \
        writel((val), (hba)->mmio_base + (reg))
 #define ufshcd_readl(hba, reg) \
index 6fa889d..dbb75cd 100644 (file)
@@ -144,8 +144,10 @@ enum {
 #define CONTROLLER_FATAL_ERROR                 0x10000
 #define SYSTEM_BUS_FATAL_ERROR                 0x20000
 
-#define UFSHCD_UIC_PWR_MASK    (UIC_HIBERNATE_ENTER |\
-                               UIC_HIBERNATE_EXIT |\
+#define UFSHCD_UIC_HIBERN8_MASK        (UIC_HIBERNATE_ENTER |\
+                               UIC_HIBERNATE_EXIT)
+
+#define UFSHCD_UIC_PWR_MASK    (UFSHCD_UIC_HIBERN8_MASK |\
                                UIC_POWER_MODE)
 
 #define UFSHCD_UIC_MASK                (UIC_COMMAND_COMPL | UFSHCD_UIC_PWR_MASK)
index 13f1b3b..1705398 100644 (file)
@@ -74,9 +74,6 @@ struct virtio_scsi {
 
        u32 num_queues;
 
-       /* If the affinity hint is set for virtqueues */
-       bool affinity_hint_set;
-
        struct hlist_node node;
 
        /* Protected by event_vq lock */
index 377b07b..7000881 100644 (file)
@@ -335,7 +335,7 @@ static void pvscsi_create_sg(struct pvscsi_ctx *ctx,
        BUG_ON(count > PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT);
 
        sge = &ctx->sgl->sge[0];
-       for (i = 0; i < count; i++, sg++) {
+       for (i = 0; i < count; i++, sg = sg_next(sg)) {
                sge[i].addr   = sg_dma_address(sg);
                sge[i].length = sg_dma_len(sg);
                sge[i].flags  = 0;
index f965a3e..fb7b289 100644 (file)
@@ -735,7 +735,7 @@ transfer_bytes(const wd33c93_regs regs, struct scsi_cmnd *cmd,
  * source or destination for THIS transfer.
  */
        if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
-               ++cmd->SCp.buffer;
+               cmd->SCp.buffer = sg_next(cmd->SCp.buffer);
                --cmd->SCp.buffers_residual;
                cmd->SCp.this_residual = cmd->SCp.buffer->length;
                cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
index c2f4006..edc8a13 100644 (file)
@@ -108,8 +108,15 @@ static inline int wd719x_wait_done(struct wd719x *wd, int timeout)
        }
 
        if (status != WD719X_INT_NOERRORS) {
+               u8 sue = wd719x_readb(wd, WD719X_AMR_SCB_ERROR);
+               /* we get this after wd719x_dev_reset, it's not an error */
+               if (sue == WD719X_SUE_TERM)
+                       return 0;
+               /* we get this after wd719x_bus_reset, it's not an error */
+               if (sue == WD719X_SUE_RESET)
+                       return 0;
                dev_err(&wd->pdev->dev, "direct command failed, status 0x%02x, SUE 0x%02x\n",
-                       status, wd719x_readb(wd, WD719X_AMR_SCB_ERROR));
+                       status, sue);
                return -EIO;
        }
 
@@ -128,8 +135,10 @@ static int wd719x_direct_cmd(struct wd719x *wd, u8 opcode, u8 dev, u8 lun,
        if (wd719x_wait_ready(wd))
                return -ETIMEDOUT;
 
-       /* make sure we get NO interrupts */
-       dev |= WD719X_DISABLE_INT;
+       /* disable interrupts except for RESET/ABORT (it breaks them) */
+       if (opcode != WD719X_CMD_BUSRESET && opcode != WD719X_CMD_ABORT &&
+           opcode != WD719X_CMD_ABORT_TAG && opcode != WD719X_CMD_RESET)
+               dev |= WD719X_DISABLE_INT;
        wd719x_writeb(wd, WD719X_AMR_CMD_PARAM, dev);
        wd719x_writeb(wd, WD719X_AMR_CMD_PARAM_2, lun);
        wd719x_writeb(wd, WD719X_AMR_CMD_PARAM_3, tag);
@@ -465,6 +474,7 @@ static int wd719x_abort(struct scsi_cmnd *cmd)
        spin_lock_irqsave(wd->sh->host_lock, flags);
        result = wd719x_direct_cmd(wd, action, cmd->device->id,
                                   cmd->device->lun, cmd->tag, scb->phys, 0);
+       wd719x_finish_cmd(scb, DID_ABORT);
        spin_unlock_irqrestore(wd->sh->host_lock, flags);
        if (result)
                return FAILED;
@@ -477,6 +487,7 @@ static int wd719x_reset(struct scsi_cmnd *cmd, u8 opcode, u8 device)
        int result;
        unsigned long flags;
        struct wd719x *wd = shost_priv(cmd->device->host);
+       struct wd719x_scb *scb, *tmp;
 
        dev_info(&wd->pdev->dev, "%s reset requested\n",
                 (opcode == WD719X_CMD_BUSRESET) ? "bus" : "device");
@@ -484,6 +495,12 @@ static int wd719x_reset(struct scsi_cmnd *cmd, u8 opcode, u8 device)
        spin_lock_irqsave(wd->sh->host_lock, flags);
        result = wd719x_direct_cmd(wd, opcode, device, 0, 0, 0,
                                   WD719X_WAIT_FOR_SCSI_RESET);
+       /* flush all SCBs (or all for a device if dev_reset) */
+       list_for_each_entry_safe(scb, tmp, &wd->active_scbs, list) {
+               if (opcode == WD719X_CMD_BUSRESET ||
+                   scb->cmd->device->id == device)
+                       wd719x_finish_cmd(scb, DID_RESET);
+       }
        spin_unlock_irqrestore(wd->sh->host_lock, flags);
        if (result)
                return FAILED;
@@ -506,22 +523,23 @@ static int wd719x_host_reset(struct scsi_cmnd *cmd)
        struct wd719x *wd = shost_priv(cmd->device->host);
        struct wd719x_scb *scb, *tmp;
        unsigned long flags;
-       int result;
 
        dev_info(&wd->pdev->dev, "host reset requested\n");
        spin_lock_irqsave(wd->sh->host_lock, flags);
-       /* Try to reinit the RISC */
-       if (wd719x_chip_init(wd) == 0)
-               result = SUCCESS;
-       else
-               result = FAILED;
+       /* stop the RISC */
+       if (wd719x_direct_cmd(wd, WD719X_CMD_SLEEP, 0, 0, 0, 0,
+                             WD719X_WAIT_FOR_RISC))
+               dev_warn(&wd->pdev->dev, "RISC sleep command failed\n");
+       /* disable RISC */
+       wd719x_writeb(wd, WD719X_PCI_MODE_SELECT, 0);
 
        /* flush all SCBs */
        list_for_each_entry_safe(scb, tmp, &wd->active_scbs, list)
-               wd719x_finish_cmd(scb, result);
+               wd719x_finish_cmd(scb, DID_RESET);
        spin_unlock_irqrestore(wd->sh->host_lock, flags);
 
-       return result;
+       /* Try to reinit the RISC */
+       return wd719x_chip_init(wd) == 0 ? SUCCESS : FAILED;
 }
 
 static int wd719x_biosparam(struct scsi_device *sdev, struct block_device *bdev,
@@ -673,7 +691,7 @@ static irqreturn_t wd719x_interrupt(int irq, void *dev_id)
                        else
                                dev_err(&wd->pdev->dev, "card returned invalid SCB pointer\n");
                } else
-                       dev_warn(&wd->pdev->dev, "direct command 0x%x completed\n",
+                       dev_dbg(&wd->pdev->dev, "direct command 0x%x completed\n",
                                 regs.bytes.OPC);
                break;
        case WD719X_INT_PIOREADY:
index b2f07d2..526e321 100644 (file)
@@ -98,11 +98,6 @@ static int slim_device_remove(struct device *dev)
 static int slim_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct slim_device *sbdev = to_slim_device(dev);
-       int ret;
-
-       ret = of_device_uevent_modalias(dev, env);
-       if (ret != -ENODEV)
-               return ret;
 
        return add_uevent_var(env, "MODALIAS=slim:%s", dev_name(&sbdev->dev));
 }
index ad3e2e2..a444bad 100644 (file)
@@ -528,10 +528,8 @@ static int qcom_slim_probe(struct platform_device *pdev)
 
        slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl");
        ctrl->base = devm_ioremap_resource(ctrl->dev, slim_mem);
-       if (IS_ERR(ctrl->base)) {
-               dev_err(&pdev->dev, "IOremap failed\n");
+       if (IS_ERR(ctrl->base))
                return PTR_ERR(ctrl->base);
-       }
 
        sctrl->set_laddr = qcom_set_laddr;
        sctrl->xfer_msg = qcom_xfer_msg;
index 2fa0532..75f87b3 100644 (file)
@@ -84,7 +84,7 @@ static const int slim_presence_rate_table[] = {
        512000,
 };
 
-/*
+/**
  * slim_stream_allocate() - Allocate a new SLIMbus Stream
  * @dev:Slim device to be associated with
  * @name: name of the stream
@@ -189,7 +189,7 @@ static int slim_get_prate_code(int rate)
        return -EINVAL;
 }
 
-/*
+/**
  * slim_stream_prepare() - Prepare a SLIMbus Stream
  *
  * @rt: instance of slim stream runtime to configure
@@ -336,7 +336,7 @@ static int slim_activate_channel(struct slim_stream_runtime *stream,
        return slim_do_transfer(sdev->ctrl, &txn);
 }
 
-/*
+/**
  * slim_stream_enable() - Enable a prepared SLIMbus Stream
  *
  * @stream: instance of slim stream runtime to enable
@@ -389,7 +389,7 @@ int slim_stream_enable(struct slim_stream_runtime *stream)
 }
 EXPORT_SYMBOL_GPL(slim_stream_enable);
 
-/*
+/**
  * slim_stream_disable() - Disable a SLIMbus Stream
  *
  * @stream: instance of slim stream runtime to disable
@@ -423,7 +423,7 @@ int slim_stream_disable(struct slim_stream_runtime *stream)
 }
 EXPORT_SYMBOL_GPL(slim_stream_disable);
 
-/*
+/**
  * slim_stream_unprepare() - Un-prepare a SLIMbus Stream
  *
  * @stream: instance of slim stream runtime to unprepare
@@ -449,7 +449,7 @@ int slim_stream_unprepare(struct slim_stream_runtime *stream)
 }
 EXPORT_SYMBOL_GPL(slim_stream_unprepare);
 
-/*
+/**
  * slim_stream_free() - Free a SLIMbus Stream
  *
  * @stream: instance of slim stream runtime to free
index 6b8ef01..d5cf953 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 // Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
 
+#include <linux/acpi.h>
 #include <linux/clk.h>
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
@@ -450,6 +451,9 @@ int geni_se_resources_off(struct geni_se *se)
 {
        int ret;
 
+       if (has_acpi_companion(se->dev))
+               return 0;
+
        ret = pinctrl_pm_select_sleep_state(se->dev);
        if (ret)
                return ret;
@@ -487,6 +491,9 @@ int geni_se_resources_on(struct geni_se *se)
 {
        int ret;
 
+       if (has_acpi_companion(se->dev))
+               return 0;
+
        ret = geni_se_clks_on(se);
        if (ret)
                return ret;
@@ -724,12 +731,14 @@ static int geni_se_probe(struct platform_device *pdev)
        if (IS_ERR(wrapper->base))
                return PTR_ERR(wrapper->base);
 
-       wrapper->ahb_clks[0].id = "m-ahb";
-       wrapper->ahb_clks[1].id = "s-ahb";
-       ret = devm_clk_bulk_get(dev, NUM_AHB_CLKS, wrapper->ahb_clks);
-       if (ret) {
-               dev_err(dev, "Err getting AHB clks %d\n", ret);
-               return ret;
+       if (!has_acpi_companion(&pdev->dev)) {
+               wrapper->ahb_clks[0].id = "m-ahb";
+               wrapper->ahb_clks[1].id = "s-ahb";
+               ret = devm_clk_bulk_get(dev, NUM_AHB_CLKS, wrapper->ahb_clks);
+               if (ret) {
+                       dev_err(dev, "Err getting AHB clks %d\n", ret);
+                       return ret;
+               }
        }
 
        dev_set_drvdata(dev, wrapper);
index aac35fc..fe74583 100644 (file)
@@ -87,7 +87,7 @@ int sdw_add_bus_master(struct sdw_bus *bus)
 
        /*
         * Initialize clock values based on Master properties. The max
-        * frequency is read from max_freq property. Current assumption
+        * frequency is read from max_clk_freq property. Current assumption
         * is that the bus will start at highest clock frequency when
         * powered on.
         *
@@ -95,7 +95,7 @@ int sdw_add_bus_master(struct sdw_bus *bus)
         * to start with bank 0 (Table 40 of Spec)
         */
        prop = &bus->prop;
-       bus->params.max_dr_freq = prop->max_freq * SDW_DOUBLE_RATE_FACTOR;
+       bus->params.max_dr_freq = prop->max_clk_freq * SDW_DOUBLE_RATE_FACTOR;
        bus->params.curr_dr_freq = bus->params.max_dr_freq;
        bus->params.curr_bank = SDW_BANK0;
        bus->params.next_bank = SDW_BANK1;
@@ -648,7 +648,7 @@ static int sdw_initialize_slave(struct sdw_slave *slave)
                return 0;
 
        /* Enable DP0 interrupts */
-       val = prop->dp0_prop->device_interrupts;
+       val = prop->dp0_prop->imp_def_interrupts;
        val |= SDW_DP0_INT_PORT_READY | SDW_DP0_INT_BRA_FAILURE;
 
        ret = sdw_update(slave, SDW_DP0_INTMASK, val, val);
index 682789b..ff4badc 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/soundwire/sdw_registers.h>
@@ -236,19 +237,19 @@ cdns_fill_msg_resp(struct sdw_cdns *cdns,
        for (i = 0; i < count; i++) {
                if (!(cdns->response_buf[i] & CDNS_MCP_RESP_ACK)) {
                        no_ack = 1;
-                       dev_dbg(cdns->dev, "Msg Ack not received\n");
+                       dev_dbg_ratelimited(cdns->dev, "Msg Ack not received\n");
                        if (cdns->response_buf[i] & CDNS_MCP_RESP_NACK) {
                                nack = 1;
-                               dev_err(cdns->dev, "Msg NACK received\n");
+                               dev_err_ratelimited(cdns->dev, "Msg NACK received\n");
                        }
                }
        }
 
        if (nack) {
-               dev_err(cdns->dev, "Msg NACKed for Slave %d\n", msg->dev_num);
+               dev_err_ratelimited(cdns->dev, "Msg NACKed for Slave %d\n", msg->dev_num);
                return SDW_CMD_FAIL;
        } else if (no_ack) {
-               dev_dbg(cdns->dev, "Msg ignored for Slave %d\n", msg->dev_num);
+               dev_dbg_ratelimited(cdns->dev, "Msg ignored for Slave %d\n", msg->dev_num);
                return SDW_CMD_IGNORED;
        }
 
@@ -356,12 +357,12 @@ cdns_program_scp_addr(struct sdw_cdns *cdns, struct sdw_msg *msg)
 
        /* For NACK, NO ack, don't return err if we are in Broadcast mode */
        if (nack) {
-               dev_err(cdns->dev,
-                       "SCP_addrpage NACKed for Slave %d\n", msg->dev_num);
+               dev_err_ratelimited(cdns->dev,
+                                   "SCP_addrpage NACKed for Slave %d\n", msg->dev_num);
                return SDW_CMD_FAIL;
        } else if (no_ack) {
-               dev_dbg(cdns->dev,
-                       "SCP_addrpage ignored for Slave %d\n", msg->dev_num);
+               dev_dbg_ratelimited(cdns->dev,
+                                   "SCP_addrpage ignored for Slave %d\n", msg->dev_num);
                return SDW_CMD_IGNORED;
        }
 
@@ -486,7 +487,8 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,
 {
        enum sdw_slave_status status[SDW_MAX_DEVICES + 1];
        bool is_slave = false;
-       u64 slave, mask;
+       u64 slave;
+       u32 mask;
        int i, set_status;
 
        /* combine the two status */
@@ -524,9 +526,9 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,
 
                /* first check if Slave reported multiple status */
                if (set_status > 1) {
-                       dev_warn(cdns->dev,
-                                "Slave reported multiple Status: %d\n",
-                                status[i]);
+                       dev_warn_ratelimited(cdns->dev,
+                                            "Slave reported multiple Status: %d\n",
+                                            mask);
                        /*
                         * TODO: we need to reread the status here by
                         * issuing a PING cmd
@@ -612,7 +614,7 @@ irqreturn_t sdw_cdns_thread(int irq, void *dev_id)
        struct sdw_cdns *cdns = dev_id;
        u32 slave0, slave1;
 
-       dev_dbg(cdns->dev, "Slave status change\n");
+       dev_dbg_ratelimited(cdns->dev, "Slave status change\n");
 
        slave0 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT0);
        slave1 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT1);
@@ -716,6 +718,8 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
        stream = &cdns->pcm;
 
        /* First two PDIs are reserved for bulk transfers */
+       if (stream->num_bd < CDNS_PCM_PDI_OFFSET)
+               return -EINVAL;
        stream->num_bd -= CDNS_PCM_PDI_OFFSET;
        offset = CDNS_PCM_PDI_OFFSET;
 
index 60293a0..317873b 100644 (file)
@@ -263,6 +263,9 @@ static void intel_pdi_init(struct sdw_intel *sdw,
        config->pcm_out = (pcm_cap & SDW_SHIM_PCMSCAP_OSS) >>
                                        SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_OSS);
 
+       dev_dbg(sdw->cdns.dev, "PCM cap bd:%d in:%d out:%d\n",
+               config->pcm_bd, config->pcm_in, config->pcm_out);
+
        /* PDM Stream Capability */
        pdm_cap = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id));
 
@@ -272,6 +275,9 @@ static void intel_pdi_init(struct sdw_intel *sdw,
                                        SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_ISS);
        config->pdm_out = (pdm_cap & SDW_SHIM_PDMSCAP_OSS) >>
                                        SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_OSS);
+
+       dev_dbg(sdw->cdns.dev, "PDM cap bd:%d in:%d out:%d\n",
+               config->pdm_bd, config->pdm_in, config->pdm_out);
 }
 
 static int
@@ -796,13 +802,14 @@ static int intel_prop_read(struct sdw_bus *bus)
        sdw_master_read_prop(bus);
 
        /* BIOS is not giving some values correctly. So, lets override them */
-       bus->prop.num_freq = 1;
-       bus->prop.freq = devm_kcalloc(bus->dev, bus->prop.num_freq,
-                                     sizeof(*bus->prop.freq), GFP_KERNEL);
-       if (!bus->prop.freq)
+       bus->prop.num_clk_freq = 1;
+       bus->prop.clk_freq = devm_kcalloc(bus->dev, bus->prop.num_clk_freq,
+                                         sizeof(*bus->prop.clk_freq),
+                                         GFP_KERNEL);
+       if (!bus->prop.clk_freq)
                return -ENOMEM;
 
-       bus->prop.freq[0] = bus->prop.max_freq;
+       bus->prop.clk_freq[0] = bus->prop.max_clk_freq;
        bus->prop.err_threshold = 5;
 
        return 0;
index 71050e5..d923b62 100644 (file)
@@ -5,7 +5,7 @@
 #define __SDW_INTEL_LOCAL_H
 
 /**
- * struct sdw_intel_res - Soundwire link resources
+ * struct sdw_intel_link_res - Soundwire link resources
  * @registers: Link IO registers base
  * @shim: Audio shim pointer
  * @alh: ALH (Audio Link Hub) pointer
index d3d6b54..70637a0 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/soundwire/sdw_intel.h>
 #include "intel.h"
 
+#define SDW_LINK_TYPE          4 /* from Intel ACPI documentation */
 #define SDW_MAX_LINKS          4
 #define SDW_SHIM_LCAP          0x0
 #define SDW_SHIM_BASE          0x2C000
@@ -80,6 +81,7 @@ static struct sdw_intel_ctx
 
        /* Check SNDWLCAP.LCOUNT */
        caps = ioread32(res->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP);
+       caps &= GENMASK(2, 0);
 
        /* Check HW supported vs property value and use min of two */
        count = min_t(u8, caps, count);
@@ -89,6 +91,9 @@ static struct sdw_intel_ctx
                dev_err(&adev->dev, "Link count %d exceeds max %d\n",
                        count, SDW_MAX_LINKS);
                return NULL;
+       } else if (!count) {
+               dev_warn(&adev->dev, "No SoundWire links detected\n");
+               return NULL;
        }
 
        dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count);
@@ -150,6 +155,12 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
 {
        struct sdw_intel_res *res = cdata;
        struct acpi_device *adev;
+       acpi_status status;
+       u64 adr;
+
+       status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
+       if (ACPI_FAILURE(status))
+               return AE_OK; /* keep going */
 
        if (acpi_bus_get_device(handle, &adev)) {
                pr_err("%s: Couldn't find ACPI handle\n", __func__);
@@ -157,7 +168,19 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
        }
 
        res->handle = handle;
-       return AE_OK;
+
+       /*
+        * On some Intel platforms, multiple children of the HDAS
+        * device can be found, but only one of them is the SoundWire
+        * controller. The SNDW device is always exposed with
+        * Name(_ADR, 0x40000000), with bits 31..28 representing the
+        * SoundWire link so filter accordingly
+        */
+       if ((adr & GENMASK(31, 28)) >> 28 != SDW_LINK_TYPE)
+               return AE_OK; /* keep going */
+
+       /* device found, stop namespace walk */
+       return AE_CTRL_TERMINATE;
 }
 
 /**
index c1f51d6..79fee1b 100644 (file)
@@ -40,7 +40,7 @@ int sdw_master_read_prop(struct sdw_bus *bus)
 
        /* Find master handle */
        snprintf(name, sizeof(name),
-                "mipi-sdw-master-%d-subproperties", bus->link_id);
+                "mipi-sdw-link-%d-subproperties", bus->link_id);
 
        link = device_get_named_child_node(bus->dev, name);
        if (!link) {
@@ -50,39 +50,40 @@ int sdw_master_read_prop(struct sdw_bus *bus)
 
        if (fwnode_property_read_bool(link,
                                      "mipi-sdw-clock-stop-mode0-supported"))
-               prop->clk_stop_mode = SDW_CLK_STOP_MODE0;
+               prop->clk_stop_modes |= BIT(SDW_CLK_STOP_MODE0);
 
        if (fwnode_property_read_bool(link,
                                      "mipi-sdw-clock-stop-mode1-supported"))
-               prop->clk_stop_mode |= SDW_CLK_STOP_MODE1;
+               prop->clk_stop_modes |= BIT(SDW_CLK_STOP_MODE1);
 
        fwnode_property_read_u32(link,
                                 "mipi-sdw-max-clock-frequency",
-                                &prop->max_freq);
+                                &prop->max_clk_freq);
 
        nval = fwnode_property_read_u32_array(link,
                        "mipi-sdw-clock-frequencies-supported", NULL, 0);
        if (nval > 0) {
-               prop->num_freq = nval;
-               prop->freq = devm_kcalloc(bus->dev, prop->num_freq,
-                                         sizeof(*prop->freq), GFP_KERNEL);
-               if (!prop->freq)
+               prop->num_clk_freq = nval;
+               prop->clk_freq = devm_kcalloc(bus->dev, prop->num_clk_freq,
+                                             sizeof(*prop->clk_freq),
+                                             GFP_KERNEL);
+               if (!prop->clk_freq)
                        return -ENOMEM;
 
                fwnode_property_read_u32_array(link,
                                "mipi-sdw-clock-frequencies-supported",
-                               prop->freq, prop->num_freq);
+                               prop->clk_freq, prop->num_clk_freq);
        }
 
        /*
         * Check the frequencies supported. If FW doesn't provide max
         * freq, then populate here by checking values.
         */
-       if (!prop->max_freq && prop->freq) {
-               prop->max_freq = prop->freq[0];
-               for (i = 1; i < prop->num_freq; i++) {
-                       if (prop->freq[i] > prop->max_freq)
-                               prop->max_freq = prop->freq[i];
+       if (!prop->max_clk_freq && prop->clk_freq) {
+               prop->max_clk_freq = prop->clk_freq[0];
+               for (i = 1; i < prop->num_clk_freq; i++) {
+                       if (prop->clk_freq[i] > prop->max_clk_freq)
+                               prop->max_clk_freq = prop->clk_freq[i];
                }
        }
 
@@ -149,13 +150,13 @@ static int sdw_slave_read_dp0(struct sdw_slave *slave,
                                dp0->words, dp0->num_words);
        }
 
-       dp0->flow_controlled = fwnode_property_read_bool(port,
+       dp0->BRA_flow_controlled = fwnode_property_read_bool(port,
                                "mipi-sdw-bra-flow-controlled");
 
        dp0->simple_ch_prep_sm = fwnode_property_read_bool(port,
                                "mipi-sdw-simplified-channel-prepare-sm");
 
-       dp0->device_interrupts = fwnode_property_read_bool(port,
+       dp0->imp_def_interrupts = fwnode_property_read_bool(port,
                                "mipi-sdw-imp-def-dp0-interrupts-supported");
 
        return 0;
@@ -224,7 +225,7 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave,
 
                fwnode_property_read_u32(node,
                                "mipi-sdw-imp-def-dpn-interrupts-supported",
-                               &dpn[i].device_interrupts);
+                               &dpn[i].imp_def_interrupts);
 
                fwnode_property_read_u32(node, "mipi-sdw-min-channel-number",
                                         &dpn[i].min_ch);
index 1d5294b..a047675 100644 (file)
@@ -439,7 +439,7 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
 
        prep_ch.bank = bus->params.next_bank;
 
-       if (dpn_prop->device_interrupts || !dpn_prop->simple_ch_prep_sm)
+       if (dpn_prop->imp_def_interrupts || !dpn_prop->simple_ch_prep_sm)
                intr = true;
 
        /*
@@ -449,7 +449,7 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
         */
        if (prep && intr) {
                ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep,
-                                            dpn_prop->device_interrupts);
+                                            dpn_prop->imp_def_interrupts);
                if (ret < 0)
                        return ret;
        }
@@ -493,7 +493,7 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
        /* Disable interrupt after Port de-prepare */
        if (!prep && intr)
                ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep,
-                                            dpn_prop->device_interrupts);
+                                            dpn_prop->imp_def_interrupts);
 
        return ret;
 }
@@ -1473,7 +1473,7 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream)
                memcpy(&params, &bus->params, sizeof(params));
 
                /* TODO: Support Asynchronous mode */
-               if ((prop->max_freq % stream->params.rate) != 0) {
+               if ((prop->max_clk_freq % stream->params.rate) != 0) {
                        dev_err(bus->dev, "Async mode not supported\n");
                        return -EINVAL;
                }
index 9167335..75ac046 100644 (file)
@@ -3652,7 +3652,7 @@ EXPORT_SYMBOL_GPL(spi_write_then_read);
 /*-------------------------------------------------------------------------*/
 
 #if IS_ENABLED(CONFIG_OF)
-static int __spi_of_device_match(struct device *dev, void *data)
+static int __spi_of_device_match(struct device *dev, const void *data)
 {
        return dev->of_node == data;
 }
@@ -3753,7 +3753,7 @@ static int spi_acpi_controller_match(struct device *dev, const void *data)
        return ACPI_COMPANION(dev->parent) == data;
 }
 
-static int spi_acpi_device_match(struct device *dev, void *data)
+static int spi_acpi_device_match(struct device *dev, const void *data)
 {
        return ACPI_COMPANION(dev) == data;
 }
index 178df58..989fe84 100644 (file)
@@ -18,24 +18,6 @@ config ION_SYSTEM_HEAP
          Choose this option to enable the Ion system heap. The system heap
          is backed by pages from the buddy allocator. If in doubt, say Y.
 
-config ION_CARVEOUT_HEAP
-       bool "Ion carveout heap support"
-       depends on ION
-       help
-         Choose this option to enable carveout heaps with Ion. Carveout heaps
-         are backed by memory reserved from the system. Allocation times are
-         typically faster at the cost of memory not being used. Unless you
-         know your system has these regions, you should say N here.
-
-config ION_CHUNK_HEAP
-       bool "Ion chunk heap support"
-       depends on ION
-       help
-          Choose this option to enable chunk heaps with Ion. This heap is
-         similar in function the carveout heap but memory is broken down
-         into smaller chunk sizes, typically corresponding to a TLB size.
-         Unless you know your system has these regions, you should say N here.
-
 config ION_CMA_HEAP
        bool "Ion CMA heap support"
        depends on ION && DMA_CMA
index 17f3a75..5f4487b 100644 (file)
@@ -1,6 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_ION) += ion.o ion_heap.o
 obj-$(CONFIG_ION_SYSTEM_HEAP) += ion_system_heap.o ion_page_pool.o
-obj-$(CONFIG_ION_CARVEOUT_HEAP) += ion_carveout_heap.o
-obj-$(CONFIG_ION_CHUNK_HEAP) += ion_chunk_heap.o
 obj-$(CONFIG_ION_CMA_HEAP) += ion_cma_heap.o
diff --git a/drivers/staging/android/ion/ion_carveout_heap.c b/drivers/staging/android/ion/ion_carveout_heap.c
deleted file mode 100644 (file)
index bb9d614..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * ION Memory Allocator carveout heap helper
- *
- * Copyright (C) 2011 Google, Inc.
- */
-
-#include <linux/dma-mapping.h>
-#include <linux/err.h>
-#include <linux/genalloc.h>
-#include <linux/io.h>
-#include <linux/mm.h>
-#include <linux/scatterlist.h>
-#include <linux/slab.h>
-
-#include "ion.h"
-
-#define ION_CARVEOUT_ALLOCATE_FAIL     -1
-
-struct ion_carveout_heap {
-       struct ion_heap heap;
-       struct gen_pool *pool;
-};
-
-static phys_addr_t ion_carveout_allocate(struct ion_heap *heap,
-                                        unsigned long size)
-{
-       struct ion_carveout_heap *carveout_heap =
-               container_of(heap, struct ion_carveout_heap, heap);
-       unsigned long offset = gen_pool_alloc(carveout_heap->pool, size);
-
-       if (!offset)
-               return ION_CARVEOUT_ALLOCATE_FAIL;
-
-       return offset;
-}
-
-static void ion_carveout_free(struct ion_heap *heap, phys_addr_t addr,
-                             unsigned long size)
-{
-       struct ion_carveout_heap *carveout_heap =
-               container_of(heap, struct ion_carveout_heap, heap);
-
-       if (addr == ION_CARVEOUT_ALLOCATE_FAIL)
-               return;
-
-       gen_pool_free(carveout_heap->pool, addr, size);
-}
-
-static int ion_carveout_heap_allocate(struct ion_heap *heap,
-                                     struct ion_buffer *buffer,
-                                     unsigned long size,
-                                     unsigned long flags)
-{
-       struct sg_table *table;
-       phys_addr_t paddr;
-       int ret;
-
-       table = kmalloc(sizeof(*table), GFP_KERNEL);
-       if (!table)
-               return -ENOMEM;
-       ret = sg_alloc_table(table, 1, GFP_KERNEL);
-       if (ret)
-               goto err_free;
-
-       paddr = ion_carveout_allocate(heap, size);
-       if (paddr == ION_CARVEOUT_ALLOCATE_FAIL) {
-               ret = -ENOMEM;
-               goto err_free_table;
-       }
-
-       sg_set_page(table->sgl, pfn_to_page(PFN_DOWN(paddr)), size, 0);
-       buffer->sg_table = table;
-
-       return 0;
-
-err_free_table:
-       sg_free_table(table);
-err_free:
-       kfree(table);
-       return ret;
-}
-
-static void ion_carveout_heap_free(struct ion_buffer *buffer)
-{
-       struct ion_heap *heap = buffer->heap;
-       struct sg_table *table = buffer->sg_table;
-       struct page *page = sg_page(table->sgl);
-       phys_addr_t paddr = PFN_PHYS(page_to_pfn(page));
-
-       ion_heap_buffer_zero(buffer);
-
-       ion_carveout_free(heap, paddr, buffer->size);
-       sg_free_table(table);
-       kfree(table);
-}
-
-static struct ion_heap_ops carveout_heap_ops = {
-       .allocate = ion_carveout_heap_allocate,
-       .free = ion_carveout_heap_free,
-       .map_user = ion_heap_map_user,
-       .map_kernel = ion_heap_map_kernel,
-       .unmap_kernel = ion_heap_unmap_kernel,
-};
-
-struct ion_heap *ion_carveout_heap_create(phys_addr_t base, size_t size)
-{
-       struct ion_carveout_heap *carveout_heap;
-       int ret;
-
-       struct page *page;
-
-       page = pfn_to_page(PFN_DOWN(base));
-       ret = ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL));
-       if (ret)
-               return ERR_PTR(ret);
-
-       carveout_heap = kzalloc(sizeof(*carveout_heap), GFP_KERNEL);
-       if (!carveout_heap)
-               return ERR_PTR(-ENOMEM);
-
-       carveout_heap->pool = gen_pool_create(PAGE_SHIFT, -1);
-       if (!carveout_heap->pool) {
-               kfree(carveout_heap);
-               return ERR_PTR(-ENOMEM);
-       }
-       gen_pool_add(carveout_heap->pool, base, size, -1);
-       carveout_heap->heap.ops = &carveout_heap_ops;
-       carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT;
-       carveout_heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
-
-       return &carveout_heap->heap;
-}
diff --git a/drivers/staging/android/ion/ion_chunk_heap.c b/drivers/staging/android/ion/ion_chunk_heap.c
deleted file mode 100644 (file)
index 3cdde9c..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * ION memory allocator chunk heap helper
- *
- * Copyright (C) 2012 Google, Inc.
- */
-
-#include <linux/dma-mapping.h>
-#include <linux/err.h>
-#include <linux/genalloc.h>
-#include <linux/mm.h>
-#include <linux/scatterlist.h>
-#include <linux/slab.h>
-
-#include "ion.h"
-
-struct ion_chunk_heap {
-       struct ion_heap heap;
-       struct gen_pool *pool;
-       unsigned long chunk_size;
-       unsigned long size;
-       unsigned long allocated;
-};
-
-static int ion_chunk_heap_allocate(struct ion_heap *heap,
-                                  struct ion_buffer *buffer,
-                                  unsigned long size,
-                                  unsigned long flags)
-{
-       struct ion_chunk_heap *chunk_heap =
-               container_of(heap, struct ion_chunk_heap, heap);
-       struct sg_table *table;
-       struct scatterlist *sg;
-       int ret, i;
-       unsigned long num_chunks;
-       unsigned long allocated_size;
-
-       allocated_size = ALIGN(size, chunk_heap->chunk_size);
-       num_chunks = allocated_size / chunk_heap->chunk_size;
-
-       if (allocated_size > chunk_heap->size - chunk_heap->allocated)
-               return -ENOMEM;
-
-       table = kmalloc(sizeof(*table), GFP_KERNEL);
-       if (!table)
-               return -ENOMEM;
-       ret = sg_alloc_table(table, num_chunks, GFP_KERNEL);
-       if (ret) {
-               kfree(table);
-               return ret;
-       }
-
-       sg = table->sgl;
-       for (i = 0; i < num_chunks; i++) {
-               unsigned long paddr = gen_pool_alloc(chunk_heap->pool,
-                                                    chunk_heap->chunk_size);
-               if (!paddr)
-                       goto err;
-               sg_set_page(sg, pfn_to_page(PFN_DOWN(paddr)),
-                           chunk_heap->chunk_size, 0);
-               sg = sg_next(sg);
-       }
-
-       buffer->sg_table = table;
-       chunk_heap->allocated += allocated_size;
-       return 0;
-err:
-       sg = table->sgl;
-       for (i -= 1; i >= 0; i--) {
-               gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)),
-                             sg->length);
-               sg = sg_next(sg);
-       }
-       sg_free_table(table);
-       kfree(table);
-       return -ENOMEM;
-}
-
-static void ion_chunk_heap_free(struct ion_buffer *buffer)
-{
-       struct ion_heap *heap = buffer->heap;
-       struct ion_chunk_heap *chunk_heap =
-               container_of(heap, struct ion_chunk_heap, heap);
-       struct sg_table *table = buffer->sg_table;
-       struct scatterlist *sg;
-       int i;
-       unsigned long allocated_size;
-
-       allocated_size = ALIGN(buffer->size, chunk_heap->chunk_size);
-
-       ion_heap_buffer_zero(buffer);
-
-       for_each_sg(table->sgl, sg, table->nents, i) {
-               gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)),
-                             sg->length);
-       }
-       chunk_heap->allocated -= allocated_size;
-       sg_free_table(table);
-       kfree(table);
-}
-
-static struct ion_heap_ops chunk_heap_ops = {
-       .allocate = ion_chunk_heap_allocate,
-       .free = ion_chunk_heap_free,
-       .map_user = ion_heap_map_user,
-       .map_kernel = ion_heap_map_kernel,
-       .unmap_kernel = ion_heap_unmap_kernel,
-};
-
-struct ion_heap *ion_chunk_heap_create(phys_addr_t base, size_t size, size_t chunk_size)
-{
-       struct ion_chunk_heap *chunk_heap;
-       int ret;
-       struct page *page;
-
-       page = pfn_to_page(PFN_DOWN(base));
-       ret = ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL));
-       if (ret)
-               return ERR_PTR(ret);
-
-       chunk_heap = kzalloc(sizeof(*chunk_heap), GFP_KERNEL);
-       if (!chunk_heap)
-               return ERR_PTR(-ENOMEM);
-
-       chunk_heap->chunk_size = chunk_size;
-       chunk_heap->pool = gen_pool_create(get_order(chunk_heap->chunk_size) +
-                                          PAGE_SHIFT, -1);
-       if (!chunk_heap->pool) {
-               ret = -ENOMEM;
-               goto error_gen_pool_create;
-       }
-       chunk_heap->size = size;
-       chunk_heap->allocated = 0;
-
-       gen_pool_add(chunk_heap->pool, base, size, -1);
-       chunk_heap->heap.ops = &chunk_heap_ops;
-       chunk_heap->heap.type = ION_HEAP_TYPE_CHUNK;
-       chunk_heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
-       pr_debug("%s: base %pa size %zu\n", __func__, &base, size);
-
-       return &chunk_heap->heap;
-
-error_gen_pool_create:
-       kfree(chunk_heap);
-       return ERR_PTR(ret);
-}
index d2c8cc7..3ef3dda 100644 (file)
@@ -27,18 +27,19 @@ static void comedi_buf_map_kref_release(struct kref *kref)
        unsigned int i;
 
        if (bm->page_list) {
-               for (i = 0; i < bm->n_pages; i++) {
-                       buf = &bm->page_list[i];
-                       clear_bit(PG_reserved,
-                                 &(virt_to_page(buf->virt_addr)->flags));
-                       if (bm->dma_dir != DMA_NONE) {
-#ifdef CONFIG_HAS_DMA
-                               dma_free_coherent(bm->dma_hw_dev,
-                                                 PAGE_SIZE,
-                                                 buf->virt_addr,
-                                                 buf->dma_addr);
-#endif
-                       } else {
+               if (bm->dma_dir != DMA_NONE) {
+                       /*
+                        * DMA buffer was allocated as a single block.
+                        * Address is in page_list[0].
+                        */
+                       buf = &bm->page_list[0];
+                       dma_free_coherent(bm->dma_hw_dev,
+                                         PAGE_SIZE * bm->n_pages,
+                                         buf->virt_addr, buf->dma_addr);
+               } else {
+                       for (i = 0; i < bm->n_pages; i++) {
+                               buf = &bm->page_list[i];
+                               ClearPageReserved(virt_to_page(buf->virt_addr));
                                free_page((unsigned long)buf->virt_addr);
                        }
                }
@@ -57,7 +58,8 @@ static void __comedi_buf_free(struct comedi_device *dev,
        unsigned long flags;
 
        if (async->prealloc_buf) {
-               vunmap(async->prealloc_buf);
+               if (s->async_dma_dir == DMA_NONE)
+                       vunmap(async->prealloc_buf);
                async->prealloc_buf = NULL;
                async->prealloc_bufsz = 0;
        }
@@ -69,6 +71,72 @@ static void __comedi_buf_free(struct comedi_device *dev,
        comedi_buf_map_put(bm);
 }
 
+static struct comedi_buf_map *
+comedi_buf_map_alloc(struct comedi_device *dev, enum dma_data_direction dma_dir,
+                    unsigned int n_pages)
+{
+       struct comedi_buf_map *bm;
+       struct comedi_buf_page *buf;
+       unsigned int i;
+
+       bm = kzalloc(sizeof(*bm), GFP_KERNEL);
+       if (!bm)
+               return NULL;
+
+       kref_init(&bm->refcount);
+       bm->dma_dir = dma_dir;
+       if (bm->dma_dir != DMA_NONE) {
+               /* Need ref to hardware device to free buffer later. */
+               bm->dma_hw_dev = get_device(dev->hw_dev);
+       }
+
+       bm->page_list = vzalloc(sizeof(*buf) * n_pages);
+       if (!bm->page_list)
+               goto err;
+
+       if (bm->dma_dir != DMA_NONE) {
+               void *virt_addr;
+               dma_addr_t dma_addr;
+
+               /*
+                * Currently, the DMA buffer needs to be allocated as a
+                * single block so that it can be mmap()'ed.
+                */
+               virt_addr = dma_alloc_coherent(bm->dma_hw_dev,
+                                              PAGE_SIZE * n_pages, &dma_addr,
+                                              GFP_KERNEL);
+               if (!virt_addr)
+                       goto err;
+
+               for (i = 0; i < n_pages; i++) {
+                       buf = &bm->page_list[i];
+                       buf->virt_addr = virt_addr + (i << PAGE_SHIFT);
+                       buf->dma_addr = dma_addr + (i << PAGE_SHIFT);
+               }
+
+               bm->n_pages = i;
+       } else {
+               for (i = 0; i < n_pages; i++) {
+                       buf = &bm->page_list[i];
+                       buf->virt_addr = (void *)get_zeroed_page(GFP_KERNEL);
+                       if (!buf->virt_addr)
+                               break;
+
+                       SetPageReserved(virt_to_page(buf->virt_addr));
+               }
+
+               bm->n_pages = i;
+               if (i < n_pages)
+                       goto err;
+       }
+
+       return bm;
+
+err:
+       comedi_buf_map_put(bm);
+       return NULL;
+}
+
 static void __comedi_buf_alloc(struct comedi_device *dev,
                               struct comedi_subdevice *s,
                               unsigned int n_pages)
@@ -86,57 +154,37 @@ static void __comedi_buf_alloc(struct comedi_device *dev,
                return;
        }
 
-       bm = kzalloc(sizeof(*async->buf_map), GFP_KERNEL);
+       bm = comedi_buf_map_alloc(dev, s->async_dma_dir, n_pages);
        if (!bm)
                return;
 
-       kref_init(&bm->refcount);
        spin_lock_irqsave(&s->spin_lock, flags);
        async->buf_map = bm;
        spin_unlock_irqrestore(&s->spin_lock, flags);
-       bm->dma_dir = s->async_dma_dir;
-       if (bm->dma_dir != DMA_NONE)
-               /* Need ref to hardware device to free buffer later. */
-               bm->dma_hw_dev = get_device(dev->hw_dev);
 
-       bm->page_list = vzalloc(sizeof(*buf) * n_pages);
-       if (bm->page_list)
+       if (bm->dma_dir != DMA_NONE) {
+               /*
+                * DMA buffer was allocated as a single block.
+                * Address is in page_list[0].
+                */
+               buf = &bm->page_list[0];
+               async->prealloc_buf = buf->virt_addr;
+       } else {
                pages = vmalloc(sizeof(struct page *) * n_pages);
+               if (!pages)
+                       return;
 
-       if (!pages)
-               return;
-
-       for (i = 0; i < n_pages; i++) {
-               buf = &bm->page_list[i];
-               if (bm->dma_dir != DMA_NONE)
-#ifdef CONFIG_HAS_DMA
-                       buf->virt_addr = dma_alloc_coherent(bm->dma_hw_dev,
-                                                           PAGE_SIZE,
-                                                           &buf->dma_addr,
-                                                           GFP_KERNEL |
-                                                           __GFP_COMP);
-#else
-                       break;
-#endif
-               else
-                       buf->virt_addr = (void *)get_zeroed_page(GFP_KERNEL);
-               if (!buf->virt_addr)
-                       break;
-
-               set_bit(PG_reserved, &(virt_to_page(buf->virt_addr)->flags));
-
-               pages[i] = virt_to_page(buf->virt_addr);
-       }
-       spin_lock_irqsave(&s->spin_lock, flags);
-       bm->n_pages = i;
-       spin_unlock_irqrestore(&s->spin_lock, flags);
+               for (i = 0; i < n_pages; i++) {
+                       buf = &bm->page_list[i];
+                       pages[i] = virt_to_page(buf->virt_addr);
+               }
 
-       /* vmap the prealloc_buf if all the pages were allocated */
-       if (i == n_pages)
+               /* vmap the pages to prealloc_buf */
                async->prealloc_buf = vmap(pages, n_pages, VM_MAP,
                                           COMEDI_PAGE_PROTECTION);
 
-       vfree(pages);
+               vfree(pages);
+       }
 }
 
 void comedi_buf_map_get(struct comedi_buf_map *bm)
index f6d1287..08d1bbb 100644 (file)
@@ -2301,11 +2301,12 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
        struct comedi_subdevice *s;
        struct comedi_async *async;
        struct comedi_buf_map *bm = NULL;
+       struct comedi_buf_page *buf;
        unsigned long start = vma->vm_start;
        unsigned long size;
        int n_pages;
        int i;
-       int retval;
+       int retval = 0;
 
        /*
         * 'trylock' avoids circular dependency with current->mm->mmap_sem
@@ -2361,24 +2362,36 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
                retval = -EINVAL;
                goto done;
        }
-       for (i = 0; i < n_pages; ++i) {
-               struct comedi_buf_page *buf = &bm->page_list[i];
+       if (bm->dma_dir != DMA_NONE) {
+               /*
+                * DMA buffer was allocated as a single block.
+                * Address is in page_list[0].
+                */
+               buf = &bm->page_list[0];
+               retval = dma_mmap_coherent(bm->dma_hw_dev, vma, buf->virt_addr,
+                                          buf->dma_addr, n_pages * PAGE_SIZE);
+       } else {
+               for (i = 0; i < n_pages; ++i) {
+                       unsigned long pfn;
+
+                       buf = &bm->page_list[i];
+                       pfn = page_to_pfn(virt_to_page(buf->virt_addr));
+                       retval = remap_pfn_range(vma, start, pfn, PAGE_SIZE,
+                                                PAGE_SHARED);
+                       if (retval)
+                               break;
 
-               if (remap_pfn_range(vma, start,
-                                   page_to_pfn(virt_to_page(buf->virt_addr)),
-                                   PAGE_SIZE, PAGE_SHARED)) {
-                       retval = -EAGAIN;
-                       goto done;
+                       start += PAGE_SIZE;
                }
-               start += PAGE_SIZE;
        }
 
-       vma->vm_ops = &comedi_vm_ops;
-       vma->vm_private_data = bm;
+       if (retval == 0) {
+               vma->vm_ops = &comedi_vm_ops;
+               vma->vm_private_data = bm;
 
-       vma->vm_ops->open(vma);
+               vma->vm_ops->open(vma);
+       }
 
-       retval = 0;
 done:
        up_read(&dev->attach_lock);
        comedi_buf_map_put(bm); /* put reference to buf map - okay if NULL */
index 8697dc0..0b2f04b 100644 (file)
@@ -46,18 +46,6 @@ static unsigned char clk_gat_sce(unsigned int which, unsigned int chan,
               ((source & 030) << 3) | (source & 007);
 }
 
-static unsigned char clk_sce(unsigned int which, unsigned int chan,
-                            unsigned int source)
-{
-       return clk_gat_sce(which, chan, source);
-}
-
-static unsigned char gat_sce(unsigned int which, unsigned int chan,
-                            unsigned int source)
-{
-       return clk_gat_sce(which, chan, source);
-}
-
 /*
  * Periods of the internal clock sources in nanoseconds.
  */
@@ -489,7 +477,7 @@ static void dio200_subdev_8254_set_gate_src(struct comedi_device *dev,
        unsigned int offset = dio200_subdev_8254_offset(dev, s);
 
        dio200_write8(dev, DIO200_GAT_SCE(offset >> 3),
-                     gat_sce((offset >> 2) & 1, chan, src));
+                     clk_gat_sce((offset >> 2) & 1, chan, src));
 }
 
 static void dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
@@ -500,7 +488,7 @@ static void dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
        unsigned int offset = dio200_subdev_8254_offset(dev, s);
 
        dio200_write8(dev, DIO200_CLK_SCE(offset >> 3),
-                     clk_sce((offset >> 2) & 1, chan, src));
+                     clk_gat_sce((offset >> 2) & 1, chan, src));
 }
 
 static int dio200_subdev_8254_config(struct comedi_device *dev,
index 65f60c2..f7e6731 100644 (file)
@@ -2330,7 +2330,8 @@ static irqreturn_t pci230_interrupt(int irq, void *d)
        devpriv->intr_running = false;
        spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
 
-       comedi_handle_events(dev, s_ao);
+       if (s_ao)
+               comedi_handle_events(dev, s_ao);
        comedi_handle_events(dev, s_ai);
 
        return IRQ_HANDLED;
index 3be927f..e15e33e 100644 (file)
@@ -557,7 +557,8 @@ static irqreturn_t dt282x_interrupt(int irq, void *d)
        }
 #endif
        comedi_handle_events(dev, s);
-       comedi_handle_events(dev, s_ao);
+       if (s_ao)
+               comedi_handle_events(dev, s_ao);
 
        return IRQ_RETVAL(handled);
 }
index 639ec15..cc9fc26 100644 (file)
@@ -558,7 +558,14 @@ void mite_prep_dma(struct mite_channel *mite_chan,
 }
 EXPORT_SYMBOL_GPL(mite_prep_dma);
 
-static struct mite_channel *__mite_request_channel(struct mite *mite,
+/**
+ * mite_request_channel_in_range() - Request a MITE dma channel.
+ * @mite: MITE device.
+ * @ring: MITE dma ring.
+ * @min_channel: minimum channel index to use.
+ * @max_channel: maximum channel index to use.
+ */
+struct mite_channel *mite_request_channel_in_range(struct mite *mite,
                                                   struct mite_ring *ring,
                                                   unsigned int min_channel,
                                                   unsigned int max_channel)
@@ -583,21 +590,6 @@ static struct mite_channel *__mite_request_channel(struct mite *mite,
        spin_unlock_irqrestore(&mite->lock, flags);
        return mite_chan;
 }
-
-/**
- * mite_request_channel_in_range() - Request a MITE dma channel.
- * @mite: MITE device.
- * @ring: MITE dma ring.
- * @min_channel: minimum channel index to use.
- * @max_channel: maximum channel index to use.
- */
-struct mite_channel *mite_request_channel_in_range(struct mite *mite,
-                                                  struct mite_ring *ring,
-                                                  unsigned int min_channel,
-                                                  unsigned int max_channel)
-{
-       return __mite_request_channel(mite, ring, min_channel, max_channel);
-}
 EXPORT_SYMBOL_GPL(mite_request_channel_in_range);
 
 /**
@@ -608,7 +600,8 @@ EXPORT_SYMBOL_GPL(mite_request_channel_in_range);
 struct mite_channel *mite_request_channel(struct mite *mite,
                                          struct mite_ring *ring)
 {
-       return __mite_request_channel(mite, ring, 0, mite->num_channels - 1);
+       return mite_request_channel_in_range(mite, ring, 0,
+                                            mite->num_channels - 1);
 }
 EXPORT_SYMBOL_GPL(mite_request_channel);
 
index b8f54b7..0350f30 100644 (file)
@@ -1226,7 +1226,7 @@ static int usbdux_pwm_period(struct comedi_device *dev,
                             unsigned int period)
 {
        struct usbdux_private *devpriv = dev->private;
-       int fx2delay = 255;
+       int fx2delay;
 
        if (period < MIN_PWM_PERIOD)
                return -EAGAIN;
index 38ab344..e704d9e 100644 (file)
@@ -2,12 +2,12 @@
 
 EROFS_VERSION = "1.0pre1"
 
-ccflags-y += -Wall -DEROFS_VERSION=\"$(EROFS_VERSION)\"
+ccflags-y += -DEROFS_VERSION=\"$(EROFS_VERSION)\"
 
 obj-$(CONFIG_EROFS_FS) += erofs.o
 # staging requirement: to be self-contained in its own directory
 ccflags-y += -I $(srctree)/$(src)/include
 erofs-objs := super.o inode.o data.o namei.o dir.o utils.o
 erofs-$(CONFIG_EROFS_FS_XATTR) += xattr.o
-erofs-$(CONFIG_EROFS_FS_ZIP) += unzip_vle.o unzip_vle_lz4.o
+erofs-$(CONFIG_EROFS_FS_ZIP) += unzip_vle.o zmap.o decompressor.o
 
diff --git a/drivers/staging/erofs/compress.h b/drivers/staging/erofs/compress.h
new file mode 100644 (file)
index 0000000..c43aa33
--- /dev/null
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * linux/drivers/staging/erofs/compress.h
+ *
+ * Copyright (C) 2019 HUAWEI, Inc.
+ *             http://www.huawei.com/
+ * Created by Gao Xiang <gaoxiang25@huawei.com>
+ */
+#ifndef __EROFS_FS_COMPRESS_H
+#define __EROFS_FS_COMPRESS_H
+
+#include "internal.h"
+
+enum {
+       Z_EROFS_COMPRESSION_SHIFTED = Z_EROFS_COMPRESSION_MAX,
+       Z_EROFS_COMPRESSION_RUNTIME_MAX
+};
+
+struct z_erofs_decompress_req {
+       struct super_block *sb;
+       struct page **in, **out;
+
+       unsigned short pageofs_out;
+       unsigned int inputsize, outputsize;
+
+       /* indicate the algorithm will be used for decompression */
+       unsigned int alg;
+       bool inplace_io, partial_decoding;
+};
+
+/*
+ * - 0x5A110C8D ('sallocated', Z_EROFS_MAPPING_STAGING) -
+ * used to mark temporary allocated pages from other
+ * file/cached pages and NULL mapping pages.
+ */
+#define Z_EROFS_MAPPING_STAGING         ((void *)0x5A110C8D)
+
+/* check if a page is marked as staging */
+static inline bool z_erofs_page_is_staging(struct page *page)
+{
+       return page->mapping == Z_EROFS_MAPPING_STAGING;
+}
+
+static inline bool z_erofs_put_stagingpage(struct list_head *pagepool,
+                                          struct page *page)
+{
+       if (!z_erofs_page_is_staging(page))
+               return false;
+
+       /* staging pages should not be used by others at the same time */
+       if (page_ref_count(page) > 1)
+               put_page(page);
+       else
+               list_add(&page->lru, pagepool);
+       return true;
+}
+
+int z_erofs_decompress(struct z_erofs_decompress_req *rq,
+                      struct list_head *pagepool);
+
+#endif
+
index 746685f..cc31c3e 100644 (file)
@@ -124,7 +124,7 @@ static int erofs_map_blocks_flatmode(struct inode *inode,
        trace_erofs_map_blocks_flatmode_enter(inode, map, flags);
 
        nblocks = DIV_ROUND_UP(inode->i_size, PAGE_SIZE);
-       lastblk = nblocks - is_inode_layout_inline(inode);
+       lastblk = nblocks - is_inode_flat_inline(inode);
 
        if (unlikely(offset >= inode->i_size)) {
                /* leave out-of-bound access unmapped */
@@ -139,7 +139,7 @@ static int erofs_map_blocks_flatmode(struct inode *inode,
        if (offset < blknr_to_addr(lastblk)) {
                map->m_pa = blknr_to_addr(vi->raw_blkaddr) + map->m_la;
                map->m_plen = blknr_to_addr(lastblk) - offset;
-       } else if (is_inode_layout_inline(inode)) {
+       } else if (is_inode_flat_inline(inode)) {
                /* 2 - inode inline B: inode, [xattrs], inline last blk... */
                struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb);
 
diff --git a/drivers/staging/erofs/decompressor.c b/drivers/staging/erofs/decompressor.c
new file mode 100644 (file)
index 0000000..1fb0abb
--- /dev/null
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * linux/drivers/staging/erofs/decompressor.c
+ *
+ * Copyright (C) 2019 HUAWEI, Inc.
+ *             http://www.huawei.com/
+ * Created by Gao Xiang <gaoxiang25@huawei.com>
+ */
+#include "compress.h"
+#include <linux/lz4.h>
+
+#ifndef LZ4_DISTANCE_MAX       /* history window size */
+#define LZ4_DISTANCE_MAX 65535 /* set to maximum value by default */
+#endif
+
+#define LZ4_MAX_DISTANCE_PAGES (DIV_ROUND_UP(LZ4_DISTANCE_MAX, PAGE_SIZE) + 1)
+#ifndef LZ4_DECOMPRESS_INPLACE_MARGIN
+#define LZ4_DECOMPRESS_INPLACE_MARGIN(srcsize)  (((srcsize) >> 8) + 32)
+#endif
+
+struct z_erofs_decompressor {
+       /*
+        * if destpages have sparsed pages, fill them with bounce pages.
+        * it also check whether destpages indicate continuous physical memory.
+        */
+       int (*prepare_destpages)(struct z_erofs_decompress_req *rq,
+                                struct list_head *pagepool);
+       int (*decompress)(struct z_erofs_decompress_req *rq, u8 *out);
+       char *name;
+};
+
+static int lz4_prepare_destpages(struct z_erofs_decompress_req *rq,
+                                struct list_head *pagepool)
+{
+       const unsigned int nr =
+               PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT;
+       struct page *availables[LZ4_MAX_DISTANCE_PAGES] = { NULL };
+       unsigned long bounced[DIV_ROUND_UP(LZ4_MAX_DISTANCE_PAGES,
+                                          BITS_PER_LONG)] = { 0 };
+       void *kaddr = NULL;
+       unsigned int i, j, top;
+
+       top = 0;
+       for (i = j = 0; i < nr; ++i, ++j) {
+               struct page *const page = rq->out[i];
+               struct page *victim;
+
+               if (j >= LZ4_MAX_DISTANCE_PAGES)
+                       j = 0;
+
+               /* 'valid' bounced can only be tested after a complete round */
+               if (test_bit(j, bounced)) {
+                       DBG_BUGON(i < LZ4_MAX_DISTANCE_PAGES);
+                       DBG_BUGON(top >= LZ4_MAX_DISTANCE_PAGES);
+                       availables[top++] = rq->out[i - LZ4_MAX_DISTANCE_PAGES];
+               }
+
+               if (page) {
+                       __clear_bit(j, bounced);
+                       if (kaddr) {
+                               if (kaddr + PAGE_SIZE == page_address(page))
+                                       kaddr += PAGE_SIZE;
+                               else
+                                       kaddr = NULL;
+                       } else if (!i) {
+                               kaddr = page_address(page);
+                       }
+                       continue;
+               }
+               kaddr = NULL;
+               __set_bit(j, bounced);
+
+               if (top) {
+                       victim = availables[--top];
+                       get_page(victim);
+               } else {
+                       if (!list_empty(pagepool)) {
+                               victim = lru_to_page(pagepool);
+                               list_del(&victim->lru);
+                               DBG_BUGON(page_ref_count(victim) != 1);
+                       } else {
+                               victim = alloc_pages(GFP_KERNEL, 0);
+                               if (!victim)
+                                       return -ENOMEM;
+                       }
+                       victim->mapping = Z_EROFS_MAPPING_STAGING;
+               }
+               rq->out[i] = victim;
+       }
+       return kaddr ? 1 : 0;
+}
+
+static void *generic_copy_inplace_data(struct z_erofs_decompress_req *rq,
+                                      u8 *src, unsigned int pageofs_in)
+{
+       /*
+        * if in-place decompression is ongoing, those decompressed
+        * pages should be copied in order to avoid being overlapped.
+        */
+       struct page **in = rq->in;
+       u8 *const tmp = erofs_get_pcpubuf(0);
+       u8 *tmpp = tmp;
+       unsigned int inlen = rq->inputsize - pageofs_in;
+       unsigned int count = min_t(uint, inlen, PAGE_SIZE - pageofs_in);
+
+       while (tmpp < tmp + inlen) {
+               if (!src)
+                       src = kmap_atomic(*in);
+               memcpy(tmpp, src + pageofs_in, count);
+               kunmap_atomic(src);
+               src = NULL;
+               tmpp += count;
+               pageofs_in = 0;
+               count = PAGE_SIZE;
+               ++in;
+       }
+       return tmp;
+}
+
+static int lz4_decompress(struct z_erofs_decompress_req *rq, u8 *out)
+{
+       unsigned int inputmargin, inlen;
+       u8 *src;
+       bool copied, support_0padding;
+       int ret;
+
+       if (rq->inputsize > PAGE_SIZE)
+               return -ENOTSUPP;
+
+       src = kmap_atomic(*rq->in);
+       inputmargin = 0;
+       support_0padding = false;
+
+       /* decompression inplace is only safe when 0padding is enabled */
+       if (EROFS_SB(rq->sb)->requirements & EROFS_REQUIREMENT_LZ4_0PADDING) {
+               support_0padding = true;
+
+               while (!src[inputmargin & ~PAGE_MASK])
+                       if (!(++inputmargin & ~PAGE_MASK))
+                               break;
+
+               if (inputmargin >= rq->inputsize) {
+                       kunmap_atomic(src);
+                       return -EIO;
+               }
+       }
+
+       copied = false;
+       inlen = rq->inputsize - inputmargin;
+       if (rq->inplace_io) {
+               const uint oend = (rq->pageofs_out +
+                                  rq->outputsize) & ~PAGE_MASK;
+               const uint nr = PAGE_ALIGN(rq->pageofs_out +
+                                          rq->outputsize) >> PAGE_SHIFT;
+
+               if (rq->partial_decoding || !support_0padding ||
+                   rq->out[nr - 1] != rq->in[0] ||
+                   rq->inputsize - oend <
+                     LZ4_DECOMPRESS_INPLACE_MARGIN(inlen)) {
+                       src = generic_copy_inplace_data(rq, src, inputmargin);
+                       inputmargin = 0;
+                       copied = true;
+               }
+       }
+
+       ret = LZ4_decompress_safe_partial(src + inputmargin, out,
+                                         inlen, rq->outputsize,
+                                         rq->outputsize);
+       if (ret < 0) {
+               errln("%s, failed to decompress, in[%p, %u, %u] out[%p, %u]",
+                     __func__, src + inputmargin, inlen, inputmargin,
+                     out, rq->outputsize);
+               WARN_ON(1);
+               print_hex_dump(KERN_DEBUG, "[ in]: ", DUMP_PREFIX_OFFSET,
+                              16, 1, src + inputmargin, inlen, true);
+               print_hex_dump(KERN_DEBUG, "[out]: ", DUMP_PREFIX_OFFSET,
+                              16, 1, out, rq->outputsize, true);
+               ret = -EIO;
+       }
+
+       if (copied)
+               erofs_put_pcpubuf(src);
+       else
+               kunmap_atomic(src);
+       return ret;
+}
+
+static struct z_erofs_decompressor decompressors[] = {
+       [Z_EROFS_COMPRESSION_SHIFTED] = {
+               .name = "shifted"
+       },
+       [Z_EROFS_COMPRESSION_LZ4] = {
+               .prepare_destpages = lz4_prepare_destpages,
+               .decompress = lz4_decompress,
+               .name = "lz4"
+       },
+};
+
+static void copy_from_pcpubuf(struct page **out, const char *dst,
+                             unsigned short pageofs_out,
+                             unsigned int outputsize)
+{
+       const char *end = dst + outputsize;
+       const unsigned int righthalf = PAGE_SIZE - pageofs_out;
+       const char *cur = dst - pageofs_out;
+
+       while (cur < end) {
+               struct page *const page = *out++;
+
+               if (page) {
+                       char *buf = kmap_atomic(page);
+
+                       if (cur >= dst) {
+                               memcpy(buf, cur, min_t(uint, PAGE_SIZE,
+                                                      end - cur));
+                       } else {
+                               memcpy(buf + pageofs_out, cur + pageofs_out,
+                                      min_t(uint, righthalf, end - cur));
+                       }
+                       kunmap_atomic(buf);
+               }
+               cur += PAGE_SIZE;
+       }
+}
+
+static int decompress_generic(struct z_erofs_decompress_req *rq,
+                             struct list_head *pagepool)
+{
+       const unsigned int nrpages_out =
+               PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT;
+       const struct z_erofs_decompressor *alg = decompressors + rq->alg;
+       unsigned int dst_maptype;
+       void *dst;
+       int ret;
+
+       if (nrpages_out == 1 && !rq->inplace_io) {
+               DBG_BUGON(!*rq->out);
+               dst = kmap_atomic(*rq->out);
+               dst_maptype = 0;
+               goto dstmap_out;
+       }
+
+       /*
+        * For the case of small output size (especially much less
+        * than PAGE_SIZE), memcpy the decompressed data rather than
+        * compressed data is preferred.
+        */
+       if (rq->outputsize <= PAGE_SIZE * 7 / 8) {
+               dst = erofs_get_pcpubuf(0);
+               if (IS_ERR(dst))
+                       return PTR_ERR(dst);
+
+               rq->inplace_io = false;
+               ret = alg->decompress(rq, dst);
+               if (!ret)
+                       copy_from_pcpubuf(rq->out, dst, rq->pageofs_out,
+                                         rq->outputsize);
+
+               erofs_put_pcpubuf(dst);
+               return ret;
+       }
+
+       ret = alg->prepare_destpages(rq, pagepool);
+       if (ret < 0) {
+               return ret;
+       } else if (ret) {
+               dst = page_address(*rq->out);
+               dst_maptype = 1;
+               goto dstmap_out;
+       }
+
+       dst = erofs_vmap(rq->out, nrpages_out);
+       if (!dst)
+               return -ENOMEM;
+       dst_maptype = 2;
+
+dstmap_out:
+       ret = alg->decompress(rq, dst + rq->pageofs_out);
+
+       if (!dst_maptype)
+               kunmap_atomic(dst);
+       else if (dst_maptype == 2)
+               erofs_vunmap(dst, nrpages_out);
+       return ret;
+}
+
+static int shifted_decompress(const struct z_erofs_decompress_req *rq,
+                             struct list_head *pagepool)
+{
+       const unsigned int nrpages_out =
+               PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT;
+       const unsigned int righthalf = PAGE_SIZE - rq->pageofs_out;
+       unsigned char *src, *dst;
+
+       if (nrpages_out > 2) {
+               DBG_BUGON(1);
+               return -EIO;
+       }
+
+       if (rq->out[0] == *rq->in) {
+               DBG_BUGON(nrpages_out != 1);
+               return 0;
+       }
+
+       src = kmap_atomic(*rq->in);
+       if (!rq->out[0]) {
+               dst = NULL;
+       } else {
+               dst = kmap_atomic(rq->out[0]);
+               memcpy(dst + rq->pageofs_out, src, righthalf);
+       }
+
+       if (rq->out[1] == *rq->in) {
+               memmove(src, src + righthalf, rq->pageofs_out);
+       } else if (nrpages_out == 2) {
+               if (dst)
+                       kunmap_atomic(dst);
+               DBG_BUGON(!rq->out[1]);
+               dst = kmap_atomic(rq->out[1]);
+               memcpy(dst, src + righthalf, rq->pageofs_out);
+       }
+       if (dst)
+               kunmap_atomic(dst);
+       kunmap_atomic(src);
+       return 0;
+}
+
+int z_erofs_decompress(struct z_erofs_decompress_req *rq,
+                      struct list_head *pagepool)
+{
+       if (rq->alg == Z_EROFS_COMPRESSION_SHIFTED)
+               return shifted_decompress(rq, pagepool);
+       return decompress_generic(rq, pagepool);
+}
+
index 9bbc687..dbf6a15 100644 (file)
@@ -42,10 +42,9 @@ static int erofs_fill_dentries(struct dir_context *ctx,
                               void *dentry_blk, unsigned int *ofs,
                               unsigned int nameoff, unsigned int maxsize)
 {
-       struct erofs_dirent *de = dentry_blk;
+       struct erofs_dirent *de = dentry_blk + *ofs;
        const struct erofs_dirent *end = dentry_blk + nameoff;
 
-       de = dentry_blk + *ofs;
        while (de < end) {
                const char *de_name;
                unsigned int de_namelen;
index 8ddb2b3..9f61abb 100644 (file)
@@ -21,7 +21,8 @@
  * Any bits that aren't in EROFS_ALL_REQUIREMENTS should be
  * incompatible with this kernel version.
  */
-#define EROFS_ALL_REQUIREMENTS  0
+#define EROFS_REQUIREMENT_LZ4_0PADDING 0x00000001
+#define EROFS_ALL_REQUIREMENTS         EROFS_REQUIREMENT_LZ4_0PADDING
 
 struct erofs_super_block {
 /*  0 */__le32 magic;           /* in the little endian */
@@ -49,19 +50,29 @@ struct erofs_super_block {
  * erofs inode data mapping:
  * 0 - inode plain without inline data A:
  * inode, [xattrs], ... | ... | no-holed data
- * 1 - inode VLE compression B:
+ * 1 - inode VLE compression B (legacy):
  * inode, [xattrs], extents ... | ...
  * 2 - inode plain with inline data C:
  * inode, [xattrs], last_inline_data, ... | ... | no-holed data
- * 3~7 - reserved
+ * 3 - inode compression D:
+ * inode, [xattrs], map_header, extents ... | ...
+ * 4~7 - reserved
  */
 enum {
-       EROFS_INODE_LAYOUT_PLAIN,
-       EROFS_INODE_LAYOUT_COMPRESSION,
-       EROFS_INODE_LAYOUT_INLINE,
+       EROFS_INODE_FLAT_PLAIN,
+       EROFS_INODE_FLAT_COMPRESSION_LEGACY,
+       EROFS_INODE_FLAT_INLINE,
+       EROFS_INODE_FLAT_COMPRESSION,
        EROFS_INODE_LAYOUT_MAX
 };
 
+static bool erofs_inode_is_data_compressed(unsigned int datamode)
+{
+       if (datamode == EROFS_INODE_FLAT_COMPRESSION)
+               return true;
+       return datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY;
+}
+
 /* bit definitions of inode i_advise */
 #define EROFS_I_VERSION_BITS            1
 #define EROFS_I_DATA_MAPPING_BITS       3
@@ -176,11 +187,39 @@ struct erofs_xattr_entry {
        sizeof(struct erofs_xattr_entry) + \
        (entry)->e_name_len + le16_to_cpu((entry)->e_value_size))
 
-/* have to be aligned with 8 bytes on disk */
-struct erofs_extent_header {
-       __le32 eh_checksum;
-       __le32 eh_reserved[3];
-} __packed;
+/* available compression algorithm types */
+enum {
+       Z_EROFS_COMPRESSION_LZ4,
+       Z_EROFS_COMPRESSION_MAX
+};
+
+/*
+ * bit 0 : COMPACTED_2B indexes (0 - off; 1 - on)
+ *  e.g. for 4k logical cluster size,      4B        if compacted 2B is off;
+ *                                  (4B) + 2B + (4B) if compacted 2B is on.
+ */
+#define Z_EROFS_ADVISE_COMPACTED_2B_BIT         0
+
+#define Z_EROFS_ADVISE_COMPACTED_2B     (1 << Z_EROFS_ADVISE_COMPACTED_2B_BIT)
+
+struct z_erofs_map_header {
+       __le32  h_reserved1;
+       __le16  h_advise;
+       /*
+        * bit 0-3 : algorithm type of head 1 (logical cluster type 01);
+        * bit 4-7 : algorithm type of head 2 (logical cluster type 11).
+        */
+       __u8    h_algorithmtype;
+       /*
+        * bit 0-2 : logical cluster bits - 12, e.g. 0 for 4096;
+        * bit 3-4 : (physical - logical) cluster bits of head 1:
+        *       For example, if logical clustersize = 4096, 1 for 8192.
+        * bit 5-7 : (physical - logical) cluster bits of head 2.
+        */
+       __u8    h_clusterbits;
+};
+
+#define Z_EROFS_VLE_LEGACY_HEADER_PADDING       8
 
 /*
  * Z_EROFS Variable-sized Logical Extent cluster type:
@@ -236,8 +275,9 @@ struct z_erofs_vle_decompressed_index {
        } di_u __packed;                /* 8 bytes */
 } __packed;
 
-#define Z_EROFS_VLE_EXTENT_ALIGN(size) round_up(size, \
-       sizeof(struct z_erofs_vle_decompressed_index))
+#define Z_EROFS_VLE_LEGACY_INDEX_ALIGN(size) \
+       (round_up(size, sizeof(struct z_erofs_vle_decompressed_index)) + \
+        sizeof(struct z_erofs_map_header) + Z_EROFS_VLE_LEGACY_HEADER_PADDING)
 
 /* dirent sorts in alphabet order, thus we can do binary search */
 struct erofs_dirent {
@@ -270,7 +310,7 @@ static inline void erofs_check_ondisk_layout_definitions(void)
        BUILD_BUG_ON(sizeof(struct erofs_inode_v2) != 64);
        BUILD_BUG_ON(sizeof(struct erofs_xattr_ibody_header) != 12);
        BUILD_BUG_ON(sizeof(struct erofs_xattr_entry) != 4);
-       BUILD_BUG_ON(sizeof(struct erofs_extent_header) != 16);
+       BUILD_BUG_ON(sizeof(struct z_erofs_map_header) != 8);
        BUILD_BUG_ON(sizeof(struct z_erofs_vle_decompressed_index) != 8);
        BUILD_BUG_ON(sizeof(struct erofs_dirent) != 12);
 
index c7d3b81..4c3d8bf 100644 (file)
@@ -20,12 +20,13 @@ static int read_inode(struct inode *inode, void *data)
        struct erofs_vnode *vi = EROFS_V(inode);
        struct erofs_inode_v1 *v1 = data;
        const unsigned int advise = le16_to_cpu(v1->i_advise);
+       erofs_blk_t nblks = 0;
 
-       vi->data_mapping_mode = __inode_data_mapping(advise);
+       vi->datamode = __inode_data_mapping(advise);
 
-       if (unlikely(vi->data_mapping_mode >= EROFS_INODE_LAYOUT_MAX)) {
-               errln("unknown data mapping mode %u of nid %llu",
-                     vi->data_mapping_mode, vi->nid);
+       if (unlikely(vi->datamode >= EROFS_INODE_LAYOUT_MAX)) {
+               errln("unsupported data mapping %u of nid %llu",
+                     vi->datamode, vi->nid);
                DBG_BUGON(1);
                return -EIO;
        }
@@ -60,6 +61,10 @@ static int read_inode(struct inode *inode, void *data)
                        le32_to_cpu(v2->i_ctime_nsec);
 
                inode->i_size = le64_to_cpu(v2->i_size);
+
+               /* total blocks for compressed files */
+               if (is_inode_layout_compression(inode))
+                       nblks = le32_to_cpu(v2->i_u.compressed_blocks);
        } else if (__inode_version(advise) == EROFS_INODE_LAYOUT_V1) {
                struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb);
 
@@ -90,6 +95,8 @@ static int read_inode(struct inode *inode, void *data)
                        sbi->build_time_nsec;
 
                inode->i_size = le32_to_cpu(v1->i_size);
+               if (is_inode_layout_compression(inode))
+                       nblks = le32_to_cpu(v1->i_u.compressed_blocks);
        } else {
                errln("unsupported on-disk inode version %u of nid %llu",
                      __inode_version(advise), vi->nid);
@@ -97,8 +104,11 @@ static int read_inode(struct inode *inode, void *data)
                return -EIO;
        }
 
-       /* measure inode.i_blocks as the generic filesystem */
-       inode->i_blocks = ((inode->i_size - 1) >> 9) + 1;
+       if (!nblks)
+               /* measure inode.i_blocks as generic filesystems */
+               inode->i_blocks = roundup(inode->i_size, EROFS_BLKSIZ) >> 9;
+       else
+               inode->i_blocks = nblks << LOG_SECTORS_PER_BLOCK;
        return 0;
 }
 
@@ -117,12 +127,9 @@ static int fill_inline_data(struct inode *inode, void *data,
 {
        struct erofs_vnode *vi = EROFS_V(inode);
        struct erofs_sb_info *sbi = EROFS_I_SB(inode);
-       int mode = vi->data_mapping_mode;
-
-       DBG_BUGON(mode >= EROFS_INODE_LAYOUT_MAX);
 
        /* should be inode inline C */
-       if (mode != EROFS_INODE_LAYOUT_INLINE)
+       if (!is_inode_flat_inline(inode))
                return 0;
 
        /* fast symlink (following ext4) */
@@ -148,7 +155,7 @@ static int fill_inline_data(struct inode *inode, void *data,
                inode->i_link = lnk;
                set_inode_fast_symlink(inode);
        }
-       return -EAGAIN;
+       return 0;
 }
 
 static int fill_inode(struct inode *inode, int isdir)
@@ -197,25 +204,21 @@ static int fill_inode(struct inode *inode, int isdir)
                        S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
                        inode->i_op = &erofs_generic_iops;
                        init_special_inode(inode, inode->i_mode, inode->i_rdev);
+                       goto out_unlock;
                } else {
                        err = -EIO;
                        goto out_unlock;
                }
 
                if (is_inode_layout_compression(inode)) {
-#ifdef CONFIG_EROFS_FS_ZIP
-                       inode->i_mapping->a_ops =
-                               &z_erofs_vle_normalaccess_aops;
-#else
-                       err = -ENOTSUPP;
-#endif
+                       err = z_erofs_fill_inode(inode);
                        goto out_unlock;
                }
 
                inode->i_mapping->a_ops = &erofs_raw_access_aops;
 
                /* fill last page if inline data is available */
-               fill_inline_data(inode, data, ofs);
+               err = fill_inline_data(inode, data, ofs);
        }
 
 out_unlock:
@@ -285,7 +288,24 @@ struct inode *erofs_iget(struct super_block *sb,
        return inode;
 }
 
+int erofs_getattr(const struct path *path, struct kstat *stat,
+                 u32 request_mask, unsigned int query_flags)
+{
+       struct inode *const inode = d_inode(path->dentry);
+
+       if (is_inode_layout_compression(inode))
+               stat->attributes |= STATX_ATTR_COMPRESSED;
+
+       stat->attributes |= STATX_ATTR_IMMUTABLE;
+       stat->attributes_mask |= (STATX_ATTR_COMPRESSED |
+                                 STATX_ATTR_IMMUTABLE);
+
+       generic_fillattr(inode, stat);
+       return 0;
+}
+
 const struct inode_operations erofs_generic_iops = {
+       .getattr = erofs_getattr,
 #ifdef CONFIG_EROFS_FS_XATTR
        .listxattr = erofs_listxattr,
 #endif
@@ -294,6 +314,7 @@ const struct inode_operations erofs_generic_iops = {
 
 const struct inode_operations erofs_symlink_iops = {
        .get_link = page_get_link,
+       .getattr = erofs_getattr,
 #ifdef CONFIG_EROFS_FS_XATTR
        .listxattr = erofs_listxattr,
 #endif
@@ -302,6 +323,7 @@ const struct inode_operations erofs_symlink_iops = {
 
 const struct inode_operations erofs_fast_symlink_iops = {
        .get_link = simple_get_link,
+       .getattr = erofs_getattr,
 #ifdef CONFIG_EROFS_FS_XATTR
        .listxattr = erofs_listxattr,
 #endif
index 382258f..963cc1b 100644 (file)
@@ -321,6 +321,10 @@ static inline void z_erofs_exit_zip_subsystem(void) {}
 
 /* page count of a compressed cluster */
 #define erofs_clusterpages(sbi)         ((1 << (sbi)->clusterbits) / PAGE_SIZE)
+
+#define EROFS_PCPUBUF_NR_PAGES          Z_EROFS_CLUSTER_MAX_PAGES
+#else
+#define EROFS_PCPUBUF_NR_PAGES          0
 #endif
 
 typedef u64 erofs_off_t;
@@ -339,9 +343,11 @@ static inline erofs_off_t iloc(struct erofs_sb_info *sbi, erofs_nid_t nid)
 
 /* atomic flag definitions */
 #define EROFS_V_EA_INITED_BIT  0
+#define EROFS_V_Z_INITED_BIT   1
 
 /* bitlock definitions (arranged in reverse order) */
 #define EROFS_V_BL_XATTR_BIT   (BITS_PER_LONG - 1)
+#define EROFS_V_BL_Z_BIT       (BITS_PER_LONG - 2)
 
 struct erofs_vnode {
        erofs_nid_t nid;
@@ -349,16 +355,24 @@ struct erofs_vnode {
        /* atomic flags (including bitlocks) */
        unsigned long flags;
 
-       unsigned char data_mapping_mode;
-       /* inline size in bytes */
+       unsigned char datamode;
        unsigned char inode_isize;
        unsigned short xattr_isize;
 
        unsigned xattr_shared_count;
        unsigned *xattr_shared_xattrs;
 
-       erofs_blk_t raw_blkaddr;
-
+       union {
+               erofs_blk_t raw_blkaddr;
+#ifdef CONFIG_EROFS_FS_ZIP
+               struct {
+                       unsigned short z_advise;
+                       unsigned char  z_algorithmtype[2];
+                       unsigned char  z_logical_clusterbits;
+                       unsigned char  z_physical_clusterbits[2];
+               };
+#endif
+       };
        /* the corresponding vfs inode */
        struct inode vfs_inode;
 };
@@ -383,20 +397,14 @@ static inline unsigned long inode_datablocks(struct inode *inode)
        return DIV_ROUND_UP(inode->i_size, EROFS_BLKSIZ);
 }
 
-static inline bool is_inode_layout_plain(struct inode *inode)
-{
-       return EROFS_V(inode)->data_mapping_mode == EROFS_INODE_LAYOUT_PLAIN;
-}
-
 static inline bool is_inode_layout_compression(struct inode *inode)
 {
-       return EROFS_V(inode)->data_mapping_mode ==
-                                       EROFS_INODE_LAYOUT_COMPRESSION;
+       return erofs_inode_is_data_compressed(EROFS_V(inode)->datamode);
 }
 
-static inline bool is_inode_layout_inline(struct inode *inode)
+static inline bool is_inode_flat_inline(struct inode *inode)
 {
-       return EROFS_V(inode)->data_mapping_mode == EROFS_INODE_LAYOUT_INLINE;
+       return EROFS_V(inode)->datamode == EROFS_INODE_FLAT_INLINE;
 }
 
 extern const struct super_operations erofs_sops;
@@ -433,6 +441,7 @@ extern const struct address_space_operations z_erofs_vle_normalaccess_aops;
  */
 enum {
        BH_Zipped = BH_PrivateStart,
+       BH_FullMapped,
 };
 
 /* Has a disk mapping */
@@ -441,6 +450,8 @@ enum {
 #define EROFS_MAP_META         (1 << BH_Meta)
 /* The extent has been compressed */
 #define EROFS_MAP_ZIPPED       (1 << BH_Zipped)
+/* The length of extent is full */
+#define EROFS_MAP_FULL_MAPPED  (1 << BH_FullMapped)
 
 struct erofs_map_blocks {
        erofs_off_t m_pa, m_la;
@@ -454,11 +465,14 @@ struct erofs_map_blocks {
 /* Flags used by erofs_map_blocks() */
 #define EROFS_GET_BLOCKS_RAW    0x0001
 
+/* zmap.c */
 #ifdef CONFIG_EROFS_FS_ZIP
+int z_erofs_fill_inode(struct inode *inode);
 int z_erofs_map_blocks_iter(struct inode *inode,
                            struct erofs_map_blocks *map,
                            int flags);
 #else
+static inline int z_erofs_fill_inode(struct inode *inode) { return -ENOTSUPP; }
 static inline int z_erofs_map_blocks_iter(struct inode *inode,
                                          struct erofs_map_blocks *map,
                                          int flags)
@@ -558,6 +572,8 @@ static inline bool is_inode_fast_symlink(struct inode *inode)
 }
 
 struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid, bool dir);
+int erofs_getattr(const struct path *path, struct kstat *stat,
+                 u32 request_mask, unsigned int query_flags);
 
 /* namei.c */
 extern const struct inode_operations erofs_dir_iops;
@@ -599,6 +615,22 @@ static inline void erofs_vunmap(const void *mem, unsigned int count)
 extern struct shrinker erofs_shrinker_info;
 
 struct page *erofs_allocpage(struct list_head *pool, gfp_t gfp);
+
+#if (EROFS_PCPUBUF_NR_PAGES > 0)
+void *erofs_get_pcpubuf(unsigned int pagenr);
+#define erofs_put_pcpubuf(buf) do { \
+       (void)&(buf);   \
+       preempt_enable();       \
+} while (0)
+#else
+static inline void *erofs_get_pcpubuf(unsigned int pagenr)
+{
+       return ERR_PTR(-ENOTSUPP);
+}
+
+#define erofs_put_pcpubuf(buf) do {} while (0)
+#endif
+
 void erofs_register_super(struct super_block *sb);
 void erofs_unregister_super(struct super_block *sb);
 
index d8d9dc9..fd3ae78 100644 (file)
@@ -247,6 +247,7 @@ static struct dentry *erofs_lookup(struct inode *dir,
 
 const struct inode_operations erofs_dir_iops = {
        .lookup = erofs_lookup,
+       .getattr = erofs_getattr,
 #ifdef CONFIG_EROFS_FS_XATTR
        .listxattr = erofs_listxattr,
 #endif
index cadbcc1..5449441 100644 (file)
@@ -383,7 +383,7 @@ static int erofs_read_super(struct super_block *sb,
                goto err;
        }
 
-       sbi = kzalloc(sizeof(struct erofs_sb_info), GFP_KERNEL);
+       sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
        if (unlikely(!sbi)) {
                err = -ENOMEM;
                goto err;
index f37d8fd..7af0ba8 100644 (file)
@@ -69,10 +69,7 @@ z_erofs_pagevec_ctor_next_page(struct z_erofs_pagevec_ctor *ctor,
                if (tags == Z_EROFS_PAGE_TYPE_EXCLUSIVE)
                        return tagptr_unfold_ptr(t);
        }
-
-       if (unlikely(nr >= ctor->nr))
-               BUG();
-
+       DBG_BUGON(nr >= ctor->nr);
        return NULL;
 }
 
index 9ecaa87..f0dab81 100644 (file)
@@ -11,6 +11,7 @@
  * distribution for more details.
  */
 #include "unzip_vle.h"
+#include "compress.h"
 #include <linux/prefetch.h>
 
 #include <trace/events/erofs.h>
@@ -329,7 +330,7 @@ try_to_claim_workgroup(struct z_erofs_vle_workgroup *grp,
                       z_erofs_vle_owned_workgrp_t *owned_head,
                       bool *hosted)
 {
-       DBG_BUGON(*hosted == true);
+       DBG_BUGON(*hosted);
 
        /* let's claim these following types of workgroup */
 retry:
@@ -468,6 +469,9 @@ z_erofs_vle_work_register(const struct z_erofs_vle_work_finder *f,
                                    Z_EROFS_VLE_WORKGRP_FMT_LZ4 :
                                    Z_EROFS_VLE_WORKGRP_FMT_PLAIN);
 
+       if (map->m_flags & EROFS_MAP_FULL_MAPPED)
+               grp->flags |= Z_EROFS_VLE_WORKGRP_FULL_LENGTH;
+
        /* new workgrps have been claimed as type 1 */
        WRITE_ONCE(grp->next, *f->owned_head);
        /* primary and followed work for all new workgrps */
@@ -552,8 +556,7 @@ repeat:
        if (IS_ERR(work))
                return PTR_ERR(work);
 got_it:
-       z_erofs_pagevec_ctor_init(&builder->vector,
-                                 Z_EROFS_VLE_INLINE_PAGEVECS,
+       z_erofs_pagevec_ctor_init(&builder->vector, Z_EROFS_NR_INLINE_PAGEVECS,
                                  work->pagevec, work->vcnt);
 
        if (builder->role >= Z_EROFS_VLE_WORK_PRIMARY) {
@@ -856,7 +859,7 @@ static inline void z_erofs_vle_read_endio(struct bio *bio)
                DBG_BUGON(PageUptodate(page));
                DBG_BUGON(!page->mapping);
 
-               if (unlikely(!sbi && !z_erofs_is_stagingpage(page))) {
+               if (unlikely(!sbi && !z_erofs_page_is_staging(page))) {
                        sbi = EROFS_SB(page->mapping->host->i_sb);
 
                        if (time_to_inject(sbi, FAULT_READ_IO)) {
@@ -897,12 +900,12 @@ static int z_erofs_vle_unzip(struct super_block *sb,
        unsigned int sparsemem_pages = 0;
        struct page *pages_onstack[Z_EROFS_VLE_VMAP_ONSTACK_PAGES];
        struct page **pages, **compressed_pages, *page;
-       unsigned int i, llen;
+       unsigned int algorithm;
+       unsigned int i, outputsize;
 
        enum z_erofs_page_type page_type;
-       bool overlapped;
+       bool overlapped, partial;
        struct z_erofs_vle_work *work;
-       void *vout;
        int err;
 
        might_sleep();
@@ -936,7 +939,7 @@ repeat:
        for (i = 0; i < nr_pages; ++i)
                pages[i] = NULL;
 
-       z_erofs_pagevec_ctor_init(&ctor, Z_EROFS_VLE_INLINE_PAGEVECS,
+       z_erofs_pagevec_ctor_init(&ctor, Z_EROFS_NR_INLINE_PAGEVECS,
                                  work->pagevec, 0);
 
        for (i = 0; i < work->vcnt; ++i) {
@@ -948,7 +951,7 @@ repeat:
                DBG_BUGON(!page);
                DBG_BUGON(!page->mapping);
 
-               if (z_erofs_gather_if_stagingpage(page_pool, page))
+               if (z_erofs_put_stagingpage(page_pool, page))
                        continue;
 
                if (page_type == Z_EROFS_VLE_PAGE_TYPE_HEAD)
@@ -978,7 +981,7 @@ repeat:
                DBG_BUGON(!page);
                DBG_BUGON(!page->mapping);
 
-               if (!z_erofs_is_stagingpage(page)) {
+               if (!z_erofs_page_is_staging(page)) {
                        if (erofs_page_is_managed(sbi, page)) {
                                if (unlikely(!PageUptodate(page)))
                                        err = -EIO;
@@ -1009,43 +1012,30 @@ repeat:
        if (unlikely(err))
                goto out;
 
-       llen = (nr_pages << PAGE_SHIFT) - work->pageofs;
-
-       if (z_erofs_vle_workgrp_fmt(grp) == Z_EROFS_VLE_WORKGRP_FMT_PLAIN) {
-               err = z_erofs_vle_plain_copy(compressed_pages, clusterpages,
-                                            pages, nr_pages, work->pageofs);
-               goto out;
-       }
-
-       if (llen > grp->llen)
-               llen = grp->llen;
-
-       err = z_erofs_vle_unzip_fast_percpu(compressed_pages, clusterpages,
-                                           pages, llen, work->pageofs);
-       if (err != -ENOTSUPP)
-               goto out;
-
-       if (sparsemem_pages >= nr_pages)
-               goto skip_allocpage;
-
-       for (i = 0; i < nr_pages; ++i) {
-               if (pages[i])
-                       continue;
-
-               pages[i] = __stagingpage_alloc(page_pool, GFP_NOFS);
-       }
-
-skip_allocpage:
-       vout = erofs_vmap(pages, nr_pages);
-       if (!vout) {
-               err = -ENOMEM;
-               goto out;
+       if (nr_pages << PAGE_SHIFT >= work->pageofs + grp->llen) {
+               outputsize = grp->llen;
+               partial = !(grp->flags & Z_EROFS_VLE_WORKGRP_FULL_LENGTH);
+       } else {
+               outputsize = (nr_pages << PAGE_SHIFT) - work->pageofs;
+               partial = true;
        }
 
-       err = z_erofs_vle_unzip_vmap(compressed_pages, clusterpages, vout,
-                                    llen, work->pageofs, overlapped);
-
-       erofs_vunmap(vout, nr_pages);
+       if (z_erofs_vle_workgrp_fmt(grp) == Z_EROFS_VLE_WORKGRP_FMT_PLAIN)
+               algorithm = Z_EROFS_COMPRESSION_SHIFTED;
+       else
+               algorithm = Z_EROFS_COMPRESSION_LZ4;
+
+       err = z_erofs_decompress(&(struct z_erofs_decompress_req) {
+                                       .sb = sb,
+                                       .in = compressed_pages,
+                                       .out = pages,
+                                       .pageofs_out = work->pageofs,
+                                       .inputsize = PAGE_SIZE,
+                                       .outputsize = outputsize,
+                                       .alg = algorithm,
+                                       .inplace_io = overlapped,
+                                       .partial_decoding = partial
+                                }, page_pool);
 
 out:
        /* must handle all compressed pages before endding pages */
@@ -1056,7 +1046,7 @@ out:
                        continue;
 
                /* recycle all individual staging pages */
-               (void)z_erofs_gather_if_stagingpage(page_pool, page);
+               (void)z_erofs_put_stagingpage(page_pool, page);
 
                WRITE_ONCE(compressed_pages[i], NULL);
        }
@@ -1069,7 +1059,7 @@ out:
                DBG_BUGON(!page->mapping);
 
                /* recycle all individual staging pages */
-               if (z_erofs_gather_if_stagingpage(page_pool, page))
+               if (z_erofs_put_stagingpage(page_pool, page))
                        continue;
 
                if (unlikely(err < 0))
@@ -1273,8 +1263,7 @@ jobqueue_init(struct super_block *sb,
                goto out;
        }
 
-       iosb = kvzalloc(sizeof(struct z_erofs_vle_unzip_io_sb),
-                       GFP_KERNEL | __GFP_NOFAIL);
+       iosb = kvzalloc(sizeof(*iosb), GFP_KERNEL | __GFP_NOFAIL);
        DBG_BUGON(!iosb);
 
        /* initialize fields in the allocated descriptor */
@@ -1600,289 +1589,3 @@ const struct address_space_operations z_erofs_vle_normalaccess_aops = {
        .readpages = z_erofs_vle_normalaccess_readpages,
 };
 
-/*
- * Variable-sized Logical Extent (Fixed Physical Cluster) Compression Mode
- * ---
- * VLE compression mode attempts to compress a number of logical data into
- * a physical cluster with a fixed size.
- * VLE compression mode uses "struct z_erofs_vle_decompressed_index".
- */
-#define __vle_cluster_advise(x, bit, bits) \
-       ((le16_to_cpu(x) >> (bit)) & ((1 << (bits)) - 1))
-
-#define __vle_cluster_type(advise) __vle_cluster_advise(advise, \
-       Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT, Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS)
-
-#define vle_cluster_type(di)   \
-       __vle_cluster_type((di)->di_advise)
-
-static int
-vle_decompressed_index_clusterofs(unsigned int *clusterofs,
-                                 unsigned int clustersize,
-                                 struct z_erofs_vle_decompressed_index *di)
-{
-       switch (vle_cluster_type(di)) {
-       case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
-               *clusterofs = clustersize;
-               break;
-       case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
-       case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
-               *clusterofs = le16_to_cpu(di->di_clusterofs);
-               break;
-       default:
-               DBG_BUGON(1);
-               return -EIO;
-       }
-       return 0;
-}
-
-static inline erofs_blk_t
-vle_extent_blkaddr(struct inode *inode, pgoff_t index)
-{
-       struct erofs_sb_info *sbi = EROFS_I_SB(inode);
-       struct erofs_vnode *vi = EROFS_V(inode);
-
-       unsigned int ofs = Z_EROFS_VLE_EXTENT_ALIGN(vi->inode_isize +
-               vi->xattr_isize) + sizeof(struct erofs_extent_header) +
-               index * sizeof(struct z_erofs_vle_decompressed_index);
-
-       return erofs_blknr(iloc(sbi, vi->nid) + ofs);
-}
-
-static inline unsigned int
-vle_extent_blkoff(struct inode *inode, pgoff_t index)
-{
-       struct erofs_sb_info *sbi = EROFS_I_SB(inode);
-       struct erofs_vnode *vi = EROFS_V(inode);
-
-       unsigned int ofs = Z_EROFS_VLE_EXTENT_ALIGN(vi->inode_isize +
-               vi->xattr_isize) + sizeof(struct erofs_extent_header) +
-               index * sizeof(struct z_erofs_vle_decompressed_index);
-
-       return erofs_blkoff(iloc(sbi, vi->nid) + ofs);
-}
-
-struct vle_map_blocks_iter_ctx {
-       struct inode *inode;
-       struct super_block *sb;
-       unsigned int clusterbits;
-
-       struct page **mpage_ret;
-       void **kaddr_ret;
-};
-
-static int
-vle_get_logical_extent_head(const struct vle_map_blocks_iter_ctx *ctx,
-                           unsigned int lcn,   /* logical cluster number */
-                           unsigned long long *ofs,
-                           erofs_blk_t *pblk,
-                           unsigned int *flags)
-{
-       const unsigned int clustersize = 1 << ctx->clusterbits;
-       const erofs_blk_t mblk = vle_extent_blkaddr(ctx->inode, lcn);
-       struct page *mpage = *ctx->mpage_ret;   /* extent metapage */
-
-       struct z_erofs_vle_decompressed_index *di;
-       unsigned int cluster_type, delta0;
-
-       if (mpage->index != mblk) {
-               kunmap_atomic(*ctx->kaddr_ret);
-               unlock_page(mpage);
-               put_page(mpage);
-
-               mpage = erofs_get_meta_page(ctx->sb, mblk, false);
-               if (IS_ERR(mpage)) {
-                       *ctx->mpage_ret = NULL;
-                       return PTR_ERR(mpage);
-               }
-               *ctx->mpage_ret = mpage;
-               *ctx->kaddr_ret = kmap_atomic(mpage);
-       }
-
-       di = *ctx->kaddr_ret + vle_extent_blkoff(ctx->inode, lcn);
-
-       cluster_type = vle_cluster_type(di);
-       switch (cluster_type) {
-       case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
-               delta0 = le16_to_cpu(di->di_u.delta[0]);
-               if (unlikely(!delta0 || delta0 > lcn)) {
-                       errln("invalid NONHEAD dl0 %u at lcn %u of nid %llu",
-                             delta0, lcn, EROFS_V(ctx->inode)->nid);
-                       DBG_BUGON(1);
-                       return -EIO;
-               }
-               return vle_get_logical_extent_head(ctx,
-                       lcn - delta0, ofs, pblk, flags);
-       case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
-               *flags ^= EROFS_MAP_ZIPPED;
-               /* fallthrough */
-       case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
-               /* clustersize should be a power of two */
-               *ofs = ((u64)lcn << ctx->clusterbits) +
-                       (le16_to_cpu(di->di_clusterofs) & (clustersize - 1));
-               *pblk = le32_to_cpu(di->di_u.blkaddr);
-               break;
-       default:
-               errln("unknown cluster type %u at lcn %u of nid %llu",
-                     cluster_type, lcn, EROFS_V(ctx->inode)->nid);
-               DBG_BUGON(1);
-               return -EIO;
-       }
-       return 0;
-}
-
-int z_erofs_map_blocks_iter(struct inode *inode,
-                           struct erofs_map_blocks *map,
-                           int flags)
-{
-       void *kaddr;
-       const struct vle_map_blocks_iter_ctx ctx = {
-               .inode = inode,
-               .sb = inode->i_sb,
-               .clusterbits = EROFS_I_SB(inode)->clusterbits,
-               .mpage_ret = &map->mpage,
-               .kaddr_ret = &kaddr
-       };
-       const unsigned int clustersize = 1 << ctx.clusterbits;
-       /* if both m_(l,p)len are 0, regularize l_lblk, l_lofs, etc... */
-       const bool initial = !map->m_llen;
-
-       /* logicial extent (start, end) offset */
-       unsigned long long ofs, end;
-       unsigned int lcn;
-       u32 ofs_rem;
-
-       /* initialize `pblk' to keep gcc from printing foolish warnings */
-       erofs_blk_t mblk, pblk = 0;
-       struct page *mpage = map->mpage;
-       struct z_erofs_vle_decompressed_index *di;
-       unsigned int cluster_type, logical_cluster_ofs;
-       int err = 0;
-
-       trace_z_erofs_map_blocks_iter_enter(inode, map, flags);
-
-       /* when trying to read beyond EOF, leave it unmapped */
-       if (unlikely(map->m_la >= inode->i_size)) {
-               DBG_BUGON(!initial);
-               map->m_llen = map->m_la + 1 - inode->i_size;
-               map->m_la = inode->i_size;
-               map->m_flags = 0;
-               goto out;
-       }
-
-       debugln("%s, m_la %llu m_llen %llu --- start", __func__,
-               map->m_la, map->m_llen);
-
-       ofs = map->m_la + map->m_llen;
-
-       /* clustersize should be power of two */
-       lcn = ofs >> ctx.clusterbits;
-       ofs_rem = ofs & (clustersize - 1);
-
-       mblk = vle_extent_blkaddr(inode, lcn);
-
-       if (!mpage || mpage->index != mblk) {
-               if (mpage)
-                       put_page(mpage);
-
-               mpage = erofs_get_meta_page(ctx.sb, mblk, false);
-               if (IS_ERR(mpage)) {
-                       err = PTR_ERR(mpage);
-                       goto out;
-               }
-               map->mpage = mpage;
-       } else {
-               lock_page(mpage);
-               DBG_BUGON(!PageUptodate(mpage));
-       }
-
-       kaddr = kmap_atomic(mpage);
-       di = kaddr + vle_extent_blkoff(inode, lcn);
-
-       debugln("%s, lcn %u mblk %u e_blkoff %u", __func__, lcn,
-               mblk, vle_extent_blkoff(inode, lcn));
-
-       err = vle_decompressed_index_clusterofs(&logical_cluster_ofs,
-                                               clustersize, di);
-       if (unlikely(err))
-               goto unmap_out;
-
-       if (!initial) {
-               /* [walking mode] 'map' has been already initialized */
-               map->m_llen += logical_cluster_ofs;
-               goto unmap_out;
-       }
-
-       /* by default, compressed */
-       map->m_flags |= EROFS_MAP_ZIPPED;
-
-       end = ((u64)lcn + 1) * clustersize;
-
-       cluster_type = vle_cluster_type(di);
-
-       switch (cluster_type) {
-       case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
-               if (ofs_rem >= logical_cluster_ofs)
-                       map->m_flags ^= EROFS_MAP_ZIPPED;
-               /* fallthrough */
-       case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
-               if (ofs_rem == logical_cluster_ofs) {
-                       pblk = le32_to_cpu(di->di_u.blkaddr);
-                       goto exact_hitted;
-               }
-
-               if (ofs_rem > logical_cluster_ofs) {
-                       ofs = (u64)lcn * clustersize | logical_cluster_ofs;
-                       pblk = le32_to_cpu(di->di_u.blkaddr);
-                       break;
-               }
-
-               /* logical cluster number should be >= 1 */
-               if (unlikely(!lcn)) {
-                       errln("invalid logical cluster 0 at nid %llu",
-                             EROFS_V(inode)->nid);
-                       err = -EIO;
-                       goto unmap_out;
-               }
-               end = ((u64)lcn-- * clustersize) | logical_cluster_ofs;
-               /* fallthrough */
-       case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
-               /* get the correspoinding first chunk */
-               err = vle_get_logical_extent_head(&ctx, lcn, &ofs,
-                                                 &pblk, &map->m_flags);
-               mpage = map->mpage;
-
-               if (unlikely(err)) {
-                       if (mpage)
-                               goto unmap_out;
-                       goto out;
-               }
-               break;
-       default:
-               errln("unknown cluster type %u at offset %llu of nid %llu",
-                     cluster_type, ofs, EROFS_V(inode)->nid);
-               err = -EIO;
-               goto unmap_out;
-       }
-
-       map->m_la = ofs;
-exact_hitted:
-       map->m_llen = end - ofs;
-       map->m_plen = clustersize;
-       map->m_pa = blknr_to_addr(pblk);
-       map->m_flags |= EROFS_MAP_MAPPED;
-unmap_out:
-       kunmap_atomic(kaddr);
-       unlock_page(mpage);
-out:
-       debugln("%s, m_la %llu m_pa %llu m_llen %llu m_plen %llu m_flags 0%o",
-               __func__, map->m_la, map->m_pa,
-               map->m_llen, map->m_plen, map->m_flags);
-
-       trace_z_erofs_map_blocks_iter_exit(inode, map, flags, err);
-
-       /* aggressively BUG_ON iff CONFIG_EROFS_FS_DEBUG is on */
-       DBG_BUGON(err < 0 && err != -ENOMEM);
-       return err;
-}
-
index 517e5ce..ab509d7 100644 (file)
 #include "internal.h"
 #include "unzip_pagevec.h"
 
-/*
- *  - 0x5A110C8D ('sallocated', Z_EROFS_MAPPING_STAGING) -
- * used for temporary allocated pages (via erofs_allocpage),
- * in order to seperate those from NULL mapping (eg. truncated pages)
- */
-#define Z_EROFS_MAPPING_STAGING                ((void *)0x5A110C8D)
-
-#define z_erofs_is_stagingpage(page)   \
-       ((page)->mapping == Z_EROFS_MAPPING_STAGING)
-
-static inline bool z_erofs_gather_if_stagingpage(struct list_head *page_pool,
-                                                struct page *page)
-{
-       if (z_erofs_is_stagingpage(page)) {
-               list_add(&page->lru, page_pool);
-               return true;
-       }
-       return false;
-}
+#define Z_EROFS_NR_INLINE_PAGEVECS      3
 
 /*
  * Structure fields follow one of the following exclusion rules.
@@ -44,8 +26,6 @@ static inline bool z_erofs_gather_if_stagingpage(struct list_head *page_pool,
  *
  */
 
-#define Z_EROFS_VLE_INLINE_PAGEVECS     3
-
 struct z_erofs_vle_work {
        struct mutex lock;
 
@@ -58,7 +38,7 @@ struct z_erofs_vle_work {
 
        union {
                /* L: pagevec */
-               erofs_vtptr_t pagevec[Z_EROFS_VLE_INLINE_PAGEVECS];
+               erofs_vtptr_t pagevec[Z_EROFS_NR_INLINE_PAGEVECS];
                struct rcu_head rcu;
        };
 };
@@ -66,6 +46,7 @@ struct z_erofs_vle_work {
 #define Z_EROFS_VLE_WORKGRP_FMT_PLAIN        0
 #define Z_EROFS_VLE_WORKGRP_FMT_LZ4          1
 #define Z_EROFS_VLE_WORKGRP_FMT_MASK         1
+#define Z_EROFS_VLE_WORKGRP_FULL_LENGTH      2
 
 typedef void *z_erofs_vle_owned_workgrp_t;
 
@@ -147,7 +128,7 @@ static inline unsigned z_erofs_onlinepage_index(struct page *page)
 {
        union z_erofs_onlinepage_converter u;
 
-       BUG_ON(!PagePrivate(page));
+       DBG_BUGON(!PagePrivate(page));
        u.v = &page_private(page);
 
        return atomic_read(u.o) >> Z_EROFS_ONLINEPAGE_INDEX_SHIFT;
@@ -179,7 +160,7 @@ repeat:
                if (!index)
                        return;
 
-               BUG_ON(id != index);
+               DBG_BUGON(id != index);
        }
 
        v = (index << Z_EROFS_ONLINEPAGE_INDEX_SHIFT) |
@@ -193,7 +174,7 @@ static inline void z_erofs_onlinepage_endio(struct page *page)
        union z_erofs_onlinepage_converter u;
        unsigned v;
 
-       BUG_ON(!PagePrivate(page));
+       DBG_BUGON(!PagePrivate(page));
        u.v = &page_private(page);
 
        v = atomic_dec_return(u.o);
@@ -211,18 +192,5 @@ static inline void z_erofs_onlinepage_endio(struct page *page)
        min_t(unsigned int, THREAD_SIZE / 8 / sizeof(struct page *), 96U)
 #define Z_EROFS_VLE_VMAP_GLOBAL_PAGES  2048
 
-/* unzip_vle_lz4.c */
-int z_erofs_vle_plain_copy(struct page **compressed_pages,
-                          unsigned int clusterpages, struct page **pages,
-                          unsigned int nr_pages, unsigned short pageofs);
-int z_erofs_vle_unzip_fast_percpu(struct page **compressed_pages,
-                                 unsigned int clusterpages,
-                                 struct page **pages, unsigned int outlen,
-                                 unsigned short pageofs);
-int z_erofs_vle_unzip_vmap(struct page **compressed_pages,
-                          unsigned int clusterpages,
-                          void *vaddr, unsigned int llen,
-                          unsigned short pageofs, bool overlapped);
-
 #endif
 
diff --git a/drivers/staging/erofs/unzip_vle_lz4.c b/drivers/staging/erofs/unzip_vle_lz4.c
deleted file mode 100644 (file)
index 0daac9b..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * linux/drivers/staging/erofs/unzip_vle_lz4.c
- *
- * Copyright (C) 2018 HUAWEI, Inc.
- *             http://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.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 the Linux
- * distribution for more details.
- */
-#include "unzip_vle.h"
-#include <linux/lz4.h>
-
-static int z_erofs_unzip_lz4(void *in, void *out, size_t inlen, size_t outlen)
-{
-       int ret = LZ4_decompress_safe_partial(in, out, inlen, outlen, outlen);
-
-       if (ret >= 0)
-               return ret;
-
-       /*
-        * LZ4_decompress_safe_partial will return an error code
-        * (< 0) if decompression failed
-        */
-       errln("%s, failed to decompress, in[%p, %zu] outlen[%p, %zu]",
-             __func__, in, inlen, out, outlen);
-       WARN_ON(1);
-       print_hex_dump(KERN_DEBUG, "raw data [in]: ", DUMP_PREFIX_OFFSET,
-                      16, 1, in, inlen, true);
-       print_hex_dump(KERN_DEBUG, "raw data [out]: ", DUMP_PREFIX_OFFSET,
-                      16, 1, out, outlen, true);
-       return -EIO;
-}
-
-#if Z_EROFS_CLUSTER_MAX_PAGES > Z_EROFS_VLE_INLINE_PAGEVECS
-#define EROFS_PERCPU_NR_PAGES   Z_EROFS_CLUSTER_MAX_PAGES
-#else
-#define EROFS_PERCPU_NR_PAGES   Z_EROFS_VLE_INLINE_PAGEVECS
-#endif
-
-static struct {
-       char data[PAGE_SIZE * EROFS_PERCPU_NR_PAGES];
-} erofs_pcpubuf[NR_CPUS];
-
-int z_erofs_vle_plain_copy(struct page **compressed_pages,
-                          unsigned int clusterpages,
-                          struct page **pages,
-                          unsigned int nr_pages,
-                          unsigned short pageofs)
-{
-       unsigned int i, j;
-       void *src = NULL;
-       const unsigned int righthalf = PAGE_SIZE - pageofs;
-       char *percpu_data;
-       bool mirrored[Z_EROFS_CLUSTER_MAX_PAGES] = { 0 };
-
-       preempt_disable();
-       percpu_data = erofs_pcpubuf[smp_processor_id()].data;
-
-       j = 0;
-       for (i = 0; i < nr_pages; j = i++) {
-               struct page *page = pages[i];
-               void *dst;
-
-               if (!page) {
-                       if (src) {
-                               if (!mirrored[j])
-                                       kunmap_atomic(src);
-                               src = NULL;
-                       }
-                       continue;
-               }
-
-               dst = kmap_atomic(page);
-
-               for (; j < clusterpages; ++j) {
-                       if (compressed_pages[j] != page)
-                               continue;
-
-                       DBG_BUGON(mirrored[j]);
-                       memcpy(percpu_data + j * PAGE_SIZE, dst, PAGE_SIZE);
-                       mirrored[j] = true;
-                       break;
-               }
-
-               if (i) {
-                       if (!src)
-                               src = mirrored[i - 1] ?
-                                       percpu_data + (i - 1) * PAGE_SIZE :
-                                       kmap_atomic(compressed_pages[i - 1]);
-
-                       memcpy(dst, src + righthalf, pageofs);
-
-                       if (!mirrored[i - 1])
-                               kunmap_atomic(src);
-
-                       if (unlikely(i >= clusterpages)) {
-                               kunmap_atomic(dst);
-                               break;
-                       }
-               }
-
-               if (!righthalf) {
-                       src = NULL;
-               } else {
-                       src = mirrored[i] ? percpu_data + i * PAGE_SIZE :
-                               kmap_atomic(compressed_pages[i]);
-
-                       memcpy(dst + pageofs, src, righthalf);
-               }
-
-               kunmap_atomic(dst);
-       }
-
-       if (src && !mirrored[j])
-               kunmap_atomic(src);
-
-       preempt_enable();
-       return 0;
-}
-
-int z_erofs_vle_unzip_fast_percpu(struct page **compressed_pages,
-                                 unsigned int clusterpages,
-                                 struct page **pages,
-                                 unsigned int outlen,
-                                 unsigned short pageofs)
-{
-       void *vin, *vout;
-       unsigned int nr_pages, i, j;
-       int ret;
-
-       if (outlen + pageofs > EROFS_PERCPU_NR_PAGES * PAGE_SIZE)
-               return -ENOTSUPP;
-
-       nr_pages = DIV_ROUND_UP(outlen + pageofs, PAGE_SIZE);
-
-       if (clusterpages == 1) {
-               vin = kmap_atomic(compressed_pages[0]);
-       } else {
-               vin = erofs_vmap(compressed_pages, clusterpages);
-               if (!vin)
-                       return -ENOMEM;
-       }
-
-       preempt_disable();
-       vout = erofs_pcpubuf[smp_processor_id()].data;
-
-       ret = z_erofs_unzip_lz4(vin, vout + pageofs,
-                               clusterpages * PAGE_SIZE, outlen);
-
-       if (ret < 0)
-               goto out;
-       ret = 0;
-
-       for (i = 0; i < nr_pages; ++i) {
-               j = min((unsigned int)PAGE_SIZE - pageofs, outlen);
-
-               if (pages[i]) {
-                       if (clusterpages == 1 &&
-                           pages[i] == compressed_pages[0]) {
-                               memcpy(vin + pageofs, vout + pageofs, j);
-                       } else {
-                               void *dst = kmap_atomic(pages[i]);
-
-                               memcpy(dst + pageofs, vout + pageofs, j);
-                               kunmap_atomic(dst);
-                       }
-               }
-               vout += PAGE_SIZE;
-               outlen -= j;
-               pageofs = 0;
-       }
-
-out:
-       preempt_enable();
-
-       if (clusterpages == 1)
-               kunmap_atomic(vin);
-       else
-               erofs_vunmap(vin, clusterpages);
-
-       return ret;
-}
-
-int z_erofs_vle_unzip_vmap(struct page **compressed_pages,
-                          unsigned int clusterpages,
-                          void *vout,
-                          unsigned int llen,
-                          unsigned short pageofs,
-                          bool overlapped)
-{
-       void *vin;
-       unsigned int i;
-       int ret;
-
-       if (overlapped) {
-               preempt_disable();
-               vin = erofs_pcpubuf[smp_processor_id()].data;
-
-               for (i = 0; i < clusterpages; ++i) {
-                       void *t = kmap_atomic(compressed_pages[i]);
-
-                       memcpy(vin + PAGE_SIZE * i, t, PAGE_SIZE);
-                       kunmap_atomic(t);
-               }
-       } else if (clusterpages == 1) {
-               vin = kmap_atomic(compressed_pages[0]);
-       } else {
-               vin = erofs_vmap(compressed_pages, clusterpages);
-       }
-
-       ret = z_erofs_unzip_lz4(vin, vout + pageofs,
-                               clusterpages * PAGE_SIZE, llen);
-       if (ret > 0)
-               ret = 0;
-
-       if (!overlapped) {
-               if (clusterpages == 1)
-                       kunmap_atomic(vin);
-               else
-                       erofs_vunmap(vin, clusterpages);
-       } else {
-               preempt_enable();
-       }
-       return ret;
-}
-
index 3e7d30b..4bbd3bf 100644 (file)
@@ -27,6 +27,18 @@ struct page *erofs_allocpage(struct list_head *pool, gfp_t gfp)
        return page;
 }
 
+#if (EROFS_PCPUBUF_NR_PAGES > 0)
+static struct {
+       u8 data[PAGE_SIZE * EROFS_PCPUBUF_NR_PAGES];
+} ____cacheline_aligned_in_smp erofs_pcpubuf[NR_CPUS];
+
+void *erofs_get_pcpubuf(unsigned int pagenr)
+{
+       preempt_disable();
+       return &erofs_pcpubuf[smp_processor_id()].data[pagenr * PAGE_SIZE];
+}
+#endif
+
 /* global shrink count (for all mounted EROFS instances) */
 static atomic_long_t erofs_global_shrink_cnt;
 
diff --git a/drivers/staging/erofs/zmap.c b/drivers/staging/erofs/zmap.c
new file mode 100644 (file)
index 0000000..9c0bd65
--- /dev/null
@@ -0,0 +1,463 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * linux/drivers/staging/erofs/zmap.c
+ *
+ * Copyright (C) 2018-2019 HUAWEI, Inc.
+ *             http://www.huawei.com/
+ * Created by Gao Xiang <gaoxiang25@huawei.com>
+ */
+#include "internal.h"
+#include <asm/unaligned.h>
+#include <trace/events/erofs.h>
+
+int z_erofs_fill_inode(struct inode *inode)
+{
+       struct erofs_vnode *const vi = EROFS_V(inode);
+       struct super_block *const sb = inode->i_sb;
+
+       if (vi->datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY) {
+               vi->z_advise = 0;
+               vi->z_algorithmtype[0] = 0;
+               vi->z_algorithmtype[1] = 0;
+               vi->z_logical_clusterbits = EROFS_SB(sb)->clusterbits;
+               vi->z_physical_clusterbits[0] = vi->z_logical_clusterbits;
+               vi->z_physical_clusterbits[1] = vi->z_logical_clusterbits;
+               set_bit(EROFS_V_Z_INITED_BIT, &vi->flags);
+       }
+
+       inode->i_mapping->a_ops = &z_erofs_vle_normalaccess_aops;
+       return 0;
+}
+
+static int fill_inode_lazy(struct inode *inode)
+{
+       struct erofs_vnode *const vi = EROFS_V(inode);
+       struct super_block *const sb = inode->i_sb;
+       int err;
+       erofs_off_t pos;
+       struct page *page;
+       void *kaddr;
+       struct z_erofs_map_header *h;
+
+       if (test_bit(EROFS_V_Z_INITED_BIT, &vi->flags))
+               return 0;
+
+       if (wait_on_bit_lock(&vi->flags, EROFS_V_BL_Z_BIT, TASK_KILLABLE))
+               return -ERESTARTSYS;
+
+       err = 0;
+       if (test_bit(EROFS_V_Z_INITED_BIT, &vi->flags))
+               goto out_unlock;
+
+       DBG_BUGON(vi->datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY);
+
+       pos = ALIGN(iloc(EROFS_SB(sb), vi->nid) + vi->inode_isize +
+                   vi->xattr_isize, 8);
+       page = erofs_get_meta_page(sb, erofs_blknr(pos), false);
+       if (IS_ERR(page)) {
+               err = PTR_ERR(page);
+               goto out_unlock;
+       }
+
+       kaddr = kmap_atomic(page);
+
+       h = kaddr + erofs_blkoff(pos);
+       vi->z_advise = le16_to_cpu(h->h_advise);
+       vi->z_algorithmtype[0] = h->h_algorithmtype & 15;
+       vi->z_algorithmtype[1] = h->h_algorithmtype >> 4;
+
+       if (vi->z_algorithmtype[0] >= Z_EROFS_COMPRESSION_MAX) {
+               errln("unknown compression format %u for nid %llu, please upgrade kernel",
+                     vi->z_algorithmtype[0], vi->nid);
+               err = -ENOTSUPP;
+               goto unmap_done;
+       }
+
+       vi->z_logical_clusterbits = LOG_BLOCK_SIZE + (h->h_clusterbits & 7);
+       vi->z_physical_clusterbits[0] = vi->z_logical_clusterbits +
+                                       ((h->h_clusterbits >> 3) & 3);
+
+       if (vi->z_physical_clusterbits[0] != LOG_BLOCK_SIZE) {
+               errln("unsupported physical clusterbits %u for nid %llu, please upgrade kernel",
+                     vi->z_physical_clusterbits[0], vi->nid);
+               err = -ENOTSUPP;
+               goto unmap_done;
+       }
+
+       vi->z_physical_clusterbits[1] = vi->z_logical_clusterbits +
+                                       ((h->h_clusterbits >> 5) & 7);
+unmap_done:
+       kunmap_atomic(kaddr);
+       unlock_page(page);
+       put_page(page);
+
+       set_bit(EROFS_V_Z_INITED_BIT, &vi->flags);
+out_unlock:
+       clear_and_wake_up_bit(EROFS_V_BL_Z_BIT, &vi->flags);
+       return err;
+}
+
+struct z_erofs_maprecorder {
+       struct inode *inode;
+       struct erofs_map_blocks *map;
+       void *kaddr;
+
+       unsigned long lcn;
+       /* compression extent information gathered */
+       u8  type;
+       u16 clusterofs;
+       u16 delta[2];
+       erofs_blk_t pblk;
+};
+
+static int z_erofs_reload_indexes(struct z_erofs_maprecorder *m,
+                                 erofs_blk_t eblk)
+{
+       struct super_block *const sb = m->inode->i_sb;
+       struct erofs_map_blocks *const map = m->map;
+       struct page *mpage = map->mpage;
+
+       if (mpage) {
+               if (mpage->index == eblk) {
+                       if (!m->kaddr)
+                               m->kaddr = kmap_atomic(mpage);
+                       return 0;
+               }
+
+               if (m->kaddr) {
+                       kunmap_atomic(m->kaddr);
+                       m->kaddr = NULL;
+               }
+               put_page(mpage);
+       }
+
+       mpage = erofs_get_meta_page(sb, eblk, false);
+       if (IS_ERR(mpage)) {
+               map->mpage = NULL;
+               return PTR_ERR(mpage);
+       }
+       m->kaddr = kmap_atomic(mpage);
+       unlock_page(mpage);
+       map->mpage = mpage;
+       return 0;
+}
+
+static int vle_legacy_load_cluster_from_disk(struct z_erofs_maprecorder *m,
+                                            unsigned long lcn)
+{
+       struct inode *const inode = m->inode;
+       struct erofs_vnode *const vi = EROFS_V(inode);
+       const erofs_off_t ibase = iloc(EROFS_I_SB(inode), vi->nid);
+       const erofs_off_t pos =
+               Z_EROFS_VLE_LEGACY_INDEX_ALIGN(ibase + vi->inode_isize +
+                                              vi->xattr_isize) +
+               lcn * sizeof(struct z_erofs_vle_decompressed_index);
+       struct z_erofs_vle_decompressed_index *di;
+       unsigned int advise, type;
+       int err;
+
+       err = z_erofs_reload_indexes(m, erofs_blknr(pos));
+       if (err)
+               return err;
+
+       m->lcn = lcn;
+       di = m->kaddr + erofs_blkoff(pos);
+
+       advise = le16_to_cpu(di->di_advise);
+       type = (advise >> Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT) &
+               ((1 << Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS) - 1);
+       switch (type) {
+       case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
+               m->clusterofs = 1 << vi->z_logical_clusterbits;
+               m->delta[0] = le16_to_cpu(di->di_u.delta[0]);
+               m->delta[1] = le16_to_cpu(di->di_u.delta[1]);
+               break;
+       case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
+       case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
+               m->clusterofs = le16_to_cpu(di->di_clusterofs);
+               m->pblk = le32_to_cpu(di->di_u.blkaddr);
+               break;
+       default:
+               DBG_BUGON(1);
+               return -EIO;
+       }
+       m->type = type;
+       return 0;
+}
+
+static unsigned int decode_compactedbits(unsigned int lobits,
+                                        unsigned int lomask,
+                                        u8 *in, unsigned int pos, u8 *type)
+{
+       const unsigned int v = get_unaligned_le32(in + pos / 8) >> (pos & 7);
+       const unsigned int lo = v & lomask;
+
+       *type = (v >> lobits) & 3;
+       return lo;
+}
+
+static int unpack_compacted_index(struct z_erofs_maprecorder *m,
+                                 unsigned int amortizedshift,
+                                 unsigned int eofs)
+{
+       struct erofs_vnode *const vi = EROFS_V(m->inode);
+       const unsigned int lclusterbits = vi->z_logical_clusterbits;
+       const unsigned int lomask = (1 << lclusterbits) - 1;
+       unsigned int vcnt, base, lo, encodebits, nblk;
+       int i;
+       u8 *in, type;
+
+       if (1 << amortizedshift == 4)
+               vcnt = 2;
+       else if (1 << amortizedshift == 2 && lclusterbits == 12)
+               vcnt = 16;
+       else
+               return -ENOTSUPP;
+
+       encodebits = ((vcnt << amortizedshift) - sizeof(__le32)) * 8 / vcnt;
+       base = round_down(eofs, vcnt << amortizedshift);
+       in = m->kaddr + base;
+
+       i = (eofs - base) >> amortizedshift;
+
+       lo = decode_compactedbits(lclusterbits, lomask,
+                                 in, encodebits * i, &type);
+       m->type = type;
+       if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) {
+               m->clusterofs = 1 << lclusterbits;
+               if (i + 1 != vcnt) {
+                       m->delta[0] = lo;
+                       return 0;
+               }
+               /*
+                * since the last lcluster in the pack is special,
+                * of which lo saves delta[1] rather than delta[0].
+                * Hence, get delta[0] by the previous lcluster indirectly.
+                */
+               lo = decode_compactedbits(lclusterbits, lomask,
+                                         in, encodebits * (i - 1), &type);
+               if (type != Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD)
+                       lo = 0;
+               m->delta[0] = lo + 1;
+               return 0;
+       }
+       m->clusterofs = lo;
+       m->delta[0] = 0;
+       /* figout out blkaddr (pblk) for HEAD lclusters */
+       nblk = 1;
+       while (i > 0) {
+               --i;
+               lo = decode_compactedbits(lclusterbits, lomask,
+                                         in, encodebits * i, &type);
+               if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD)
+                       i -= lo;
+
+               if (i >= 0)
+                       ++nblk;
+       }
+       in += (vcnt << amortizedshift) - sizeof(__le32);
+       m->pblk = le32_to_cpu(*(__le32 *)in) + nblk;
+       return 0;
+}
+
+static int compacted_load_cluster_from_disk(struct z_erofs_maprecorder *m,
+                                           unsigned long lcn)
+{
+       struct inode *const inode = m->inode;
+       struct erofs_vnode *const vi = EROFS_V(inode);
+       const unsigned int lclusterbits = vi->z_logical_clusterbits;
+       const erofs_off_t ebase = ALIGN(iloc(EROFS_I_SB(inode), vi->nid) +
+                                       vi->inode_isize + vi->xattr_isize, 8) +
+               sizeof(struct z_erofs_map_header);
+       const unsigned int totalidx = DIV_ROUND_UP(inode->i_size, EROFS_BLKSIZ);
+       unsigned int compacted_4b_initial, compacted_2b;
+       unsigned int amortizedshift;
+       erofs_off_t pos;
+       int err;
+
+       if (lclusterbits != 12)
+               return -ENOTSUPP;
+
+       if (lcn >= totalidx)
+               return -EINVAL;
+
+       m->lcn = lcn;
+       /* used to align to 32-byte (compacted_2b) alignment */
+       compacted_4b_initial = (32 - ebase % 32) / 4;
+       if (compacted_4b_initial == 32 / 4)
+               compacted_4b_initial = 0;
+
+       if (vi->z_advise & Z_EROFS_ADVISE_COMPACTED_2B)
+               compacted_2b = rounddown(totalidx - compacted_4b_initial, 16);
+       else
+               compacted_2b = 0;
+
+       pos = ebase;
+       if (lcn < compacted_4b_initial) {
+               amortizedshift = 2;
+               goto out;
+       }
+       pos += compacted_4b_initial * 4;
+       lcn -= compacted_4b_initial;
+
+       if (lcn < compacted_2b) {
+               amortizedshift = 1;
+               goto out;
+       }
+       pos += compacted_2b * 2;
+       lcn -= compacted_2b;
+       amortizedshift = 2;
+out:
+       pos += lcn * (1 << amortizedshift);
+       err = z_erofs_reload_indexes(m, erofs_blknr(pos));
+       if (err)
+               return err;
+       return unpack_compacted_index(m, amortizedshift, erofs_blkoff(pos));
+}
+
+static int vle_load_cluster_from_disk(struct z_erofs_maprecorder *m,
+                                     unsigned int lcn)
+{
+       const unsigned int datamode = EROFS_V(m->inode)->datamode;
+
+       if (datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY)
+               return vle_legacy_load_cluster_from_disk(m, lcn);
+
+       if (datamode == EROFS_INODE_FLAT_COMPRESSION)
+               return compacted_load_cluster_from_disk(m, lcn);
+
+       return -EINVAL;
+}
+
+static int vle_extent_lookback(struct z_erofs_maprecorder *m,
+                              unsigned int lookback_distance)
+{
+       struct erofs_vnode *const vi = EROFS_V(m->inode);
+       struct erofs_map_blocks *const map = m->map;
+       const unsigned int lclusterbits = vi->z_logical_clusterbits;
+       unsigned long lcn = m->lcn;
+       int err;
+
+       if (lcn < lookback_distance) {
+               DBG_BUGON(1);
+               return -EIO;
+       }
+
+       /* load extent head logical cluster if needed */
+       lcn -= lookback_distance;
+       err = vle_load_cluster_from_disk(m, lcn);
+       if (err)
+               return err;
+
+       switch (m->type) {
+       case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
+               return vle_extent_lookback(m, m->delta[0]);
+       case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
+               map->m_flags &= ~EROFS_MAP_ZIPPED;
+               /* fallthrough */
+       case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
+               map->m_la = (lcn << lclusterbits) | m->clusterofs;
+               break;
+       default:
+               errln("unknown type %u at lcn %lu of nid %llu",
+                     m->type, lcn, vi->nid);
+               DBG_BUGON(1);
+               return -EIO;
+       }
+       return 0;
+}
+
+int z_erofs_map_blocks_iter(struct inode *inode,
+                           struct erofs_map_blocks *map,
+                           int flags)
+{
+       struct erofs_vnode *const vi = EROFS_V(inode);
+       struct z_erofs_maprecorder m = {
+               .inode = inode,
+               .map = map,
+       };
+       int err = 0;
+       unsigned int lclusterbits, endoff;
+       unsigned long long ofs, end;
+
+       trace_z_erofs_map_blocks_iter_enter(inode, map, flags);
+
+       /* when trying to read beyond EOF, leave it unmapped */
+       if (unlikely(map->m_la >= inode->i_size)) {
+               map->m_llen = map->m_la + 1 - inode->i_size;
+               map->m_la = inode->i_size;
+               map->m_flags = 0;
+               goto out;
+       }
+
+       err = fill_inode_lazy(inode);
+       if (err)
+               goto out;
+
+       lclusterbits = vi->z_logical_clusterbits;
+       ofs = map->m_la;
+       m.lcn = ofs >> lclusterbits;
+       endoff = ofs & ((1 << lclusterbits) - 1);
+
+       err = vle_load_cluster_from_disk(&m, m.lcn);
+       if (err)
+               goto unmap_out;
+
+       map->m_flags = EROFS_MAP_ZIPPED;        /* by default, compressed */
+       end = (m.lcn + 1ULL) << lclusterbits;
+
+       switch (m.type) {
+       case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
+               if (endoff >= m.clusterofs)
+                       map->m_flags &= ~EROFS_MAP_ZIPPED;
+               /* fallthrough */
+       case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
+               if (endoff >= m.clusterofs) {
+                       map->m_la = (m.lcn << lclusterbits) | m.clusterofs;
+                       break;
+               }
+               /* m.lcn should be >= 1 if endoff < m.clusterofs */
+               if (unlikely(!m.lcn)) {
+                       errln("invalid logical cluster 0 at nid %llu",
+                             vi->nid);
+                       err = -EIO;
+                       goto unmap_out;
+               }
+               end = (m.lcn << lclusterbits) | m.clusterofs;
+               map->m_flags |= EROFS_MAP_FULL_MAPPED;
+               m.delta[0] = 1;
+               /* fallthrough */
+       case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
+               /* get the correspoinding first chunk */
+               err = vle_extent_lookback(&m, m.delta[0]);
+               if (unlikely(err))
+                       goto unmap_out;
+               break;
+       default:
+               errln("unknown type %u at offset %llu of nid %llu",
+                     m.type, ofs, vi->nid);
+               err = -EIO;
+               goto unmap_out;
+       }
+
+       map->m_llen = end - map->m_la;
+       map->m_plen = 1 << lclusterbits;
+       map->m_pa = blknr_to_addr(m.pblk);
+       map->m_flags |= EROFS_MAP_MAPPED;
+
+unmap_out:
+       if (m.kaddr)
+               kunmap_atomic(m.kaddr);
+
+out:
+       debugln("%s, m_la %llu m_pa %llu m_llen %llu m_plen %llu m_flags 0%o",
+               __func__, map->m_la, map->m_pa,
+               map->m_llen, map->m_plen, map->m_flags);
+
+       trace_z_erofs_map_blocks_iter_exit(inode, map, flags, err);
+
+       /* aggressively BUG_ON iff CONFIG_EROFS_FS_DEBUG is on */
+       DBG_BUGON(err < 0 && err != -ENOMEM);
+       return err;
+}
+
index 8bc3d9a..635a0a7 100644 (file)
@@ -14,6 +14,7 @@ if HMS_ANYBUSS_BUS
 config ARCX_ANYBUS_CONTROLLER
        tristate "Arcx Anybus-S Controller"
        depends on OF && GPIOLIB && HAS_IOMEM && REGULATOR
+       select REGMAP_MMIO
        help
          Select this to get support for the Arcx Anybus controller.
          It connects to the SoC via a parallel memory bus, and
index a167fb6..2ecffa4 100644 (file)
@@ -111,49 +111,31 @@ static void export_reset_1(struct device *dev, bool assert)
  * at a time for now.
  */
 
-static int read_reg_bus(void *context, unsigned int reg,
-                       unsigned int *val)
-{
-       void __iomem *base = context;
-
-       *val = readb(base + reg);
-       return 0;
-}
-
-static int write_reg_bus(void *context, unsigned int reg,
-                        unsigned int val)
-{
-       void __iomem *base = context;
-
-       writeb(val, base + reg);
-       return 0;
-}
+static const struct regmap_config arcx_regmap_cfg = {
+       .reg_bits = 16,
+       .val_bits = 8,
+       .max_register = 0x7ff,
+       .use_single_read = true,
+       .use_single_write = true,
+       /*
+        * single-byte parallel bus accesses are atomic, so don't
+        * require any synchronization.
+        */
+       .disable_locking = true,
+};
 
 static struct regmap *create_parallel_regmap(struct platform_device *pdev,
                                             int idx)
 {
-       struct regmap_config regmap_cfg = {
-               .reg_bits = 11,
-               .val_bits = 8,
-               /*
-                * single-byte parallel bus accesses are atomic, so don't
-                * require any synchronization.
-                */
-               .disable_locking = true,
-               .reg_read = read_reg_bus,
-               .reg_write = write_reg_bus,
-       };
        struct resource *res;
        void __iomem *base;
        struct device *dev = &pdev->dev;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, idx + 1);
-       if (resource_size(res) < (1 << regmap_cfg.reg_bits))
-               return ERR_PTR(-EINVAL);
        base = devm_ioremap_resource(dev, res);
        if (IS_ERR(base))
                return ERR_CAST(base);
-       return devm_regmap_init(dev, NULL, base, &regmap_cfg);
+       return devm_regmap_init_mmio(dev, base, &arcx_regmap_cfg);
 }
 
 static struct anybuss_host *
index 60b8514..f6f5b92 100644 (file)
@@ -211,16 +211,16 @@ static ssize_t fieldbus_write(struct file *filp, const char __user *buf,
        return fbdev->write_area(fbdev, buf, size, offset);
 }
 
-static unsigned int fieldbus_poll(struct file *filp, poll_table *wait)
+static __poll_t fieldbus_poll(struct file *filp, poll_table *wait)
 {
        struct fb_open_file *of = filp->private_data;
        struct fieldbus_dev *fbdev = of->fbdev;
-       unsigned int mask = POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
+       __poll_t mask = EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM;
 
        poll_wait(filp, &fbdev->dc_wq, wait);
        /* data changed ? */
        if (fbdev->dc_event != of->dc_event)
-               mask |= POLLPRI | POLLERR;
+               mask |= EPOLLPRI | EPOLLERR;
        return mask;
 }
 
index 368837c..244237b 100644 (file)
@@ -6,7 +6,7 @@
 config FSL_DPAA2
        bool "Freescale DPAA2 devices"
        depends on FSL_MC_BUS
-       ---help---
+       help
          Build drivers for Freescale DataPath Acceleration
          Architecture (DPAA2) family of SoCs.
 
@@ -14,6 +14,6 @@ config FSL_DPAA2_ETHSW
        tristate "Freescale DPAA2 Ethernet Switch"
        depends on FSL_DPAA2
        depends on NET_SWITCHDEV
-       ---help---
-       Driver for Freescale DPAA2 Ethernet Switch. Select
-       BRIDGE to have support for bridge tools.
+       help
+         Driver for Freescale DPAA2 Ethernet Switch. Select
+         BRIDGE to have support for bridge tools.
index e3c3e42..f73edaf 100644 (file)
@@ -1086,6 +1086,7 @@ static int port_switchdev_event(struct notifier_block *unused,
                dev_hold(dev);
                break;
        default:
+               kfree(switchdev_work);
                return NOTIFY_DONE;
        }
 
index a445d58..13179f0 100644 (file)
@@ -702,8 +702,7 @@ static bool gasket_mmap_has_permissions(struct gasket_dev *gasket_dev,
        if ((vma->vm_flags & VM_WRITE) &&
            !gasket_owned_by_current_tgid(&gasket_dev->dev_info)) {
                dev_dbg(gasket_dev->dev,
-                       "Attempting to mmap a region for write without owning "
-                       "device.\n");
+                       "Attempting to mmap a region for write without owning device.\n");
                return false;
        }
 
@@ -1054,8 +1053,7 @@ static int gasket_mmap(struct file *filp, struct vm_area_struct *vma)
        }
        if (bar_index > 0 && is_coherent_region) {
                dev_err(gasket_dev->dev,
-                       "double matching bar and coherent buffers for address "
-                       "0x%lx\n",
+                       "double matching bar and coherent buffers for address 0x%lx\n",
                        raw_offset);
                trace_gasket_mmap_exit(bar_index);
                return -EINVAL;
index 0ca48e6..7ecfba4 100644 (file)
@@ -353,8 +353,7 @@ long gasket_handle_ioctl(struct file *filp, uint cmd, void __user *argp)
                 */
                trace_gasket_ioctl_integer_data(arg);
                dev_dbg(gasket_dev->dev,
-                       "Unknown ioctl cmd=0x%x not caught by "
-                       "gasket_is_supported_ioctl\n",
+                       "Unknown ioctl cmd=0x%x not caught by gasket_is_supported_ioctl\n",
                        cmd);
                retval = -EINVAL;
                break;
index d35c4fb..f6d7157 100644 (file)
@@ -237,8 +237,8 @@ int gasket_page_table_init(struct gasket_page_table **ppg_tbl,
         * hardware register that contains the page table size.
         */
        if (total_entries == ULONG_MAX) {
-               dev_dbg(device, "Error reading page table size. "
-                       "Initializing page table with size 0\n");
+               dev_dbg(device,
+                       "Error reading page table size. Initializing page table with size 0\n");
                total_entries = 0;
        }
 
@@ -491,8 +491,7 @@ static int gasket_perform_mapping(struct gasket_page_table *pg_tbl,
 
                        if (ret <= 0) {
                                dev_err(pg_tbl->device,
-                                       "get user pages failed for addr=0x%lx, "
-                                       "offset=0x%lx [ret=%d]\n",
+                                       "get user pages failed for addr=0x%lx, offset=0x%lx [ret=%d]\n",
                                        page_addr, offset, ret);
                                return ret ? ret : -ENOMEM;
                        }
@@ -779,8 +778,8 @@ static bool gasket_is_extended_dev_addr_bad(struct gasket_page_table *pg_tbl,
 
        if (page_lvl0_idx >= pg_tbl->num_extended_entries) {
                dev_err(pg_tbl->device,
-                       "starting level 0 slot at %lu is too large, max is < "
-                       "%u\n", page_lvl0_idx, pg_tbl->num_extended_entries);
+                       "starting level 0 slot at %lu is too large, max is < %u\n",
+                       page_lvl0_idx, pg_tbl->num_extended_entries);
                return true;
        }
 
@@ -965,8 +964,7 @@ static int gasket_map_extended_pages(struct gasket_page_table *pg_tbl,
        if (ret) {
                dev_addr_end = dev_addr + (num_pages / PAGE_SIZE) - 1;
                dev_err(pg_tbl->device,
-                       "page table slots (%lu,%lu) (@ 0x%lx) to (%lu,%lu) are "
-                       "not available\n",
+                       "page table slots (%lu,%lu) (@ 0x%lx) to (%lu,%lu) are not available\n",
                        gasket_extended_lvl0_page_idx(pg_tbl, dev_addr),
                        dev_addr,
                        gasket_extended_lvl1_page_idx(pg_tbl, dev_addr),
index 2fa8809..cebc1d9 100644 (file)
@@ -414,12 +414,6 @@ static int get_results(struct loopback_test *t)
        return 0;
 }
 
-void log_csv_error(int len, int err)
-{
-       fprintf(stderr, "unable to write %d bytes to csv %s\n", len,
-               strerror(err));
-}
-
 int format_output(struct loopback_test *t,
                  struct loopback_results *r,
                  const char *dev_name,
index 7038175..3968713 100644 (file)
 /* Power supply above 3.625 V */
 #define ADIS16203_DIAG_STAT_POWER_HIGH_BIT    1
 
-/* Power supply below 3.15 V */
+/* Power supply below 2.975 V */
 #define ADIS16203_DIAG_STAT_POWER_LOW_BIT     0
 
 /* GLOB_CMD */
@@ -234,7 +234,7 @@ static const char * const adis16203_status_error_msgs[] = {
        [ADIS16203_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
        [ADIS16203_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed",
        [ADIS16203_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
-       [ADIS16203_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V",
+       [ADIS16203_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 2.975V",
 };
 
 static const struct adis_data adis16203_data = {
@@ -311,9 +311,17 @@ static int adis16203_remove(struct spi_device *spi)
        return 0;
 }
 
+static const struct of_device_id adis16203_of_match[] = {
+       { .compatible = "adi,adis16203" },
+       { },
+};
+
+MODULE_DEVICE_TABLE(of, adis16203_of_match);
+
 static struct spi_driver adis16203_driver = {
        .driver = {
                .name = "adis16203",
+               .of_match_table = adis16203_of_match,
        },
        .probe = adis16203_probe,
        .remove = adis16203_remove,
index b80e0d2..62f4b3b 100644 (file)
 /* Power supply above 3.625 V */
 #define ADIS16240_DIAG_STAT_POWER_HIGH_BIT     1
 
- /* Power supply below 3.15 V */
+ /* Power supply below 2.225 V */
 #define ADIS16240_DIAG_STAT_POWER_LOW_BIT      0
 
 /* GLOB_CMD */
@@ -435,9 +435,16 @@ static int adis16240_remove(struct spi_device *spi)
        return 0;
 }
 
+static const struct of_device_id adis16240_of_match[] = {
+       { .compatible = "adi,adis16240" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, adis16240_of_match);
+
 static struct spi_driver adis16240_driver = {
        .driver = {
                .name = "adis16240",
+               .of_match_table = adis16240_of_match,
        },
        .probe = adis16240_probe,
        .remove = adis16240_remove,
index 23d9a65..31cd9a1 100644 (file)
@@ -12,6 +12,9 @@ config AD7816
          Say yes here to build support for Analog Devices AD7816/7/8
          temperature sensors and ADC.
 
+         To compile this driver as a module, choose M here: the
+         module will be called ad7816.
+
 config AD7192
        tristate "Analog Devices AD7190 AD7192 AD7193 AD7195 ADC driver"
        depends on SPI
index 2066241..af513e0 100644 (file)
@@ -126,9 +126,22 @@ static const struct spi_device_id adt7316_spi_id[] = {
 
 MODULE_DEVICE_TABLE(spi, adt7316_spi_id);
 
+static const struct of_device_id adt7316_of_spi_match[] = {
+       { .compatible = "adi,adt7316" },
+       { .compatible = "adi,adt7317" },
+       { .compatible = "adi,adt7318" },
+       { .compatible = "adi,adt7516" },
+       { .compatible = "adi,adt7517" },
+       { .compatible = "adi,adt7519" },
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, adt7316_of_spi_match);
+
 static struct spi_driver adt7316_driver = {
        .driver = {
                .name = "adt7316",
+               .of_match_table = adt7316_of_spi_match,
                .pm = ADT7316_PM_OPS,
        },
        .probe = adt7316_spi_probe,
index dc8c25d..9cb3d0e 100644 (file)
@@ -2155,7 +2155,7 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus,
                chip->dac_bits = 8;
 
        chip->ldac_pin = devm_gpiod_get_optional(dev, "adi,ldac",
-                                               GPIOD_OUT_LOW);
+                                                GPIOD_OUT_LOW);
        if (IS_ERR(chip->ldac_pin)) {
                ret = PTR_ERR(chip->ldac_pin);
                dev_err(dev, "Failed to request ldac GPIO: %d\n", ret);
index e075244..f4954d8 100644 (file)
@@ -46,6 +46,9 @@
 #define AD7150_SN0                 22
 #define AD7150_ID                  23
 
+/* AD7150 masks */
+#define AD7150_THRESHTYPE_MSK                  GENMASK(6, 5)
+
 /**
  * struct ad7150_chip_info - instance specific chip data
  * @client: i2c client for this device
@@ -138,7 +141,7 @@ static int ad7150_read_event_config(struct iio_dev *indio_dev,
        if (ret < 0)
                return ret;
 
-       threshtype = (ret >> 5) & 0x03;
+       threshtype = FIELD_GET(AD7150_THRESHTYPE_MSK, ret);
 
        /*check if threshold mode is fixed or adaptive*/
        thrfixed = FIELD_GET(AD7150_CFG_FIX, ret);
@@ -162,7 +165,8 @@ static int ad7150_read_event_config(struct iio_dev *indio_dev,
        return -EINVAL;
 }
 
-/* lock should be held */
+/* state_lock should be held to ensure consistent state*/
+
 static int ad7150_write_event_params(struct iio_dev *indio_dev,
                                     unsigned int chan,
                                     enum iio_event_type type,
@@ -201,16 +205,11 @@ static int ad7150_write_event_params(struct iio_dev *indio_dev,
        ret = i2c_smbus_write_byte_data(chip->client,
                                        ad7150_addresses[chan][4],
                                        sens);
-       if (ret < 0)
+       if (ret)
                return ret;
-
-       ret = i2c_smbus_write_byte_data(chip->client,
+       return i2c_smbus_write_byte_data(chip->client,
                                        ad7150_addresses[chan][5],
                                        timeout);
-       if (ret < 0)
-               return ret;
-
-       return 0;
 }
 
 static int ad7150_write_event_config(struct iio_dev *indio_dev,
@@ -353,8 +352,8 @@ static ssize_t ad7150_show_timeout(struct device *dev,
 
        /* use the event code for consistency reasons */
        int chan = IIO_EVENT_CODE_EXTRACT_CHAN(this_attr->address);
-       int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(this_attr->address)
-                       == IIO_EV_DIR_RISING);
+       int rising = (IIO_EVENT_CODE_EXTRACT_DIR(this_attr->address)
+                     == IIO_EV_DIR_RISING) ? 1 : 0;
 
        switch (IIO_EVENT_CODE_EXTRACT_TYPE(this_attr->address)) {
        case IIO_EV_TYPE_MAG_ADAPTIVE:
@@ -468,30 +467,21 @@ static const struct iio_event_spec ad7150_events[] = {
        },
 };
 
+#define AD7150_CAPACITANCE_CHAN(_chan) {                       \
+               .type = IIO_CAPACITANCE,                        \
+               .indexed = 1,                                   \
+               .channel = _chan,                               \
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |  \
+               BIT(IIO_CHAN_INFO_AVERAGE_RAW),                 \
+               .event_spec = ad7150_events,                    \
+               .num_event_specs = ARRAY_SIZE(ad7150_events),   \
+       }
+
 static const struct iio_chan_spec ad7150_channels[] = {
-       {
-               .type = IIO_CAPACITANCE,
-               .indexed = 1,
-               .channel = 0,
-               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
-               BIT(IIO_CHAN_INFO_AVERAGE_RAW),
-               .event_spec = ad7150_events,
-               .num_event_specs = ARRAY_SIZE(ad7150_events),
-       }, {
-               .type = IIO_CAPACITANCE,
-               .indexed = 1,
-               .channel = 1,
-               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
-               BIT(IIO_CHAN_INFO_AVERAGE_RAW),
-               .event_spec = ad7150_events,
-               .num_event_specs = ARRAY_SIZE(ad7150_events),
-       },
+       AD7150_CAPACITANCE_CHAN(0),
+       AD7150_CAPACITANCE_CHAN(1)
 };
 
-/*
- * threshold events
- */
-
 static irqreturn_t ad7150_event_handler(int irq, void *private)
 {
        struct iio_dev *indio_dev = private;
@@ -580,10 +570,6 @@ static const struct iio_info ad7150_info = {
        .write_event_value = &ad7150_write_event_value,
 };
 
-/*
- * device probe and remove
- */
-
 static int ad7150_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
index 47610d8..21527d8 100644 (file)
@@ -748,9 +748,19 @@ static const struct i2c_device_id ad7746_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, ad7746_id);
 
+static const struct of_device_id ad7746_of_match[] = {
+       { .compatible = "adi,ad7745" },
+       { .compatible = "adi,ad7746" },
+       { .compatible = "adi,ad7747" },
+       { },
+};
+
+MODULE_DEVICE_TABLE(of, ad7746_of_match);
+
 static struct i2c_driver ad7746_driver = {
        .driver = {
                .name = KBUILD_MODNAME,
+               .of_match_table = ad7746_of_match,
        },
        .probe = ad7746_probe,
        .id_table = ad7746_id,
index 6de3cd7..038d673 100644 (file)
@@ -521,9 +521,20 @@ static const struct spi_device_id ad9834_id[] = {
 };
 MODULE_DEVICE_TABLE(spi, ad9834_id);
 
+static const struct of_device_id ad9834_of_match[] = {
+       {.compatible = "adi,ad9833"},
+       {.compatible = "adi,ad9834"},
+       {.compatible = "adi,ad9837"},
+       {.compatible = "adi,ad9838"},
+       {}
+};
+
+MODULE_DEVICE_TABLE(of, ad9834_of_match);
+
 static struct spi_driver ad9834_driver = {
        .driver = {
                .name   = "ad9834",
+               .of_match_table = ad9834_of_match
        },
        .probe          = ad9834_probe,
        .remove         = ad9834_remove,
index b6be0bc..0c1bd10 100644 (file)
@@ -647,9 +647,6 @@ static int ad2s1210_probe(struct spi_device *spi)
        struct ad2s1210_state *st;
        int ret;
 
-       if (!spi->dev.platform_data)
-               return -EINVAL;
-
        indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
        if (!indio_dev)
                return -ENOMEM;
index 3bb2efd..8979653 100644 (file)
@@ -23,7 +23,7 @@ config KPC2000_CORE
          If unsure, say N.
 
 config KPC2000_SPI
-       tristate "Kaktronics KPC SPI device"
+       tristate "Daktronics KPC SPI device"
        depends on KPC2000 && SPI
        help
          Say Y here if you wish to support the Daktronics KPC PCI
@@ -35,7 +35,7 @@ config KPC2000_SPI
          If unsure, say N.
 
 config KPC2000_I2C
-       tristate "Kaktronics KPC I2C device"
+       tristate "Daktronics KPC I2C device"
        depends on KPC2000 && I2C
        help
          Say Y here if you wish to support the Daktronics KPC PCI
index 1e48e9d..d15ed49 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 
 obj-$(CONFIG_KPC2000) += kpc2000/
-obj-$(CONFIG_KPC2000_I2C) += kpc_i2c/
-obj-$(CONFIG_KPC2000_SPI) += kpc_spi/
+obj-$(CONFIG_KPC2000_I2C) += kpc2000_i2c.o
+obj-$(CONFIG_KPC2000_SPI) += kpc2000_spi.o
 obj-$(CONFIG_KPC2000_DMA) += kpc_dma/
index 8c7af29..9b5ab37 100644 (file)
@@ -1,8 +1,2 @@
 - the kpc_spi driver doesn't seem to let multiple transactions (to different instances of the core) happen in parallel...
 - The kpc_i2c driver is a hot mess, it should probably be cleaned up a ton.  It functions against current hardware though.
-- pcard->card_num in kp2000_pcie_probe() is a global variable and needs atomic / locking / something better.
-- probe_core_uio() probably needs error handling
-- the loop in kp2000_probe_cores() that uses probe_core_uio() also probably needs error handling
-- would be nice if the AIO fileops in kpc_dma could be made to work
-    - probably want to add a CONFIG_ option to control compilation of the AIO functions
-- if the AIO fileops in kpc_dma start working, next would be making iov_count > 1 work too
index 28ab1e1..c274ad0 100644 (file)
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 
 obj-m := kpc2000.o
-kpc2000-objs += kp2000_module.o  core.o  cell_probe.o  fileops.o
+kpc2000-objs += core.o  cell_probe.o
index e0dba91..c124a83 100644 (file)
@@ -4,7 +4,6 @@
 #include <linux/types.h>
 #include <linux/export.h>
 #include <linux/slab.h>
-#include <asm/io.h>
 #include <linux/io.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
 #include <linux/mfd/core.h>
@@ -25,7 +24,7 @@
  *                                                              D                   C2S DMA Present
  *                                                               DDD                C2S DMA Channel Number    [up to 8 channels]
  *                                                                  II              IRQ Count [0 to 3 IRQs per core]
                                                                     1111111000
*                                                                    1111111000
  *                                                                    IIIIIII       IRQ Base Number [up to 128 IRQs per card]
  *                                                                           ___    Spare
  *
 #define KP_CORE_ID_SPI          5
 
 struct core_table_entry {
-    u16     type;
-    u32     offset;
-    u32     length;
-    bool    s2c_dma_present;
-    u8      s2c_dma_channel_num;
-    bool    c2s_dma_present;
-    u8      c2s_dma_channel_num;
-    u8      irq_count;
-    u8      irq_base_num;
+       u16  type;
+       u32  offset;
+       u32  length;
+       bool s2c_dma_present;
+       u8   s2c_dma_channel_num;
+       bool c2s_dma_present;
+       u8   c2s_dma_channel_num;
+       u8   irq_count;
+       u8   irq_base_num;
 };
 
 static
 void  parse_core_table_entry_v0(struct core_table_entry *cte, const u64 read_val)
 {
-    cte->type                = ((read_val & 0xFFF0000000000000) >> 52);
-    cte->offset              = ((read_val & 0x00000000FFFF0000) >> 16) * 4096;
-    cte->length              = ((read_val & 0x0000FFFF00000000) >> 32) * 8;
-    cte->s2c_dma_present     = ((read_val & 0x0008000000000000) >> 51);
-    cte->s2c_dma_channel_num = ((read_val & 0x0007000000000000) >> 48);
-    cte->c2s_dma_present     = ((read_val & 0x0000000000008000) >> 15);
-    cte->c2s_dma_channel_num = ((read_val & 0x0000000000007000) >> 12);
-    cte->irq_count           = ((read_val & 0x0000000000000C00) >> 10);
-    cte->irq_base_num        = ((read_val & 0x00000000000003F8) >>  3);
+       cte->type                = ((read_val & 0xFFF0000000000000) >> 52);
+       cte->offset              = ((read_val & 0x00000000FFFF0000) >> 16) * 4096;
+       cte->length              = ((read_val & 0x0000FFFF00000000) >> 32) * 8;
+       cte->s2c_dma_present     = ((read_val & 0x0008000000000000) >> 51);
+       cte->s2c_dma_channel_num = ((read_val & 0x0007000000000000) >> 48);
+       cte->c2s_dma_present     = ((read_val & 0x0000000000008000) >> 15);
+       cte->c2s_dma_channel_num = ((read_val & 0x0000000000007000) >> 12);
+       cte->irq_count           = ((read_val & 0x0000000000000C00) >> 10);
+       cte->irq_base_num        = ((read_val & 0x00000000000003F8) >>  3);
 }
 
 static
 void dbg_cte(struct kp2000_device *pcard, struct core_table_entry *cte)
 {
-    dev_dbg(&pcard->pdev->dev, "CTE: type:%3d  offset:%3d (%3d)  length:%3d (%3d)  s2c:%d  c2s:%d  irq_count:%d  base_irq:%d\n",
-        cte->type,
-        cte->offset,
-        cte->offset / 4096,
-        cte->length,
-        cte->length / 8,
-        (cte->s2c_dma_present ? cte->s2c_dma_channel_num : -1),
-        (cte->c2s_dma_present ? cte->c2s_dma_channel_num : -1),
-        cte->irq_count,
-        cte->irq_base_num
-    );
+       dev_dbg(&pcard->pdev->dev, "CTE: type:%3d  offset:%3d (%3d)  length:%3d (%3d)  s2c:%d  c2s:%d  irq_count:%d  base_irq:%d\n",
+               cte->type,
+               cte->offset,
+               cte->offset / 4096,
+               cte->length,
+               cte->length / 8,
+               (cte->s2c_dma_present ? cte->s2c_dma_channel_num : -1),
+               (cte->c2s_dma_present ? cte->c2s_dma_channel_num : -1),
+               cte->irq_count,
+               cte->irq_base_num
+       );
 }
 
 static
 void parse_core_table_entry(struct core_table_entry *cte, const u64 read_val, const u8 entry_rev)
 {
        switch (entry_rev) {
-       case 0: parse_core_table_entry_v0(cte, read_val); break;
-       default: cte->type = 0; break;
+       case 0:
+               parse_core_table_entry_v0(cte, read_val);
+               break;
+       default:
+               cte->type = 0;
+               break;
        }
 }
 
-
-int  probe_core_basic(unsigned int core_num, struct kp2000_device *pcard, char *name, const struct core_table_entry cte)
+static int probe_core_basic(unsigned int core_num, struct kp2000_device *pcard,
+                           char *name, const struct core_table_entry cte)
 {
-    struct mfd_cell  cell = {0};
-    struct resource  resources[2];
-
-    struct kpc_core_device_platdata  core_pdata = {
-        .card_id           = pcard->card_id,
-        .build_version     = pcard->build_version,
-        .hardware_revision = pcard->hardware_revision,
-        .ssid              = pcard->ssid,
-        .ddna              = pcard->ddna,
-    };
-
-    dev_dbg(&pcard->pdev->dev, "Found Basic core: type = %02d  dma = %02x / %02x  offset = 0x%x  length = 0x%x (%d regs)\n", cte.type, KPC_OLD_S2C_DMA_CH_NUM(cte), KPC_OLD_C2S_DMA_CH_NUM(cte), cte.offset, cte.length, cte.length / 8);
-    
-    
-    cell.platform_data = &core_pdata;
-    cell.pdata_size = sizeof(struct kpc_core_device_platdata);
-    cell.name = name;
-    cell.id = core_num;
-    cell.num_resources = 2;
-    
-    memset(&resources, 0, sizeof(resources));
-
-    resources[0].start = cte.offset;
-    resources[0].end   = cte.offset + (cte.length - 1);
-    resources[0].flags = IORESOURCE_MEM;
-    
-    resources[1].start = pcard->pdev->irq;
-    resources[1].end   = pcard->pdev->irq;
-    resources[1].flags = IORESOURCE_IRQ;
-    
-    cell.resources = resources;
-    
-    return mfd_add_devices(
-        PCARD_TO_DEV(pcard),    // parent
-        pcard->card_num * 100,  // id
-        &cell,                  // struct mfd_cell *
-        1,                      // ndevs
-        &pcard->regs_base_resource,
-        0,                      // irq_base
-        NULL                    // struct irq_domain *
-    );
+       struct mfd_cell  cell = { .id = core_num, .name = name };
+       struct resource resources[2];
+
+       struct kpc_core_device_platdata core_pdata = {
+               .card_id           = pcard->card_id,
+               .build_version     = pcard->build_version,
+               .hardware_revision = pcard->hardware_revision,
+               .ssid              = pcard->ssid,
+               .ddna              = pcard->ddna,
+       };
+
+       dev_dbg(&pcard->pdev->dev, "Found Basic core: type = %02d  dma = %02x / %02x  offset = 0x%x  length = 0x%x (%d regs)\n", cte.type, KPC_OLD_S2C_DMA_CH_NUM(cte), KPC_OLD_C2S_DMA_CH_NUM(cte), cte.offset, cte.length, cte.length / 8);
+
+       cell.platform_data = &core_pdata;
+       cell.pdata_size = sizeof(struct kpc_core_device_platdata);
+       cell.num_resources = 2;
+
+       memset(&resources, 0, sizeof(resources));
+
+       resources[0].start = cte.offset;
+       resources[0].end   = cte.offset + (cte.length - 1);
+       resources[0].flags = IORESOURCE_MEM;
+
+       resources[1].start = pcard->pdev->irq;
+       resources[1].end   = pcard->pdev->irq;
+       resources[1].flags = IORESOURCE_IRQ;
+
+       cell.resources = resources;
+
+       return mfd_add_devices(PCARD_TO_DEV(pcard),    // parent
+                              pcard->card_num * 100,  // id
+                              &cell,                  // struct mfd_cell *
+                              1,                      // ndevs
+                              &pcard->regs_base_resource,
+                              0,                      // irq_base
+                              NULL);                  // struct irq_domain *
 }
 
-
 struct kpc_uio_device {
-    struct list_head list;
-    struct kp2000_device *pcard;
-    struct device  *dev;
-    struct uio_info uioinfo;
-    struct core_table_entry cte;
-    u16 core_num;
+       struct list_head list;
+       struct kp2000_device *pcard;
+       struct device  *dev;
+       struct uio_info uioinfo;
+       struct core_table_entry cte;
+       u16 core_num;
 };
 
-static ssize_t  show_attr(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t offset_show(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       struct kpc_uio_device *kudev = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", kudev->cte.offset);
+}
+static DEVICE_ATTR_RO(offset);
+
+static ssize_t size_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct kpc_uio_device *kudev = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", kudev->cte.length);
+}
+static DEVICE_ATTR_RO(size);
+
+static ssize_t type_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct kpc_uio_device *kudev = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", kudev->cte.type);
+}
+static DEVICE_ATTR_RO(type);
+
+static ssize_t s2c_dma_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       struct kpc_uio_device *kudev = dev_get_drvdata(dev);
+
+       if (!kudev->cte.s2c_dma_present)
+               return sprintf(buf, "%s", "not present\n");
+
+       return sprintf(buf, "%u\n", kudev->cte.s2c_dma_channel_num);
+}
+static DEVICE_ATTR_RO(s2c_dma);
+
+static ssize_t c2s_dma_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       struct kpc_uio_device *kudev = dev_get_drvdata(dev);
+
+       if (!kudev->cte.c2s_dma_present)
+               return sprintf(buf, "%s", "not present\n");
+
+       return sprintf(buf, "%u\n", kudev->cte.c2s_dma_channel_num);
+}
+static DEVICE_ATTR_RO(c2s_dma);
+
+static ssize_t irq_count_show(struct device *dev, struct device_attribute *attr,
+                             char *buf)
 {
-    struct kpc_uio_device *kudev = dev_get_drvdata(dev);
-    
-    #define ATTR_NAME_CMP(v)  (strcmp(v, attr->attr.name) == 0)
-    if ATTR_NAME_CMP("offset"){
-        return scnprintf(buf, PAGE_SIZE, "%u\n", kudev->cte.offset);
-    } else if ATTR_NAME_CMP("size"){
-        return scnprintf(buf, PAGE_SIZE, "%u\n", kudev->cte.length);
-    } else if ATTR_NAME_CMP("type"){
-        return scnprintf(buf, PAGE_SIZE, "%u\n", kudev->cte.type);
-    }
-    else if ATTR_NAME_CMP("s2c_dma"){
-        if (kudev->cte.s2c_dma_present){
-            return scnprintf(buf, PAGE_SIZE, "%u\n", kudev->cte.s2c_dma_channel_num);
-        } else {
-            return scnprintf(buf, PAGE_SIZE, "not present\n");
-        }
-    } else if ATTR_NAME_CMP("c2s_dma"){
-        if (kudev->cte.c2s_dma_present){
-            return scnprintf(buf, PAGE_SIZE, "%u\n", kudev->cte.c2s_dma_channel_num);
-        } else {
-            return scnprintf(buf, PAGE_SIZE, "not present\n");
-        }
-    }
-    else if ATTR_NAME_CMP("irq_count"){
-        return scnprintf(buf, PAGE_SIZE, "%u\n", kudev->cte.irq_count);
-    } else if ATTR_NAME_CMP("irq_base_num"){
-        return scnprintf(buf, PAGE_SIZE, "%u\n", kudev->cte.irq_base_num);
-    } else if ATTR_NAME_CMP("core_num"){
-        return scnprintf(buf, PAGE_SIZE, "%u\n", kudev->core_num);
-    } else {
-        return 0;
-    }
-    #undef ATTR_NAME_CMP
+       struct kpc_uio_device *kudev = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", kudev->cte.irq_count);
+}
+static DEVICE_ATTR_RO(irq_count);
+
+static ssize_t irq_base_num_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct kpc_uio_device *kudev = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", kudev->cte.irq_base_num);
 }
+static DEVICE_ATTR_RO(irq_base_num);
+
+static ssize_t core_num_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       struct kpc_uio_device *kudev = dev_get_drvdata(dev);
 
+       return sprintf(buf, "%u\n", kudev->core_num);
+}
+static DEVICE_ATTR_RO(core_num);
 
-DEVICE_ATTR(offset,  0444, show_attr, NULL);
-DEVICE_ATTR(size,    0444, show_attr, NULL);
-DEVICE_ATTR(type,    0444, show_attr, NULL);
-DEVICE_ATTR(s2c_dma_ch, 0444, show_attr, NULL);
-DEVICE_ATTR(c2s_dma_ch, 0444, show_attr, NULL);
-DEVICE_ATTR(s2c_dma, 0444, show_attr, NULL);
-DEVICE_ATTR(c2s_dma, 0444, show_attr, NULL);
-DEVICE_ATTR(irq_count, 0444, show_attr, NULL);
-DEVICE_ATTR(irq_base_num, 0444, show_attr, NULL);
-DEVICE_ATTR(core_num, 0444, show_attr, NULL);
-struct attribute * kpc_uio_class_attrs[] = {
+struct attribute *kpc_uio_class_attrs[] = {
        &dev_attr_offset.attr,
        &dev_attr_size.attr,
        &dev_attr_type.attr,
-       &dev_attr_s2c_dma_ch.attr,
-       &dev_attr_c2s_dma_ch.attr,
        &dev_attr_s2c_dma.attr,
        &dev_attr_c2s_dma.attr,
        &dev_attr_irq_count.attr,
@@ -208,264 +233,277 @@ struct attribute * kpc_uio_class_attrs[] = {
        NULL,
 };
 
-
 static
 int  kp2000_check_uio_irq(struct kp2000_device *pcard, u32 irq_num)
 {
-    u64 interrupt_active   =  readq(pcard->sysinfo_regs_base + REG_INTERRUPT_ACTIVE);
-    u64 interrupt_mask_inv = ~readq(pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
-    u64 irq_check_mask = (1 << irq_num);
-    if (interrupt_active & irq_check_mask){ // if it's active (interrupt pending)
-        if (interrupt_mask_inv & irq_check_mask){    // and if it's not masked off
-            return 1;
-        }
-    }
-    return 0;
+       u64 interrupt_active   =  readq(pcard->sysinfo_regs_base + REG_INTERRUPT_ACTIVE);
+       u64 interrupt_mask_inv = ~readq(pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
+       u64 irq_check_mask = BIT_ULL(irq_num);
+
+       if (interrupt_active & irq_check_mask) { // if it's active (interrupt pending)
+               if (interrupt_mask_inv & irq_check_mask) {    // and if it's not masked off
+                       return 1;
+               }
+       }
+       return 0;
 }
 
 static
 irqreturn_t  kuio_handler(int irq, struct uio_info *uioinfo)
 {
-    struct kpc_uio_device *kudev = uioinfo->priv;
-    if (irq != kudev->pcard->pdev->irq)
-        return IRQ_NONE;
-    
-    if (kp2000_check_uio_irq(kudev->pcard, kudev->cte.irq_base_num)){
-        writeq((1 << kudev->cte.irq_base_num), kudev->pcard->sysinfo_regs_base + REG_INTERRUPT_ACTIVE); // Clear the active flag
-        return IRQ_HANDLED;
-    }
-    return IRQ_NONE;
+       struct kpc_uio_device *kudev = uioinfo->priv;
+
+       if (irq != kudev->pcard->pdev->irq)
+               return IRQ_NONE;
+
+       if (kp2000_check_uio_irq(kudev->pcard, kudev->cte.irq_base_num)) {
+               /* Clear the active flag */
+               writeq(BIT_ULL(kudev->cte.irq_base_num),
+                      kudev->pcard->sysinfo_regs_base + REG_INTERRUPT_ACTIVE);
+               return IRQ_HANDLED;
+       }
+       return IRQ_NONE;
 }
 
 static
 int kuio_irqcontrol(struct uio_info *uioinfo, s32 irq_on)
 {
-    struct kpc_uio_device *kudev = uioinfo->priv;
-    struct kp2000_device *pcard = kudev->pcard;
-    u64 mask;
-    
-    lock_card(pcard);
-    mask = readq(pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
-    if (irq_on){
-        mask &= ~(1 << (kudev->cte.irq_base_num));
-    } else {
-        mask |= (1 << (kudev->cte.irq_base_num));
-    }
-    writeq(mask, pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
-    unlock_card(pcard);
-    
-    return 0;
+       struct kpc_uio_device *kudev = uioinfo->priv;
+       struct kp2000_device *pcard = kudev->pcard;
+       u64 mask;
+
+       mutex_lock(&pcard->sem);
+       mask = readq(pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
+       if (irq_on)
+               mask &= ~(BIT_ULL(kudev->cte.irq_base_num));
+       else
+               mask |= BIT_ULL(kudev->cte.irq_base_num);
+       writeq(mask, pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
+       mutex_unlock(&pcard->sem);
+
+       return 0;
 }
 
-int  probe_core_uio(unsigned int core_num, struct kp2000_device *pcard, char *name, const struct core_table_entry cte)
+static int probe_core_uio(unsigned int core_num, struct kp2000_device *pcard,
+                         char *name, const struct core_table_entry cte)
 {
-    struct kpc_uio_device  *kudev;
-    int rv;
-
-    dev_dbg(&pcard->pdev->dev, "Found UIO core:   type = %02d  dma = %02x / %02x  offset = 0x%x  length = 0x%x (%d regs)\n", cte.type, KPC_OLD_S2C_DMA_CH_NUM(cte), KPC_OLD_C2S_DMA_CH_NUM(cte), cte.offset, cte.length, cte.length / 8);
-    
-    kudev = kzalloc(sizeof(struct kpc_uio_device), GFP_KERNEL);
-    if (!kudev){
-        dev_err(&pcard->pdev->dev, "probe_core_uio: failed to kzalloc kpc_uio_device\n");
-        return -ENOMEM;
-    }
-    
-    INIT_LIST_HEAD(&kudev->list);
-    kudev->pcard = pcard;
-    kudev->cte = cte;
-    kudev->core_num = core_num;
-    
-    kudev->uioinfo.priv = kudev;
-    kudev->uioinfo.name = name;
-    kudev->uioinfo.version = "0.0";
-    if (cte.irq_count > 0){
-        kudev->uioinfo.irq_flags = IRQF_SHARED;
-        kudev->uioinfo.irq = pcard->pdev->irq;
-        kudev->uioinfo.handler = kuio_handler;
-        kudev->uioinfo.irqcontrol = kuio_irqcontrol;
-    } else {
-        kudev->uioinfo.irq = 0;
-    }
-
-    kudev->uioinfo.mem[0].name = "uiomap";
-    kudev->uioinfo.mem[0].addr = pci_resource_start(pcard->pdev, REG_BAR) + cte.offset;
-    kudev->uioinfo.mem[0].size = (cte.length + PAGE_SIZE-1) & ~(PAGE_SIZE-1); // Round up to nearest PAGE_SIZE boundary
-    kudev->uioinfo.mem[0].memtype = UIO_MEM_PHYS;
-    
-    kudev->dev = device_create(kpc_uio_class, &pcard->pdev->dev, MKDEV(0,0), kudev, "%s.%d.%d.%d", kudev->uioinfo.name, pcard->card_num, cte.type, kudev->core_num);
-    if (IS_ERR(kudev->dev)) {
-        dev_err(&pcard->pdev->dev, "probe_core_uio device_create failed!\n");
-        return -ENODEV;
-    }
-    dev_set_drvdata(kudev->dev, kudev);
-    
-    rv = uio_register_device(kudev->dev, &kudev->uioinfo);
-    if (rv){
-        dev_err(&pcard->pdev->dev, "probe_core_uio failed uio_register_device: %d\n", rv);
-        return rv;
-    }
-    
-    list_add_tail(&kudev->list, &pcard->uio_devices_list);
-    
-    return 0;
-}
+       struct kpc_uio_device *kudev;
+       int rv;
+
+       dev_dbg(&pcard->pdev->dev, "Found UIO core:   type = %02d  dma = %02x / %02x  offset = 0x%x  length = 0x%x (%d regs)\n", cte.type, KPC_OLD_S2C_DMA_CH_NUM(cte), KPC_OLD_C2S_DMA_CH_NUM(cte), cte.offset, cte.length, cte.length / 8);
+
+       kudev = kzalloc(sizeof(*kudev), GFP_KERNEL);
+       if (!kudev)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&kudev->list);
+       kudev->pcard = pcard;
+       kudev->cte = cte;
+       kudev->core_num = core_num;
+
+       kudev->uioinfo.priv = kudev;
+       kudev->uioinfo.name = name;
+       kudev->uioinfo.version = "0.0";
+       if (cte.irq_count > 0) {
+               kudev->uioinfo.irq_flags = IRQF_SHARED;
+               kudev->uioinfo.irq = pcard->pdev->irq;
+               kudev->uioinfo.handler = kuio_handler;
+               kudev->uioinfo.irqcontrol = kuio_irqcontrol;
+       } else {
+               kudev->uioinfo.irq = 0;
+       }
+
+       kudev->uioinfo.mem[0].name = "uiomap";
+       kudev->uioinfo.mem[0].addr = pci_resource_start(pcard->pdev, REG_BAR) + cte.offset;
+       kudev->uioinfo.mem[0].size = (cte.length + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); // Round up to nearest PAGE_SIZE boundary
+       kudev->uioinfo.mem[0].memtype = UIO_MEM_PHYS;
+
+       kudev->dev = device_create(kpc_uio_class, &pcard->pdev->dev, MKDEV(0, 0), kudev, "%s.%d.%d.%d", kudev->uioinfo.name, pcard->card_num, cte.type, kudev->core_num);
+       if (IS_ERR(kudev->dev)) {
+               dev_err(&pcard->pdev->dev, "%s: device_create failed!\n",
+                       __func__);
+               kfree(kudev);
+               return -ENODEV;
+       }
+       dev_set_drvdata(kudev->dev, kudev);
+
+       rv = uio_register_device(kudev->dev, &kudev->uioinfo);
+       if (rv) {
+               dev_err(&pcard->pdev->dev, "%s: failed uio_register_device: %d\n",
+                       __func__, rv);
+               put_device(kudev->dev);
+               kfree(kudev);
+               return rv;
+       }
 
+       list_add_tail(&kudev->list, &pcard->uio_devices_list);
+
+       return 0;
+}
 
 static int  create_dma_engine_core(struct kp2000_device *pcard, size_t engine_regs_offset, int engine_num, int irq_num)
 {
-    struct mfd_cell  cell = {0};
-    struct resource  resources[2];
-
-    dev_dbg(&pcard->pdev->dev, "create_dma_core(pcard = [%p], engine_regs_offset = %zx, engine_num = %d)\n", pcard, engine_regs_offset, engine_num);
-    
-    cell.platform_data = NULL;
-    cell.pdata_size = 0;
-    cell.id = engine_num;
-    cell.name = KP_DRIVER_NAME_DMA_CONTROLLER;
-    cell.num_resources = 2;
-    
-    memset(&resources, 0, sizeof(resources));
-
-    resources[0].start = engine_regs_offset;
-    resources[0].end   = engine_regs_offset + (KPC_DMA_ENGINE_SIZE - 1);
-    resources[0].flags = IORESOURCE_MEM;
-    
-    resources[1].start = irq_num;
-    resources[1].end   = irq_num;
-    resources[1].flags = IORESOURCE_IRQ;
-    
-    cell.resources = resources;
-    
-    return mfd_add_devices(
-        PCARD_TO_DEV(pcard),    // parent
-        pcard->card_num * 100,  // id
-        &cell,                  // struct mfd_cell *
-        1,                      // ndevs
-        &pcard->dma_base_resource,
-        0,                      // irq_base
-        NULL                    // struct irq_domain *
-    );
+       struct mfd_cell  cell = { .id = engine_num };
+       struct resource  resources[2];
+
+       cell.platform_data = NULL;
+       cell.pdata_size = 0;
+       cell.name = KP_DRIVER_NAME_DMA_CONTROLLER;
+       cell.num_resources = 2;
+
+       memset(&resources, 0, sizeof(resources));
+
+       resources[0].start = engine_regs_offset;
+       resources[0].end   = engine_regs_offset + (KPC_DMA_ENGINE_SIZE - 1);
+       resources[0].flags = IORESOURCE_MEM;
+
+       resources[1].start = irq_num;
+       resources[1].end   = irq_num;
+       resources[1].flags = IORESOURCE_IRQ;
+
+       cell.resources = resources;
+
+       return mfd_add_devices(PCARD_TO_DEV(pcard),    // parent
+                              pcard->card_num * 100,  // id
+                              &cell,                  // struct mfd_cell *
+                              1,                      // ndevs
+                              &pcard->dma_base_resource,
+                              0,                      // irq_base
+                              NULL);                  // struct irq_domain *
 }
 
 static int  kp2000_setup_dma_controller(struct kp2000_device *pcard)
 {
-    int err;
-    unsigned int i;
-    u64 capabilities_reg;
-    
-    // S2C Engines
-    for (i = 0 ; i < 32 ; i++){
-        capabilities_reg = readq( pcard->dma_bar_base + KPC_DMA_S2C_BASE_OFFSET + (KPC_DMA_ENGINE_SIZE * i) );
-        if (capabilities_reg & ENGINE_CAP_PRESENT_MASK){
-            err = create_dma_engine_core(pcard, (KPC_DMA_S2C_BASE_OFFSET + (KPC_DMA_ENGINE_SIZE * i)), i,  pcard->pdev->irq);
-            if (err) goto err_out;
-        }
-    }
-    // C2S Engines
-    for (i = 0 ; i < 32 ; i++){
-        capabilities_reg = readq( pcard->dma_bar_base + KPC_DMA_C2S_BASE_OFFSET + (KPC_DMA_ENGINE_SIZE * i) );
-        if (capabilities_reg & ENGINE_CAP_PRESENT_MASK){
-            err = create_dma_engine_core(pcard, (KPC_DMA_C2S_BASE_OFFSET + (KPC_DMA_ENGINE_SIZE * i)), 32+i,  pcard->pdev->irq);
-            if (err) goto err_out;
-        }
-    }
-    
-    return 0;
-    
+       int err;
+       unsigned int i;
+       u64 capabilities_reg;
+
+       // S2C Engines
+       for (i = 0 ; i < 32 ; i++) {
+               capabilities_reg = readq(pcard->dma_bar_base + KPC_DMA_S2C_BASE_OFFSET + (KPC_DMA_ENGINE_SIZE * i));
+               if (capabilities_reg & ENGINE_CAP_PRESENT_MASK) {
+                       err = create_dma_engine_core(pcard, (KPC_DMA_S2C_BASE_OFFSET + (KPC_DMA_ENGINE_SIZE * i)), i,  pcard->pdev->irq);
+                       if (err)
+                               goto err_out;
+               }
+       }
+       // C2S Engines
+       for (i = 0 ; i < 32 ; i++) {
+               capabilities_reg = readq(pcard->dma_bar_base + KPC_DMA_C2S_BASE_OFFSET + (KPC_DMA_ENGINE_SIZE * i));
+               if (capabilities_reg & ENGINE_CAP_PRESENT_MASK) {
+                       err = create_dma_engine_core(pcard, (KPC_DMA_C2S_BASE_OFFSET + (KPC_DMA_ENGINE_SIZE * i)), 32 + i,  pcard->pdev->irq);
+                       if (err)
+                               goto err_out;
+               }
+       }
+
+       return 0;
+
 err_out:
-    dev_err(&pcard->pdev->dev, "kp2000_setup_dma_controller: failed to add a DMA Engine: %d\n", err);
-    return err;
+       dev_err(&pcard->pdev->dev, "%s: failed to add a DMA Engine: %d\n",
+               __func__, err);
+       return err;
 }
 
 int  kp2000_probe_cores(struct kp2000_device *pcard)
 {
-    int err = 0;
-    int i;
-    int current_type_id;
-    u64 read_val;
-    unsigned int highest_core_id = 0;
-    struct core_table_entry cte;
-
-    dev_dbg(&pcard->pdev->dev, "kp2000_probe_cores(pcard = %p / %d)\n", pcard, pcard->card_num);
-    
-    err = kp2000_setup_dma_controller(pcard);
-    if (err) return err;
-    
-    INIT_LIST_HEAD(&pcard->uio_devices_list);
-    
-    // First, iterate the core table looking for the highest CORE_ID
-    for (i = 0 ; i < pcard->core_table_length ; i++){
-        read_val = readq(pcard->sysinfo_regs_base + ((pcard->core_table_offset + i) * 8));
-        parse_core_table_entry(&cte, read_val, pcard->core_table_rev);
-        dbg_cte(pcard, &cte);
-        if (cte.type > highest_core_id){
-            highest_core_id = cte.type;
-        }
-        if (cte.type == KP_CORE_ID_INVALID){
-            dev_info(&pcard->pdev->dev, "Found Invalid core: %016llx\n", read_val);
-        }
-    }
-    // Then, iterate over the possible core types.
-    for (current_type_id = 1 ; current_type_id <= highest_core_id ; current_type_id++){
-        unsigned int core_num = 0;
-        // Foreach core type, iterate the whole table and instantiate subdevices for each core.
-        // Yes, this is O(n*m) but the actual runtime is small enough that it's an acceptable tradeoff.
-        for (i = 0 ; i < pcard->core_table_length ; i++){
-            read_val = readq(pcard->sysinfo_regs_base + ((pcard->core_table_offset + i) * 8));
-            parse_core_table_entry(&cte, read_val, pcard->core_table_rev);
-            
-            if (cte.type == current_type_id){
-                switch (cte.type){
-                    case KP_CORE_ID_I2C:
-                        err = probe_core_basic(core_num, pcard, KP_DRIVER_NAME_I2C, cte);
-                        break;
-                    
-                    case KP_CORE_ID_SPI:
-                        err = probe_core_basic(core_num, pcard, KP_DRIVER_NAME_SPI, cte);
-                        break;
-                    
-                    default:
-                        err = probe_core_uio(core_num, pcard, "kpc_uio", cte);
-                        break;
-                }
-                if (err){
-                    dev_err(&pcard->pdev->dev, "kp2000_probe_cores: failed to add core %d: %d\n", i, err);
-                    return err;
-                }
-                core_num++;
-            }
-        }
-    }
-    
-    // Finally, instantiate a UIO device for the core_table.
-    cte.type                = 0; // CORE_ID_BOARD_INFO
-    cte.offset              = 0; // board info is always at the beginning
-    cte.length              = 512*8;
-    cte.s2c_dma_present     = false;
-    cte.s2c_dma_channel_num = 0;
-    cte.c2s_dma_present     = false;
-    cte.c2s_dma_channel_num = 0;
-    cte.irq_count           = 0;
-    cte.irq_base_num        = 0;
-    err = probe_core_uio(0, pcard, "kpc_uio", cte);
-    if (err){
-        dev_err(&pcard->pdev->dev, "kp2000_probe_cores: failed to add board_info core: %d\n", err);
-        return err;
-    }
-    
-    return 0;
+       int err = 0;
+       int i;
+       int current_type_id;
+       u64 read_val;
+       unsigned int highest_core_id = 0;
+       struct core_table_entry cte;
+
+       err = kp2000_setup_dma_controller(pcard);
+       if (err)
+               return err;
+
+       INIT_LIST_HEAD(&pcard->uio_devices_list);
+
+       // First, iterate the core table looking for the highest CORE_ID
+       for (i = 0 ; i < pcard->core_table_length ; i++) {
+               read_val = readq(pcard->sysinfo_regs_base + ((pcard->core_table_offset + i) * 8));
+               parse_core_table_entry(&cte, read_val, pcard->core_table_rev);
+               dbg_cte(pcard, &cte);
+               if (cte.type > highest_core_id)
+                       highest_core_id = cte.type;
+               if (cte.type == KP_CORE_ID_INVALID)
+                       dev_info(&pcard->pdev->dev, "Found Invalid core: %016llx\n", read_val);
+       }
+       // Then, iterate over the possible core types.
+       for (current_type_id = 1 ; current_type_id <= highest_core_id ; current_type_id++) {
+               unsigned int core_num = 0;
+               // Foreach core type, iterate the whole table and instantiate subdevices for each core.
+               // Yes, this is O(n*m) but the actual runtime is small enough that it's an acceptable tradeoff.
+               for (i = 0 ; i < pcard->core_table_length ; i++) {
+                       read_val = readq(pcard->sysinfo_regs_base + ((pcard->core_table_offset + i) * 8));
+                       parse_core_table_entry(&cte, read_val, pcard->core_table_rev);
+
+                       if (cte.type != current_type_id)
+                               continue;
+
+                       switch (cte.type) {
+                       case KP_CORE_ID_I2C:
+                               err = probe_core_basic(core_num, pcard,
+                                                      KP_DRIVER_NAME_I2C, cte);
+                               break;
+
+                       case KP_CORE_ID_SPI:
+                               err = probe_core_basic(core_num, pcard,
+                                                      KP_DRIVER_NAME_SPI, cte);
+                               break;
+
+                       default:
+                               err = probe_core_uio(core_num, pcard, "kpc_uio", cte);
+                               break;
+                       }
+                       if (err) {
+                               dev_err(&pcard->pdev->dev,
+                                       "%s: failed to add core %d: %d\n",
+                                       __func__, i, err);
+                               goto error;
+                       }
+                       core_num++;
+               }
+       }
+
+       // Finally, instantiate a UIO device for the core_table.
+       cte.type                = 0; // CORE_ID_BOARD_INFO
+       cte.offset              = 0; // board info is always at the beginning
+       cte.length              = 512 * 8;
+       cte.s2c_dma_present     = false;
+       cte.s2c_dma_channel_num = 0;
+       cte.c2s_dma_present     = false;
+       cte.c2s_dma_channel_num = 0;
+       cte.irq_count           = 0;
+       cte.irq_base_num        = 0;
+       err = probe_core_uio(0, pcard, "kpc_uio", cte);
+       if (err) {
+               dev_err(&pcard->pdev->dev, "%s: failed to add board_info core: %d\n",
+                       __func__, err);
+               goto error;
+       }
+
+       return 0;
+
+error:
+       kp2000_remove_cores(pcard);
+       mfd_remove_devices(PCARD_TO_DEV(pcard));
+       return err;
 }
 
 void  kp2000_remove_cores(struct kp2000_device *pcard)
 {
-    struct list_head *ptr;
-    struct list_head *next;
-    list_for_each_safe(ptr, next, &pcard->uio_devices_list){
-        struct kpc_uio_device *kudev = list_entry(ptr, struct kpc_uio_device, list);
-        uio_unregister_device(&kudev->uioinfo);
-        device_unregister(kudev->dev);
-        list_del(&kudev->list);
-        kfree(kudev);
-    }
+       struct list_head *ptr;
+       struct list_head *next;
+
+       list_for_each_safe(ptr, next, &pcard->uio_devices_list) {
+               struct kpc_uio_device *kudev = list_entry(ptr, struct kpc_uio_device, list);
+
+               uio_unregister_device(&kudev->uioinfo);
+               device_unregister(kudev->dev);
+               list_del(&kudev->list);
+               kfree(kudev);
+       }
 }
 
index 40390cd..cb05cca 100644 (file)
@@ -1,11 +1,17 @@
 // SPDX-License-Identifier: GPL-2.0+
+#include <linux/kernel.h>
+#include <linux/idr.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/types.h>
 #include <linux/export.h>
 #include <linux/slab.h>
-#include <asm/io.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/cdev.h>
+#include <linux/rwsem.h>
+#include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/mfd/core.h>
 #include <linux/platform_device.h>
 #include <linux/sched.h>
 #include <linux/jiffies.h>
 #include "pcie.h"
+#include "uapi.h"
 
+static DEFINE_IDA(card_num_ida);
 
 /*******************************************************
-  * SysFS Attributes
-  ******************************************************/
-static ssize_t  show_attr(struct device *dev, struct device_attribute *attr, char *buf)
+ * SysFS Attributes
+ ******************************************************/
+
+static ssize_t ssid_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
 {
-    struct pci_dev *pdev = to_pci_dev(dev);
-    struct kp2000_device *pcard;
-
-    if (!pdev)  return -ENXIO;
-    pcard = pci_get_drvdata(pdev);
-    if (!pcard)  return -ENXIO;
-    
-    if (strcmp("ssid", attr->attr.name) == 0){         return scnprintf(buf, PAGE_SIZE, "%016llx\n", pcard->ssid);  } else
-    if (strcmp("ddna", attr->attr.name) == 0){         return scnprintf(buf, PAGE_SIZE, "%016llx\n", pcard->ddna);  } else
-    if (strcmp("card_id", attr->attr.name) == 0){      return scnprintf(buf, PAGE_SIZE, "%08x\n", pcard->card_id);  } else
-    if (strcmp("hw_rev", attr->attr.name) == 0){       return scnprintf(buf, PAGE_SIZE, "%08x\n", pcard->hardware_revision);  } else
-    if (strcmp("build", attr->attr.name) == 0){        return scnprintf(buf, PAGE_SIZE, "%08x\n", pcard->build_version);  } else
-    if (strcmp("build_date", attr->attr.name) == 0){   return scnprintf(buf, PAGE_SIZE, "%08x\n", pcard->build_datestamp);  } else
-    if (strcmp("build_time", attr->attr.name) == 0){   return scnprintf(buf, PAGE_SIZE, "%08x\n", pcard->build_timestamp);  } else
-    { return -ENXIO; }
+       struct kp2000_device *pcard = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%016llx\n", pcard->ssid);
 }
+static DEVICE_ATTR_RO(ssid);
 
-static ssize_t  show_cpld_config_reg(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t ddna_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
 {
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct kp2000_device *pcard;
-       u64 val;
+       struct kp2000_device *pcard = dev_get_drvdata(dev);
 
-       if (!pdev)
-               return -ENXIO;
+       return sprintf(buf, "%016llx\n", pcard->ddna);
+}
+static DEVICE_ATTR_RO(ddna);
 
-       pcard = pci_get_drvdata(pdev);
-       if (!pcard)
-               return -ENXIO;
+static ssize_t card_id_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       struct kp2000_device *pcard = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%08x\n", pcard->card_id);
+}
+static DEVICE_ATTR_RO(card_id);
+
+static ssize_t hw_rev_show(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       struct kp2000_device *pcard = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%08x\n", pcard->hardware_revision);
+}
+static DEVICE_ATTR_RO(hw_rev);
+
+static ssize_t build_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct kp2000_device *pcard = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%08x\n", pcard->build_version);
+}
+static DEVICE_ATTR_RO(build);
+
+static ssize_t build_date_show(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       struct kp2000_device *pcard = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%08x\n", pcard->build_datestamp);
+}
+static DEVICE_ATTR_RO(build_date);
+
+static ssize_t build_time_show(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       struct kp2000_device *pcard = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%08x\n", pcard->build_timestamp);
+}
+static DEVICE_ATTR_RO(build_time);
+
+static ssize_t cpld_reg_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       struct kp2000_device *pcard = dev_get_drvdata(dev);
+       u64 val;
 
        val = readq(pcard->sysinfo_regs_base + REG_CPLD_CONFIG);
-       return scnprintf(buf, PAGE_SIZE, "%016llx\n", val);
+       return sprintf(buf, "%016llx\n", val);
+}
+static DEVICE_ATTR_RO(cpld_reg);
+
+static ssize_t cpld_reconfigure(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct kp2000_device *pcard = dev_get_drvdata(dev);
+       long wr_val;
+       int rv;
+
+       rv = kstrtol(buf, 0, &wr_val);
+       if (rv < 0)
+               return rv;
+       if (wr_val > 7)
+               return -EINVAL;
+
+       wr_val = wr_val << 8;
+       wr_val |= 0x1; // Set the "Configure Go" bit
+       writeq(wr_val, pcard->sysinfo_regs_base + REG_CPLD_CONFIG);
+       return count;
 }
-static ssize_t cpld_reconfigure(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static DEVICE_ATTR(cpld_reconfigure, 0220, NULL, cpld_reconfigure);
+
+static ssize_t irq_mask_reg_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
 {
-    struct pci_dev *pdev = to_pci_dev(dev);
-    long wr_val;
-    struct kp2000_device *pcard;
-    int rv;
-
-    if (!pdev)  return -ENXIO;
-    pcard = pci_get_drvdata(pdev);
-    if (!pcard)  return -ENXIO;
-    
-    rv = kstrtol(buf, 0, &wr_val);
-    if (rv < 0)  return rv;
-    if (wr_val > 7)  return -EINVAL;
-    
-    wr_val = wr_val << 8;
-    wr_val |= 0x1; // Set the "Configure Go" bit
-    writeq(wr_val, pcard->sysinfo_regs_base + REG_CPLD_CONFIG);
-    return count;
+       struct kp2000_device *pcard = dev_get_drvdata(dev);
+       u64 val;
+
+       val = readq(pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
+       return sprintf(buf, "%016llx\n", val);
 }
+static DEVICE_ATTR_RO(irq_mask_reg);
 
+static ssize_t irq_active_reg_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct kp2000_device *pcard = dev_get_drvdata(dev);
+       u64 val;
 
-DEVICE_ATTR(ssid,       0444, show_attr, NULL);
-DEVICE_ATTR(ddna,       0444, show_attr, NULL);
-DEVICE_ATTR(card_id,    0444, show_attr, NULL);
-DEVICE_ATTR(hw_rev,     0444, show_attr, NULL);
-DEVICE_ATTR(build,      0444, show_attr, NULL);
-DEVICE_ATTR(build_date, 0444, show_attr, NULL);
-DEVICE_ATTR(build_time, 0444, show_attr, NULL);
-DEVICE_ATTR(cpld_reg,   0444, show_cpld_config_reg, NULL);
-DEVICE_ATTR(cpld_reconfigure,   0220, NULL, cpld_reconfigure);
-
-static const struct attribute *  kp_attr_list[] = {
-    &dev_attr_ssid.attr,
-    &dev_attr_ddna.attr,
-    &dev_attr_card_id.attr,
-    &dev_attr_hw_rev.attr,
-    &dev_attr_build.attr,
-    &dev_attr_build_date.attr,
-    &dev_attr_build_time.attr,
-    &dev_attr_cpld_reg.attr,
-    &dev_attr_cpld_reconfigure.attr,
-    NULL,
-};
+       val = readq(pcard->sysinfo_regs_base + REG_INTERRUPT_ACTIVE);
+       return sprintf(buf, "%016llx\n", val);
+}
+static DEVICE_ATTR_RO(irq_active_reg);
 
+static ssize_t pcie_error_count_reg_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       struct kp2000_device *pcard = dev_get_drvdata(dev);
+       u64 val;
+
+       val = readq(pcard->sysinfo_regs_base + REG_PCIE_ERROR_COUNT);
+       return sprintf(buf, "%016llx\n", val);
+}
+static DEVICE_ATTR_RO(pcie_error_count_reg);
+
+static ssize_t core_table_offset_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct kp2000_device *pcard = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%08x\n", pcard->core_table_offset);
+}
+static DEVICE_ATTR_RO(core_table_offset);
+
+static ssize_t core_table_length_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct kp2000_device *pcard = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%08x\n", pcard->core_table_length);
+}
+static DEVICE_ATTR_RO(core_table_length);
+
+static const struct attribute *kp_attr_list[] = {
+       &dev_attr_ssid.attr,
+       &dev_attr_ddna.attr,
+       &dev_attr_card_id.attr,
+       &dev_attr_hw_rev.attr,
+       &dev_attr_build.attr,
+       &dev_attr_build_date.attr,
+       &dev_attr_build_time.attr,
+       &dev_attr_cpld_reg.attr,
+       &dev_attr_cpld_reconfigure.attr,
+       &dev_attr_irq_mask_reg.attr,
+       &dev_attr_irq_active_reg.attr,
+       &dev_attr_pcie_error_count_reg.attr,
+       &dev_attr_core_table_offset.attr,
+       &dev_attr_core_table_length.attr,
+       NULL,
+};
 
 /*******************************************************
 * Functions
 ******************************************************/
+ * Functions
+ ******************************************************/
 
 static void wait_and_read_ssid(struct kp2000_device *pcard)
 {
-    u64 read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_SSID);
-    unsigned long timeout;
-    
-    if (read_val & 0x8000000000000000){
-        pcard->ssid = read_val;
-        return;
-    }
-    
-    timeout = jiffies + (HZ * 2);
-    do {
-        read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_SSID);
-        if (read_val & 0x8000000000000000){
-            pcard->ssid = read_val;
-            return;
-        }
-        cpu_relax();
-        //schedule();
-    } while (time_before(jiffies, timeout));
-    
-    dev_notice(&pcard->pdev->dev, "SSID didn't show up!\n");
-    
-    #if 0
-    // Timed out waiting for the SSID to show up, just use the DDNA instead?
-    read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_DDNA);
-    pcard->ssid = read_val;
-    #else
-    // Timed out waiting for the SSID to show up, stick all zeros in the value
-    pcard->ssid = 0;
-    #endif
+       u64 read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_SSID);
+       unsigned long timeout;
+
+       if (read_val & 0x8000000000000000) {
+               pcard->ssid = read_val;
+               return;
+       }
+
+       timeout = jiffies + (HZ * 2);
+       do {
+               read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_SSID);
+               if (read_val & 0x8000000000000000) {
+                       pcard->ssid = read_val;
+                       return;
+               }
+               cpu_relax();
+               //schedule();
+       } while (time_before(jiffies, timeout));
+
+       dev_notice(&pcard->pdev->dev, "SSID didn't show up!\n");
+
+       // Timed out waiting for the SSID to show up, stick all zeros in the
+       // value
+       pcard->ssid = 0;
 }
 
 static int  read_system_regs(struct kp2000_device *pcard)
 {
-    u64 read_val;
-    
-    read_val = readq(pcard->sysinfo_regs_base + REG_MAGIC_NUMBER);
-    if (read_val != KP2000_MAGIC_VALUE){
-        dev_err(&pcard->pdev->dev, "Invalid magic!  Got: 0x%016llx  Want: 0x%016lx\n", read_val, KP2000_MAGIC_VALUE);
-        return -EILSEQ;
-    }
-    
-    read_val = readq(pcard->sysinfo_regs_base + REG_CARD_ID_AND_BUILD);
-    pcard->card_id = (read_val & 0xFFFFFFFF00000000) >> 32;
-    pcard->build_version = (read_val & 0x00000000FFFFFFFF) >> 0;
-    
-    read_val = readq(pcard->sysinfo_regs_base + REG_DATE_AND_TIME_STAMPS);
-    pcard->build_datestamp = (read_val & 0xFFFFFFFF00000000) >> 32;
-    pcard->build_timestamp = (read_val & 0x00000000FFFFFFFF) >> 0;
-    
-    read_val = readq(pcard->sysinfo_regs_base + REG_CORE_TABLE_OFFSET);
-    pcard->core_table_length = (read_val & 0xFFFFFFFF00000000) >> 32;
-    pcard->core_table_offset = (read_val & 0x00000000FFFFFFFF) >> 0;
-    
-    wait_and_read_ssid(pcard);
-    
-    read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_HW_ID);
-    pcard->core_table_rev    = (read_val & 0x0000000000000F00) >> 8;
-    pcard->hardware_revision = (read_val & 0x000000000000001F);
-    
-    read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_DDNA);
-    pcard->ddna = read_val;
-    
-    dev_info(&pcard->pdev->dev, "system_regs: %08x %08x %08x %08x  %02x  %d %d  %016llx  %016llx\n",
-        pcard->card_id,
-        pcard->build_version,
-        pcard->build_datestamp,
-        pcard->build_timestamp,
-        pcard->hardware_revision,
-        pcard->core_table_rev,
-        pcard->core_table_length,
-        pcard->ssid,
-        pcard->ddna
-    );
-    
-    if (pcard->core_table_rev > 1){
-        dev_err(&pcard->pdev->dev, "core table entry revision is higher than we can deal with, cannot continue with this card!\n");
-        return 1;
-    }
-    
-    return 0;
+       u64 read_val;
+
+       read_val = readq(pcard->sysinfo_regs_base + REG_MAGIC_NUMBER);
+       if (read_val != KP2000_MAGIC_VALUE) {
+               dev_err(&pcard->pdev->dev,
+                       "Invalid magic!  Got: 0x%016llx  Want: 0x%016llx\n",
+                       read_val, KP2000_MAGIC_VALUE);
+               return -EILSEQ;
+       }
+
+       read_val = readq(pcard->sysinfo_regs_base + REG_CARD_ID_AND_BUILD);
+       pcard->card_id = (read_val & 0xFFFFFFFF00000000) >> 32;
+       pcard->build_version = (read_val & 0x00000000FFFFFFFF) >> 0;
+
+       read_val = readq(pcard->sysinfo_regs_base + REG_DATE_AND_TIME_STAMPS);
+       pcard->build_datestamp = (read_val & 0xFFFFFFFF00000000) >> 32;
+       pcard->build_timestamp = (read_val & 0x00000000FFFFFFFF) >> 0;
+
+       read_val = readq(pcard->sysinfo_regs_base + REG_CORE_TABLE_OFFSET);
+       pcard->core_table_length = (read_val & 0xFFFFFFFF00000000) >> 32;
+       pcard->core_table_offset = (read_val & 0x00000000FFFFFFFF) >> 0;
+
+       wait_and_read_ssid(pcard);
+
+       read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_HW_ID);
+       pcard->core_table_rev    = (read_val & 0x0000000000000F00) >> 8;
+       pcard->hardware_revision = (read_val & 0x000000000000001F);
+
+       read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_DDNA);
+       pcard->ddna = read_val;
+
+       dev_info(&pcard->pdev->dev,
+                "system_regs: %08x %08x %08x %08x  %02x  %d %d  %016llx  %016llx\n",
+                pcard->card_id,
+                pcard->build_version,
+                pcard->build_datestamp,
+                pcard->build_timestamp,
+                pcard->hardware_revision,
+                pcard->core_table_rev,
+                pcard->core_table_length,
+                pcard->ssid,
+                pcard->ddna);
+
+       if (pcard->core_table_rev > 1) {
+               dev_err(&pcard->pdev->dev,
+                       "core table entry revision is higher than we can deal with, cannot continue with this card!\n");
+               return 1;
+       }
+
+       return 0;
 }
 
-irqreturn_t  kp2000_irq_handler(int irq, void *dev_id)
+static irqreturn_t kp2000_irq_handler(int irq, void *dev_id)
 {
-    struct kp2000_device  *pcard = (struct kp2000_device*)dev_id;
-    SetBackEndControl(pcard->dma_common_regs, KPC_DMA_CARD_IRQ_ENABLE | KPC_DMA_CARD_USER_INTERRUPT_MODE | KPC_DMA_CARD_USER_INTERRUPT_ACTIVE);
-    return IRQ_HANDLED;
+       struct kp2000_device *pcard = dev_id;
+
+       writel(KPC_DMA_CARD_IRQ_ENABLE |
+              KPC_DMA_CARD_USER_INTERRUPT_MODE |
+              KPC_DMA_CARD_USER_INTERRUPT_ACTIVE,
+              pcard->dma_common_regs);
+       return IRQ_HANDLED;
 }
 
-int  kp2000_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+static int kp2000_pcie_probe(struct pci_dev *pdev,
+                            const struct pci_device_id *id)
 {
-    int err = 0;
-    struct kp2000_device *pcard;
-    static int card_count = 1;
-    int rv;
-    unsigned long reg_bar_phys_addr;
-    unsigned long reg_bar_phys_len;
-    unsigned long dma_bar_phys_addr;
-    unsigned long dma_bar_phys_len;
-    u16 regval;
-    dev_dbg(&pdev->dev, "kp2000_pcie_probe(pdev = [%p], id = [%p])\n", pdev, id);
-    
-    //{ Step 1: Allocate a struct for the pcard
-    pcard = kzalloc(sizeof(struct kp2000_device), GFP_KERNEL);
-    if (NULL == pcard){
-        dev_err(&pdev->dev, "probe: failed to allocate private card data\n");
-        return -ENOMEM;
-    }
-    dev_dbg(&pdev->dev, "probe: allocated struct kp2000_device @ %p\n", pcard);
-    //}
-    
-    //{ Step 2: Initialize trivial pcard elements
-    pcard->card_num = card_count;
-    card_count++;
-    scnprintf(pcard->name, 16, "kpcard%d", pcard->card_num);
-    
-    mutex_init(&pcard->sem);
-    lock_card(pcard);
-    
-    pcard->pdev = pdev;
-    pci_set_drvdata(pdev, pcard);
-    //}
-    
-    //{ Step 3: Enable PCI device
-    err = pci_enable_device(pcard->pdev);
-    if (err){
-        dev_err(&pcard->pdev->dev, "probe: failed to enable PCIE2000 PCIe device (%d)\n", err);
-        goto out3;
-    }
-    //}
-    
-    //{ Step 4: Setup the Register BAR
-    reg_bar_phys_addr = pci_resource_start(pcard->pdev, REG_BAR);
-    reg_bar_phys_len = pci_resource_len(pcard->pdev, REG_BAR);
-    
-    pcard->regs_bar_base = ioremap_nocache(reg_bar_phys_addr, PAGE_SIZE);
-    if (NULL == pcard->regs_bar_base){
-        dev_err(&pcard->pdev->dev, "probe: REG_BAR could not remap memory to virtual space\n");
-        err = -ENODEV;
-        goto out4;
-    }
-    dev_dbg(&pcard->pdev->dev, "probe: REG_BAR virt hardware address start [%p]\n", pcard->regs_bar_base);
-    
-    err = pci_request_region(pcard->pdev, REG_BAR, KP_DRIVER_NAME_KP2000);
-    if (err){
-        iounmap(pcard->regs_bar_base);
-        dev_err(&pcard->pdev->dev, "probe: failed to acquire PCI region (%d)\n", err);
-        err = -ENODEV;
-        goto out4;
-    }
-    
-    pcard->regs_base_resource.start = reg_bar_phys_addr;
-    pcard->regs_base_resource.end   = reg_bar_phys_addr + reg_bar_phys_len - 1;
-    pcard->regs_base_resource.flags = IORESOURCE_MEM;
-    //}
-    
-    //{ Step 5: Setup the DMA BAR
-    dma_bar_phys_addr = pci_resource_start(pcard->pdev, DMA_BAR);
-    dma_bar_phys_len = pci_resource_len(pcard->pdev, DMA_BAR);
-    
-    pcard->dma_bar_base = ioremap_nocache(dma_bar_phys_addr, dma_bar_phys_len);
-    if (NULL == pcard->dma_bar_base){
-        dev_err(&pcard->pdev->dev, "probe: DMA_BAR could not remap memory to virtual space\n");
-        err = -ENODEV;
-        goto out5;
-    }
-    dev_dbg(&pcard->pdev->dev, "probe: DMA_BAR virt hardware address start [%p]\n", pcard->dma_bar_base);
-    
-    pcard->dma_common_regs = pcard->dma_bar_base + KPC_DMA_COMMON_OFFSET;
-    
-    err = pci_request_region(pcard->pdev, DMA_BAR, "kp2000_pcie");
-    if (err){
-        iounmap(pcard->dma_bar_base);
-        dev_err(&pcard->pdev->dev, "probe: failed to acquire PCI region (%d)\n", err);
-        err = -ENODEV;
-        goto out5;
-    }
-    
-    pcard->dma_base_resource.start = dma_bar_phys_addr;
-    pcard->dma_base_resource.end   = dma_bar_phys_addr + dma_bar_phys_len - 1;
-    pcard->dma_base_resource.flags = IORESOURCE_MEM;
-    //}
-    
-    //{ Step 6: System Regs
-    pcard->sysinfo_regs_base = pcard->regs_bar_base;
-    err = read_system_regs(pcard);
-    if (err)
-        goto out6;
-    
-    // Disable all "user" interrupts because they're not used yet.
-    writeq(0xFFFFFFFFFFFFFFFF, pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
-    //}
-    
-    //{ Step 7: Configure PCI thingies
-    // let the card master PCIe
-    pci_set_master(pcard->pdev);
-    // enable IO and mem if not already done
-    pci_read_config_word(pcard->pdev, PCI_COMMAND, &regval);
-    regval |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
-    pci_write_config_word(pcard->pdev, PCI_COMMAND, regval);
-    
-    // Clear relaxed ordering bit
-    pcie_capability_clear_and_set_word(pcard->pdev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_RELAX_EN, 0);
-    
-    // Set Max_Payload_Size and Max_Read_Request_Size
-    regval = (0x0) << 5; // Max_Payload_Size = 128 B
-    pcie_capability_clear_and_set_word(pcard->pdev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_PAYLOAD, regval);
-    regval = (0x0) << 12; // Max_Read_Request_Size = 128 B
-    pcie_capability_clear_and_set_word(pcard->pdev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_READRQ, regval);
-    
-    // Enable error reporting for: Correctable Errors, Non-Fatal Errors, Fatal Errors, Unsupported Requests
-    pcie_capability_clear_and_set_word(pcard->pdev, PCI_EXP_DEVCTL, 0, PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
-    
-    err = dma_set_mask(PCARD_TO_DEV(pcard), DMA_BIT_MASK(64));
-    if (err){
-        dev_err(&pcard->pdev->dev, "CANNOT use DMA mask %0llx\n", DMA_BIT_MASK(64));
-        goto out7;
-    }
-    dev_dbg(&pcard->pdev->dev, "Using DMA mask %0llx\n", dma_get_mask(PCARD_TO_DEV(pcard)));
-    //}
-    
-    //{ Step 8: Configure IRQs
-    err = pci_enable_msi(pcard->pdev);
-    if (err < 0)
-        goto out8a;
-    
-    rv = request_irq(pcard->pdev->irq, kp2000_irq_handler, IRQF_SHARED, pcard->name, pcard);
-    if (rv){
-        dev_err(&pcard->pdev->dev, "kp2000_pcie_probe: failed to request_irq: %d\n", rv);
-        goto out8b;
-    }
-    //}
-    
-    //{ Step 9: Setup sysfs attributes
-    err = sysfs_create_files(&(pdev->dev.kobj), kp_attr_list);
-    if (err){
-        dev_err(&pdev->dev, "Failed to add sysfs files: %d\n", err);
-        goto out9;
-    }
-    //}
-    
-    //{ Step 10: Setup misc device
-    pcard->miscdev.minor = MISC_DYNAMIC_MINOR;
-    pcard->miscdev.fops = &kp2000_fops;
-    pcard->miscdev.parent = &pcard->pdev->dev;
-    pcard->miscdev.name = pcard->name;
-    
-    err = misc_register(&pcard->miscdev);
-    if (err){
-        dev_err(&pcard->pdev->dev, "kp2000_pcie_probe: misc_register failed: %d\n", err);
-        goto out10;
-    }
-    //}
-    
-    //{ Step 11: Probe cores
-    err = kp2000_probe_cores(pcard);
-    if (err)
-        goto out11;
-    //}
-    
-    //{ Step 12: Enable IRQs in HW
-    SetBackEndControl(pcard->dma_common_regs, KPC_DMA_CARD_IRQ_ENABLE | KPC_DMA_CARD_USER_INTERRUPT_MODE);
-    //}
-    
-    dev_dbg(&pcard->pdev->dev, "kp2000_pcie_probe() complete!\n");
-    unlock_card(pcard);
-    return 0;
-
-  out11:
-    misc_deregister(&pcard->miscdev);
-  out10:
-    sysfs_remove_files(&(pdev->dev.kobj), kp_attr_list);
-  out9:
-    free_irq(pcard->pdev->irq, pcard);
-  out8b:
-    pci_disable_msi(pcard->pdev);
-  out8a:
-  out7:
-  out6:
-    iounmap(pcard->dma_bar_base);
-    pci_release_region(pdev, DMA_BAR);
-    pcard->dma_bar_base = NULL;
-  out5:
-    iounmap(pcard->regs_bar_base);
-    pci_release_region(pdev, REG_BAR);
-    pcard->regs_bar_base = NULL;
-  out4:
-    pci_disable_device(pcard->pdev);
-  out3:
-    unlock_card(pcard);
-    kfree(pcard);
-    return err;
+       int err = 0;
+       struct kp2000_device *pcard;
+       int rv;
+       unsigned long reg_bar_phys_addr;
+       unsigned long reg_bar_phys_len;
+       unsigned long dma_bar_phys_addr;
+       unsigned long dma_bar_phys_len;
+       u16 regval;
+
+       pcard = kzalloc(sizeof(*pcard), GFP_KERNEL);
+       if (!pcard)
+               return -ENOMEM;
+       dev_dbg(&pdev->dev, "probe: allocated struct kp2000_device @ %p\n",
+               pcard);
+
+       err = ida_simple_get(&card_num_ida, 1, INT_MAX, GFP_KERNEL);
+       if (err < 0) {
+               dev_err(&pdev->dev, "probe: failed to get card number (%d)\n",
+                       err);
+               goto err_free_pcard;
+       }
+       pcard->card_num = err;
+       scnprintf(pcard->name, 16, "kpcard%u", pcard->card_num);
+
+       mutex_init(&pcard->sem);
+       mutex_lock(&pcard->sem);
+
+       pcard->pdev = pdev;
+       pci_set_drvdata(pdev, pcard);
+
+       err = pci_enable_device(pcard->pdev);
+       if (err) {
+               dev_err(&pcard->pdev->dev,
+                       "probe: failed to enable PCIE2000 PCIe device (%d)\n",
+                       err);
+               goto err_remove_ida;
+       }
+
+       /* Setup the Register BAR */
+       reg_bar_phys_addr = pci_resource_start(pcard->pdev, REG_BAR);
+       reg_bar_phys_len = pci_resource_len(pcard->pdev, REG_BAR);
+
+       pcard->regs_bar_base = ioremap_nocache(reg_bar_phys_addr, PAGE_SIZE);
+       if (!pcard->regs_bar_base) {
+               dev_err(&pcard->pdev->dev,
+                       "probe: REG_BAR could not remap memory to virtual space\n");
+               err = -ENODEV;
+               goto err_disable_device;
+       }
+       dev_dbg(&pcard->pdev->dev,
+               "probe: REG_BAR virt hardware address start [%p]\n",
+               pcard->regs_bar_base);
+
+       err = pci_request_region(pcard->pdev, REG_BAR, KP_DRIVER_NAME_KP2000);
+       if (err) {
+               dev_err(&pcard->pdev->dev,
+                       "probe: failed to acquire PCI region (%d)\n",
+                       err);
+               err = -ENODEV;
+               goto err_unmap_regs;
+       }
+
+       pcard->regs_base_resource.start = reg_bar_phys_addr;
+       pcard->regs_base_resource.end   = reg_bar_phys_addr +
+                                         reg_bar_phys_len - 1;
+       pcard->regs_base_resource.flags = IORESOURCE_MEM;
+
+       /* Setup the DMA BAR */
+       dma_bar_phys_addr = pci_resource_start(pcard->pdev, DMA_BAR);
+       dma_bar_phys_len = pci_resource_len(pcard->pdev, DMA_BAR);
+
+       pcard->dma_bar_base = ioremap_nocache(dma_bar_phys_addr,
+                                             dma_bar_phys_len);
+       if (!pcard->dma_bar_base) {
+               dev_err(&pcard->pdev->dev,
+                       "probe: DMA_BAR could not remap memory to virtual space\n");
+               err = -ENODEV;
+               goto err_release_regs;
+       }
+       dev_dbg(&pcard->pdev->dev,
+               "probe: DMA_BAR virt hardware address start [%p]\n",
+               pcard->dma_bar_base);
+
+       pcard->dma_common_regs = pcard->dma_bar_base + KPC_DMA_COMMON_OFFSET;
+
+       err = pci_request_region(pcard->pdev, DMA_BAR, "kp2000_pcie");
+       if (err) {
+               dev_err(&pcard->pdev->dev,
+                       "probe: failed to acquire PCI region (%d)\n", err);
+               err = -ENODEV;
+               goto err_unmap_dma;
+       }
+
+       pcard->dma_base_resource.start = dma_bar_phys_addr;
+       pcard->dma_base_resource.end   = dma_bar_phys_addr +
+                                        dma_bar_phys_len - 1;
+       pcard->dma_base_resource.flags = IORESOURCE_MEM;
+
+       /* Read System Regs */
+       pcard->sysinfo_regs_base = pcard->regs_bar_base;
+       err = read_system_regs(pcard);
+       if (err)
+               goto err_release_dma;
+
+       // Disable all "user" interrupts because they're not used yet.
+       writeq(0xFFFFFFFFFFFFFFFF,
+              pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
+
+       // let the card master PCIe
+       pci_set_master(pcard->pdev);
+
+       // enable IO and mem if not already done
+       pci_read_config_word(pcard->pdev, PCI_COMMAND, &regval);
+       regval |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+       pci_write_config_word(pcard->pdev, PCI_COMMAND, regval);
+
+       // Clear relaxed ordering bit
+       pcie_capability_clear_and_set_word(pcard->pdev, PCI_EXP_DEVCTL,
+                                          PCI_EXP_DEVCTL_RELAX_EN, 0);
+
+       // Set Max_Payload_Size and Max_Read_Request_Size
+       regval = (0x0) << 5; // Max_Payload_Size = 128 B
+       pcie_capability_clear_and_set_word(pcard->pdev, PCI_EXP_DEVCTL,
+                                          PCI_EXP_DEVCTL_PAYLOAD, regval);
+       regval = (0x0) << 12; // Max_Read_Request_Size = 128 B
+       pcie_capability_clear_and_set_word(pcard->pdev, PCI_EXP_DEVCTL,
+                                          PCI_EXP_DEVCTL_READRQ, regval);
+
+       // Enable error reporting for: Correctable Errors, Non-Fatal Errors,
+       // Fatal Errors, Unsupported Requests
+       pcie_capability_clear_and_set_word(pcard->pdev, PCI_EXP_DEVCTL, 0,
+                                          PCI_EXP_DEVCTL_CERE |
+                                          PCI_EXP_DEVCTL_NFERE |
+                                          PCI_EXP_DEVCTL_FERE |
+                                          PCI_EXP_DEVCTL_URRE);
+
+       err = dma_set_mask(PCARD_TO_DEV(pcard), DMA_BIT_MASK(64));
+       if (err) {
+               dev_err(&pcard->pdev->dev,
+                       "CANNOT use DMA mask %0llx\n", DMA_BIT_MASK(64));
+               goto err_release_dma;
+       }
+       dev_dbg(&pcard->pdev->dev,
+               "Using DMA mask %0llx\n", dma_get_mask(PCARD_TO_DEV(pcard)));
+
+       err = pci_enable_msi(pcard->pdev);
+       if (err < 0)
+               goto err_release_dma;
+
+       rv = request_irq(pcard->pdev->irq, kp2000_irq_handler, IRQF_SHARED,
+                        pcard->name, pcard);
+       if (rv) {
+               dev_err(&pcard->pdev->dev,
+                       "%s: failed to request_irq: %d\n", __func__, rv);
+               goto err_disable_msi;
+       }
+
+       err = sysfs_create_files(&pdev->dev.kobj, kp_attr_list);
+       if (err) {
+               dev_err(&pdev->dev, "Failed to add sysfs files: %d\n", err);
+               goto err_free_irq;
+       }
+
+       err = kp2000_probe_cores(pcard);
+       if (err)
+               goto err_remove_sysfs;
+
+       /* Enable IRQs in HW */
+       writel(KPC_DMA_CARD_IRQ_ENABLE | KPC_DMA_CARD_USER_INTERRUPT_MODE,
+              pcard->dma_common_regs);
+
+       mutex_unlock(&pcard->sem);
+       return 0;
+
+err_remove_sysfs:
+       sysfs_remove_files(&pdev->dev.kobj, kp_attr_list);
+err_free_irq:
+       free_irq(pcard->pdev->irq, pcard);
+err_disable_msi:
+       pci_disable_msi(pcard->pdev);
+err_release_dma:
+       pci_release_region(pdev, DMA_BAR);
+err_unmap_dma:
+       iounmap(pcard->dma_bar_base);
+err_release_regs:
+       pci_release_region(pdev, REG_BAR);
+err_unmap_regs:
+       iounmap(pcard->regs_bar_base);
+err_disable_device:
+       pci_disable_device(pcard->pdev);
+err_remove_ida:
+       mutex_unlock(&pcard->sem);
+       ida_simple_remove(&card_num_ida, pcard->card_num);
+err_free_pcard:
+       kfree(pcard);
+       return err;
+}
+
+static void kp2000_pcie_remove(struct pci_dev *pdev)
+{
+       struct kp2000_device *pcard = pci_get_drvdata(pdev);
+
+       if (!pcard)
+               return;
+
+       mutex_lock(&pcard->sem);
+       kp2000_remove_cores(pcard);
+       mfd_remove_devices(PCARD_TO_DEV(pcard));
+       sysfs_remove_files(&pdev->dev.kobj, kp_attr_list);
+       free_irq(pcard->pdev->irq, pcard);
+       pci_disable_msi(pcard->pdev);
+       if (pcard->dma_bar_base) {
+               iounmap(pcard->dma_bar_base);
+               pci_release_region(pdev, DMA_BAR);
+               pcard->dma_bar_base = NULL;
+       }
+       if (pcard->regs_bar_base) {
+               iounmap(pcard->regs_bar_base);
+               pci_release_region(pdev, REG_BAR);
+               pcard->regs_bar_base = NULL;
+       }
+       pci_disable_device(pcard->pdev);
+       pci_set_drvdata(pdev, NULL);
+       mutex_unlock(&pcard->sem);
+       ida_simple_remove(&card_num_ida, pcard->card_num);
+       kfree(pcard);
 }
 
+struct class *kpc_uio_class;
+ATTRIBUTE_GROUPS(kpc_uio_class);
+
+static const struct pci_device_id kp2000_pci_device_ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_DAKTRONICS, PCI_DEVICE_ID_DAKTRONICS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_DAKTRONICS, PCI_DEVICE_ID_DAKTRONICS_KADOKA_P2KR0) },
+       { 0, }
+};
+MODULE_DEVICE_TABLE(pci, kp2000_pci_device_ids);
+
+static struct pci_driver kp2000_driver_inst = {
+       .name =         "kp2000_pcie",
+       .id_table =     kp2000_pci_device_ids,
+       .probe =        kp2000_pcie_probe,
+       .remove =       kp2000_pcie_remove,
+};
 
-void  kp2000_pcie_remove(struct pci_dev *pdev)
+static int __init kp2000_pcie_init(void)
 {
-    struct kp2000_device *pcard = pci_get_drvdata(pdev);
-
-    dev_dbg(&pdev->dev, "kp2000_pcie_remove(pdev=%p)\n", pdev);
-    
-    if (pcard == NULL)  return;
-    
-    lock_card(pcard);
-    kp2000_remove_cores(pcard);
-    mfd_remove_devices(PCARD_TO_DEV(pcard));
-    misc_deregister(&pcard->miscdev);
-    sysfs_remove_files(&(pdev->dev.kobj), kp_attr_list);
-    free_irq(pcard->pdev->irq, pcard);
-    pci_disable_msi(pcard->pdev);
-    if (pcard->dma_bar_base != NULL){
-        iounmap(pcard->dma_bar_base);
-        pci_release_region(pdev, DMA_BAR);
-        pcard->dma_bar_base = NULL;
-    }
-    if (pcard->regs_bar_base != NULL){
-        iounmap(pcard->regs_bar_base);
-        pci_release_region(pdev, REG_BAR);
-        pcard->regs_bar_base = NULL;
-    }
-    pci_disable_device(pcard->pdev);
-    pci_set_drvdata(pdev, NULL);
-    unlock_card(pcard);
-    kfree(pcard);
+       kpc_uio_class = class_create(THIS_MODULE, "kpc_uio");
+       if (IS_ERR(kpc_uio_class))
+               return PTR_ERR(kpc_uio_class);
+
+       kpc_uio_class->dev_groups = kpc_uio_class_groups;
+       return pci_register_driver(&kp2000_driver_inst);
 }
+module_init(kp2000_pcie_init);
+
+static void __exit kp2000_pcie_exit(void)
+{
+       pci_unregister_driver(&kp2000_driver_inst);
+       class_destroy(kpc_uio_class);
+       ida_destroy(&card_num_ida);
+}
+module_exit(kp2000_pcie_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lee.Brooke@Daktronics.com, Matt.Sickler@Daktronics.com");
+MODULE_SOFTDEP("pre: uio post: kpc_nwl_dma kpc_i2c kpc_spi");
index f35e636..21450e3 100644 (file)
 #define KPC_DMA_CARD_S2C_INTERRUPT_STATUS_MASK  0x00FF0000
 #define KPC_DMA_CARD_C2S_INTERRUPT_STATUS_MASK  0xFF000000
 
-static inline  void  SetBackEndControl(void __iomem *regs, u32 value)
-{
-    writel(value, regs + 0);
-}
-static inline  u32  GetBackEndStatus(void __iomem *regs)
-{
-    return readl(regs + 0);
-}
-
-static inline  u32  BackEndControlSetClear(void __iomem *regs, u32 set_bits, u32 clear_bits)
-{
-    u32 start_val = GetBackEndStatus(regs);
-    u32 new_val = start_val;
-    new_val &= ~clear_bits;
-    new_val |= set_bits;
-    SetBackEndControl(regs, new_val);
-    return start_val;
-}
-
 #endif /* KPC_DMA_COMMON_DEFS_H_ */
diff --git a/drivers/staging/kpc2000/kpc2000/fileops.c b/drivers/staging/kpc2000/kpc2000/fileops.c
deleted file mode 100644 (file)
index b3b0b76..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>   /* printk() */
-#include <linux/slab.h>     /* kmalloc() */
-#include <linux/fs.h>       /* everything... */
-#include <linux/errno.h>    /* error codes */
-#include <linux/types.h>    /* size_t */
-#include <linux/cdev.h>
-#include <linux/uaccess.h>    /* copy_*_user */
-#include <linux/rwsem.h>
-#include <linux/idr.h>
-#include <linux/io-64-nonatomic-lo-hi.h>
-#include <linux/device.h>
-#include <linux/sched.h>
-#include "pcie.h"
-#include "uapi.h"
-
-int  kp2000_cdev_open(struct inode *inode, struct file *filp)
-{
-       struct kp2000_device *pcard = container_of(filp->private_data, struct kp2000_device, miscdev);
-
-       dev_dbg(&pcard->pdev->dev, "kp2000_cdev_open(filp = [%p], pcard = [%p])\n", filp, pcard);
-
-       filp->private_data = pcard; /* so other methods can access it */
-
-       return 0;
-}
-
-int  kp2000_cdev_close(struct inode *inode, struct file *filp)
-{
-       struct kp2000_device *pcard = filp->private_data;
-
-       dev_dbg(&pcard->pdev->dev, "kp2000_cdev_close(filp = [%p], pcard = [%p])\n", filp, pcard);
-       return 0;
-}
-
-
-ssize_t  kp2000_cdev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
-{
-       struct kp2000_device *pcard = filp->private_data;
-       int cnt = 0;
-       int ret;
-#define BUFF_CNT  1024
-       char buff[BUFF_CNT] = {0}; //NOTE: Increase this so it is at least as large as all the scnprintfs.  And don't use unbounded strings. "%s"
-       //NOTE: also, this is a really shitty way to implement the read() call, but it will work for any size 'count'.
-
-       if (WARN(NULL == buf, "kp2000_cdev_read: buf is a NULL pointer!\n"))
-               return -EINVAL;
-
-       cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Card ID                 : 0x%08x\n", pcard->card_id);
-       cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Build Version           : 0x%08x\n", pcard->build_version);
-       cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Build Date              : 0x%08x\n", pcard->build_datestamp);
-       cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Build Time              : 0x%08x\n", pcard->build_timestamp);
-       cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Core Table Offset       : 0x%08x\n", pcard->core_table_offset);
-       cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Core Table Length       : 0x%08x\n", pcard->core_table_length);
-       cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Hardware Revision       : 0x%08x\n", pcard->hardware_revision);
-       cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "SSID                    : 0x%016llx\n", pcard->ssid);
-       cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "DDNA                    : 0x%016llx\n", pcard->ddna);
-       cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "IRQ Mask                : 0x%016llx\n", readq(pcard->sysinfo_regs_base + REG_INTERRUPT_MASK));
-       cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "IRQ Active              : 0x%016llx\n", readq(pcard->sysinfo_regs_base + REG_INTERRUPT_ACTIVE));
-       cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "CPLD                    : 0x%016llx\n", readq(pcard->sysinfo_regs_base + REG_CPLD_CONFIG));
-
-       if (*f_pos >= cnt)
-               return 0;
-
-       if (count > cnt)
-               count = cnt;
-
-       ret = copy_to_user(buf, buff + *f_pos, count);
-       if (ret)
-               return -EFAULT;
-       *f_pos += count;
-       return count;
-}
-
-ssize_t  kp2000_cdev_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
-{
-       return -EINVAL;
-}
-
-long  kp2000_cdev_ioctl(struct file *filp, unsigned int ioctl_num, unsigned long ioctl_param)
-{
-       struct kp2000_device *pcard = filp->private_data;
-
-       dev_dbg(&pcard->pdev->dev, "kp2000_cdev_ioctl(filp = [%p], ioctl_num = 0x%08x, ioctl_param = 0x%016lx) pcard = [%p]\n", filp, ioctl_num, ioctl_param, pcard);
-
-       switch (ioctl_num){
-       case KP2000_IOCTL_GET_CPLD_REG:             return readq(pcard->sysinfo_regs_base + REG_CPLD_CONFIG);
-       case KP2000_IOCTL_GET_PCIE_ERROR_REG:       return readq(pcard->sysinfo_regs_base + REG_PCIE_ERROR_COUNT);
-    
-       case KP2000_IOCTL_GET_EVERYTHING: {
-               struct kp2000_regs temp;
-               int ret;
-
-               memset(&temp, 0, sizeof(temp));
-               temp.card_id = pcard->card_id;
-               temp.build_version = pcard->build_version;
-               temp.build_datestamp = pcard->build_datestamp;
-               temp.build_timestamp = pcard->build_timestamp;
-               temp.hw_rev = pcard->hardware_revision;
-               temp.ssid = pcard->ssid;
-               temp.ddna = pcard->ddna;
-               temp.cpld_reg = readq(pcard->sysinfo_regs_base + REG_CPLD_CONFIG);
-
-               ret = copy_to_user((void*)ioctl_param, (void*)&temp, sizeof(temp));
-               if (ret)
-                       return -EFAULT;
-
-               return sizeof(temp);
-               }
-
-       default:
-               return -ENOTTY;
-       }
-       return -ENOTTY;
-}
-
-
-struct file_operations  kp2000_fops = {
-       .owner      = THIS_MODULE,
-       .open       = kp2000_cdev_open,
-       .release    = kp2000_cdev_close,
-       .read       = kp2000_cdev_read,
-       //.write      = kp2000_cdev_write,
-       //.poll       = kp2000_cdev_poll,
-       //.fasync     = kp2000_cdev_fasync,
-       .llseek     = noop_llseek,
-       .unlocked_ioctl = kp2000_cdev_ioctl,
-};
-
diff --git a/drivers/staging/kpc2000/kpc2000/kp2000_module.c b/drivers/staging/kpc2000/kpc2000/kp2000_module.c
deleted file mode 100644 (file)
index fa3bd26..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/types.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-#include <asm/io.h>
-#include <linux/io.h>
-#include <linux/mfd/core.h>
-#include <linux/platform_device.h>
-#include <linux/ioport.h>
-#include "pcie.h"
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Lee.Brooke@Daktronics.com, Matt.Sickler@Daktronics.com");
-MODULE_SOFTDEP("pre: uio post: kpc_nwl_dma kpc_i2c kpc_spi");
-
-struct class *kpc_uio_class;
-ATTRIBUTE_GROUPS(kpc_uio_class);
-
-static const struct pci_device_id kp2000_pci_device_ids[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_DAKTRONICS, PCI_DEVICE_ID_DAKTRONICS) },
-       { PCI_DEVICE(PCI_VENDOR_ID_DAKTRONICS, PCI_DEVICE_ID_DAKTRONICS_KADOKA_P2KR0) },
-       { 0, }
-};
-MODULE_DEVICE_TABLE(pci, kp2000_pci_device_ids);
-
-static struct pci_driver  kp2000_driver_inst = {
-       .name       = "kp2000_pcie",
-       .id_table   = kp2000_pci_device_ids,
-       .probe      = kp2000_pcie_probe,
-       .remove     = kp2000_pcie_remove
-};
-
-
-static int __init  kp2000_pcie_init(void)
-{
-       kpc_uio_class = class_create(THIS_MODULE, "kpc_uio");
-       if (IS_ERR(kpc_uio_class))
-               return PTR_ERR(kpc_uio_class);
-
-       kpc_uio_class->dev_groups = kpc_uio_class_groups;
-       return pci_register_driver(&kp2000_driver_inst);
-}
-module_init(kp2000_pcie_init);
-
-static void __exit  kp2000_pcie_exit(void)
-{
-       pci_unregister_driver(&kp2000_driver_inst);
-       class_destroy(kpc_uio_class);
-}
-module_exit(kp2000_pcie_exit);
index 893aebf..cb815c3 100644 (file)
@@ -2,7 +2,6 @@
 #ifndef KP2000_PCIE_H
 #define KP2000_PCIE_H
 #include <linux/types.h>
-#include <linux/miscdevice.h>
 #include <linux/pci.h>
 #include "../kpc.h"
 #include "dma_common_defs.h"
  *      9   <---------------------- IRQ Active Flags ---------------------->
  */
 
-#define REG_WIDTH   8
-#define REG_MAGIC_NUMBER            (0 * REG_WIDTH)
-#define REG_CARD_ID_AND_BUILD       (1 * REG_WIDTH)
-#define REG_DATE_AND_TIME_STAMPS    (2 * REG_WIDTH)
-#define REG_CORE_TABLE_OFFSET       (3 * REG_WIDTH)
-#define REG_FPGA_SSID               (4 * REG_WIDTH)
-#define REG_FPGA_HW_ID              (5 * REG_WIDTH)
-#define REG_FPGA_DDNA               (6 * REG_WIDTH)
-#define REG_CPLD_CONFIG             (7 * REG_WIDTH)
-#define REG_INTERRUPT_MASK          (8 * REG_WIDTH)
-#define REG_INTERRUPT_ACTIVE        (9 * REG_WIDTH)
-#define REG_PCIE_ERROR_COUNT        (10 * REG_WIDTH)
+#define REG_WIDTH                      8
+#define REG_MAGIC_NUMBER               (0 * REG_WIDTH)
+#define REG_CARD_ID_AND_BUILD          (1 * REG_WIDTH)
+#define REG_DATE_AND_TIME_STAMPS       (2 * REG_WIDTH)
+#define REG_CORE_TABLE_OFFSET          (3 * REG_WIDTH)
+#define REG_FPGA_SSID                  (4 * REG_WIDTH)
+#define REG_FPGA_HW_ID                 (5 * REG_WIDTH)
+#define REG_FPGA_DDNA                  (6 * REG_WIDTH)
+#define REG_CPLD_CONFIG                        (7 * REG_WIDTH)
+#define REG_INTERRUPT_MASK             (8 * REG_WIDTH)
+#define REG_INTERRUPT_ACTIVE           (9 * REG_WIDTH)
+#define REG_PCIE_ERROR_COUNT           (10 * REG_WIDTH)
 
-#define KP2000_MAGIC_VALUE      0x196C61482231894D
+#define KP2000_MAGIC_VALUE             0x196C61482231894DULL
 
-#define PCI_VENDOR_ID_DAKTRONICS    0x1c33
-#define PCI_DEVICE_ID_DAKTRONICS    0x6021
+#define PCI_VENDOR_ID_DAKTRONICS       0x1c33
+#define PCI_DEVICE_ID_DAKTRONICS       0x6021
 
-#define DMA_BAR     0
-#define REG_BAR     1
+#define DMA_BAR                                0
+#define REG_BAR                                1
 
 struct kp2000_device {
-    struct pci_dev     *pdev;
-    struct miscdevice   miscdev;
-    char                name[16];
-    
-    unsigned int        card_num;
-    struct mutex        sem;
-    
-    void __iomem       *sysinfo_regs_base;
-    void __iomem       *regs_bar_base;
-    struct resource     regs_base_resource;
-    void __iomem       *dma_bar_base;
-    void __iomem       *dma_common_regs;
-    struct resource     dma_base_resource;
-    
-    // "System Registers"
-    u32                 card_id;
-    u32                 build_version;
-    u32                 build_datestamp;
-    u32                 build_timestamp;
-    u32                 core_table_offset;
-    u32                 core_table_length;
-    u8                  core_table_rev;
-    u8                  hardware_revision;
-    u64                 ssid;
-    u64                 ddna;
-    
-    // IRQ stuff
-    unsigned int        irq;
-    
-    struct list_head    uio_devices_list;
+       struct pci_dev          *pdev;
+       char                    name[16];
+
+       unsigned int            card_num;
+       struct mutex            sem;
+
+       void __iomem            *sysinfo_regs_base;
+       void __iomem            *regs_bar_base;
+       struct resource         regs_base_resource;
+       void __iomem            *dma_bar_base;
+       void __iomem            *dma_common_regs;
+       struct resource         dma_base_resource;
+
+       // "System Registers"
+       u32                     card_id;
+       u32                     build_version;
+       u32                     build_datestamp;
+       u32                     build_timestamp;
+       u32                     core_table_offset;
+       u32                     core_table_length;
+       u8                      core_table_rev;
+       u8                      hardware_revision;
+       u64                     ssid;
+       u64                     ddna;
+
+       // IRQ stuff
+       unsigned int            irq;
+
+       struct list_head        uio_devices_list;
 };
 
 extern struct class *kpc_uio_class;
 extern struct attribute *kpc_uio_class_attrs[];
 
-int   kp2000_pcie_probe(struct pci_dev *dev, const struct pci_device_id *id);
-void  kp2000_pcie_remove(struct pci_dev *pdev);
-int   kp2000_probe_cores(struct kp2000_device *pcard);
-void  kp2000_remove_cores(struct kp2000_device *pcard);
-
-extern struct file_operations  kp2000_fops;
-
+int kp2000_probe_cores(struct kp2000_device *pcard);
+void kp2000_remove_cores(struct kp2000_device *pcard);
 
 // Define this quick little macro because the expression is used frequently
-#define PCARD_TO_DEV(pcard)  (&(pcard->pdev->dev))
-
-static inline void
-lock_card(struct kp2000_device *pcard)
-{
-    BUG_ON(pcard == NULL);
-    mutex_lock(&pcard->sem);
-}
-static inline void
-unlock_card(struct kp2000_device *pcard)
-{
-    BUG_ON(pcard == NULL);
-    mutex_unlock(&pcard->sem);
-}
-
+#define PCARD_TO_DEV(pcard)    (&(pcard->pdev->dev))
 
 #endif /* KP2000_PCIE_H */
index ef8008b..16f37f0 100644 (file)
@@ -5,18 +5,18 @@
 #include <linux/ioctl.h>
 
 struct kp2000_regs {
-    __u32 card_id;
-    __u32 build_version;
-    __u32 build_datestamp;
-    __u32 build_timestamp;
-    __u32 hw_rev;
-    __u64 ssid;
-    __u64 ddna;
-    __u64 cpld_reg;
+       __u32 card_id;
+       __u32 build_version;
+       __u32 build_datestamp;
+       __u32 build_timestamp;
+       __u32 hw_rev;
+       __u64 ssid;
+       __u64 ddna;
+       __u64 cpld_reg;
 };
 
-#define KP2000_IOCTL_GET_CPLD_REG               _IOR('k', 9, __u32)
-#define KP2000_IOCTL_GET_PCIE_ERROR_REG         _IOR('k', 11, __u32)
-#define KP2000_IOCTL_GET_EVERYTHING             _IOR('k', 8, struct kp2000_regs*)
+#define KP2000_IOCTL_GET_CPLD_REG              _IOR('k', 9, __u32)
+#define KP2000_IOCTL_GET_PCIE_ERROR_REG                _IOR('k', 11, __u32)
+#define KP2000_IOCTL_GET_EVERYTHING            _IOR('k', 8, struct kp2000_regs*)
 
 #endif /* KP2000_CDEV_UAPI_H_ */
diff --git a/drivers/staging/kpc2000/kpc2000_i2c.c b/drivers/staging/kpc2000/kpc2000_i2c.c
new file mode 100644 (file)
index 0000000..b108da4
--- /dev/null
@@ -0,0 +1,651 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * KPC2000 i2c driver
+ *
+ * Adapted i2c-i801.c for use with Kadoka hardware.
+ *
+ * Copyright (C) 1998 - 2002
+ *     Frodo Looijaard <frodol@dds.nl>,
+ *     Philip Edelbrock <phil@netroedge.com>,
+ *     Mark D. Studebaker <mdsxyz123@yahoo.com>
+ * Copyright (C) 2007 - 2012
+ *     Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2010 Intel Corporation
+ *     David Woodhouse <dwmw2@infradead.org>
+ * Copyright (C) 2014-2018 Daktronics
+ *     Matt Sickler <matt.sickler@daktronics.com>,
+ *     Jordon Hofer <jordon.hofer@daktronics.com>
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include "kpc.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Matt.Sickler@Daktronics.com");
+
+struct i2c_device {
+       unsigned long           smba;
+       struct i2c_adapter      adapter;
+       unsigned int            features;
+};
+
+/*****************************
+ *** Part 1 - i2c Handlers ***
+ *****************************/
+
+#define REG_SIZE 8
+
+/* I801 SMBus address offsets */
+#define SMBHSTSTS(p)    ((0  * REG_SIZE) + (p)->smba)
+#define SMBHSTCNT(p)    ((2  * REG_SIZE) + (p)->smba)
+#define SMBHSTCMD(p)    ((3  * REG_SIZE) + (p)->smba)
+#define SMBHSTADD(p)    ((4  * REG_SIZE) + (p)->smba)
+#define SMBHSTDAT0(p)   ((5  * REG_SIZE) + (p)->smba)
+#define SMBHSTDAT1(p)   ((6  * REG_SIZE) + (p)->smba)
+#define SMBBLKDAT(p)    ((7  * REG_SIZE) + (p)->smba)
+#define SMBPEC(p)       ((8  * REG_SIZE) + (p)->smba)   /* ICH3 and later */
+#define SMBAUXSTS(p)    ((12 * REG_SIZE) + (p)->smba)   /* ICH4 and later */
+#define SMBAUXCTL(p)    ((13 * REG_SIZE) + (p)->smba)   /* ICH4 and later */
+
+/* PCI Address Constants */
+#define SMBBAR      4
+#define SMBHSTCFG   0x040
+
+/* Host configuration bits for SMBHSTCFG */
+#define SMBHSTCFG_HST_EN        1
+#define SMBHSTCFG_SMB_SMI_EN    2
+#define SMBHSTCFG_I2C_EN        4
+
+/* Auxiliary control register bits, ICH4+ only */
+#define SMBAUXCTL_CRC       1
+#define SMBAUXCTL_E32B      2
+
+/* kill bit for SMBHSTCNT */
+#define SMBHSTCNT_KILL      2
+
+/* Other settings */
+#define MAX_RETRIES         400
+#define ENABLE_INT9         0       /* set to 0x01 to enable - untested */
+
+/* I801 command constants */
+#define I801_QUICK              0x00
+#define I801_BYTE               0x04
+#define I801_BYTE_DATA          0x08
+#define I801_WORD_DATA          0x0C
+#define I801_PROC_CALL          0x10    /* unimplemented */
+#define I801_BLOCK_DATA         0x14
+#define I801_I2C_BLOCK_DATA     0x18    /* ICH5 and later */
+#define I801_BLOCK_LAST         0x34
+#define I801_I2C_BLOCK_LAST     0x38    /* ICH5 and later */
+#define I801_START              0x40
+#define I801_PEC_EN             0x80    /* ICH3 and later */
+
+/* I801 Hosts Status register bits */
+#define SMBHSTSTS_BYTE_DONE     0x80
+#define SMBHSTSTS_INUSE_STS     0x40
+#define SMBHSTSTS_SMBALERT_STS  0x20
+#define SMBHSTSTS_FAILED        0x10
+#define SMBHSTSTS_BUS_ERR       0x08
+#define SMBHSTSTS_DEV_ERR       0x04
+#define SMBHSTSTS_INTR          0x02
+#define SMBHSTSTS_HOST_BUSY     0x01
+
+#define STATUS_FLAGS        (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | SMBHSTSTS_INTR)
+
+/* Older devices have their ID defined in <linux/pci_ids.h> */
+#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS       0x1c22
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS          0x1d22
+/* Patsburg also has three 'Integrated Device Function' SMBus controllers */
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0     0x1d70
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1     0x1d71
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2     0x1d72
+#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS      0x1e22
+#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS          0x2330
+#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS     0x3b30
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS         0x8c22
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS      0x9c22
+
+#define FEATURE_SMBUS_PEC       BIT(0)
+#define FEATURE_BLOCK_BUFFER    BIT(1)
+#define FEATURE_BLOCK_PROC      BIT(2)
+#define FEATURE_I2C_BLOCK_READ  BIT(3)
+/* Not really a feature, but it's convenient to handle it as such */
+#define FEATURE_IDF             BIT(15)
+
+// FIXME!
+#undef inb_p
+#define inb_p(a) readq((void *)a)
+#undef outb_p
+#define outb_p(d, a) writeq(d, (void *)a)
+
+/* Make sure the SMBus host is ready to start transmitting.
+ * Return 0 if it is, -EBUSY if it is not.
+ */
+static int i801_check_pre(struct i2c_device *priv)
+{
+       int status;
+
+       status = inb_p(SMBHSTSTS(priv));
+       if (status & SMBHSTSTS_HOST_BUSY) {
+               dev_err(&priv->adapter.dev, "SMBus is busy, can't use it! (status=%x)\n", status);
+               return -EBUSY;
+       }
+
+       status &= STATUS_FLAGS;
+       if (status) {
+               //dev_dbg(&priv->adapter.dev, "Clearing status flags (%02x)\n", status);
+               outb_p(status, SMBHSTSTS(priv));
+               status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
+               if (status) {
+                       dev_err(&priv->adapter.dev, "Failed clearing status flags (%02x)\n", status);
+                       return -EBUSY;
+               }
+       }
+       return 0;
+}
+
+/* Convert the status register to an error code, and clear it. */
+static int i801_check_post(struct i2c_device *priv, int status, int timeout)
+{
+       int result = 0;
+
+       /* If the SMBus is still busy, we give up */
+       if (timeout) {
+               dev_err(&priv->adapter.dev, "Transaction timeout\n");
+               /* try to stop the current command */
+               dev_dbg(&priv->adapter.dev, "Terminating the current operation\n");
+               outb_p(inb_p(SMBHSTCNT(priv)) | SMBHSTCNT_KILL, SMBHSTCNT(priv));
+               usleep_range(1000, 2000);
+               outb_p(inb_p(SMBHSTCNT(priv)) & (~SMBHSTCNT_KILL), SMBHSTCNT(priv));
+
+               /* Check if it worked */
+               status = inb_p(SMBHSTSTS(priv));
+               if ((status & SMBHSTSTS_HOST_BUSY) || !(status & SMBHSTSTS_FAILED))
+                       dev_err(&priv->adapter.dev, "Failed terminating the transaction\n");
+               outb_p(STATUS_FLAGS, SMBHSTSTS(priv));
+               return -ETIMEDOUT;
+       }
+
+       if (status & SMBHSTSTS_FAILED) {
+               result = -EIO;
+               dev_err(&priv->adapter.dev, "Transaction failed\n");
+       }
+       if (status & SMBHSTSTS_DEV_ERR) {
+               result = -ENXIO;
+               dev_dbg(&priv->adapter.dev, "No response\n");
+       }
+       if (status & SMBHSTSTS_BUS_ERR) {
+               result = -EAGAIN;
+               dev_dbg(&priv->adapter.dev, "Lost arbitration\n");
+       }
+
+       if (result) {
+               /* Clear error flags */
+               outb_p(status & STATUS_FLAGS, SMBHSTSTS(priv));
+               status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
+               if (status)
+                       dev_warn(&priv->adapter.dev, "Failed clearing status flags at end of transaction (%02x)\n", status);
+       }
+
+       return result;
+}
+
+static int i801_transaction(struct i2c_device *priv, int xact)
+{
+       int status;
+       int result;
+       int timeout = 0;
+
+       result = i801_check_pre(priv);
+       if (result < 0)
+               return result;
+       /* the current contents of SMBHSTCNT can be overwritten, since PEC,
+        * INTREN, SMBSCMD are passed in xact
+        */
+       outb_p(xact | I801_START, SMBHSTCNT(priv));
+
+       /* We will always wait for a fraction of a second! */
+       do {
+               usleep_range(250, 500);
+               status = inb_p(SMBHSTSTS(priv));
+       } while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_RETRIES));
+
+       result = i801_check_post(priv, status, timeout > MAX_RETRIES);
+       if (result < 0)
+               return result;
+
+       outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
+       return 0;
+}
+
+/* wait for INTR bit as advised by Intel */
+static void i801_wait_hwpec(struct i2c_device *priv)
+{
+       int timeout = 0;
+       int status;
+
+       do {
+               usleep_range(250, 500);
+               status = inb_p(SMBHSTSTS(priv));
+       } while ((!(status & SMBHSTSTS_INTR)) && (timeout++ < MAX_RETRIES));
+
+       if (timeout > MAX_RETRIES)
+               dev_dbg(&priv->adapter.dev, "PEC Timeout!\n");
+
+       outb_p(status, SMBHSTSTS(priv));
+}
+
+static int i801_block_transaction_by_block(struct i2c_device *priv, union i2c_smbus_data *data, char read_write, int hwpec)
+{
+       int i, len;
+       int status;
+
+       inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
+
+       /* Use 32-byte buffer to process this transaction */
+       if (read_write == I2C_SMBUS_WRITE) {
+               len = data->block[0];
+               outb_p(len, SMBHSTDAT0(priv));
+               for (i = 0; i < len; i++)
+                       outb_p(data->block[i + 1], SMBBLKDAT(priv));
+       }
+
+       status = i801_transaction(priv, I801_BLOCK_DATA | ENABLE_INT9 | I801_PEC_EN * hwpec);
+       if (status)
+               return status;
+
+       if (read_write == I2C_SMBUS_READ) {
+               len = inb_p(SMBHSTDAT0(priv));
+               if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
+                       return -EPROTO;
+
+               data->block[0] = len;
+               for (i = 0; i < len; i++)
+                       data->block[i + 1] = inb_p(SMBBLKDAT(priv));
+       }
+       return 0;
+}
+
+static int i801_block_transaction_byte_by_byte(struct i2c_device *priv, union i2c_smbus_data *data, char read_write, int command, int hwpec)
+{
+       int i, len;
+       int smbcmd;
+       int status;
+       int result;
+       int timeout;
+
+       result = i801_check_pre(priv);
+       if (result < 0)
+               return result;
+
+       len = data->block[0];
+
+       if (read_write == I2C_SMBUS_WRITE) {
+               outb_p(len, SMBHSTDAT0(priv));
+               outb_p(data->block[1], SMBBLKDAT(priv));
+       }
+
+       for (i = 1; i <= len; i++) {
+               if (i == len && read_write == I2C_SMBUS_READ) {
+                       if (command == I2C_SMBUS_I2C_BLOCK_DATA)
+                               smbcmd = I801_I2C_BLOCK_LAST;
+                       else
+                               smbcmd = I801_BLOCK_LAST;
+               } else {
+                       if (command == I2C_SMBUS_I2C_BLOCK_DATA && read_write == I2C_SMBUS_READ)
+                               smbcmd = I801_I2C_BLOCK_DATA;
+                       else
+                               smbcmd = I801_BLOCK_DATA;
+               }
+               outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT(priv));
+
+               if (i == 1)
+                       outb_p(inb(SMBHSTCNT(priv)) | I801_START, SMBHSTCNT(priv));
+               /* We will always wait for a fraction of a second! */
+               timeout = 0;
+               do {
+                       usleep_range(250, 500);
+                       status = inb_p(SMBHSTSTS(priv));
+               } while ((!(status & SMBHSTSTS_BYTE_DONE)) && (timeout++ < MAX_RETRIES));
+
+               result = i801_check_post(priv, status, timeout > MAX_RETRIES);
+               if (result < 0)
+                       return result;
+               if (i == 1 && read_write == I2C_SMBUS_READ && command != I2C_SMBUS_I2C_BLOCK_DATA) {
+                       len = inb_p(SMBHSTDAT0(priv));
+                       if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
+                               dev_err(&priv->adapter.dev, "Illegal SMBus block read size %d\n", len);
+                               /* Recover */
+                               while (inb_p(SMBHSTSTS(priv)) & SMBHSTSTS_HOST_BUSY)
+                                       outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
+                               outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
+                               return -EPROTO;
+                       }
+                       data->block[0] = len;
+               }
+
+               /* Retrieve/store value in SMBBLKDAT */
+               if (read_write == I2C_SMBUS_READ)
+                       data->block[i] = inb_p(SMBBLKDAT(priv));
+               if (read_write == I2C_SMBUS_WRITE && i + 1 <= len)
+                       outb_p(data->block[i + 1], SMBBLKDAT(priv));
+               /* signals SMBBLKDAT ready */
+               outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS(priv));
+       }
+
+       return 0;
+}
+
+static int i801_set_block_buffer_mode(struct i2c_device *priv)
+{
+       outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv));
+       if ((inb_p(SMBAUXCTL(priv)) & SMBAUXCTL_E32B) == 0)
+               return -EIO;
+       return 0;
+}
+
+/* Block transaction function */
+static int i801_block_transaction(struct i2c_device *priv, union i2c_smbus_data *data, char read_write, int command, int hwpec)
+{
+       int result = 0;
+       //unsigned char hostc;
+
+       if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
+               if (read_write == I2C_SMBUS_WRITE) {
+                       /* set I2C_EN bit in configuration register */
+                       //TODO: Figure out the right thing to do here...
+                       //pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc);
+                       //pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc | SMBHSTCFG_I2C_EN);
+               } else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) {
+                       dev_err(&priv->adapter.dev, "I2C block read is unsupported!\n");
+                       return -EOPNOTSUPP;
+               }
+       }
+
+       if (read_write == I2C_SMBUS_WRITE || command == I2C_SMBUS_I2C_BLOCK_DATA) {
+               if (data->block[0] < 1)
+                       data->block[0] = 1;
+               if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
+                       data->block[0] = I2C_SMBUS_BLOCK_MAX;
+       } else {
+               data->block[0] = 32;    /* max for SMBus block reads */
+       }
+
+       /* Experience has shown that the block buffer can only be used for
+        * SMBus (not I2C) block transactions, even though the datasheet
+        * doesn't mention this limitation.
+        */
+       if ((priv->features & FEATURE_BLOCK_BUFFER) && command != I2C_SMBUS_I2C_BLOCK_DATA && i801_set_block_buffer_mode(priv) == 0)
+               result = i801_block_transaction_by_block(priv, data, read_write, hwpec);
+       else
+               result = i801_block_transaction_byte_by_byte(priv, data, read_write, command, hwpec);
+       if (result == 0 && hwpec)
+               i801_wait_hwpec(priv);
+       if (command == I2C_SMBUS_I2C_BLOCK_DATA && read_write == I2C_SMBUS_WRITE) {
+               /* restore saved configuration register value */
+               //TODO: Figure out the right thing to do here...
+               //pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc);
+       }
+       return result;
+}
+
+/* Return negative errno on error. */
+static s32 i801_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data)
+{
+       int hwpec;
+       int block = 0;
+       int ret, xact = 0;
+       struct i2c_device *priv = i2c_get_adapdata(adap);
+
+       hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA;
+
+       switch (size) {
+       case I2C_SMBUS_QUICK:
+               dev_dbg(&priv->adapter.dev, "  [acc] SMBUS_QUICK\n");
+               outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv));
+               xact = I801_QUICK;
+               break;
+       case I2C_SMBUS_BYTE:
+               dev_dbg(&priv->adapter.dev, "  [acc] SMBUS_BYTE\n");
+
+               outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv));
+               if (read_write == I2C_SMBUS_WRITE)
+                       outb_p(command, SMBHSTCMD(priv));
+               xact = I801_BYTE;
+               break;
+       case I2C_SMBUS_BYTE_DATA:
+               dev_dbg(&priv->adapter.dev, "  [acc] SMBUS_BYTE_DATA\n");
+               outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv));
+               outb_p(command, SMBHSTCMD(priv));
+               if (read_write == I2C_SMBUS_WRITE)
+                       outb_p(data->byte, SMBHSTDAT0(priv));
+               xact = I801_BYTE_DATA;
+               break;
+       case I2C_SMBUS_WORD_DATA:
+               dev_dbg(&priv->adapter.dev, "  [acc] SMBUS_WORD_DATA\n");
+               outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv));
+               outb_p(command, SMBHSTCMD(priv));
+               if (read_write == I2C_SMBUS_WRITE) {
+                       outb_p(data->word & 0xff, SMBHSTDAT0(priv));
+                       outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
+               }
+               xact = I801_WORD_DATA;
+               break;
+       case I2C_SMBUS_BLOCK_DATA:
+               dev_dbg(&priv->adapter.dev, "  [acc] SMBUS_BLOCK_DATA\n");
+               outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv));
+               outb_p(command, SMBHSTCMD(priv));
+               block = 1;
+               break;
+       case I2C_SMBUS_I2C_BLOCK_DATA:
+               dev_dbg(&priv->adapter.dev, "  [acc] SMBUS_I2C_BLOCK_DATA\n");
+               /* NB: page 240 of ICH5 datasheet shows that the R/#W
+                * bit should be cleared here, even when reading
+                */
+               outb_p((addr & 0x7f) << 1, SMBHSTADD(priv));
+               if (read_write == I2C_SMBUS_READ) {
+                       /* NB: page 240 of ICH5 datasheet also shows
+                        * that DATA1 is the cmd field when reading
+                        */
+                       outb_p(command, SMBHSTDAT1(priv));
+               } else {
+                       outb_p(command, SMBHSTCMD(priv));
+               }
+               block = 1;
+               break;
+       default:
+               dev_dbg(&priv->adapter.dev, "  [acc] Unsupported transaction %d\n", size);
+               return -EOPNOTSUPP;
+       }
+
+       if (hwpec) { /* enable/disable hardware PEC */
+               dev_dbg(&priv->adapter.dev, "  [acc] hwpec: yes\n");
+               outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv));
+       } else {
+               dev_dbg(&priv->adapter.dev, "  [acc] hwpec: no\n");
+               outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC), SMBAUXCTL(priv));
+       }
+
+       if (block) {
+               //ret = 0;
+               dev_dbg(&priv->adapter.dev, "  [acc] block: yes\n");
+               ret = i801_block_transaction(priv, data, read_write, size, hwpec);
+       } else {
+               dev_dbg(&priv->adapter.dev, "  [acc] block: no\n");
+               ret = i801_transaction(priv, xact | ENABLE_INT9);
+       }
+
+       /* Some BIOSes don't like it when PEC is enabled at reboot or resume
+        * time, so we forcibly disable it after every transaction. Turn off
+        * E32B for the same reason.
+        */
+       if (hwpec || block) {
+               dev_dbg(&priv->adapter.dev, "  [acc] hwpec || block\n");
+               outb_p(inb_p(SMBAUXCTL(priv)) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
+       }
+       if (block) {
+               dev_dbg(&priv->adapter.dev, "  [acc] block\n");
+               return ret;
+       }
+       if (ret) {
+               dev_dbg(&priv->adapter.dev, "  [acc] ret %d\n", ret);
+               return ret;
+       }
+       if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK)) {
+               dev_dbg(&priv->adapter.dev, "  [acc] I2C_SMBUS_WRITE || I801_QUICK  -> ret 0\n");
+               return 0;
+       }
+
+       switch (xact & 0x7f) {
+       case I801_BYTE:  /* Result put in SMBHSTDAT0 */
+       case I801_BYTE_DATA:
+               dev_dbg(&priv->adapter.dev, "  [acc] I801_BYTE or I801_BYTE_DATA\n");
+               data->byte = inb_p(SMBHSTDAT0(priv));
+               break;
+       case I801_WORD_DATA:
+               dev_dbg(&priv->adapter.dev, "  [acc] I801_WORD_DATA\n");
+               data->word = inb_p(SMBHSTDAT0(priv)) + (inb_p(SMBHSTDAT1(priv)) << 8);
+               break;
+       }
+       return 0;
+}
+
+static u32 i801_func(struct i2c_adapter *adapter)
+{
+       struct i2c_device *priv = i2c_get_adapdata(adapter);
+
+       /* original settings
+        * u32 f = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+        * I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+        * I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
+        * ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
+        * ((priv->features & FEATURE_I2C_BLOCK_READ) ?
+        * I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0);
+        */
+
+       // http://lxr.free-electrons.com/source/include/uapi/linux/i2c.h#L85
+
+       u32 f =
+               I2C_FUNC_I2C                     | /* 0x00000001 (I enabled this one) */
+               !I2C_FUNC_10BIT_ADDR             | /* 0x00000002 */
+               !I2C_FUNC_PROTOCOL_MANGLING      | /* 0x00000004 */
+               ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | /* 0x00000008 */
+               !I2C_FUNC_SMBUS_BLOCK_PROC_CALL  | /* 0x00008000 */
+               I2C_FUNC_SMBUS_QUICK             | /* 0x00010000 */
+               !I2C_FUNC_SMBUS_READ_BYTE        | /* 0x00020000 */
+               !I2C_FUNC_SMBUS_WRITE_BYTE       | /* 0x00040000 */
+               !I2C_FUNC_SMBUS_READ_BYTE_DATA   | /* 0x00080000 */
+               !I2C_FUNC_SMBUS_WRITE_BYTE_DATA  | /* 0x00100000 */
+               !I2C_FUNC_SMBUS_READ_WORD_DATA   | /* 0x00200000 */
+               !I2C_FUNC_SMBUS_WRITE_WORD_DATA  | /* 0x00400000 */
+               !I2C_FUNC_SMBUS_PROC_CALL        | /* 0x00800000 */
+               !I2C_FUNC_SMBUS_READ_BLOCK_DATA  | /* 0x01000000 */
+               !I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | /* 0x02000000 */
+               ((priv->features & FEATURE_I2C_BLOCK_READ) ? I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0) | /* 0x04000000 */
+               I2C_FUNC_SMBUS_WRITE_I2C_BLOCK   | /* 0x08000000 */
+
+               I2C_FUNC_SMBUS_BYTE              | /* _READ_BYTE  _WRITE_BYTE */
+               I2C_FUNC_SMBUS_BYTE_DATA         | /* _READ_BYTE_DATA  _WRITE_BYTE_DATA */
+               I2C_FUNC_SMBUS_WORD_DATA         | /* _READ_WORD_DATA  _WRITE_WORD_DATA */
+               I2C_FUNC_SMBUS_BLOCK_DATA        | /* _READ_BLOCK_DATA  _WRITE_BLOCK_DATA */
+               !I2C_FUNC_SMBUS_I2C_BLOCK        | /* _READ_I2C_BLOCK  _WRITE_I2C_BLOCK */
+               !I2C_FUNC_SMBUS_EMUL;              /* _QUICK  _BYTE  _BYTE_DATA  _WORD_DATA  _PROC_CALL  _WRITE_BLOCK_DATA  _I2C_BLOCK _PEC */
+       return f;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+       .smbus_xfer     = i801_access,
+       .functionality  = i801_func,
+};
+
+/********************************
+ *** Part 2 - Driver Handlers ***
+ ********************************/
+static int pi2c_probe(struct platform_device *pldev)
+{
+       int err;
+       struct i2c_device *priv;
+       struct resource *res;
+
+       priv = devm_kzalloc(&pldev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       i2c_set_adapdata(&priv->adapter, priv);
+       priv->adapter.owner = THIS_MODULE;
+       priv->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+       priv->adapter.algo = &smbus_algorithm;
+
+       res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENXIO;
+
+       priv->smba = (unsigned long)devm_ioremap_nocache(&pldev->dev,
+                                                        res->start,
+                                                        resource_size(res));
+       if (!priv->smba)
+               return -ENOMEM;
+
+       platform_set_drvdata(pldev, priv);
+
+       priv->features |= FEATURE_IDF;
+       priv->features |= FEATURE_I2C_BLOCK_READ;
+       priv->features |= FEATURE_SMBUS_PEC;
+       priv->features |= FEATURE_BLOCK_BUFFER;
+
+       //init_MUTEX(&lddata->sem);
+
+       /* set up the sysfs linkage to our parent device */
+       priv->adapter.dev.parent = &pldev->dev;
+
+       /* Retry up to 3 times on lost arbitration */
+       priv->adapter.retries = 3;
+
+       //snprintf(priv->adapter.name, sizeof(priv->adapter.name), "Fake SMBus I801 adapter at %04lx", priv->smba);
+       snprintf(priv->adapter.name, sizeof(priv->adapter.name), "Fake SMBus I801 adapter");
+
+       err = i2c_add_adapter(&priv->adapter);
+       if (err) {
+               dev_err(&priv->adapter.dev, "Failed to add SMBus adapter\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static int pi2c_remove(struct platform_device *pldev)
+{
+       struct i2c_device *lddev;
+
+       lddev = (struct i2c_device *)platform_get_drvdata(pldev);
+
+       i2c_del_adapter(&lddev->adapter);
+
+       //TODO: Figure out the right thing to do here...
+       //pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
+       //pci_release_region(dev, SMBBAR);
+       //pci_set_drvdata(dev, NULL);
+
+       //cdev_del(&lddev->cdev);
+
+       return 0;
+}
+
+static struct platform_driver i2c_plat_driver_i = {
+       .probe      = pi2c_probe,
+       .remove     = pi2c_remove,
+       .driver     = {
+               .name   = KP_DRIVER_NAME_I2C,
+       },
+};
+
+module_platform_driver(i2c_plat_driver_i);
diff --git a/drivers/staging/kpc2000/kpc2000_spi.c b/drivers/staging/kpc2000/kpc2000_spi.c
new file mode 100644 (file)
index 0000000..35ac1d7
--- /dev/null
@@ -0,0 +1,520 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * KP2000 SPI controller driver
+ *
+ * Copyright (C) 2014-2018 Daktronics
+ * Author: Matt Sickler <matt.sickler@daktronics.com>
+ * Very loosely based on spi-omap2-mcspi.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/gcd.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/mtd/partitions.h>
+
+#include "kpc.h"
+
+static struct mtd_partition p2kr0_spi0_parts[] = {
+       { .name = "SLOT_0",     .size = 7798784,                .offset = 0,                },
+       { .name = "SLOT_1",     .size = 7798784,                .offset = MTDPART_OFS_NXTBLK},
+       { .name = "SLOT_2",     .size = 7798784,                .offset = MTDPART_OFS_NXTBLK},
+       { .name = "SLOT_3",     .size = 7798784,                .offset = MTDPART_OFS_NXTBLK},
+       { .name = "CS0_EXTRA",  .size = MTDPART_SIZ_FULL,       .offset = MTDPART_OFS_NXTBLK},
+};
+
+static struct mtd_partition p2kr0_spi1_parts[] = {
+       { .name = "SLOT_4",     .size = 7798784,                .offset = 0,                },
+       { .name = "SLOT_5",     .size = 7798784,                .offset = MTDPART_OFS_NXTBLK},
+       { .name = "SLOT_6",     .size = 7798784,                .offset = MTDPART_OFS_NXTBLK},
+       { .name = "SLOT_7",     .size = 7798784,                .offset = MTDPART_OFS_NXTBLK},
+       { .name = "CS1_EXTRA",  .size = MTDPART_SIZ_FULL,       .offset = MTDPART_OFS_NXTBLK},
+};
+
+static struct flash_platform_data p2kr0_spi0_pdata = {
+       .name =         "SPI0",
+       .nr_parts =     ARRAY_SIZE(p2kr0_spi0_parts),
+       .parts =        p2kr0_spi0_parts,
+};
+static struct flash_platform_data p2kr0_spi1_pdata = {
+       .name =         "SPI1",
+       .nr_parts =     ARRAY_SIZE(p2kr0_spi1_parts),
+       .parts =        p2kr0_spi1_parts,
+};
+
+static struct spi_board_info p2kr0_board_info[] = {
+       {
+               .modalias =             "n25q256a11",
+               .bus_num =              1,
+               .chip_select =          0,
+               .mode =                 SPI_MODE_0,
+               .platform_data =        &p2kr0_spi0_pdata
+       },
+       {
+               .modalias =             "n25q256a11",
+               .bus_num =              1,
+               .chip_select =          1,
+               .mode =                 SPI_MODE_0,
+               .platform_data =        &p2kr0_spi1_pdata
+       },
+};
+
+/***************
+ * SPI Defines *
+ ***************/
+#define KP_SPI_REG_CONFIG 0x0 /* 0x00 */
+#define KP_SPI_REG_STATUS 0x1 /* 0x08 */
+#define KP_SPI_REG_FFCTRL 0x2 /* 0x10 */
+#define KP_SPI_REG_TXDATA 0x3 /* 0x18 */
+#define KP_SPI_REG_RXDATA 0x4 /* 0x20 */
+
+#define KP_SPI_CLK           48000000
+#define KP_SPI_MAX_FIFODEPTH 64
+#define KP_SPI_MAX_FIFOWCNT  0xFFFF
+
+#define KP_SPI_REG_CONFIG_TRM_TXRX 0
+#define KP_SPI_REG_CONFIG_TRM_RX   1
+#define KP_SPI_REG_CONFIG_TRM_TX   2
+
+#define KP_SPI_REG_STATUS_RXS   0x01
+#define KP_SPI_REG_STATUS_TXS   0x02
+#define KP_SPI_REG_STATUS_EOT   0x04
+#define KP_SPI_REG_STATUS_TXFFE 0x10
+#define KP_SPI_REG_STATUS_TXFFF 0x20
+#define KP_SPI_REG_STATUS_RXFFE 0x40
+#define KP_SPI_REG_STATUS_RXFFF 0x80
+
+/******************
+ * SPI Structures *
+ ******************/
+struct kp_spi {
+       struct spi_master  *master;
+       u64 __iomem        *base;
+       struct device      *dev;
+};
+
+struct kp_spi_controller_state {
+       void __iomem   *base;
+       s64             conf_cache;
+};
+
+union kp_spi_config {
+       /* use this to access individual elements */
+       struct __packed spi_config_bitfield {
+               unsigned int pha       : 1; /* spim_clk Phase      */
+               unsigned int pol       : 1; /* spim_clk Polarity   */
+               unsigned int epol      : 1; /* spim_csx Polarity   */
+               unsigned int dpe       : 1; /* Transmission Enable */
+               unsigned int wl        : 5; /* Word Length         */
+               unsigned int           : 3;
+               unsigned int trm       : 2; /* TxRx Mode           */
+               unsigned int cs        : 4; /* Chip Select         */
+               unsigned int wcnt      : 7; /* Word Count          */
+               unsigned int ffen      : 1; /* FIFO Enable         */
+               unsigned int spi_en    : 1; /* SPI Enable          */
+               unsigned int           : 5;
+       } bitfield;
+       /* use this to grab the whole register */
+       u32 reg;
+};
+
+union kp_spi_status {
+       struct __packed spi_status_bitfield {
+               unsigned int rx    :  1; /* Rx Status       */
+               unsigned int tx    :  1; /* Tx Status       */
+               unsigned int eo    :  1; /* End of Transfer */
+               unsigned int       :  1;
+               unsigned int txffe :  1; /* Tx FIFO Empty   */
+               unsigned int txfff :  1; /* Tx FIFO Full    */
+               unsigned int rxffe :  1; /* Rx FIFO Empty   */
+               unsigned int rxfff :  1; /* Rx FIFO Full    */
+               unsigned int       : 24;
+       } bitfield;
+       u32 reg;
+};
+
+union kp_spi_ffctrl {
+       struct __packed spi_ffctrl_bitfield {
+               unsigned int ffstart :  1; /* FIFO Start */
+               unsigned int         : 31;
+       } bitfield;
+       u32 reg;
+};
+
+/***************
+ * SPI Helpers *
+ ***************/
+       static inline u64
+kp_spi_read_reg(struct kp_spi_controller_state *cs, int idx)
+{
+       u64 __iomem *addr = cs->base;
+       u64 val;
+
+       addr += idx;
+       if ((idx == KP_SPI_REG_CONFIG) && (cs->conf_cache >= 0))
+               return cs->conf_cache;
+
+       val = readq(addr);
+       return val;
+}
+
+       static inline void
+kp_spi_write_reg(struct kp_spi_controller_state *cs, int idx, u64 val)
+{
+       u64 __iomem *addr = cs->base;
+
+       addr += idx;
+       writeq(val, addr);
+       if (idx == KP_SPI_REG_CONFIG)
+               cs->conf_cache = val;
+}
+
+       static int
+kp_spi_wait_for_reg_bit(struct kp_spi_controller_state *cs, int idx,
+                       unsigned long bit)
+{
+       unsigned long timeout;
+
+       timeout = jiffies + msecs_to_jiffies(1000);
+       while (!(kp_spi_read_reg(cs, idx) & bit)) {
+               if (time_after(jiffies, timeout)) {
+                       if (!(kp_spi_read_reg(cs, idx) & bit))
+                               return -ETIMEDOUT;
+                       else
+                               return 0;
+               }
+               cpu_relax();
+       }
+       return 0;
+}
+
+       static unsigned
+kp_spi_txrx_pio(struct spi_device *spidev, struct spi_transfer *transfer)
+{
+       struct kp_spi_controller_state *cs = spidev->controller_state;
+       unsigned int count = transfer->len;
+       unsigned int c = count;
+
+       int i;
+       int res;
+       u8 *rx       = transfer->rx_buf;
+       const u8 *tx = transfer->tx_buf;
+       int processed = 0;
+
+       if (tx) {
+               for (i = 0 ; i < c ; i++) {
+                       char val = *tx++;
+
+                       res = kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS,
+                                                     KP_SPI_REG_STATUS_TXS);
+                       if (res < 0)
+                               goto out;
+
+                       kp_spi_write_reg(cs, KP_SPI_REG_TXDATA, val);
+                       processed++;
+               }
+       }
+       else if (rx) {
+               for (i = 0 ; i < c ; i++) {
+                       char test = 0;
+
+                       kp_spi_write_reg(cs, KP_SPI_REG_TXDATA, 0x00);
+                       res = kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS,
+                                                     KP_SPI_REG_STATUS_RXS);
+                       if (res < 0)
+                               goto out;
+
+                       test = kp_spi_read_reg(cs, KP_SPI_REG_RXDATA);
+                       *rx++ = test;
+                       processed++;
+               }
+       }
+
+       if (kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS,
+                                   KP_SPI_REG_STATUS_EOT) < 0) {
+               //TODO: Figure out how to abort transaction??
+               //Ths has never happened in practice though...
+       }
+
+out:
+       return processed;
+}
+
+/*****************
+ * SPI Functions *
+ *****************/
+       static int
+kp_spi_setup(struct spi_device *spidev)
+{
+       union kp_spi_config sc;
+       struct kp_spi *kpspi = spi_master_get_devdata(spidev->master);
+       struct kp_spi_controller_state *cs;
+
+       /* setup controller state */
+       cs = spidev->controller_state;
+       if (!cs) {
+               cs = kzalloc(sizeof(*cs), GFP_KERNEL);
+               if (!cs)
+                       return -ENOMEM;
+               cs->base = kpspi->base;
+               cs->conf_cache = -1;
+               spidev->controller_state = cs;
+       }
+
+       /* set config register */
+       sc.bitfield.wl = spidev->bits_per_word - 1;
+       sc.bitfield.cs = spidev->chip_select;
+       sc.bitfield.spi_en = 0;
+       sc.bitfield.trm = 0;
+       sc.bitfield.ffen = 0;
+       kp_spi_write_reg(spidev->controller_state, KP_SPI_REG_CONFIG, sc.reg);
+       return 0;
+}
+
+       static int
+kp_spi_transfer_one_message(struct spi_master *master, struct spi_message *m)
+{
+       struct kp_spi_controller_state *cs;
+       struct spi_device   *spidev;
+       struct kp_spi       *kpspi;
+       struct spi_transfer *transfer;
+       union kp_spi_config sc;
+       int status = 0;
+
+       spidev = m->spi;
+       kpspi = spi_master_get_devdata(master);
+       m->actual_length = 0;
+       m->status = 0;
+
+       cs = spidev->controller_state;
+
+       /* reject invalid messages and transfers */
+       if (list_empty(&m->transfers))
+               return -EINVAL;
+
+       /* validate input */
+       list_for_each_entry(transfer, &m->transfers, transfer_list) {
+               const void *tx_buf = transfer->tx_buf;
+               void       *rx_buf = transfer->rx_buf;
+               unsigned int len = transfer->len;
+
+               if (transfer->speed_hz > KP_SPI_CLK ||
+                   (len && !(rx_buf || tx_buf))) {
+                       dev_dbg(kpspi->dev, "  transfer: %d Hz, %d %s%s, %d bpw\n",
+                                       transfer->speed_hz,
+                                       len,
+                                       tx_buf ? "tx" : "",
+                                       rx_buf ? "rx" : "",
+                                       transfer->bits_per_word);
+                       dev_dbg(kpspi->dev, "  transfer -EINVAL\n");
+                       return -EINVAL;
+               }
+               if (transfer->speed_hz &&
+                   transfer->speed_hz < (KP_SPI_CLK >> 15)) {
+                       dev_dbg(kpspi->dev, "speed_hz %d below minimum %d Hz\n",
+                                       transfer->speed_hz,
+                                       KP_SPI_CLK >> 15);
+                       dev_dbg(kpspi->dev, "  speed_hz -EINVAL\n");
+                       return -EINVAL;
+               }
+       }
+
+       /* assert chip select to start the sequence*/
+       sc.reg = kp_spi_read_reg(cs, KP_SPI_REG_CONFIG);
+       sc.bitfield.spi_en = 1;
+       kp_spi_write_reg(cs, KP_SPI_REG_CONFIG, sc.reg);
+
+       /* work */
+       if (kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS,
+                                   KP_SPI_REG_STATUS_EOT) < 0) {
+               dev_info(kpspi->dev, "EOT timed out\n");
+               goto out;
+       }
+
+       /* do the transfers for this message */
+       list_for_each_entry(transfer, &m->transfers, transfer_list) {
+               if (!transfer->tx_buf && !transfer->rx_buf &&
+                   transfer->len) {
+                       status = -EINVAL;
+                       goto error;
+               }
+
+               /* transfer */
+               if (transfer->len) {
+                       unsigned int word_len = spidev->bits_per_word;
+                       unsigned int count;
+
+                       /* set up the transfer... */
+                       sc.reg = kp_spi_read_reg(cs, KP_SPI_REG_CONFIG);
+
+                       /* ...direction */
+                       if (transfer->tx_buf)
+                               sc.bitfield.trm = KP_SPI_REG_CONFIG_TRM_TX;
+                       else if (transfer->rx_buf)
+                               sc.bitfield.trm = KP_SPI_REG_CONFIG_TRM_RX;
+
+                       /* ...word length */
+                       if (transfer->bits_per_word)
+                               word_len = transfer->bits_per_word;
+                       sc.bitfield.wl = word_len - 1;
+
+                       /* ...chip select */
+                       sc.bitfield.cs = spidev->chip_select;
+
+                       /* ...and write the new settings */
+                       kp_spi_write_reg(cs, KP_SPI_REG_CONFIG, sc.reg);
+
+                       /* do the transfer */
+                       count = kp_spi_txrx_pio(spidev, transfer);
+                       m->actual_length += count;
+
+                       if (count != transfer->len) {
+                               status = -EIO;
+                               goto error;
+                       }
+               }
+
+               if (transfer->delay_usecs)
+                       udelay(transfer->delay_usecs);
+       }
+
+       /* de-assert chip select to end the sequence */
+       sc.reg = kp_spi_read_reg(cs, KP_SPI_REG_CONFIG);
+       sc.bitfield.spi_en = 0;
+       kp_spi_write_reg(cs, KP_SPI_REG_CONFIG, sc.reg);
+
+out:
+       /* done work */
+       spi_finalize_current_message(master);
+       return 0;
+
+error:
+       m->status = status;
+       return status;
+}
+
+       static void
+kp_spi_cleanup(struct spi_device *spidev)
+{
+       struct kp_spi_controller_state *cs = spidev->controller_state;
+
+       if (cs)
+               kfree(cs);
+}
+
+/******************
+ * Probe / Remove *
+ ******************/
+       static int
+kp_spi_probe(struct platform_device *pldev)
+{
+       struct kpc_core_device_platdata *drvdata;
+       struct spi_master *master;
+       struct kp_spi *kpspi;
+       struct resource *r;
+       int status = 0;
+       int i;
+
+       drvdata = pldev->dev.platform_data;
+       if (!drvdata) {
+               dev_err(&pldev->dev, "%s: platform_data is NULL\n", __func__);
+               return -ENODEV;
+       }
+
+       master = spi_alloc_master(&pldev->dev, sizeof(struct kp_spi));
+       if (!master) {
+               dev_err(&pldev->dev, "%s: master allocation failed\n",
+                       __func__);
+               return -ENOMEM;
+       }
+
+       /* set up the spi functions */
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+       master->bits_per_word_mask = (unsigned int)SPI_BPW_RANGE_MASK(4, 32);
+       master->setup = kp_spi_setup;
+       master->transfer_one_message = kp_spi_transfer_one_message;
+       master->cleanup = kp_spi_cleanup;
+
+       platform_set_drvdata(pldev, master);
+
+       kpspi = spi_master_get_devdata(master);
+       kpspi->master = master;
+       kpspi->dev = &pldev->dev;
+
+       master->num_chipselect = 4;
+       if (pldev->id != -1)
+               master->bus_num = pldev->id;
+
+       r = platform_get_resource(pldev, IORESOURCE_MEM, 0);
+       if (!r) {
+               dev_err(&pldev->dev, "%s: Unable to get platform resources\n",
+                       __func__);
+               status = -ENODEV;
+               goto free_master;
+       }
+
+       kpspi->base = devm_ioremap_nocache(&pldev->dev, r->start,
+                                          resource_size(r));
+
+       status = spi_register_master(master);
+       if (status < 0) {
+               dev_err(&pldev->dev, "Unable to register SPI device\n");
+               goto free_master;
+       }
+
+       /* register the slave boards */
+#define NEW_SPI_DEVICE_FROM_BOARD_INFO_TABLE(table) \
+       for (i = 0 ; i < ARRAY_SIZE(table) ; i++) { \
+               spi_new_device(master, &(table[i])); \
+       }
+
+       switch ((drvdata->card_id & 0xFFFF0000) >> 16) {
+       case PCI_DEVICE_ID_DAKTRONICS_KADOKA_P2KR0:
+               NEW_SPI_DEVICE_FROM_BOARD_INFO_TABLE(p2kr0_board_info);
+               break;
+       default:
+               dev_err(&pldev->dev, "Unknown hardware, cant know what partition table to use!\n");
+               goto free_master;
+       }
+
+       return status;
+
+free_master:
+       spi_master_put(master);
+       return status;
+}
+
+       static int
+kp_spi_remove(struct platform_device *pldev)
+{
+       struct spi_master *master = platform_get_drvdata(pldev);
+
+       spi_unregister_master(master);
+       return 0;
+}
+
+static struct platform_driver kp_spi_driver = {
+       .driver = {
+               .name =     KP_DRIVER_NAME_SPI,
+       },
+       .probe =    kp_spi_probe,
+       .remove =   kp_spi_remove,
+};
+
+module_platform_driver(kp_spi_driver);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:kp_spi");
index 6959bac..51a4dd5 100644 (file)
@@ -2,7 +2,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/types.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 static
 irqreturn_t  ndd_irq_handler(int irq, void *dev_id)
 {
-       struct kpc_dma_device *ldev = (struct kpc_dma_device*)dev_id;
-       
+       struct kpc_dma_device *ldev = (struct kpc_dma_device *)dev_id;
+
        if ((GetEngineControl(ldev) & ENG_CTL_IRQ_ACTIVE) || (ldev->desc_completed->MyDMAAddr != GetEngineCompletePtr(ldev)))
                schedule_work(&ldev->irq_work);
-       
+
        return IRQ_HANDLED;
 }
 
@@ -27,217 +27,215 @@ void  ndd_irq_worker(struct work_struct *ws)
 {
        struct kpc_dma_descriptor *cur;
        struct kpc_dma_device *eng = container_of(ws, struct kpc_dma_device, irq_work);
+
        lock_engine(eng);
-       
+
        if (GetEngineCompletePtr(eng) == 0)
                goto out;
-       
+
        if (eng->desc_completed->MyDMAAddr == GetEngineCompletePtr(eng))
                goto out;
-       
+
        cur = eng->desc_completed;
        do {
                cur = cur->Next;
                dev_dbg(&eng->pldev->dev, "Handling completed descriptor %p (acd = %p)\n", cur, cur->acd);
                BUG_ON(cur == eng->desc_next); // Ordering failure.
-               
-               if (cur->DescControlFlags & DMA_DESC_CTL_SOP){
+
+               if (cur->DescControlFlags & DMA_DESC_CTL_SOP) {
                        eng->accumulated_bytes = 0;
                        eng->accumulated_flags = 0;
                }
-               
+
                eng->accumulated_bytes += cur->DescByteCount;
                if (cur->DescStatusFlags & DMA_DESC_STS_ERROR)
                        eng->accumulated_flags |= ACD_FLAG_ENG_ACCUM_ERROR;
-               
+
                if (cur->DescStatusFlags & DMA_DESC_STS_SHORT)
                        eng->accumulated_flags |= ACD_FLAG_ENG_ACCUM_SHORT;
-               
-               if (cur->DescControlFlags & DMA_DESC_CTL_EOP){
+
+               if (cur->DescControlFlags & DMA_DESC_CTL_EOP) {
                        if (cur->acd)
                                transfer_complete_cb(cur->acd, eng->accumulated_bytes, eng->accumulated_flags | ACD_FLAG_DONE);
                }
-               
+
                eng->desc_completed = cur;
        } while (cur->MyDMAAddr != GetEngineCompletePtr(eng));
-       
+
  out:
        SetClearEngineControl(eng, ENG_CTL_IRQ_ACTIVE, 0);
-       
+
        unlock_engine(eng);
 }
 
-
 /**********  DMA Engine Init/Teardown  **********/
 void  start_dma_engine(struct kpc_dma_device *eng)
 {
        eng->desc_next       = eng->desc_pool_first;
        eng->desc_completed  = eng->desc_pool_last;
-       
+
        // Setup the engine pointer registers
        SetEngineNextPtr(eng, eng->desc_pool_first);
        SetEngineSWPtr(eng, eng->desc_pool_first);
        ClearEngineCompletePtr(eng);
-       
+
        WriteEngineControl(eng, ENG_CTL_DMA_ENABLE | ENG_CTL_IRQ_ENABLE);
 }
 
 int  setup_dma_engine(struct kpc_dma_device *eng, u32 desc_cnt)
 {
        u32 caps;
-       struct kpc_dma_descriptor * cur;
-       struct kpc_dma_descriptor * next;
+       struct kpc_dma_descriptor *cur;
+       struct kpc_dma_descriptor *next;
        dma_addr_t next_handle;
        dma_addr_t head_handle;
        unsigned int i;
        int rv;
-       dev_dbg(&eng->pldev->dev, "Setting up DMA engine [%p]\n", eng);
-       
+
        caps = GetEngineCapabilities(eng);
-       
-       if (WARN(!(caps & ENG_CAP_PRESENT), "setup_dma_engine() called for DMA Engine at %p which isn't present in hardware!\n", eng))
+
+       if (WARN(!(caps & ENG_CAP_PRESENT), "%s() called for DMA Engine at %p which isn't present in hardware!\n", __func__, eng))
                return -ENXIO;
-       
-       if (caps & ENG_CAP_DIRECTION){
+
+       if (caps & ENG_CAP_DIRECTION) {
                eng->dir = DMA_FROM_DEVICE;
        } else {
                eng->dir = DMA_TO_DEVICE;
        }
-       
+
        eng->desc_pool_cnt = desc_cnt;
        eng->desc_pool = dma_pool_create("KPC DMA Descriptors", &eng->pldev->dev, sizeof(struct kpc_dma_descriptor), DMA_DESC_ALIGNMENT, 4096);
-       
+
        eng->desc_pool_first = dma_pool_alloc(eng->desc_pool, GFP_KERNEL | GFP_DMA, &head_handle);
-       if (!eng->desc_pool_first){
-               dev_err(&eng->pldev->dev, "setup_dma_engine: couldn't allocate desc_pool_first!\n");
+       if (!eng->desc_pool_first) {
+               dev_err(&eng->pldev->dev, "%s: couldn't allocate desc_pool_first!\n", __func__);
                dma_pool_destroy(eng->desc_pool);
                return -ENOMEM;
        }
-       
+
        eng->desc_pool_first->MyDMAAddr = head_handle;
        clear_desc(eng->desc_pool_first);
-       
+
        cur = eng->desc_pool_first;
-       for (i = 1 ; i < eng->desc_pool_cnt ; i++){
+       for (i = 1 ; i < eng->desc_pool_cnt ; i++) {
                next = dma_pool_alloc(eng->desc_pool, GFP_KERNEL | GFP_DMA, &next_handle);
-               if (next == NULL)
+               if (!next)
                        goto done_alloc;
-               
+
                clear_desc(next);
                next->MyDMAAddr = next_handle;
-               
+
                cur->DescNextDescPtr = next_handle;
                cur->Next = next;
                cur = next;
        }
-       
+
  done_alloc:
        // Link the last descriptor back to the first, so it's a circular linked list
        cur->Next = eng->desc_pool_first;
        cur->DescNextDescPtr = eng->desc_pool_first->MyDMAAddr;
-       
+
        eng->desc_pool_last = cur;
        eng->desc_completed = eng->desc_pool_last;
-       
+
        // Setup work queue
        INIT_WORK(&eng->irq_work, ndd_irq_worker);
-       
+
        // Grab IRQ line
        rv = request_irq(eng->irq, ndd_irq_handler, IRQF_SHARED, KP_DRIVER_NAME_DMA_CONTROLLER, eng);
-       if (rv){
-               dev_err(&eng->pldev->dev, "setup_dma_engine: failed to request_irq: %d\n", rv);
+       if (rv) {
+               dev_err(&eng->pldev->dev, "%s: failed to request_irq: %d\n", __func__, rv);
                return rv;
        }
-       
+
        // Turn on the engine!
        start_dma_engine(eng);
        unlock_engine(eng);
-       
+
        return 0;
 }
 
 void  stop_dma_engine(struct kpc_dma_device *eng)
 {
        unsigned long timeout;
-       dev_dbg(&eng->pldev->dev, "Destroying DMA engine [%p]\n", eng);
-       
+
        // Disable the descriptor engine
        WriteEngineControl(eng, 0);
-       
+
        // Wait for descriptor engine to finish current operaion
        timeout = jiffies + (HZ / 2);
-       while (GetEngineControl(eng) & ENG_CTL_DMA_RUNNING){
-               if (time_after(jiffies, timeout)){
+       while (GetEngineControl(eng) & ENG_CTL_DMA_RUNNING) {
+               if (time_after(jiffies, timeout)) {
                        dev_crit(&eng->pldev->dev, "DMA_RUNNING still asserted!\n");
                        break;
                }
        }
-       
+
        // Request a reset
        WriteEngineControl(eng, ENG_CTL_DMA_RESET_REQUEST);
-       
+
        // Wait for reset request to be processed
        timeout = jiffies + (HZ / 2);
-       while (GetEngineControl(eng) & (ENG_CTL_DMA_RUNNING | ENG_CTL_DMA_RESET_REQUEST)){
-               if (time_after(jiffies, timeout)){
+       while (GetEngineControl(eng) & (ENG_CTL_DMA_RUNNING | ENG_CTL_DMA_RESET_REQUEST)) {
+               if (time_after(jiffies, timeout)) {
                        dev_crit(&eng->pldev->dev, "ENG_CTL_DMA_RESET_REQUEST still asserted!\n");
                        break;
                }
        }
-       
+
        // Request a reset
        WriteEngineControl(eng, ENG_CTL_DMA_RESET);
-       
+
        // And wait for reset to complete
        timeout = jiffies + (HZ / 2);
-       while (GetEngineControl(eng) & ENG_CTL_DMA_RESET){
-               if (time_after(jiffies, timeout)){
+       while (GetEngineControl(eng) & ENG_CTL_DMA_RESET) {
+               if (time_after(jiffies, timeout)) {
                        dev_crit(&eng->pldev->dev, "DMA_RESET still asserted!\n");
                        break;
                }
        }
-       
+
        // Clear any persistent bits just to make sure there is no residue from the reset
        SetClearEngineControl(eng, (ENG_CTL_IRQ_ACTIVE | ENG_CTL_DESC_COMPLETE | ENG_CTL_DESC_ALIGN_ERR | ENG_CTL_DESC_FETCH_ERR | ENG_CTL_SW_ABORT_ERR | ENG_CTL_DESC_CHAIN_END | ENG_CTL_DMA_WAITING_PERSIST), 0);
-       
+
        // Reset performance counters
-       
+
        // Completely disable the engine
        WriteEngineControl(eng, 0);
 }
 
 void  destroy_dma_engine(struct kpc_dma_device *eng)
 {
-       struct kpc_dma_descriptor * cur;
+       struct kpc_dma_descriptor *cur;
        dma_addr_t cur_handle;
        unsigned int i;
-       
+
        stop_dma_engine(eng);
-       
+
        cur = eng->desc_pool_first;
        cur_handle = eng->desc_pool_first->MyDMAAddr;
-       
-       for (i = 0 ; i < eng->desc_pool_cnt ; i++){
+
+       for (i = 0 ; i < eng->desc_pool_cnt ; i++) {
                struct kpc_dma_descriptor *next = cur->Next;
                dma_addr_t next_handle = cur->DescNextDescPtr;
+
                dma_pool_free(eng->desc_pool, cur, cur_handle);
                cur_handle = next_handle;
                cur = next;
        }
-       
+
        dma_pool_destroy(eng->desc_pool);
-       
+
        free_irq(eng->irq, eng);
 }
 
-
-
 /**********  Helper Functions  **********/
 int  count_descriptors_available(struct kpc_dma_device *eng)
 {
        u32 count = 0;
        struct kpc_dma_descriptor *cur = eng->desc_next;
-       while (cur != eng->desc_completed){
+
+       while (cur != eng->desc_completed) {
                BUG_ON(cur == NULL);
                count++;
                cur = cur->Next;
@@ -247,7 +245,7 @@ int  count_descriptors_available(struct kpc_dma_device *eng)
 
 void  clear_desc(struct kpc_dma_descriptor *desc)
 {
-       if (desc == NULL)
+       if (!desc)
                return;
        desc->DescByteCount         = 0;
        desc->DescStatusErrorFlags  = 0;
index 6166587..48ca88b 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/types.h>    /* size_t */
 #include <linux/cdev.h>
 #include <linux/uaccess.h>  /* copy_*_user */
-#include <linux/aio.h>      /* aio stuff */
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
 #include "kpc_dma_driver.h"
@@ -21,20 +20,19 @@ unsigned int  count_pages(unsigned long iov_base, size_t iov_len)
 {
        unsigned long first = (iov_base             & PAGE_MASK) >> PAGE_SHIFT;
        unsigned long last  = ((iov_base+iov_len-1) & PAGE_MASK) >> PAGE_SHIFT;
+
        return last - first + 1;
 }
 
 static inline
 unsigned int  count_parts_for_sge(struct scatterlist *sg)
 {
-       unsigned int sg_length = sg_dma_len(sg);
-       sg_length += (0x80000-1);
-       return (sg_length / 0x80000);
+       return DIV_ROUND_UP(sg_dma_len(sg), 0x80000);
 }
 
 /**********  Transfer Helpers  **********/
-static
-int  kpc_dma_transfer(struct dev_private_data *priv, struct kiocb *kcb, unsigned long iov_base, size_t iov_len)
+static int kpc_dma_transfer(struct dev_private_data *priv,
+                           unsigned long iov_base, size_t iov_len)
 {
        unsigned int i = 0;
        long rv = 0;
@@ -50,75 +48,72 @@ int  kpc_dma_transfer(struct dev_private_data *priv, struct kiocb *kcb, unsigned
        u64 card_addr;
        u64 dma_addr;
        u64 user_ctl;
-       
+
        BUG_ON(priv == NULL);
        ldev = priv->ldev;
        BUG_ON(ldev == NULL);
-       
-       dev_dbg(&priv->ldev->pldev->dev, "kpc_dma_transfer(priv = [%p], kcb = [%p], iov_base = [%p], iov_len = %ld) ldev = [%p]\n", priv, kcb, (void*)iov_base, iov_len, ldev);
-       
-       acd = (struct aio_cb_data *) kzalloc(sizeof(struct aio_cb_data), GFP_KERNEL);
-       if (!acd){
+
+       acd = kzalloc(sizeof(*acd), GFP_KERNEL);
+       if (!acd) {
                dev_err(&priv->ldev->pldev->dev, "Couldn't kmalloc space for for the aio data\n");
                return -ENOMEM;
        }
        memset(acd, 0x66, sizeof(struct aio_cb_data));
-       
+
        acd->priv = priv;
        acd->ldev = priv->ldev;
        acd->cpl = &done;
        acd->flags = 0;
-       acd->kcb = kcb;
        acd->len = iov_len;
        acd->page_count = count_pages(iov_base, iov_len);
-       
+
        // Allocate an array of page pointers
        acd->user_pages = kzalloc(sizeof(struct page *) * acd->page_count, GFP_KERNEL);
-       if (!acd->user_pages){
+       if (!acd->user_pages) {
                dev_err(&priv->ldev->pldev->dev, "Couldn't kmalloc space for for the page pointers\n");
                rv = -ENOMEM;
                goto err_alloc_userpages;
        }
-       
+
        // Lock the user buffer pages in memory, and hold on to the page pointers (for the sglist)
        down_read(&current->mm->mmap_sem);      /*  get memory map semaphore */
        rv = get_user_pages(iov_base, acd->page_count, FOLL_TOUCH | FOLL_WRITE | FOLL_GET, acd->user_pages, NULL);
        up_read(&current->mm->mmap_sem);        /*  release the semaphore */
-       if (rv != acd->page_count){
+       if (rv != acd->page_count) {
                dev_err(&priv->ldev->pldev->dev, "Couldn't get_user_pages (%ld)\n", rv);
                goto err_get_user_pages;
        }
-       
+
        // Allocate and setup the sg_table (scatterlist entries)
        rv = sg_alloc_table_from_pages(&acd->sgt, acd->user_pages, acd->page_count, iov_base & (PAGE_SIZE-1), iov_len, GFP_KERNEL);
-       if (rv){
+       if (rv) {
                dev_err(&priv->ldev->pldev->dev, "Couldn't alloc sg_table (%ld)\n", rv);
                goto err_alloc_sg_table;
        }
-       
+
        // Setup the DMA mapping for all the sg entries
        acd->mapped_entry_count = dma_map_sg(&ldev->pldev->dev, acd->sgt.sgl, acd->sgt.nents, ldev->dir);
-       if (acd->mapped_entry_count <= 0){
+       if (acd->mapped_entry_count <= 0) {
                dev_err(&priv->ldev->pldev->dev, "Couldn't dma_map_sg (%d)\n", acd->mapped_entry_count);
                goto err_dma_map_sg;
        }
 
        // Calculate how many descriptors are actually needed for this transfer.
-       for_each_sg(acd->sgt.sgl, sg, acd->mapped_entry_count, i){
+       for_each_sg(acd->sgt.sgl, sg, acd->mapped_entry_count, i) {
                desc_needed += count_parts_for_sge(sg);
        }
-       
+
        lock_engine(ldev);
-       
+
        // Figoure out how many descriptors are available and return an error if there aren't enough
        num_descrs_avail = count_descriptors_available(ldev);
        dev_dbg(&priv->ldev->pldev->dev, "    mapped_entry_count = %d    num_descrs_needed = %d    num_descrs_avail = %d\n", acd->mapped_entry_count, desc_needed, num_descrs_avail);
-       if (desc_needed >= ldev->desc_pool_cnt){
+       if (desc_needed >= ldev->desc_pool_cnt) {
                dev_warn(&priv->ldev->pldev->dev, "    mapped_entry_count = %d    num_descrs_needed = %d    num_descrs_avail = %d    TOO MANY to ever complete!\n", acd->mapped_entry_count, desc_needed, num_descrs_avail);
                rv = -EAGAIN;
                goto err_descr_too_many;
        }
-       if (desc_needed > num_descrs_avail){
+       if (desc_needed > num_descrs_avail) {
                dev_warn(&priv->ldev->pldev->dev, "    mapped_entry_count = %d    num_descrs_needed = %d    num_descrs_avail = %d    Too many to complete right now.\n", acd->mapped_entry_count, desc_needed, num_descrs_avail);
                rv = -EMSGSIZE;
                goto err_descr_too_many;
@@ -127,70 +122,67 @@ int  kpc_dma_transfer(struct dev_private_data *priv, struct kiocb *kcb, unsigned
        // Loop through all the sg table entries and fill out a descriptor for each one.
        desc = ldev->desc_next;
        card_addr = acd->priv->card_addr;
-       for_each_sg(acd->sgt.sgl, sg, acd->mapped_entry_count, i){
+       for_each_sg(acd->sgt.sgl, sg, acd->mapped_entry_count, i) {
                pcnt = count_parts_for_sge(sg);
-               for (p = 0 ; p < pcnt ; p++){
+               for (p = 0 ; p < pcnt ; p++) {
                        // Fill out the descriptor
                        BUG_ON(desc == NULL);
                        clear_desc(desc);
-                       if (p != pcnt-1){
+                       if (p != pcnt-1) {
                                desc->DescByteCount = 0x80000;
                        } else {
                                desc->DescByteCount = sg_dma_len(sg) - (p * 0x80000);
                        }
                        desc->DescBufferByteCount = desc->DescByteCount;
-                       
+
                        desc->DescControlFlags |= DMA_DESC_CTL_IRQONERR;
                        if (i == 0 && p == 0)
                                desc->DescControlFlags |= DMA_DESC_CTL_SOP;
                        if (i == acd->mapped_entry_count-1 && p == pcnt-1)
                                desc->DescControlFlags |= DMA_DESC_CTL_EOP | DMA_DESC_CTL_IRQONDONE;
-                       
+
                        desc->DescCardAddrLS = (card_addr & 0xFFFFFFFF);
                        desc->DescCardAddrMS = (card_addr >> 32) & 0xF;
                        card_addr += desc->DescByteCount;
-                       
+
                        dma_addr  = sg_dma_address(sg) + (p * 0x80000);
                        desc->DescSystemAddrLS = (dma_addr & 0x00000000FFFFFFFF) >>  0;
                        desc->DescSystemAddrMS = (dma_addr & 0xFFFFFFFF00000000) >> 32;
-                       
+
                        user_ctl = acd->priv->user_ctl;
-                       if (i == acd->mapped_entry_count-1 && p == pcnt-1){
+                       if (i == acd->mapped_entry_count-1 && p == pcnt-1) {
                                user_ctl = acd->priv->user_ctl_last;
                        }
                        desc->DescUserControlLS = (user_ctl & 0x00000000FFFFFFFF) >>  0;
                        desc->DescUserControlMS = (user_ctl & 0xFFFFFFFF00000000) >> 32;
-                       
+
                        if (i == acd->mapped_entry_count-1 && p == pcnt-1)
                                desc->acd = acd;
-                       
+
                        dev_dbg(&priv->ldev->pldev->dev, "  Filled descriptor %p (acd = %p)\n", desc, desc->acd);
-                       
+
                        ldev->desc_next = desc->Next;
                        desc = desc->Next;
                }
        }
-       
+
        // Send the filled descriptors off to the hardware to process!
        SetEngineSWPtr(ldev, ldev->desc_next);
-       
+
        unlock_engine(ldev);
-       
-       // If this is a synchronous kiocb, we need to put the calling process to sleep until the transfer is complete
-       if (kcb == NULL || is_sync_kiocb(kcb)){
-               rv = wait_for_completion_interruptible(&done);
-               // If the user aborted (rv == -ERESTARTSYS), we're no longer responsible for cleaning up the acd
-               if (rv == -ERESTARTSYS){
-                       acd->cpl = NULL;
-               }
-               if (rv == 0){
-                       rv = acd->len;
-                       kfree(acd);
-               }
-               return rv;
+
+       rv = wait_for_completion_interruptible(&done);
+       /*
+        * If the user aborted (rv == -ERESTARTSYS), we're no longer responsible
+        * for cleaning up the acd
+        */
+       if (rv == -ERESTARTSYS)
+               acd->cpl = NULL;
+       if (rv == 0) {
+               rv = acd->len;
+               kfree(acd);
        }
-       
-       return -EIOCBQUEUED;
+       return rv;
 
  err_descr_too_many:
        unlock_engine(ldev);
@@ -198,58 +190,52 @@ int  kpc_dma_transfer(struct dev_private_data *priv, struct kiocb *kcb, unsigned
        sg_free_table(&acd->sgt);
  err_dma_map_sg:
  err_alloc_sg_table:
-       for (i = 0 ; i < acd->page_count ; i++){
+       for (i = 0 ; i < acd->page_count ; i++) {
                put_page(acd->user_pages[i]);
        }
  err_get_user_pages:
        kfree(acd->user_pages);
  err_alloc_userpages:
        kfree(acd);
-       dev_dbg(&priv->ldev->pldev->dev, "kpc_dma_transfer returning with error %ld\n", rv);
+       dev_dbg(&priv->ldev->pldev->dev, "%s returning with error %ld\n", __func__, rv);
        return rv;
 }
 
 void  transfer_complete_cb(struct aio_cb_data *acd, size_t xfr_count, u32 flags)
 {
        unsigned int i;
-       
+
        BUG_ON(acd == NULL);
        BUG_ON(acd->user_pages == NULL);
        BUG_ON(acd->sgt.sgl == NULL);
        BUG_ON(acd->ldev == NULL);
        BUG_ON(acd->ldev->pldev == NULL);
-       
-       dev_dbg(&acd->ldev->pldev->dev, "transfer_complete_cb(acd = [%p])\n", acd);
-       
-       for (i = 0 ; i < acd->page_count ; i++){
-               if (!PageReserved(acd->user_pages[i])){
+
+       for (i = 0 ; i < acd->page_count ; i++) {
+               if (!PageReserved(acd->user_pages[i])) {
                        set_page_dirty(acd->user_pages[i]);
                }
        }
-       
+
        dma_unmap_sg(&acd->ldev->pldev->dev, acd->sgt.sgl, acd->sgt.nents, acd->ldev->dir);
-       
-       for (i = 0 ; i < acd->page_count ; i++){
+
+       for (i = 0 ; i < acd->page_count ; i++) {
                put_page(acd->user_pages[i]);
        }
-       
+
        sg_free_table(&acd->sgt);
-       
+
        kfree(acd->user_pages);
-       
+
        acd->flags = flags;
-       
-       if (acd->kcb == NULL || is_sync_kiocb(acd->kcb)){
-               if (acd->cpl){
-                       complete(acd->cpl);
-               } else {
-                       // There's no completion, so we're responsible for cleaning up the acd
-                       kfree(acd);
-               }
+
+       if (acd->cpl) {
+               complete(acd->cpl);
        } else {
-#ifdef CONFIG_KPC_DMA_AIO
-               aio_complete(acd->kcb, acd->len, acd->flags);
-#endif
+               /*
+                * There's no completion, so we're responsible for cleaning up
+                * the acd
+                */
                kfree(acd);
        }
 }
@@ -260,22 +246,22 @@ int  kpc_dma_open(struct inode *inode, struct file *filp)
 {
        struct dev_private_data *priv;
        struct kpc_dma_device *ldev = kpc_dma_lookup_device(iminor(inode));
-       if (ldev == NULL)
+
+       if (!ldev)
                return -ENODEV;
-       
-       if (! atomic_dec_and_test(&ldev->open_count)){
+
+       if (!atomic_dec_and_test(&ldev->open_count)) {
                atomic_inc(&ldev->open_count);
                return -EBUSY; /* already open */
        }
-       
+
        priv = kzalloc(sizeof(struct dev_private_data), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
-       
+
        priv->ldev = ldev;
        filp->private_data = priv;
-       
-       dev_dbg(&priv->ldev->pldev->dev, "kpc_dma_open(inode = [%p], filp = [%p]) priv = [%p] ldev = [%p]\n", inode, filp, priv, priv->ldev);
+
        return 0;
 }
 
@@ -285,134 +271,81 @@ int  kpc_dma_close(struct inode *inode, struct file *filp)
        struct kpc_dma_descriptor *cur;
        struct dev_private_data *priv = (struct dev_private_data *)filp->private_data;
        struct kpc_dma_device *eng = priv->ldev;
-       dev_dbg(&priv->ldev->pldev->dev, "kpc_dma_close(inode = [%p], filp = [%p]) priv = [%p], ldev = [%p]\n", inode, filp, priv, priv->ldev);
-       
+
        lock_engine(eng);
-       
+
        stop_dma_engine(eng);
-       
+
        cur = eng->desc_completed->Next;
-       while (cur != eng->desc_next){
+       while (cur != eng->desc_next) {
                dev_dbg(&eng->pldev->dev, "Aborting descriptor %p (acd = %p)\n", cur, cur->acd);
-               if (cur->DescControlFlags & DMA_DESC_CTL_EOP){
+               if (cur->DescControlFlags & DMA_DESC_CTL_EOP) {
                        if (cur->acd)
                                transfer_complete_cb(cur->acd, 0, ACD_FLAG_ABORT);
                }
-               
+
                clear_desc(cur);
                eng->desc_completed = cur;
-               
+
                cur = cur->Next;
        }
-       
+
        start_dma_engine(eng);
-       
+
        unlock_engine(eng);
-       
+
        atomic_inc(&priv->ldev->open_count); /* release the device */
        kfree(priv);
        return 0;
 }
 
-#ifdef CONFIG_KPC_DMA_AIO
 static
-int  kpc_dma_aio_cancel(struct kiocb *kcb)
+ssize_t  kpc_dma_read(struct file *filp,       char __user *user_buf, size_t count, loff_t *ppos)
 {
-       struct dev_private_data *priv = (struct dev_private_data *)kcb->ki_filp->private_data;
-       dev_dbg(&priv->ldev->pldev->dev, "kpc_dma_aio_cancel(kcb = [%p]) priv = [%p], ldev = [%p]\n", kcb, priv, priv->ldev);
-       return 0;
-}
+       struct dev_private_data *priv = (struct dev_private_data *)filp->private_data;
 
-static
-ssize_t   kpc_dma_aio_read(struct kiocb *kcb, const struct iovec *iov, unsigned long iov_count, loff_t pos)
-{
-       struct dev_private_data *priv = (struct dev_private_data *)kcb->ki_filp->private_data;
-       dev_dbg(&priv->ldev->pldev->dev, "kpc_dma_aio_read(kcb = [%p], iov = [%p], iov_count = %ld, pos = %lld) priv = [%p], ldev = [%p]\n", kcb, iov, iov_count, pos, priv, priv->ldev);
-       
        if (priv->ldev->dir != DMA_FROM_DEVICE)
                return -EMEDIUMTYPE;
-       
-       if (iov_count != 1){
-               dev_err(&priv->ldev->pldev->dev, "kpc_dma_aio_read() called with iov_count > 1!\n");
-               return -EFAULT;
-       }
-       
-       if (!is_sync_kiocb(kcb))
-               kiocb_set_cancel_fn(kcb, kpc_dma_aio_cancel);
-       return kpc_dma_transfer(priv, kcb, (unsigned long)iov->iov_base, iov->iov_len);
-}
 
-static
-ssize_t  kpc_dma_aio_write(struct kiocb *kcb, const struct iovec *iov, unsigned long iov_count, loff_t pos)
-{
-       struct dev_private_data *priv = (struct dev_private_data *)kcb->ki_filp->private_data;
-       dev_dbg(&priv->ldev->pldev->dev, "kpc_dma_aio_write(kcb = [%p], iov = [%p], iov_count = %ld, pos = %lld) priv = [%p], ldev = [%p]\n", kcb, iov, iov_count, pos, priv, priv->ldev);
-       
-       if (priv->ldev->dir != DMA_TO_DEVICE)
-               return -EMEDIUMTYPE;
-       
-       if (iov_count != 1){
-               dev_err(&priv->ldev->pldev->dev, "kpc_dma_aio_write() called with iov_count > 1!\n");
-               return -EFAULT;
-       }
-       
-       if (!is_sync_kiocb(kcb))
-               kiocb_set_cancel_fn(kcb, kpc_dma_aio_cancel);
-       return kpc_dma_transfer(priv, kcb, (unsigned long)iov->iov_base, iov->iov_len);
-}
-#endif
-
-static
-ssize_t  kpc_dma_read( struct file *filp,       char __user *user_buf, size_t count, loff_t *ppos)
-{
-       struct dev_private_data *priv = (struct dev_private_data *)filp->private_data;
-       dev_dbg(&priv->ldev->pldev->dev, "kpc_dma_read(filp = [%p], user_buf = [%p], count = %zu, ppos = [%p]) priv = [%p], ldev = [%p]\n", filp, user_buf, count, ppos, priv, priv->ldev);
-       
-       if (priv->ldev->dir != DMA_FROM_DEVICE)
-               return -EMEDIUMTYPE;
-       
-       return kpc_dma_transfer(priv, (struct kiocb *)NULL, (unsigned long)user_buf, count);
+       return kpc_dma_transfer(priv, (unsigned long)user_buf, count);
 }
 
 static
 ssize_t  kpc_dma_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *ppos)
 {
        struct dev_private_data *priv = (struct dev_private_data *)filp->private_data;
-       dev_dbg(&priv->ldev->pldev->dev, "kpc_dma_write(filp = [%p], user_buf = [%p], count = %zu, ppos = [%p]) priv = [%p], ldev = [%p]\n", filp, user_buf, count, ppos, priv, priv->ldev);
-       
+
        if (priv->ldev->dir != DMA_TO_DEVICE)
                return -EMEDIUMTYPE;
-       
-       return kpc_dma_transfer(priv, (struct kiocb *)NULL, (unsigned long)user_buf, count);
+
+       return kpc_dma_transfer(priv, (unsigned long)user_buf, count);
 }
 
 static
 long  kpc_dma_ioctl(struct file *filp, unsigned int ioctl_num, unsigned long ioctl_param)
 {
        struct dev_private_data *priv = (struct dev_private_data *)filp->private_data;
-       dev_dbg(&priv->ldev->pldev->dev, "kpc_dma_ioctl(filp = [%p], ioctl_num = 0x%x, ioctl_param = 0x%lx) priv = [%p], ldev = [%p]\n", filp, ioctl_num, ioctl_param, priv, priv->ldev);
-       
-       switch (ioctl_num){
-               case KND_IOCTL_SET_CARD_ADDR:           priv->card_addr  = ioctl_param; return priv->card_addr; 
-               case KND_IOCTL_SET_USER_CTL:            priv->user_ctl   = ioctl_param; return priv->user_ctl; 
-               case KND_IOCTL_SET_USER_CTL_LAST:       priv->user_ctl_last = ioctl_param; return priv->user_ctl_last; 
-               case KND_IOCTL_GET_USER_STS:            return priv->user_sts;
+
+       switch (ioctl_num) {
+       case KND_IOCTL_SET_CARD_ADDR:
+               priv->card_addr  = ioctl_param; return priv->card_addr;
+       case KND_IOCTL_SET_USER_CTL:
+               priv->user_ctl   = ioctl_param; return priv->user_ctl;
+       case KND_IOCTL_SET_USER_CTL_LAST:
+               priv->user_ctl_last = ioctl_param; return priv->user_ctl_last;
+       case KND_IOCTL_GET_USER_STS:
+               return priv->user_sts;
        }
-       
+
        return -ENOTTY;
 }
 
-
-struct file_operations  kpc_dma_fops = {
+const struct file_operations  kpc_dma_fops = {
        .owner      = THIS_MODULE,
        .open           = kpc_dma_open,
        .release        = kpc_dma_close,
        .read           = kpc_dma_read,
        .write          = kpc_dma_write,
-#ifdef CONFIG_KPC_DMA_AIO
-       .aio_read       = kpc_dma_aio_read,
-       .aio_write      = kpc_dma_aio_write,
-#endif
        .unlocked_ioctl = kpc_dma_ioctl,
 };
 
index aeae58d..a05ae6d 100644 (file)
@@ -14,16 +14,16 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Matt.Sickler@daktronics.com");
 
 #define KPC_DMA_CHAR_MAJOR    UNNAMED_MAJOR
-#define KPC_DMA_NUM_MINORS    1 << MINORBITS
+#define KPC_DMA_NUM_MINORS    BIT(MINORBITS)
 static DEFINE_MUTEX(kpc_dma_mtx);
 static int assigned_major_num;
 static LIST_HEAD(kpc_dma_list);
 
-
 /**********  kpc_dma_list list management  **********/
-struct kpc_dma_device *  kpc_dma_lookup_device(int minor)
+struct kpc_dma_device *kpc_dma_lookup_device(int minor)
 {
        struct kpc_dma_device *c;
+
        mutex_lock(&kpc_dma_mtx);
        list_for_each_entry(c, &kpc_dma_list, list) {
                if (c->pldev->id == minor) {
@@ -31,19 +31,19 @@ struct kpc_dma_device *  kpc_dma_lookup_device(int minor)
                }
        }
        c = NULL; // not-found case
-  out:
+out:
        mutex_unlock(&kpc_dma_mtx);
        return c;
 }
 
-void  kpc_dma_add_device(struct kpc_dma_device * ldev)
+static void kpc_dma_add_device(struct kpc_dma_device *ldev)
 {
        mutex_lock(&kpc_dma_mtx);
        list_add(&ldev->list, &kpc_dma_list);
        mutex_unlock(&kpc_dma_mtx);
 }
 
-void kpc_dma_del_device(struct kpc_dma_device * ldev)
+static void kpc_dma_del_device(struct kpc_dma_device *ldev)
 {
        mutex_lock(&kpc_dma_mtx);
        list_del(&ldev->list);
@@ -55,11 +55,14 @@ static ssize_t  show_engine_regs(struct device *dev, struct device_attribute *at
 {
        struct kpc_dma_device *ldev;
        struct platform_device *pldev = to_platform_device(dev);
-       if (!pldev) return 0;
+
+       if (!pldev)
+               return 0;
        ldev = platform_get_drvdata(pldev);
-       if (!ldev) return 0;
-       
-       return scnprintf(buf, PAGE_SIZE, 
+       if (!ldev)
+               return 0;
+
+       return scnprintf(buf, PAGE_SIZE,
                "EngineControlStatus      = 0x%08x\n"
                "RegNextDescPtr           = 0x%08x\n"
                "RegSWDescPtr             = 0x%08x\n"
@@ -78,15 +81,14 @@ static ssize_t  show_engine_regs(struct device *dev, struct device_attribute *at
                ldev->desc_completed
        );
 }
-DEVICE_ATTR(engine_regs, 0444, show_engine_regs, NULL);
+static DEVICE_ATTR(engine_regs, 0444, show_engine_regs, NULL);
 
-static const struct attribute *  ndd_attr_list[] = {
+static const struct attribute *ndd_attr_list[] = {
        &dev_attr_engine_regs.attr,
        NULL,
 };
 
-struct class *kpc_dma_class;
-
+static struct class *kpc_dma_class;
 
 /**********  Platform Driver Functions  **********/
 static
@@ -95,73 +97,72 @@ int  kpc_dma_probe(struct platform_device *pldev)
        struct resource *r = NULL;
        int rv = 0;
        dev_t dev;
-       
+
        struct kpc_dma_device *ldev = kzalloc(sizeof(struct kpc_dma_device), GFP_KERNEL);
-       if (!ldev){
-               dev_err(&pldev->dev, "kpc_dma_probe: unable to kzalloc space for kpc_dma_device\n");
+
+       if (!ldev) {
+               dev_err(&pldev->dev, "%s: unable to kzalloc space for kpc_dma_device\n", __func__);
                rv = -ENOMEM;
                goto err_rv;
        }
-       
-       dev_dbg(&pldev->dev, "kpc_dma_probe(pldev = [%p]) ldev = [%p]\n", pldev, ldev);
-       
+
        INIT_LIST_HEAD(&ldev->list);
-       
+
        ldev->pldev = pldev;
        platform_set_drvdata(pldev, ldev);
        atomic_set(&ldev->open_count, 1);
-       
+
        mutex_init(&ldev->sem);
        lock_engine(ldev);
-       
+
        // Get Engine regs resource
        r = platform_get_resource(pldev, IORESOURCE_MEM, 0);
-       if (!r){
-               dev_err(&ldev->pldev->dev, "kpc_dma_probe: didn't get the engine regs resource!\n");
+       if (!r) {
+               dev_err(&ldev->pldev->dev, "%s: didn't get the engine regs resource!\n", __func__);
                rv = -ENXIO;
                goto err_kfree;
        }
        ldev->eng_regs = ioremap_nocache(r->start, resource_size(r));
-       if (!ldev->eng_regs){
-               dev_err(&ldev->pldev->dev, "kpc_dma_probe: failed to ioremap engine regs!\n");
+       if (!ldev->eng_regs) {
+               dev_err(&ldev->pldev->dev, "%s: failed to ioremap engine regs!\n", __func__);
                rv = -ENXIO;
                goto err_kfree;
        }
-       
+
        r = platform_get_resource(pldev, IORESOURCE_IRQ, 0);
-       if (!r){
-               dev_err(&ldev->pldev->dev, "kpc_dma_probe: didn't get the IRQ resource!\n");
+       if (!r) {
+               dev_err(&ldev->pldev->dev, "%s: didn't get the IRQ resource!\n", __func__);
                rv = -ENXIO;
                goto err_kfree;
        }
        ldev->irq = r->start;
-       
+
        // Setup miscdev struct
        dev = MKDEV(assigned_major_num, pldev->id);
        ldev->kpc_dma_dev = device_create(kpc_dma_class, &pldev->dev, dev, ldev, "kpc_dma%d", pldev->id);
-       if (IS_ERR(ldev->kpc_dma_dev)){
-               dev_err(&ldev->pldev->dev, "kpc_dma_probe: device_create failed: %d\n", rv);
+       if (IS_ERR(ldev->kpc_dma_dev)) {
+               dev_err(&ldev->pldev->dev, "%s: device_create failed: %d\n", __func__, rv);
                goto err_kfree;
        }
-       
+
        // Setup the DMA engine
        rv = setup_dma_engine(ldev, 30);
-       if (rv){
-               dev_err(&ldev->pldev->dev, "kpc_dma_probe: failed to setup_dma_engine: %d\n", rv);
+       if (rv) {
+               dev_err(&ldev->pldev->dev, "%s: failed to setup_dma_engine: %d\n", __func__, rv);
                goto err_misc_dereg;
        }
-       
+
        // Setup the sysfs files
        rv = sysfs_create_files(&(ldev->pldev->dev.kobj), ndd_attr_list);
-       if (rv){
-               dev_err(&ldev->pldev->dev, "kpc_dma_probe: Failed to add sysfs files: %d\n", rv);
+       if (rv) {
+               dev_err(&ldev->pldev->dev, "%s: Failed to add sysfs files: %d\n", __func__, rv);
                goto err_destroy_eng;
        }
-       
+
        kpc_dma_add_device(ldev);
-       
+
        return 0;
-       
+
  err_destroy_eng:
        destroy_dma_engine(ldev);
  err_misc_dereg:
@@ -176,70 +177,67 @@ static
 int  kpc_dma_remove(struct platform_device *pldev)
 {
        struct kpc_dma_device *ldev = platform_get_drvdata(pldev);
+
        if (!ldev)
                return -ENXIO;
-       
-       dev_dbg(&ldev->pldev->dev, "kpc_dma_remove(pldev = [%p]) ldev = [%p]\n", pldev, ldev);
-       
+
        lock_engine(ldev);
        sysfs_remove_files(&(ldev->pldev->dev.kobj), ndd_attr_list);
        destroy_dma_engine(ldev);
        kpc_dma_del_device(ldev);
        device_destroy(kpc_dma_class, MKDEV(assigned_major_num, ldev->pldev->id));
        kfree(ldev);
-       
+
        return 0;
 }
 
-
 /**********  Driver Functions  **********/
-struct platform_driver kpc_dma_plat_driver_i = {
+static struct platform_driver kpc_dma_plat_driver_i = {
        .probe        = kpc_dma_probe,
        .remove       = kpc_dma_remove,
        .driver = {
                .name   = KP_DRIVER_NAME_DMA_CONTROLLER,
-               .owner  = THIS_MODULE,
        },
 };
 
 static
-int __init  kpc_dma_driver_init(void)
+int __init kpc_dma_driver_init(void)
 {
        int err;
-       
+
        err = __register_chrdev(KPC_DMA_CHAR_MAJOR, 0, KPC_DMA_NUM_MINORS, "kpc_dma", &kpc_dma_fops);
-       if (err < 0){
+       if (err < 0) {
                pr_err("Can't allocate a major number (%d) for kpc_dma (err = %d)\n", KPC_DMA_CHAR_MAJOR, err);
                goto fail_chrdev_register;
        }
        assigned_major_num = err;
-       
+
        kpc_dma_class = class_create(THIS_MODULE, "kpc_dma");
        err = PTR_ERR(kpc_dma_class);
-       if (IS_ERR(kpc_dma_class)){
+       if (IS_ERR(kpc_dma_class)) {
                pr_err("Can't create class kpc_dma (err = %d)\n", err);
                goto fail_class_create;
        }
-       
+
        err = platform_driver_register(&kpc_dma_plat_driver_i);
-       if (err){
+       if (err) {
                pr_err("Can't register platform driver for kpc_dma (err = %d)\n", err);
                goto fail_platdriver_register;
        }
-       
+
        return err;
-       
-  fail_platdriver_register:
+
+fail_platdriver_register:
        class_destroy(kpc_dma_class);
-  fail_class_create:
+fail_class_create:
        __unregister_chrdev(KPC_DMA_CHAR_MAJOR, 0, KPC_DMA_NUM_MINORS, "kpc_dma");
-  fail_chrdev_register:
+fail_chrdev_register:
        return err;
 }
 module_init(kpc_dma_driver_init);
 
 static
-void __exit  kpc_dma_driver_exit(void)
+void __exit kpc_dma_driver_exit(void)
 {
        platform_driver_unregister(&kpc_dma_plat_driver_i);
        class_destroy(kpc_dma_class);
index ef913b7..4c8cc86 100644 (file)
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 #include <linux/workqueue.h>
-#include <linux/aio.h>
 #include <linux/bitops.h>
 #include "../kpc.h"
 
-
 struct kp2000_device;
 struct kpc_dma_device {
        struct list_head            list;
@@ -27,23 +25,23 @@ struct kpc_dma_device {
        struct device              *kpc_dma_dev;
        struct kobject              kobj;
        char                        name[16];
-       
+
        int                         dir; // DMA_FROM_DEVICE || DMA_TO_DEVICE
        struct mutex                sem;
        unsigned int                irq;
        struct work_struct          irq_work;
-       
+
        atomic_t                    open_count;
-       
+
        size_t                      accumulated_bytes;
        u32                         accumulated_flags;
-       
+
        // Descriptor "Pool" housekeeping
        u32                         desc_pool_cnt;
        struct dma_pool            *desc_pool;
        struct kpc_dma_descriptor  *desc_pool_first;
        struct kpc_dma_descriptor  *desc_pool_last;
-       
+
        struct kpc_dma_descriptor  *desc_next;
        struct kpc_dma_descriptor  *desc_completed;
 };
@@ -56,9 +54,9 @@ struct dev_private_data {
        u64                         user_sts;
 };
 
-struct kpc_dma_device *  kpc_dma_lookup_device(int minor);
+struct kpc_dma_device *kpc_dma_lookup_device(int minor);
 
-extern struct file_operations  kpc_dma_fops;
+extern const struct file_operations  kpc_dma_fops;
 
 #define ENG_CAP_PRESENT                 0x00000001
 #define ENG_CAP_DIRECTION               0x00000002
@@ -88,9 +86,8 @@ struct aio_cb_data {
        struct kpc_dma_device      *ldev;
        struct completion  *cpl;
        unsigned char       flags;
-       struct kiocb       *kcb;
        size_t              len;
-       
+
        unsigned int        page_count;
        struct page       **user_pages;
        struct sg_table     sgt;
@@ -119,10 +116,10 @@ struct kpc_dma_descriptor {
                volatile u32  DescSystemAddrLS;
                volatile u32  DescSystemAddrMS;
                volatile u32  DescNextDescPtr;
-               
+
                dma_addr_t    MyDMAAddr;
                struct kpc_dma_descriptor   *Next;
-               
+
                struct aio_cb_data  *acd;
 } __attribute__((packed));
 // DescControlFlags:
@@ -157,35 +154,41 @@ void  WriteEngineControl(struct kpc_dma_device *eng, u32 value)
 {
        writel(value, eng->eng_regs + 1);
 }
+
 static inline
 u32  GetEngineControl(struct kpc_dma_device *eng)
 {
        return readl(eng->eng_regs + 1);
 }
+
 static inline
 void  SetClearEngineControl(struct kpc_dma_device *eng, u32 set_bits, u32 clear_bits)
 {
        u32 val = GetEngineControl(eng);
+
        val |= set_bits;
        val &= ~clear_bits;
        WriteEngineControl(eng, val);
 }
 
 static inline
-void  SetEngineNextPtr(struct kpc_dma_device *eng, struct kpc_dma_descriptor * desc)
+void  SetEngineNextPtr(struct kpc_dma_device *eng, struct kpc_dma_descriptor *desc)
 {
        writel(desc->MyDMAAddr, eng->eng_regs + 2);
 }
+
 static inline
-void  SetEngineSWPtr(struct kpc_dma_device *eng, struct kpc_dma_descriptor * desc)
+void  SetEngineSWPtr(struct kpc_dma_device *eng, struct kpc_dma_descriptor *desc)
 {
        writel(desc->MyDMAAddr, eng->eng_regs + 3);
 }
+
 static inline
 void  ClearEngineCompletePtr(struct kpc_dma_device *eng)
 {
        writel(0, eng->eng_regs + 4);
 }
+
 static inline
 u32  GetEngineCompletePtr(struct kpc_dma_device *eng)
 {
@@ -206,7 +209,6 @@ void  unlock_engine(struct kpc_dma_device *eng)
        mutex_unlock(&eng->sem);
 }
 
-
 /// Shared Functions
 void  start_dma_engine(struct kpc_dma_device *eng);
 int   setup_dma_engine(struct kpc_dma_device *eng, u32 desc_cnt);
diff --git a/drivers/staging/kpc2000/kpc_i2c/Makefile b/drivers/staging/kpc2000/kpc_i2c/Makefile
deleted file mode 100644 (file)
index 73ec07a..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-obj-m := kpc2000_i2c.o
-kpc2000_i2c-objs := i2c_driver.o fileops.o
diff --git a/drivers/staging/kpc2000/kpc_i2c/fileops.c b/drivers/staging/kpc2000/kpc_i2c/fileops.c
deleted file mode 100644 (file)
index e749c09..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-#if 0
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>      /* printk() */
-#include <linux/slab.h>                /* kmalloc() */
-#include <linux/fs.h>          /* everything... */
-#include <linux/errno.h>       /* error codes */
-#include <linux/types.h>       /* size_t */
-#include <linux/cdev.h>
-#include <asm/uaccess.h>       /* copy_*_user */
-
-#include "i2c_driver.h"
-
-int i2c_cdev_open(struct inode *inode, struct file *filp)
-{
-  struct i2c_device *lddev;
-  
-  if(NULL == inode) {
-    //printk(KERN_WARNING "<pl_i2c> i2c_cdev_open: inode is a NULL pointer\n");
-    DBG_PRINT(KERN_WARNING, "i2c_cdev_open: inode is a NULL pointer\n");
-    return -EINVAL;
-  }
-  if(NULL == filp) {
-    //printk(KERN_WARNING "<pl_i2c> i2c_cdev_open: filp is a NULL pointer\n");
-    DBG_PRINT(KERN_WARNING, "i2c_cdev_open: filp is a NULL pointer\n");
-    return -EINVAL;
-  }
-  
-  lddev = container_of(inode->i_cdev, struct i2c_device, cdev);
-  //printk(KERN_DEBUG "<pl_i2c> i2c_cdev_open(filp = [%p], lddev = [%p])\n", filp, lddev);
-  DBG_PRINT(KERN_DEBUG, "i2c_cdev_open(filp = [%p], lddev = [%p])\n", filp, lddev);
-  
-  filp->private_data = lddev; /* so other methods can access it */
-  
-  return 0;    /* success */
-}
-
-int i2c_cdev_close(struct inode *inode, struct file *filp)
-{
-  struct i2c_device *lddev;
-  
-  if(NULL == inode) {
-    //printk(KERN_WARNING "<pl_i2c> i2c_cdev_close: inode is a NULL pointer\n");
-    DBG_PRINT(KERN_WARNING, "i2c_cdev_close: inode is a NULL pointer\n");
-    return -EINVAL;
-  }
-  if(NULL == filp) {
-    //printk(KERN_WARNING "<pl_i2c> i2c_cdev_close: filp is a NULL pointer\n");
-    DBG_PRINT(KERN_WARNING, "i2c_cdev_close: filp is a NULL pointer\n");
-    return -EINVAL;
-  }
-  
-  lddev = filp->private_data;
-  //printk(KERN_DEBUG "<pl_i2c> i2c_cdev_close(filp = [%p], lddev = [%p])\n", filp, lddev);
-  DBG_PRINT(KERN_DEBUG, "i2c_cdev_close(filp = [%p], lddev = [%p])\n", filp, lddev);
-  
-  return 0;
-}
-
-ssize_t i2c_cdev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
-{
-  size_t copy;
-  ssize_t ret = 0;
-  int err = 0;
-  u64 read_val;
-  char tmp_buf[48] = { 0 };
-  struct i2c_device *lddev = filp->private_data;
-
-  if(NULL == filp) {
-    //printk(KERN_WARNING "<pl_i2c> i2c_cdev_read: filp is a NULL pointer\n");
-    DBG_PRINT(KERN_WARNING, "i2c_cdev_read: filp is a NULL pointer\n");
-    return -EINVAL;
-  }
-  if(NULL == buf) {
-    //printk(KERN_WARNING "<pl_i2c> i2c_cdev_read: buf is a NULL pointer\n");
-    DBG_PRINT(KERN_WARNING, "i2c_cdev_read: buf is a NULL pointer\n");
-    return -EINVAL;
-  }
-  if(NULL == f_pos) {
-    //printk(KERN_WARNING "<pl_i2c> i2c_cdev_read: f_pos is a NULL pointer\n");
-    DBG_PRINT(KERN_WARNING, "i2c_cdev_read: f_pos is a NULL pointer\n");
-    return -EINVAL;
-  }
-
-  if(count < sizeof(tmp_buf)) {
-    //printk(KERN_INFO "<pl_i2c> i2c_cdev_read: buffer is too small (count = %d, should be at least %d bytes)\n", (int)count, (int)sizeof(tmp_buf));
-    DBG_PRINT(KERN_INFO, "i2c_cdev_read: buffer is too small (count = %d, should be at least %d bytes)\n", (int)count, (int)sizeof(tmp_buf));
-    return -EINVAL;
-  }
-  if(((*f_pos * 8) + lddev->pldev->resource[0].start) > lddev->pldev->resource[0].end) {
-    //printk(KERN_INFO "<pl_i2c> i2c_cdev_read: bad read addr %016llx\n", (*f_pos * 8) + lddev->pldev->resource[0].start);
-    DBG_PRINT(KERN_INFO, "i2c_cdev_read: bad read addr %016llx\n", (*f_pos * 8) + lddev->pldev->resource[0].start);
-    //printk(KERN_INFO "<pl_i2c> i2c_cdev_read: addr end %016llx\n", lddev->pldev->resource[0].end);
-    DBG_PRINT(KERN_INFO, "i2c_cdev_read: addr end %016llx\n", lddev->pldev->resource[0].end);
-    //printk(KERN_INFO "<pl_i2c> i2c_cdev_read: EOF reached\n");
-    DBG_PRINT(KERN_INFO, "i2c_cdev_read: EOF reached\n");
-    return 0;
-  }
-
-  down_read(&lddev->rw_sem);
-  
-  read_val = *(lddev->regs + *f_pos);
-  copy = clamp_t(size_t, count, 1, sizeof(tmp_buf));
-  copy = scnprintf(tmp_buf, copy, "reg: 0x%x val: 0x%llx\n", (unsigned int)*f_pos, read_val);
-  err = copy_to_user(buf, tmp_buf, copy);
-  if(err) {
-    //printk(KERN_INFO "<pl_i2c> i2c_cdev_read: could not copy to user (err = %d)\n", err);
-    DBG_PRINT(KERN_INFO, "i2c_cdev_read: could not copy to user (err = %d)\n", err);
-    return -EINVAL;
-  }
-
-  ret = (ssize_t)copy;
-  (*f_pos)++;
-  
-  up_read(&lddev->rw_sem);
-  
-  return ret;
-}
-
-ssize_t i2c_cdev_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
-{
-  u8 reg;
-  u8 val;
-  char tmp[8] = { 0 };
-  struct i2c_device *lddev = filp->private_data;
-
-  if(NULL == filp) {
-    //printk(KERN_WARNING "<pl_i2c> i2c_cdev_write: filp is a NULL pointer\n");
-    DBG_PRINT(KERN_WARNING, "i2c_cdev_write: filp is a NULL pointer\n");
-    return -EINVAL;
-  }
-  if(NULL == buf) {
-    //printk(KERN_WARNING "<pl_i2c> i2c_cdev_write: buf is a NULL pointer\n");
-    DBG_PRINT(KERN_WARNING, "i2c_cdev_write: buf is a NULL pointer\n");
-    return -EINVAL;
-  }
-  if(NULL == f_pos) {
-    //printk(KERN_WARNING "<pl_i2c> i2c_cdev_write: f_pos is a NULL pointer\n");
-    DBG_PRINT(KERN_WARNING, "i2c_cdev_write: f_pos is a NULL pointer\n");
-    return -EINVAL;
-  }
-
-  //printk(KERN_DEBUG "<pl_i2c> i2c_cdev_write(filp = [%p], lddev = [%p])\n", filp, lddev);
-  DBG_PRINT(KERN_DEBUG, "i2c_cdev_write(filp = [%p], lddev = [%p])\n", filp, lddev);
-
-  down_write(&lddev->rw_sem);
-
-  if(count >= 2) {
-    if(copy_from_user(tmp, buf, 2)) {
-      return -EFAULT;
-    }
-    
-    reg = tmp[0] - '0';
-    val = tmp[1] - '0';
-
-    //printk(KERN_DEBUG "  reg = %d  val = %d\n", reg, val);
-    DBG_PRINT(KERN_DEBUG, "  reg = %d  val = %d\n", reg, val);
-
-    if(reg >= 0 && reg < 16) {
-      //printk(KERN_DEBUG "  Writing 0x%x to %p\n", val, lddev->regs + reg);
-      DBG_PRINT(KERN_DEBUG, "  Writing 0x%x to %p\n", val, lddev->regs + reg);
-      *(lddev->regs + reg) = val;
-    }
-  }
-
-  (*f_pos)++;
-
-  up_write(&lddev->rw_sem);
-
-  return count;
-}
-
-struct file_operations i2c_fops = {
-  .owner               = THIS_MODULE,
-  .open                = i2c_cdev_open,
-  .release     = i2c_cdev_close,
-  .read                = i2c_cdev_read,
-  .write               = i2c_cdev_write,
-};
-#endif
diff --git a/drivers/staging/kpc2000/kpc_i2c/i2c_driver.c b/drivers/staging/kpc2000/kpc_i2c/i2c_driver.c
deleted file mode 100644 (file)
index 0fb068b..0000000
+++ /dev/null
@@ -1,699 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*  Copyright (c) 2014-2018  Daktronics,
-                             Matt Sickler <matt.sickler@daktronics.com>,
-                             Jordon Hofer <jordon.hofer@daktronics.com>
-    Adapted i2c-i801.c for use with Kadoka hardware.
-    Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
-    Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
-    <mdsxyz123@yahoo.com>
-    Copyright (C) 2007 - 2012  Jean Delvare <khali@linux-fr.org>
-    Copyright (C) 2010         Intel Corporation,
-                               David Woodhouse <dwmw2@infradead.org>
-*/
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <asm/io.h>
-#include <linux/io-64-nonatomic-lo-hi.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/fs.h>
-#include <linux/rwsem.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include "../kpc.h"
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Matt.Sickler@Daktronics.com");
-MODULE_SOFTDEP("pre: i2c-dev");
-
-struct i2c_device {
-    unsigned long           smba;
-    struct i2c_adapter      adapter;
-    struct platform_device *pldev;
-    struct rw_semaphore     rw_sem;
-    unsigned int            features;
-};
-
-/*****************************
- *** Part 1 - i2c Handlers ***
- *****************************/
-
-#define REG_SIZE 8
-
-/* I801 SMBus address offsets */
-#define SMBHSTSTS(p)    ((0  * REG_SIZE) + (p)->smba)
-#define SMBHSTCNT(p)    ((2  * REG_SIZE) + (p)->smba)
-#define SMBHSTCMD(p)    ((3  * REG_SIZE) + (p)->smba)
-#define SMBHSTADD(p)    ((4  * REG_SIZE) + (p)->smba)
-#define SMBHSTDAT0(p)   ((5  * REG_SIZE) + (p)->smba)
-#define SMBHSTDAT1(p)   ((6  * REG_SIZE) + (p)->smba)
-#define SMBBLKDAT(p)    ((7  * REG_SIZE) + (p)->smba)
-#define SMBPEC(p)       ((8  * REG_SIZE) + (p)->smba)   /* ICH3 and later */
-#define SMBAUXSTS(p)    ((12 * REG_SIZE) + (p)->smba)   /* ICH4 and later */
-#define SMBAUXCTL(p)    ((13 * REG_SIZE) + (p)->smba)   /* ICH4 and later */
-
-/* PCI Address Constants */
-#define SMBBAR      4
-#define SMBHSTCFG   0x040
-
-/* Host configuration bits for SMBHSTCFG */
-#define SMBHSTCFG_HST_EN        1
-#define SMBHSTCFG_SMB_SMI_EN    2
-#define SMBHSTCFG_I2C_EN        4
-
-/* Auxiliary control register bits, ICH4+ only */
-#define SMBAUXCTL_CRC       1
-#define SMBAUXCTL_E32B      2
-
-/* kill bit for SMBHSTCNT */
-#define SMBHSTCNT_KILL      2
-
-/* Other settings */
-#define MAX_RETRIES         400
-#define ENABLE_INT9         0       /* set to 0x01 to enable - untested */
-
-/* I801 command constants */
-#define I801_QUICK              0x00
-#define I801_BYTE               0x04
-#define I801_BYTE_DATA          0x08
-#define I801_WORD_DATA          0x0C
-#define I801_PROC_CALL          0x10    /* unimplemented */
-#define I801_BLOCK_DATA         0x14
-#define I801_I2C_BLOCK_DATA     0x18    /* ICH5 and later */
-#define I801_BLOCK_LAST         0x34
-#define I801_I2C_BLOCK_LAST     0x38    /* ICH5 and later */
-#define I801_START              0x40
-#define I801_PEC_EN             0x80    /* ICH3 and later */
-
-/* I801 Hosts Status register bits */
-#define SMBHSTSTS_BYTE_DONE     0x80
-#define SMBHSTSTS_INUSE_STS     0x40
-#define SMBHSTSTS_SMBALERT_STS  0x20
-#define SMBHSTSTS_FAILED        0x10
-#define SMBHSTSTS_BUS_ERR       0x08
-#define SMBHSTSTS_DEV_ERR       0x04
-#define SMBHSTSTS_INTR          0x02
-#define SMBHSTSTS_HOST_BUSY     0x01
-
-#define STATUS_FLAGS        (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | SMBHSTSTS_INTR)
-
-/* Older devices have their ID defined in <linux/pci_ids.h> */
-#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS       0x1c22
-#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS          0x1d22
-/* Patsburg also has three 'Integrated Device Function' SMBus controllers */
-#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0     0x1d70
-#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1     0x1d71
-#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2     0x1d72
-#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS      0x1e22
-#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS          0x2330
-#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS     0x3b30
-#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS         0x8c22
-#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS      0x9c22
-
-
-#define FEATURE_SMBUS_PEC       (1 << 0)
-#define FEATURE_BLOCK_BUFFER    (1 << 1)
-#define FEATURE_BLOCK_PROC      (1 << 2)
-#define FEATURE_I2C_BLOCK_READ  (1 << 3)
-/* Not really a feature, but it's convenient to handle it as such */
-#define FEATURE_IDF             (1 << 15)
-
-static unsigned int disable_features;
-module_param(disable_features, uint, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(disable_features, "Disable selected driver features");
-
-// FIXME!
-#undef inb_p
-#define inb_p(a) readq((void*)a)
-#undef outb_p
-#define outb_p(d,a) writeq(d,(void*)a)
-
-/* Make sure the SMBus host is ready to start transmitting.
-   Return 0 if it is, -EBUSY if it is not. */
-static int i801_check_pre(struct i2c_device *priv)
-{
-    int status;
-    
-    dev_dbg(&priv->adapter.dev, "i801_check_pre\n");
-    
-    status = inb_p(SMBHSTSTS(priv));
-    if (status & SMBHSTSTS_HOST_BUSY) {
-        dev_err(&priv->adapter.dev, "SMBus is busy, can't use it! (status=%x)\n", status);
-        return -EBUSY;
-    }
-    
-    status &= STATUS_FLAGS;
-    if (status) {
-        //dev_dbg(&priv->adapter.dev, "Clearing status flags (%02x)\n", status);
-        outb_p(status, SMBHSTSTS(priv));
-        status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
-        if (status) {
-          dev_err(&priv->adapter.dev, "Failed clearing status flags (%02x)\n", status);
-          return -EBUSY;
-        }
-    }
-    return 0;
-}
-
-/* Convert the status register to an error code, and clear it. */
-static int i801_check_post(struct i2c_device *priv, int status, int timeout)
-{
-    int result = 0;
-    
-    dev_dbg(&priv->adapter.dev, "i801_check_post\n");
-    
-    /* If the SMBus is still busy, we give up */
-    if (timeout) {
-        dev_err(&priv->adapter.dev, "Transaction timeout\n");
-        /* try to stop the current command */
-        dev_dbg(&priv->adapter.dev, "Terminating the current operation\n");
-        outb_p(inb_p(SMBHSTCNT(priv)) | SMBHSTCNT_KILL, SMBHSTCNT(priv));
-        usleep_range(1000, 2000);
-        outb_p(inb_p(SMBHSTCNT(priv)) & (~SMBHSTCNT_KILL), SMBHSTCNT(priv));
-        
-        /* Check if it worked */
-        status = inb_p(SMBHSTSTS(priv));
-        if ((status & SMBHSTSTS_HOST_BUSY) || !(status & SMBHSTSTS_FAILED)) {
-            dev_err(&priv->adapter.dev, "Failed terminating the transaction\n");
-        }
-        outb_p(STATUS_FLAGS, SMBHSTSTS(priv));
-        return -ETIMEDOUT;
-    }
-    
-    if (status & SMBHSTSTS_FAILED) {
-        result = -EIO;
-        dev_err(&priv->adapter.dev, "Transaction failed\n");
-    }
-    if (status & SMBHSTSTS_DEV_ERR) {
-        result = -ENXIO;
-        dev_dbg(&priv->adapter.dev, "No response\n");
-    }
-    if (status & SMBHSTSTS_BUS_ERR) {
-        result = -EAGAIN;
-        dev_dbg(&priv->adapter.dev, "Lost arbitration\n");
-    }
-    
-    if (result) {
-        /* Clear error flags */
-        outb_p(status & STATUS_FLAGS, SMBHSTSTS(priv));
-        status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
-        if (status) {
-            dev_warn(&priv->adapter.dev, "Failed clearing status flags at end of transaction (%02x)\n", status);
-        }
-    }
-    
-    return result;
-}
-
-static int i801_transaction(struct i2c_device *priv, int xact)
-{
-    int status;
-    int result;
-    int timeout = 0;
-    
-    dev_dbg(&priv->adapter.dev, "i801_transaction\n");
-    
-    result = i801_check_pre(priv);
-    if (result < 0) {
-        return result;
-    }
-    /* the current contents of SMBHSTCNT can be overwritten, since PEC,
-    * INTREN, SMBSCMD are passed in xact */
-    outb_p(xact | I801_START, SMBHSTCNT(priv));
-    
-    /* We will always wait for a fraction of a second! */
-    do {
-        usleep_range(250, 500);
-        status = inb_p(SMBHSTSTS(priv));
-    } while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_RETRIES));
-    
-    result = i801_check_post(priv, status, timeout > MAX_RETRIES);
-    if (result < 0) {
-        return result;
-    }
-    
-    outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
-    return 0;
-}
-
-/* wait for INTR bit as advised by Intel */
-static void i801_wait_hwpec(struct i2c_device *priv)
-{
-    int timeout = 0;
-    int status;
-    
-    dev_dbg(&priv->adapter.dev, "i801_wait_hwpec\n");
-    
-    do {
-        usleep_range(250, 500);
-        status = inb_p(SMBHSTSTS(priv));
-    } while ((!(status & SMBHSTSTS_INTR)) && (timeout++ < MAX_RETRIES));
-    
-    if (timeout > MAX_RETRIES) {
-        dev_dbg(&priv->adapter.dev, "PEC Timeout!\n");
-    }
-    
-    outb_p(status, SMBHSTSTS(priv));
-}
-
-static int i801_block_transaction_by_block(struct i2c_device *priv, union i2c_smbus_data *data, char read_write, int hwpec)
-{
-    int i, len;
-    int status;
-    
-    dev_dbg(&priv->adapter.dev, "i801_block_transaction_by_block\n");
-    
-    inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
-    
-    /* Use 32-byte buffer to process this transaction */
-    if (read_write == I2C_SMBUS_WRITE) {
-        len = data->block[0];
-        outb_p(len, SMBHSTDAT0(priv));
-        for (i = 0; i < len; i++) {
-            outb_p(data->block[i+1], SMBBLKDAT(priv));
-        }
-    }
-    
-    status = i801_transaction(priv, I801_BLOCK_DATA | ENABLE_INT9 | I801_PEC_EN * hwpec);
-    if (status) {
-        return status;
-    }
-
-    if (read_write == I2C_SMBUS_READ) {
-        len = inb_p(SMBHSTDAT0(priv));
-        if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
-            return -EPROTO;
-        }
-        
-        data->block[0] = len;
-        for (i = 0; i < len; i++) {
-            data->block[i + 1] = inb_p(SMBBLKDAT(priv));
-        }
-    }
-    return 0;
-}
-
-static int i801_block_transaction_byte_by_byte(struct i2c_device *priv, union i2c_smbus_data *data, char read_write, int command, int hwpec)
-{
-    int i, len;
-    int smbcmd;
-    int status;
-    int result;
-    int timeout;
-    
-    dev_dbg(&priv->adapter.dev, "i801_block_transaction_byte_by_byte\n");
-    
-    result = i801_check_pre(priv);
-    if (result < 0) {
-        return result;
-    }
-    
-    len = data->block[0];
-    
-    if (read_write == I2C_SMBUS_WRITE) {
-        outb_p(len, SMBHSTDAT0(priv));
-        outb_p(data->block[1], SMBBLKDAT(priv));
-    }
-    
-    for (i = 1; i <= len; i++) {
-        if (i == len && read_write == I2C_SMBUS_READ) {
-            if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
-                smbcmd = I801_I2C_BLOCK_LAST;
-            } else {
-                smbcmd = I801_BLOCK_LAST;
-            }
-        } else {
-            if (command == I2C_SMBUS_I2C_BLOCK_DATA && read_write == I2C_SMBUS_READ) {
-                smbcmd = I801_I2C_BLOCK_DATA;
-            } else {
-                smbcmd = I801_BLOCK_DATA;
-            }
-        }
-        outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT(priv));
-        
-        if (i == 1) {
-            outb_p(inb(SMBHSTCNT(priv)) | I801_START, SMBHSTCNT(priv));
-        }
-        /* We will always wait for a fraction of a second! */
-        timeout = 0;
-        do {
-            usleep_range(250, 500);
-            status = inb_p(SMBHSTSTS(priv));
-        } while ((!(status & SMBHSTSTS_BYTE_DONE)) && (timeout++ < MAX_RETRIES));
-        
-        result = i801_check_post(priv, status, timeout > MAX_RETRIES);
-        if (result < 0) {
-            return result;
-        }
-        if (i == 1 && read_write == I2C_SMBUS_READ && command != I2C_SMBUS_I2C_BLOCK_DATA) {
-            len = inb_p(SMBHSTDAT0(priv));
-            if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
-                dev_err(&priv->adapter.dev, "Illegal SMBus block read size %d\n", len);
-                /* Recover */
-                while (inb_p(SMBHSTSTS(priv)) & SMBHSTSTS_HOST_BUSY) {
-                    outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
-                }
-                outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
-                return -EPROTO;
-            }
-            data->block[0] = len;
-        }
-        
-        /* Retrieve/store value in SMBBLKDAT */
-        if (read_write == I2C_SMBUS_READ) {
-            data->block[i] = inb_p(SMBBLKDAT(priv));
-        }
-        if (read_write == I2C_SMBUS_WRITE && i+1 <= len) {
-            outb_p(data->block[i+1], SMBBLKDAT(priv));
-        }
-        /* signals SMBBLKDAT ready */
-        outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS(priv));
-    }
-    
-    return 0;
-}
-
-static int i801_set_block_buffer_mode(struct i2c_device *priv)
-{
-    dev_dbg(&priv->adapter.dev, "i801_set_block_buffer_mode\n");
-    
-    outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv));
-    if ((inb_p(SMBAUXCTL(priv)) & SMBAUXCTL_E32B) == 0) {
-        return -EIO;
-    }
-    return 0;
-}
-
-/* Block transaction function */
-static int i801_block_transaction(struct i2c_device *priv, union i2c_smbus_data *data, char read_write, int command, int hwpec)
-{
-    int result = 0;
-    //unsigned char hostc;
-    
-    dev_dbg(&priv->adapter.dev, "i801_block_transaction\n");
-    
-    if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
-        if (read_write == I2C_SMBUS_WRITE) {
-            /* set I2C_EN bit in configuration register */
-            //TODO: Figure out the right thing to do here...
-            //pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc);
-            //pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc | SMBHSTCFG_I2C_EN);
-        } else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) {
-            dev_err(&priv->adapter.dev, "I2C block read is unsupported!\n");
-            return -EOPNOTSUPP;
-        }
-    }
-    
-    if (read_write == I2C_SMBUS_WRITE || command == I2C_SMBUS_I2C_BLOCK_DATA) {
-        if (data->block[0] < 1) {
-            data->block[0] = 1;
-        }
-        if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
-            data->block[0] = I2C_SMBUS_BLOCK_MAX;
-        }
-    } else {
-        data->block[0] = 32;   /* max for SMBus block reads */
-    }
-    
-    /* Experience has shown that the block buffer can only be used for
-        SMBus (not I2C) block transactions, even though the datasheet
-        doesn't mention this limitation. */
-    if ((priv->features & FEATURE_BLOCK_BUFFER) && command != I2C_SMBUS_I2C_BLOCK_DATA && i801_set_block_buffer_mode(priv) == 0) {
-        result = i801_block_transaction_by_block(priv, data, read_write, hwpec);
-    } else {
-        result = i801_block_transaction_byte_by_byte(priv, data, read_write, command, hwpec);
-    }  
-    if (result == 0 && hwpec) {
-        i801_wait_hwpec(priv);
-    }
-    if (command == I2C_SMBUS_I2C_BLOCK_DATA && read_write == I2C_SMBUS_WRITE) {
-        /* restore saved configuration register value */
-        //TODO: Figure out the right thing to do here...
-        //pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc);
-    }
-    return result;
-}
-
-/* Return negative errno on error. */
-static s32 i801_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data)
-{
-    int hwpec;
-    int block = 0;
-    int ret, xact = 0;
-    struct i2c_device *priv = i2c_get_adapdata(adap);
-    
-    dev_dbg(&priv->adapter.dev, "i801_access (addr=%0d)  flags=%x  read_write=%x  command=%x  size=%x",
-      addr, flags, read_write, command, size );
-    
-    hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA;
-    
-    switch (size) {
-        case I2C_SMBUS_QUICK:
-            dev_dbg(&priv->adapter.dev, "  [acc] SMBUS_QUICK\n");
-            outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv));
-            xact = I801_QUICK;
-            break;
-        case I2C_SMBUS_BYTE:
-            dev_dbg(&priv->adapter.dev, "  [acc] SMBUS_BYTE\n");
-            
-            outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv));
-            if (read_write == I2C_SMBUS_WRITE) {
-                outb_p(command, SMBHSTCMD(priv));
-            }
-            xact = I801_BYTE;
-            break;
-        case I2C_SMBUS_BYTE_DATA:
-            dev_dbg(&priv->adapter.dev, "  [acc] SMBUS_BYTE_DATA\n");
-            outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv));
-            outb_p(command, SMBHSTCMD(priv));
-            if (read_write == I2C_SMBUS_WRITE) {
-                outb_p(data->byte, SMBHSTDAT0(priv));
-            }
-            xact = I801_BYTE_DATA;
-            break;
-        case I2C_SMBUS_WORD_DATA:
-            dev_dbg(&priv->adapter.dev, "  [acc] SMBUS_WORD_DATA\n");
-            outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv));
-            outb_p(command, SMBHSTCMD(priv));
-            if (read_write == I2C_SMBUS_WRITE) {
-                outb_p(data->word & 0xff, SMBHSTDAT0(priv));
-                outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
-            }
-            xact = I801_WORD_DATA;
-            break;
-        case I2C_SMBUS_BLOCK_DATA:
-            dev_dbg(&priv->adapter.dev, "  [acc] SMBUS_BLOCK_DATA\n");
-            outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv));
-            outb_p(command, SMBHSTCMD(priv));
-            block = 1;
-            break;
-        case I2C_SMBUS_I2C_BLOCK_DATA:
-            dev_dbg(&priv->adapter.dev, "  [acc] SMBUS_I2C_BLOCK_DATA\n");
-            /* NB: page 240 of ICH5 datasheet shows that the R/#W
-             * bit should be cleared here, even when reading */
-            outb_p((addr & 0x7f) << 1, SMBHSTADD(priv));
-            if (read_write == I2C_SMBUS_READ) {
-                /* NB: page 240 of ICH5 datasheet also shows
-                 * that DATA1 is the cmd field when reading */
-                outb_p(command, SMBHSTDAT1(priv));
-            } else {
-                outb_p(command, SMBHSTCMD(priv));
-            }
-            block = 1;
-            break;
-        default:
-            dev_dbg(&priv->adapter.dev, "  [acc] Unsupported transaction %d\n", size);
-            return -EOPNOTSUPP;
-    }
-    
-    if (hwpec) { /* enable/disable hardware PEC */
-        dev_dbg(&priv->adapter.dev, "  [acc] hwpec: yes\n");
-        outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv));
-    } else {
-        dev_dbg(&priv->adapter.dev, "  [acc] hwpec: no\n");
-        outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC), SMBAUXCTL(priv));
-    }
-    
-    if (block) {
-        //ret = 0;
-        dev_dbg(&priv->adapter.dev, "  [acc] block: yes\n");
-        ret = i801_block_transaction(priv, data, read_write, size, hwpec);
-    } else {
-        dev_dbg(&priv->adapter.dev, "  [acc] block: no\n");
-        ret = i801_transaction(priv, xact | ENABLE_INT9);
-    }
-    
-    /* Some BIOSes don't like it when PEC is enabled at reboot or resume
-       time, so we forcibly disable it after every transaction. Turn off
-       E32B for the same reason. */
-    if (hwpec || block) {
-        dev_dbg(&priv->adapter.dev, "  [acc] hwpec || block\n");
-        outb_p(inb_p(SMBAUXCTL(priv)) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
-    }
-    if (block) {
-        dev_dbg(&priv->adapter.dev, "  [acc] block\n");
-        return ret;
-    }
-    if (ret) {
-        dev_dbg(&priv->adapter.dev, "  [acc] ret %d\n", ret);
-        return ret;
-    }
-    if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK)) {
-        dev_dbg(&priv->adapter.dev, "  [acc] I2C_SMBUS_WRITE || I801_QUICK  -> ret 0\n");
-        return 0;
-    }
-    
-    switch (xact & 0x7f) {
-        case I801_BYTE:  /* Result put in SMBHSTDAT0 */
-        case I801_BYTE_DATA:
-            dev_dbg(&priv->adapter.dev, "  [acc] I801_BYTE or I801_BYTE_DATA\n");
-            data->byte = inb_p(SMBHSTDAT0(priv));
-            break;
-        case I801_WORD_DATA:
-            dev_dbg(&priv->adapter.dev, "  [acc] I801_WORD_DATA\n");
-            data->word = inb_p(SMBHSTDAT0(priv)) + (inb_p(SMBHSTDAT1(priv)) << 8);
-            break;
-    }
-    return 0;
-}
-
-
-
-static u32 i801_func(struct i2c_adapter *adapter)
-{
-    struct i2c_device *priv = i2c_get_adapdata(adapter);
-    
-    /* original settings
-    u32 f = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-      I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-      I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
-      ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
-      ((priv->features & FEATURE_I2C_BLOCK_READ) ?
-       I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0);
-     */
-    
-    // http://lxr.free-electrons.com/source/include/uapi/linux/i2c.h#L85
-    
-    u32 f = 
-        I2C_FUNC_I2C                     | /* 0x00000001 (I enabled this one) */
-        !I2C_FUNC_10BIT_ADDR             | /* 0x00000002 */
-        !I2C_FUNC_PROTOCOL_MANGLING      | /* 0x00000004 */
-        ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | /* 0x00000008 */
-        !I2C_FUNC_SMBUS_BLOCK_PROC_CALL  | /* 0x00008000 */
-        I2C_FUNC_SMBUS_QUICK             | /* 0x00010000 */
-        !I2C_FUNC_SMBUS_READ_BYTE        | /* 0x00020000 */
-        !I2C_FUNC_SMBUS_WRITE_BYTE       | /* 0x00040000 */
-        !I2C_FUNC_SMBUS_READ_BYTE_DATA   | /* 0x00080000 */
-        !I2C_FUNC_SMBUS_WRITE_BYTE_DATA  | /* 0x00100000 */
-        !I2C_FUNC_SMBUS_READ_WORD_DATA   | /* 0x00200000 */
-        !I2C_FUNC_SMBUS_WRITE_WORD_DATA  | /* 0x00400000 */
-        !I2C_FUNC_SMBUS_PROC_CALL        | /* 0x00800000 */
-        !I2C_FUNC_SMBUS_READ_BLOCK_DATA  | /* 0x01000000 */
-        !I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | /* 0x02000000 */
-        ((priv->features & FEATURE_I2C_BLOCK_READ) ? I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0) | /* 0x04000000 */
-        I2C_FUNC_SMBUS_WRITE_I2C_BLOCK   | /* 0x08000000 */
-        
-        I2C_FUNC_SMBUS_BYTE              | /* _READ_BYTE  _WRITE_BYTE */
-        I2C_FUNC_SMBUS_BYTE_DATA         | /* _READ_BYTE_DATA  _WRITE_BYTE_DATA */
-        I2C_FUNC_SMBUS_WORD_DATA         | /* _READ_WORD_DATA  _WRITE_WORD_DATA */
-        I2C_FUNC_SMBUS_BLOCK_DATA        | /* _READ_BLOCK_DATA  _WRITE_BLOCK_DATA */
-        !I2C_FUNC_SMBUS_I2C_BLOCK        | /* _READ_I2C_BLOCK  _WRITE_I2C_BLOCK */
-        !I2C_FUNC_SMBUS_EMUL;              /* _QUICK  _BYTE  _BYTE_DATA  _WORD_DATA  _PROC_CALL  _WRITE_BLOCK_DATA  _I2C_BLOCK _PEC */
-    return f;
-}
-
-static const struct i2c_algorithm smbus_algorithm = {
-    .smbus_xfer     = i801_access,
-    .functionality  = i801_func,
-};
-
-
-
-/********************************
- *** Part 2 - Driver Handlers ***
- ********************************/
-int pi2c_probe(struct platform_device *pldev)
-{
-    int err;
-    struct i2c_device *priv;
-    struct resource *res;
-    
-    dev_dbg(&pldev->dev, "pi2c_probe(pldev = %p '%s')\n", pldev, pldev->name);
-    
-    priv = kzalloc(sizeof(struct i2c_device), GFP_KERNEL);
-    if (!priv) {
-        return -ENOMEM;
-    }
-    
-    i2c_set_adapdata(&priv->adapter, priv);
-    priv->adapter.owner = THIS_MODULE;
-    priv->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
-    priv->adapter.algo = &smbus_algorithm;
-    
-    res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
-    priv->smba = (unsigned long)ioremap_nocache(res->start, resource_size(res));
-    
-    priv->pldev = pldev;
-    pldev->dev.platform_data = priv;
-    
-    priv->features |= FEATURE_IDF;
-    priv->features |= FEATURE_I2C_BLOCK_READ;
-    priv->features |= FEATURE_SMBUS_PEC;
-    priv->features |= FEATURE_BLOCK_BUFFER;
-    
-    //init_MUTEX(&lddata->sem);
-    init_rwsem(&priv->rw_sem);
-    
-    /* set up the sysfs linkage to our parent device */
-    priv->adapter.dev.parent = &pldev->dev;
-    
-    /* Retry up to 3 times on lost arbitration */
-    priv->adapter.retries = 3;
-    
-    //snprintf(priv->adapter.name, sizeof(priv->adapter.name), "Fake SMBus I801 adapter at %04lx", priv->smba);
-    snprintf(priv->adapter.name, sizeof(priv->adapter.name), "Fake SMBus I801 adapter");
-    
-    err = i2c_add_adapter(&priv->adapter);
-    if (err) {
-        dev_err(&priv->adapter.dev, "Failed to add SMBus adapter\n");
-        return err;
-    }
-    
-    return 0;
-}
-
-int pi2c_remove(struct platform_device *pldev)
-{
-    struct i2c_device *lddev;
-    dev_dbg(&pldev->dev, "pi2c_remove(pldev = %p '%s')\n", pldev, pldev->name);
-    
-    lddev = (struct i2c_device *)pldev->dev.platform_data;
-    
-    i2c_del_adapter(&lddev->adapter);
-    
-    //TODO: Figure out the right thing to do here...
-    //pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
-    //pci_release_region(dev, SMBBAR);
-    //pci_set_drvdata(dev, NULL);
-    
-    //cdev_del(&lddev->cdev);
-    if(lddev != 0) {
-        kfree(lddev);
-        pldev->dev.platform_data = 0;
-    }
-    
-    return 0;
-}
-
-struct platform_driver i2c_plat_driver_i = {
-    .probe      = pi2c_probe,
-    .remove     = pi2c_remove,
-    .driver     = {
-        .name   = KP_DRIVER_NAME_I2C,
-        .owner  = THIS_MODULE,
-    },
-};
-
-module_platform_driver(i2c_plat_driver_i);
diff --git a/drivers/staging/kpc2000/kpc_spi/Makefile b/drivers/staging/kpc2000/kpc_spi/Makefile
deleted file mode 100644 (file)
index 3018d20..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-obj-m += kpc2000_spi.o
-kpc2000_spi-objs := spi_driver.o
diff --git a/drivers/staging/kpc2000/kpc_spi/spi_driver.c b/drivers/staging/kpc2000/kpc_spi/spi_driver.c
deleted file mode 100644 (file)
index 86df165..0000000
+++ /dev/null
@@ -1,507 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * KP2000 SPI controller driver
- *
- * Copyright (C) 2014-2018 Daktronics
- * Author: Matt Sickler <matt.sickler@daktronics.com>
- * Very loosely based on spi-omap2-mcspi.c
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io-64-nonatomic-lo-hi.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/gcd.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/flash.h>
-#include <linux/mtd/partitions.h>
-
-#include "../kpc.h"
-#include "spi_parts.h"
-
-
-/***************
- * SPI Defines *
- ***************/
-#define KP_SPI_REG_CONFIG 0x0 /* 0x00 */
-#define KP_SPI_REG_STATUS 0x1 /* 0x08 */
-#define KP_SPI_REG_FFCTRL 0x2 /* 0x10 */
-#define KP_SPI_REG_TXDATA 0x3 /* 0x18 */
-#define KP_SPI_REG_RXDATA 0x4 /* 0x20 */
-
-#define KP_SPI_CLK           48000000
-#define KP_SPI_MAX_FIFODEPTH 64
-#define KP_SPI_MAX_FIFOWCNT  0xFFFF
-
-#define KP_SPI_REG_CONFIG_TRM_TXRX 0
-#define KP_SPI_REG_CONFIG_TRM_RX   1
-#define KP_SPI_REG_CONFIG_TRM_TX   2
-
-#define KP_SPI_REG_STATUS_RXS   0x01
-#define KP_SPI_REG_STATUS_TXS   0x02
-#define KP_SPI_REG_STATUS_EOT   0x04
-#define KP_SPI_REG_STATUS_TXFFE 0x10
-#define KP_SPI_REG_STATUS_TXFFF 0x20
-#define KP_SPI_REG_STATUS_RXFFE 0x40
-#define KP_SPI_REG_STATUS_RXFFF 0x80
-
-
-
-/******************
- * SPI Structures *
- ******************/
-struct kp_spi {
-       struct spi_master  *master;
-       u64 __iomem        *base;
-       unsigned long       phys;
-       struct device      *dev;
-       int                 fifo_depth;
-       unsigned int        pin_dir:1;
-};
-
-
-struct kp_spi_controller_state {
-    void __iomem   *base;
-    unsigned long   phys;
-    unsigned char   chip_select;
-    int             word_len;
-    s64             conf_cache;
-};
-
-
-union kp_spi_config {
-    /* use this to access individual elements */
-    struct __attribute__((packed)) spi_config_bitfield {
-        unsigned int pha       : 1; /* spim_clk Phase      */
-        unsigned int pol       : 1; /* spim_clk Polarity   */
-        unsigned int epol      : 1; /* spim_csx Polarity   */
-        unsigned int dpe       : 1; /* Transmission Enable */
-        unsigned int wl        : 5; /* Word Length         */
-        unsigned int           : 3;
-        unsigned int trm       : 2; /* TxRx Mode           */
-        unsigned int cs        : 4; /* Chip Select         */
-        unsigned int wcnt      : 7; /* Word Count          */
-        unsigned int ffen      : 1; /* FIFO Enable         */
-        unsigned int spi_en    : 1; /* SPI Enable          */
-        unsigned int           : 5;
-    } bitfield;
-    /* use this to grab the whole register */
-    u32 reg;
-};
-
-
-
-union kp_spi_status {
-    struct __attribute__((packed)) spi_status_bitfield {
-        unsigned int rx    :  1; /* Rx Status       */
-        unsigned int tx    :  1; /* Tx Status       */
-        unsigned int eo    :  1; /* End of Transfer */
-        unsigned int       :  1;
-        unsigned int txffe :  1; /* Tx FIFO Empty   */
-        unsigned int txfff :  1; /* Tx FIFO Full    */
-        unsigned int rxffe :  1; /* Rx FIFO Empty   */
-        unsigned int rxfff :  1; /* Rx FIFO Full    */
-        unsigned int       : 24;
-    } bitfield;
-    u32 reg;
-};
-
-
-
-union kp_spi_ffctrl {
-    struct __attribute__((packed)) spi_ffctrl_bitfield {
-        unsigned int ffstart :  1; /* FIFO Start */
-        unsigned int         : 31;
-    } bitfield;
-    u32 reg;
-};
-
-
-
-/***************
- * SPI Helpers *
- ***************/
-static inline int
-kp_spi_bytes_per_word(int word_len)
-{
-    if (word_len <= 8){
-        return 1;
-    }
-    else if (word_len <= 16) {
-        return 2;
-    }
-    else { /* word_len <= 32 */
-        return 4;
-    }
-}
-
-static inline u64
-kp_spi_read_reg(struct kp_spi_controller_state *cs, int idx)
-{
-    u64 __iomem *addr = cs->base;
-    u64 val;
-
-    addr += idx;
-    if ((idx == KP_SPI_REG_CONFIG) && (cs->conf_cache >= 0)){
-        return cs->conf_cache;
-    }
-    val = readq((void*)addr);
-    return val;
-}
-
-static inline void
-kp_spi_write_reg(struct kp_spi_controller_state *cs, int idx, u64 val)
-{
-    u64 __iomem *addr = cs->base;
-    addr += idx;
-    writeq(val, (void*)addr);
-    if (idx == KP_SPI_REG_CONFIG)
-        cs->conf_cache = val;
-}
-
-static int
-kp_spi_wait_for_reg_bit(struct kp_spi_controller_state *cs, int idx, unsigned long bit)
-{
-    unsigned long timeout;
-    timeout = jiffies + msecs_to_jiffies(1000);
-    while (!(kp_spi_read_reg(cs, idx) & bit)) {
-        if (time_after(jiffies, timeout)) {
-            if (!(kp_spi_read_reg(cs, idx) & bit)) {
-                return -ETIMEDOUT;
-            } else {
-                return 0;
-            }
-        }
-        cpu_relax();
-    }
-    return 0;
-}
-
-static unsigned
-kp_spi_txrx_pio(struct spi_device *spidev, struct spi_transfer *transfer)
-{
-    struct kp_spi_controller_state *cs = spidev->controller_state;
-    unsigned int count = transfer->len;
-    unsigned int c = count;
-    
-    int i;
-    u8 *rx       = transfer->rx_buf;
-    const u8 *tx = transfer->tx_buf;
-    int processed = 0;
-    
-    if (tx) {
-        for (i = 0 ; i < c ; i++) {
-            char val = *tx++;
-            
-            if (kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS, KP_SPI_REG_STATUS_TXS) < 0) {
-                goto out;
-            }
-            
-            kp_spi_write_reg(cs, KP_SPI_REG_TXDATA, val);
-            processed++;
-        }
-    }
-    else if(rx) {
-        for (i = 0 ; i < c ; i++) {
-            char test=0;
-            
-            kp_spi_write_reg(cs, KP_SPI_REG_TXDATA, 0x00);
-            
-            if (kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS, KP_SPI_REG_STATUS_RXS) < 0) {
-                goto out;
-            }
-            
-            test = kp_spi_read_reg(cs, KP_SPI_REG_RXDATA);
-            *rx++ = test;
-            processed++;
-        }
-    }
-    
-    if (kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS, KP_SPI_REG_STATUS_EOT) < 0) {
-        //TODO: Figure out how to abort transaction??  This has never happened in practice though...
-    }
-    
- out:
-    return processed;
-}
-
-/*****************
- * SPI Functions *
- *****************/
-static int
-kp_spi_setup(struct spi_device *spidev)
-{
-    union kp_spi_config sc;
-    struct kp_spi *kpspi = spi_master_get_devdata(spidev->master);
-    struct kp_spi_controller_state *cs;
-    
-    /* setup controller state */
-    cs = spidev->controller_state;
-    if (!cs) {
-        cs = kzalloc(sizeof(*cs), GFP_KERNEL);
-        if(!cs) {
-            return -ENOMEM;
-        }
-        cs->base = kpspi->base;
-        cs->phys = kpspi->phys;
-        cs->chip_select = spidev->chip_select;
-        cs->word_len = spidev->bits_per_word;
-        cs->conf_cache = -1;
-        spidev->controller_state = cs;
-    }
-    
-    /* set config register */
-    sc.bitfield.wl = spidev->bits_per_word - 1;
-    sc.bitfield.cs = spidev->chip_select;
-    sc.bitfield.spi_en = 0;
-    sc.bitfield.trm = 0;
-    sc.bitfield.ffen = 0;
-    kp_spi_write_reg(spidev->controller_state, KP_SPI_REG_CONFIG, sc.reg);
-    return 0;
-}
-
-static int
-kp_spi_transfer_one_message(struct spi_master *master, struct spi_message *m)
-{
-    struct kp_spi_controller_state *cs;
-    struct spi_device   *spidev;
-    struct kp_spi       *kpspi;
-    struct spi_transfer *transfer;
-    union kp_spi_config sc;
-    int status = 0;
-    
-    spidev = m->spi;
-    kpspi = spi_master_get_devdata(master);
-    m->actual_length = 0;
-    m->status = 0;
-    
-    cs = spidev->controller_state;
-    
-    /* reject invalid messages and transfers */
-    if (list_empty(&m->transfers)) {
-        return -EINVAL;
-    }
-    
-    /* validate input */
-    list_for_each_entry(transfer, &m->transfers, transfer_list) {
-        const void *tx_buf = transfer->tx_buf;
-        void       *rx_buf = transfer->rx_buf;
-        unsigned    len = transfer->len;
-        
-        if (transfer->speed_hz > KP_SPI_CLK || (len && !(rx_buf || tx_buf))) {
-            dev_dbg(kpspi->dev, "  transfer: %d Hz, %d %s%s, %d bpw\n",
-                    transfer->speed_hz,
-                    len,
-                    tx_buf ? "tx" : "",
-                    rx_buf ? "rx" : "",
-                    transfer->bits_per_word);
-            dev_dbg(kpspi->dev, "  transfer -EINVAL\n");
-            return -EINVAL;
-        }
-        if (transfer->speed_hz && (transfer->speed_hz < (KP_SPI_CLK >> 15))) {
-            dev_dbg(kpspi->dev, "speed_hz %d below minimum %d Hz\n",
-                    transfer->speed_hz,
-                    KP_SPI_CLK >> 15);
-            dev_dbg(kpspi->dev, "  speed_hz -EINVAL\n");
-            return -EINVAL;
-        }
-    }
-    
-    /* assert chip select to start the sequence*/
-    sc.reg = kp_spi_read_reg(cs, KP_SPI_REG_CONFIG);
-    sc.bitfield.spi_en = 1;
-    kp_spi_write_reg(cs, KP_SPI_REG_CONFIG, sc.reg);
-    
-    /* work */
-    if (kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS, KP_SPI_REG_STATUS_EOT) < 0) {
-        dev_info(kpspi->dev, "EOT timed out\n");
-        goto out;
-    }
-    
-    /* do the transfers for this message */
-    list_for_each_entry(transfer, &m->transfers, transfer_list) {
-        if (transfer->tx_buf == NULL && transfer->rx_buf == NULL && transfer->len) {
-            status = -EINVAL;
-            break;
-        }
-        
-        /* transfer */
-        if (transfer->len) {
-            unsigned int word_len = spidev->bits_per_word;
-            unsigned count;
-            
-            /* set up the transfer... */
-            sc.reg = kp_spi_read_reg(cs, KP_SPI_REG_CONFIG);
-            
-            /* ...direction */
-            if (transfer->tx_buf) {
-                sc.bitfield.trm = KP_SPI_REG_CONFIG_TRM_TX;
-            }
-            else if (transfer->rx_buf) {
-                sc.bitfield.trm = KP_SPI_REG_CONFIG_TRM_RX;
-            }
-            
-            /* ...word length */
-            if (transfer->bits_per_word) {
-                word_len = transfer->bits_per_word;
-            }
-            cs->word_len = word_len;
-            sc.bitfield.wl = word_len-1;
-            
-            /* ...chip select */
-            sc.bitfield.cs = spidev->chip_select;
-            
-            /* ...and write the new settings */
-            kp_spi_write_reg(cs, KP_SPI_REG_CONFIG, sc.reg);
-            
-            /* do the transfer */
-            count = kp_spi_txrx_pio(spidev, transfer);
-            m->actual_length += count;
-            
-            if (count != transfer->len) {
-                status = -EIO;
-                break;
-            }
-        }
-        
-        if (transfer->delay_usecs) {
-            udelay(transfer->delay_usecs);
-        }
-    }
-    
-    /* de-assert chip select to end the sequence */
-    sc.reg = kp_spi_read_reg(cs, KP_SPI_REG_CONFIG);
-    sc.bitfield.spi_en = 0;
-    kp_spi_write_reg(cs, KP_SPI_REG_CONFIG, sc.reg);
-    
- out:
-    /* done work */
-    spi_finalize_current_message(master);
-    return 0;
-}
-
-static void
-kp_spi_cleanup(struct spi_device *spidev)
-{
-    struct kp_spi_controller_state *cs = spidev->controller_state;
-    if (cs) {
-        kfree(cs);
-    }
-}
-
-
-
-/******************
- * Probe / Remove *
- ******************/
-static int
-kp_spi_probe(struct platform_device *pldev)
-{
-    struct kpc_core_device_platdata *drvdata;
-    struct spi_master *master;
-    struct kp_spi *kpspi;
-    struct resource *r;
-    int status = 0;
-    int i;
-
-    drvdata = pldev->dev.platform_data;
-    if (!drvdata){
-        dev_err(&pldev->dev, "kp_spi_probe: platform_data is NULL!\n");
-        return -ENODEV;
-    }
-    
-    master = spi_alloc_master(&pldev->dev, sizeof(struct kp_spi));
-    if (master == NULL) {
-        dev_err(&pldev->dev, "kp_spi_probe: master allocation failed\n");
-        return -ENOMEM;
-    }
-    
-    /* set up the spi functions */
-    master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
-    master->bits_per_word_mask = (unsigned int)SPI_BPW_RANGE_MASK(4, 32);
-    master->setup = kp_spi_setup;
-    master->transfer_one_message = kp_spi_transfer_one_message;
-    master->cleanup = kp_spi_cleanup;
-    
-    platform_set_drvdata(pldev, master);
-    
-    kpspi = spi_master_get_devdata(master);
-    kpspi->master = master;
-    kpspi->dev = &pldev->dev;
-    
-    master->num_chipselect = 4;
-    if (pldev->id != -1) {
-        master->bus_num = pldev->id;
-    }
-    kpspi->pin_dir = 0;
-    
-    r = platform_get_resource(pldev, IORESOURCE_MEM, 0);
-    if (r == NULL) {
-        dev_err(&pldev->dev, "kp_spi_probe: Unable to get platform resources\n");
-        status = -ENODEV;
-        goto free_master;
-    }
-    
-    kpspi->phys = (unsigned long)ioremap_nocache(r->start, resource_size(r));
-    kpspi->base = (u64 __iomem *)kpspi->phys;
-    
-    status = spi_register_master(master);
-    if (status < 0) {
-        dev_err(&pldev->dev, "Unable to register SPI device\n");
-        goto free_master;
-    }
-    
-    /* register the slave boards */
-    #define NEW_SPI_DEVICE_FROM_BOARD_INFO_TABLE(table) \
-        for (i = 0 ; i < ARRAY_SIZE(table) ; i++) { \
-            spi_new_device(master, &(table[i])); \
-        }
-    
-    switch ((drvdata->card_id & 0xFFFF0000) >> 16){
-        case PCI_DEVICE_ID_DAKTRONICS_KADOKA_P2KR0:
-            NEW_SPI_DEVICE_FROM_BOARD_INFO_TABLE(p2kr0_board_info);
-            break;
-        default:
-            dev_err(&pldev->dev, "Unknown hardware, cant know what partition table to use!\n");
-            goto free_master;
-            break;
-    }
-    
-    return status;
-
- free_master:
-    spi_master_put(master);
-    return status;
-}
-
-static int
-kp_spi_remove(struct platform_device *pldev)
-{
-    struct spi_master * master = platform_get_drvdata(pldev);
-    spi_unregister_master(master);
-    return 0;
-}
-
-
-static struct platform_driver kp_spi_driver = {
-    .driver = {
-        .name =     KP_DRIVER_NAME_SPI,
-    },
-    .probe =    kp_spi_probe,
-    .remove =   kp_spi_remove,
-};
-
-module_platform_driver(kp_spi_driver);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:kp_spi");
diff --git a/drivers/staging/kpc2000/kpc_spi/spi_parts.h b/drivers/staging/kpc2000/kpc_spi/spi_parts.h
deleted file mode 100644 (file)
index 33e62ac..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-#ifndef __KPC_SPI_SPI_PARTS_H__
-#define __KPC_SPI_SPI_PARTS_H__
-
-static struct mtd_partition p2kr0_spi0_parts[] = {
-    { .name = "SLOT_0",    .size = 7798784,          .offset = 0,                 },
-    { .name = "SLOT_1",    .size = 7798784,          .offset = MTDPART_OFS_NXTBLK },
-    { .name = "SLOT_2",    .size = 7798784,          .offset = MTDPART_OFS_NXTBLK },
-    { .name = "SLOT_3",    .size = 7798784,          .offset = MTDPART_OFS_NXTBLK },
-    { .name = "CS0_EXTRA", .size = MTDPART_SIZ_FULL, .offset = MTDPART_OFS_NXTBLK }
-};
-static struct mtd_partition p2kr0_spi1_parts[] = {
-    { .name = "SLOT_4",    .size   = 7798784,          .offset = 0,                 },
-    { .name = "SLOT_5",    .size   = 7798784,          .offset = MTDPART_OFS_NXTBLK },
-    { .name = "SLOT_6",    .size   = 7798784,          .offset = MTDPART_OFS_NXTBLK },
-    { .name = "SLOT_7",    .size   = 7798784,          .offset = MTDPART_OFS_NXTBLK },
-    { .name = "CS1_EXTRA", .size   = MTDPART_SIZ_FULL, .offset = MTDPART_OFS_NXTBLK }
-};
-
-static struct flash_platform_data p2kr0_spi0_pdata = {
-    .name = "SPI0",
-    .nr_parts = ARRAY_SIZE(p2kr0_spi0_parts),
-    .parts = p2kr0_spi0_parts,
-};
-static struct flash_platform_data p2kr0_spi1_pdata = {
-    .name = "SPI1",
-    .nr_parts = ARRAY_SIZE(p2kr0_spi1_parts),
-    .parts = p2kr0_spi1_parts,
-};
-
-static struct spi_board_info p2kr0_board_info[] = {
-    {
-        .modalias = "n25q256a11",
-        .bus_num = 1,
-        .chip_select = 0,
-        .mode = SPI_MODE_0,
-        .platform_data = &p2kr0_spi0_pdata
-    },
-    {
-        .modalias = "n25q256a11",
-        .bus_num = 1,
-        .chip_select = 1,
-        .mode = SPI_MODE_0,
-        .platform_data = &p2kr0_spi1_pdata
-    },
-};
-
-#endif
index 74551eb..4b37954 100644 (file)
@@ -380,7 +380,7 @@ int ks_wlan_hw_tx(struct ks_wlan_private *priv, void *p, unsigned long size,
                                           struct sk_buff *skb),
                  struct sk_buff *skb)
 {
-       int result = 0;
+       int result;
        struct hostif_hdr *hdr;
 
        hdr = (struct hostif_hdr *)p;
index e089366..2666f9e 100644 (file)
@@ -1067,7 +1067,6 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb)
        unsigned int length = 0;
        struct hostif_data_request *pp;
        unsigned char *p;
-       int result = 0;
        unsigned short eth_proto;
        struct ether_hdr *eth_hdr;
        unsigned short keyinfo = 0;
@@ -1209,8 +1208,8 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb)
        pp->header.event = cpu_to_le16(HIF_DATA_REQ);
 
        /* tx request */
-       result = ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp) + skb_len),
-                              send_packet_complete, skb);
+       ret = ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp) + skb_len),
+                           send_packet_complete, skb);
 
        /* MIC FAILURE REPORT check */
        if (eth_proto == ETH_P_PAE &&
@@ -1225,7 +1224,7 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb)
                        priv->wpa.mic_failure.stop = 1;
        }
 
-       return result;
+       return ret;
 
 err_kfree:
        kfree(pp);
index 25b3e18..2bf8114 100644 (file)
@@ -31,13 +31,13 @@ Description:
                                or output
 
                dbr_size        configure DBR data buffer size (this is used
-                               for MediaLB communiction only)
+                               for MediaLB communication only)
 
                packets_per_xact
                                configure the number of packets that will be
                                collected from the network before being
                                transmitted via USB (this is used for USB
-                               communiction only)
+                               communication only)
 
                device          name of the device the link is to be attached to
 
@@ -75,13 +75,13 @@ Description:
                                or output
 
                dbr_size        configure DBR data buffer size (this is used
-                               for MediaLB communiction only)
+                               for MediaLB communication only)
 
                packets_per_xact
                                configure the number of packets that will be
                                collected from the network before being
                                transmitted via USB (this is used for USB
-                               communiction only)
+                               communication only)
 
                device          name of the device the link is to be attached to
 
@@ -119,13 +119,13 @@ Description:
                                or output
 
                dbr_size        configure DBR data buffer size (this is used
-                               for MediaLB communiction only)
+                               for MediaLB communication only)
 
                packets_per_xact
                                configure the number of packets that will be
                                collected from the network before being
                                transmitted via USB (this is used for USB
-                               communiction only)
+                               communication only)
 
                device          name of the device the link is to be attached to
 
@@ -173,13 +173,13 @@ Description:
                                or output
 
                dbr_size        configure DBR data buffer size (this is used
-                               for MediaLB communiction only)
+                               for MediaLB communication only)
 
                packets_per_xact
                                configure the number of packets that will be
                                collected from the network before being
                                transmitted via USB (this is used for USB
-                               communiction only)
+                               communication only)
 
                device          name of the device the link is to be attached to
 
index 56d7919..2fa8dea 100644 (file)
@@ -42,7 +42,7 @@ the attached network interface controller hardware. Hence, a given module
 of this layer is designed to handle exactly one of the peripheral
 interfaces (e.g. USB, MediaLB, I2C) the hardware provides.
 
-A module of the application layer is referred to as a core comoponent,
+A module of the application layer is referred to as a core component,
 which kind of extends the core by providing connectivity to the user space.
 Applications, then, can access a MOST network via character devices, an
 ALSA soundcard, a Network adapter or a V4L2 capture device.
@@ -119,7 +119,7 @@ following components are available
 
 The driver is to be configured via configfs. Each loaded component kernel
 object (see section 1.3) registers a subsystem with configfs, which is used to
-configure and establish communiction pathways (links) to attached devices on
+configure and establish communication pathways (links) to attached devices on
 the bus. To do so, the user has to descend into the component's configuration
 directory and create a new directory (child config itmes). The name of this
 directory will be used as a reference for the link and it will contain the
@@ -137,12 +137,12 @@ following attributes:
        - direction
          configure whether this link will be an input or output
        - dbr_size
-         configure DBR data buffer size (this is used for MediaLB communiction
+         configure DBR data buffer size (this is used for MediaLB communication
          only)
        - packets_per_xact
          configure the number of packets that will be collected from the
          network before being transmitted via USB (this is used for USB
-         communiction only)
+         communication only)
        - device
          name of the device the link is to be attached to
        - channel
index db32ea7..8948d52 100644 (file)
@@ -3,7 +3,7 @@ menuconfig MOST
         tristate "MOST support"
        depends on HAS_DMA && CONFIGFS_FS
         default n
-        ---help---
+        help
          Say Y here if you want to enable MOST support.
          This driver needs at least one additional component to enable the
          desired access from userspace (e.g. character devices) and one that
index 1d8bf29..0254956 100644 (file)
@@ -35,56 +35,42 @@ static struct list_head mdev_link_list;
 
 static int set_cfg_buffer_size(struct mdev_link *link)
 {
-       if (!link->buffer_size)
-               return -ENODATA;
        return most_set_cfg_buffer_size(link->device, link->channel,
                                        link->buffer_size);
 }
 
 static int set_cfg_subbuffer_size(struct mdev_link *link)
 {
-       if (!link->subbuffer_size)
-               return -ENODATA;
        return most_set_cfg_subbuffer_size(link->device, link->channel,
                                           link->subbuffer_size);
 }
 
 static int set_cfg_dbr_size(struct mdev_link *link)
 {
-       if (!link->dbr_size)
-               return -ENODATA;
        return most_set_cfg_dbr_size(link->device, link->channel,
                                     link->dbr_size);
 }
 
 static int set_cfg_num_buffers(struct mdev_link *link)
 {
-       if (!link->num_buffers)
-               return -ENODATA;
        return most_set_cfg_num_buffers(link->device, link->channel,
                                        link->num_buffers);
 }
 
 static int set_cfg_packets_xact(struct mdev_link *link)
 {
-       if (!link->packets_per_xact)
-               return -ENODATA;
        return most_set_cfg_packets_xact(link->device, link->channel,
                                         link->packets_per_xact);
 }
 
 static int set_cfg_direction(struct mdev_link *link)
 {
-       if (!strlen(link->direction))
-               return -ENODATA;
        return most_set_cfg_direction(link->device, link->channel,
                                      link->direction);
 }
 
 static int set_cfg_datatype(struct mdev_link *link)
 {
-       if (!strlen(link->datatype))
-               return -ENODATA;
        return most_set_cfg_datatype(link->device, link->channel,
                                     link->datatype);
 }
index 86a8545..b9841ad 100644 (file)
@@ -561,13 +561,6 @@ static int split_string(char *buf, char **a, char **b, char **c, char **d)
        return 0;
 }
 
-static int match_bus_dev(struct device *dev, void *data)
-{
-       char *mdev_name = data;
-
-       return !strcmp(dev_name(dev), mdev_name);
-}
-
 /**
  * get_channel - get pointer to channel
  * @mdev: name of the device interface
@@ -579,7 +572,7 @@ static struct most_channel *get_channel(char *mdev, char *mdev_ch)
        struct most_interface *iface;
        struct most_channel *c, *tmp;
 
-       dev = bus_find_device(&mc.bus, NULL, mdev, match_bus_dev);
+       dev = bus_find_device_by_name(&mc.bus, NULL, mdev);
        if (!dev)
                return NULL;
        iface = to_most_interface(dev);
index c8a64e2..aababdf 100644 (file)
@@ -507,13 +507,24 @@ static struct core_component comp = {
 
 static int __init most_net_init(void)
 {
+       int err;
+
        spin_lock_init(&list_lock);
        mutex_init(&probe_disc_mt);
-       return most_register_component(&comp);
+       err = most_register_component(&comp);
+       if (err)
+               return err;
+       err = most_register_configfs_subsys(&comp);
+       if (err) {
+               most_deregister_component(&comp);
+               return err;
+       }
+       return 0;
 }
 
 static void __exit most_net_exit(void)
 {
+       most_deregister_configfs_subsys(&comp);
        most_deregister_component(&comp);
 }
 
index adca250..6f6e98a 100644 (file)
@@ -250,11 +250,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(cap->card, "MOST", sizeof(cap->card));
        snprintf(cap->bus_info, sizeof(cap->bus_info),
                 "%s", mdev->iface->description);
-
-       cap->capabilities =
-               V4L2_CAP_READWRITE |
-               V4L2_CAP_TUNER |
-               V4L2_CAP_VIDEO_CAPTURE;
        return 0;
 }
 
@@ -366,6 +361,7 @@ static const struct video_device comp_videodev_template = {
        .release = video_device_release,
        .ioctl_ops = &video_ioctl_ops,
        .tvnorms = V4L2_STD_UNKNOWN,
+       .device_caps = V4L2_CAP_READWRITE | V4L2_CAP_VIDEO_CAPTURE,
 };
 
 /**************************************************************************/
@@ -540,8 +536,18 @@ static struct core_component comp = {
 
 static int __init comp_init(void)
 {
+       int err;
+
        spin_lock_init(&list_lock);
-       return most_register_component(&comp);
+       err = most_register_component(&comp);
+       if (err)
+               return err;
+       err = most_register_configfs_subsys(&comp);
+       if (err) {
+               most_deregister_component(&comp);
+               return err;
+       }
+       return 0;
 }
 
 static void __exit comp_exit(void)
@@ -566,6 +572,7 @@ static void __exit comp_exit(void)
        }
        spin_unlock_irq(&list_lock);
 
+       most_deregister_configfs_subsys(&comp);
        most_deregister_component(&comp);
        BUG_ON(!list_empty(&video_devices));
 }
index 0fbb993..60db067 100644 (file)
@@ -468,7 +468,7 @@ static struct dma_async_tx_descriptor *mtk_hsdma_prep_dma_memcpy(
        if (len <= 0)
                return NULL;
 
-       desc = kzalloc(sizeof(struct mtk_hsdma_desc), GFP_ATOMIC);
+       desc = kzalloc(sizeof(*desc), GFP_ATOMIC);
        if (!desc) {
                dev_err(c->device->dev, "alloc memcpy decs error\n");
                return NULL;
@@ -664,9 +664,8 @@ static int mtk_hsdma_probe(struct platform_device *pdev)
                return -EINVAL;
 
        hsdma = devm_kzalloc(&pdev->dev, sizeof(*hsdma), GFP_KERNEL);
-       if (!hsdma) {
+       if (!hsdma)
                return -EINVAL;
-       }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        base = devm_ioremap_resource(&pdev->dev, res);
index 3ea08ab..6932ab7 100644 (file)
@@ -1,6 +1,11 @@
 # SPDX-License-Identifier: GPL-2.0
 config DTB_GNUBEE1
-       bool "GnuBee1 NAS"
+       bool "GnuBee1 2.5inch NAS"
+       depends on SOC_MT7621 && DTB_RT_NONE
+       select BUILTIN_DTB
+
+config DTB_GNUBEE2
+       bool "GnuBee2 3.5inch NAS"
        depends on SOC_MT7621 && DTB_RT_NONE
        select BUILTIN_DTB
 
index aeec48a..b4ab99f 100644 (file)
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 dtb-$(CONFIG_DTB_GNUBEE1)      += gbpc1.dtb
+dtb-$(CONFIG_DTB_GNUBEE2)      += gbpc2.dtb
 
 obj-y                          += $(patsubst %.dtb, %.dtb.o, $(dtb-y))
index 1580313..1b758e5 100644 (file)
@@ -2,4 +2,4 @@
 - ensure all usage matches code
 - ensure all features used are documented
 
-Cc: NeilBrown <neil@brown.name>
\ No newline at end of file
+Cc: NeilBrown <neil@brown.name>
index 250c15a..1fb560f 100644 (file)
 
 &pinctrl {
        state_default: pinctrl0 {
-               gpio {
+               default_gpio: gpio {
                        groups = "wdt", "rgmii2", "uart3";
                        function = "gpio";
                };
diff --git a/drivers/staging/mt7621-dts/gbpc2.dts b/drivers/staging/mt7621-dts/gbpc2.dts
new file mode 100644 (file)
index 0000000..52760e7
--- /dev/null
@@ -0,0 +1,21 @@
+/dts-v1/;
+
+#include "gbpc1.dts"
+
+/ {
+       compatible = "gnubee,gb-pc2", "mediatek,mt7621-soc";
+       model = "GB-PC2";
+};
+
+&default_gpio {
+       groups = "wdt", "uart3";
+       function = "gpio";
+};
+
+&gmac1 {
+       status = "ok";
+};
+
+&phy_external {
+       status = "ok";
+};
index 280ec33..a4c0811 100644 (file)
@@ -1,4 +1,5 @@
 #include <dt-bindings/interrupt-controller/mips-gic.h>
+#include <dt-bindings/gpio/gpio.h>
 
 / {
        #address-cells = <1>;
                clock-frequency = <220000000>;
        };
 
+       mmc_clock: mmc_clock@0 {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <48000000>;
+       };
+
+       mmc_fixed_3v3: fixedregulator@0 {
+               compatible = "regulator-fixed";
+               regulator-name = "mmc_power";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               enable-active-high;
+               regulator-always-on;
+         };
+
+         mmc_fixed_1v8_io: fixedregulator@1 {
+               compatible = "regulator-fixed";
+               regulator-name = "mmc_io";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               enable-active-high;
+               regulator-always-on;
+       };
+
        palmbus: palmbus@1E000000 {
                compatible = "palmbus";
                reg = <0x1E000000 0x100000>;
        sdhci: sdhci@1E130000 {
                status = "disabled";
 
-               compatible = "ralink,mt7620-sdhci";
+               compatible = "mediatek,mt7620-mmc";
                reg = <0x1E130000 0x4000>;
 
+               bus-width = <4>;
+               max-frequency = <48000000>;
+               cap-sd-highspeed;
+               cap-mmc-highspeed;
+               vmmc-supply = <&mmc_fixed_3v3>;
+               vqmmc-supply = <&mmc_fixed_1v8_io>;
+               disable-wp;
+
+               pinctrl-names = "default", "state_uhs";
+               pinctrl-0 = <&sdhci_pins>;
+               pinctrl-1 = <&sdhci_pins>;
+
+               clocks = <&mmc_clock &mmc_clock>;
+               clock-names = "source", "hclk";
+
                interrupt-parent = <&gic>;
                interrupts = <GIC_SHARED 20 IRQ_TYPE_LEVEL_HIGH>;
        };
                        compatible = "mediatek,eth-mac";
                        reg = <1>;
                        status = "off";
-                       phy-mode = "rgmii";
-                       phy-handle = <&phy5>;
+                       phy-mode = "rgmii-rxid";
+                       phy-handle = <&phy_external>;
                };
                mdio-bus {
                        #address-cells = <1>;
                        #size-cells = <0>;
 
-                       phy5: ethernet-phy@5 {
+                       phy_external: ethernet-phy@5 {
+                               status = "off";
                                reg = <5>;
-                               phy-mode = "rgmii";
+                               phy-mode = "rgmii-rxid";
+
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&rgmii2_pins>;
                        };
 
                        switch0: switch0@0 {
                #address-cells = <3>;
                #size-cells = <2>;
 
+               perst-gpio = <&gpio 19 GPIO_ACTIVE_HIGH>;
                pinctrl-names = "default";
                pinctrl-0 = <&pcie_pins>;
 
index 2576f17..d2a07f1 100644 (file)
 #include <mt7621.h>
 #include <ralink_regs.h>
 
-#define RALINK_CLKCFG1                         0x30
-
-#define PCIE_PORT_CLK_EN(x)                    BIT(24 + (x))
-
 #define RG_PE1_PIPE_REG                                0x02c
 #define RG_PE1_PIPE_RST                                BIT(12)
 #define RG_PE1_PIPE_CMD_FRC                    BIT(4)
@@ -286,10 +282,6 @@ static int mt7621_pci_phy_power_off(struct phy *phy)
 
 static int mt7621_pci_phy_exit(struct phy *phy)
 {
-       struct mt7621_pci_phy_instance *instance = phy_get_drvdata(phy);
-
-       rt_sysc_m32(PCIE_PORT_CLK_EN(instance->index), 0, RALINK_CLKCFG1);
-
        return 0;
 }
 
index 5a6ee41..604ec81 100644 (file)
@@ -6,6 +6,7 @@ Required properties:
 - reg: Base addresses and lengths of the PCIe subsys and root ports.
 - bus-range: Range of bus numbers associated with this controller.
 - #address-cells: Address representation for root ports (must be 3)
+- perst-gpio: PCIe reset signal line.
 - pinctrl-names : The pin control state names.
 - pinctrl-0: The "default" pinctrl state.
 - #size-cells: Size representation for root ports (must be 2)
@@ -48,6 +49,7 @@ Example for MT7621:
                #address-cells = <3>;
                #size-cells = <2>;
 
+               perst-gpio = <&gpio 19 GPIO_ACTIVE_HIGH>;
                pinctrl-names = "default";
                pinctrl-0 = <&pcie_pins>;
 
index 03d919a..89fa813 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/bitops.h>
 #include <linux/delay.h>
+#include <linux/gpio/consumer.h>
 #include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/of.h>
 
 /* sysctl */
 #define MT7621_CHIP_REV_ID             0x0c
+#define MT7621_GPIO_MODE               0x60
 #define CHIP_REV_MT7621_E2             0x0101
 
 /* MediaTek specific configuration registers */
 #define PCIE_FTS_NUM                   0x70c
 #define PCIE_FTS_NUM_MASK              GENMASK(15, 8)
-#define PCIE_FTS_NUM_L0(x)             ((x) & 0xff << 8)
+#define PCIE_FTS_NUM_L0(x)             (((x) & 0xff) << 8)
 
 /* rt_sysc_membase relative registers */
+#define RALINK_CLKCFG1                 0x30
 #define RALINK_PCIE_CLK_GEN            0x7c
 #define RALINK_PCIE_CLK_GEN1           0x80
 
@@ -81,7 +84,6 @@
 #define PCIE_BAR_ENABLE                        BIT(0)
 #define PCIE_PORT_INT_EN(x)            BIT(20 + (x))
 #define PCIE_PORT_CLK_EN(x)            BIT(24 + (x))
-#define PCIE_PORT_PERST(x)             BIT(1 + (x))
 #define PCIE_PORT_LINKUP               BIT(0)
 
 #define PCIE_CLK_GEN_EN                        BIT(31)
@@ -89,6 +91,9 @@
 #define PCIE_CLK_GEN1_DIS              GENMASK(30, 24)
 #define PCIE_CLK_GEN1_EN               (BIT(27) | BIT(25))
 #define MEMORY_BASE                    0x0
+#define PERST_MODE_MASK                        GENMASK(11, 10)
+#define PERST_MODE_GPIO                        BIT(10)
+#define PERST_DELAY_US                 1000
 
 /**
  * struct mt7621_pcie_port - PCIe port information
@@ -119,6 +124,7 @@ struct mt7621_pcie_port {
  * @offset: IO / Memory offset
  * @dev: Pointer to PCIe device
  * @ports: pointer to PCIe port information
+ * @perst: gpio reset
  * @rst: pointer to pcie reset
  */
 struct mt7621_pcie {
@@ -132,6 +138,7 @@ struct mt7621_pcie {
                resource_size_t io;
        } offset;
        struct list_head ports;
+       struct gpio_desc *perst;
        struct reset_control *rst;
 };
 
@@ -198,6 +205,28 @@ static void write_config(struct mt7621_pcie *pcie, unsigned int dev,
        pcie_write(pcie, val, RALINK_PCI_CONFIG_DATA);
 }
 
+static inline void mt7621_perst_gpio_pcie_assert(struct mt7621_pcie *pcie)
+{
+       gpiod_set_value(pcie->perst, 0);
+       mdelay(PERST_DELAY_US);
+}
+
+static inline void mt7621_perst_gpio_pcie_deassert(struct mt7621_pcie *pcie)
+{
+       gpiod_set_value(pcie->perst, 1);
+       mdelay(PERST_DELAY_US);
+}
+
+static inline bool mt7621_pcie_port_is_linkup(struct mt7621_pcie_port *port)
+{
+       return (pcie_port_read(port, RALINK_PCI_STATUS) & PCIE_PORT_LINKUP) != 0;
+}
+
+static inline void mt7621_pcie_port_clk_disable(struct mt7621_pcie_port *port)
+{
+       rt_sysc_m32(PCIE_PORT_CLK_EN(port->slot), 0, RALINK_CLKCFG1);
+}
+
 static inline void mt7621_control_assert(struct mt7621_pcie_port *port)
 {
        u32 chip_rev_id = rt_sysc_r32(MT7621_CHIP_REV_ID);
@@ -344,6 +373,12 @@ static int mt7621_pcie_parse_dt(struct mt7621_pcie *pcie)
        struct resource regs;
        int err;
 
+       pcie->perst = devm_gpiod_get(dev, "perst", GPIOD_OUT_HIGH);
+       if (IS_ERR(pcie->perst)) {
+               dev_err(dev, "failed to get gpio perst\n");
+               return PTR_ERR(pcie->perst);
+       }
+
        err = of_address_to_resource(node, 0, &regs);
        if (err) {
                dev_err(dev, "missing \"reg\" property\n");
@@ -384,7 +419,6 @@ static int mt7621_pcie_init_port(struct mt7621_pcie_port *port)
        struct mt7621_pcie *pcie = port->pcie;
        struct device *dev = pcie->dev;
        u32 slot = port->slot;
-       u32 val = 0;
        int err;
 
        /*
@@ -393,47 +427,35 @@ static int mt7621_pcie_init_port(struct mt7621_pcie_port *port)
         */
        mt7621_reset_port(port);
 
-       val = read_config(pcie, slot, PCIE_FTS_NUM);
-       dev_info(dev, "Port %d N_FTS = %x\n", (unsigned int)val, slot);
-
        err = phy_init(port->phy);
        if (err) {
                dev_err(dev, "failed to initialize port%d phy\n", slot);
-               goto err_phy_init;
+               return err;
        }
 
        err = phy_power_on(port->phy);
        if (err) {
                dev_err(dev, "failed to power on port%d phy\n", slot);
-               goto err_phy_on;
-       }
-
-       if ((pcie_port_read(port, RALINK_PCI_STATUS) & PCIE_PORT_LINKUP) == 0) {
-               dev_err(dev, "pcie%d no card, disable it (RST & CLK)\n", slot);
-               mt7621_control_assert(port);
-               port->enabled = false;
-               err = -ENODEV;
-               goto err_no_link_up;
+               phy_exit(port->phy);
+               return err;
        }
 
        port->enabled = true;
 
        return 0;
-
-err_no_link_up:
-       phy_power_off(port->phy);
-err_phy_on:
-       phy_exit(port->phy);
-err_phy_init:
-       return err;
 }
 
 static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
 {
        struct device *dev = pcie->dev;
        struct mt7621_pcie_port *port, *tmp;
+       u32 val = 0;
        int err;
 
+       rt_sysc_m32(PERST_MODE_MASK, PERST_MODE_GPIO, MT7621_GPIO_MODE);
+
+       mt7621_perst_gpio_pcie_assert(pcie);
+
        list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
                u32 slot = port->slot;
 
@@ -441,10 +463,30 @@ static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
                if (err) {
                        dev_err(dev, "Initiating port %d failed\n", slot);
                        list_del(&port->list);
+               } else {
+                       val = read_config(pcie, slot, PCIE_FTS_NUM);
+                       dev_info(dev, "Port %d N_FTS = %x\n", slot,
+                                (unsigned int)val);
                }
        }
 
        reset_control_assert(pcie->rst);
+
+       mt7621_perst_gpio_pcie_deassert(pcie);
+
+       list_for_each_entry(port, &pcie->ports, list) {
+               u32 slot = port->slot;
+
+               if (!mt7621_pcie_port_is_linkup(port)) {
+                       dev_err(dev, "pcie%d no card, disable it (RST & CLK)\n",
+                               slot);
+                       phy_power_off(port->phy);
+                       mt7621_control_assert(port);
+                       mt7621_pcie_port_clk_disable(port);
+                       port->enabled = false;
+               }
+       }
+
        rt_sysc_m32(0x30, 2 << 4, SYSC_REG_SYSTEM_CONFIG1);
        rt_sysc_m32(PCIE_CLK_GEN_EN, PCIE_CLK_GEN_DIS, RALINK_PCIE_CLK_GEN);
        rt_sysc_m32(PCIE_CLK_GEN1_DIS, PCIE_CLK_GEN1_EN, RALINK_PCIE_CLK_GEN1);
@@ -453,30 +495,12 @@ static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
        reset_control_deassert(pcie->rst);
 }
 
-static int mt7621_pcie_enable_port(struct mt7621_pcie_port *port)
+static void mt7621_pcie_enable_port(struct mt7621_pcie_port *port)
 {
        struct mt7621_pcie *pcie = port->pcie;
        u32 slot = port->slot;
        u32 offset = MT7621_PCIE_OFFSET + (slot * MT7621_NEXT_PORT);
        u32 val;
-       int err;
-
-       /* assert port PERST_N */
-       val = pcie_read(pcie, RALINK_PCI_PCICFG_ADDR);
-       val |= PCIE_PORT_PERST(slot);
-       pcie_write(pcie, val, RALINK_PCI_PCICFG_ADDR);
-
-       /* de-assert port PERST_N */
-       val = pcie_read(pcie, RALINK_PCI_PCICFG_ADDR);
-       val &= ~PCIE_PORT_PERST(slot);
-       pcie_write(pcie, val, RALINK_PCI_PCICFG_ADDR);
-
-       /* 100ms timeout value should be enough for Gen1 training */
-       err = readl_poll_timeout(port->base + RALINK_PCI_STATUS,
-                                val, !!(val & PCIE_PORT_LINKUP),
-                                20, 100 * USEC_PER_MSEC);
-       if (err)
-               return -ETIMEDOUT;
 
        /* enable pcie interrupt */
        val = pcie_read(pcie, RALINK_PCI_PCIMSK_ADDR);
@@ -492,8 +516,6 @@ static int mt7621_pcie_enable_port(struct mt7621_pcie_port *port)
        /* configure class code and revision ID */
        pcie_write(pcie, PCIE_CLASS_CODE | PCIE_REVISION_ID,
                   offset + RALINK_PCI_CLASS);
-
-       return 0;
 }
 
 static void mt7621_pcie_enable_ports(struct mt7621_pcie *pcie)
@@ -506,12 +528,8 @@ static void mt7621_pcie_enable_ports(struct mt7621_pcie *pcie)
 
        list_for_each_entry(port, &pcie->ports, list) {
                if (port->enabled) {
-                       if (mt7621_pcie_enable_port(port)) {
-                               dev_err(dev, "de-assert port %d PERST_N\n",
-                                       port->slot);
-                               continue;
-                       }
-                       dev_info(dev, "PCIE%d enabled\n", slot);
+                       mt7621_pcie_enable_port(port);
+                       dev_info(dev, "PCIE%d enabled\n", num_slots_enabled);
                        num_slots_enabled++;
                }
        }
@@ -709,4 +727,4 @@ static int __init mt7621_pci_init(void)
        return platform_driver_register(&mt7621_pci_driver);
 }
 
-arch_initcall(mt7621_pci_init);
+module_init(mt7621_pci_init);
index 07a06c5..05079f7 100644 (file)
@@ -385,7 +385,7 @@ static void *xlr_config_spill(struct xlr_net_priv *priv, int reg_start_0,
 
        base = priv->base_addr;
        spill_size = size;
-       spill = kmalloc(spill_size + SMP_CACHE_BYTES, GFP_ATOMIC);
+       spill = kmalloc(spill_size + SMP_CACHE_BYTES, GFP_KERNEL);
        if (!spill)
                return ZERO_SIZE_PTR;
 
index aeec163..cd2b777 100644 (file)
@@ -521,8 +521,7 @@ static void octeon_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
  */
 static inline u32 cvmx_usb_read_csr32(struct octeon_hcd *usb, u64 address)
 {
-       u32 result = cvmx_read64_uint32(address ^ 4);
-       return result;
+       return cvmx_read64_uint32(address ^ 4);
 }
 
 /**
index c889f0b..40c6f4e 100644 (file)
@@ -871,7 +871,6 @@ abort:
 static long
 pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
-       int                     retval = 0;
        struct pi433_instance   *instance;
        struct pi433_device     *device;
        struct pi433_tx_cfg     tx_cfg;
@@ -923,10 +922,10 @@ pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                mutex_unlock(&device->rx_lock);
                break;
        default:
-               retval = -EINVAL;
+               return -EINVAL;
        }
 
-       return retval;
+       return 0;
 }
 
 #ifdef CONFIG_COMPAT
index 4cd1625..7d86bb8 100644 (file)
@@ -722,10 +722,10 @@ int rf69_set_packet_format(struct spi_device *spi,
        switch (packet_format) {
        case packet_length_var:
                return rf69_set_bit(spi, REG_PACKETCONFIG1,
-                                   MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE);
+                                   MASK_PACKETCONFIG1_PACKET_FORMAT_VARIABLE);
        case packet_length_fix:
                return rf69_clear_bit(spi, REG_PACKETCONFIG1,
-                                     MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE);
+                                     MASK_PACKETCONFIG1_PACKET_FORMAT_VARIABLE);
        default:
                dev_dbg(&spi->dev, "set: illegal input param");
                return -EINVAL;
index f925a83..be5497c 100644 (file)
 #define  MASK_SYNC_CONFIG_SYNC_TOLERANCE       0x07
 
 /* RegPacketConfig1 */
-#define  MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE      0x80
+#define  MASK_PACKETCONFIG1_PACKET_FORMAT_VARIABLE     0x80
 #define  MASK_PACKETCONFIG1_DCFREE                     0x60
 #define  MASK_PACKETCONFIG1_CRC_ON                     0x10 /* default */
 #define  MASK_PACKETCONFIG1_CRCAUTOCLEAR_OFF           0x08
index de3e357..5854551 100644 (file)
@@ -814,9 +814,8 @@ static int gdma_dma_probe(struct platform_device *pdev)
        dma_dev = devm_kzalloc(&pdev->dev,
                               struct_size(dma_dev, chan, data->chancnt),
                               GFP_KERNEL);
-       if (!dma_dev) {
+       if (!dma_dev)
                return -EINVAL;
-       }
        dma_dev->data = data;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
index 4f7ef28..970d5ab 100644 (file)
@@ -8,7 +8,7 @@ config R8188EU
        select LIB80211
        select LIB80211_CRYPT_WEP
        select LIB80211_CRYPT_CCMP
-       ---help---
+       help
        This option adds the Realtek RTL8188EU USB device such as TP-Link TL-WN725N.
        If built as a module, it will be called r8188eu.
 
@@ -17,7 +17,7 @@ if R8188EU
 config 88EU_AP_MODE
        bool "Realtek RTL8188EU AP mode"
        default y
-       ---help---
+       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,
        "Y" should be selected.
index 797ffa6..28b3cdd 100644 (file)
@@ -482,7 +482,7 @@ int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwi
        return ret;
 }
 
-int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len)
+void rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len)
 {
        u8 authmode, sec_idx, i;
        u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01};
@@ -539,8 +539,6 @@ int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie,
                        }
                }
        }
-
-       return *rsn_len + *wpa_len;
 }
 
 u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen)
index 9a4aad5..d2f7a88 100644 (file)
@@ -159,7 +159,8 @@ static void _rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *
        spin_unlock_bh(&free_queue->lock);
 }
 
-void _rtw_free_network_nolock(struct   mlme_priv *pmlmepriv, struct wlan_network *pnetwork)
+static void rtw_free_network_nolock(struct mlme_priv *pmlmepriv,
+                                   struct wlan_network *pnetwork)
 {
        struct __queue *free_queue = &pmlmepriv->free_bss_pool;
 
@@ -276,12 +277,6 @@ static struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv)
        return _rtw_alloc_network(pmlmepriv);
 }
 
-static void rtw_free_network_nolock(struct mlme_priv *pmlmepriv,
-                                   struct wlan_network *pnetwork)
-{
-       _rtw_free_network_nolock(pmlmepriv, pnetwork);
-}
-
 int rtw_is_same_ibss(struct adapter *adapter, struct wlan_network *pnetwork)
 {
        int ret = true;
@@ -1330,11 +1325,10 @@ void _rtw_join_timeout_handler (struct timer_list *t)
                                        continue;
                                }
                                break;
-                       } else {
-                               DBG_88E("%s We've try roaming but fail\n", __func__);
-                               rtw_indicate_disconnect(adapter);
-                               break;
                        }
+                       DBG_88E("%s We've try roaming but fail\n", __func__);
+                       rtw_indicate_disconnect(adapter);
+                       break;
                }
        } else {
                rtw_indicate_disconnect(adapter);
@@ -2058,17 +2052,16 @@ void _rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network)
                        do_join_r = rtw_do_join(padapter);
                        if (do_join_r == _SUCCESS) {
                                break;
-                       } else {
-                               DBG_88E("roaming do_join return %d\n", do_join_r);
-                               pmlmepriv->to_roaming--;
+                       }
+                       DBG_88E("roaming do_join return %d\n", do_join_r);
+                       pmlmepriv->to_roaming--;
 
-                               if (pmlmepriv->to_roaming > 0) {
-                                       continue;
-                               } else {
-                                       DBG_88E("%s(%d) -to roaming fail, indicate_disconnect\n", __func__, __LINE__);
-                                       rtw_indicate_disconnect(padapter);
-                                       break;
-                               }
+                       if (pmlmepriv->to_roaming > 0) {
+                               continue;
+                       } else {
+                               DBG_88E("%s(%d) -to roaming fail, indicate_disconnect\n", __func__, __LINE__);
+                               rtw_indicate_disconnect(padapter);
+                               break;
                        }
                }
        }
index 8f28aef..6f3c032 100644 (file)
@@ -5322,7 +5322,7 @@ u8 set_tx_beacon_cmd(struct adapter *padapter)
        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
-       u8 res = _SUCCESS;
+       u8 res;
        int len_diff = 0;
 
        ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
index 087f6c9..9caf704 100644 (file)
@@ -450,7 +450,7 @@ static struct recv_frame *portctrl(struct adapter *adapter,
                memcpy(&be_tmp, ptr, 2);
                ether_type = ntohs(be_tmp);
 
-               if ((psta != NULL) && (psta->ieee8021x_blocked)) {
+               if (psta && (psta->ieee8021x_blocked)) {
                        /* blocked */
                        /* only accept EAPOL frame */
                        RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########%s:psta->ieee8021x_blocked==1\n", __func__));
@@ -700,7 +700,7 @@ static int sta2sta_data_frame(struct adapter *adapter,
        else
                *psta = rtw_get_stainfo(pstapriv, sta_addr); /*  get ap_info */
 
-       if (*psta == NULL) {
+       if (!*psta) {
                RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under %s ; drop pkt\n", __func__));
                ret = _FAIL;
                goto exit;
@@ -764,7 +764,7 @@ static int ap2sta_data_frame(
                else
                        *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /*  get ap_info */
 
-               if (*psta == NULL) {
+               if (!*psta) {
                        RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("ap2sta: can't get psta under STATION_MODE ; drop pkt\n"));
                        ret = _FAIL;
                        goto exit;
@@ -786,7 +786,7 @@ static int ap2sta_data_frame(
        } else {
                if (!memcmp(myhwaddr, pattrib->dst, ETH_ALEN) && !mcast) {
                        *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /*  get sta_info */
-                       if (*psta == NULL) {
+                       if (!*psta) {
                                DBG_88E("issue_deauth to the ap =%pM for the reason(7)\n", (pattrib->bssid));
 
                                issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
@@ -820,7 +820,7 @@ static int sta2ap_data_frame(struct adapter *adapter,
                }
 
                *psta = rtw_get_stainfo(pstapriv, pattrib->src);
-               if (*psta == NULL) {
+               if (!*psta) {
                        RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under AP_MODE; drop pkt\n"));
                        DBG_88E("issue_deauth to sta=%pM for the reason(7)\n", (pattrib->src));
 
@@ -883,7 +883,7 @@ static int validate_recv_ctrl_frame(struct adapter *padapter,
                aid = GetAid(pframe);
                psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
 
-               if ((psta == NULL) || (psta->aid != aid))
+               if ((!psta) || (psta->aid != aid))
                        return _FAIL;
 
                /* for rx pkt statistics */
@@ -1479,7 +1479,7 @@ struct recv_frame *recvframe_chk_defrag(struct adapter *padapter,
                }
        }
 
-       if ((prtnframe != NULL) && (prtnframe->attrib.privacy)) {
+       if (prtnframe && (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"));
index f404370..7bfc5b7 100644 (file)
@@ -27,9 +27,6 @@ static const u8 EPIGRAM_OUI[] = {0x00, 0x90, 0x4c};
 
 u8 REALTEK_96B_IE[] = {0x00, 0xe0, 0x4c, 0x02, 0x01, 0x20};
 
-#define R2T_PHY_DELAY  (0)
-
-/* define WAIT_FOR_BCN_TO_M    (3000) */
 #define WAIT_FOR_BCN_TO_MIN    (6000)
 #define WAIT_FOR_BCN_TO_MAX    (20000)
 
@@ -349,16 +346,6 @@ void set_channel_bwmode(struct adapter *padapter, unsigned char channel, unsigne
        SetBWMode(padapter, bwmode, channel_offset);
 }
 
-int get_bsstype(unsigned short capability)
-{
-       if (capability & BIT(0))
-               return WIFI_FW_AP_STATE;
-       else if (capability & BIT(1))
-               return WIFI_FW_ADHOC_STATE;
-       else
-               return 0;
-}
-
 u16 get_beacon_interval(struct wlan_bssid_ex *bss)
 {
        __le16 val;
@@ -1041,7 +1028,6 @@ void update_beacon_info(struct adapter *padapter, u8 *pframe, uint pkt_len, stru
 
                switch (pIE->ElementID) {
                case _HT_EXTRA_INFO_IE_:        /* HT info */
-                       /* HT_info_handler(padapter, pIE); */
                        bwmode_update_check(padapter, pIE);
                        break;
                case _ERPINFO_IE_:
@@ -1088,36 +1074,6 @@ unsigned int is_ap_in_tkip(struct adapter *padapter)
        }
 }
 
-unsigned int is_ap_in_wep(struct adapter *padapter)
-{
-       u32 i;
-       struct ndis_802_11_var_ie *pIE;
-       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
-       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
-       struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
-
-       if (rtw_get_capability((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) {
-               for (i = sizeof(struct ndis_802_11_fixed_ie); i < pmlmeinfo->network.ie_length;) {
-                       pIE = (struct ndis_802_11_var_ie *)(pmlmeinfo->network.ies + i);
-
-                       switch (pIE->ElementID) {
-                       case _VENDOR_SPECIFIC_IE_:
-                               if (!memcmp(pIE->data, RTW_WPA_OUI, 4))
-                                       return false;
-                               break;
-                       case _RSN_IE_2_:
-                               return false;
-                       default:
-                               break;
-                       }
-                       i += (pIE->Length + 2);
-               }
-               return true;
-       } else {
-               return false;
-       }
-}
-
 static int wifirate2_ratetbl_inx(unsigned char rate)
 {
        rate = rate & 0x7f;
@@ -1346,8 +1302,6 @@ void update_IOT_info(struct adapter *padapter)
                               false);
                break;
        case HT_IOT_PEER_REALTEK:
-               /* rtw_write16(padapter, 0x4cc, 0xffff); */
-               /* rtw_write16(padapter, 0x546, 0x01c0); */
                /* disable high power */
                Switch_DM_Func(padapter, (u32)(~DYNAMIC_BB_DYNAMIC_TXPWR),
                               false);
index ff481fb..95f1b14 100644 (file)
@@ -283,9 +283,3 @@ bool hal_mapping_out_pipe(struct adapter *adapter, u8 numoutpipe)
        }
        return result;
 }
-
-void hal_init_macaddr(struct adapter *adapter)
-{
-       rtw_hal_set_hwreg(adapter, HW_VAR_MAC_ADDR,
-                         adapter->eeprompriv.mac_addr);
-}
index 74f7c9c..4e2f6cb 100644 (file)
@@ -942,11 +942,6 @@ void odm_RSSIMonitorCheckCE(struct odm_dm_struct *pDM_Odm)
 /* 3============================================================ */
 
 void odm_TXPowerTrackingInit(struct odm_dm_struct *pDM_Odm)
-{
-       odm_TXPowerTrackingThermalMeterInit(pDM_Odm);
-}
-
-void odm_TXPowerTrackingThermalMeterInit(struct odm_dm_struct *pDM_Odm)
 {
        pDM_Odm->RFCalibrateInfo.bTXPowerTracking = true;
        pDM_Odm->RFCalibrateInfo.TXPowercount = 0;
@@ -962,11 +957,6 @@ void ODM_TXPowerTrackingCheck(struct odm_dm_struct *pDM_Odm)
        /*  2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */
        /*  at the same time. In the stage2/3, we need to prive universal interface and merge all */
        /*  HW dynamic mechanism. */
-       odm_TXPowerTrackingCheckCE(pDM_Odm);
-}
-
-void odm_TXPowerTrackingCheckCE(struct odm_dm_struct *pDM_Odm)
-{
        struct adapter *Adapter = pDM_Odm->Adapter;
 
        if (!(pDM_Odm->SupportAbility & ODM_RF_TX_PWR_TRACK))
index 149b000..d5a9ac5 100644 (file)
@@ -387,10 +387,9 @@ static void odm_Process_RSSIForDM(struct odm_dm_struct *dm_odm,
 }
 
 /*  Endianness before calling this API */
-static void ODM_PhyStatusQuery_92CSeries(struct odm_dm_struct *dm_odm,
-                                        struct odm_phy_status_info *pPhyInfo,
-                                        u8 *pPhyStatus,
-                                        struct odm_per_pkt_info *pPktinfo)
+void ODM_PhyStatusQuery(struct odm_dm_struct *dm_odm,
+                       struct odm_phy_status_info *pPhyInfo,
+                       u8 *pPhyStatus, struct odm_per_pkt_info *pPktinfo)
 {
        odm_RxPhyStatus92CSeries_Parsing(dm_odm, pPhyInfo, pPhyStatus,
                                         pPktinfo);
@@ -398,12 +397,4 @@ static void ODM_PhyStatusQuery_92CSeries(struct odm_dm_struct *dm_odm,
                ;/*  Select the packets to do RSSI checking for antenna switching. */
        else
                odm_Process_RSSIForDM(dm_odm, pPhyInfo, pPktinfo);
-
-}
-
-void ODM_PhyStatusQuery(struct odm_dm_struct *dm_odm,
-                       struct odm_phy_status_info *pPhyInfo,
-                       u8 *pPhyStatus, struct odm_per_pkt_info *pPktinfo)
-{
-       ODM_PhyStatusQuery_92CSeries(dm_odm, pPhyInfo, pPhyStatus, pPktinfo);
 }
index 70c02c4..ac55520 100644 (file)
@@ -469,10 +469,7 @@ static void usb_AggSettingTxUpdate(struct adapter *Adapter)
  *
  *---------------------------------------------------------------------------
  */
-static void
-usb_AggSettingRxUpdate(
-               struct adapter *Adapter
-       )
+static void usb_AggSettingRxUpdate(struct adapter *Adapter)
 {
        struct hal_data_8188e *haldata = Adapter->HalData;
        u8 valueDMA;
@@ -749,7 +746,8 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter)
        _InitDriverInfoSize(Adapter, DRVINFO_SZ);
 
        _InitInterrupt(Adapter);
-       hal_init_macaddr(Adapter);/* set mac_address */
+       rtw_hal_set_hwreg(Adapter, HW_VAR_MAC_ADDR,
+                         Adapter->eeprompriv.mac_addr);
        _InitNetworkType(Adapter);/* set msr */
        _InitWMACSetting(Adapter);
        _InitAdaptiveCtrl(Adapter);
@@ -1044,10 +1042,7 @@ static void Hal_EfuseParseMACAddr_8188EU(struct adapter *adapt, u8 *hwinfo, bool
                 eeprom->mac_addr));
 }
 
-static void
-readAdapterInfo_8188EU(
-               struct adapter *adapt
-       )
+static void readAdapterInfo_8188EU(struct adapter *adapt)
 {
        struct eeprom_priv *eeprom = GET_EEPROM_EFUSE_PRIV(adapt);
 
@@ -1067,9 +1062,7 @@ readAdapterInfo_8188EU(
        Hal_ReadThermalMeter_88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
 }
 
-static void _ReadPROMContent(
-       struct adapter *Adapter
-       )
+static void _ReadPROMContent(struct adapter *Adapter)
 {
        struct eeprom_priv *eeprom = GET_EEPROM_EFUSE_PRIV(Adapter);
        u8 eeValue;
@@ -1782,11 +1775,8 @@ void rtw_hal_get_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
 /*     Description: */
 /*             Query setting of specified variable. */
 /*  */
-u8 rtw_hal_get_def_var(
-               struct adapter *Adapter,
-               enum hal_def_variable eVariable,
-               void *pValue
-       )
+u8 rtw_hal_get_def_var(struct adapter *Adapter, enum hal_def_variable eVariable,
+                      void *pValue)
 {
        struct hal_data_8188e *haldata = Adapter->HalData;
        u8 bResult = _SUCCESS;
index 2f7bdad..93cbbe7 100644 (file)
@@ -148,5 +148,4 @@ void hal_set_brate_cfg(u8 *brates, u16 *rate_cfg);
 
 bool hal_mapping_out_pipe(struct adapter *adapter, u8 numoutpipe);
 
-void hal_init_macaddr(struct adapter *adapter);
 #endif /* __HAL_COMMON_H__ */
index c60b833..d569fe5 100644 (file)
 #include "wifi.h"
 #include <linux/wireless.h>
 
-#define MGMT_QUEUE_NUM 5
-
-#define ETH_ALEN       6
-#define ETH_TYPE_LEN           2
-#define PAYLOAD_TYPE_LEN       1
-
 #ifdef CONFIG_88EU_AP_MODE
 
 #define RTL_IOCTL_HOSTAPD (SIOCIWFIRSTPRIV + 28)
@@ -749,8 +743,8 @@ int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher,
 int rtw_parse_wpa2_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher,
                      int *pairwise_cipher, int *is_8021x);
 
-int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len,
-                  u8 *wpa_ie, u16 *wpa_len);
+void rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len,
+                   u8 *wpa_ie, u16 *wpa_len);
 
 u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen);
 u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen);
index df096c3..5254d87 100644 (file)
@@ -59,9 +59,7 @@ void odm_RefreshRateAdaptiveMaskCE(struct odm_dm_struct *pDM_Odm);
 void odm_RefreshRateAdaptiveMaskAPADSL(struct odm_dm_struct *pDM_Odm);
 void odm_DynamicTxPowerNIC(struct odm_dm_struct *pDM_Odm);
 void odm_RSSIMonitorCheckCE(struct odm_dm_struct *pDM_Odm);
-void odm_TXPowerTrackingThermalMeterInit(struct odm_dm_struct *pDM_Odm);
 void odm_EdcaTurboCheckCE(struct odm_dm_struct *pDM_Odm);
-void odm_TXPowerTrackingCheckCE(struct odm_dm_struct *pDM_Odm);
 void odm_SwAntDivChkAntSwitchCallback(void *FunctionContext);
 void odm_InitHybridAntDiv(struct odm_dm_struct *pDM_Odm);
 void odm_HwAntDiv(struct odm_dm_struct *pDM_Odm);
index db25eb5..1052549 100644 (file)
@@ -111,10 +111,4 @@ struct eeprom_priv {
        u8              efuse_eeprom_data[HWSET_MAX_SIZE_512];
 };
 
-void eeprom_write16(struct adapter *padapter, u16 reg, u16 data);
-u16 eeprom_read16(struct adapter *padapter, u16 reg);
-void read_eeprom_content(struct adapter *padapter);
-void eeprom_read_sz(struct adapter *adapt, u16 reg, u8 *data, u32 sz);
-void read_eeprom_content_by_attrib(struct adapter *padapter);
-
 #endif  /* __RTL871X_EEPROM_H__ */
index bfef665..9abb7c3 100644 (file)
@@ -335,9 +335,6 @@ void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv);
 
 struct wlan_network *_rtw_alloc_network(struct mlme_priv *pmlmepriv);
 
-void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv,
-                             struct wlan_network *pnetwork);
-
 int rtw_if_up(struct adapter *padapter);
 
 u8 *rtw_get_capability_from_ie(u8 *ie);
index 1fb2349..327f7d1 100644 (file)
@@ -485,7 +485,6 @@ void flush_all_cam_entry(struct adapter *padapter);
 void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src,
                    struct adapter *adapter, bool update_ie);
 
-int get_bsstype(unsigned short capability);
 u16 get_beacon_interval(struct wlan_bssid_ex *bss);
 
 int is_client_associated_to_ap(struct adapter *padapter);
@@ -526,7 +525,6 @@ void set_sta_rate(struct adapter *padapter, struct sta_info *psta);
 unsigned char get_highest_rate_idx(u32 mask);
 int support_short_GI(struct adapter *padapter, struct ieee80211_ht_cap *caps);
 unsigned int is_ap_in_tkip(struct adapter *padapter);
-unsigned int is_ap_in_wep(struct adapter *padapter);
 
 void report_join_res(struct adapter *padapter, int res);
 void report_survey_event(struct adapter *padapter,
index eaa4adb..ec5835d 100644 (file)
@@ -1686,7 +1686,7 @@ static int rtw_wx_get_enc(struct net_device *dev,
                            struct iw_request_info *info,
                            union iwreq_data *wrqu, char *keybuf)
 {
-       uint key, ret = 0;
+       uint key;
        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
        struct iw_point *erq = &(wrqu->encoding);
        struct  mlme_priv       *pmlmepriv = &(padapter->mlmepriv);
@@ -1744,7 +1744,7 @@ static int rtw_wx_get_enc(struct net_device *dev,
                break;
        }
 
-       return ret;
+       return 0;
 }
 
 static int rtw_wx_get_power(struct net_device *dev,
@@ -2508,7 +2508,6 @@ static int rtw_add_sta(struct net_device *dev, struct ieee_param *param)
 
 static int rtw_del_sta(struct net_device *dev, struct ieee_param *param)
 {
-       int ret = 0;
        struct sta_info *psta = NULL;
        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
        struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
@@ -2538,7 +2537,7 @@ static int rtw_del_sta(struct net_device *dev, struct ieee_param *param)
                DBG_88E("rtw_del_sta(), sta has already been removed or never been added\n");
        }
 
-       return ret;
+       return 0;
 }
 
 static int rtw_ioctl_get_sta_data(struct net_device *dev, struct ieee_param *param, int len)
@@ -2636,7 +2635,6 @@ static int rtw_get_sta_wpaie(struct net_device *dev, struct ieee_param *param)
 
 static int rtw_set_wps_beacon(struct net_device *dev, struct ieee_param *param, int len)
 {
-       int ret = 0;
        unsigned char wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
        struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
@@ -2668,12 +2666,11 @@ static int rtw_set_wps_beacon(struct net_device *dev, struct ieee_param *param,
                pmlmeext->bstart_bss = true;
        }
 
-       return ret;
+       return 0;
 }
 
 static int rtw_set_wps_probe_resp(struct net_device *dev, struct ieee_param *param, int len)
 {
-       int ret = 0;
        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
        struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
        int ie_len;
@@ -2698,12 +2695,11 @@ static int rtw_set_wps_probe_resp(struct net_device *dev, struct ieee_param *par
                memcpy(pmlmepriv->wps_probe_resp_ie, param->u.bcn_ie.buf, ie_len);
        }
 
-       return ret;
+       return 0;
 }
 
 static int rtw_set_wps_assoc_resp(struct net_device *dev, struct ieee_param *param, int len)
 {
-       int ret = 0;
        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
        struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
        int ie_len;
@@ -2729,12 +2725,11 @@ static int rtw_set_wps_assoc_resp(struct net_device *dev, struct ieee_param *par
                memcpy(pmlmepriv->wps_assoc_resp_ie, param->u.bcn_ie.buf, ie_len);
        }
 
-       return ret;
+       return 0;
 }
 
 static int rtw_set_hidden_ssid(struct net_device *dev, struct ieee_param *param, int len)
 {
-       int ret = 0;
        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
        struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
        struct mlme_ext_priv    *pmlmeext = &(padapter->mlmeextpriv);
@@ -2754,7 +2749,7 @@ static int rtw_set_hidden_ssid(struct net_device *dev, struct ieee_param *param,
                value = 0;
        DBG_88E("%s value(%u)\n", __func__, value);
        pmlmeinfo->hidden_ssid_mode = value;
-       return ret;
+       return 0;
 }
 
 static int rtw_ioctl_acl_remove_sta(struct net_device *dev, struct ieee_param *param, int len)
@@ -2787,7 +2782,6 @@ static int rtw_ioctl_acl_add_sta(struct net_device *dev, struct ieee_param *para
 
 static int rtw_ioctl_set_macaddr_acl(struct net_device *dev, struct ieee_param *param, int len)
 {
-       int ret = 0;
        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
        struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
 
@@ -2796,7 +2790,7 @@ static int rtw_ioctl_set_macaddr_acl(struct net_device *dev, struct ieee_param *
 
        rtw_set_macaddr_acl(padapter, param->u.mlme.command);
 
-       return ret;
+       return 0;
 }
 
 static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p)
index 9db11b1..e660bd4 100644 (file)
@@ -93,11 +93,11 @@ void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie)
        union iwreq_data wrqu;
 
        RT_TRACE(_module_mlme_osdep_c_, _drv_info_,
-                ("+rtw_report_sec_ie, authmode=%d\n", authmode));
+                ("+%s, authmode=%d\n", __func__, authmode));
        buff = NULL;
        if (authmode == _WPA_IE_ID_) {
                RT_TRACE(_module_mlme_osdep_c_, _drv_info_,
-                        ("rtw_report_sec_ie, authmode=%d\n", authmode));
+                        ("%s, authmode=%d\n", __func__, authmode));
                buff = rtw_malloc(IW_CUSTOM_MAX);
                if (!buff)
                        return;
@@ -149,7 +149,7 @@ void rtw_indicate_sta_assoc_event(struct adapter *padapter, struct sta_info *pst
 
        memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN);
 
-       DBG_88E("+rtw_indicate_sta_assoc_event\n");
+       DBG_88E("+%s\n", __func__);
 
        wireless_send_event(padapter->pnetdev, IWEVREGISTERED, &wrqu, NULL);
 }
@@ -172,7 +172,7 @@ void rtw_indicate_sta_disassoc_event(struct adapter *padapter, struct sta_info *
 
        memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN);
 
-       DBG_88E("+rtw_indicate_sta_disassoc_event\n");
+       DBG_88E("+%s\n", __func__);
 
        wireless_send_event(padapter->pnetdev, IWEVEXPIRED, &wrqu, NULL);
 }
index 2c088af..8907bf6 100644 (file)
@@ -19,6 +19,7 @@ MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Realtek Wireless Lan Driver");
 MODULE_AUTHOR("Realtek Semiconductor Corp.");
 MODULE_VERSION(DRIVERVERSION);
+MODULE_FIRMWARE("rtlwifi/rtl8188eufw.bin");
 
 #define RTW_NOTCH_FILTER 0 /* 0:Disable, 1:Enable, */
 
index 7a09061..daf6db3 100644 (file)
@@ -67,7 +67,7 @@ int rtw_android_cmdstr_to_num(char *cmdstr)
        int cmd_num;
 
        for (cmd_num = 0; cmd_num < ANDROID_WIFI_CMD_MAX; cmd_num++)
-               if (0 == strncasecmp(cmdstr, android_wifi_cmd_str[cmd_num],
+               if (!strncasecmp(cmdstr, android_wifi_cmd_str[cmd_num],
                                  strlen(android_wifi_cmd_str[cmd_num])))
                        break;
        return cmd_num;
index 5215a0b..7d78f16 100644 (file)
@@ -1427,7 +1427,7 @@ static bool _rtl92e_set_rf_power_state(struct net_device *dev,
                                 "_rtl92e_set_rf_power_state() eRfOn!\n");
                        if ((priv->rtllib->eRFPowerState == eRfOff) &&
                             RT_IN_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC)) {
-                               bool rtstatus = true;
+                               bool rtstatus;
                                u32 InitilizeCount = 3;
 
                                do {
index 55d8579..1b7e3fd 100644 (file)
@@ -334,7 +334,7 @@ static void _rtl92e_dm_check_rate_adaptive(struct net_device *dev)
 
        if (!priv->up) {
                RT_TRACE(COMP_RATE,
-                        "<---- _rtl92e_dm_check_rate_adaptive(): driver is going to unload\n");
+                        "<---- %s: driver is going to unload\n", __func__);
                return;
        }
 
@@ -1178,7 +1178,7 @@ void rtl92e_dm_restore_state(struct net_device *dev)
 
        if (!priv->up) {
                RT_TRACE(COMP_RATE,
-                        "<---- rtl92e_dm_restore_state(): driver is going to unload\n");
+                        "<---- %s: driver is going to unload\n", __func__);
                return;
        }
 
index bb13b1d..64d9fee 100644 (file)
@@ -83,7 +83,6 @@ struct net_device *alloc_rtllib(int sizeof_priv)
                return NULL;
        }
        ieee = (struct rtllib_device *)netdev_priv_rsl(dev);
-       memset(ieee, 0, sizeof(struct rtllib_device) + sizeof_priv);
        ieee->dev = dev;
 
        err = rtllib_networks_allocate(ieee);
index d7975aa..4a6c3f6 100644 (file)
@@ -109,7 +109,6 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
        }
 
        ieee = netdev_priv(dev);
-       memset(ieee, 0, sizeof(struct ieee80211_device) + sizeof_priv);
        ieee->dev = dev;
 
        err = ieee80211_networks_allocate(ieee);
@@ -155,7 +154,7 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
        ieee80211_softmac_init(ieee);
 
        ieee->pHTInfo = kzalloc(sizeof(RT_HIGH_THROUGHPUT), GFP_KERNEL);
-       if (ieee->pHTInfo == NULL) {
+       if (!ieee->pHTInfo) {
                IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc memory for HTInfo\n");
 
                /* By this point in code ieee80211_networks_allocate() has been
index 0e762e5..0a3e478 100644 (file)
@@ -67,7 +67,7 @@ ieee80211_frag_cache_find(struct ieee80211_device *ieee, unsigned int seq,
 
        for (i = 0; i < IEEE80211_FRAG_CACHE_LEN; i++) {
                entry = &ieee->frag_cache[tid][i];
-               if (entry->skb != NULL &&
+               if (entry->skb &&
                    time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
                        IEEE80211_DEBUG_FRAG(
                                "expiring fragment cache entry "
@@ -77,7 +77,7 @@ ieee80211_frag_cache_find(struct ieee80211_device *ieee, unsigned int seq,
                        entry->skb = NULL;
                }
 
-               if (entry->skb != NULL && entry->seq == seq &&
+               if (entry->skb && entry->seq == seq &&
                    (entry->last_frag + 1 == frag || frag == -1) &&
                    memcmp(entry->src_addr, src, ETH_ALEN) == 0 &&
                    memcmp(entry->dst_addr, dst, ETH_ALEN) == 0)
@@ -102,7 +102,7 @@ ieee80211_frag_cache_get(struct ieee80211_device *ieee,
        struct rtl_80211_hdr_4addrqos *hdr_4addrqos;
        u8 tid;
 
-       if (((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) {
+       if (((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS) && IEEE80211_QOS_HAS_SEQ(fc)) {
          hdr_4addrqos = (struct rtl_80211_hdr_4addrqos *)hdr;
          tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QCTL_TID;
          tid = UP2AC(tid);
@@ -133,7 +133,7 @@ ieee80211_frag_cache_get(struct ieee80211_device *ieee,
                if (ieee->frag_next_idx[tid] >= IEEE80211_FRAG_CACHE_LEN)
                        ieee->frag_next_idx[tid] = 0;
 
-               if (entry->skb != NULL)
+               if (entry->skb)
                        dev_kfree_skb_any(entry->skb);
 
                entry->first_frag_time = jiffies;
@@ -169,7 +169,7 @@ static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee,
        struct rtl_80211_hdr_4addrqos *hdr_4addrqos;
        u8 tid;
 
-       if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) {
+       if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS) && IEEE80211_QOS_HAS_SEQ(fc)) {
          hdr_4addrqos = (struct rtl_80211_hdr_4addrqos *)hdr;
          tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QCTL_TID;
          tid = UP2AC(tid);
@@ -426,7 +426,7 @@ static int is_duplicate_packet(struct ieee80211_device *ieee,
 
 
        //TO2DS and QoS
-       if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) {
+       if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS) && IEEE80211_QOS_HAS_SEQ(fc)) {
          hdr_4addrqos = (struct rtl_80211_hdr_4addrqos *)header;
          tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QCTL_TID;
          tid = UP2AC(tid);
@@ -557,7 +557,7 @@ void ieee80211_indicate_packets(struct ieee80211_device *ieee, struct ieee80211_
                        //stats->rx_packets++;
                        //stats->rx_bytes += sub_skb->len;
 
-               /* Indicat the packets to upper layer */
+               /* Indicate the packets to upper layer */
                        if (sub_skb) {
                                sub_skb->protocol = eth_type_trans(sub_skb, ieee->dev);
                                memset(sub_skb->cb, 0, sizeof(sub_skb->cb));
@@ -773,7 +773,7 @@ static u8 parse_subframe(struct sk_buff *skb,
        /* just for debug purpose */
        SeqNum = WLAN_GET_SEQ_SEQ(le16_to_cpu(hdr->seq_ctl));
 
-       if ((IEEE80211_QOS_HAS_SEQ(fc))&&\
+       if ((IEEE80211_QOS_HAS_SEQ(fc)) && \
                        (((frameqos *)(skb->data + IEEE80211_3ADDR_LEN))->field.reserved)) {
                bIsAggregateFrame = true;
        }
@@ -1092,7 +1092,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
             ieee->iw_mode == IW_MODE_REPEAT) &&
            !from_assoc_ap) {
                switch (hostap_handle_sta_rx(ieee, dev, skb, rx_stats,
-                                            wds != NULL)) {
+                                            wds)) {
                case AP_RX_CONTINUE_NOT_AUTHORIZED:
                case AP_RX_CONTINUE:
                        break;
@@ -1109,7 +1109,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
        if (stype != IEEE80211_STYPE_DATA &&
            stype != IEEE80211_STYPE_DATA_CFACK &&
            stype != IEEE80211_STYPE_DATA_CFPOLL &&
-           stype != IEEE80211_STYPE_DATA_CFACKPOLL&&
+           stype != IEEE80211_STYPE_DATA_CFACKPOLL &&
            stype != IEEE80211_STYPE_QOS_DATA//add by David,2006.8.4
            ) {
                if (stype != IEEE80211_STYPE_NULLFUNC)
@@ -1311,7 +1311,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
                                        stats->multicast++;
                                }
 
-                               /* Indicat the packets to upper layer */
+                               /* Indicate the packets to upper layer */
                                sub_skb->protocol = eth_type_trans(sub_skb, dev);
                                memset(sub_skb->cb, 0, sizeof(sub_skb->cb));
                                sub_skb->dev = dev;
@@ -1388,7 +1388,7 @@ static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info
        int ret = 0;
        u16 size = sizeof(struct ieee80211_qos_parameter_info) - 2;
 
-       if ((info_element == NULL) || (element_param == NULL))
+       if (!info_element || !element_param)
                return -1;
 
        if (info_element->id == QOS_ELEMENT_ID && info_element->len == size) {
@@ -2508,7 +2508,7 @@ static inline void ieee80211_process_probe_response(
        list_for_each_entry(target, &ieee->network_list, list) {
                if (is_same_network(target, network, ieee))
                        break;
-               if ((oldest == NULL) ||
+               if (!oldest ||
                    (target->last_scanned < oldest->last_scanned))
                        oldest = target;
        }
@@ -2565,7 +2565,7 @@ static inline void ieee80211_process_probe_response(
                //      printk("====>2 network->ssid=%s FLAG=%d target.ssid=%s FLAG=%d\n", network->ssid, network->flags, target->ssid, target->flags);
                if(((network->flags & NETWORK_EMPTY_ESSID) == NETWORK_EMPTY_ESSID) \
                    && (((network->ssid_len > 0) && (strncmp(target->ssid, network->ssid, network->ssid_len)))\
-                   ||((ieee->current_network.ssid_len == network->ssid_len)&&(strncmp(ieee->current_network.ssid, network->ssid, network->ssid_len) == 0)&&(ieee->state == IEEE80211_NOLINK))))
+                   ||((ieee->current_network.ssid_len == network->ssid_len) && (strncmp(ieee->current_network.ssid, network->ssid, network->ssid_len) == 0) && (ieee->state == IEEE80211_NOLINK))))
                        renew = 1;
                //YJ,add,080819,for hidden ap,end
 
@@ -2575,11 +2575,10 @@ static inline void ieee80211_process_probe_response(
        }
 
        spin_unlock_irqrestore(&ieee->lock, flags);
-       if (is_beacon(beacon->header.frame_ctl)&&is_same_network(&ieee->current_network, network, ieee)&&\
+       if (is_beacon(beacon->header.frame_ctl) && is_same_network(&ieee->current_network, network, ieee) && \
                (ieee->state == IEEE80211_LINKED)) {
-               if (ieee->handle_beacon != NULL) {
+               if (ieee->handle_beacon)
                        ieee->handle_beacon(ieee->dev,beacon,&ieee->current_network);
-               }
        }
 
 out:
index 944c889..e0da090 100644 (file)
@@ -1796,7 +1796,7 @@ static void ieee80211_process_action(struct ieee80211_device *ieee,
        u8 *act = ieee80211_get_payload(header);
        u8 tmp = 0;
 //     IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len);
-       if (act == NULL) {
+       if (!act) {
                IEEE80211_DEBUG(IEEE80211_DL_ERR, "error to get payload of action frame\n");
                return;
        }
@@ -1929,7 +1929,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
                                                memcpy(ieee->pHTInfo->PeerHTCapBuf, network->bssht.bdHTCapBuf, network->bssht.bdHTCapLen);
                                                memcpy(ieee->pHTInfo->PeerHTInfoBuf, network->bssht.bdHTInfoBuf, network->bssht.bdHTInfoLen);
                                        }
-                                       if (ieee->handle_assoc_response != NULL)
+                                       if (ieee->handle_assoc_response)
                                                ieee->handle_assoc_response(ieee->dev, (struct ieee80211_assoc_response_frame *)header, network);
                                }
                                ieee80211_associate_complete(ieee);
@@ -2659,14 +2659,13 @@ static int ieee80211_wpa_set_wpa_ie(struct ieee80211_device *ieee,
 {
        u8 *buf;
 
-       if (param->u.wpa_ie.len > MAX_WPA_IE_LEN ||
-           (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL))
+       if (param->u.wpa_ie.len > MAX_WPA_IE_LEN)
                return -EINVAL;
 
        if (param->u.wpa_ie.len) {
                buf = kmemdup(param->u.wpa_ie.data, param->u.wpa_ie.len,
                              GFP_KERNEL);
-               if (buf == NULL)
+               if (!buf)
                        return -ENOMEM;
 
                kfree(ieee->wpa_ie);
@@ -2856,7 +2855,7 @@ static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee,
                goto done;
        }
 
-       if (*crypt == NULL || (*crypt)->ops != ops) {
+       if (!*crypt || (*crypt)->ops != ops) {
                struct ieee80211_crypt_data *new_crypt;
 
                ieee80211_crypt_delayed_deinit(ieee, crypt);
@@ -2871,7 +2870,7 @@ static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee,
                        new_crypt->priv =
                                new_crypt->ops->init(param->u.crypt.idx);
 
-               if (new_crypt->priv == NULL) {
+               if (!new_crypt->priv) {
                        kfree(new_crypt);
                        param->u.crypt.err = IEEE_CRYPT_ERR_CRYPT_INIT_FAILED;
                        ret = -EINVAL;
index aab1586..4a8d16a 100644 (file)
@@ -244,9 +244,9 @@ int ieee80211_wx_set_rts(struct ieee80211_device *ieee,
                             struct iw_request_info *info,
                             union iwreq_data *wrqu, char *extra)
 {
-       if (wrqu->rts.disabled || !wrqu->rts.fixed)
+       if (wrqu->rts.disabled || !wrqu->rts.fixed) {
                ieee->rts = DEFAULT_RTS_THRESHOLD;
-       else {
+       else {
                if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
                                wrqu->rts.value > MAX_RTS_THRESHOLD)
                        return -EINVAL;
index 8e1ec44..fc6eb97 100644 (file)
@@ -169,8 +169,7 @@ int ieee80211_encrypt_fragment(
        struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx];
        int res;
 
-       if (!(crypt && crypt->ops))
-       {
+       if (!(crypt && crypt->ops)) {
                printk("=========>%s(), crypt is null\n", __func__);
                return -1;
        }
@@ -309,32 +308,25 @@ static void ieee80211_tx_query_agg_cap(struct ieee80211_device *ieee,
        if (!Adapter->HalFunc.GetNmodeSupportBySecCfgHandler(Adapter))
                return;
 #endif
-       if (!ieee->GetNmodeSupportBySecCfg(ieee->dev))
-       {
+       if (!ieee->GetNmodeSupportBySecCfg(ieee->dev)) {
                return;
        }
-       if (pHTInfo->bCurrentAMPDUEnable)
-       {
-               if (!GetTs(ieee, (struct ts_common_info **)(&pTxTs), hdr->addr1, skb->priority, TX_DIR, true))
-               {
+       if (pHTInfo->bCurrentAMPDUEnable) {
+               if (!GetTs(ieee, (struct ts_common_info **)(&pTxTs), hdr->addr1, skb->priority, TX_DIR, true)) {
                        printk("===>can't get TS\n");
                        return;
                }
-               if (!pTxTs->tx_admitted_ba_record.valid)
-               {
+               if (!pTxTs->tx_admitted_ba_record.valid) {
                        TsStartAddBaProcess(ieee, pTxTs);
                        goto FORCED_AGG_SETTING;
-               }
-               else if (!pTxTs->using_ba)
-               {
+               } else if (!pTxTs->using_ba) {
                        if (SN_LESS(pTxTs->tx_admitted_ba_record.start_seq_ctrl.field.seq_num, (pTxTs->tx_cur_seq + 1) % 4096))
                                pTxTs->using_ba = true;
                        else
                                goto FORCED_AGG_SETTING;
                }
 
-               if (ieee->iw_mode == IW_MODE_INFRA)
-               {
+               if (ieee->iw_mode == IW_MODE_INFRA) {
                        tcb_desc->bAMPDUEnable = true;
                        tcb_desc->ampdu_factor = pHTInfo->CurrentAMPDUFactor;
                        tcb_desc->ampdu_density = pHTInfo->CurrentMPDUDensity;
@@ -366,12 +358,9 @@ static void ieee80211_qurey_ShortPreambleMode(struct ieee80211_device *ieee,
                                              struct cb_desc *tcb_desc)
 {
        tcb_desc->bUseShortPreamble = false;
-       if (tcb_desc->data_rate == 2)
-       {//// 1M can only use Long Preamble. 11B spec
+       if (tcb_desc->data_rate == 2) {//// 1M can only use Long Preamble. 11B spec
                return;
-       }
-       else if (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
-       {
+       } else if (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
                tcb_desc->bUseShortPreamble = true;
        }
        return;
@@ -386,8 +375,7 @@ ieee80211_query_HTCapShortGI(struct ieee80211_device *ieee, struct cb_desc *tcb_
        if (!pHTInfo->bCurrentHTSupport||!pHTInfo->bEnableHT)
                return;
 
-       if (pHTInfo->bForcedShortGI)
-       {
+       if (pHTInfo->bForcedShortGI) {
                tcb_desc->bUseShortGI = true;
                return;
        }
@@ -535,27 +523,25 @@ static void ieee80211_txrate_selectmode(struct ieee80211_device *ieee,
                                        struct cb_desc *tcb_desc)
 {
 #ifdef TO_DO_LIST
-       if(!IsDataFrame(pFrame))
-       {
+       if (!IsDataFrame(pFrame)) {
                pTcb->bTxDisableRateFallBack = true;
                pTcb->bTxUseDriverAssingedRate = true;
                pTcb->RATRIndex = 7;
                return;
        }
 
-       if(pMgntInfo->ForcedDataRate!= 0)
-       {
+       if (pMgntInfo->ForcedDataRate!= 0) {
                pTcb->bTxDisableRateFallBack = true;
                pTcb->bTxUseDriverAssingedRate = true;
                return;
        }
 #endif
-       if(ieee->bTxDisableRateFallBack)
+       if (ieee->bTxDisableRateFallBack)
                tcb_desc->bTxDisableRateFallBack = true;
 
-       if(ieee->bTxUseDriverAssingedRate)
+       if (ieee->bTxUseDriverAssingedRate)
                tcb_desc->bTxUseDriverAssingedRate = true;
-       if(!tcb_desc->bTxDisableRateFallBack || !tcb_desc->bTxUseDriverAssingedRate)
+       if (!tcb_desc->bTxDisableRateFallBack || !tcb_desc->bTxUseDriverAssingedRate)
        {
                if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC)
                        tcb_desc->RATRIndex = 0;
@@ -614,7 +600,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
 
-       if(likely(ieee->raw_tx == 0)){
+       if (likely(ieee->raw_tx == 0)) {
                if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) {
                        printk(KERN_WARNING "%s: skb too small (%d).\n",
                        ieee->dev->name, skb->len);
@@ -690,15 +676,13 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
                if (is_multicast_ether_addr(header.addr1)) {
                        frag_size = MAX_FRAG_THRESHOLD;
                        qos_ctl |= QOS_CTL_NOTCONTAIN_ACK;
-               }
-               else {
+               } else {
                        frag_size = ieee->fts;//default:392
                        qos_ctl = 0;
                }
 
                //if (ieee->current_network.QoS_Enable)
-               if(qos_actived)
-               {
+               if (qos_actived) {
                        hdr_len = IEEE80211_3ADDR_LEN + 2;
 
                        skb->priority = ieee80211_classify(skb, &ieee->current_network);
@@ -746,12 +730,10 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
                txb->payload_size = __cpu_to_le16(bytes);
 
                //if (ieee->current_network.QoS_Enable)
-               if(qos_actived)
-               {
+               if (qos_actived)
                        txb->queue_index = UP2AC(skb->priority);
-               } else {
+               else
                        txb->queue_index = WME_AC_BK;
-               }
 
 
 
index dead134..be08cd1 100644 (file)
@@ -243,8 +243,7 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
 
        list_for_each_entry(network, &ieee->network_list, list) {
                i++;
-               if((stop-ev)<200)
-               {
+               if((stop-ev)<200) {
                        err = -E2BIG;
                        break;
                }
@@ -312,7 +311,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
                /* Check all the keys to see if any are still configured,
                 * and if no key index was provided, de-init them all */
                for (i = 0; i < WEP_KEYS; i++) {
-                       if (ieee->crypt[i] != NULL) {
+                       if (ieee->crypt[i]) {
                                if (key_provided)
                                        break;
                                ieee80211_crypt_delayed_deinit(
@@ -334,14 +333,14 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
        sec.enabled = 1;
        sec.flags |= SEC_ENABLED;
 
-       if (*crypt != NULL && (*crypt)->ops != NULL &&
+       if (*crypt && (*crypt)->ops &&
            strcmp((*crypt)->ops->name, "WEP") != 0) {
                /* changing to use WEP; deinit previously used algorithm
                 * on this key */
                ieee80211_crypt_delayed_deinit(ieee, crypt);
        }
 
-       if (*crypt == NULL) {
+       if (!*crypt) {
                struct ieee80211_crypt_data *new_crypt;
 
                /* take WEP into use */
@@ -469,7 +468,7 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
        crypt = ieee->crypt[key];
        erq->flags = key + 1;
 
-       if (crypt == NULL || crypt->ops == NULL) {
+       if (!crypt || !crypt->ops) {
                erq->length = 0;
                erq->flags |= IW_ENCODE_DISABLED;
                return 0;
@@ -538,7 +537,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
 
                for (i = 0; i < WEP_KEYS; i++)
 
-                       if (ieee->crypt[i] != NULL)
+                       if (ieee->crypt[i])
 
                                break;
 
@@ -583,7 +582,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
                goto done;
        }
 
-       if (*crypt == NULL || (*crypt)->ops != ops) {
+       if (!*crypt || (*crypt)->ops != ops) {
                struct ieee80211_crypt_data *new_crypt;
 
                ieee80211_crypt_delayed_deinit(ieee, crypt);
@@ -596,7 +595,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
                new_crypt->ops = ops;
                if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
                        new_crypt->priv = new_crypt->ops->init(idx);
-               if (new_crypt->priv == NULL) {
+               if (!new_crypt->priv) {
                        kfree(new_crypt);
                        ret = -EINVAL;
                        goto done;
@@ -684,7 +683,7 @@ int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee,
        encoding->flags = idx + 1;
        memset(ext, 0, sizeof(*ext));
 
-       if (crypt == NULL || crypt->ops == NULL ) {
+       if (!crypt || !crypt->ops) {
                ext->alg = IW_ENCODE_ALG_NONE;
                ext->key_len = 0;
                encoding->flags |= IW_ENCODE_DISABLED;
@@ -761,8 +760,7 @@ int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
                } else if (data->value & IW_AUTH_ALG_LEAP) {
                        ieee->open_wep = 1;
                        ieee->auth_mode = 2;
-               }
-               else
+               } else
                        return -EINVAL;
                break;
 
@@ -787,28 +785,24 @@ int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
 {
        u8 *buf;
 
-       if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
-       {
+       if (len>MAX_WPA_IE_LEN || (len && !ie)) {
        //      printk("return error out, len:%d\n", len);
        return -EINVAL;
        }
 
 
-       if (len)
-       {
-               if (len != ie[1]+2)
-               {
+       if (len) {
+               if (len != ie[1]+2) {
                        printk("len:%zu, ie:%d\n", len, ie[1]);
                        return -EINVAL;
                }
                buf = kmemdup(ie, len, GFP_KERNEL);
-               if (buf == NULL)
+               if (!buf)
                        return -ENOMEM;
                kfree(ieee->wpa_ie);
                ieee->wpa_ie = buf;
                ieee->wpa_ie_len = len;
-       }
-       else{
+       } else {
                kfree(ieee->wpa_ie);
                ieee->wpa_ie = NULL;
                ieee->wpa_ie_len = 0;
index 7cac668..59d179a 100644 (file)
@@ -51,7 +51,7 @@ static void RxPktPendingTimeout(struct timer_list *t)
                                if (SN_EQUAL(pReorderEntry->SeqNum, pRxTs->rx_indicate_seq))
                                        pRxTs->rx_indicate_seq = (pRxTs->rx_indicate_seq + 1) % 4096;
 
-                               IEEE80211_DEBUG(IEEE80211_DL_REORDER, "RxPktPendingTimeout(): IndicateSeq: %d\n", pReorderEntry->SeqNum);
+                               IEEE80211_DEBUG(IEEE80211_DL_REORDER, "%s: IndicateSeq: %d\n", __func__, pReorderEntry->SeqNum);
                                ieee->stats_IndicateArray[index] = pReorderEntry->prxb;
                                index++;
 
@@ -97,7 +97,7 @@ static void TsAddBaProcess(struct timer_list *t)
        struct ieee80211_device *ieee = container_of(pTxTs, struct ieee80211_device, TxTsRecord[num]);
 
        TsInitAddBA(ieee, pTxTs, BA_POLICY_IMMEDIATE, false);
-       IEEE80211_DEBUG(IEEE80211_DL_BA, "TsAddBaProcess(): ADDBA Req is started!! \n");
+       IEEE80211_DEBUG(IEEE80211_DL_BA, "%s: ADDBA Req is started!! \n", __func__);
 }
 
 
@@ -456,7 +456,7 @@ void RemovePeerTS(struct ieee80211_device *ieee, u8 *Addr)
 {
        struct ts_common_info   *pTS, *pTmpTS;
 
-       printk("===========>RemovePeerTS,%pM\n", Addr);
+       printk("===========>%s,%pM\n", __func__, Addr);
        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, list) {
                if (memcmp(pTS->addr, Addr, 6) == 0) {
                        RemoveTsEntry(ieee, pTS, TX_DIR);
@@ -525,11 +525,11 @@ void TsStartAddBaProcess(struct ieee80211_device *ieee, struct tx_ts_record *pTx
        if (!pTxTS->add_ba_req_in_progress) {
                pTxTS->add_ba_req_in_progress = true;
                if (pTxTS->add_ba_req_delayed)  {
-                       IEEE80211_DEBUG(IEEE80211_DL_BA, "TsStartAddBaProcess(): Delayed Start ADDBA after 60 sec!!\n");
+                       IEEE80211_DEBUG(IEEE80211_DL_BA, "%s: Delayed Start ADDBA after 60 sec!!\n", __func__);
                        mod_timer(&pTxTS->ts_add_ba_timer,
                                  jiffies + msecs_to_jiffies(TS_ADDBA_DELAY));
                } else {
-                       IEEE80211_DEBUG(IEEE80211_DL_BA, "TsStartAddBaProcess(): Immediately Start ADDBA now!!\n");
+                       IEEE80211_DEBUG(IEEE80211_DL_BA, "%s: Immediately Start ADDBA now!!\n", __func__);
                        mod_timer(&pTxTS->ts_add_ba_timer, jiffies+10); //set 10 ticks
                }
        } else {
index 4065a47..fe1f279 100644 (file)
@@ -713,7 +713,7 @@ static u32 get_rxpacket_shiftbytes_819xusb(struct ieee80211_rx_stats *pstats)
                + pstats->RxBufShift);
 }
 
-static int rtl8192_rx_initiate(struct net_device *dev)
+void rtl8192_rx_enable(struct net_device *dev)
 {
        struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev);
        struct urb *entry;
@@ -763,8 +763,6 @@ static int rtl8192_rx_initiate(struct net_device *dev)
                skb_queue_tail(&priv->rx_queue, skb);
                usb_submit_urb(entry, GFP_KERNEL);
        }
-
-       return 0;
 }
 
 void rtl8192_set_rxconf(struct net_device *dev)
@@ -810,12 +808,6 @@ void rtl8192_set_rxconf(struct net_device *dev)
        write_nic_dword(dev, RCR, rxconf);
 }
 
-/* wait to be removed */
-void rtl8192_rx_enable(struct net_device *dev)
-{
-       rtl8192_rx_initiate(dev);
-}
-
 void rtl8192_rtx_disable(struct net_device *dev)
 {
        u8 cmd;
index 2ba0104..ade14ef 100644 (file)
@@ -99,8 +99,7 @@ static        void    dm_dynamic_txpower(struct net_device *dev);
 static void dm_send_rssi_tofw(struct net_device *dev);
 static void    dm_ctstoself(struct net_device *dev);
 /*---------------------------Define function prototype------------------------*/
-/*
- * ================================================================================
+/* ================================================================================
  *     HW Dynamic mechanism interface.
  * ================================================================================
  *
@@ -178,8 +177,7 @@ void dm_CheckRxAggregation(struct net_device *dev)
 
                        ulValue = (pHTInfo->UsbRxFwAggrEn<<24) | (pHTInfo->UsbRxFwAggrPageNum<<16) |
                                (pHTInfo->UsbRxFwAggrPacketNum<<8) | (pHTInfo->UsbRxFwAggrTimeout);
-                       /*
-                        * If usb rx firmware aggregation is enabled,
+                       /* If usb rx firmware aggregation is enabled,
                         * when anyone of three threshold conditions above is reached,
                         * firmware will send aggregated packet to driver.
                         */
@@ -219,8 +217,7 @@ void hal_dm_watchdog(struct net_device *dev)
 #endif
 }      /* HalDmWatchDog */
 
-/*
- * Decide Rate Adaptive Set according to distance (signal strength)
+/* Decide Rate Adaptive Set according to distance (signal strength)
  *     01/11/2008      MHC             Modify input arguments and RATR table level.
  *     01/16/2008      MHC             RF_Type is assigned in ReadAdapterInfo(). We must call
  *                                             the function after making sure RF_Type.
@@ -246,8 +243,7 @@ void init_rate_adaptive(struct net_device *dev)
        pra->ping_rssi_thresh_for_ra = 15;
 
        if (priv->rf_type == RF_2T4R) {
-               /*
-                * 07/10/08 MH Modify for RA smooth scheme.
+               /* 07/10/08 MH Modify for RA smooth scheme.
                 * 2008/01/11 MH Modify 2T RATR table for different RSSI. 080515 porting by amy from windows code.
                 */
                pra->upper_rssi_threshold_ratr          =       0x8f0f0000;
@@ -336,9 +332,10 @@ static void dm_check_rate_adaptive(struct net_device *dev)
                                ((bshort_gi_enabled) ? BIT(31) : 0);
 
                /* 2007/10/08 MH We support RA smooth scheme now. When it is the first
-                  time to link with AP. We will not change upper/lower threshold. If
-                  STA stay in high or low level, we must change two different threshold
-                  to prevent jumping frequently. */
+                * time to link with AP. We will not change upper/lower threshold. If
+                * STA stay in high or low level, we must change two different threshold
+                * to prevent jumping frequently.
+                */
                if (pra->ratr_state == DM_RATR_STA_HIGH) {
                        HighRSSIThreshForRA     = pra->high2low_rssi_thresh_for_ra;
                        LowRSSIThreshForRA      = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ?
@@ -387,8 +384,7 @@ static void dm_check_rate_adaptive(struct net_device *dev)
                        }
                }
 
-               /*
-                * 2008.04.01
+               /* 2008.04.01
                 * For RTL819X, if pairwisekey = wep/tkip, we support only MCS0~7.
                 */
                if (priv->ieee80211->GetHalfNmodeSupportByAPsHandler(dev))
@@ -683,8 +679,7 @@ static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device *dev)
                return;
        }
 
-       /*
-        * ==========================
+       /* ==========================
         * this is only for test, should be masked
         * ==========================
         */
@@ -850,8 +845,7 @@ static void dm_InitializeTXPowerTracking_TSSI(struct net_device *dev)
        priv->txbbgain_table[36].txbb_iq_amplifygain =               -24;
        priv->txbbgain_table[36].txbbgain_value = 0x10000040;
 
-       /*
-        * ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29
+       /* ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29
         * This Table is for CH1~CH13
         */
        priv->cck_txbbgain_table[0].ccktxbb_valuearray[0] = 0x36;
@@ -1061,8 +1055,7 @@ static void dm_InitializeTXPowerTracking_TSSI(struct net_device *dev)
        priv->cck_txbbgain_table[22].ccktxbb_valuearray[6] = 0x03;
        priv->cck_txbbgain_table[22].ccktxbb_valuearray[7] = 0x01;
 
-       /*
-        * ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29
+       /* ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29
         * This Table is for CH14
         */
        priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[0] = 0x36;
@@ -1282,8 +1275,7 @@ static void dm_InitializeTXPowerTracking_ThermalMeter(struct net_device *dev)
 {
        struct r8192_priv *priv = ieee80211_priv(dev);
 
-       /*
-        * Tx Power tracking by Thermal Meter requires Firmware R/W 3-wire. This mechanism
+       /* Tx Power tracking by Thermal Meter requires Firmware R/W 3-wire. This mechanism
         * can be enabled only when Firmware R/W 3-wire is enabled. Otherwise, frequent r/w
         * 3-wire by driver causes RF to go into a wrong state.
         */
@@ -1330,8 +1322,7 @@ static void dm_CheckTXPowerTracking_ThermalMeter(struct net_device *dev)
        }
 
        if (!TM_Trigger) {
-               /*
-                * Attention!! You have to write all 12bits of data to RF, or it may cause RF to crash
+               /* Attention!! You have to write all 12bits of data to RF, or it may cause RF to crash
                 * actually write reg0x02 bit1=0, then bit1=1.
                 * DbgPrint("Trigger ThermalMeter, write RF reg0x2 = 0x4d to 0x4f\n");
                 */
@@ -1563,18 +1554,6 @@ static void dm_bb_initialgain_restore(struct net_device *dev)
 
 }      /* dm_BBInitialGainRestore */
 
-void dm_backup_dynamic_mechanism_state(struct net_device *dev)
-{
-       struct r8192_priv *priv = ieee80211_priv(dev);
-
-       /* Fsync to avoid reset */
-       priv->bswitch_fsync  = false;
-       priv->bfsync_processing = false;
-       /* Backup BB InitialGain */
-       dm_bb_initialgain_backup(dev);
-
-}      /* DM_BackupDynamicMechanismState */
-
 static void dm_bb_initialgain_backup(struct net_device *dev)
 {
        struct r8192_priv *priv = ieee80211_priv(dev);
@@ -1748,10 +1727,12 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(
        pHalData->UndecoratedSmoothedPWDB, DM_DigTable.RssiLowThresh,
        DM_DigTable.RssiHighThresh, DM_DigTable.Dig_State);*/
        /* 1. When RSSI decrease, We have to judge if it is smaller than a threshold
-                 and then execute the step below. */
+        * and then execute the step below.
+        */
        if (priv->undecorated_smoothed_pwdb <= dm_digtable.rssi_low_thresh) {
                /* 2008/02/05 MH When we execute silent reset, the DIG PHY parameters
-                  will be reset to init value. We must prevent the condition. */
+                * will be reset to init value. We must prevent the condition.
+                */
                if (dm_digtable.dig_state == DM_STA_DIG_OFF &&
                    (priv->reset_count == reset_cnt)) {
                        return;
@@ -1773,8 +1754,7 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(
 
                /*  1.3 Lower PD_TH for OFDM. */
                if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
-                       /*
-                        * 2008/01/11 MH 40MHZ 90/92 register are not the same.
+                       /* 2008/01/11 MH 40MHZ 90/92 register are not the same.
                         * 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
                         */
                        write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00);
@@ -1797,7 +1777,8 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(
        }
 
        /* 2. When RSSI increase, We have to judge if it is larger than a threshold
-                 and then execute the step below.  */
+        * and then execute the step below.
+        */
        if (priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh) {
                u8 reset_flag = 0;
 
@@ -1814,8 +1795,7 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(
                dm_digtable.dig_state = DM_STA_DIG_ON;
                /*DbgPrint("DIG ON\n\r");*/
 
-               /*
-                * 2.1 Set initial gain.
+               /* 2.1 Set initial gain.
                 * 2008/02/26 MH SD3-Jerry suggest to prevent dirty environment.
                 */
                if (reset_flag == 1) {
@@ -1832,8 +1812,7 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(
 
                /* 2.2 Higher PD_TH for OFDM. */
                if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
-                       /*
-                        * 2008/01/11 MH 40MHZ 90/92 register are not the same.
+                       /* 2008/01/11 MH 40MHZ 90/92 register are not the same.
                         * 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
                         */
                        write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20);
@@ -1850,8 +1829,7 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(
                /* 2.3 Higher CS ratio for CCK. */
                write_nic_byte(dev, 0xa0a, 0xcd);
 
-               /*
-                * 2.4 Lower EDCCA.
+               /* 2.4 Lower EDCCA.
                 * 2008/01/11 MH 90/92 series are the same.
                 */
                /*PlatformEFIOWrite4Byte(pAdapter, rOFDM0_ECCAThreshold, 0x346);*/
@@ -1892,8 +1870,7 @@ static void dm_ctrl_initgain_byrssi_highpwr(
                (priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_power_highthresh))
                return;
 
-       /*
-        * 3. When RSSI >75% or <70%, it is a high power issue. We have to judge if
+       /* 3. When RSSI >75% or <70%, it is a high power issue. We have to judge if
         *    it is larger than a threshold and then execute the step below.
         *
         * 2008/02/05 MH SD3-Jerry Modify PD_TH for high power issue.
@@ -2042,8 +2019,7 @@ static void dm_pd_th(
                        if (dm_digtable.curpd_thstate == DIG_PD_AT_LOW_POWER) {
                                /*  Lower PD_TH for OFDM. */
                                if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
-                                       /*
-                                        * 2008/01/11 MH 40MHZ 90/92 register are not the same.
+                                       /* 2008/01/11 MH 40MHZ 90/92 register are not the same.
                                         * 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
                                         */
                                        write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00);
@@ -2055,8 +2031,7 @@ static void dm_pd_th(
                        } else if (dm_digtable.curpd_thstate == DIG_PD_AT_NORMAL_POWER) {
                                /* Higher PD_TH for OFDM. */
                                if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
-                                       /*
-                                        * 2008/01/11 MH 40MHZ 90/92 register are not the same.
+                                       /* 2008/01/11 MH 40MHZ 90/92 register are not the same.
                                         * 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
                                         */
                                        write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20);
@@ -2155,8 +2130,7 @@ static void dm_check_edca_turbo(
        unsigned long                           curTxOkCnt = 0;
        unsigned long                           curRxOkCnt = 0;
 
-       /*
-        * Do not be Turbo if it's under WiFi config and Qos Enabled, because the EDCA parameters
+       /* Do not be Turbo if it's under WiFi config and Qos Enabled, because the EDCA parameters
         * should follow the settings from QAP. By Bruce, 2007-12-07.
         */
        if (priv->ieee80211->state != IEEE80211_LINKED)
@@ -2188,8 +2162,7 @@ static void dm_check_edca_turbo(
 
                priv->bcurrent_turbo_EDCA = true;
        } else {
-               /*
-                * Turn Off EDCA turbo here.
+               /* Turn Off EDCA turbo here.
                 * Restore original EDCA according to the declaration of AP.
                 */
                if (priv->bcurrent_turbo_EDCA) {
@@ -2219,8 +2192,7 @@ static void dm_check_edca_turbo(
                        write_nic_dword(dev, EDCAPARA_BE, u4bAcParam);
 
 
-                       /*
-                        * Check ACM bit.
+                       /* Check ACM bit.
                         * If it is set, immediately set ACM control bit to downgrading AC for passing WMM testplan. Annie, 2005-12-13.
                         */
                        {
@@ -2272,11 +2244,10 @@ static void dm_ctstoself(struct net_device *dev)
                pHTInfo->IOTAction &= ~HT_IOT_ACT_FORCED_CTS2SELF;
                return;
        }
-       /*
-       1. Uplink
-       2. Linksys350/Linksys300N
-       3. <50 disable, >55 enable
-       */
+       /* 1. Uplink
+        * 2. Linksys350/Linksys300N
+        * 3. <50 disable, >55 enable
+        */
 
        if (pHTInfo->IOTPeer == HT_IOT_PEER_BROADCOM) {
                curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt;
@@ -2319,8 +2290,7 @@ static    void    dm_check_pbc_gpio(struct net_device *dev)
                return;
 
        if (tmp1byte & BIT(6) || tmp1byte & BIT(0)) {
-               /*
-                * Here we only set bPbcPressed to TRUE
+               /* Here we only set bPbcPressed to TRUE
                 * After trigger PBC, the variable will be set to FALSE
                 */
                RT_TRACE(COMP_IO, "CheckPbcGPIO - PBC is pressed\n");
@@ -2354,7 +2324,8 @@ void dm_rf_pathcheck_workitemcallback(struct work_struct *work)
        u8 rfpath = 0, i;
 
        /* 2008/01/30 MH After discussing with SD3 Jerry, 0xc04/0xd04 register will
-          always be the same. We only read 0xc04 now. */
+        * always be the same. We only read 0xc04 now.
+        */
        read_nic_byte(dev, 0xc04, &rfpath);
 
        /* Check Bit 0-3, it means if RF A-D is enabled. */
@@ -2529,8 +2500,7 @@ static void dm_rxpath_sel_byrssi(struct net_device *dev)
                }
        }
 
-       /*
-        * Set CCK Rx path
+       /* Set CCK Rx path
         * reg0xA07[3:2]=cck default rx path, reg0xa07[1:0]=cck optional rx path.
         */
        update_cck_rx_path = 0;
@@ -3049,8 +3019,7 @@ static void dm_send_rssi_tofw(struct net_device *dev)
 {
        struct r8192_priv *priv = ieee80211_priv(dev);
 
-       /*
-        * If we test chariot, we should stop the TX command ?
+       /* If we test chariot, we should stop the TX command ?
         * Because 92E will always silent reset when we send tx command. We use register
         * 0x1e0(byte) to notify driver.
         */
index 0de0332..0b2a1c6 100644 (file)
@@ -161,7 +161,6 @@ void hal_dm_watchdog(struct net_device *dev);
 void init_rate_adaptive(struct net_device *dev);
 void dm_txpower_trackingcallback(struct work_struct *work);
 void dm_restore_dynamic_mechanism_state(struct net_device *dev);
-void dm_backup_dynamic_mechanism_state(struct net_device *dev);
 void dm_force_tx_fw_info(struct net_device *dev,
                         u32 force_type, u32 force_value);
 void dm_init_edca_turbo(struct net_device *dev);
index 9ae8663..0c43250 100644 (file)
@@ -148,14 +148,9 @@ struct _adapter {
        bool    driver_stopped;
        bool    surprise_removed;
        bool    suspended;
-       u32     IsrContent;
-       u32     ImrContent;
-       u8      EepromAddressSize;
+       u8      eeprom_address_size;
        u8      hw_init_completed;
-       struct task_struct *cmdThread;
-       pid_t evtThread;
-       struct task_struct *xmitThread;
-       pid_t recvThread;
+       struct task_struct *cmd_thread;
        uint (*dvobj_init)(struct _adapter *adapter);
        void (*dvobj_deinit)(struct _adapter *adapter);
        struct net_device *pnetdev;
@@ -163,9 +158,9 @@ struct _adapter {
        struct net_device_stats stats;
        struct iw_statistics iwstats;
        int pid; /*process id from UI*/
-       struct work_struct wkFilterRxFF0;
+       struct work_struct wk_filter_rx_ff0;
        u8 blnEnableRxFF0Filter;
-       spinlock_t lockRxFF0Filter;
+       spinlock_t lock_rx_ff0_filter;
        const struct firmware *fw;
        struct usb_interface *pusb_intf;
        struct mutex mutex_start;
index 401f0e4..40145c0 100644 (file)
 
 static void rtl871x_load_fw_cb(const struct firmware *firmware, void *context)
 {
-       struct _adapter *padapter = context;
+       struct _adapter *adapter = context;
 
-       complete(&padapter->rtl8712_fw_ready);
+       complete(&adapter->rtl8712_fw_ready);
        if (!firmware) {
-               struct usb_device *udev = padapter->dvobjpriv.pusbdev;
-               struct usb_interface *pusb_intf = padapter->pusb_intf;
+               struct usb_device *udev = adapter->dvobjpriv.pusbdev;
+               struct usb_interface *usb_intf = adapter->pusb_intf;
 
                dev_err(&udev->dev, "r8712u: Firmware request failed\n");
                usb_put_dev(udev);
-               usb_set_intfdata(pusb_intf, NULL);
+               usb_set_intfdata(usb_intf, NULL);
                return;
        }
-       padapter->fw = firmware;
+       adapter->fw = firmware;
        /* firmware available - start netdev */
-       register_netdev(padapter->pnetdev);
+       register_netdev(adapter->pnetdev);
 }
 
 static const char firmware_file[] = "rtlwifi/rtl8712u.bin";
@@ -65,47 +65,47 @@ int rtl871x_load_fw(struct _adapter *padapter)
 }
 MODULE_FIRMWARE("rtlwifi/rtl8712u.bin");
 
-static u32 rtl871x_open_fw(struct _adapter *padapter, const u8 **ppmappedfw)
+static u32 rtl871x_open_fw(struct _adapter *adapter, const u8 **mappedfw)
 {
-       const struct firmware **praw = &padapter->fw;
+       const struct firmware **raw = &adapter->fw;
 
-       if (padapter->fw->size > 200000) {
-               dev_err(&padapter->pnetdev->dev, "r8172u: Badfw->size of %d\n",
-                       (int)padapter->fw->size);
+       if (adapter->fw->size > 200000) {
+               dev_err(&adapter->pnetdev->dev, "r8172u: Badfw->size of %d\n",
+                       (int)adapter->fw->size);
                return 0;
        }
-       *ppmappedfw = (*praw)->data;
-       return (*praw)->size;
+       *mappedfw = (*raw)->data;
+       return (*raw)->size;
 }
 
-static void fill_fwpriv(struct _adapter *padapter, struct fw_priv *pfwpriv)
+static void fill_fwpriv(struct _adapter *adapter, struct fw_priv *fwpriv)
 {
-       struct dvobj_priv *pdvobj = &padapter->dvobjpriv;
-       struct registry_priv *pregpriv = &padapter->registrypriv;
+       struct dvobj_priv *dvobj = &adapter->dvobjpriv;
+       struct registry_priv *regpriv = &adapter->registrypriv;
 
-       memset(pfwpriv, 0, sizeof(struct fw_priv));
+       memset(fwpriv, 0, sizeof(struct fw_priv));
        /* todo: check if needs endian conversion */
-       pfwpriv->hci_sel =  RTL8712_HCI_TYPE_72USB;
-       pfwpriv->usb_ep_num = (u8)pdvobj->nr_endpoint;
-       pfwpriv->bw_40MHz_en = pregpriv->cbw40_enable;
-       switch (pregpriv->rf_config) {
+       fwpriv->hci_sel =  RTL8712_HCI_TYPE_72USB;
+       fwpriv->usb_ep_num = (u8)dvobj->nr_endpoint;
+       fwpriv->bw_40MHz_en = regpriv->cbw40_enable;
+       switch (regpriv->rf_config) {
        case RTL8712_RF_1T1R:
-               pfwpriv->rf_config = RTL8712_RFC_1T1R;
+               fwpriv->rf_config = RTL8712_RFC_1T1R;
                break;
        case RTL8712_RF_2T2R:
-               pfwpriv->rf_config = RTL8712_RFC_2T2R;
+               fwpriv->rf_config = RTL8712_RFC_2T2R;
                break;
        case RTL8712_RF_1T2R:
        default:
-               pfwpriv->rf_config = RTL8712_RFC_1T2R;
+               fwpriv->rf_config = RTL8712_RFC_1T2R;
        }
-       pfwpriv->mp_mode = (pregpriv->mp_mode == 1) ? 1 : 0;
+       fwpriv->mp_mode = (regpriv->mp_mode == 1) ? 1 : 0;
        /* 0:off 1:on 2:auto */
-       pfwpriv->vcs_type = pregpriv->vrtl_carrier_sense;
-       pfwpriv->vcs_mode = pregpriv->vcs_type; /* 1:RTS/CTS 2:CTS to self */
+       fwpriv->vcs_type = regpriv->vrtl_carrier_sense;
+       fwpriv->vcs_mode = regpriv->vcs_type; /* 1:RTS/CTS 2:CTS to self */
        /* default enable turbo_mode */
-       pfwpriv->turbo_mode = ((pregpriv->wifi_test == 1) ? 0 : 1);
-       pfwpriv->low_power_mode = pregpriv->low_power;
+       fwpriv->turbo_mode = ((regpriv->wifi_test == 1) ? 0 : 1);
+       fwpriv->low_power_mode = regpriv->low_power;
 }
 
 static void update_fwhdr(struct fw_hdr *pfwhdr, const u8 *pmappedfw)
@@ -141,7 +141,7 @@ static u8 chk_fwhdr(struct fw_hdr *pfwhdr, u32 ulfilelength)
        return _SUCCESS;
 }
 
-static u8 rtl8712_dl_fw(struct _adapter *padapter)
+static u8 rtl8712_dl_fw(struct _adapter *adapter)
 {
        sint i;
        u8 tmp8, tmp8_a;
@@ -150,56 +150,56 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter)
        uint dump_imem_sz, imem_sz, dump_emem_sz, emem_sz; /* max = 49152; */
        struct fw_hdr fwhdr;
        u32 ulfilelength;       /* FW file size */
-       const u8 *pmappedfw = NULL;
-       u8 *ptmpchar = NULL, *ppayload, *ptr;
-       struct tx_desc *ptx_desc;
+       const u8 *mappedfw = NULL;
+       u8 *tmpchar = NULL, *payload, *ptr;
+       struct tx_desc *txdesc;
        u32 txdscp_sz = sizeof(struct tx_desc);
        u8 ret = _FAIL;
 
-       ulfilelength = rtl871x_open_fw(padapter, &pmappedfw);
-       if (pmappedfw && (ulfilelength > 0)) {
-               update_fwhdr(&fwhdr, pmappedfw);
+       ulfilelength = rtl871x_open_fw(adapter, &mappedfw);
+       if (mappedfw && (ulfilelength > 0)) {
+               update_fwhdr(&fwhdr, mappedfw);
                if (chk_fwhdr(&fwhdr, ulfilelength) == _FAIL)
                        return ret;
-               fill_fwpriv(padapter, &fwhdr.fwpriv);
+               fill_fwpriv(adapter, &fwhdr.fwpriv);
                /* firmware check ok */
                maxlen = (fwhdr.img_IMEM_size > fwhdr.img_SRAM_size) ?
                          fwhdr.img_IMEM_size : fwhdr.img_SRAM_size;
                maxlen += txdscp_sz;
-               ptmpchar = kmalloc(maxlen + FWBUFF_ALIGN_SZ, GFP_KERNEL);
-               if (!ptmpchar)
+               tmpchar = kmalloc(maxlen + FWBUFF_ALIGN_SZ, GFP_KERNEL);
+               if (!tmpchar)
                        return ret;
 
-               ptx_desc = (struct tx_desc *)(ptmpchar + FWBUFF_ALIGN_SZ -
-                           ((addr_t)(ptmpchar) & (FWBUFF_ALIGN_SZ - 1)));
-               ppayload = (u8 *)(ptx_desc) + txdscp_sz;
-               ptr = (u8 *)pmappedfw + FIELD_OFFSET(struct fw_hdr, fwpriv) +
+               txdesc = (struct tx_desc *)(tmpchar + FWBUFF_ALIGN_SZ -
+                           ((addr_t)(tmpchar) & (FWBUFF_ALIGN_SZ - 1)));
+               payload = (u8 *)(txdesc) + txdscp_sz;
+               ptr = (u8 *)mappedfw + FIELD_OFFSET(struct fw_hdr, fwpriv) +
                      fwhdr.fw_priv_sz;
                /* Download FirmWare */
                /* 1. determine IMEM code size and Load IMEM Code Section */
                imem_sz = fwhdr.img_IMEM_size;
                do {
-                       memset(ptx_desc, 0, TXDESC_SIZE);
+                       memset(txdesc, 0, TXDESC_SIZE);
                        if (imem_sz >  MAX_DUMP_FWSZ/*49152*/) {
                                dump_imem_sz = MAX_DUMP_FWSZ;
                        } else {
                                dump_imem_sz = imem_sz;
-                               ptx_desc->txdw0 |= cpu_to_le32(BIT(28));
+                               txdesc->txdw0 |= cpu_to_le32(BIT(28));
                        }
-                       ptx_desc->txdw0 |= cpu_to_le32(dump_imem_sz &
+                       txdesc->txdw0 |= cpu_to_le32(dump_imem_sz &
                                                       0x0000ffff);
-                       memcpy(ppayload, ptr, dump_imem_sz);
-                       r8712_write_mem(padapter, RTL8712_DMA_VOQ,
+                       memcpy(payload, ptr, dump_imem_sz);
+                       r8712_write_mem(adapter, RTL8712_DMA_VOQ,
                                        dump_imem_sz + TXDESC_SIZE,
-                                       (u8 *)ptx_desc);
+                                       (u8 *)txdesc);
                        ptr += dump_imem_sz;
                        imem_sz -= dump_imem_sz;
                } while (imem_sz > 0);
                i = 10;
-               tmp16 = r8712_read16(padapter, TCR);
+               tmp16 = r8712_read16(adapter, TCR);
                while (((tmp16 & _IMEM_CODE_DONE) == 0) && (i > 0)) {
                        usleep_range(10, 1000);
-                       tmp16 = r8712_read16(padapter, TCR);
+                       tmp16 = r8712_read16(adapter, TCR);
                        i--;
                }
                if (i == 0 || (tmp16 & _IMEM_CHK_RPT) == 0)
@@ -208,94 +208,94 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter)
                /* 2.Download EMEM code size and Load EMEM Code Section */
                emem_sz = fwhdr.img_SRAM_size;
                do {
-                       memset(ptx_desc, 0, TXDESC_SIZE);
+                       memset(txdesc, 0, TXDESC_SIZE);
                        if (emem_sz >  MAX_DUMP_FWSZ) { /* max=48k */
                                dump_emem_sz = MAX_DUMP_FWSZ;
                        } else {
                                dump_emem_sz = emem_sz;
-                               ptx_desc->txdw0 |= cpu_to_le32(BIT(28));
+                               txdesc->txdw0 |= cpu_to_le32(BIT(28));
                        }
-                       ptx_desc->txdw0 |= cpu_to_le32(dump_emem_sz &
+                       txdesc->txdw0 |= cpu_to_le32(dump_emem_sz &
                                                       0x0000ffff);
-                       memcpy(ppayload, ptr, dump_emem_sz);
-                       r8712_write_mem(padapter, RTL8712_DMA_VOQ,
+                       memcpy(payload, ptr, dump_emem_sz);
+                       r8712_write_mem(adapter, RTL8712_DMA_VOQ,
                                        dump_emem_sz + TXDESC_SIZE,
-                                       (u8 *)ptx_desc);
+                                       (u8 *)txdesc);
                        ptr += dump_emem_sz;
                        emem_sz -= dump_emem_sz;
                } while (emem_sz > 0);
                i = 5;
-               tmp16 = r8712_read16(padapter, TCR);
+               tmp16 = r8712_read16(adapter, TCR);
                while (((tmp16 & _EMEM_CODE_DONE) == 0) && (i > 0)) {
                        usleep_range(10, 1000);
-                       tmp16 = r8712_read16(padapter, TCR);
+                       tmp16 = r8712_read16(adapter, TCR);
                        i--;
                }
                if (i == 0 || (tmp16 & _EMEM_CHK_RPT) == 0)
                        goto exit_fail;
 
                /* 3.Enable CPU */
-               tmp8 = r8712_read8(padapter, SYS_CLKR);
-               r8712_write8(padapter, SYS_CLKR, tmp8 | BIT(2));
-               tmp8_a = r8712_read8(padapter, SYS_CLKR);
+               tmp8 = r8712_read8(adapter, SYS_CLKR);
+               r8712_write8(adapter, SYS_CLKR, tmp8 | BIT(2));
+               tmp8_a = r8712_read8(adapter, SYS_CLKR);
                if (tmp8_a != (tmp8 | BIT(2)))
                        goto exit_fail;
 
-               tmp8 = r8712_read8(padapter, SYS_FUNC_EN + 1);
-               r8712_write8(padapter, SYS_FUNC_EN + 1, tmp8 | BIT(2));
-               tmp8_a = r8712_read8(padapter, SYS_FUNC_EN + 1);
+               tmp8 = r8712_read8(adapter, SYS_FUNC_EN + 1);
+               r8712_write8(adapter, SYS_FUNC_EN + 1, tmp8 | BIT(2));
+               tmp8_a = r8712_read8(adapter, SYS_FUNC_EN + 1);
                if (tmp8_a != (tmp8 | BIT(2)))
                        goto exit_fail;
 
-               r8712_read32(padapter, TCR);
+               r8712_read32(adapter, TCR);
 
                /* 4.polling IMEM Ready */
                i = 100;
-               tmp16 = r8712_read16(padapter, TCR);
+               tmp16 = r8712_read16(adapter, TCR);
                while (((tmp16 & _IMEM_RDY) == 0) && (i > 0)) {
                        msleep(20);
-                       tmp16 = r8712_read16(padapter, TCR);
+                       tmp16 = r8712_read16(adapter, TCR);
                        i--;
                }
                if (i == 0) {
-                       r8712_write16(padapter, 0x10250348, 0xc000);
-                       r8712_write16(padapter, 0x10250348, 0xc001);
-                       r8712_write16(padapter, 0x10250348, 0x2000);
-                       r8712_write16(padapter, 0x10250348, 0x2001);
-                       r8712_write16(padapter, 0x10250348, 0x2002);
-                       r8712_write16(padapter, 0x10250348, 0x2003);
+                       r8712_write16(adapter, 0x10250348, 0xc000);
+                       r8712_write16(adapter, 0x10250348, 0xc001);
+                       r8712_write16(adapter, 0x10250348, 0x2000);
+                       r8712_write16(adapter, 0x10250348, 0x2001);
+                       r8712_write16(adapter, 0x10250348, 0x2002);
+                       r8712_write16(adapter, 0x10250348, 0x2003);
                        goto exit_fail;
                }
                /* 5.Download DMEM code size and Load EMEM Code Section */
-               memset(ptx_desc, 0, TXDESC_SIZE);
-               ptx_desc->txdw0 |= cpu_to_le32(fwhdr.fw_priv_sz & 0x0000ffff);
-               ptx_desc->txdw0 |= cpu_to_le32(BIT(28));
-               memcpy(ppayload, &fwhdr.fwpriv, fwhdr.fw_priv_sz);
-               r8712_write_mem(padapter, RTL8712_DMA_VOQ,
-                               fwhdr.fw_priv_sz + TXDESC_SIZE, (u8 *)ptx_desc);
+               memset(txdesc, 0, TXDESC_SIZE);
+               txdesc->txdw0 |= cpu_to_le32(fwhdr.fw_priv_sz & 0x0000ffff);
+               txdesc->txdw0 |= cpu_to_le32(BIT(28));
+               memcpy(payload, &fwhdr.fwpriv, fwhdr.fw_priv_sz);
+               r8712_write_mem(adapter, RTL8712_DMA_VOQ,
+                               fwhdr.fw_priv_sz + TXDESC_SIZE, (u8 *)txdesc);
 
                /* polling dmem code done */
                i = 100;
-               tmp16 = r8712_read16(padapter, TCR);
+               tmp16 = r8712_read16(adapter, TCR);
                while (((tmp16 & _DMEM_CODE_DONE) == 0) && (i > 0)) {
                        msleep(20);
-                       tmp16 = r8712_read16(padapter, TCR);
+                       tmp16 = r8712_read16(adapter, TCR);
                        i--;
                }
                if (i == 0)
                        goto exit_fail;
 
-               tmp8 = r8712_read8(padapter, 0x1025000A);
+               tmp8 = r8712_read8(adapter, 0x1025000A);
                if (tmp8 & BIT(4)) /* When boot from EEPROM,
                                    * & FW need more time to read EEPROM
                                    */
                        i = 60;
                else                    /* boot from EFUSE */
                        i = 30;
-               tmp16 = r8712_read16(padapter, TCR);
+               tmp16 = r8712_read16(adapter, TCR);
                while (((tmp16 & _FWRDY) == 0) && (i > 0)) {
                        msleep(100);
-                       tmp16 = r8712_read16(padapter, TCR);
+                       tmp16 = r8712_read16(adapter, TCR);
                        i--;
                }
                if (i == 0)
@@ -306,7 +306,7 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter)
        ret = _SUCCESS;
 
 exit_fail:
-       kfree(ptmpchar);
+       kfree(tmpchar);
        return ret;
 }
 
index 4cca739..b4a0991 100644 (file)
@@ -156,13 +156,13 @@ static uint r8712_get_rateset_len(u8 *rateset)
        return i;
 }
 
-int r8712_generate_ie(struct registry_priv *pregistrypriv)
+int r8712_generate_ie(struct registry_priv *registrypriv)
 {
        int rate_len;
        uint sz = 0;
-       struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network;
-       u8 *ie = pdev_network->IEs;
-       u16 beaconPeriod = (u16)pdev_network->Configuration.BeaconPeriod;
+       struct wlan_bssid_ex *dev_network = &registrypriv->dev_network;
+       u8 *ie = dev_network->IEs;
+       u16 beaconPeriod = (u16)dev_network->Configuration.BeaconPeriod;
 
        /*timestamp will be inserted by hardware*/
        sz += 8;
@@ -174,65 +174,65 @@ int r8712_generate_ie(struct registry_priv *pregistrypriv)
        /*capability info*/
        *(u16 *)ie = 0;
        *(__le16 *)ie |= cpu_to_le16(cap_IBSS);
-       if (pregistrypriv->preamble == PREAMBLE_SHORT)
+       if (registrypriv->preamble == PREAMBLE_SHORT)
                *(__le16 *)ie |= cpu_to_le16(cap_ShortPremble);
-       if (pdev_network->Privacy)
+       if (dev_network->Privacy)
                *(__le16 *)ie |= cpu_to_le16(cap_Privacy);
        sz += 2;
        ie += 2;
        /*SSID*/
-       ie = r8712_set_ie(ie, _SSID_IE_, pdev_network->Ssid.SsidLength,
-                         pdev_network->Ssid.Ssid, &sz);
+       ie = r8712_set_ie(ie, _SSID_IE_, dev_network->Ssid.SsidLength,
+                         dev_network->Ssid.Ssid, &sz);
        /*supported rates*/
-       set_supported_rate(pdev_network->rates, pregistrypriv->wireless_mode);
-       rate_len = r8712_get_rateset_len(pdev_network->rates);
+       set_supported_rate(dev_network->rates, registrypriv->wireless_mode);
+       rate_len = r8712_get_rateset_len(dev_network->rates);
        if (rate_len > 8) {
                ie = r8712_set_ie(ie, _SUPPORTEDRATES_IE_, 8,
-                                 pdev_network->rates, &sz);
+                                 dev_network->rates, &sz);
                ie = r8712_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8),
-                                 (pdev_network->rates + 8), &sz);
+                                 (dev_network->rates + 8), &sz);
        } else {
                ie = r8712_set_ie(ie, _SUPPORTEDRATES_IE_,
-                                 rate_len, pdev_network->rates, &sz);
+                                 rate_len, dev_network->rates, &sz);
        }
        /*DS parameter set*/
        ie = r8712_set_ie(ie, _DSSET_IE_, 1,
-                         (u8 *)&pdev_network->Configuration.DSConfig, &sz);
+                         (u8 *)&dev_network->Configuration.DSConfig, &sz);
        /*IBSS Parameter Set*/
        ie = r8712_set_ie(ie, _IBSS_PARA_IE_, 2,
-                         (u8 *)&pdev_network->Configuration.ATIMWindow, &sz);
+                         (u8 *)&dev_network->Configuration.ATIMWindow, &sz);
        return sz;
 }
 
-unsigned char *r8712_get_wpa_ie(unsigned char *pie, uint *wpa_ie_len, int limit)
+unsigned char *r8712_get_wpa_ie(unsigned char *ie, uint *wpa_ie_len, int limit)
 {
        u32 len;
        u16 val16;
        unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01};
-       u8 *pbuf = pie;
+       u8 *buf = ie;
 
        while (1) {
-               pbuf = r8712_get_ie(pbuf, _WPA_IE_ID_, &len, limit);
-               if (pbuf) {
+               buf = r8712_get_ie(buf, _WPA_IE_ID_, &len, limit);
+               if (buf) {
                        /*check if oui matches...*/
-                       if (memcmp((pbuf + 2), wpa_oui_type,
+                       if (memcmp((buf + 2), wpa_oui_type,
                                   sizeof(wpa_oui_type)))
                                goto check_next_ie;
                        /*check version...*/
-                       memcpy((u8 *)&val16, (pbuf + 6), sizeof(val16));
+                       memcpy((u8 *)&val16, (buf + 6), sizeof(val16));
                        le16_to_cpus(&val16);
                        if (val16 != 0x0001)
                                goto check_next_ie;
-                       *wpa_ie_len = *(pbuf + 1);
-                       return pbuf;
+                       *wpa_ie_len = *(buf + 1);
+                       return buf;
                }
                *wpa_ie_len = 0;
                return NULL;
 check_next_ie:
-               limit = limit - (pbuf - pie) - 2 - len;
+               limit = limit - (buf - ie) - 2 - len;
                if (limit <= 0)
                        break;
-               pbuf += (2 + len);
+               buf += (2 + len);
        }
        *wpa_ie_len = 0;
        return NULL;
@@ -283,12 +283,12 @@ int r8712_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher,
 
        if (wpa_ie_len <= 0) {
                /* No WPA IE - fail silently */
-               return _FAIL;
+               return -EINVAL;
        }
        if ((*wpa_ie != _WPA_IE_ID_) ||
            (*(wpa_ie + 1) != (u8)(wpa_ie_len - 2)) ||
            (memcmp(wpa_ie + 2, (void *)WPA_OUI_TYPE, WPA_SELECTOR_LEN)))
-               return _FAIL;
+               return -EINVAL;
        pos = wpa_ie;
        pos += 8;
        left = wpa_ie_len - 8;
@@ -298,7 +298,7 @@ int r8712_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher,
                pos += WPA_SELECTOR_LEN;
                left -= WPA_SELECTOR_LEN;
        } else if (left > 0) {
-               return _FAIL;
+               return -EINVAL;
        }
        /*pairwise_cipher*/
        if (left >= 2) {
@@ -306,16 +306,16 @@ int r8712_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher,
                pos += 2;
                left -= 2;
                if (count == 0 || left < count * WPA_SELECTOR_LEN)
-                       return _FAIL;
+                       return -EINVAL;
                for (i = 0; i < count; i++) {
                        *pairwise_cipher |= r8712_get_wpa_cipher_suite(pos);
                        pos += WPA_SELECTOR_LEN;
                        left -= WPA_SELECTOR_LEN;
                }
        } else if (left == 1) {
-               return _FAIL;
+               return -EINVAL;
        }
-       return _SUCCESS;
+       return 0;
 }
 
 int r8712_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher,
@@ -327,11 +327,11 @@ int r8712_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher,
 
        if (rsn_ie_len <= 0) {
                /* No RSN IE - fail silently */
-               return _FAIL;
+               return -EINVAL;
        }
        if ((*rsn_ie != _WPA2_IE_ID_) ||
            (*(rsn_ie + 1) != (u8)(rsn_ie_len - 2)))
-               return _FAIL;
+               return -EINVAL;
        pos = rsn_ie;
        pos += 4;
        left = rsn_ie_len - 4;
@@ -341,7 +341,7 @@ int r8712_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher,
                pos += RSN_SELECTOR_LEN;
                left -= RSN_SELECTOR_LEN;
        } else if (left > 0) {
-               return _FAIL;
+               return -EINVAL;
        }
        /*pairwise_cipher*/
        if (left >= 2) {
@@ -349,16 +349,16 @@ int r8712_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher,
                pos += 2;
                left -= 2;
                if (count == 0 || left < count * RSN_SELECTOR_LEN)
-                       return _FAIL;
+                       return -EINVAL;
                for (i = 0; i < count; i++) {
                        *pairwise_cipher |= r8712_get_wpa2_cipher_suite(pos);
                        pos += RSN_SELECTOR_LEN;
                        left -= RSN_SELECTOR_LEN;
                }
        } else if (left == 1) {
-               return _FAIL;
+               return -EINVAL;
        }
-       return _SUCCESS;
+       return 0;
 }
 
 int r8712_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len,
index 4d473f0..b9f5104 100644 (file)
@@ -60,22 +60,22 @@ static void wdg_timeout_handler (struct timer_list *t)
        struct _adapter *adapter =
                from_timer(adapter, t, mlmepriv.wdg_timer);
 
-       _r8712_wdg_timeout_handler(adapter);
+       r8712_wdg_wk_cmd(adapter);
 
        mod_timer(&adapter->mlmepriv.wdg_timer,
                  jiffies + msecs_to_jiffies(2000));
 }
 
-void r8712_init_mlme_timer(struct _adapter *padapter)
+void r8712_init_mlme_timer(struct _adapter *adapter)
 {
-       struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct  mlme_priv *mlmepriv = &adapter->mlmepriv;
 
-       timer_setup(&pmlmepriv->assoc_timer, join_timeout_handler, 0);
-       timer_setup(&pmlmepriv->sitesurveyctrl.sitesurvey_ctrl_timer,
+       timer_setup(&mlmepriv->assoc_timer, join_timeout_handler, 0);
+       timer_setup(&mlmepriv->sitesurveyctrl.sitesurvey_ctrl_timer,
                    sitesurvey_ctrl_handler, 0);
-       timer_setup(&pmlmepriv->scan_to_timer, _scan_timeout_handler, 0);
-       timer_setup(&pmlmepriv->dhcp_timer, dhcp_timeout_handler, 0);
-       timer_setup(&pmlmepriv->wdg_timer, wdg_timeout_handler, 0);
+       timer_setup(&mlmepriv->scan_to_timer, _scan_timeout_handler, 0);
+       timer_setup(&mlmepriv->dhcp_timer, dhcp_timeout_handler, 0);
+       timer_setup(&mlmepriv->wdg_timer, wdg_timeout_handler, 0);
 }
 
 void r8712_os_indicate_connect(struct _adapter *adapter)
@@ -119,16 +119,16 @@ void r8712_os_indicate_disconnect(struct _adapter *adapter)
                adapter->securitypriv.btkip_countermeasure =
                                         backupTKIPCountermeasure;
        } else { /*reset values in securitypriv*/
-               struct security_priv *psec_priv = &adapter->securitypriv;
-
-               psec_priv->AuthAlgrthm = 0; /*open system*/
-               psec_priv->PrivacyAlgrthm = _NO_PRIVACY_;
-               psec_priv->PrivacyKeyIndex = 0;
-               psec_priv->XGrpPrivacy = _NO_PRIVACY_;
-               psec_priv->XGrpKeyid = 1;
-               psec_priv->ndisauthtype = Ndis802_11AuthModeOpen;
-               psec_priv->ndisencryptstatus = Ndis802_11WEPDisabled;
-               psec_priv->wps_phase = false;
+               struct security_priv *sec_priv = &adapter->securitypriv;
+
+               sec_priv->AuthAlgrthm = 0; /*open system*/
+               sec_priv->PrivacyAlgrthm = _NO_PRIVACY_;
+               sec_priv->PrivacyKeyIndex = 0;
+               sec_priv->XGrpPrivacy = _NO_PRIVACY_;
+               sec_priv->XGrpKeyid = 1;
+               sec_priv->ndisauthtype = Ndis802_11AuthModeOpen;
+               sec_priv->ndisencryptstatus = Ndis802_11WEPDisabled;
+               sec_priv->wps_phase = false;
        }
 }
 
index c962696..b554cf8 100644 (file)
@@ -221,9 +221,9 @@ struct net_device *r8712_init_netdev(void)
 
 static u32 start_drv_threads(struct _adapter *padapter)
 {
-       padapter->cmdThread = kthread_run(r8712_cmd_thread, padapter, "%s",
+       padapter->cmd_thread = kthread_run(r8712_cmd_thread, padapter, "%s",
                                          padapter->pnetdev->name);
-       if (IS_ERR(padapter->cmdThread))
+       if (IS_ERR(padapter->cmd_thread))
                return _FAIL;
        return _SUCCESS;
 }
@@ -235,7 +235,7 @@ void r8712_stop_drv_threads(struct _adapter *padapter)
 
        /*Below is to terminate r8712_cmd_thread & event_thread...*/
        complete(&padapter->cmdpriv.cmd_queue_comp);
-       if (padapter->cmdThread)
+       if (padapter->cmd_thread)
                wait_for_completion_interruptible(completion);
        padapter->cmdpriv.cmd_seq = 1;
 }
@@ -297,10 +297,10 @@ static u8 init_default_value(struct _adapter *padapter)
 
 u8 r8712_init_drv_sw(struct _adapter *padapter)
 {
-       if ((r8712_init_cmd_priv(&padapter->cmdpriv)) == _FAIL)
+       if (r8712_init_cmd_priv(&padapter->cmdpriv))
                return _FAIL;
        padapter->cmdpriv.padapter = padapter;
-       if ((r8712_init_evt_priv(&padapter->evtpriv)) == _FAIL)
+       if (r8712_init_evt_priv(&padapter->evtpriv))
                return _FAIL;
        if (r8712_init_mlme_priv(padapter) == _FAIL)
                return _FAIL;
@@ -310,7 +310,8 @@ u8 r8712_init_drv_sw(struct _adapter *padapter)
               sizeof(struct security_priv));
        timer_setup(&padapter->securitypriv.tkip_timer,
                    r8712_use_tkipkey_handler, 0);
-       _r8712_init_sta_priv(&padapter->stapriv);
+       if (_r8712_init_sta_priv(&padapter->stapriv))
+               return _FAIL;
        padapter->stapriv.padapter = padapter;
        r8712_init_bcmc_stainfo(padapter);
        r8712_init_pwrctrl_priv(padapter);
index 4e20cba..84c4c85 100644 (file)
@@ -72,11 +72,11 @@ int r8712_os_recvbuf_resource_free(struct _adapter *padapter,
        return _SUCCESS;
 }
 
-void r8712_handle_tkip_mic_err(struct _adapter *padapter, u8 bgroup)
+void r8712_handle_tkip_mic_err(struct _adapter *adapter, u8 bgroup)
 {
        union iwreq_data wrqu;
        struct iw_michaelmicfailure ev;
-       struct mlme_priv *pmlmepriv  = &padapter->mlmepriv;
+       struct mlme_priv *mlmepriv  = &adapter->mlmepriv;
 
        memset(&ev, 0x00, sizeof(ev));
        if (bgroup)
@@ -84,54 +84,54 @@ void r8712_handle_tkip_mic_err(struct _adapter *padapter, u8 bgroup)
        else
                ev.flags |= IW_MICFAILURE_PAIRWISE;
        ev.src_addr.sa_family = ARPHRD_ETHER;
-       ether_addr_copy(ev.src_addr.sa_data, &pmlmepriv->assoc_bssid[0]);
+       ether_addr_copy(ev.src_addr.sa_data, &mlmepriv->assoc_bssid[0]);
        memset(&wrqu, 0x00, sizeof(wrqu));
        wrqu.data.length = sizeof(ev);
-       wireless_send_event(padapter->pnetdev, IWEVMICHAELMICFAILURE, &wrqu,
+       wireless_send_event(adapter->pnetdev, IWEVMICHAELMICFAILURE, &wrqu,
                            (char *)&ev);
 }
 
-void r8712_recv_indicatepkt(struct _adapter *padapter,
-                           union recv_frame *precv_frame)
+void r8712_recv_indicatepkt(struct _adapter *adapter,
+                           union recv_frame *recvframe)
 {
-       struct recv_priv *precvpriv;
-       struct  __queue *pfree_recv_queue;
+       struct recv_priv *recvpriv;
+       struct  __queue *free_recv_queue;
        _pkt *skb;
-       struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+       struct rx_pkt_attrib *attrib = &recvframe->u.hdr.attrib;
 
-       precvpriv = &padapter->recvpriv;
-       pfree_recv_queue = &precvpriv->free_recv_queue;
-       skb = precv_frame->u.hdr.pkt;
+       recvpriv = &adapter->recvpriv;
+       free_recv_queue = &recvpriv->free_recv_queue;
+       skb = recvframe->u.hdr.pkt;
        if (!skb)
                goto _recv_indicatepkt_drop;
-       skb->data = precv_frame->u.hdr.rx_data;
-       skb->len = precv_frame->u.hdr.len;
+       skb->data = recvframe->u.hdr.rx_data;
+       skb->len = recvframe->u.hdr.len;
        skb_set_tail_pointer(skb, skb->len);
-       if ((pattrib->tcpchk_valid == 1) && (pattrib->tcp_chkrpt == 1))
+       if ((attrib->tcpchk_valid == 1) && (attrib->tcp_chkrpt == 1))
                skb->ip_summed = CHECKSUM_UNNECESSARY;
        else
                skb->ip_summed = CHECKSUM_NONE;
-       skb->dev = padapter->pnetdev;
-       skb->protocol = eth_type_trans(skb, padapter->pnetdev);
+       skb->dev = adapter->pnetdev;
+       skb->protocol = eth_type_trans(skb, adapter->pnetdev);
        netif_rx(skb);
-       precv_frame->u.hdr.pkt = NULL; /* pointers to NULL before
+       recvframe->u.hdr.pkt = NULL; /* pointers to NULL before
                                        * r8712_free_recvframe()
                                        */
-       r8712_free_recvframe(precv_frame, pfree_recv_queue);
+       r8712_free_recvframe(recvframe, free_recv_queue);
        return;
 _recv_indicatepkt_drop:
         /*enqueue back to free_recv_queue*/
-       if (precv_frame)
-               r8712_free_recvframe(precv_frame, pfree_recv_queue);
-       precvpriv->rx_drop++;
+       if (recvframe)
+               r8712_free_recvframe(recvframe, free_recv_queue);
+       recvpriv->rx_drop++;
 }
 
 static void _r8712_reordering_ctrl_timeout_handler (struct timer_list *t)
 {
-       struct recv_reorder_ctrl *preorder_ctrl =
-                        from_timer(preorder_ctrl, t, reordering_ctrl_timer);
+       struct recv_reorder_ctrl *reorder_ctrl =
+                        from_timer(reorder_ctrl, t, reordering_ctrl_timer);
 
-       r8712_reordering_ctrl_timeout_handler(preorder_ctrl);
+       r8712_reordering_ctrl_timeout_handler(reorder_ctrl);
 }
 
 void r8712_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl)
index 00babd0..4f3b54a 100644 (file)
@@ -23,7 +23,7 @@
 /* reserve 3 bytes for HW stop read */
 static int efuse_available_max_size = EFUSE_MAX_SIZE - 3 /*0x1FD*/;
 
-static void efuse_reg_ctrl(struct _adapter *padapter, u8 bPowerOn)
+static void efuse_reg_ctrl(struct _adapter *adapter, u8 bPowerOn)
 {
        u8 tmpu8 = 0;
 
@@ -31,53 +31,53 @@ static void efuse_reg_ctrl(struct _adapter *padapter, u8 bPowerOn)
                /* -----------------e-fuse pwr & clk reg ctrl ---------------
                 * Enable LDOE25 Macro Block
                 */
-               tmpu8 = r8712_read8(padapter, EFUSE_TEST + 3);
+               tmpu8 = r8712_read8(adapter, EFUSE_TEST + 3);
                tmpu8 |= 0x80;
-               r8712_write8(padapter, EFUSE_TEST + 3, tmpu8);
+               r8712_write8(adapter, EFUSE_TEST + 3, tmpu8);
                msleep(20); /* for some platform , need some delay time */
                /* Change Efuse Clock for write action to 40MHZ */
-               r8712_write8(padapter, EFUSE_CLK_CTRL, 0x03);
+               r8712_write8(adapter, EFUSE_CLK_CTRL, 0x03);
                msleep(20); /* for some platform , need some delay time */
        } else {
                /* -----------------e-fuse pwr & clk reg ctrl -----------------
                 * Disable LDOE25 Macro Block
                 */
-               tmpu8 = r8712_read8(padapter, EFUSE_TEST + 3);
+               tmpu8 = r8712_read8(adapter, EFUSE_TEST + 3);
                tmpu8 &= 0x7F;
-               r8712_write8(padapter, EFUSE_TEST + 3, tmpu8);
+               r8712_write8(adapter, EFUSE_TEST + 3, tmpu8);
                /* Change Efuse Clock for write action to 500K */
-               r8712_write8(padapter, EFUSE_CLK_CTRL, 0x02);
+               r8712_write8(adapter, EFUSE_CLK_CTRL, 0x02);
        }
 }
 
 /*
  * Before write E-Fuse, this function must be called.
  */
-u8 r8712_efuse_reg_init(struct _adapter *padapter)
+u8 r8712_efuse_reg_init(struct _adapter *adapter)
 {
        return true;
 }
 
-void r8712_efuse_reg_uninit(struct _adapter *padapter)
+void r8712_efuse_reg_uninit(struct _adapter *adapter)
 {
-       efuse_reg_ctrl(padapter, false);
+       efuse_reg_ctrl(adapter, false);
 }
 
-static u8 efuse_one_byte_read(struct _adapter *padapter, u16 addr, u8 *data)
+static u8 efuse_one_byte_read(struct _adapter *adapter, u16 addr, u8 *data)
 {
        u8 tmpidx = 0, bResult;
 
        /* -----------------e-fuse reg ctrl --------------------------------- */
-       r8712_write8(padapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */
-       r8712_write8(padapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) |
-              (r8712_read8(padapter, EFUSE_CTRL + 2) & 0xFC));
-       r8712_write8(padapter, EFUSE_CTRL + 3, 0x72); /* read cmd */
+       r8712_write8(adapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */
+       r8712_write8(adapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) |
+              (r8712_read8(adapter, EFUSE_CTRL + 2) & 0xFC));
+       r8712_write8(adapter, EFUSE_CTRL + 3, 0x72); /* read cmd */
        /* wait for complete */
-       while (!(0x80 & r8712_read8(padapter, EFUSE_CTRL + 3)) &&
+       while (!(0x80 & r8712_read8(adapter, EFUSE_CTRL + 3)) &&
               (tmpidx < 100))
                tmpidx++;
        if (tmpidx < 100) {
-               *data = r8712_read8(padapter, EFUSE_CTRL);
+               *data = r8712_read8(adapter, EFUSE_CTRL);
                bResult = true;
        } else {
                *data = 0xff;
@@ -86,18 +86,18 @@ static u8 efuse_one_byte_read(struct _adapter *padapter, u16 addr, u8 *data)
        return bResult;
 }
 
-static u8 efuse_one_byte_write(struct _adapter *padapter, u16 addr, u8 data)
+static u8 efuse_one_byte_write(struct _adapter *adapter, u16 addr, u8 data)
 {
        u8 tmpidx = 0, bResult;
 
        /* -----------------e-fuse reg ctrl -------------------------------- */
-       r8712_write8(padapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */
-       r8712_write8(padapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) |
-              (r8712_read8(padapter, EFUSE_CTRL + 2) & 0xFC));
-       r8712_write8(padapter, EFUSE_CTRL, data); /* data */
-       r8712_write8(padapter, EFUSE_CTRL + 3, 0xF2); /* write cmd */
+       r8712_write8(adapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */
+       r8712_write8(adapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) |
+              (r8712_read8(adapter, EFUSE_CTRL + 2) & 0xFC));
+       r8712_write8(adapter, EFUSE_CTRL, data); /* data */
+       r8712_write8(adapter, EFUSE_CTRL + 3, 0xF2); /* write cmd */
        /* wait for complete */
-       while ((0x80 &  r8712_read8(padapter, EFUSE_CTRL + 3)) &&
+       while ((0x80 &  r8712_read8(adapter, EFUSE_CTRL + 3)) &&
               (tmpidx < 100))
                tmpidx++;
        if (tmpidx < 100)
@@ -107,32 +107,32 @@ static u8 efuse_one_byte_write(struct _adapter *padapter, u16 addr, u8 data)
        return bResult;
 }
 
-static u8 efuse_one_byte_rw(struct _adapter *padapter, u8 bRead, u16 addr,
+static u8 efuse_one_byte_rw(struct _adapter *adapter, u8 bRead, u16 addr,
                            u8 *data)
 {
        u8 tmpidx = 0, tmpv8 = 0, bResult;
 
        /* -----------------e-fuse reg ctrl --------------------------------- */
-       r8712_write8(padapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */
+       r8712_write8(adapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */
        tmpv8 = ((u8)((addr >> 8) & 0x03)) |
-                (r8712_read8(padapter, EFUSE_CTRL + 2) & 0xFC);
-       r8712_write8(padapter, EFUSE_CTRL + 2, tmpv8);
+                (r8712_read8(adapter, EFUSE_CTRL + 2) & 0xFC);
+       r8712_write8(adapter, EFUSE_CTRL + 2, tmpv8);
        if (bRead) {
-               r8712_write8(padapter, EFUSE_CTRL + 3,  0x72); /* read cmd */
-               while (!(0x80 & r8712_read8(padapter, EFUSE_CTRL + 3)) &&
+               r8712_write8(adapter, EFUSE_CTRL + 3,  0x72); /* read cmd */
+               while (!(0x80 & r8712_read8(adapter, EFUSE_CTRL + 3)) &&
                       (tmpidx < 100))
                        tmpidx++;
                if (tmpidx < 100) {
-                       *data = r8712_read8(padapter, EFUSE_CTRL);
+                       *data = r8712_read8(adapter, EFUSE_CTRL);
                        bResult = true;
                } else {
                        *data = 0;
                        bResult = false;
                }
        } else {
-               r8712_write8(padapter, EFUSE_CTRL, *data); /* data */
-               r8712_write8(padapter, EFUSE_CTRL + 3, 0xF2); /* write cmd */
-               while ((0x80 & r8712_read8(padapter, EFUSE_CTRL + 3)) &&
+               r8712_write8(adapter, EFUSE_CTRL, *data); /* data */
+               r8712_write8(adapter, EFUSE_CTRL + 3, 0xF2); /* write cmd */
+               while ((0x80 & r8712_read8(adapter, EFUSE_CTRL + 3)) &&
                       (tmpidx < 100))
                        tmpidx++;
                if (tmpidx < 100)
@@ -143,12 +143,12 @@ static u8 efuse_one_byte_rw(struct _adapter *padapter, u8 bRead, u16 addr,
        return bResult;
 }
 
-static u8 efuse_is_empty(struct _adapter *padapter, u8 *empty)
+static u8 efuse_is_empty(struct _adapter *adapter, u8 *empty)
 {
        u8 value, ret = true;
 
        /* read one byte to check if E-Fuse is empty */
-       if (efuse_one_byte_rw(padapter, true, 0, &value)) {
+       if (efuse_one_byte_rw(adapter, true, 0, &value)) {
                if (value == 0xFF)
                        *empty = true;
                else
@@ -159,7 +159,7 @@ static u8 efuse_is_empty(struct _adapter *padapter, u8 *empty)
        return ret;
 }
 
-void r8712_efuse_change_max_size(struct _adapter *padapter)
+void r8712_efuse_change_max_size(struct _adapter *adapter)
 {
        u16 pre_pg_data_saddr = 0x1FB;
        u16 i;
@@ -167,7 +167,7 @@ void r8712_efuse_change_max_size(struct _adapter *padapter)
        u8 pre_pg_data[5];
 
        for (i = 0; i < pre_pg_data_size; i++)
-               efuse_one_byte_read(padapter, pre_pg_data_saddr + i,
+               efuse_one_byte_read(adapter, pre_pg_data_saddr + i,
                                    &pre_pg_data[i]);
        if ((pre_pg_data[0] == 0x03) && (pre_pg_data[1] == 0x00) &&
            (pre_pg_data[2] == 0x00) && (pre_pg_data[3] == 0x00) &&
@@ -175,7 +175,7 @@ void r8712_efuse_change_max_size(struct _adapter *padapter)
                efuse_available_max_size -= pre_pg_data_size;
 }
 
-int r8712_efuse_get_max_size(struct _adapter *padapter)
+int r8712_efuse_get_max_size(struct _adapter *adapter)
 {
        return  efuse_available_max_size;
 }
@@ -206,14 +206,14 @@ static void pgpacket_copy_data(const u8 word_en, const u8 *sourdata,
        }
 }
 
-u16 r8712_efuse_get_current_size(struct _adapter *padapter)
+u16 r8712_efuse_get_current_size(struct _adapter *adapter)
 {
        int bContinual = true;
        u16 efuse_addr = 0;
        u8 hworden = 0;
        u8 efuse_data, word_cnts = 0;
 
-       while (bContinual && efuse_one_byte_read(padapter, efuse_addr,
+       while (bContinual && efuse_one_byte_read(adapter, efuse_addr,
               &efuse_data) && (efuse_addr < efuse_available_max_size)) {
                if (efuse_data != 0xFF) {
                        hworden =  efuse_data & 0x0F;
@@ -227,7 +227,7 @@ u16 r8712_efuse_get_current_size(struct _adapter *padapter)
        return efuse_addr;
 }
 
-u8 r8712_efuse_pg_packet_read(struct _adapter *padapter, u8 offset, u8 *data)
+u8 r8712_efuse_pg_packet_read(struct _adapter *adapter, u8 offset, u8 *data)
 {
        u8 hoffset = 0, hworden = 0, word_cnts = 0;
        u16 efuse_addr = 0;
@@ -242,7 +242,7 @@ u8 r8712_efuse_pg_packet_read(struct _adapter *padapter, u8 offset, u8 *data)
                return false;
        memset(data, 0xFF, sizeof(u8) * PGPKT_DATA_SIZE);
        while (efuse_addr < efuse_available_max_size) {
-               if (efuse_one_byte_read(padapter, efuse_addr, &efuse_data)) {
+               if (efuse_one_byte_read(adapter, efuse_addr, &efuse_data)) {
                        if (efuse_data == 0xFF)
                                break;
                        hoffset = (efuse_data >> 4) & 0x0F;
@@ -252,7 +252,7 @@ u8 r8712_efuse_pg_packet_read(struct _adapter *padapter, u8 offset, u8 *data)
                                memset(tmpdata, 0xFF, PGPKT_DATA_SIZE);
                                for (tmpidx = 0; tmpidx < word_cnts * 2;
                                     tmpidx++) {
-                                       if (efuse_one_byte_read(padapter,
+                                       if (efuse_one_byte_read(adapter,
                                            efuse_addr + 1 + tmpidx,
                                            &efuse_data)) {
                                                tmpdata[tmpidx] = efuse_data;
@@ -271,7 +271,7 @@ u8 r8712_efuse_pg_packet_read(struct _adapter *padapter, u8 offset, u8 *data)
        return ret;
 }
 
-static u8 fix_header(struct _adapter *padapter, u8 header, u16 header_addr)
+static u8 fix_header(struct _adapter *adapter, u8 header, u16 header_addr)
 {
        struct PGPKT_STRUCT pkt;
        u8 offset, word_en, value;
@@ -287,7 +287,7 @@ static u8 fix_header(struct _adapter *padapter, u8 header, u16 header_addr)
        /* retrieve original data */
        addr = 0;
        while (addr < header_addr) {
-               if (!efuse_one_byte_read(padapter, addr++, &value)) {
+               if (!efuse_one_byte_read(adapter, addr++, &value)) {
                        ret = false;
                        break;
                }
@@ -301,13 +301,13 @@ static u8 fix_header(struct _adapter *padapter, u8 header, u16 header_addr)
                        if (BIT(i) & word_en) {
                                if (BIT(i) & pkt.word_en) {
                                        if (efuse_one_byte_read(
-                                                       padapter, addr,
+                                                       adapter, addr,
                                                        &value))
                                                pkt.data[i * 2] = value;
                                        else
                                                return false;
                                        if (efuse_one_byte_read(
-                                                       padapter,
+                                                       adapter,
                                                        addr + 1,
                                                        &value))
                                                pkt.data[i * 2 + 1] =
@@ -325,24 +325,24 @@ static u8 fix_header(struct _adapter *padapter, u8 header, u16 header_addr)
        /* fill original data */
        for (i = 0; i < PGPKG_MAX_WORDS; i++) {
                if (BIT(i) & pkt.word_en) {
-                       efuse_one_byte_write(padapter, addr, pkt.data[i * 2]);
-                       efuse_one_byte_write(padapter, addr + 1,
+                       efuse_one_byte_write(adapter, addr, pkt.data[i * 2]);
+                       efuse_one_byte_write(adapter, addr + 1,
                                             pkt.data[i * 2 + 1]);
                        /* additional check */
-                       if (!efuse_one_byte_read(padapter, addr, &value)) {
+                       if (!efuse_one_byte_read(adapter, addr, &value)) {
                                ret = false;
                        } else if (pkt.data[i * 2] != value) {
                                ret = false;
                                if (value == 0xFF) /* write again */
-                                       efuse_one_byte_write(padapter, addr,
+                                       efuse_one_byte_write(adapter, addr,
                                                             pkt.data[i * 2]);
                        }
-                       if (!efuse_one_byte_read(padapter, addr + 1, &value)) {
+                       if (!efuse_one_byte_read(adapter, addr + 1, &value)) {
                                ret = false;
                        } else if (pkt.data[i * 2 + 1] != value) {
                                ret = false;
                                if (value == 0xFF) /* write again */
-                                       efuse_one_byte_write(padapter, addr + 1,
+                                       efuse_one_byte_write(adapter, addr + 1,
                                                             pkt.data[i * 2 +
                                                                      1]);
                        }
@@ -352,7 +352,7 @@ static u8 fix_header(struct _adapter *padapter, u8 header, u16 header_addr)
        return ret;
 }
 
-u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, const u8 offset,
+u8 r8712_efuse_pg_packet_write(struct _adapter *adapter, const u8 offset,
                               const u8 word_en, const u8 *data)
 {
        u8 pg_header = 0;
@@ -363,7 +363,7 @@ u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, const u8 offset,
        u8 bResult = true;
 
        /* check if E-Fuse Clock Enable and E-Fuse Clock is 40M */
-       efuse_data = r8712_read8(padapter, EFUSE_CLK_CTRL);
+       efuse_data = r8712_read8(adapter, EFUSE_CLK_CTRL);
        if (efuse_data != 0x03)
                return false;
        pg_header = MAKE_EFUSE_HEADER(offset, word_en);
@@ -371,15 +371,15 @@ u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, const u8 offset,
        repeat_times = 0;
        efuse_addr = 0;
        while (efuse_addr < efuse_available_max_size) {
-               curr_size = r8712_efuse_get_current_size(padapter);
+               curr_size = r8712_efuse_get_current_size(adapter);
                if ((curr_size + 1 + target_word_cnts * 2) >
                     efuse_available_max_size)
                        return false; /*target_word_cnts + pg header(1 byte)*/
                efuse_addr = curr_size; /* current size is also the last addr*/
-               efuse_one_byte_write(padapter, efuse_addr, pg_header); /*hdr*/
+               efuse_one_byte_write(adapter, efuse_addr, pg_header); /*hdr*/
                sub_repeat = 0;
                /* check if what we read is what we write */
-               while (!efuse_one_byte_read(padapter, efuse_addr,
+               while (!efuse_one_byte_read(adapter, efuse_addr,
                                            &efuse_data)) {
                        if (++sub_repeat > _REPEAT_THRESHOLD_) {
                                bResult = false; /* continue to blind write */
@@ -394,10 +394,10 @@ u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, const u8 offset,
                        /* go to next address */
                        efuse_addr++;
                        for (i = 0; i < target_word_cnts * 2; i++) {
-                               efuse_one_byte_write(padapter,
+                               efuse_one_byte_write(adapter,
                                                     efuse_addr + i,
                                                     *(data + i));
-                               if (!efuse_one_byte_read(padapter,
+                               if (!efuse_one_byte_read(adapter,
                                                         efuse_addr + i,
                                                         &efuse_data))
                                        bResult = false;
@@ -411,7 +411,7 @@ u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, const u8 offset,
                if (efuse_data == 0xFF)
                        return bResult; /* nothing damaged. */
                /* call rescue procedure */
-               if (!fix_header(padapter, efuse_data, efuse_addr))
+               if (!fix_header(adapter, efuse_data, efuse_addr))
                        return false; /* rescue fail */
 
                if (++repeat_times > _REPEAT_THRESHOLD_) /* fail */
@@ -421,7 +421,7 @@ u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, const u8 offset,
        return bResult;
 }
 
-u8 r8712_efuse_access(struct _adapter *padapter, u8 bRead, u16 start_addr,
+u8 r8712_efuse_access(struct _adapter *adapter, u8 bRead, u16 start_addr,
                      u16 cnts, u8 *data)
 {
        int i;
@@ -432,7 +432,7 @@ u8 r8712_efuse_access(struct _adapter *padapter, u8 bRead, u16 start_addr,
        if (!bRead && ((start_addr + cnts) >
           efuse_available_max_size))
                return false;
-       if (!bRead && !r8712_efuse_reg_init(padapter))
+       if (!bRead && !r8712_efuse_reg_init(adapter))
                return false;
        /* -----------------e-fuse one byte read / write ---------------------*/
        for (i = 0; i < cnts; i++) {
@@ -440,17 +440,17 @@ u8 r8712_efuse_access(struct _adapter *padapter, u8 bRead, u16 start_addr,
                        res = false;
                        break;
                }
-               res = efuse_one_byte_rw(padapter, bRead, start_addr + i,
+               res = efuse_one_byte_rw(adapter, bRead, start_addr + i,
                                        data + i);
                if (!bRead && !res)
                        break;
        }
        if (!bRead)
-               r8712_efuse_reg_uninit(padapter);
+               r8712_efuse_reg_uninit(adapter);
        return res;
 }
 
-u8 r8712_efuse_map_read(struct _adapter *padapter, u16 addr, u16 cnts, u8 *data)
+u8 r8712_efuse_map_read(struct _adapter *adapter, u16 addr, u16 cnts, u8 *data)
 {
        u8 offset, ret = true;
        u8 pktdata[PGPKT_DATA_SIZE];
@@ -458,13 +458,13 @@ u8 r8712_efuse_map_read(struct _adapter *padapter, u16 addr, u16 cnts, u8 *data)
 
        if ((addr + cnts) > EFUSE_MAP_MAX_SIZE)
                return false;
-       if (efuse_is_empty(padapter, &offset) && offset) {
+       if (efuse_is_empty(adapter, &offset) && offset) {
                for (i = 0; i < cnts; i++)
                        data[i] = 0xFF;
                return ret;
        }
        offset = (addr >> 3) & 0xF;
-       ret = r8712_efuse_pg_packet_read(padapter, offset, pktdata);
+       ret = r8712_efuse_pg_packet_read(adapter, offset, pktdata);
        i = addr & 0x7; /* pktdata index */
        idx = 0;        /* data index */
 
@@ -475,14 +475,14 @@ u8 r8712_efuse_map_read(struct _adapter *padapter, u16 addr, u16 cnts, u8 *data)
                                return ret;
                }
                offset++;
-               if (!r8712_efuse_pg_packet_read(padapter, offset, pktdata))
+               if (!r8712_efuse_pg_packet_read(adapter, offset, pktdata))
                        ret = false;
                i = 0;
        } while (1);
        return ret;
 }
 
-u8 r8712_efuse_map_write(struct _adapter *padapter, u16 addr, u16 cnts,
+u8 r8712_efuse_map_write(struct _adapter *adapter, u16 addr, u16 cnts,
                         u8 *data)
 {
        u8 offset, word_en, empty;
@@ -492,10 +492,10 @@ u8 r8712_efuse_map_write(struct _adapter *padapter, u16 addr, u16 cnts,
        if ((addr + cnts) > EFUSE_MAP_MAX_SIZE)
                return false;
        /* check if E-Fuse Clock Enable and E-Fuse Clock is 40M */
-       empty = r8712_read8(padapter, EFUSE_CLK_CTRL);
+       empty = r8712_read8(adapter, EFUSE_CLK_CTRL);
        if (empty != 0x03)
                return false;
-       if (efuse_is_empty(padapter, &empty)) {
+       if (efuse_is_empty(adapter, &empty)) {
                if (empty)
                        memset(pktdata, 0xFF, PGPKT_DATA_SIZE);
        } else {
@@ -503,7 +503,7 @@ u8 r8712_efuse_map_write(struct _adapter *padapter, u16 addr, u16 cnts,
        }
        offset = (addr >> 3) & 0xF;
        if (!empty)
-               if (!r8712_efuse_pg_packet_read(padapter, offset, pktdata))
+               if (!r8712_efuse_pg_packet_read(adapter, offset, pktdata))
                        return false;
        word_en = 0xF;
        memset(newdata, 0xFF, PGPKT_DATA_SIZE);
@@ -546,14 +546,14 @@ u8 r8712_efuse_map_write(struct _adapter *padapter, u16 addr, u16 cnts,
                }
 
                if (word_en != 0xF)
-                       if (!r8712_efuse_pg_packet_write(padapter, offset,
+                       if (!r8712_efuse_pg_packet_write(adapter, offset,
                                                         word_en, newdata))
                                return false;
                if (idx == cnts)
                        break;
                offset++;
                if (!empty)
-                       if (!r8712_efuse_pg_packet_read(padapter, offset,
+                       if (!r8712_efuse_pg_packet_read(adapter, offset,
                                                        pktdata))
                                return false;
                i = 0;
index 7574a4b..307b0e2 100644 (file)
@@ -419,7 +419,7 @@ static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz)
        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
 #endif
        u8 blnSetTxDescOffset;
-       sint bmcst = IS_MCAST(pattrib->ra);
+       bool bmcst = is_multicast_ether_addr(pattrib->ra);
        struct ht_priv *phtpriv = &pmlmepriv->htpriv;
        struct tx_desc txdesc_mp;
 
index 05a78ac..26b6180 100644 (file)
@@ -43,7 +43,7 @@
  * No irqsave is necessary.
  */
 
-static sint _init_cmd_priv(struct cmd_priv *pcmdpriv)
+int r8712_init_cmd_priv(struct cmd_priv *pcmdpriv)
 {
        init_completion(&pcmdpriv->cmd_queue_comp);
        init_completion(&pcmdpriv->terminate_cmdthread_comp);
@@ -55,7 +55,7 @@ static sint _init_cmd_priv(struct cmd_priv *pcmdpriv)
        pcmdpriv->cmd_allocated_buf = kmalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ,
                                              GFP_ATOMIC);
        if (!pcmdpriv->cmd_allocated_buf)
-               return _FAIL;
+               return -ENOMEM;
        pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf  +  CMDBUFF_ALIGN_SZ -
                            ((addr_t)(pcmdpriv->cmd_allocated_buf) &
                            (CMDBUFF_ALIGN_SZ - 1));
@@ -63,36 +63,36 @@ static sint _init_cmd_priv(struct cmd_priv *pcmdpriv)
        if (!pcmdpriv->rsp_allocated_buf) {
                kfree(pcmdpriv->cmd_allocated_buf);
                pcmdpriv->cmd_allocated_buf = NULL;
-               return _FAIL;
+               return -ENOMEM;
        }
        pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf  +  4 -
                            ((addr_t)(pcmdpriv->rsp_allocated_buf) & 3);
        pcmdpriv->cmd_issued_cnt = 0;
        pcmdpriv->cmd_done_cnt = 0;
        pcmdpriv->rsp_cnt = 0;
-       return _SUCCESS;
+       return 0;
 }
 
-static sint _init_evt_priv(struct evt_priv *pevtpriv)
+int r8712_init_evt_priv(struct evt_priv *pevtpriv)
 {
        /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
        pevtpriv->event_seq = 0;
        pevtpriv->evt_allocated_buf = kmalloc(MAX_EVTSZ + 4, GFP_ATOMIC);
 
        if (!pevtpriv->evt_allocated_buf)
-               return _FAIL;
+               return -ENOMEM;
        pevtpriv->evt_buf = pevtpriv->evt_allocated_buf  +  4 -
                            ((addr_t)(pevtpriv->evt_allocated_buf) & 3);
        pevtpriv->evt_done_cnt = 0;
-       return _SUCCESS;
+       return 0;
 }
 
-static void _free_evt_priv(struct evt_priv *pevtpriv)
+void r8712_free_evt_priv(struct evt_priv *pevtpriv)
 {
        kfree(pevtpriv->evt_allocated_buf);
 }
 
-static void _free_cmd_priv(struct cmd_priv *pcmdpriv)
+void r8712_free_cmd_priv(struct cmd_priv *pcmdpriv)
 {
        if (pcmdpriv) {
                kfree(pcmdpriv->cmd_allocated_buf);
@@ -103,26 +103,30 @@ static void _free_cmd_priv(struct cmd_priv *pcmdpriv)
 /*
  * Calling Context:
  *
- * _enqueue_cmd can only be called between kernel thread,
+ * r8712_enqueue_cmd can only be called between kernel thread,
  * since only spin_lock is used.
  *
  * ISR/Call-Back functions can't call this sub-function.
  *
  */
 
-static sint _enqueue_cmd(struct  __queue *queue, struct cmd_obj *obj)
+void r8712_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj)
 {
+       struct __queue *queue;
        unsigned long irqL;
 
+       if (pcmdpriv->padapter->eeprompriv.bautoload_fail_flag)
+               return;
        if (!obj)
-               return _SUCCESS;
+               return;
+       queue = &pcmdpriv->cmd_queue;
        spin_lock_irqsave(&queue->lock, irqL);
        list_add_tail(&obj->list, &queue->queue);
        spin_unlock_irqrestore(&queue->lock, irqL);
-       return _SUCCESS;
+       complete(&pcmdpriv->cmd_queue_comp);
 }
 
-static struct cmd_obj *_dequeue_cmd(struct  __queue *queue)
+struct cmd_obj *r8712_dequeue_cmd(struct  __queue *queue)
 {
        unsigned long irqL;
        struct cmd_obj *obj;
@@ -136,57 +140,20 @@ static struct cmd_obj *_dequeue_cmd(struct  __queue *queue)
        return obj;
 }
 
-u32 r8712_init_cmd_priv(struct cmd_priv *pcmdpriv)
-{
-       return _init_cmd_priv(pcmdpriv);
-}
-
-u32 r8712_init_evt_priv(struct evt_priv *pevtpriv)
-{
-       return _init_evt_priv(pevtpriv);
-}
-
-void r8712_free_evt_priv(struct evt_priv *pevtpriv)
-{
-       _free_evt_priv(pevtpriv);
-}
-
-void r8712_free_cmd_priv(struct cmd_priv *pcmdpriv)
-{
-       _free_cmd_priv(pcmdpriv);
-}
-
-u32 r8712_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj)
-{
-       int res;
-
-       if (pcmdpriv->padapter->eeprompriv.bautoload_fail_flag)
-               return _FAIL;
-       res = _enqueue_cmd(&pcmdpriv->cmd_queue, obj);
-       complete(&pcmdpriv->cmd_queue_comp);
-       return res;
-}
-
-u32 r8712_enqueue_cmd_ex(struct cmd_priv *pcmdpriv, struct cmd_obj *obj)
+void r8712_enqueue_cmd_ex(struct cmd_priv *pcmdpriv, struct cmd_obj *obj)
 {
        unsigned long irqL;
        struct  __queue *queue;
 
        if (!obj)
-               return _SUCCESS;
+               return;
        if (pcmdpriv->padapter->eeprompriv.bautoload_fail_flag)
-               return _FAIL;
+               return;
        queue = &pcmdpriv->cmd_queue;
        spin_lock_irqsave(&queue->lock, irqL);
        list_add_tail(&obj->list, &queue->queue);
        spin_unlock_irqrestore(&queue->lock, irqL);
        complete(&pcmdpriv->cmd_queue_comp);
-       return _SUCCESS;
-}
-
-struct cmd_obj *r8712_dequeue_cmd(struct  __queue *queue)
-{
-       return _dequeue_cmd(queue);
 }
 
 void r8712_free_cmd_obj(struct cmd_obj *pcmd)
@@ -242,7 +209,7 @@ u8 r8712_sitesurvey_cmd(struct _adapter *padapter,
        return _SUCCESS;
 }
 
-u8 r8712_setdatarate_cmd(struct _adapter *padapter, u8 *rateset)
+int r8712_setdatarate_cmd(struct _adapter *padapter, u8 *rateset)
 {
        struct cmd_obj          *ph2c;
        struct setdatarate_parm *pbsetdataratepara;
@@ -250,21 +217,21 @@ u8 r8712_setdatarate_cmd(struct _adapter *padapter, u8 *rateset)
 
        ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
        if (!ph2c)
-               return _FAIL;
+               return -ENOMEM;
        pbsetdataratepara = kmalloc(sizeof(*pbsetdataratepara), GFP_ATOMIC);
        if (!pbsetdataratepara) {
                kfree(ph2c);
-               return _FAIL;
+               return -ENOMEM;
        }
        init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara,
                                   GEN_CMD_CODE(_SetDataRate));
        pbsetdataratepara->mac_id = 5;
        memcpy(pbsetdataratepara->datarates, rateset, NumRates);
        r8712_enqueue_cmd(pcmdpriv, ph2c);
-       return _SUCCESS;
+       return 0;
 }
 
-u8 r8712_set_chplan_cmd(struct _adapter *padapter, int chplan)
+void r8712_set_chplan_cmd(struct _adapter *padapter, int chplan)
 {
        struct cmd_obj *ph2c;
        struct SetChannelPlan_param *psetchplanpara;
@@ -272,81 +239,19 @@ u8 r8712_set_chplan_cmd(struct _adapter *padapter, int chplan)
 
        ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
        if (!ph2c)
-               return _FAIL;
+               return;
        psetchplanpara = kmalloc(sizeof(*psetchplanpara), GFP_ATOMIC);
        if (!psetchplanpara) {
                kfree(ph2c);
-               return _FAIL;
+               return;
        }
        init_h2fwcmd_w_parm_no_rsp(ph2c, psetchplanpara,
                                GEN_CMD_CODE(_SetChannelPlan));
        psetchplanpara->ChannelPlan = chplan;
        r8712_enqueue_cmd(pcmdpriv, ph2c);
-       return _SUCCESS;
-}
-
-u8 r8712_setbasicrate_cmd(struct _adapter *padapter, u8 *rateset)
-{
-       struct cmd_obj *ph2c;
-       struct setbasicrate_parm *pssetbasicratepara;
-       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
-
-       ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
-       if (!ph2c)
-               return _FAIL;
-       pssetbasicratepara = kmalloc(sizeof(*pssetbasicratepara), GFP_ATOMIC);
-       if (!pssetbasicratepara) {
-               kfree(ph2c);
-               return _FAIL;
-       }
-       init_h2fwcmd_w_parm_no_rsp(ph2c, pssetbasicratepara,
-               _SetBasicRate_CMD_);
-       memcpy(pssetbasicratepara->basicrates, rateset, NumRates);
-       r8712_enqueue_cmd(pcmdpriv, ph2c);
-       return _SUCCESS;
-}
-
-u8 r8712_setfwdig_cmd(struct _adapter *padapter, u8 type)
-{
-       struct cmd_obj *ph2c;
-       struct writePTM_parm *pwriteptmparm;
-       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
-
-       ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
-       if (!ph2c)
-               return _FAIL;
-       pwriteptmparm = kmalloc(sizeof(*pwriteptmparm), GFP_ATOMIC);
-       if (!pwriteptmparm) {
-               kfree(ph2c);
-               return _FAIL;
-       }
-       init_h2fwcmd_w_parm_no_rsp(ph2c, pwriteptmparm, GEN_CMD_CODE(_SetDIG));
-       pwriteptmparm->type = type;
-       r8712_enqueue_cmd(pcmdpriv, ph2c);
-       return _SUCCESS;
-}
-
-u8 r8712_setfwra_cmd(struct _adapter *padapter, u8 type)
-{
-       struct cmd_obj *ph2c;
-       struct writePTM_parm *pwriteptmparm;
-       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
-
-       ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
-       if (!ph2c)
-               return _FAIL;
-       pwriteptmparm = kmalloc(sizeof(*pwriteptmparm), GFP_ATOMIC);
-       if (!pwriteptmparm) {
-               kfree(ph2c);
-               return _FAIL;
-       }
-       init_h2fwcmd_w_parm_no_rsp(ph2c, pwriteptmparm, GEN_CMD_CODE(_SetRA));
-       pwriteptmparm->type = type;
-       r8712_enqueue_cmd(pcmdpriv, ph2c);
-       return _SUCCESS;
 }
 
-u8 r8712_setrfreg_cmd(struct _adapter  *padapter, u8 offset, u32 val)
+int r8712_setrfreg_cmd(struct _adapter  *padapter, u8 offset, u32 val)
 {
        struct cmd_obj *ph2c;
        struct writeRF_parm *pwriterfparm;
@@ -354,20 +259,20 @@ u8 r8712_setrfreg_cmd(struct _adapter  *padapter, u8 offset, u32 val)
 
        ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
        if (!ph2c)
-               return _FAIL;
+               return -ENOMEM;
        pwriterfparm = kmalloc(sizeof(*pwriterfparm), GFP_ATOMIC);
        if (!pwriterfparm) {
                kfree(ph2c);
-               return _FAIL;
+               return -ENOMEM;
        }
        init_h2fwcmd_w_parm_no_rsp(ph2c, pwriterfparm, GEN_CMD_CODE(_SetRFReg));
        pwriterfparm->offset = offset;
        pwriterfparm->value = val;
        r8712_enqueue_cmd(pcmdpriv, ph2c);
-       return _SUCCESS;
+       return 0;
 }
 
-u8 r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval)
+int r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval)
 {
        struct cmd_obj *ph2c;
        struct readRF_parm *prdrfparm;
@@ -375,11 +280,11 @@ u8 r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval)
 
        ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
        if (!ph2c)
-               return _FAIL;
+               return -ENOMEM;
        prdrfparm = kmalloc(sizeof(*prdrfparm), GFP_ATOMIC);
        if (!prdrfparm) {
                kfree(ph2c);
-               return _FAIL;
+               return -ENOMEM;
        }
        INIT_LIST_HEAD(&ph2c->list);
        ph2c->cmdcode = GEN_CMD_CODE(_GetRFReg);
@@ -389,7 +294,7 @@ u8 r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval)
        ph2c->rspsz = sizeof(struct readRF_rsp);
        prdrfparm->offset = offset;
        r8712_enqueue_cmd(pcmdpriv, ph2c);
-       return _SUCCESS;
+       return 0;
 }
 
 void r8712_getbbrfreg_cmdrsp_callback(struct _adapter *padapter,
@@ -409,7 +314,7 @@ void r8712_readtssi_cmdrsp_callback(struct _adapter *padapter,
        padapter->mppriv.workparam.bcompleted = true;
 }
 
-u8 r8712_createbss_cmd(struct _adapter *padapter)
+int r8712_createbss_cmd(struct _adapter *padapter)
 {
        struct cmd_obj *pcmd;
        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
@@ -419,7 +324,7 @@ u8 r8712_createbss_cmd(struct _adapter *padapter)
        padapter->ledpriv.LedControlHandler(padapter, LED_CTL_START_TO_LINK);
        pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC);
        if (!pcmd)
-               return _FAIL;
+               return -ENOMEM;
        INIT_LIST_HEAD(&pcmd->list);
        pcmd->cmdcode = _CreateBss_CMD_;
        pcmd->parmbuf = (unsigned char *)pdev_network;
@@ -431,10 +336,10 @@ u8 r8712_createbss_cmd(struct _adapter *padapter)
        pdev_network->IELength = pdev_network->IELength;
        pdev_network->Ssid.SsidLength = pdev_network->Ssid.SsidLength;
        r8712_enqueue_cmd(pcmdpriv, pcmd);
-       return _SUCCESS;
+       return 0;
 }
 
-u8 r8712_joinbss_cmd(struct _adapter  *padapter, struct wlan_network *pnetwork)
+int r8712_joinbss_cmd(struct _adapter  *padapter, struct wlan_network *pnetwork)
 {
        struct wlan_bssid_ex *psecnetwork;
        struct cmd_obj          *pcmd;
@@ -449,7 +354,7 @@ u8 r8712_joinbss_cmd(struct _adapter  *padapter, struct wlan_network *pnetwork)
        padapter->ledpriv.LedControlHandler(padapter, LED_CTL_START_TO_LINK);
        pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC);
        if (!pcmd)
-               return _FAIL;
+               return -ENOMEM;
 
        /* for hidden ap to set fw_state here */
        if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE) !=
@@ -468,10 +373,6 @@ u8 r8712_joinbss_cmd(struct _adapter  *padapter, struct wlan_network *pnetwork)
                }
        }
        psecnetwork = &psecuritypriv->sec_bss;
-       if (!psecnetwork) {
-               kfree(pcmd);
-               return _FAIL;
-       }
        memcpy(psecnetwork, &pnetwork->network, sizeof(*psecnetwork));
        psecuritypriv->authenticator_ie[0] = (unsigned char)
                                             psecnetwork->IELength;
@@ -570,10 +471,10 @@ u8 r8712_joinbss_cmd(struct _adapter  *padapter, struct wlan_network *pnetwork)
        pcmd->rsp = NULL;
        pcmd->rspsz = 0;
        r8712_enqueue_cmd(pcmdpriv, pcmd);
-       return _SUCCESS;
+       return 0;
 }
 
-u8 r8712_disassoc_cmd(struct _adapter *padapter) /* for sta_mode */
+void r8712_disassoc_cmd(struct _adapter *padapter) /* for sta_mode */
 {
        struct cmd_obj *pdisconnect_cmd;
        struct disconnect_parm *pdisconnect;
@@ -581,19 +482,18 @@ u8 r8712_disassoc_cmd(struct _adapter *padapter) /* for sta_mode */
 
        pdisconnect_cmd = kmalloc(sizeof(*pdisconnect_cmd), GFP_ATOMIC);
        if (!pdisconnect_cmd)
-               return _FAIL;
+               return;
        pdisconnect = kmalloc(sizeof(*pdisconnect), GFP_ATOMIC);
        if (!pdisconnect) {
                kfree(pdisconnect_cmd);
-               return _FAIL;
+               return;
        }
        init_h2fwcmd_w_parm_no_rsp(pdisconnect_cmd, pdisconnect,
                                   _DisConnect_CMD_);
        r8712_enqueue_cmd(pcmdpriv, pdisconnect_cmd);
-       return _SUCCESS;
 }
 
-u8 r8712_setopmode_cmd(struct _adapter *padapter,
+void r8712_setopmode_cmd(struct _adapter *padapter,
                 enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype)
 {
        struct cmd_obj *ph2c;
@@ -603,19 +503,18 @@ u8 r8712_setopmode_cmd(struct _adapter *padapter,
 
        ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
        if (!ph2c)
-               return _FAIL;
+               return;
        psetop = kmalloc(sizeof(*psetop), GFP_ATOMIC);
        if (!psetop) {
                kfree(ph2c);
-               return _FAIL;
+               return;
        }
        init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_);
        psetop->mode = (u8)networktype;
        r8712_enqueue_cmd(pcmdpriv, ph2c);
-       return _SUCCESS;
 }
 
-u8 r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key)
+void r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key)
 {
        struct cmd_obj *ph2c;
        struct set_stakey_parm *psetstakey_para;
@@ -627,17 +526,17 @@ u8 r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key)
 
        ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
        if (!ph2c)
-               return _FAIL;
+               return;
        psetstakey_para = kmalloc(sizeof(*psetstakey_para), GFP_ATOMIC);
        if (!psetstakey_para) {
                kfree(ph2c);
-               return _FAIL;
+               return;
        }
        psetstakey_rsp = kmalloc(sizeof(*psetstakey_rsp), GFP_ATOMIC);
        if (!psetstakey_rsp) {
                kfree(ph2c);
                kfree(psetstakey_para);
-               return _FAIL;
+               return;
        }
        init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
        ph2c->rsp = (u8 *) psetstakey_rsp;
@@ -656,53 +555,9 @@ u8 r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key)
                        &psecuritypriv->XGrpKey[
                        psecuritypriv->XGrpKeyid - 1]. skey, 16);
        r8712_enqueue_cmd(pcmdpriv, ph2c);
-       return _SUCCESS;
-}
-
-u8 r8712_setrfintfs_cmd(struct _adapter *padapter, u8 mode)
-{
-       struct cmd_obj *ph2c;
-       struct setrfintfs_parm *psetrfintfsparm;
-       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
-
-       ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
-       if (!ph2c)
-               return _FAIL;
-       psetrfintfsparm = kmalloc(sizeof(*psetrfintfsparm), GFP_ATOMIC);
-       if (!psetrfintfsparm) {
-               kfree(ph2c);
-               return _FAIL;
-       }
-       init_h2fwcmd_w_parm_no_rsp(ph2c, psetrfintfsparm,
-                                  GEN_CMD_CODE(_SetRFIntFs));
-       psetrfintfsparm->rfintfs = mode;
-       r8712_enqueue_cmd(pcmdpriv, ph2c);
-       return _SUCCESS;
-}
-
-u8 r8712_setrttbl_cmd(struct _adapter *padapter,
-                     struct setratable_parm *prate_table)
-{
-       struct cmd_obj *ph2c;
-       struct setratable_parm *psetrttblparm;
-       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
-
-       ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
-       if (!ph2c)
-               return _FAIL;
-       psetrttblparm = kmalloc(sizeof(*psetrttblparm), GFP_ATOMIC);
-       if (!psetrttblparm) {
-               kfree(ph2c);
-               return _FAIL;
-       }
-       init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm,
-                                  GEN_CMD_CODE(_SetRaTable));
-       memcpy(psetrttblparm, prate_table, sizeof(struct setratable_parm));
-       r8712_enqueue_cmd(pcmdpriv, ph2c);
-       return _SUCCESS;
 }
 
-u8 r8712_setMacAddr_cmd(struct _adapter *padapter, u8 *mac_addr)
+void r8712_setMacAddr_cmd(struct _adapter *padapter, u8 *mac_addr)
 {
        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
        struct cmd_obj *ph2c;
@@ -710,49 +565,19 @@ u8 r8712_setMacAddr_cmd(struct _adapter *padapter, u8 *mac_addr)
 
        ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
        if (!ph2c)
-               return _FAIL;
+               return;
        psetMacAddr_para = kmalloc(sizeof(*psetMacAddr_para), GFP_ATOMIC);
        if (!psetMacAddr_para) {
                kfree(ph2c);
-               return _FAIL;
+               return;
        }
        init_h2fwcmd_w_parm_no_rsp(ph2c, psetMacAddr_para,
                                   _SetMacAddress_CMD_);
        ether_addr_copy(psetMacAddr_para->MacAddr, mac_addr);
        r8712_enqueue_cmd(pcmdpriv, ph2c);
-       return _SUCCESS;
-}
-
-u8 r8712_setassocsta_cmd(struct _adapter *padapter, u8 *mac_addr)
-{
-       struct cmd_priv                 *pcmdpriv = &padapter->cmdpriv;
-       struct cmd_obj                  *ph2c;
-       struct set_assocsta_parm        *psetassocsta_para;
-       struct set_assocsta_rsp         *psetassocsta_rsp = NULL;
-
-       ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
-       if (!ph2c)
-               return _FAIL;
-       psetassocsta_para = kmalloc(sizeof(*psetassocsta_para), GFP_ATOMIC);
-       if (!psetassocsta_para) {
-               kfree(ph2c);
-               return _FAIL;
-       }
-       psetassocsta_rsp = kmalloc(sizeof(*psetassocsta_rsp), GFP_ATOMIC);
-       if (!psetassocsta_rsp) {
-               kfree(ph2c);
-               kfree(psetassocsta_para);
-               return _FAIL;
-       }
-       init_h2fwcmd_w_parm_no_rsp(ph2c, psetassocsta_para, _SetAssocSta_CMD_);
-       ph2c->rsp = (u8 *) psetassocsta_rsp;
-       ph2c->rspsz = sizeof(struct set_assocsta_rsp);
-       ether_addr_copy(psetassocsta_para->addr, mac_addr);
-       r8712_enqueue_cmd(pcmdpriv, ph2c);
-       return _SUCCESS;
 }
 
-u8 r8712_addbareq_cmd(struct _adapter *padapter, u8 tid)
+void r8712_addbareq_cmd(struct _adapter *padapter, u8 tid)
 {
        struct cmd_priv         *pcmdpriv = &padapter->cmdpriv;
        struct cmd_obj          *ph2c;
@@ -760,20 +585,19 @@ u8 r8712_addbareq_cmd(struct _adapter *padapter, u8 tid)
 
        ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
        if (!ph2c)
-               return _FAIL;
+               return;
        paddbareq_parm = kmalloc(sizeof(*paddbareq_parm), GFP_ATOMIC);
        if (!paddbareq_parm) {
                kfree(ph2c);
-               return _FAIL;
+               return;
        }
        paddbareq_parm->tid = tid;
        init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm,
                                   GEN_CMD_CODE(_AddBAReq));
        r8712_enqueue_cmd_ex(pcmdpriv, ph2c);
-       return _SUCCESS;
 }
 
-u8 r8712_wdg_wk_cmd(struct _adapter *padapter)
+void r8712_wdg_wk_cmd(struct _adapter *padapter)
 {
        struct cmd_obj *ph2c;
        struct drvint_cmd_parm  *pdrvintcmd_param;
@@ -781,18 +605,17 @@ u8 r8712_wdg_wk_cmd(struct _adapter *padapter)
 
        ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
        if (!ph2c)
-               return _FAIL;
+               return;
        pdrvintcmd_param = kmalloc(sizeof(*pdrvintcmd_param), GFP_ATOMIC);
        if (!pdrvintcmd_param) {
                kfree(ph2c);
-               return _FAIL;
+               return;
        }
        pdrvintcmd_param->i_cid = WDG_WK_CID;
        pdrvintcmd_param->sz = 0;
        pdrvintcmd_param->pbuf = NULL;
        init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvintcmd_param, _DRV_INT_CMD_);
        r8712_enqueue_cmd_ex(pcmdpriv, ph2c);
-       return _SUCCESS;
 }
 
 void r8712_survey_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd)
@@ -949,7 +772,7 @@ void r8712_setassocsta_cmdrsp_callback(struct _adapter *padapter,
        r8712_free_cmd_obj(pcmd);
 }
 
-u8 r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl,
+void r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl,
                        u32 tryPktCnt, u32 tryPktInterval, u32 firstStageTO)
 {
        struct cmd_obj *ph2c;
@@ -958,11 +781,11 @@ u8 r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl,
 
        ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
        if (!ph2c)
-               return _FAIL;
+               return;
        param = kzalloc(sizeof(*param), GFP_ATOMIC);
        if (!param) {
                kfree(ph2c);
-               return _FAIL;
+               return;
        }
 
        param->EnableDrvCtrl = (unsigned char)enableDrvCtrl;
@@ -973,5 +796,4 @@ u8 r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl,
        init_h2fwcmd_w_parm_no_rsp(ph2c, param,
                                GEN_CMD_CODE(_DisconnectCtrlEx));
        r8712_enqueue_cmd(pcmdpriv, ph2c);
-       return _SUCCESS;
 }
index 262984c..98d7fbf 100644 (file)
@@ -79,14 +79,14 @@ do {\
        pcmd->rspsz = 0;\
 } while (0)
 
-u32 r8712_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj);
-u32 r8712_enqueue_cmd_ex(struct cmd_priv *pcmdpriv, struct cmd_obj *obj);
+void r8712_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj);
+void r8712_enqueue_cmd_ex(struct cmd_priv *pcmdpriv, struct cmd_obj *obj);
 struct cmd_obj *r8712_dequeue_cmd(struct  __queue *queue);
 void r8712_free_cmd_obj(struct cmd_obj *pcmd);
 int r8712_cmd_thread(void *context);
-u32 r8712_init_cmd_priv(struct cmd_priv *pcmdpriv);
+int r8712_init_cmd_priv(struct cmd_priv *pcmdpriv);
 void r8712_free_cmd_priv(struct cmd_priv *pcmdpriv);
-u32 r8712_init_evt_priv(struct evt_priv *pevtpriv);
+int r8712_init_evt_priv(struct evt_priv *pevtpriv);
 void r8712_free_evt_priv(struct evt_priv *pevtpriv);
 
 enum rtl871x_drvint_cid {
@@ -708,29 +708,22 @@ struct DisconnectCtrlEx_param {
 #define H2C_CMD_OVERFLOW               0x06
 #define H2C_RESERVED                   0x07
 
-u8 r8712_setMacAddr_cmd(struct _adapter *padapter, u8 *mac_addr);
-u8 r8712_setassocsta_cmd(struct _adapter *padapter, u8 *mac_addr);
+void r8712_setMacAddr_cmd(struct _adapter *padapter, u8 *mac_addr);
 u8 r8712_sitesurvey_cmd(struct _adapter *padapter,
                        struct ndis_802_11_ssid *pssid);
-u8 r8712_createbss_cmd(struct _adapter *padapter);
-u8 r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key);
-u8 r8712_joinbss_cmd(struct _adapter *padapter,
-                    struct wlan_network *pnetwork);
-u8 r8712_disassoc_cmd(struct _adapter *padapter);
-u8 r8712_setopmode_cmd(struct _adapter *padapter,
+int r8712_createbss_cmd(struct _adapter *padapter);
+void r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key);
+int r8712_joinbss_cmd(struct _adapter *padapter,
+                     struct wlan_network *pnetwork);
+void r8712_disassoc_cmd(struct _adapter *padapter);
+void r8712_setopmode_cmd(struct _adapter *padapter,
                 enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype);
-u8 r8712_setdatarate_cmd(struct _adapter *padapter, u8 *rateset);
-u8 r8712_set_chplan_cmd(struct _adapter  *padapter, int chplan);
-u8 r8712_setbasicrate_cmd(struct _adapter *padapter, u8 *rateset);
-u8 r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval);
-u8 r8712_setrfintfs_cmd(struct _adapter *padapter, u8 mode);
-u8 r8712_setrfreg_cmd(struct _adapter  *padapter, u8 offset, u32 val);
-u8 r8712_setrttbl_cmd(struct _adapter  *padapter,
-                     struct setratable_parm *prate_table);
-u8 r8712_setfwdig_cmd(struct _adapter *padapter, u8 type);
-u8 r8712_setfwra_cmd(struct _adapter *padapter, u8 type);
-u8 r8712_addbareq_cmd(struct _adapter *padapter, u8 tid);
-u8 r8712_wdg_wk_cmd(struct _adapter *padapter);
+int r8712_setdatarate_cmd(struct _adapter *padapter, u8 *rateset);
+void r8712_set_chplan_cmd(struct _adapter  *padapter, int chplan);
+int r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval);
+int r8712_setrfreg_cmd(struct _adapter  *padapter, u8 offset, u32 val);
+void r8712_addbareq_cmd(struct _adapter *padapter, u8 tid);
+void r8712_wdg_wk_cmd(struct _adapter *padapter);
 void r8712_survey_cmd_callback(struct _adapter  *padapter,
                               struct cmd_obj *pcmd);
 void r8712_disassoc_cmd_callback(struct _adapter  *padapter,
@@ -747,7 +740,7 @@ void r8712_setstaKey_cmdrsp_callback(struct _adapter  *padapter,
                                     struct cmd_obj *pcmd);
 void r8712_setassocsta_cmdrsp_callback(struct _adapter  *padapter,
                                       struct cmd_obj *pcmd);
-u8 r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl,
+void r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl,
                        u32 tryPktCnt, u32 tryPktInterval, u32 firstStageTO);
 
 struct _cmd_callback {
index 0027d8e..221bf92 100644 (file)
@@ -150,7 +150,7 @@ void r8712_eeprom_write16(struct _adapter *padapter, u16 reg, u16 data)
        x |= _EEM1 | _EECS;
        r8712_write8(padapter, EE_9346CR, x);
        shift_out_bits(padapter, EEPROM_EWEN_OPCODE, 5);
-       if (padapter->EepromAddressSize == 8)   /*CF+ and SDIO*/
+       if (padapter->eeprom_address_size == 8) /*CF+ and SDIO*/
                shift_out_bits(padapter, 0, 6);
        else    /* USB */
                shift_out_bits(padapter, 0, 4);
@@ -165,7 +165,7 @@ void r8712_eeprom_write16(struct _adapter *padapter, u16 reg, u16 data)
         */
        shift_out_bits(padapter, EEPROM_WRITE_OPCODE, 3);
        /* select which word in the EEPROM that we are writing to. */
-       shift_out_bits(padapter, reg, padapter->EepromAddressSize);
+       shift_out_bits(padapter, reg, padapter->eeprom_address_size);
        /* write the data to the selected EEPROM word. */
        shift_out_bits(padapter, data, 16);
        if (wait_eeprom_cmd_done(padapter)) {
@@ -207,7 +207,7 @@ u16 r8712_eeprom_read16(struct _adapter *padapter, u16 reg) /*ReadEEprom*/
         * The opcode is 3bits in length, reg is 6 bits long
         */
        shift_out_bits(padapter, EEPROM_READ_OPCODE, 3);
-       shift_out_bits(padapter, reg, padapter->EepromAddressSize);
+       shift_out_bits(padapter, reg, padapter->eeprom_address_size);
        /* Now read the data (16 bits) in from the selected EEPROM word */
        data = shift_in_bits(padapter);
        eeprom_clean(padapter);
index 17dafef..87024d6 100644 (file)
@@ -107,13 +107,11 @@ uint r8712_alloc_io_queue(struct _adapter *adapter)
        INIT_LIST_HEAD(&pio_queue->processing);
        INIT_LIST_HEAD(&pio_queue->pending);
        spin_lock_init(&pio_queue->lock);
-       pio_queue->pallocated_free_ioreqs_buf = kmalloc(NUM_IOREQ *
+       pio_queue->pallocated_free_ioreqs_buf = kzalloc(NUM_IOREQ *
                                                (sizeof(struct io_req)) + 4,
                                                GFP_ATOMIC);
        if ((pio_queue->pallocated_free_ioreqs_buf) == NULL)
                goto alloc_io_queue_fail;
-       memset(pio_queue->pallocated_free_ioreqs_buf, 0,
-                       (NUM_IOREQ * (sizeof(struct io_req)) + 4));
        pio_queue->free_ioreqs_buf = pio_queue->pallocated_free_ioreqs_buf + 4
                        - ((addr_t)(pio_queue->pallocated_free_ioreqs_buf)
                        & 3);
index a7230c0..b08b9a1 100644 (file)
@@ -124,10 +124,91 @@ static inline void handle_group_key(struct ieee_param *param,
        }
 }
 
-static noinline_for_stack char *translate_scan(struct _adapter *padapter,
-                                  struct iw_request_info *info,
-                                  struct wlan_network *pnetwork,
-                                  char *start, char *stop)
+static noinline_for_stack char *translate_scan_wpa(struct iw_request_info *info,
+                                                  struct wlan_network *pnetwork,
+                                                  struct iw_event *iwe,
+                                                  char *start, char *stop)
+{
+       /* parsing WPA/WPA2 IE */
+       u8 buf[MAX_WPA_IE_LEN];
+       u8 wpa_ie[255], rsn_ie[255];
+       u16 wpa_len = 0, rsn_len = 0;
+       int n, i;
+
+       r8712_get_sec_ie(pnetwork->network.IEs,
+                        pnetwork->network.IELength, rsn_ie, &rsn_len,
+                        wpa_ie, &wpa_len);
+       if (wpa_len > 0) {
+               memset(buf, 0, MAX_WPA_IE_LEN);
+               n = sprintf(buf, "wpa_ie=");
+               for (i = 0; i < wpa_len; i++) {
+                       n += snprintf(buf + n, MAX_WPA_IE_LEN - n,
+                                               "%02x", wpa_ie[i]);
+                       if (n >= MAX_WPA_IE_LEN)
+                               break;
+               }
+               memset(iwe, 0, sizeof(*iwe));
+               iwe->cmd = IWEVCUSTOM;
+               iwe->u.data.length = (u16)strlen(buf);
+               start = iwe_stream_add_point(info, start, stop,
+                       iwe, buf);
+               memset(iwe, 0, sizeof(*iwe));
+               iwe->cmd = IWEVGENIE;
+               iwe->u.data.length = (u16)wpa_len;
+               start = iwe_stream_add_point(info, start, stop,
+                       iwe, wpa_ie);
+       }
+       if (rsn_len > 0) {
+               memset(buf, 0, MAX_WPA_IE_LEN);
+               n = sprintf(buf, "rsn_ie=");
+               for (i = 0; i < rsn_len; i++) {
+                       n += snprintf(buf + n, MAX_WPA_IE_LEN - n,
+                                               "%02x", rsn_ie[i]);
+                       if (n >= MAX_WPA_IE_LEN)
+                               break;
+               }
+               memset(iwe, 0, sizeof(*iwe));
+               iwe->cmd = IWEVCUSTOM;
+               iwe->u.data.length = strlen(buf);
+               start = iwe_stream_add_point(info, start, stop,
+                       iwe, buf);
+               memset(iwe, 0, sizeof(*iwe));
+               iwe->cmd = IWEVGENIE;
+               iwe->u.data.length = rsn_len;
+               start = iwe_stream_add_point(info, start, stop, iwe,
+                       rsn_ie);
+       }
+
+       return start;
+}
+
+static noinline_for_stack char *translate_scan_wps(struct iw_request_info *info,
+                                                  struct wlan_network *pnetwork,
+                                                  struct iw_event *iwe,
+                                                  char *start, char *stop)
+{
+       /* parsing WPS IE */
+       u8 wps_ie[512];
+       uint wps_ielen;
+
+       if (r8712_get_wps_ie(pnetwork->network.IEs,
+           pnetwork->network.IELength,
+           wps_ie, &wps_ielen)) {
+               if (wps_ielen > 2) {
+                       iwe->cmd = IWEVGENIE;
+                       iwe->u.data.length = (u16)wps_ielen;
+                       start = iwe_stream_add_point(info, start, stop,
+                               iwe, wps_ie);
+               }
+       }
+
+       return start;
+}
+
+static char *translate_scan(struct _adapter *padapter,
+                           struct iw_request_info *info,
+                           struct wlan_network *pnetwork,
+                           char *start, char *stop)
 {
        struct iw_event iwe;
        struct ieee80211_ht_cap *pht_capie;
@@ -240,73 +321,11 @@ static noinline_for_stack char *translate_scan(struct _adapter *padapter,
        /* Check if we added any event */
        if ((current_val - start) > iwe_stream_lcp_len(info))
                start = current_val;
-       /* parsing WPA/WPA2 IE */
-       {
-               u8 buf[MAX_WPA_IE_LEN];
-               u8 wpa_ie[255], rsn_ie[255];
-               u16 wpa_len = 0, rsn_len = 0;
-               int n;
-
-               r8712_get_sec_ie(pnetwork->network.IEs,
-                                pnetwork->network.IELength, rsn_ie, &rsn_len,
-                                wpa_ie, &wpa_len);
-               if (wpa_len > 0) {
-                       memset(buf, 0, MAX_WPA_IE_LEN);
-                       n = sprintf(buf, "wpa_ie=");
-                       for (i = 0; i < wpa_len; i++) {
-                               n += snprintf(buf + n, MAX_WPA_IE_LEN - n,
-                                                       "%02x", wpa_ie[i]);
-                               if (n >= MAX_WPA_IE_LEN)
-                                       break;
-                       }
-                       memset(&iwe, 0, sizeof(iwe));
-                       iwe.cmd = IWEVCUSTOM;
-                       iwe.u.data.length = (u16)strlen(buf);
-                       start = iwe_stream_add_point(info, start, stop,
-                               &iwe, buf);
-                       memset(&iwe, 0, sizeof(iwe));
-                       iwe.cmd = IWEVGENIE;
-                       iwe.u.data.length = (u16)wpa_len;
-                       start = iwe_stream_add_point(info, start, stop,
-                               &iwe, wpa_ie);
-               }
-               if (rsn_len > 0) {
-                       memset(buf, 0, MAX_WPA_IE_LEN);
-                       n = sprintf(buf, "rsn_ie=");
-                       for (i = 0; i < rsn_len; i++) {
-                               n += snprintf(buf + n, MAX_WPA_IE_LEN - n,
-                                                       "%02x", rsn_ie[i]);
-                               if (n >= MAX_WPA_IE_LEN)
-                                       break;
-                       }
-                       memset(&iwe, 0, sizeof(iwe));
-                       iwe.cmd = IWEVCUSTOM;
-                       iwe.u.data.length = strlen(buf);
-                       start = iwe_stream_add_point(info, start, stop,
-                               &iwe, buf);
-                       memset(&iwe, 0, sizeof(iwe));
-                       iwe.cmd = IWEVGENIE;
-                       iwe.u.data.length = rsn_len;
-                       start = iwe_stream_add_point(info, start, stop, &iwe,
-                               rsn_ie);
-               }
-       }
 
-       { /* parsing WPS IE */
-               u8 wps_ie[512];
-               uint wps_ielen;
+       start = translate_scan_wpa(info, pnetwork, &iwe, start, stop);
+
+       start = translate_scan_wps(info, pnetwork, &iwe, start, stop);
 
-               if (r8712_get_wps_ie(pnetwork->network.IEs,
-                   pnetwork->network.IELength,
-                   wps_ie, &wps_ielen)) {
-                       if (wps_ielen > 2) {
-                               iwe.cmd = IWEVGENIE;
-                               iwe.u.data.length = (u16)wps_ielen;
-                               start = iwe_stream_add_point(info, start, stop,
-                                       &iwe, wps_ie);
-                       }
-               }
-       }
        /* Add quality statistics */
        iwe.cmd = IWEVQUAL;
        rssi = r8712_signal_scale_mapping(pnetwork->network.Rssi);
@@ -478,13 +497,13 @@ static int r871x_set_wpa_ie(struct _adapter *padapter, char *pie,
                        goto exit;
                }
                if (r8712_parse_wpa_ie(buf, ielen, &group_cipher,
-                   &pairwise_cipher) == _SUCCESS) {
+                   &pairwise_cipher) == 0) {
                        padapter->securitypriv.AuthAlgrthm = 2;
                        padapter->securitypriv.ndisauthtype =
                                  Ndis802_11AuthModeWPAPSK;
                }
                if (r8712_parse_wpa2_ie(buf, ielen, &group_cipher,
-                   &pairwise_cipher) == _SUCCESS) {
+                   &pairwise_cipher) == 0) {
                        padapter->securitypriv.AuthAlgrthm = 2;
                        padapter->securitypriv.ndisauthtype =
                                  Ndis802_11AuthModeWPA2PSK;
@@ -1309,7 +1328,7 @@ static int r8711_wx_set_rate(struct net_device *dev,
        u32 ratevalue = 0;
        u8 datarates[NumRates];
        u8 mpdatarate[NumRates] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff};
-       int i, ret = 0;
+       int i;
 
        if (target_rate == -1) {
                ratevalue = 11;
@@ -1367,9 +1386,7 @@ set_rate:
                        datarates[i] = 0xff;
                }
        }
-       if (r8712_setdatarate_cmd(padapter, datarates) != _SUCCESS)
-               ret = -ENOMEM;
-       return ret;
+       return r8712_setdatarate_cmd(padapter, datarates);
 }
 
 static int r8711_wx_get_rate(struct net_device *dev,
@@ -1577,7 +1594,7 @@ static int r8711_wx_get_enc(struct net_device *dev,
                                struct iw_request_info *info,
                                union iwreq_data *wrqu, char *keybuf)
 {
-       uint key, ret = 0;
+       uint key;
        struct _adapter *padapter = netdev_priv(dev);
        struct iw_point *erq = &(wrqu->encoding);
        struct  mlme_priv       *pmlmepriv = &(padapter->mlmepriv);
@@ -1633,7 +1650,7 @@ static int r8711_wx_get_enc(struct net_device *dev,
                erq->flags |= IW_ENCODE_DISABLED;
                break;
        }
-       return ret;
+       return 0;
 }
 
 static int r8711_wx_get_power(struct net_device *dev,
index 2dc20da..b78101a 100644 (file)
@@ -429,7 +429,7 @@ uint oid_rt_pro_rf_write_registry_hdl(struct oid_par_priv*
                return RNDIS_STATUS_NOT_ACCEPTED;
        if (poid_par_priv->information_buf_len ==
           (sizeof(unsigned long) * 3)) {
-               if (!r8712_setrfreg_cmd(Adapter,
+               if (r8712_setrfreg_cmd(Adapter,
                        *(unsigned char *)poid_par_priv->information_buf,
                        (unsigned long)(*((unsigned long *)
                                        poid_par_priv->information_buf + 2))))
@@ -467,7 +467,7 @@ uint oid_rt_pro_rf_read_registry_hdl(struct oid_par_priv *poid_par_priv)
                 * RegDataWidth = *((unsigned long *)InformationBuffer+1);
                 * RegDataValue =  *((unsigned long *)InformationBuffer+2);
                 */
-                       if (!r8712_getrfreg_cmd(Adapter,
+                       if (r8712_getrfreg_cmd(Adapter,
                            *(unsigned char *)poid_par_priv->information_buf,
                            (unsigned char *)&Adapter->mppriv.workparam.io_value
                            ))
index 2622d5e..f3c0a93 100644 (file)
@@ -66,7 +66,7 @@ static u8 do_join(struct _adapter *padapter)
        }
 
        ret = r8712_select_and_join_from_scan(pmlmepriv);
-       if (ret == _SUCCESS) {
+       if (!ret) {
                mod_timer(&pmlmepriv->assoc_timer,
                          jiffies + msecs_to_jiffies(MAX_JOIN_TIMEOUT));
        } else {
@@ -84,7 +84,7 @@ static u8 do_join(struct _adapter *padapter)
                               sizeof(struct ndis_802_11_ssid));
                        r8712_update_registrypriv_dev_network(padapter);
                        r8712_generate_random_ibss(pibss);
-                       if (r8712_createbss_cmd(padapter) != _SUCCESS)
+                       if (r8712_createbss_cmd(padapter))
                                return false;
                        pmlmepriv->to_join = false;
                } else {
index 7c7267d..0cc879a 100644 (file)
@@ -29,7 +29,7 @@
 
 static void update_ht_cap(struct _adapter *padapter, u8 *pie, uint ie_len);
 
-static sint _init_mlme_priv(struct _adapter *padapter)
+int r8712_init_mlme_priv(struct _adapter *padapter)
 {
        sint    i;
        u8      *pbuf;
@@ -129,8 +129,8 @@ static void free_network_nolock(struct mlme_priv *pmlmepriv,
  * Shall be called under atomic context...
  * to avoid possible racing condition...
  */
-static struct wlan_network *_r8712_find_network(struct  __queue *scanned_queue,
-                                        u8 *addr)
+static struct wlan_network *r8712_find_network(struct  __queue *scanned_queue,
+                                              u8 *addr)
 {
        unsigned long irqL;
        struct list_head *phead, *plist;
@@ -151,7 +151,7 @@ static struct wlan_network *_r8712_find_network(struct  __queue *scanned_queue,
        return pnetwork;
 }
 
-static void _free_network_queue(struct _adapter *padapter)
+void r8712_free_network_queue(struct _adapter *padapter)
 {
        unsigned long irqL;
        struct list_head *phead, *plist;
@@ -205,11 +205,6 @@ u8 *r8712_get_capability_from_ie(u8 *ie)
        return ie + 8 + 2;
 }
 
-int r8712_init_mlme_priv(struct _adapter *padapter)
-{
-       return _init_mlme_priv(padapter);
-}
-
 void r8712_free_mlme_priv(struct mlme_priv *pmlmepriv)
 {
        kfree(pmlmepriv->free_bss_buf);
@@ -220,25 +215,6 @@ static struct      wlan_network *alloc_network(struct mlme_priv *pmlmepriv)
        return _r8712_alloc_network(pmlmepriv);
 }
 
-void r8712_free_network_queue(struct _adapter *dev)
-{
-       _free_network_queue(dev);
-}
-
-/*
- * return the wlan_network with the matching addr
- * Shall be called under atomic context...
- * to avoid possible racing condition...
- */
-static struct wlan_network *r8712_find_network(struct  __queue *scanned_queue,
-                                              u8 *addr)
-{
-       struct wlan_network *pnetwork = _r8712_find_network(scanned_queue,
-                                                           addr);
-
-       return pnetwork;
-}
-
 int r8712_is_same_ibss(struct _adapter *adapter, struct wlan_network *pnetwork)
 {
        int ret = true;
@@ -558,8 +534,7 @@ void r8712_surveydone_event_callback(struct _adapter *adapter, u8 *pbuf)
                        if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
                                set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
 
-                               if (r8712_select_and_join_from_scan(pmlmepriv)
-                                   == _SUCCESS) {
+                               if (!r8712_select_and_join_from_scan(pmlmepriv)) {
                                        mod_timer(&pmlmepriv->assoc_timer, jiffies +
                                                  msecs_to_jiffies(MAX_JOIN_TIMEOUT));
                                } else {
@@ -584,8 +559,7 @@ void r8712_surveydone_event_callback(struct _adapter *adapter, u8 *pbuf)
                } else {
                        pmlmepriv->to_join = false;
                        set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
-                       if (r8712_select_and_join_from_scan(pmlmepriv) ==
-                           _SUCCESS)
+                       if (!r8712_select_and_join_from_scan(pmlmepriv))
                                mod_timer(&pmlmepriv->assoc_timer, jiffies +
                                          msecs_to_jiffies(MAX_JOIN_TIMEOUT));
                        else
@@ -1091,11 +1065,6 @@ void _r8712_dhcp_timeout_handler (struct _adapter *adapter)
                            adapter->registrypriv.smart_ps);
 }
 
-void _r8712_wdg_timeout_handler(struct _adapter *adapter)
-{
-       r8712_wdg_wk_cmd(adapter);
-}
-
 int r8712_select_and_join_from_scan(struct mlme_priv *pmlmepriv)
 {
        struct list_head *phead;
@@ -1116,7 +1085,7 @@ int r8712_select_and_join_from_scan(struct mlme_priv *pmlmepriv)
                                pnetwork = pnetwork_max_rssi;
                                goto ask_for_joinbss;
                        }
-                       return _FAIL;
+                       return -EINVAL;
                }
                pnetwork = container_of(pmlmepriv->pscanned,
                                        struct wlan_network, list);
index 8a54181..a160107 100644 (file)
@@ -172,7 +172,7 @@ void r8712_wpspbc_event_callback(struct _adapter *adapter, u8 *pbuf);
 void r8712_free_network_queue(struct _adapter *adapter);
 int r8712_init_mlme_priv(struct _adapter *adapter);
 void r8712_free_mlme_priv(struct mlme_priv *pmlmepriv);
-sint r8712_select_and_join_from_scan(struct mlme_priv *pmlmepriv);
+int r8712_select_and_join_from_scan(struct mlme_priv *pmlmepriv);
 sint r8712_set_key(struct _adapter *adapter,
                   struct security_priv *psecuritypriv, sint keyid);
 sint r8712_set_auth(struct _adapter *adapter,
@@ -195,7 +195,6 @@ void _r8712_sitesurvey_ctrl_handler(struct _adapter *adapter);
 void _r8712_join_timeout_handler(struct _adapter *adapter);
 void r8712_scan_timeout_handler(struct _adapter *adapter);
 void _r8712_dhcp_timeout_handler(struct _adapter *adapter);
-void _r8712_wdg_timeout_handler(struct _adapter *adapter);
 struct wlan_network *_r8712_alloc_network(struct mlme_priv *pmlmepriv);
 sint r8712_if_up(struct _adapter *padapter);
 void r8712_joinbss_reset(struct _adapter *padapter);
index ba37950..edd3da0 100644 (file)
@@ -709,20 +709,18 @@ static u32 GetPhyRxPktCounts(struct _adapter *pAdapter, u32 selbit)
 
 u32 r8712_GetPhyRxPktReceived(struct _adapter *pAdapter)
 {
-       u32 OFDM_cnt = 0, CCK_cnt = 0, HT_cnt = 0;
+       u32 OFDM_cnt = GetPhyRxPktCounts(pAdapter, OFDM_MPDU_OK_BIT);
+       u32 CCK_cnt  = GetPhyRxPktCounts(pAdapter, CCK_MPDU_OK_BIT);
+       u32 HT_cnt   = GetPhyRxPktCounts(pAdapter, HT_MPDU_OK_BIT);
 
-       OFDM_cnt = GetPhyRxPktCounts(pAdapter, OFDM_MPDU_OK_BIT);
-       CCK_cnt = GetPhyRxPktCounts(pAdapter, CCK_MPDU_OK_BIT);
-       HT_cnt = GetPhyRxPktCounts(pAdapter, HT_MPDU_OK_BIT);
        return OFDM_cnt + CCK_cnt + HT_cnt;
 }
 
 u32 r8712_GetPhyRxPktCRC32Error(struct _adapter *pAdapter)
 {
-       u32 OFDM_cnt = 0, CCK_cnt = 0, HT_cnt = 0;
+       u32 OFDM_cnt = GetPhyRxPktCounts(pAdapter, OFDM_MPDU_FAIL_BIT);
+       u32 CCK_cnt  = GetPhyRxPktCounts(pAdapter, CCK_MPDU_FAIL_BIT);
+       u32 HT_cnt   = GetPhyRxPktCounts(pAdapter, HT_MPDU_FAIL_BIT);
 
-       OFDM_cnt = GetPhyRxPktCounts(pAdapter, OFDM_MPDU_FAIL_BIT);
-       CCK_cnt = GetPhyRxPktCounts(pAdapter, CCK_MPDU_FAIL_BIT);
-       HT_cnt = GetPhyRxPktCounts(pAdapter, HT_MPDU_FAIL_BIT);
        return OFDM_cnt + CCK_cnt + HT_cnt;
 }
index 588346d..aa8f850 100644 (file)
@@ -153,7 +153,7 @@ static int mp_start_test(struct _adapter *padapter)
        struct sta_info *psta;
        unsigned long length;
        unsigned long irqL;
-       int res = _SUCCESS;
+       int res = 0;
 
        /* 3 1. initialize a new struct wlan_bssid_ex */
        memcpy(bssid.MacAddress, pmppriv->network_macaddr, ETH_ALEN);
@@ -187,7 +187,7 @@ static int mp_start_test(struct _adapter *padapter)
                r8712_free_stainfo(padapter, psta);
        psta = r8712_alloc_stainfo(&padapter->stapriv, bssid.MacAddress);
        if (psta == NULL) {
-               res = _FAIL;
+               res = -ENOMEM;
                goto end_of_mp_start_test;
        }
        /* 3 3. join pseudo AdHoc */
@@ -231,22 +231,6 @@ end_of_mp_stop_test:
        return _SUCCESS;
 }
 
-int mp_start_joinbss(struct _adapter *padapter, struct ndis_802_11_ssid *pssid)
-{
-       struct mp_priv *pmppriv = &padapter->mppriv;
-       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
-       unsigned char res = _SUCCESS;
-
-       if (!check_fwstate(pmlmepriv, WIFI_MP_STATE))
-               return _FAIL;
-       if (!check_fwstate(pmlmepriv, _FW_LINKED))
-               return _FAIL;
-       _clr_fwstate_(pmlmepriv, _FW_LINKED);
-       res = r8712_setassocsta_cmd(padapter, pmppriv->network_macaddr);
-       set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
-       return res;
-}
-
 uint oid_rt_pro_set_data_rate_hdl(struct oid_par_priv
                                         *poid_par_priv)
 {
@@ -278,7 +262,7 @@ uint oid_rt_pro_start_test_hdl(struct oid_par_priv *poid_par_priv)
                return  RNDIS_STATUS_NOT_ACCEPTED;
        mode = *((u32 *)poid_par_priv->information_buf);
        Adapter->mppriv.mode = mode;/* 1 for loopback*/
-       if (mp_start_test(Adapter) == _FAIL)
+       if (mp_start_test(Adapter))
                status = RNDIS_STATUS_NOT_ACCEPTED;
        r8712_write8(Adapter, MSR, 1); /* Link in ad hoc network, 0x1025004C */
        r8712_write8(Adapter, RCR, 0); /* RCR : disable all pkt, 0x10250048 */
@@ -661,11 +645,6 @@ uint oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv)
                        status = RNDIS_STATUS_NOT_ACCEPTED;
                        break;
                }
-
-               if ((status == RNDIS_STATUS_SUCCESS) &&
-                   (RegRWStruct->offset == HIMR) &&
-                   (RegRWStruct->width == 4))
-                       Adapter->ImrContent = RegRWStruct->value;
        }
        return status;
 }
index 44cd911..64e2ae4 100644 (file)
@@ -71,8 +71,6 @@ struct DR_VARIABLE_STRUCT {
        u32 variable;
 };
 
-int mp_start_joinbss(struct _adapter *padapter, struct ndis_802_11_ssid *pssid);
-
 /* oid_rtl_seg_87_11_00 */
 uint oid_rt_pro_read_register_hdl(struct oid_par_priv *poid_par_priv);
 uint oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv);
index 28f7369..5298fe6 100644 (file)
@@ -151,7 +151,7 @@ sint r8712_recvframe_chkmic(struct _adapter *adapter,
        if (prxattrib->encrypt == _TKIP_) {
                /* calculate mic code */
                if (stainfo != NULL) {
-                       if (IS_MCAST(prxattrib->ra)) {
+                       if (is_multicast_ether_addr(prxattrib->ra)) {
                                iv = precvframe->u.hdr.rx_data +
                                     prxattrib->hdrlen;
                                idx = iv[3];
@@ -180,12 +180,12 @@ sint r8712_recvframe_chkmic(struct _adapter *adapter,
                        if (bmic_err) {
                                if (prxattrib->bdecrypted)
                                        r8712_handle_tkip_mic_err(adapter,
-                                               (u8)IS_MCAST(prxattrib->ra));
+                                               (u8)is_multicast_ether_addr(prxattrib->ra));
                                res = _FAIL;
                        } else {
                                /* mic checked ok */
                                if (!psecuritypriv->bcheck_grpkey &&
-                                   IS_MCAST(prxattrib->ra))
+                                   is_multicast_ether_addr(prxattrib->ra))
                                        psecuritypriv->bcheck_grpkey = true;
                        }
                        recvframe_pull_tail(precvframe, 8);
@@ -305,7 +305,7 @@ static sint sta2sta_data_frame(struct _adapter *adapter,
        u8 *mybssid  = get_bssid(pmlmepriv);
        u8 *myhwaddr = myid(&adapter->eeprompriv);
        u8 *sta_addr = NULL;
-       sint bmcast = IS_MCAST(pattrib->dst);
+       bool bmcast = is_multicast_ether_addr(pattrib->dst);
 
        if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ||
            check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
@@ -331,7 +331,7 @@ static sint sta2sta_data_frame(struct _adapter *adapter,
                        /* For AP mode, if DA == MCAST, then BSSID should
                         * be also MCAST
                         */
-                       if (!IS_MCAST(pattrib->bssid))
+                       if (!is_multicast_ether_addr(pattrib->bssid))
                                return _FAIL;
                } else { /* not mc-frame */
                        /* For AP mode, if DA is non-MCAST, then it must be
@@ -373,7 +373,7 @@ static sint ap2sta_data_frame(struct _adapter *adapter,
        struct  mlme_priv *pmlmepriv = &adapter->mlmepriv;
        u8 *mybssid  = get_bssid(pmlmepriv);
        u8 *myhwaddr = myid(&adapter->eeprompriv);
-       sint bmcast = IS_MCAST(pattrib->dst);
+       bool bmcast = is_multicast_ether_addr(pattrib->dst);
 
        if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) &&
            check_fwstate(pmlmepriv, _FW_LINKED)) {
@@ -532,7 +532,7 @@ static sint validate_recv_data_frame(struct _adapter *adapter,
 
        if (pattrib->privacy) {
                GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt,
-                              IS_MCAST(pattrib->ra));
+                              is_multicast_ether_addr(pattrib->ra));
                SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len,
                               pattrib->encrypt);
        } else {
index f826450..693008b 100644 (file)
@@ -665,7 +665,7 @@ u32 r8712_tkip_decrypt(struct _adapter *padapter, u8 *precvframe)
                        length = ((union recv_frame *)precvframe)->
                                 u.hdr.len - prxattrib->hdrlen -
                                 prxattrib->iv_len;
-                       if (IS_MCAST(prxattrib->ra)) {
+                       if (is_multicast_ether_addr(prxattrib->ra)) {
                                idx = iv[3];
                                prwskey = &psecuritypriv->XGrpKey[
                                         ((idx >> 6) & 0x3) - 1].skey[0];
@@ -1368,7 +1368,7 @@ u32 r8712_aes_decrypt(struct _adapter *padapter, u8 *precvframe)
                stainfo = r8712_get_stainfo(&padapter->stapriv,
                                            &prxattrib->ta[0]);
                if (stainfo != NULL) {
-                       if (IS_MCAST(prxattrib->ra)) {
+                       if (is_multicast_ether_addr(prxattrib->ra)) {
                                iv = pframe + prxattrib->hdrlen;
                                idx = iv[3];
                                prwskey = &psecuritypriv->XGrpKey[
index 7c30b9e..653812c 100644 (file)
@@ -34,7 +34,7 @@ static void _init_stainfo(struct sta_info *psta)
        INIT_LIST_HEAD(&psta->auth_list);
 }
 
-u32 _r8712_init_sta_priv(struct        sta_priv *pstapriv)
+int _r8712_init_sta_priv(struct        sta_priv *pstapriv)
 {
        struct sta_info *psta;
        s32 i;
@@ -42,7 +42,7 @@ u32 _r8712_init_sta_priv(struct       sta_priv *pstapriv)
        pstapriv->pallocated_stainfo_buf = kmalloc(sizeof(struct sta_info) *
                                                   NUM_STA + 4, GFP_ATOMIC);
        if (!pstapriv->pallocated_stainfo_buf)
-               return _FAIL;
+               return -ENOMEM;
        pstapriv->pstainfo_buf = pstapriv->pallocated_stainfo_buf + 4 -
                ((addr_t)(pstapriv->pallocated_stainfo_buf) & 3);
        _init_queue(&pstapriv->free_sta_queue);
@@ -59,7 +59,7 @@ u32 _r8712_init_sta_priv(struct       sta_priv *pstapriv)
        }
        INIT_LIST_HEAD(&pstapriv->asoc_list);
        INIT_LIST_HEAD(&pstapriv->auth_list);
-       return _SUCCESS;
+       return 0;
 }
 
 /* this function is used to free the memory of lock || sema for all stainfos */
@@ -77,14 +77,13 @@ static void mfree_all_stainfo(struct sta_priv *pstapriv)
        spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL);
 }
 
-u32 _r8712_free_sta_priv(struct sta_priv *pstapriv)
+void _r8712_free_sta_priv(struct sta_priv *pstapriv)
 {
        if (pstapriv) {
                /* be done before free sta_hash_lock */
                mfree_all_stainfo(pstapriv);
                kfree(pstapriv->pallocated_stainfo_buf);
        }
-       return _SUCCESS;
 }
 
 struct sta_info *r8712_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr)
index f6fe8ea..0a26d71 100644 (file)
@@ -133,13 +133,14 @@ sint _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv,
                pxmitbuf->pbuf = pxmitbuf->pallocated_buf + XMITBUF_ALIGN_SZ -
                                 ((addr_t) (pxmitbuf->pallocated_buf) &
                                 (XMITBUF_ALIGN_SZ - 1));
-               r8712_xmit_resource_alloc(padapter, pxmitbuf);
+               if (r8712_xmit_resource_alloc(padapter, pxmitbuf))
+                       return _FAIL;
                list_add_tail(&pxmitbuf->list,
                                 &(pxmitpriv->free_xmitbuf_queue.queue));
                pxmitbuf++;
        }
        pxmitpriv->free_xmitbuf_cnt = NR_XMITBUFF;
-       INIT_WORK(&padapter->wkFilterRxFF0, r8712_SetFilter);
+       INIT_WORK(&padapter->wk_filter_rx_ff0, r8712_SetFilter);
        alloc_hwxmits(padapter);
        init_hwxmits(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);
        tasklet_init(&pxmitpriv->xmit_tasklet,
@@ -181,7 +182,7 @@ sint r8712_update_attrib(struct _adapter *padapter, _pkt *pkt,
 
        struct tx_cmd txdesc;
 
-       sint bmcast;
+       bool bmcast;
        struct sta_priv         *pstapriv = &padapter->stapriv;
        struct security_priv    *psecuritypriv = &padapter->securitypriv;
        struct mlme_priv        *pmlmepriv = &padapter->mlmepriv;
@@ -257,7 +258,7 @@ sint r8712_update_attrib(struct _adapter *padapter, _pkt *pkt,
                        }
                }
        }
-       bmcast = IS_MCAST(pattrib->ra);
+       bmcast = is_multicast_ether_addr(pattrib->ra);
        /* get sta_info*/
        if (bmcast) {
                psta = r8712_get_bcmc_stainfo(padapter);
@@ -353,7 +354,7 @@ static sint xmitframe_addmic(struct _adapter *padapter,
        struct  security_priv *psecuritypriv = &padapter->securitypriv;
        struct  xmit_priv *pxmitpriv = &padapter->xmitpriv;
        u8 priority[4] = {0x0, 0x0, 0x0, 0x0};
-       sint bmcst = IS_MCAST(pattrib->ra);
+       bool bmcst = is_multicast_ether_addr(pattrib->ra);
 
        if (pattrib->psta)
                stainfo = pattrib->psta;
@@ -523,7 +524,7 @@ static sint make_wlanhdr(struct _adapter *padapter, u8 *hdr,
                /* Update Seq Num will be handled by f/w */
                {
                        struct sta_info *psta;
-                       sint bmcst = IS_MCAST(pattrib->ra);
+                       bool bmcst = is_multicast_ether_addr(pattrib->ra);
 
                        if (pattrib->psta) {
                                psta = pattrib->psta;
@@ -594,7 +595,7 @@ sint r8712_xmitframe_coalesce(struct _adapter *padapter, _pkt *pkt,
        struct xmit_priv        *pxmitpriv = &padapter->xmitpriv;
        struct pkt_attrib       *pattrib = &pxmitframe->attrib;
        u8 *pbuf_start;
-       sint bmcst = IS_MCAST(pattrib->ra);
+       bool bmcst = is_multicast_ether_addr(pattrib->ra);
 
        if (pattrib->psta == NULL)
                return _FAIL;
@@ -903,7 +904,7 @@ sint r8712_xmit_classifier(struct _adapter *padapter,
        struct pkt_attrib *pattrib = &pxmitframe->attrib;
        struct sta_priv *pstapriv = &padapter->stapriv;
        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
-       sint bmcst = IS_MCAST(pattrib->ra);
+       bool bmcst = is_multicast_ether_addr(pattrib->ra);
 
        if (pattrib->psta) {
                psta = pattrib->psta;
index 3bea2e3..4199cb5 100644 (file)
@@ -148,8 +148,8 @@ struct xmit_frame {
        _pkt *pkt;
        int frame_tag;
        struct _adapter *padapter;
-        u8 *buf_addr;
-        struct xmit_buf *pxmitbuf;
+       u8 *buf_addr;
+       struct xmit_buf *pxmitbuf;
        u8 *mem_addr;
        u16 sz[8];
        struct urb *pxmit_urb[8];
index 45dbed1..d042d90 100644 (file)
@@ -119,8 +119,8 @@ static inline u32 wifi_mac_hash(u8 *mac)
        return x;
 }
 
-u32 _r8712_init_sta_priv(struct sta_priv *pstapriv);
-u32 _r8712_free_sta_priv(struct sta_priv *pstapriv);
+int _r8712_init_sta_priv(struct sta_priv *pstapriv);
+void _r8712_free_sta_priv(struct sta_priv *pstapriv);
 struct sta_info *r8712_alloc_stainfo(struct sta_priv *pstapriv,
                                     u8 *hwaddr);
 void r8712_free_stainfo(struct _adapter *padapter, struct sta_info *psta);
index 02e73c2..6cc4a70 100644 (file)
 #include "usb_ops.h"
 #include "usb_osintf.h"
 
-u8 r8712_usb_hal_bus_init(struct _adapter *padapter)
+u8 r8712_usb_hal_bus_init(struct _adapter *adapter)
 {
        u8 val8 = 0;
        u8 ret = _SUCCESS;
        int PollingCnt = 20;
-       struct registry_priv *pregistrypriv = &padapter->registrypriv;
+       struct registry_priv *registrypriv = &adapter->registrypriv;
 
-       if (pregistrypriv->chip_version == RTL8712_FPGA) {
+       if (registrypriv->chip_version == RTL8712_FPGA) {
                val8 = 0x01;
                /* switch to 80M clock */
-               r8712_write8(padapter, SYS_CLKR, val8);
-               val8 = r8712_read8(padapter, SPS1_CTRL);
+               r8712_write8(adapter, SYS_CLKR, val8);
+               val8 = r8712_read8(adapter, SPS1_CTRL);
                val8 = val8 | 0x01;
                /* enable VSPS12 LDO Macro block */
-               r8712_write8(padapter, SPS1_CTRL, val8);
-               val8 = r8712_read8(padapter, AFE_MISC);
+               r8712_write8(adapter, SPS1_CTRL, val8);
+               val8 = r8712_read8(adapter, AFE_MISC);
                val8 = val8 | 0x01;
                /* Enable AFE Macro Block's Bandgap */
-               r8712_write8(padapter, AFE_MISC, val8);
-               val8 = r8712_read8(padapter, LDOA15_CTRL);
+               r8712_write8(adapter, AFE_MISC, val8);
+               val8 = r8712_read8(adapter, LDOA15_CTRL);
                val8 = val8 | 0x01;
                /* enable LDOA15 block */
-               r8712_write8(padapter, LDOA15_CTRL, val8);
-               val8 = r8712_read8(padapter, SPS1_CTRL);
+               r8712_write8(adapter, LDOA15_CTRL, val8);
+               val8 = r8712_read8(adapter, SPS1_CTRL);
                val8 = val8 | 0x02;
                /* Enable VSPS12_SW Macro Block */
-               r8712_write8(padapter, SPS1_CTRL, val8);
-               val8 = r8712_read8(padapter, AFE_MISC);
+               r8712_write8(adapter, SPS1_CTRL, val8);
+               val8 = r8712_read8(adapter, AFE_MISC);
                val8 = val8 | 0x02;
                /* Enable AFE Macro Block's Mbias */
-               r8712_write8(padapter, AFE_MISC, val8);
-               val8 = r8712_read8(padapter, SYS_ISO_CTRL + 1);
+               r8712_write8(adapter, AFE_MISC, val8);
+               val8 = r8712_read8(adapter, SYS_ISO_CTRL + 1);
                val8 = val8 | 0x08;
                /* isolate PCIe Analog 1.2V to PCIe 3.3V and PCIE Digital */
-               r8712_write8(padapter, SYS_ISO_CTRL + 1, val8);
-               val8 = r8712_read8(padapter, SYS_ISO_CTRL + 1);
+               r8712_write8(adapter, SYS_ISO_CTRL + 1, val8);
+               val8 = r8712_read8(adapter, SYS_ISO_CTRL + 1);
                val8 = val8 & 0xEF;
                /* attatch AFE PLL to MACTOP/BB/PCIe Digital */
-               r8712_write8(padapter, SYS_ISO_CTRL + 1, val8);
-               val8 = r8712_read8(padapter, AFE_XTAL_CTRL + 1);
+               r8712_write8(adapter, SYS_ISO_CTRL + 1, val8);
+               val8 = r8712_read8(adapter, AFE_XTAL_CTRL + 1);
                val8 = val8 & 0xFB;
                /* enable AFE clock */
-               r8712_write8(padapter, AFE_XTAL_CTRL + 1, val8);
-               val8 = r8712_read8(padapter, AFE_PLL_CTRL);
+               r8712_write8(adapter, AFE_XTAL_CTRL + 1, val8);
+               val8 = r8712_read8(adapter, AFE_PLL_CTRL);
                val8 = val8 | 0x01;
                /* Enable AFE PLL Macro Block */
-               r8712_write8(padapter, AFE_PLL_CTRL, val8);
+               r8712_write8(adapter, AFE_PLL_CTRL, val8);
                val8 = 0xEE;
                /* release isolation AFE PLL & MD */
-               r8712_write8(padapter, SYS_ISO_CTRL, val8);
-               val8 = r8712_read8(padapter, SYS_CLKR + 1);
+               r8712_write8(adapter, SYS_ISO_CTRL, val8);
+               val8 = r8712_read8(adapter, SYS_CLKR + 1);
                val8 = val8 | 0x08;
                /* enable MAC clock */
-               r8712_write8(padapter, SYS_CLKR + 1, val8);
-               val8 = r8712_read8(padapter, SYS_FUNC_EN + 1);
+               r8712_write8(adapter, SYS_CLKR + 1, val8);
+               val8 = r8712_read8(adapter, SYS_FUNC_EN + 1);
                val8 = val8 | 0x08;
                /* enable Core digital and enable IOREG R/W */
-               r8712_write8(padapter, SYS_FUNC_EN + 1, val8);
+               r8712_write8(adapter, SYS_FUNC_EN + 1, val8);
                val8 = val8 | 0x80;
                /* enable REG_EN */
-               r8712_write8(padapter, SYS_FUNC_EN + 1, val8);
-               val8 = r8712_read8(padapter, SYS_CLKR + 1);
+               r8712_write8(adapter, SYS_FUNC_EN + 1, val8);
+               val8 = r8712_read8(adapter, SYS_CLKR + 1);
                val8 = (val8 | 0x80) & 0xBF;
                /* switch the control path */
-               r8712_write8(padapter, SYS_CLKR + 1, val8);
+               r8712_write8(adapter, SYS_CLKR + 1, val8);
                val8 = 0xFC;
-               r8712_write8(padapter, CR, val8);
+               r8712_write8(adapter, CR, val8);
                val8 = 0x37;
-               r8712_write8(padapter, CR + 1, val8);
+               r8712_write8(adapter, CR + 1, val8);
                /* reduce EndPoint & init it */
-               r8712_write8(padapter, 0x102500ab, r8712_read8(padapter,
+               r8712_write8(adapter, 0x102500ab, r8712_read8(adapter,
                             0x102500ab) | BIT(6) | BIT(7));
                /* consideration of power consumption - init */
-               r8712_write8(padapter, 0x10250008, r8712_read8(padapter,
+               r8712_write8(adapter, 0x10250008, r8712_read8(adapter,
                             0x10250008) & 0xfffffffb);
-       } else if (pregistrypriv->chip_version == RTL8712_1stCUT) {
+       } else if (registrypriv->chip_version == RTL8712_1stCUT) {
                /* Initialization for power on sequence, */
-               r8712_write8(padapter, SPS0_CTRL + 1, 0x53);
-               r8712_write8(padapter, SPS0_CTRL, 0x57);
+               r8712_write8(adapter, SPS0_CTRL + 1, 0x53);
+               r8712_write8(adapter, SPS0_CTRL, 0x57);
                /* Enable AFE Macro Block's Bandgap and Enable AFE Macro
                 * Block's Mbias
                 */
-               val8 = r8712_read8(padapter, AFE_MISC);
-               r8712_write8(padapter, AFE_MISC, (val8 | AFE_MISC_BGEN |
+               val8 = r8712_read8(adapter, AFE_MISC);
+               r8712_write8(adapter, AFE_MISC, (val8 | AFE_MISC_BGEN |
                             AFE_MISC_MBEN));
                /* Enable LDOA15 block */
-               val8 = r8712_read8(padapter, LDOA15_CTRL);
-               r8712_write8(padapter, LDOA15_CTRL, (val8 | LDA15_EN));
-               val8 = r8712_read8(padapter, SPS1_CTRL);
-               r8712_write8(padapter, SPS1_CTRL, (val8 | SPS1_LDEN));
+               val8 = r8712_read8(adapter, LDOA15_CTRL);
+               r8712_write8(adapter, LDOA15_CTRL, (val8 | LDA15_EN));
+               val8 = r8712_read8(adapter, SPS1_CTRL);
+               r8712_write8(adapter, SPS1_CTRL, (val8 | SPS1_LDEN));
                msleep(20);
                /* Enable Switch Regulator Block */
-               val8 = r8712_read8(padapter, SPS1_CTRL);
-               r8712_write8(padapter, SPS1_CTRL, (val8 | SPS1_SWEN));
-               r8712_write32(padapter, SPS1_CTRL, 0x00a7b267);
-               val8 = r8712_read8(padapter, SYS_ISO_CTRL + 1);
-               r8712_write8(padapter, SYS_ISO_CTRL + 1, (val8 | 0x08));
+               val8 = r8712_read8(adapter, SPS1_CTRL);
+               r8712_write8(adapter, SPS1_CTRL, (val8 | SPS1_SWEN));
+               r8712_write32(adapter, SPS1_CTRL, 0x00a7b267);
+               val8 = r8712_read8(adapter, SYS_ISO_CTRL + 1);
+               r8712_write8(adapter, SYS_ISO_CTRL + 1, (val8 | 0x08));
                /* Engineer Packet CP test Enable */
-               val8 = r8712_read8(padapter, SYS_FUNC_EN + 1);
-               r8712_write8(padapter, SYS_FUNC_EN + 1, (val8 | 0x20));
-               val8 = r8712_read8(padapter, SYS_ISO_CTRL + 1);
-               r8712_write8(padapter, SYS_ISO_CTRL + 1, (val8 & 0x6F));
+               val8 = r8712_read8(adapter, SYS_FUNC_EN + 1);
+               r8712_write8(adapter, SYS_FUNC_EN + 1, (val8 | 0x20));
+               val8 = r8712_read8(adapter, SYS_ISO_CTRL + 1);
+               r8712_write8(adapter, SYS_ISO_CTRL + 1, (val8 & 0x6F));
                /* Enable AFE clock */
-               val8 = r8712_read8(padapter, AFE_XTAL_CTRL + 1);
-               r8712_write8(padapter, AFE_XTAL_CTRL + 1, (val8 & 0xfb));
+               val8 = r8712_read8(adapter, AFE_XTAL_CTRL + 1);
+               r8712_write8(adapter, AFE_XTAL_CTRL + 1, (val8 & 0xfb));
                /* Enable AFE PLL Macro Block */
-               val8 = r8712_read8(padapter, AFE_PLL_CTRL);
-               r8712_write8(padapter, AFE_PLL_CTRL, (val8 | 0x11));
+               val8 = r8712_read8(adapter, AFE_PLL_CTRL);
+               r8712_write8(adapter, AFE_PLL_CTRL, (val8 | 0x11));
                /* Attach AFE PLL to MACTOP/BB/PCIe Digital */
-               val8 = r8712_read8(padapter, SYS_ISO_CTRL);
-               r8712_write8(padapter, SYS_ISO_CTRL, (val8 & 0xEE));
+               val8 = r8712_read8(adapter, SYS_ISO_CTRL);
+               r8712_write8(adapter, SYS_ISO_CTRL, (val8 & 0xEE));
                /* Switch to 40M clock */
-               val8 = r8712_read8(padapter, SYS_CLKR);
-               r8712_write8(padapter, SYS_CLKR, val8 & (~SYS_CLKSEL));
+               val8 = r8712_read8(adapter, SYS_CLKR);
+               r8712_write8(adapter, SYS_CLKR, val8 & (~SYS_CLKSEL));
                /* SSC Disable */
-               val8 = r8712_read8(padapter, SYS_CLKR);
+               val8 = r8712_read8(adapter, SYS_CLKR);
                /* Enable MAC clock */
-               val8 = r8712_read8(padapter, SYS_CLKR + 1);
-               r8712_write8(padapter, SYS_CLKR + 1, (val8 | 0x18));
+               val8 = r8712_read8(adapter, SYS_CLKR + 1);
+               r8712_write8(adapter, SYS_CLKR + 1, (val8 | 0x18));
                /* Revised POS, */
-               r8712_write8(padapter, PMC_FSM, 0x02);
+               r8712_write8(adapter, PMC_FSM, 0x02);
                /* Enable Core digital and enable IOREG R/W */
-               val8 = r8712_read8(padapter, SYS_FUNC_EN + 1);
-               r8712_write8(padapter, SYS_FUNC_EN + 1, (val8 | 0x08));
+               val8 = r8712_read8(adapter, SYS_FUNC_EN + 1);
+               r8712_write8(adapter, SYS_FUNC_EN + 1, (val8 | 0x08));
                /* Enable REG_EN */
-               val8 = r8712_read8(padapter, SYS_FUNC_EN + 1);
-               r8712_write8(padapter, SYS_FUNC_EN + 1, (val8 | 0x80));
+               val8 = r8712_read8(adapter, SYS_FUNC_EN + 1);
+               r8712_write8(adapter, SYS_FUNC_EN + 1, (val8 | 0x80));
                /* Switch the control path to FW */
-               val8 = r8712_read8(padapter, SYS_CLKR + 1);
-               r8712_write8(padapter, SYS_CLKR + 1, (val8 | 0x80) & 0xBF);
-               r8712_write8(padapter, CR, 0xFC);
-               r8712_write8(padapter, CR + 1, 0x37);
+               val8 = r8712_read8(adapter, SYS_CLKR + 1);
+               r8712_write8(adapter, SYS_CLKR + 1, (val8 | 0x80) & 0xBF);
+               r8712_write8(adapter, CR, 0xFC);
+               r8712_write8(adapter, CR + 1, 0x37);
                /* Fix the RX FIFO issue(usb error), */
-               val8 = r8712_read8(padapter, 0x1025FE5c);
-               r8712_write8(padapter, 0x1025FE5c, (val8 | BIT(7)));
-               val8 = r8712_read8(padapter, 0x102500ab);
-               r8712_write8(padapter, 0x102500ab, (val8 | BIT(6) | BIT(7)));
+               val8 = r8712_read8(adapter, 0x1025FE5c);
+               r8712_write8(adapter, 0x1025FE5c, (val8 | BIT(7)));
+               val8 = r8712_read8(adapter, 0x102500ab);
+               r8712_write8(adapter, 0x102500ab, (val8 | BIT(6) | BIT(7)));
                /* For power save, used this in the bit file after 970621 */
-               val8 = r8712_read8(padapter, SYS_CLKR);
-               r8712_write8(padapter, SYS_CLKR, val8 & (~CPU_CLKSEL));
-       } else if (pregistrypriv->chip_version == RTL8712_2ndCUT ||
-                 pregistrypriv->chip_version == RTL8712_3rdCUT) {
+               val8 = r8712_read8(adapter, SYS_CLKR);
+               r8712_write8(adapter, SYS_CLKR, val8 & (~CPU_CLKSEL));
+       } else if (registrypriv->chip_version == RTL8712_2ndCUT ||
+                  registrypriv->chip_version == RTL8712_3rdCUT) {
                /* Initialization for power on sequence,
                 * E-Fuse leakage prevention sequence
                 */
-               r8712_write8(padapter, 0x37, 0xb0);
+               r8712_write8(adapter, 0x37, 0xb0);
                msleep(20);
-               r8712_write8(padapter, 0x37, 0x30);
+               r8712_write8(adapter, 0x37, 0x30);
                /* Set control path switch to HW control and reset Digital Core,
                 * CPU Core and MAC I/O to solve FW download fail when system
                 * from resume sate.
                 */
-               val8 = r8712_read8(padapter, SYS_CLKR + 1);
+               val8 = r8712_read8(adapter, SYS_CLKR + 1);
                if (val8 & 0x80) {
                        val8 &= 0x3f;
-                       r8712_write8(padapter, SYS_CLKR + 1, val8);
+                       r8712_write8(adapter, SYS_CLKR + 1, val8);
                }
-               val8 = r8712_read8(padapter, SYS_FUNC_EN + 1);
+               val8 = r8712_read8(adapter, SYS_FUNC_EN + 1);
                val8 &= 0x73;
-               r8712_write8(padapter, SYS_FUNC_EN + 1, val8);
+               r8712_write8(adapter, SYS_FUNC_EN + 1, val8);
                msleep(20);
                /* Revised POS, */
                /* Enable AFE Macro Block's Bandgap and Enable AFE Macro
                 * Block's Mbias
                 */
-               r8712_write8(padapter, SPS0_CTRL + 1, 0x53);
-               r8712_write8(padapter, SPS0_CTRL, 0x57);
-               val8 = r8712_read8(padapter, AFE_MISC);
+               r8712_write8(adapter, SPS0_CTRL + 1, 0x53);
+               r8712_write8(adapter, SPS0_CTRL, 0x57);
+               val8 = r8712_read8(adapter, AFE_MISC);
                /*Bandgap*/
-               r8712_write8(padapter, AFE_MISC, (val8 | AFE_MISC_BGEN));
-               r8712_write8(padapter, AFE_MISC, (val8 | AFE_MISC_BGEN |
+               r8712_write8(adapter, AFE_MISC, (val8 | AFE_MISC_BGEN));
+               r8712_write8(adapter, AFE_MISC, (val8 | AFE_MISC_BGEN |
                             AFE_MISC_MBEN | AFE_MISC_I32_EN));
                /* Enable PLL Power (LDOA15V) */
-               val8 = r8712_read8(padapter, LDOA15_CTRL);
-               r8712_write8(padapter, LDOA15_CTRL, (val8 | LDA15_EN));
+               val8 = r8712_read8(adapter, LDOA15_CTRL);
+               r8712_write8(adapter, LDOA15_CTRL, (val8 | LDA15_EN));
                /* Enable LDOV12D block */
-               val8 = r8712_read8(padapter, LDOV12D_CTRL);
-               r8712_write8(padapter, LDOV12D_CTRL, (val8 | LDV12_EN));
-               val8 = r8712_read8(padapter, SYS_ISO_CTRL + 1);
-               r8712_write8(padapter, SYS_ISO_CTRL + 1, (val8 | 0x08));
+               val8 = r8712_read8(adapter, LDOV12D_CTRL);
+               r8712_write8(adapter, LDOV12D_CTRL, (val8 | LDV12_EN));
+               val8 = r8712_read8(adapter, SYS_ISO_CTRL + 1);
+               r8712_write8(adapter, SYS_ISO_CTRL + 1, (val8 | 0x08));
                /* Engineer Packet CP test Enable */
-               val8 = r8712_read8(padapter, SYS_FUNC_EN + 1);
-               r8712_write8(padapter, SYS_FUNC_EN + 1, (val8 | 0x20));
+               val8 = r8712_read8(adapter, SYS_FUNC_EN + 1);
+               r8712_write8(adapter, SYS_FUNC_EN + 1, (val8 | 0x20));
                /* Support 64k IMEM */
-               val8 = r8712_read8(padapter, SYS_ISO_CTRL + 1);
-               r8712_write8(padapter, SYS_ISO_CTRL + 1, (val8 & 0x68));
+               val8 = r8712_read8(adapter, SYS_ISO_CTRL + 1);
+               r8712_write8(adapter, SYS_ISO_CTRL + 1, (val8 & 0x68));
                /* Enable AFE clock */
-               val8 = r8712_read8(padapter, AFE_XTAL_CTRL + 1);
-               r8712_write8(padapter, AFE_XTAL_CTRL + 1, (val8 & 0xfb));
+               val8 = r8712_read8(adapter, AFE_XTAL_CTRL + 1);
+               r8712_write8(adapter, AFE_XTAL_CTRL + 1, (val8 & 0xfb));
                /* Enable AFE PLL Macro Block */
-               val8 = r8712_read8(padapter, AFE_PLL_CTRL);
-               r8712_write8(padapter, AFE_PLL_CTRL, (val8 | 0x11));
+               val8 = r8712_read8(adapter, AFE_PLL_CTRL);
+               r8712_write8(adapter, AFE_PLL_CTRL, (val8 | 0x11));
                /* Some sample will download fw failure. The clock will be
                 * stable with 500 us delay after reset the PLL
                 * TODO: When usleep is added to kernel, change next 3
                 * udelay(500) to usleep(500)
                 */
                udelay(500);
-               r8712_write8(padapter, AFE_PLL_CTRL, (val8 | 0x51));
+               r8712_write8(adapter, AFE_PLL_CTRL, (val8 | 0x51));
                udelay(500);
-               r8712_write8(padapter, AFE_PLL_CTRL, (val8 | 0x11));
+               r8712_write8(adapter, AFE_PLL_CTRL, (val8 | 0x11));
                udelay(500);
                /* Attach AFE PLL to MACTOP/BB/PCIe Digital */
-               val8 = r8712_read8(padapter, SYS_ISO_CTRL);
-               r8712_write8(padapter, SYS_ISO_CTRL, (val8 & 0xEE));
+               val8 = r8712_read8(adapter, SYS_ISO_CTRL);
+               r8712_write8(adapter, SYS_ISO_CTRL, (val8 & 0xEE));
                /* Switch to 40M clock */
-               r8712_write8(padapter, SYS_CLKR, 0x00);
+               r8712_write8(adapter, SYS_CLKR, 0x00);
                /* CPU Clock and 80M Clock SSC Disable to overcome FW download
                 * fail timing issue.
                 */
-               val8 = r8712_read8(padapter, SYS_CLKR);
-               r8712_write8(padapter, SYS_CLKR, (val8 | 0xa0));
+               val8 = r8712_read8(adapter, SYS_CLKR);
+               r8712_write8(adapter, SYS_CLKR, (val8 | 0xa0));
                /* Enable MAC clock */
-               val8 = r8712_read8(padapter, SYS_CLKR + 1);
-               r8712_write8(padapter, SYS_CLKR + 1, (val8 | 0x18));
+               val8 = r8712_read8(adapter, SYS_CLKR + 1);
+               r8712_write8(adapter, SYS_CLKR + 1, (val8 | 0x18));
                /* Revised POS, */
-               r8712_write8(padapter, PMC_FSM, 0x02);
+               r8712_write8(adapter, PMC_FSM, 0x02);
                /* Enable Core digital and enable IOREG R/W */
-               val8 = r8712_read8(padapter, SYS_FUNC_EN + 1);
-               r8712_write8(padapter, SYS_FUNC_EN + 1, (val8 | 0x08));
+               val8 = r8712_read8(adapter, SYS_FUNC_EN + 1);
+               r8712_write8(adapter, SYS_FUNC_EN + 1, (val8 | 0x08));
                /* Enable REG_EN */
-               val8 = r8712_read8(padapter, SYS_FUNC_EN + 1);
-               r8712_write8(padapter, SYS_FUNC_EN + 1, (val8 | 0x80));
+               val8 = r8712_read8(adapter, SYS_FUNC_EN + 1);
+               r8712_write8(adapter, SYS_FUNC_EN + 1, (val8 | 0x80));
                /* Switch the control path to FW */
-               val8 = r8712_read8(padapter, SYS_CLKR + 1);
-               r8712_write8(padapter, SYS_CLKR + 1, (val8 | 0x80) & 0xBF);
-               r8712_write8(padapter, CR, 0xFC);
-               r8712_write8(padapter, CR + 1, 0x37);
+               val8 = r8712_read8(adapter, SYS_CLKR + 1);
+               r8712_write8(adapter, SYS_CLKR + 1, (val8 | 0x80) & 0xBF);
+               r8712_write8(adapter, CR, 0xFC);
+               r8712_write8(adapter, CR + 1, 0x37);
                /* Fix the RX FIFO issue(usb error), 970410 */
-               val8 = r8712_read8(padapter, 0x1025FE5c);
-               r8712_write8(padapter, 0x1025FE5c, (val8 | BIT(7)));
+               val8 = r8712_read8(adapter, 0x1025FE5c);
+               r8712_write8(adapter, 0x1025FE5c, (val8 | BIT(7)));
                /* For power save, used this in the bit file after 970621 */
-               val8 = r8712_read8(padapter, SYS_CLKR);
-               r8712_write8(padapter, SYS_CLKR, val8 & (~CPU_CLKSEL));
+               val8 = r8712_read8(adapter, SYS_CLKR);
+               r8712_write8(adapter, SYS_CLKR, val8 & (~CPU_CLKSEL));
                /* Revised for 8051 ROM code wrong operation. */
-               r8712_write8(padapter, 0x1025fe1c, 0x80);
+               r8712_write8(adapter, 0x1025fe1c, 0x80);
                /* To make sure that TxDMA can ready to download FW.
                 * We should reset TxDMA if IMEM RPT was not ready.
                 */
                do {
-                       val8 = r8712_read8(padapter, TCR);
+                       val8 = r8712_read8(adapter, TCR);
                        if ((val8 & _TXDMA_INIT_VALUE) == _TXDMA_INIT_VALUE)
                                break;
                        udelay(5); /* PlatformStallExecution(5); */
                } while (PollingCnt--); /* Delay 1ms */
 
                if (PollingCnt <= 0) {
-                       val8 = r8712_read8(padapter, CR);
-                       r8712_write8(padapter, CR, val8 & (~_TXDMA_EN));
+                       val8 = r8712_read8(adapter, CR);
+                       r8712_write8(adapter, CR, val8 & (~_TXDMA_EN));
                        udelay(2); /* PlatformStallExecution(2); */
                        /* Reset TxDMA */
-                       r8712_write8(padapter, CR, val8 | _TXDMA_EN);
+                       r8712_write8(adapter, CR, val8 | _TXDMA_EN);
                }
        } else {
                ret = _FAIL;
@@ -280,28 +280,28 @@ u8 r8712_usb_hal_bus_init(struct _adapter *padapter)
        return ret;
 }
 
-unsigned int r8712_usb_inirp_init(struct _adapter *padapter)
+unsigned int r8712_usb_inirp_init(struct _adapter *adapter)
 {
        u8 i;
-       struct recv_buf *precvbuf;
-       struct intf_hdl *pintfhdl = &padapter->pio_queue->intf;
-       struct recv_priv *precvpriv = &(padapter->recvpriv);
+       struct recv_buf *recvbuf;
+       struct intf_hdl *intfhdl = &adapter->pio_queue->intf;
+       struct recv_priv *recvpriv = &(adapter->recvpriv);
 
-       precvpriv->ff_hwaddr = RTL8712_DMA_RX0FF; /* mapping rx fifo address */
+       recvpriv->ff_hwaddr = RTL8712_DMA_RX0FF; /* mapping rx fifo address */
        /* issue Rx irp to receive data */
-       precvbuf = (struct recv_buf *)precvpriv->precv_buf;
+       recvbuf = (struct recv_buf *)recvpriv->precv_buf;
        for (i = 0; i < NR_RECVBUFF; i++) {
-               if (r8712_usb_read_port(pintfhdl, precvpriv->ff_hwaddr, 0,
-                  (unsigned char *)precvbuf) == false)
+               if (r8712_usb_read_port(intfhdl, recvpriv->ff_hwaddr, 0,
+                                       (unsigned char *)recvbuf) == false)
                        return _FAIL;
-               precvbuf++;
-               precvpriv->free_recv_buf_queue_cnt--;
+               recvbuf++;
+               recvpriv->free_recv_buf_queue_cnt--;
        }
        return _SUCCESS;
 }
 
-unsigned int r8712_usb_inirp_deinit(struct _adapter *padapter)
+unsigned int r8712_usb_inirp_deinit(struct _adapter *adapter)
 {
-       r8712_usb_read_port_cancel(padapter);
+       r8712_usb_read_port_cancel(adapter);
        return _SUCCESS;
 }
index 7478bbd..d0daae0 100644 (file)
@@ -246,7 +246,7 @@ static uint r8712_usb_dvobj_init(struct _adapter *padapter)
        struct usb_device *pusbd = pdvobjpriv->pusbdev;
 
        pdvobjpriv->padapter = padapter;
-       padapter->EepromAddressSize = 6;
+       padapter->eeprom_address_size = 6;
        phost_iface = &pintf->altsetting[0];
        piface_desc = &phost_iface->desc;
        pdvobjpriv->nr_endpoint = piface_desc->bNumEndpoints;
@@ -571,7 +571,7 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf,
        /* step 6. Load the firmware asynchronously */
        if (rtl871x_load_fw(padapter))
                goto error;
-       spin_lock_init(&padapter->lockRxFF0Filter);
+       spin_lock_init(&padapter->lock_rx_ff0_filter);
        mutex_init(&padapter->mutex_start);
        return 0;
 error:
index eef52d5..e64845e 100644 (file)
@@ -22,7 +22,7 @@
 #include "usb_ops.h"
 #include "recv_osdep.h"
 
-static u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr)
+static u8 usb_read8(struct intf_hdl *intfhdl, u32 addr)
 {
        u8 request;
        u8 requesttype;
@@ -30,19 +30,19 @@ static u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr)
        u16 index;
        u16 len;
        __le32 data;
-       struct intf_priv *pintfpriv = pintfhdl->pintfpriv;
+       struct intf_priv *intfpriv = intfhdl->pintfpriv;
 
        request = 0x05;
        requesttype = 0x01; /* read_in */
        index = 0;
        wvalue = (u16)(addr & 0x0000ffff);
        len = 1;
-       r8712_usbctrl_vendorreq(pintfpriv, request, wvalue, index, &data, len,
-                         requesttype);
+       r8712_usbctrl_vendorreq(intfpriv, request, wvalue, index, &data, len,
+                               requesttype);
        return (u8)(le32_to_cpu(data) & 0x0ff);
 }
 
-static u16 usb_read16(struct intf_hdl *pintfhdl, u32 addr)
+static u16 usb_read16(struct intf_hdl *intfhdl, u32 addr)
 {
        u8 request;
        u8 requesttype;
@@ -50,19 +50,19 @@ static u16 usb_read16(struct intf_hdl *pintfhdl, u32 addr)
        u16 index;
        u16 len;
        __le32 data;
-       struct intf_priv *pintfpriv = pintfhdl->pintfpriv;
+       struct intf_priv *intfpriv = intfhdl->pintfpriv;
 
        request = 0x05;
        requesttype = 0x01; /* read_in */
        index = 0;
        wvalue = (u16)(addr & 0x0000ffff);
        len = 2;
-       r8712_usbctrl_vendorreq(pintfpriv, request, wvalue, index, &data, len,
-                         requesttype);
+       r8712_usbctrl_vendorreq(intfpriv, request, wvalue, index, &data, len,
+                               requesttype);
        return (u16)(le32_to_cpu(data) & 0xffff);
 }
 
-static u32 usb_read32(struct intf_hdl *pintfhdl, u32 addr)
+static u32 usb_read32(struct intf_hdl *intfhdl, u32 addr)
 {
        u8 request;
        u8 requesttype;
@@ -70,19 +70,19 @@ static u32 usb_read32(struct intf_hdl *pintfhdl, u32 addr)
        u16 index;
        u16 len;
        __le32 data;
-       struct intf_priv *pintfpriv = pintfhdl->pintfpriv;
+       struct intf_priv *intfpriv = intfhdl->pintfpriv;
 
        request = 0x05;
        requesttype = 0x01; /* read_in */
        index = 0;
        wvalue = (u16)(addr & 0x0000ffff);
        len = 4;
-       r8712_usbctrl_vendorreq(pintfpriv, request, wvalue, index, &data, len,
-                         requesttype);
+       r8712_usbctrl_vendorreq(intfpriv, request, wvalue, index, &data, len,
+                               requesttype);
        return le32_to_cpu(data);
 }
 
-static void usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val)
+static void usb_write8(struct intf_hdl *intfhdl, u32 addr, u8 val)
 {
        u8 request;
        u8 requesttype;
@@ -90,7 +90,7 @@ static void usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val)
        u16 index;
        u16 len;
        __le32 data;
-       struct intf_priv *pintfpriv = pintfhdl->pintfpriv;
+       struct intf_priv *intfpriv = intfhdl->pintfpriv;
 
        request = 0x05;
        requesttype = 0x00; /* write_out */
@@ -98,11 +98,11 @@ static void usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val)
        wvalue = (u16)(addr & 0x0000ffff);
        len = 1;
        data = cpu_to_le32((u32)val & 0x000000ff);
-       r8712_usbctrl_vendorreq(pintfpriv, request, wvalue, index, &data, len,
-                         requesttype);
+       r8712_usbctrl_vendorreq(intfpriv, request, wvalue, index, &data, len,
+                               requesttype);
 }
 
-static void usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val)
+static void usb_write16(struct intf_hdl *intfhdl, u32 addr, u16 val)
 {
        u8 request;
        u8 requesttype;
@@ -110,7 +110,7 @@ static void usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val)
        u16 index;
        u16 len;
        __le32 data;
-       struct intf_priv *pintfpriv = pintfhdl->pintfpriv;
+       struct intf_priv *intfpriv = intfhdl->pintfpriv;
 
        request = 0x05;
        requesttype = 0x00; /* write_out */
@@ -118,11 +118,11 @@ static void usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val)
        wvalue = (u16)(addr & 0x0000ffff);
        len = 2;
        data = cpu_to_le32((u32)val & 0x0000ffff);
-       r8712_usbctrl_vendorreq(pintfpriv, request, wvalue, index, &data, len,
-                         requesttype);
+       r8712_usbctrl_vendorreq(intfpriv, request, wvalue, index, &data, len,
+                               requesttype);
 }
 
-static void usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val)
+static void usb_write32(struct intf_hdl *intfhdl, u32 addr, u32 val)
 {
        u8 request;
        u8 requesttype;
@@ -130,7 +130,7 @@ static void usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val)
        u16 index;
        u16 len;
        __le32 data;
-       struct intf_priv *pintfpriv = pintfhdl->pintfpriv;
+       struct intf_priv *intfpriv = intfhdl->pintfpriv;
 
        request = 0x05;
        requesttype = 0x00; /* write_out */
@@ -138,13 +138,13 @@ static void usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val)
        wvalue = (u16)(addr & 0x0000ffff);
        len = 4;
        data = cpu_to_le32(val);
-       r8712_usbctrl_vendorreq(pintfpriv, request, wvalue, index, &data, len,
-                         requesttype);
+       r8712_usbctrl_vendorreq(intfpriv, request, wvalue, index, &data, len,
+                               requesttype);
 }
 
-void r8712_usb_set_intf_option(u32 *poption)
+void r8712_usb_set_intf_option(u32 *option)
 {
-       *poption = ((*poption) | _INTF_ASYNC_);
+       *option = ((*option) | _INTF_ASYNC_);
 }
 
 static void usb_intf_hdl_init(u8 *priv)
@@ -163,24 +163,24 @@ static void usb_intf_hdl_close(u8 *priv)
 {
 }
 
-void r8712_usb_set_intf_funs(struct intf_hdl *pintf_hdl)
+void r8712_usb_set_intf_funs(struct intf_hdl *intfhdl)
 {
-       pintf_hdl->intf_hdl_init = usb_intf_hdl_init;
-       pintf_hdl->intf_hdl_unload = usb_intf_hdl_unload;
-       pintf_hdl->intf_hdl_open = usb_intf_hdl_open;
-       pintf_hdl->intf_hdl_close = usb_intf_hdl_close;
+       intfhdl->intf_hdl_init = usb_intf_hdl_init;
+       intfhdl->intf_hdl_unload = usb_intf_hdl_unload;
+       intfhdl->intf_hdl_open = usb_intf_hdl_open;
+       intfhdl->intf_hdl_close = usb_intf_hdl_close;
 }
 
-void r8712_usb_set_intf_ops(struct _io_ops     *pops)
+void r8712_usb_set_intf_ops(struct _io_ops *ops)
 {
-       memset((u8 *)pops, 0, sizeof(struct _io_ops));
-       pops->_read8 = usb_read8;
-       pops->_read16 = usb_read16;
-       pops->_read32 = usb_read32;
-       pops->_read_port = r8712_usb_read_port;
-       pops->_write8 = usb_write8;
-       pops->_write16 = usb_write16;
-       pops->_write32 = usb_write32;
-       pops->_write_mem = r8712_usb_write_mem;
-       pops->_write_port = r8712_usb_write_port;
+       memset((u8 *)ops, 0, sizeof(struct _io_ops));
+       ops->_read8 = usb_read8;
+       ops->_read16 = usb_read16;
+       ops->_read32 = usb_read32;
+       ops->_read_port = r8712_usb_read_port;
+       ops->_write8 = usb_write8;
+       ops->_write16 = usb_write16;
+       ops->_write32 = usb_write32;
+       ops->_write_mem = r8712_usb_write_mem;
+       ops->_write_port = r8712_usb_write_port;
 }
index 77346de..1a5b966 100644 (file)
@@ -278,17 +278,6 @@ static inline unsigned char get_tofr_ds(unsigned char *pframe)
 
 #define GetAddr4Ptr(pbuf)      ((unsigned char *)((addr_t)(pbuf) + 24))
 
-
-
-static inline int IS_MCAST(unsigned char *da)
-{
-       if ((*da) & 0x01)
-               return true;
-       else
-               return false;
-}
-
-
 static inline unsigned char *get_da(unsigned char *pframe)
 {
        unsigned char   *da;
index 8bcb077..01d713d 100644 (file)
@@ -93,22 +93,22 @@ void r8712_set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib)
 
 void r8712_SetFilter(struct work_struct *work)
 {
-       struct _adapter *padapter = container_of(work, struct _adapter,
-                                               wkFilterRxFF0);
+       struct _adapter *adapter = container_of(work, struct _adapter,
+                                               wk_filter_rx_ff0);
        u8  oldvalue = 0x00, newvalue = 0x00;
        unsigned long irqL;
 
-       oldvalue = r8712_read8(padapter, 0x117);
+       oldvalue = r8712_read8(adapter, 0x117);
        newvalue = oldvalue & 0xfe;
-       r8712_write8(padapter, 0x117, newvalue);
+       r8712_write8(adapter, 0x117, newvalue);
 
-       spin_lock_irqsave(&padapter->lockRxFF0Filter, irqL);
-       padapter->blnEnableRxFF0Filter = 1;
-       spin_unlock_irqrestore(&padapter->lockRxFF0Filter, irqL);
+       spin_lock_irqsave(&adapter->lock_rx_ff0_filter, irqL);
+       adapter->blnEnableRxFF0Filter = 1;
+       spin_unlock_irqrestore(&adapter->lock_rx_ff0_filter, irqL);
        do {
                msleep(100);
-       } while (padapter->blnEnableRxFF0Filter == 1);
-       r8712_write8(padapter, 0x117, oldvalue);
+       } while (adapter->blnEnableRxFF0Filter == 1);
+       r8712_write8(adapter, 0x117, oldvalue);
 }
 
 int r8712_xmit_resource_alloc(struct _adapter *padapter,
@@ -120,11 +120,11 @@ int r8712_xmit_resource_alloc(struct _adapter *padapter,
                pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
                if (!pxmitbuf->pxmit_urb[i]) {
                        netdev_err(padapter->pnetdev, "pxmitbuf->pxmit_urb[i] == NULL\n");
-                       return _FAIL;
+                       return -ENOMEM;
                }
                kmemleak_not_leak(pxmitbuf->pxmit_urb[i]);
        }
-       return _SUCCESS;
+       return 0;
 }
 
 void r8712_xmit_resource_free(struct _adapter *padapter,
@@ -147,36 +147,36 @@ void r8712_xmit_complete(struct _adapter *padapter, struct xmit_frame *pxframe)
        pxframe->pkt = NULL;
 }
 
-int r8712_xmit_entry(_pkt *pkt, struct  net_device *pnetdev)
+int r8712_xmit_entry(_pkt *pkt, struct  net_device *netdev)
 {
-       struct xmit_frame *pxmitframe = NULL;
-       struct _adapter *padapter = netdev_priv(pnetdev);
-       struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+       struct xmit_frame *xmitframe = NULL;
+       struct _adapter *adapter = netdev_priv(netdev);
+       struct xmit_priv *xmitpriv = &(adapter->xmitpriv);
 
-       if (!r8712_if_up(padapter))
+       if (!r8712_if_up(adapter))
                goto _xmit_entry_drop;
 
-       pxmitframe = r8712_alloc_xmitframe(pxmitpriv);
-       if (!pxmitframe)
+       xmitframe = r8712_alloc_xmitframe(xmitpriv);
+       if (!xmitframe)
                goto _xmit_entry_drop;
 
-       if ((!r8712_update_attrib(padapter, pkt, &pxmitframe->attrib)))
+       if ((!r8712_update_attrib(adapter, pkt, &xmitframe->attrib)))
                goto _xmit_entry_drop;
 
-       padapter->ledpriv.LedControlHandler(padapter, LED_CTL_TX);
-       pxmitframe->pkt = pkt;
-       if (r8712_pre_xmit(padapter, pxmitframe)) {
+       adapter->ledpriv.LedControlHandler(adapter, LED_CTL_TX);
+       xmitframe->pkt = pkt;
+       if (r8712_pre_xmit(adapter, xmitframe)) {
                /*dump xmitframe directly or drop xframe*/
                dev_kfree_skb_any(pkt);
-               pxmitframe->pkt = NULL;
+               xmitframe->pkt = NULL;
        }
-       pxmitpriv->tx_pkts++;
-       pxmitpriv->tx_bytes += pxmitframe->attrib.last_txcmdsz;
+       xmitpriv->tx_pkts++;
+       xmitpriv->tx_bytes += xmitframe->attrib.last_txcmdsz;
        return 0;
 _xmit_entry_drop:
-       if (pxmitframe)
-               r8712_free_xmitframe(pxmitpriv, pxmitframe);
-       pxmitpriv->tx_drop++;
+       if (xmitframe)
+               r8712_free_xmitframe(xmitpriv, xmitframe);
+       xmitpriv->tx_drop++;
        dev_kfree_skb_any(pkt);
        return 0;
 }
index 744091d..a884673 100644 (file)
@@ -5,7 +5,7 @@ config RTL8723BS
        depends on m
        select WIRELESS_EXT
        select WEXT_PRIV
-       ---help---
+       help
        This option enables support for RTL8723BS SDIO drivers, such as
        the wifi found on the 1st gen Intel Compute Stick, the CHIP
        and many other Intel Atom and ARM based devices.
index 58e02f9..45065fd 100644 (file)
@@ -12,5 +12,4 @@ TODO:
 - switch to use MAC80211
 
 Please send any patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
-Bastien Nocera <hadess@hadess.net>, Hans de Goede <hdegoede@redhat.com>
-and Larry Finger <Larry.Finger@lwfinger.net>.
+Hans de Goede <hdegoede@redhat.com> and Larry Finger <Larry.Finger@lwfinger.net>.
index bc02306..7bd5c61 100644 (file)
@@ -443,7 +443,7 @@ void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level)
        }
 
        psta->wireless_mode = sta_band;
-       psta->raid = rtw_hal_networktype_to_raid(padapter, psta);
+       psta->raid = networktype_to_raid_ex(padapter, psta);
 
        if (psta->aid < NUM_STA) {
                u8 arg[4] = {0};
@@ -512,7 +512,7 @@ void update_bmc_sta(struct adapter *padapter)
                rtw_hal_update_sta_rate_mask(padapter, psta);
                tx_ra_bitmap = psta->ra_mask;
 
-               psta->raid = rtw_hal_networktype_to_raid(padapter, psta);
+               psta->raid = networktype_to_raid_ex(padapter, psta);
 
                /* ap mode */
                rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true);
@@ -1394,10 +1394,9 @@ int rtw_acl_add_sta(struct adapter *padapter, u8 *addr)
        return ret;
 }
 
-int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr)
+void rtw_acl_remove_sta(struct adapter *padapter, u8 *addr)
 {
        struct list_head        *plist, *phead;
-       int ret = 0;
        struct rtw_wlan_acl_node *paclnode;
        struct sta_priv *pstapriv = &padapter->stapriv;
        struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
@@ -1438,7 +1437,6 @@ int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr)
 
        DBG_871X("%s, acl_num =%d\n", __func__, pacl_list->num);
 
-       return ret;
 }
 
 u8 rtw_ap_set_pairwise_key(struct adapter *padapter, struct sta_info *psta)
@@ -1504,8 +1502,6 @@ static int rtw_ap_set_key(
                goto exit;
        }
 
-       memset(psetkeyparm, 0, sizeof(struct setkey_parm));
-
        psetkeyparm->keyid = (u8)keyid;
        if (is_wep_enc(alg))
                padapter->securitypriv.key_mask |= BIT(psetkeyparm->keyid);
@@ -1914,7 +1910,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;
@@ -2072,7 +2068,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_871X("%s, updated =%d\n", __func__, beacon_updated);
@@ -2136,7 +2132,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. */
        /* associated_clients_update(padapter,  beacon_updated); //move it to avoid deadlock */
 
        DBG_871X("%s, updated =%d\n", __func__, beacon_updated);
@@ -2156,7 +2152,7 @@ u8 ap_free_sta(
        if (!psta)
                return beacon_updated;
 
-       if (active == true) {
+       if (active) {
                /* tear down Rx AMPDU */
                send_delba(padapter, 0, psta->hwaddr);/*  recipient */
 
@@ -2189,10 +2185,9 @@ u8 ap_free_sta(
        return beacon_updated;
 }
 
-int rtw_sta_flush(struct adapter *padapter)
+void rtw_sta_flush(struct adapter *padapter)
 {
        struct list_head        *phead, *plist;
-       int ret = 0;
        struct sta_info *psta = NULL;
        struct sta_priv *pstapriv = &padapter->stapriv;
        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
@@ -2202,7 +2197,7 @@ int rtw_sta_flush(struct adapter *padapter)
        DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev));
 
        if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
-               return ret;
+               return;
 
        spin_lock_bh(&pstapriv->asoc_list_lock);
        phead = &pstapriv->asoc_list;
@@ -2226,8 +2221,6 @@ int rtw_sta_flush(struct adapter *padapter)
        issue_deauth(padapter, bc_addr, WLAN_REASON_DEAUTH_LEAVING);
 
        associated_clients_update(padapter, true);
-
-       return ret;
 }
 
 /* called > TSR LEVEL for USB or SDIO Interface*/
index 35310e8..44219b7 100644 (file)
@@ -9,42 +9,6 @@
 #include <rtw_btcoex.h>
 #include <hal_btcoex.h>
 
-
-void rtw_btcoex_Initialize(struct adapter *padapter)
-{
-       hal_btcoex_Initialize(padapter);
-}
-
-void rtw_btcoex_PowerOnSetting(struct adapter *padapter)
-{
-       hal_btcoex_PowerOnSetting(padapter);
-}
-
-void rtw_btcoex_HAL_Initialize(struct adapter *padapter, u8 bWifiOnly)
-{
-       hal_btcoex_InitHwConfig(padapter, bWifiOnly);
-}
-
-void rtw_btcoex_IpsNotify(struct adapter *padapter, u8 type)
-{
-       hal_btcoex_IpsNotify(padapter, type);
-}
-
-void rtw_btcoex_LpsNotify(struct adapter *padapter, u8 type)
-{
-       hal_btcoex_LpsNotify(padapter, type);
-}
-
-void rtw_btcoex_ScanNotify(struct adapter *padapter, u8 type)
-{
-       hal_btcoex_ScanNotify(padapter, type);
-}
-
-void rtw_btcoex_ConnectNotify(struct adapter *padapter, u8 action)
-{
-       hal_btcoex_ConnectNotify(padapter, action);
-}
-
 void rtw_btcoex_MediaStatusNotify(struct adapter *padapter, u8 mediaStatus)
 {
        if ((mediaStatus == RT_MEDIA_CONNECT)
@@ -55,26 +19,6 @@ void rtw_btcoex_MediaStatusNotify(struct adapter *padapter, u8 mediaStatus)
        hal_btcoex_MediaStatusNotify(padapter, mediaStatus);
 }
 
-void rtw_btcoex_SpecialPacketNotify(struct adapter *padapter, u8 pktType)
-{
-       hal_btcoex_SpecialPacketNotify(padapter, pktType);
-}
-
-void rtw_btcoex_IQKNotify(struct adapter *padapter, u8 state)
-{
-       hal_btcoex_IQKNotify(padapter, state);
-}
-
-void rtw_btcoex_BtInfoNotify(struct adapter *padapter, u8 length, u8 *tmpBuf)
-{
-       hal_btcoex_BtInfoNotify(padapter, length, tmpBuf);
-}
-
-void rtw_btcoex_SuspendNotify(struct adapter *padapter, u8 state)
-{
-       hal_btcoex_SuspendNotify(padapter, state);
-}
-
 void rtw_btcoex_HaltNotify(struct adapter *padapter)
 {
        if (!padapter->bup) {
@@ -94,95 +38,6 @@ void rtw_btcoex_HaltNotify(struct adapter *padapter)
        hal_btcoex_HaltNotify(padapter);
 }
 
-u8 rtw_btcoex_IsBtDisabled(struct adapter *padapter)
-{
-       return hal_btcoex_IsBtDisabled(padapter);
-}
-
-void rtw_btcoex_Handler(struct adapter *padapter)
-{
-       hal_btcoex_Hanlder(padapter);
-}
-
-s32 rtw_btcoex_IsBTCoexCtrlAMPDUSize(struct adapter *padapter)
-{
-       s32 coexctrl;
-
-       coexctrl = hal_btcoex_IsBTCoexCtrlAMPDUSize(padapter);
-
-       return coexctrl;
-}
-
-void rtw_btcoex_SetManualControl(struct adapter *padapter, u8 manual)
-{
-       hal_btcoex_SetManualControl(padapter, manual);
-}
-
-u8 rtw_btcoex_IsBtControlLps(struct adapter *padapter)
-{
-       return hal_btcoex_IsBtControlLps(padapter);
-}
-
-u8 rtw_btcoex_IsLpsOn(struct adapter *padapter)
-{
-       return hal_btcoex_IsLpsOn(padapter);
-}
-
-u8 rtw_btcoex_RpwmVal(struct adapter *padapter)
-{
-       return hal_btcoex_RpwmVal(padapter);
-}
-
-u8 rtw_btcoex_LpsVal(struct adapter *padapter)
-{
-       return hal_btcoex_LpsVal(padapter);
-}
-
-void rtw_btcoex_SetBTCoexist(struct adapter *padapter, u8 bBtExist)
-{
-       hal_btcoex_SetBTCoexist(padapter, bBtExist);
-}
-
-void rtw_btcoex_SetChipType(struct adapter *padapter, u8 chipType)
-{
-       hal_btcoex_SetChipType(padapter, chipType);
-}
-
-void rtw_btcoex_SetPGAntNum(struct adapter *padapter, u8 antNum)
-{
-       hal_btcoex_SetPgAntNum(padapter, antNum);
-}
-
-void rtw_btcoex_SetSingleAntPath(struct adapter *padapter, u8 singleAntPath)
-{
-       hal_btcoex_SetSingleAntPath(padapter, singleAntPath);
-}
-
-u32 rtw_btcoex_GetRaMask(struct adapter *padapter)
-{
-       return hal_btcoex_GetRaMask(padapter);
-}
-
-void rtw_btcoex_RecordPwrMode(struct adapter *padapter, u8 *pCmdBuf, u8 cmdLen)
-{
-       hal_btcoex_RecordPwrMode(padapter, pCmdBuf, cmdLen);
-}
-
-void rtw_btcoex_DisplayBtCoexInfo(struct adapter *padapter, u8 *pbuf, u32 bufsize)
-{
-       hal_btcoex_DisplayBtCoexInfo(padapter, pbuf, bufsize);
-}
-
-void rtw_btcoex_SetDBG(struct adapter *padapter, u32 *pDbgModule)
-{
-       hal_btcoex_SetDBG(padapter, pDbgModule);
-}
-
-u32 rtw_btcoex_GetDBG(struct adapter *padapter, u8 *pStrBuf, u32 bufSize)
-{
-       return hal_btcoex_GetDBG(padapter, pStrBuf, bufSize);
-}
-
 /*  ================================================== */
 /*  Below Functions are called by BT-Coex */
 /*  ================================================== */
@@ -212,7 +67,7 @@ void rtw_btcoex_LPS_Enter(struct adapter *padapter)
        pwrpriv = adapter_to_pwrctl(padapter);
 
        pwrpriv->bpower_saving = true;
-       lpsVal = rtw_btcoex_LpsVal(padapter);
+       lpsVal = hal_btcoex_LpsVal(padapter);
        rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, lpsVal, "BTCOEX");
 }
 
index ecaa769..addc557 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <drv_types.h>
 #include <rtw_debug.h>
+#include <hal_btcoex.h>
 #include <linux/jiffies.h>
 
 static struct _cmd_callback rtw_cmd_callback[] = {
@@ -1439,7 +1440,7 @@ static void dynamic_chk_wk_hdl(struct adapter *padapter)
        /*  */
        /*  BT-Coexist */
        /*  */
-       rtw_btcoex_Handler(padapter);
+       hal_btcoex_Handler(padapter);
 
 
        /* always call rtw_ps_processor() at last one. */
@@ -1462,7 +1463,7 @@ void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type)
        switch (lps_ctrl_type) {
        case LPS_CTRL_SCAN:
                /* DBG_871X("LPS_CTRL_SCAN\n"); */
-               rtw_btcoex_ScanNotify(padapter, true);
+               hal_btcoex_ScanNotify(padapter, true);
 
                if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
                        /*  connect */
@@ -1491,7 +1492,7 @@ void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type)
        case LPS_CTRL_SPECIAL_PACKET:
                /* DBG_871X("LPS_CTRL_SPECIAL_PACKET\n"); */
                pwrpriv->DelayLPSLastTimeStamp = jiffies;
-               rtw_btcoex_SpecialPacketNotify(padapter, PACKET_DHCP);
+               hal_btcoex_SpecialPacketNotify(padapter, PACKET_DHCP);
                LPS_Leave(padapter, "LPS_CTRL_SPECIAL_PACKET");
                break;
        case LPS_CTRL_LEAVE:
@@ -1594,7 +1595,7 @@ static void rtw_lps_change_dtim_hdl(struct adapter *padapter, u8 dtim)
        if (dtim <= 0 || dtim > 16)
                return;
 
-       if (rtw_btcoex_IsBtControlLps(padapter) == true)
+       if (hal_btcoex_IsBtControlLps(padapter) == true)
                return;
 
        mutex_lock(&pwrpriv->lock);
@@ -1660,22 +1661,6 @@ exit:
 
 }
 
-static void power_saving_wk_hdl(struct adapter *padapter)
-{
-        rtw_ps_processor(padapter);
-}
-
-/* add for CONFIG_IEEE80211W, none 11w can use it */
-static void reset_securitypriv_hdl(struct adapter *padapter)
-{
-        rtw_reset_securitypriv(padapter);
-}
-
-static void free_assoc_resources_hdl(struct adapter *padapter)
-{
-        rtw_free_assoc_resources(padapter, 1);
-}
-
 u8 rtw_ps_cmd(struct adapter *padapter)
 {
        struct cmd_obj          *ppscmd;
@@ -1738,7 +1723,7 @@ static void rtw_chk_hi_queue_hdl(struct adapter *padapter)
                        pstapriv->tim_bitmap &= ~BIT(0);
                        pstapriv->sta_dz_bitmap &= ~BIT(0);
 
-                       if (update_tim == true)
+                       if (update_tim)
                                update_beacon(padapter, _TIM_IE_, NULL, true);
                } else {/* re check again */
                        rtw_chk_hi_queue_cmd(padapter);
@@ -1844,7 +1829,7 @@ static void rtw_btinfo_hdl(struct adapter *adapter, u8 *buf, u16 buf_len)
                buf[1] = 0;
        else if (cmd_idx == BTINFO_BT_AUTO_RPT)
                buf[1] = 2;
-       rtw_btcoex_BtInfoNotify(adapter, len+1, &buf[1]);
+       hal_btcoex_BtInfoNotify(adapter, len+1, &buf[1]);
 }
 
 u8 rtw_c2h_packet_wk_cmd(struct adapter *padapter, u8 *pbuf, u16 length)
@@ -1934,7 +1919,7 @@ static void c2h_wk_callback(_workitem *work)
                        c2h_evt = rtw_malloc(16);
                        if (c2h_evt != NULL) {
                                /* This C2H event is not read, read & clear now */
-                               if (rtw_hal_c2h_evt_read(adapter, c2h_evt) != _SUCCESS) {
+                               if (c2h_evt_read_88xx(adapter, c2h_evt) != _SUCCESS) {
                                        kfree(c2h_evt);
                                        continue;
                                }
@@ -1977,7 +1962,7 @@ u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf)
                dynamic_chk_wk_hdl(padapter);
                break;
        case POWER_SAVING_CTRL_WK_CID:
-               power_saving_wk_hdl(padapter);
+               rtw_ps_processor(padapter);
                break;
        case LPS_CTRL_WK_CID:
                lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type);
@@ -1993,10 +1978,10 @@ u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf)
                break;
        /* add for CONFIG_IEEE80211W, none 11w can use it */
        case RESET_SECURITYPRIV:
-               reset_securitypriv_hdl(padapter);
+               rtw_reset_securitypriv(padapter);
                break;
        case FREE_ASSOC_RESOURCES:
-               free_assoc_resources_hdl(padapter);
+               rtw_free_assoc_resources(padapter, 1);
                break;
        case C2H_WK_CID:
                rtw_hal_set_hwreg_with_buf(padapter, HW_VAR_C2H_HANDLE, pdrvextra_cmd->pbuf, pdrvextra_cmd->size);
index 9f8446c..695a859 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <drv_types.h>
 #include <rtw_debug.h>
+#include <hal_btcoex.h>
 
 u32 GlobalDebugLevel = _drv_err_;
 
@@ -1350,7 +1351,7 @@ int proc_get_btcoex_dbg(struct seq_file *m, void *v)
        char buf[512] = {0};
        padapter = (struct adapter *)rtw_netdev_priv(dev);
 
-       rtw_btcoex_GetDBG(padapter, buf, 512);
+       hal_btcoex_GetDBG(padapter, buf, 512);
 
        DBG_871X_SEL(m, "%s", buf);
 
@@ -1410,7 +1411,7 @@ ssize_t proc_set_btcoex_dbg(struct file *file, const char __user *buffer, size_t
 
        DBG_871X(FUNC_ADPT_FMT ": input 0x%08X 0x%08X\n",
                FUNC_ADPT_ARG(padapter), module[0], module[1]);
-       rtw_btcoex_SetDBG(padapter, module);
+       hal_btcoex_SetDBG(padapter, module);
 
        return count;
 }
@@ -1428,7 +1429,7 @@ int proc_get_btcoex_info(struct seq_file *m, void *v)
        if (!pbuf)
                return -ENOMEM;
 
-       rtw_btcoex_DisplayBtCoexInfo(padapter, pbuf, bufsize);
+       hal_btcoex_DisplayBtCoexInfo(padapter, pbuf, bufsize);
 
        DBG_871X_SEL(m, "%s\n", pbuf);
 
index 5eea02c..3cbd65d 100644 (file)
@@ -118,25 +118,6 @@ _func_enter_;
 _func_exit_;
 }
 
-u16 wait_eeprom_cmd_done(_adapter *padapter)
-{
-       u8 x;
-       u16 i, res = false;
-_func_enter_;
-       standby(padapter);
-       for (i = 0; i < 200; i++) {
-               x = rtw_read8(padapter, EE_9346CR);
-               if (x & _EEDO) {
-                       res = true;
-                       goto exit;
-                       }
-               udelay(CLOCK_RATE);
-       }
-exit:
-_func_exit_;
-       return res;
-}
-
 void eeprom_clean(_adapter *padapter)
 {
        u16 x;
@@ -166,68 +147,6 @@ out:
 _func_exit_;
 }
 
-void eeprom_write16(_adapter *padapter, u16 reg, u16 data)
-{
-       u8 x;
-
-_func_enter_;
-
-       x = rtw_read8(padapter, EE_9346CR);
-
-       x &= ~(_EEDI | _EEDO | _EESK | _EEM0);
-       x |= _EEM1 | _EECS;
-       rtw_write8(padapter, EE_9346CR, x);
-
-       shift_out_bits(padapter, EEPROM_EWEN_OPCODE, 5);
-
-       if (padapter->EepromAddressSize == 8)   /*CF+ and SDIO*/
-               shift_out_bits(padapter, 0, 6);
-       else                                                                    /*USB*/
-               shift_out_bits(padapter, 0, 4);
-
-       standby(padapter);
-
-/* Commented out by rcnjko, 2004.0
-*       Erase this particular word.  Write the erase opcode and register
-*       number in that order. The opcode is 3bits in length; reg is 6 bits long.
-*      shift_out_bits(Adapter, EEPROM_ERASE_OPCODE, 3);
-*      shift_out_bits(Adapter, reg, Adapter->EepromAddressSize);
-*
-*      if (wait_eeprom_cmd_done(Adapter ) == false)
-*      {
-*              return;
-*      }
-*/
-
-       standby(padapter);
-
-       /* write the new word to the EEPROM*/
-
-       /* send the write opcode the EEPORM*/
-       shift_out_bits(padapter, EEPROM_WRITE_OPCODE, 3);
-
-       /* select which word in the EEPROM that we are writing to.*/
-       shift_out_bits(padapter, reg, padapter->EepromAddressSize);
-
-       /* write the data to the selected EEPROM word.*/
-       shift_out_bits(padapter, data, 16);
-
-       if (wait_eeprom_cmd_done(padapter) == false) {
-
-               goto exit;
-       }
-
-       standby(padapter);
-
-       shift_out_bits(padapter, EEPROM_EWDS_OPCODE, 5);
-       shift_out_bits(padapter, reg, 4);
-
-       eeprom_clean(padapter);
-exit:
-_func_exit_;
-       return;
-}
-
 u16 eeprom_read16(_adapter *padapter, u16 reg) /*ReadEEprom*/
 {
 
@@ -268,53 +187,6 @@ _func_exit_;
 
 }
 
-
-
-
-/*From even offset*/
-void eeprom_read_sz(_adapter *padapter, u16 reg, u8 *data, u32 sz)
-{
-
-       u16 x, data16;
-       u32 i;
-_func_enter_;
-       if (padapter->bSurpriseRemoved == true) {
-               RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true"));
-               goto out;
-       }
-       /* select EEPROM, reset bits, set _EECS*/
-       x = rtw_read8(padapter, EE_9346CR);
-
-       if (padapter->bSurpriseRemoved == true) {
-               RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true"));
-               goto out;
-       }
-
-       x &= ~(_EEDI | _EEDO | _EESK | _EEM0);
-       x |= _EEM1 | _EECS;
-       rtw_write8(padapter, EE_9346CR, (unsigned char)x);
-
-       /* write the read opcode and register number in that order*/
-       /* The opcode is 3bits in length, reg is 6 bits long*/
-       shift_out_bits(padapter, EEPROM_READ_OPCODE, 3);
-       shift_out_bits(padapter, reg, padapter->EepromAddressSize);
-
-
-       for (i = 0; i < sz; i += 2) {
-               data16 = shift_in_bits(padapter);
-               data[i] = data16 & 0xff;
-               data[i+1] = data16 >> 8;
-       }
-
-       eeprom_clean(padapter);
-out:
-_func_exit_;
-
-
-
-}
-
-
 /*addr_off : address offset of the entry in eeprom (not the tuple number of eeprom (reg); that is addr_off !=reg)*/
 u8 eeprom_read(_adapter *padapter, u32 addr_off, u8 sz, u8 *rbuf)
 {
@@ -348,14 +220,3 @@ _func_enter_;
 _func_exit_;
        return true;
 }
-
-
-
-void read_eeprom_content(_adapter *padapter)
-{
-
-_func_enter_;
-
-
-_func_exit_;
-}
index aaf2743..6018d87 100644 (file)
@@ -654,7 +654,7 @@ int rtw_get_wapi_ie(u8 *in_ie, uint in_len, u8 *wapi_ie, u16 *wapi_len)
 }
 /* endif */
 
-int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len)
+void rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len)
 {
        u8 authmode, sec_idx, i;
        u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01};
@@ -705,8 +705,6 @@ int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie,
                        }
                }
        }
-
-       return *rsn_len + *wpa_len;
 }
 
 u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen)
index bd75bca..8eb0ff5 100644 (file)
@@ -357,7 +357,7 @@ u8 rtw_set_802_11_connect(struct adapter *padapter, u8 *bssid, struct ndis_802_1
        if (!bssid || rtw_validate_bssid(bssid) == false)
                bssid_valid = false;
 
-       if (ssid_valid == false && bssid_valid == false) {
+       if (!ssid_valid && !bssid_valid) {
                DBG_871X(FUNC_ADPT_FMT" ssid:%p, ssid_valid:%d, bssid:%p, bssid_valid:%d\n",
                        FUNC_ADPT_ARG(padapter), ssid, ssid_valid, bssid, bssid_valid);
                status = _FAIL;
index 5f78f1e..34adf57 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/etherdevice.h>
 #include <drv_types.h>
 #include <rtw_debug.h>
+#include <hal_btcoex.h>
 #include <linux/jiffies.h>
 
 extern u8 rtw_do_join(struct adapter *padapter);
@@ -275,7 +276,7 @@ exit:
        return pnetwork;
 }
 
-void _rtw_free_network_queue(struct adapter *padapter, u8 isfreeall)
+void rtw_free_network_queue(struct adapter *padapter, u8 isfreeall)
 {
        struct list_head *phead, *plist;
        struct wlan_network *pnetwork;
@@ -375,12 +376,6 @@ void rtw_free_network_nolock(struct adapter *padapter, struct wlan_network *pnet
        rtw_cfg80211_unlink_bss(padapter, pnetwork);
 }
 
-
-void rtw_free_network_queue(struct adapter *dev, u8 isfreeall)
-{
-       _rtw_free_network_queue(dev, isfreeall);
-}
-
 /*
        return the wlan_network with the matching addr
 
@@ -1192,7 +1187,7 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, str
                rtw_hal_update_sta_rate_mask(padapter, psta);
 
                psta->wireless_mode = pmlmeext->cur_wireless_mode;
-               psta->raid = rtw_hal_networktype_to_raid(padapter, psta);
+               psta->raid = networktype_to_raid_ex(padapter, psta);
 
 
                /* sta mode */
@@ -1672,7 +1667,7 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf)
                        roam_target = pmlmepriv->roam_network;
                }
 
-               if (roam == true) {
+               if (roam) {
                        if (rtw_to_roam(adapter) > 0)
                                rtw_dec_to_roam(adapter); /* this stadel_event is caused by roaming, decrease to_roam */
                        else if (rtw_to_roam(adapter) == 0)
@@ -1894,10 +1889,10 @@ void rtw_dynamic_check_timer_handler(struct adapter *adapter)
                return;
 
        if (is_primary_adapter(adapter))
-               DBG_871X("IsBtDisabled =%d, IsBtControlLps =%d\n", rtw_btcoex_IsBtDisabled(adapter), rtw_btcoex_IsBtControlLps(adapter));
+               DBG_871X("IsBtDisabled =%d, IsBtControlLps =%d\n", hal_btcoex_IsBtDisabled(adapter), hal_btcoex_IsBtControlLps(adapter));
 
        if ((adapter_to_pwrctl(adapter)->bFwCurrentInPSMode == true)
-               && (rtw_btcoex_IsBtControlLps(adapter) == false)
+               && (hal_btcoex_IsBtControlLps(adapter) == false)
                ) {
                u8 bEnterPS;
 
@@ -1936,11 +1931,6 @@ inline void rtw_clear_scan_deny(struct adapter *adapter)
        DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter));
 }
 
-void rtw_set_scan_deny_timer_hdl(struct adapter *adapter)
-{
-       rtw_clear_scan_deny(adapter);
-}
-
 void rtw_set_scan_deny(struct adapter *adapter, u32 ms)
 {
        struct mlme_priv *mlmepriv = &adapter->mlmepriv;
@@ -2229,7 +2219,6 @@ sint rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv)
                goto exit;
        }
 
-       memset(psetauthparm, 0, sizeof(struct setauth_parm));
        psetauthparm->mode = (unsigned char)psecuritypriv->dot11AuthAlgrthm;
 
        pcmd->cmdcode = _SetAuth_CMD_;
@@ -2262,7 +2251,6 @@ sint rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, s
                res = _FAIL;
                goto exit;
        }
-       memset(psetkeyparm, 0, sizeof(struct setkey_parm));
 
        if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) {
                psetkeyparm->algorithm = (unsigned char)psecuritypriv->dot118021XGrpPrivacy;
index d110d45..4285844 100644 (file)
@@ -9,9 +9,9 @@
 #include <drv_types.h>
 #include <rtw_debug.h>
 #include <rtw_wifi_regd.h>
+#include <hal_btcoex.h>
 #include <linux/kernel.h>
 
-
 static struct mlme_handler mlme_sta_tbl[] = {
        {WIFI_ASSOCREQ,         "OnAssocReq",   &OnAssocReq},
        {WIFI_ASSOCRSP,         "OnAssocRsp",   &OnAssocRsp},
@@ -51,7 +51,6 @@ static struct action_handler OnAction_tbl[] = {
        {RTW_WLAN_CATEGORY_P2P, "ACTION_P2P", &DoReserved},
 };
 
-
 static u8 null_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
 
 /**************************************************
@@ -279,7 +278,7 @@ void init_mlme_default_rate_set(struct adapter *padapter)
 static void init_mlme_ext_priv_value(struct adapter *padapter)
 {
        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
-       struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
 
        atomic_set(&pmlmeext->event_seq, 0);
        pmlmeext->mgnt_seq = 0;/* reset to zero when disconnect at client mode */
@@ -372,9 +371,8 @@ static void init_channel_list(struct adapter *padapter, RT_CHANNEL_INFO *channel
                struct p2p_reg_class *reg = NULL;
 
                for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
-                       if (!has_channel(channel_set, chanset_size, ch)) {
+                       if (!has_channel(channel_set, chanset_size, ch))
                                continue;
-                       }
 
                        if ((0 == padapter->registrypriv.ht_enable) && (8 == o->inc))
                                continue;
@@ -383,7 +381,7 @@ static void init_channel_list(struct adapter *padapter, RT_CHANNEL_INFO *channel
                                ((BW40MINUS == o->bw) || (BW40PLUS == o->bw)))
                                continue;
 
-                       if (reg == NULL) {
+                       if (!reg) {
                                reg = &channel_list->reg_class[cla];
                                cla++;
                                reg->reg_class = o->op_class;
@@ -466,8 +464,8 @@ int init_mlme_ext_priv(struct adapter *padapter)
        int     res = _SUCCESS;
        struct registry_priv *pregistrypriv = &padapter->registrypriv;
        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
-       struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
-       struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
 
        pmlmeext->padapter = padapter;
 
@@ -611,8 +609,8 @@ unsigned int OnProbeReq(struct adapter *padapter, union recv_frame *precv_frame)
        unsigned char *p;
        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
-       struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
-       struct wlan_bssid_ex    *cur = &(pmlmeinfo->network);
+       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 is_valid_p2p_probereq = false;
@@ -661,7 +659,7 @@ unsigned int OnProbeReq(struct adapter *padapter, union recv_frame *precv_frame)
                        /*  allocate a new one */
                        DBG_871X("going to alloc stainfo for rc ="MAC_FMT"\n",  MAC_ARG(get_sa(pframe)));
                        psta = rtw_alloc_stainfo(pstapriv, get_sa(pframe));
-                       if (psta == NULL) {
+                       if (!psta) {
                                /* TODO: */
                                DBG_871X(" Exceed the upper limit of supported clients...\n");
                                return _SUCCESS;
@@ -1219,7 +1217,7 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame)
        }
 
        pstat = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
-       if (pstat == NULL) {
+       if (!pstat) {
                status = _RSON_CLS2_;
                goto asoc_class2_error;
        }
@@ -1261,7 +1259,6 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame)
                goto OnAssocReqFail;
        }
 
-
        /*  now we should check all the fields... */
        /*  checking SSID */
        p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SSID_IE_, &ie_len,
@@ -1280,7 +1277,7 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame)
                        status = _STATS_FAILURE_;
        }
 
-       if (_STATS_SUCCESSFUL_ != status)
+       if (status != _STATS_SUCCESSFUL_)
                goto OnAssocReqFail;
 
        /*  check if the supported rate is ok */
@@ -1376,11 +1373,11 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame)
                wpa_ie_len = 0;
        }
 
-       if (_STATS_SUCCESSFUL_ != status)
+       if (status != _STATS_SUCCESSFUL_)
                goto OnAssocReqFail;
 
        pstat->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
-       if (wpa_ie == NULL) {
+       if (!wpa_ie) {
                if (elems.wps_ie) {
                        DBG_871X("STA included WPS IE in "
                                   "(Re)Association Request - assume WPS is "
@@ -1946,16 +1943,15 @@ unsigned int OnAction_back(struct adapter *padapter, union recv_frame *precv_fra
        addr = GetAddr2Ptr(pframe);
        psta = rtw_get_stainfo(pstapriv, addr);
 
-       if (psta == NULL)
+       if (!psta)
                return _SUCCESS;
 
        frame_body = (unsigned char *)(pframe + sizeof(struct ieee80211_hdr_3addr));
 
        category = frame_body[0];
        if (category == RTW_WLAN_CATEGORY_BACK) {/*  representing Block Ack */
-               if (!pmlmeinfo->HT_enable) {
+               if (!pmlmeinfo->HT_enable)
                        return _SUCCESS;
-               }
 
                action = frame_body[1];
                DBG_871X("%s, action =%d\n", __func__, action);
@@ -2400,9 +2396,8 @@ s32 dump_mgntframe_and_wait_ack(struct adapter *padapter, struct xmit_frame *pmg
                pxmitpriv->ack_tx = true;
                pxmitpriv->seq_no = seq_no++;
                pmgntframe->ack_report = 1;
-               if (rtw_hal_mgnt_xmit(padapter, pmgntframe) == _SUCCESS) {
+               if (rtw_hal_mgnt_xmit(padapter, pmgntframe) == _SUCCESS)
                        ret = rtw_ack_tx_wait(pxmitpriv, timeout_ms);
-               }
 
                pxmitpriv->ack_tx = false;
                mutex_unlock(&pxmitpriv->ack_tx_mutex);
@@ -2465,7 +2460,7 @@ void issue_beacon(struct adapter *padapter, int timeout_ms)
        /* DBG_871X("%s\n", __func__); */
 
        pmgntframe = alloc_mgtxmitframe(pxmitpriv);
-       if (pmgntframe == NULL) {
+       if (!pmgntframe) {
                DBG_871X("%s, alloc mgnt frame fail\n", __func__);
                return;
        }
@@ -2846,7 +2841,7 @@ static int _issue_probereq(struct adapter *padapter,
        RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+issue_probereq\n"));
 
        pmgntframe = alloc_mgtxmitframe(pxmitpriv);
-       if (pmgntframe == NULL)
+       if (!pmgntframe)
                goto exit;
 
        /* update attribute */
@@ -3219,7 +3214,6 @@ void issue_asocrsp(struct adapter *padapter, unsigned short status, struct sta_i
 
        }
 
-
        if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) {
                pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6, REALTEK_96B_IE, &(pattrib->pktlen));
        }
@@ -3264,7 +3258,6 @@ void issue_assocreq(struct adapter *padapter)
        pattrib = &pmgntframe->attrib;
        update_mgntframe_attrib(padapter, pattrib);
 
-
        memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
 
        pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
@@ -3914,7 +3907,7 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch
        DBG_871X("%s, category =%d, action =%d, status =%d\n", __func__, category, action, status);
 
        pmgntframe = alloc_mgtxmitframe(pxmitpriv);
-       if (pmgntframe == NULL)
+       if (!pmgntframe)
                return;
 
        /* update attribute */
@@ -3952,7 +3945,7 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch
                        } while (pmlmeinfo->dialogToken == 0);
                        pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->dialogToken), &(pattrib->pktlen));
 
-                       if (rtw_btcoex_IsBTCoexCtrlAMPDUSize(padapter)) {
+                       if (hal_btcoex_IsBTCoexCtrlAMPDUSize(padapter)) {
                                /*  A-MSDU NOT Supported */
                                BA_para_set = 0;
                                /*  immediate Block Ack */
@@ -4008,7 +4001,7 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch
                        else
                                BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x1000); /* 64 buffer size */
 
-                       if (rtw_btcoex_IsBTCoexCtrlAMPDUSize(padapter) &&
+                       if (hal_btcoex_IsBTCoexCtrlAMPDUSize(padapter) &&
                            padapter->driver_rx_ampdu_factor == 0xFF) {
                                /*  max buffer size is 8 MSDU */
                                BA_para_set &= ~RTW_IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
@@ -5038,12 +5031,12 @@ void report_survey_event(struct adapter *padapter, union recv_frame *precv_frame
        pcmdpriv = &padapter->cmdpriv;
 
        pcmd_obj = rtw_zmalloc(sizeof(struct cmd_obj));
-       if (pcmd_obj == NULL)
+       if (!pcmd_obj)
                return;
 
        cmdsz = (sizeof(struct survey_event) + sizeof(struct C2HEvent_Header));
        pevtcmd = rtw_zmalloc(cmdsz);
-       if (pevtcmd == NULL) {
+       if (!pevtcmd) {
                kfree(pcmd_obj);
                return;
        }
@@ -5091,12 +5084,12 @@ void report_surveydone_event(struct adapter *padapter)
        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
 
        pcmd_obj = rtw_zmalloc(sizeof(struct cmd_obj));
-       if (pcmd_obj == NULL)
+       if (!pcmd_obj)
                return;
 
        cmdsz = (sizeof(struct surveydone_event) + sizeof(struct C2HEvent_Header));
        pevtcmd = rtw_zmalloc(cmdsz);
-       if (pevtcmd == NULL) {
+       if (!pevtcmd) {
                kfree(pcmd_obj);
                return;
        }
@@ -5138,12 +5131,12 @@ void report_join_res(struct adapter *padapter, int res)
        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
 
        pcmd_obj = rtw_zmalloc(sizeof(struct cmd_obj));
-       if (pcmd_obj == NULL)
+       if (!pcmd_obj)
                return;
 
        cmdsz = (sizeof(struct joinbss_event) + sizeof(struct C2HEvent_Header));
        pevtcmd = rtw_zmalloc(cmdsz);
-       if (pevtcmd == NULL) {
+       if (!pevtcmd) {
                kfree(pcmd_obj);
                return;
        }
@@ -5189,12 +5182,12 @@ void report_wmm_edca_update(struct adapter *padapter)
        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
 
        pcmd_obj = rtw_zmalloc(sizeof(struct cmd_obj));
-       if (pcmd_obj == NULL)
+       if (!pcmd_obj)
                return;
 
        cmdsz = (sizeof(struct wmm_event) + sizeof(struct C2HEvent_Header));
        pevtcmd = rtw_zmalloc(cmdsz);
-       if (pevtcmd == NULL) {
+       if (!pevtcmd) {
                kfree(pcmd_obj);
                return;
        }
@@ -5571,7 +5564,7 @@ void mlmeext_sta_add_event_callback(struct adapter *padapter, struct sta_info *p
 
        /*  ToDo: HT for Ad-hoc */
        psta->wireless_mode = rtw_check_network_type(psta->bssrateset, psta->bssratelen, pmlmeext->cur_channel);
-       psta->raid = rtw_hal_networktype_to_raid(padapter, psta);
+       psta->raid = networktype_to_raid_ex(padapter, psta);
 
        /* rate radaptive */
        Update_RA_Entry(padapter, psta);
@@ -6044,7 +6037,7 @@ u8 setopmode_hdl(struct adapter *padapter, u8 *pbuf)
        }
 
        rtw_hal_set_hwreg(padapter, HW_VAR_SET_OPMODE, (u8 *)(&type));
-       /* Set_NETYPE0_MSR(padapter, type); */
+       /* Set_MSR(padapter, type); */
 
 
 #ifdef CONFIG_AUTO_AP_MODE
@@ -6436,9 +6429,8 @@ u8 setauth_hdl(struct adapter *padapter, unsigned char *pbuf)
        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
        struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
 
-       if (pparm->mode < 4) {
+       if (pparm->mode < 4)
                pmlmeinfo->auth_algo = pparm->mode;
-       }
 
        return  H2C_SUCCESS;
 }
@@ -6772,7 +6764,7 @@ int rtw_chk_start_clnt_join(struct adapter *padapter, u8 *ch, u8 *bw, u8 *offset
                *offset = cur_ch_offset;
        }
 
-       return connect_allow == true ? _SUCCESS : _FAIL;
+       return connect_allow ? _SUCCESS : _FAIL;
 }
 
 /* Find union about ch, bw, ch_offset of all linked/linking interfaces */
@@ -6780,10 +6772,6 @@ int rtw_get_ch_setting_union(struct adapter *adapter, u8 *ch, u8 *bw, u8 *offset
 {
        struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
        struct adapter *iface;
-       struct mlme_ext_priv *mlmeext;
-       u8 ch_ret = 0;
-       u8 bw_ret = CHANNEL_WIDTH_20;
-       u8 offset_ret = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
 
        if (ch)
                *ch = 0;
@@ -6793,15 +6781,10 @@ int rtw_get_ch_setting_union(struct adapter *adapter, u8 *ch, u8 *bw, u8 *offset
                *offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
 
        iface = dvobj->padapters;
-       mlmeext = &iface->mlmeextpriv;
 
        if (!check_fwstate(&iface->mlmepriv, _FW_LINKED|_FW_UNDER_LINKING))
                return 0;
 
-       ch_ret = mlmeext->cur_channel;
-       bw_ret = mlmeext->cur_bwmode;
-       offset_ret = mlmeext->cur_ch_offset;
-
        return 1;
 }
 
index 5c468c5..ae7fb70 100644 (file)
@@ -43,7 +43,7 @@ void ips_enter(struct adapter *padapter)
        struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
 
 
-       rtw_btcoex_IpsNotify(padapter, pwrpriv->ips_mode_req);
+       hal_btcoex_IpsNotify(padapter, pwrpriv->ips_mode_req);
 
        mutex_lock(&pwrpriv->lock);
        _ips_enter(padapter);
@@ -90,7 +90,7 @@ int ips_leave(struct adapter *padapter)
        mutex_unlock(&pwrpriv->lock);
 
        if (_SUCCESS == ret)
-               rtw_btcoex_IpsNotify(padapter, IPS_NONE);
+               hal_btcoex_IpsNotify(padapter, IPS_NONE);
 
        return ret;
 }
@@ -178,7 +178,7 @@ void rtw_ps_processor(struct adapter *padapter)
        if (pwrpriv->ips_mode_req == IPS_NONE)
                goto exit;
 
-       if (rtw_pwr_unassociated_idle(padapter) == false)
+       if (!rtw_pwr_unassociated_idle(padapter))
                goto exit;
 
        if ((pwrpriv->rf_pwrstate == rf_on) && ((pwrpriv->pwr_state_check_cnts%4) == 0)) {
@@ -221,7 +221,7 @@ void traffic_check_for_leave_lps(struct adapter *padapter, u8 tx, u32 tx_packets
                        if (xmit_cnt > 8) {
                                if ((adapter_to_pwrctl(padapter)->bLeisurePs)
                                        && (adapter_to_pwrctl(padapter)->pwr_mode != PS_MODE_ACTIVE)
-                                       && (rtw_btcoex_IsBtControlLps(padapter) == false)
+                                       && (hal_btcoex_IsBtControlLps(padapter) == false)
                                        ) {
                                        DBG_871X("leave lps via Tx = %d\n", xmit_cnt);
                                        bLeaveLPS = true;
@@ -236,7 +236,7 @@ void traffic_check_for_leave_lps(struct adapter *padapter, u8 tx, u32 tx_packets
                if (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 4/*2*/) {
                        if ((adapter_to_pwrctl(padapter)->bLeisurePs)
                                && (adapter_to_pwrctl(padapter)->pwr_mode != PS_MODE_ACTIVE)
-                               && (rtw_btcoex_IsBtControlLps(padapter) == false)
+                               && (hal_btcoex_IsBtControlLps(padapter) == false)
                                ) {
                                DBG_871X("leave lps via Rx = %d\n", pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod);
                                bLeaveLPS = true;
@@ -418,10 +418,10 @@ void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_a
        /* if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) */
        if (ps_mode == PS_MODE_ACTIVE) {
                if (1
-                       && (((rtw_btcoex_IsBtControlLps(padapter) == false)
+                       && (((hal_btcoex_IsBtControlLps(padapter) == false)
                                        )
-                               || ((rtw_btcoex_IsBtControlLps(padapter) == true)
-                                       && (rtw_btcoex_IsLpsOn(padapter) == false))
+                               || ((hal_btcoex_IsBtControlLps(padapter) == true)
+                                       && (hal_btcoex_IsLpsOn(padapter) == false))
                                )
                        ) {
                        DBG_871X(FUNC_ADPT_FMT" Leave 802.11 power save - %s\n",
@@ -457,19 +457,19 @@ void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_a
                        rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode));
                        pwrpriv->bFwCurrentInPSMode = false;
 
-                       rtw_btcoex_LpsNotify(padapter, ps_mode);
+                       hal_btcoex_LpsNotify(padapter, ps_mode);
                }
        } else {
                if ((PS_RDY_CHECK(padapter) && check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE))
-                       || ((rtw_btcoex_IsBtControlLps(padapter) == true)
-                               && (rtw_btcoex_IsLpsOn(padapter) == true))
+                       || ((hal_btcoex_IsBtControlLps(padapter) == true)
+                               && (hal_btcoex_IsLpsOn(padapter) == true))
                        ) {
                        u8 pslv;
 
                        DBG_871X(FUNC_ADPT_FMT" Enter 802.11 power save - %s\n",
                                FUNC_ADPT_ARG(padapter), msg);
 
-                       rtw_btcoex_LpsNotify(padapter, ps_mode);
+                       hal_btcoex_LpsNotify(padapter, ps_mode);
 
                        pwrpriv->bFwCurrentInPSMode = true;
                        pwrpriv->pwr_mode = ps_mode;
@@ -481,11 +481,11 @@ void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_a
                        if (pwrpriv->alives == 0)
                                pslv = PS_STATE_S0;
 
-                       if ((rtw_btcoex_IsBtDisabled(padapter) == false)
-                               && (rtw_btcoex_IsBtControlLps(padapter) == true)) {
+                       if ((hal_btcoex_IsBtDisabled(padapter) == false)
+                               && (hal_btcoex_IsBtControlLps(padapter) == true)) {
                                u8 val8;
 
-                               val8 = rtw_btcoex_LpsVal(padapter);
+                               val8 = hal_btcoex_LpsVal(padapter);
                                if (val8 & BIT(4))
                                        pslv = PS_STATE_S2;
                        }
@@ -544,7 +544,7 @@ void LPS_Enter(struct adapter *padapter, const char *msg)
        int n_assoc_iface = 0;
        char buf[32] = {0};
 
-       if (rtw_btcoex_IsBtControlLps(padapter) == true)
+       if (hal_btcoex_IsBtControlLps(padapter) == true)
                return;
 
        /* Skip lps enter request if number of assocated adapters is not 1 */
@@ -589,7 +589,7 @@ void LPS_Leave(struct adapter *padapter, const char *msg)
 
 /*     DBG_871X("+LeisurePSLeave\n"); */
 
-       if (rtw_btcoex_IsBtControlLps(padapter) == true)
+       if (hal_btcoex_IsBtControlLps(padapter) == true)
                return;
 
        if (pwrpriv->bLeisurePs) {
@@ -910,11 +910,11 @@ void rtw_unregister_task_alive(struct adapter *padapter, u32 task)
        pwrctrl = adapter_to_pwrctl(padapter);
        pslv = PS_STATE_S0;
 
-       if ((rtw_btcoex_IsBtDisabled(padapter) == false)
-               && (rtw_btcoex_IsBtControlLps(padapter) == true)) {
+       if ((hal_btcoex_IsBtDisabled(padapter) == false)
+               && (hal_btcoex_IsBtControlLps(padapter) == true)) {
                u8 val8;
 
-               val8 = rtw_btcoex_LpsVal(padapter);
+               val8 = hal_btcoex_LpsVal(padapter);
                if (val8 & BIT(4))
                        pslv = PS_STATE_S2;
        }
@@ -1051,11 +1051,11 @@ void rtw_unregister_tx_alive(struct adapter *padapter)
        pwrctrl = adapter_to_pwrctl(padapter);
        pslv = PS_STATE_S0;
 
-       if ((rtw_btcoex_IsBtDisabled(padapter) == false)
-               && (rtw_btcoex_IsBtControlLps(padapter) == true)) {
+       if ((hal_btcoex_IsBtDisabled(padapter) == false)
+               && (hal_btcoex_IsBtControlLps(padapter) == true)) {
                u8 val8;
 
-               val8 = rtw_btcoex_LpsVal(padapter);
+               val8 = hal_btcoex_LpsVal(padapter);
                if (val8 & BIT(4))
                        pslv = PS_STATE_S2;
        }
@@ -1093,11 +1093,11 @@ void rtw_unregister_cmd_alive(struct adapter *padapter)
        pwrctrl = adapter_to_pwrctl(padapter);
        pslv = PS_STATE_S0;
 
-       if ((rtw_btcoex_IsBtDisabled(padapter) == false)
-               && (rtw_btcoex_IsBtControlLps(padapter) == true)) {
+       if ((hal_btcoex_IsBtDisabled(padapter) == false)
+               && (hal_btcoex_IsBtControlLps(padapter) == true)) {
                u8 val8;
 
-               val8 = rtw_btcoex_LpsVal(padapter);
+               val8 = hal_btcoex_LpsVal(padapter);
                if (val8 & BIT(4))
                        pslv = PS_STATE_S2;
        }
index b543e97..687ff3c 100644 (file)
@@ -50,7 +50,7 @@ sint _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter)
 
        precvpriv->pallocated_frame_buf = vzalloc(NR_RECVFRAME * sizeof(union recv_frame) + RXFRAME_ALIGN_SZ);
 
-       if (precvpriv->pallocated_frame_buf == NULL) {
+       if (!precvpriv->pallocated_frame_buf) {
                res = _FAIL;
                goto exit;
        }
@@ -67,7 +67,7 @@ sint _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter)
 
                list_add_tail(&(precvframe->u.list), &(precvpriv->free_recv_queue.queue));
 
-               res = rtw_os_recv_resource_alloc(padapter, precvframe);
+               rtw_os_recv_resource_alloc(padapter, precvframe);
 
                precvframe->u.hdr.len = 0;
 
@@ -122,7 +122,7 @@ union recv_frame *_rtw_alloc_recvframe(struct __queue *pfree_recv_queue)
 
                list_del_init(&precvframe->u.hdr.list);
                padapter = precvframe->u.hdr.adapter;
-               if (padapter != NULL) {
+               if (padapter) {
                        precvpriv = &padapter->recvpriv;
                        if (pfree_recv_queue == &precvpriv->free_recv_queue)
                                precvpriv->free_recvframe_cnt--;
@@ -160,7 +160,7 @@ int rtw_free_recvframe(union recv_frame *precvframe, struct __queue *pfree_recv_
 
        list_add_tail(&(precvframe->u.hdr.list), get_list_head(pfree_recv_queue));
 
-       if (padapter != NULL) {
+       if (padapter) {
                if (pfree_recv_queue == &precvpriv->free_recv_queue)
                                precvpriv->free_recvframe_cnt++;
        }
@@ -183,7 +183,7 @@ sint _rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue)
 
        list_add_tail(&(precvframe->u.hdr.list), get_list_head(queue));
 
-       if (padapter != NULL)
+       if (padapter)
                if (queue == &precvpriv->free_recv_queue)
                        precvpriv->free_recvframe_cnt++;
 
@@ -334,7 +334,7 @@ sint recvframe_chkmic(struct adapter *adapter,  union recv_frame *precvframe)
                        prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2], prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5]));
 
                /* calculate mic code */
-               if (stainfo != NULL) {
+               if (stainfo) {
                        if (IS_MCAST(prxattrib->ra)) {
                                /* mickey =&psecuritypriv->dot118021XGrprxmickey.skey[0]; */
                                /* iv = precvframe->u.hdr.rx_data+prxattrib->hdrlen; */
@@ -570,7 +570,7 @@ union recv_frame *portctrl(struct adapter *adapter, union recv_frame *precv_fram
        RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:adapter->securitypriv.dot11AuthAlgrthm =%d\n", adapter->securitypriv.dot11AuthAlgrthm));
 
        if (auth_alg == 2) {
-               if ((psta != NULL) && (psta->ieee8021x_blocked)) {
+               if ((psta) && (psta->ieee8021x_blocked)) {
                        __be16 be_tmp;
 
                        /* blocked */
@@ -859,7 +859,7 @@ sint sta2sta_data_frame(
        else
                *psta = rtw_get_stainfo(pstapriv, sta_addr); /*  get ap_info */
 
-       if (*psta == NULL) {
+       if (!*psta) {
                RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under sta2sta_data_frame ; drop pkt\n"));
                ret = _FAIL;
                goto exit;
@@ -942,7 +942,7 @@ sint ap2sta_data_frame(
                else
                        *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /*  get ap_info */
 
-               if (*psta == NULL) {
+               if (!*psta) {
                        RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("ap2sta: can't get psta under STATION_MODE ; drop pkt\n"));
                        #ifdef DBG_RX_DROP_FRAME
                        DBG_871X("DBG_RX_DROP_FRAME %s can't get psta under STATION_MODE ; drop pkt\n", __func__);
@@ -974,7 +974,7 @@ sint ap2sta_data_frame(
 
 
                *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /*  get sta_info */
-               if (*psta == NULL) {
+               if (!*psta) {
                        RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under MP_MODE ; drop pkt\n"));
                        #ifdef DBG_RX_DROP_FRAME
                        DBG_871X("DBG_RX_DROP_FRAME %s can't get psta under WIFI_MP_STATE ; drop pkt\n", __func__);
@@ -991,7 +991,7 @@ sint ap2sta_data_frame(
        } else {
                if (!memcmp(myhwaddr, pattrib->dst, ETH_ALEN) && (!bmcast)) {
                        *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /*  get sta_info */
-                       if (*psta == NULL) {
+                       if (!*psta) {
 
                                /* for AP multicast issue , modify by yiwei */
                                static unsigned long send_issue_deauth_time;
@@ -1042,7 +1042,7 @@ sint sta2ap_data_frame(
                }
 
                *psta = rtw_get_stainfo(pstapriv, pattrib->src);
-               if (*psta == NULL) {
+               if (!*psta) {
                        RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under AP_MODE; drop pkt\n"));
                        DBG_871X("issue_deauth to sta =" MAC_FMT " for the reason(7)\n", MAC_ARG(pattrib->src));
 
@@ -1099,7 +1099,7 @@ sint validate_recv_ctrl_frame(struct adapter *padapter, union recv_frame *precv_
                return _FAIL;
 
        psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
-       if (psta == NULL)
+       if (!psta)
                return _FAIL;
 
        /* for rx pkt statistics */
@@ -1226,7 +1226,7 @@ sint validate_recv_mgnt_frame(struct adapter *padapter, union recv_frame *precv_
        RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("+validate_recv_mgnt_frame\n"));
 
        precv_frame = recvframe_chk_defrag(padapter, precv_frame);
-       if (precv_frame == NULL) {
+       if (!precv_frame) {
                RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("%s: fragment packet\n", __func__));
                return _SUCCESS;
        }
@@ -1274,7 +1274,7 @@ sint validate_recv_data_frame(struct adapter *adapter, union recv_frame *precv_f
        psa = get_sa(ptr);
        pbssid = get_hdr_bssid(ptr);
 
-       if (pbssid == NULL) {
+       if (!pbssid) {
                #ifdef DBG_RX_DROP_FRAME
                DBG_871X("DBG_RX_DROP_FRAME %s pbssid == NULL\n", __func__);
                #endif
@@ -1329,7 +1329,7 @@ sint validate_recv_data_frame(struct adapter *adapter, union recv_frame *precv_f
        }
 
 
-       if (psta == NULL) {
+       if (!psta) {
                RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" after to_fr_ds_chk; psta == NULL\n"));
                #ifdef DBG_RX_DROP_FRAME
                DBG_871X("DBG_RX_DROP_FRAME %s psta == NULL\n", __func__);
@@ -1426,7 +1426,7 @@ static sint validate_80211w_mgmt(struct adapter *adapter, union recv_frame *prec
                        /* actual management data frame body */
                        data_len = pattrib->pkt_len - pattrib->hdrlen - pattrib->iv_len - pattrib->icv_len;
                        mgmt_DATA = rtw_zmalloc(data_len);
-                       if (mgmt_DATA == NULL) {
+                       if (!mgmt_DATA) {
                                DBG_871X("%s mgmt allocate fail  !!!!!!!!!\n", __func__);
                                goto validate_80211w_fail;
                        }
@@ -1615,7 +1615,6 @@ sint wlanhdr_to_ethhdr(union recv_frame *precvframe)
        u8 *psnap_type;
        struct ieee80211_snap_hdr       *psnap;
        __be16 be_tmp;
-       sint ret = _SUCCESS;
        struct adapter                  *adapter = precvframe->u.hdr.adapter;
        struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
        u8 *ptr = get_recvframe_data(precvframe) ; /*  point to frame_ctrl field */
@@ -1702,7 +1701,7 @@ sint wlanhdr_to_ethhdr(union recv_frame *precvframe)
                memcpy(ptr+12, &be_tmp, 2);
        }
 
-       return ret;
+       return _SUCCESS;
 }
 
 /* perform defrag */
@@ -1812,7 +1811,7 @@ union recv_frame *recvframe_chk_defrag(struct adapter *padapter, union recv_fram
 
        psta_addr = pfhdr->attrib.ta;
        psta = rtw_get_stainfo(pstapriv, psta_addr);
-       if (psta == NULL) {
+       if (!psta) {
                u8 type = GetFrameType(pfhdr->rx_data);
                if (type != WIFI_DATA_TYPE) {
                        psta = rtw_get_bcmc_stainfo(padapter);
@@ -1828,7 +1827,7 @@ union recv_frame *recvframe_chk_defrag(struct adapter *padapter, union recv_fram
        if (ismfrag == 1) {
                /* 0~(n-1) fragment frame */
                /* enqueue to defraf_g */
-               if (pdefrag_q != NULL) {
+               if (pdefrag_q) {
                        if (fragnum == 0)
                                /* the first fragment */
                                if (!list_empty(&pdefrag_q->queue))
@@ -1859,7 +1858,7 @@ union recv_frame *recvframe_chk_defrag(struct adapter *padapter, union recv_fram
        if ((ismfrag == 0) && (fragnum != 0)) {
                /* the last fragment frame */
                /* enqueue the last fragment */
-               if (pdefrag_q != NULL) {
+               if (pdefrag_q) {
                        /* spin_lock(&pdefrag_q->lock); */
                        phead = get_list_head(pdefrag_q);
                        list_add_tail(&pfhdr->list, phead);
@@ -1880,7 +1879,7 @@ union recv_frame *recvframe_chk_defrag(struct adapter *padapter, union recv_fram
        }
 
 
-       if ((prtnframe != NULL) && (prtnframe->u.hdr.attrib.privacy)) {
+       if ((prtnframe) && (prtnframe->u.hdr.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"));
@@ -1900,7 +1899,6 @@ static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe)
        _pkt *sub_pkt, *subframes[MAX_SUBFRAME_COUNT];
        struct recv_priv *precvpriv = &padapter->recvpriv;
        struct __queue *pfree_recv_queue = &(precvpriv->free_recv_queue);
-       int     ret = _SUCCESS;
 
        nr_subframes = 0;
 
@@ -1924,7 +1922,7 @@ static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe)
                }
 
                sub_pkt = rtw_os_alloc_msdu_pkt(prframe, nSubframe_Length, pdata);
-               if (sub_pkt == NULL) {
+               if (!sub_pkt) {
                        DBG_871X("%s(): allocate sub packet fail !!!\n", __func__);
                        break;
                }
@@ -1969,7 +1967,7 @@ static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe)
        prframe->u.hdr.len = 0;
        rtw_free_recvframe(prframe, pfree_recv_queue);/* free this recv_frame */
 
-       return ret;
+       return  _SUCCESS;
 }
 
 int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num);
@@ -2453,7 +2451,7 @@ static int recv_func_posthandle(struct adapter *padapter, union recv_frame *prfr
        DBG_COUNTER(padapter->rx_logs.core_rx_post);
 
        prframe = decryptor(padapter, prframe);
-       if (prframe == NULL) {
+       if (!prframe) {
                RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("decryptor: drop pkt\n"));
                #ifdef DBG_RX_DROP_FRAME
                DBG_871X("DBG_RX_DROP_FRAME %s decryptor: drop pkt\n", __func__);
@@ -2464,7 +2462,7 @@ static int recv_func_posthandle(struct adapter *padapter, union recv_frame *prfr
        }
 
        prframe = recvframe_chk_defrag(padapter, prframe);
-       if (prframe == NULL)    {
+       if (!prframe)   {
                RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chk_defrag: drop pkt\n"));
                #ifdef DBG_RX_DROP_FRAME
                DBG_871X("DBG_RX_DROP_FRAME %s recvframe_chk_defrag: drop pkt\n", __func__);
@@ -2474,7 +2472,7 @@ static int recv_func_posthandle(struct adapter *padapter, union recv_frame *prfr
        }
 
        prframe = portctrl(padapter, prframe);
-       if (prframe == NULL) {
+       if (!prframe) {
                RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("portctrl: drop pkt\n"));
                #ifdef DBG_RX_DROP_FRAME
                DBG_871X("DBG_RX_DROP_FRAME %s portctrl: drop pkt\n", __func__);
index fdbf967..76c5037 100644 (file)
@@ -302,14 +302,9 @@ void Switch_DM_Func(struct adapter *padapter, u32 mode, u8 enable)
                rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_CLR, (u8 *)(&mode));
 }
 
-static void Set_NETYPE0_MSR(struct adapter *padapter, u8 type)
-{
-       rtw_hal_set_hwreg(padapter, HW_VAR_MEDIA_STATUS, (u8 *)(&type));
-}
-
 void Set_MSR(struct adapter *padapter, u8 type)
 {
-       Set_NETYPE0_MSR(padapter, type);
+       rtw_hal_set_hwreg(padapter, HW_VAR_MEDIA_STATUS, (u8 *)(&type));
 }
 
 inline u8 rtw_get_oper_ch(struct adapter *adapter)
@@ -745,7 +740,7 @@ s16 rtw_camid_alloc(struct adapter *adapter, struct sta_info *sta, u8 kid)
                i = _rtw_camid_search(adapter, addr, kid);
                if (i >= 0) {
                        /* Fix issue that pairwise and group key have same key id. Pairwise key first, group key can overwirte group only(ex: rekey) */
-                       if (sta || _rtw_camid_is_gk(adapter, i) == true)
+                       if (sta || _rtw_camid_is_gk(adapter, i))
                                cam_id = i;
                        else
                                DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" group key id:%u the same key id as pairwise key\n"
@@ -1620,16 +1615,10 @@ void Update_RA_Entry(struct adapter *padapter, struct sta_info *psta)
        rtw_hal_update_ra_mask(psta, 0);
 }
 
-void enable_rate_adaptive(struct adapter *padapter, struct sta_info *psta);
-void enable_rate_adaptive(struct adapter *padapter, struct sta_info *psta)
-{
-       Update_RA_Entry(padapter, psta);
-}
-
 void set_sta_rate(struct adapter *padapter, struct sta_info *psta)
 {
        /* rate adaptive */
-       enable_rate_adaptive(padapter, psta);
+       Update_RA_Entry(padapter, psta);
 }
 
 unsigned char check_assoc_AP(u8 *pframe, uint len)
@@ -1943,7 +1932,7 @@ void adaptive_early_32k(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len)
 
        /* delay = (timestamp mod 1024*100)/1000 (unit: ms) */
        /* delay_ms = do_div(tsf, (pmlmeinfo->bcn_interval*1024))/1000; */
-       delay_ms = rtw_modular64(tsf, (pmlmeinfo->bcn_interval*1024));
+       delay_ms = do_div(tsf, (pmlmeinfo->bcn_interval*1024));
        delay_ms = delay_ms/1000;
 
        if (delay_ms >= 8)
index 2bb679e..b5dcb78 100644 (file)
@@ -76,7 +76,7 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
 
        pxmitpriv->pallocated_frame_buf = vzalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4);
 
-       if (pxmitpriv->pallocated_frame_buf  == NULL) {
+       if (!pxmitpriv->pallocated_frame_buf) {
                pxmitpriv->pxmit_frame_buf = NULL;
                RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_frame fail!\n"));
                res = _FAIL;
@@ -115,7 +115,7 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
 
        pxmitpriv->pallocated_xmitbuf = vzalloc(NR_XMITBUFF * sizeof(struct xmit_buf) + 4);
 
-       if (pxmitpriv->pallocated_xmitbuf  == NULL) {
+       if (!pxmitpriv->pallocated_xmitbuf) {
                RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_buf fail!\n"));
                res = _FAIL;
                goto exit;
@@ -166,7 +166,7 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
 
        pxmitpriv->xframe_ext_alloc_addr = vzalloc(NR_XMIT_EXTBUFF * sizeof(struct xmit_frame) + 4);
 
-       if (pxmitpriv->xframe_ext_alloc_addr  == NULL) {
+       if (!pxmitpriv->xframe_ext_alloc_addr) {
                pxmitpriv->xframe_ext = NULL;
                RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xframe_ext fail!\n"));
                res = _FAIL;
@@ -199,7 +199,7 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
 
        pxmitpriv->pallocated_xmit_extbuf = vzalloc(NR_XMIT_EXTBUFF * sizeof(struct xmit_buf) + 4);
 
-       if (pxmitpriv->pallocated_xmit_extbuf  == NULL) {
+       if (!pxmitpriv->pallocated_xmit_extbuf) {
                RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_extbuf fail!\n"));
                res = _FAIL;
                goto exit;
@@ -288,7 +288,7 @@ void _rtw_free_xmit_priv(struct xmit_priv *pxmitpriv)
 
        rtw_hal_free_xmit_priv(padapter);
 
-       if (pxmitpriv->pxmit_frame_buf == NULL)
+       if (!pxmitpriv->pxmit_frame_buf)
                return;
 
        for (i = 0; i < NR_XMITFRAME; i++) {
@@ -335,7 +335,7 @@ void _rtw_free_xmit_priv(struct xmit_priv *pxmitpriv)
 
        for (i = 0; i < CMDBUF_MAX; i++) {
                pxmitbuf = &pxmitpriv->pcmd_xmitbuf[i];
-               if (pxmitbuf != NULL)
+               if (pxmitbuf)
                        rtw_os_xmit_resource_free(padapter, pxmitbuf, MAX_CMDBUF_SZ+XMITBUF_ALIGN_SZ, true);
        }
 
@@ -625,13 +625,11 @@ exit:
 
 u8 qos_acm(u8 acm_mask, u8 priority)
 {
-       u8 change_priority = priority;
-
        switch (priority) {
        case 0:
        case 3:
                if (acm_mask & BIT(1))
-                       change_priority = 1;
+                       priority = 1;
                break;
        case 1:
        case 2:
@@ -639,19 +637,19 @@ u8 qos_acm(u8 acm_mask, u8 priority)
        case 4:
        case 5:
                if (acm_mask & BIT(2))
-                       change_priority = 0;
+                       priority = 0;
                break;
        case 6:
        case 7:
                if (acm_mask & BIT(3))
-                       change_priority = 5;
+                       priority = 5;
                break;
        default:
                DBG_871X("qos_acm(): invalid pattrib->priority: %d!!!\n", priority);
                break;
        }
 
-       return change_priority;
+       return priority;
 }
 
 static void set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib)
@@ -774,7 +772,7 @@ static s32 update_attrib(struct adapter *padapter, _pkt *pkt, struct pkt_attrib
                psta = rtw_get_bcmc_stainfo(padapter);
        } else {
                psta = rtw_get_stainfo(pstapriv, pattrib->ra);
-               if (psta == NULL)       { /*  if we cannot get psta => drop the pkt */
+               if (!psta)      { /*  if we cannot get psta => drop the pkt */
                        DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_ucast_sta);
                        RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra:" MAC_FMT"\n", MAC_ARG(pattrib->ra)));
                        #ifdef DBG_TX_DROP_FRAME
@@ -789,7 +787,7 @@ static s32 update_attrib(struct adapter *padapter, _pkt *pkt, struct pkt_attrib
                }
        }
 
-       if (psta == NULL) {
+       if (!psta) {
                /*  if we cannot get psta => drop the pkt */
                DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_sta);
                RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra:" MAC_FMT "\n", MAC_ARG(pattrib->ra)));
@@ -1098,7 +1096,7 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr
                                return _FAIL;
                        }
 
-                       if (psta == NULL) {
+                       if (!psta) {
                                DBG_871X("%s, psta ==NUL\n", __func__);
                                return _FAIL;
                        }
@@ -1241,7 +1239,7 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit_fram
                return _FAIL;
        }
 */
-       if (pxmitframe->buf_addr == NULL) {
+       if (!pxmitframe->buf_addr) {
                DBG_8192C("==> %s buf_addr == NULL\n", __func__);
                return _FAIL;
        }
@@ -1376,7 +1374,7 @@ s32 rtw_mgmt_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit
        tmp_buf = BIP_AAD = rtw_zmalloc(ori_len);
        subtype = GetFrameSubType(pframe); /* bit(7)~bit(2) */
 
-       if (BIP_AAD == NULL)
+       if (!BIP_AAD)
                return _FAIL;
 
        spin_lock_bh(&padapter->security_key_mutex);
@@ -1442,13 +1440,13 @@ s32 rtw_mgmt_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit
                        else
                                psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra);
 
-                       if (psta == NULL) {
+                       if (!psta) {
 
                                DBG_871X("%s, psta ==NUL\n", __func__);
                                goto xmitframe_coalesce_fail;
                        }
 
-                       if (!(psta->state & _FW_LINKED) || pxmitframe->buf_addr == NULL) {
+                       if (!(psta->state & _FW_LINKED) || !pxmitframe->buf_addr) {
                                DBG_871X("%s, not _FW_LINKED or addr null\n", __func__);
                                goto xmitframe_coalesce_fail;
                        }
@@ -1570,7 +1568,7 @@ void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len)
        case AUTO_VCS:
        default:
                perp = rtw_get_ie(ie, _ERPINFO_IE_, &erp_len, ie_len);
-               if (perp == NULL)
+               if (!perp)
                        pxmitpriv->vcs = NONE_VCS;
                else {
                        protection = (*(perp + 2)) & BIT(1);
@@ -1622,7 +1620,7 @@ static struct xmit_buf *__rtw_alloc_cmd_xmitbuf(struct xmit_priv *pxmitpriv,
        struct xmit_buf *pxmitbuf =  NULL;
 
        pxmitbuf = &pxmitpriv->pcmd_xmitbuf[buf_type];
-       if (pxmitbuf !=  NULL) {
+       if (pxmitbuf) {
                pxmitbuf->priv_data = NULL;
 
                pxmitbuf->len = 0;
@@ -1647,13 +1645,13 @@ struct xmit_frame *__rtw_alloc_cmdxmitframe(struct xmit_priv *pxmitpriv,
        struct xmit_buf         *pxmitbuf;
 
        pcmdframe = rtw_alloc_xmitframe(pxmitpriv);
-       if (pcmdframe == NULL) {
+       if (!pcmdframe) {
                DBG_871X("%s, alloc xmitframe fail\n", __func__);
                return NULL;
        }
 
        pxmitbuf = __rtw_alloc_cmd_xmitbuf(pxmitpriv, buf_type);
-       if (pxmitbuf == NULL) {
+       if (!pxmitbuf) {
                DBG_871X("%s, alloc xmitbuf fail\n", __func__);
                rtw_free_xmitframe(pxmitpriv, pcmdframe);
                return NULL;
@@ -1693,7 +1691,7 @@ struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv)
                list_del_init(&(pxmitbuf->list));
        }
 
-       if (pxmitbuf !=  NULL) {
+       if (pxmitbuf) {
                pxmitpriv->free_xmit_extbuf_cnt--;
                #ifdef DBG_XMIT_BUF_EXT
                DBG_871X("DBG_XMIT_BUF_EXT ALLOC no =%d,  free_xmit_extbuf_cnt =%d\n", pxmitbuf->no, pxmitpriv->free_xmit_extbuf_cnt);
@@ -1723,7 +1721,7 @@ s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
        _irqL irqL;
        struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue;
 
-       if (pxmitbuf == NULL)
+       if (!pxmitbuf)
                return _FAIL;
 
        spin_lock_irqsave(&pfree_queue->lock, irqL);
@@ -1765,7 +1763,7 @@ struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv)
                list_del_init(&(pxmitbuf->list));
        }
 
-       if (pxmitbuf !=  NULL) {
+       if (pxmitbuf) {
                pxmitpriv->free_xmitbuf_cnt--;
                #ifdef DBG_XMIT_BUF
                DBG_871X("DBG_XMIT_BUF ALLOC no =%d,  free_xmitbuf_cnt =%d\n", pxmitbuf->no, pxmitpriv->free_xmitbuf_cnt);
@@ -1801,7 +1799,7 @@ s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
 
        /* DBG_871X("+rtw_free_xmitbuf\n"); */
 
-       if (pxmitbuf == NULL)
+       if (!pxmitbuf)
                return _FAIL;
 
        if (pxmitbuf->sctx) {
@@ -1831,7 +1829,7 @@ s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
 
 static void rtw_init_xmitframe(struct xmit_frame *pxframe)
 {
-       if (pxframe !=  NULL) { /* default value setting */
+       if (pxframe) { /* default value setting */
                pxframe->buf_addr = NULL;
                pxframe->pxmitbuf = NULL;
 
@@ -1927,7 +1925,7 @@ struct xmit_frame *rtw_alloc_xmitframe_once(struct xmit_priv *pxmitpriv)
 
        alloc_addr = rtw_zmalloc(sizeof(struct xmit_frame) + 4);
 
-       if (alloc_addr == NULL)
+       if (!alloc_addr)
                goto exit;
 
        pxframe = (struct xmit_frame *)N_BYTE_ALIGMENT((SIZE_PTR)(alloc_addr), 4);
@@ -1955,7 +1953,7 @@ s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitfram
        struct adapter *padapter = pxmitpriv->adapter;
        _pkt *pndis_pkt = NULL;
 
-       if (pxmitframe == NULL) {
+       if (!pxmitframe) {
                RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("======rtw_free_xmitframe():pxmitframe == NULL!!!!!!!!!!\n"));
                goto exit;
        }
@@ -2109,7 +2107,7 @@ s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe)
                return _FAIL;
        }
 
-       if (psta == NULL) {
+       if (!psta) {
                DBG_COUNTER(padapter->tx_logs.core_tx_enqueue_class_err_nosta);
                res = _FAIL;
                DBG_8192C("rtw_xmit_classifier: psta == NULL\n");
@@ -2310,7 +2308,7 @@ s32 rtw_xmit(struct adapter *padapter, _pkt **ppkt)
                drop_cnt = 0;
        }
 
-       if (pxmitframe == NULL) {
+       if (!pxmitframe) {
                drop_cnt++;
                RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit: no more pxmitframe\n"));
                DBG_COUNTER(padapter->tx_logs.core_tx_err_pxmitframe);
@@ -2409,7 +2407,7 @@ sint xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fr
                return false;
        }
 
-       if (psta == NULL) {
+       if (!psta) {
                DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_warn_nosta);
                DBG_871X("%s, psta ==NUL\n", __func__);
                return false;
@@ -2426,7 +2424,7 @@ sint xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fr
                /* DBG_871X("directly xmit pspoll_triggered packet\n"); */
 
                /* pattrib->triggered = 0; */
-               if (bmcst && xmitframe_hiq_filter(pxmitframe) == true)
+               if (bmcst && xmitframe_hiq_filter(pxmitframe))
                        pattrib->qsel = 0x11;/* HIQ */
 
                return ret;
@@ -2455,7 +2453,7 @@ sint xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fr
 
                        /* DBG_871X("enqueue, sq_len =%d, tim =%x\n", psta->sleepq_len, pstapriv->tim_bitmap); */
 
-                       if (update_tim == true) {
+                       if (update_tim) {
                                update_beacon(padapter, _TIM_IE_, NULL, true);
                        } else {
                                chk_bmc_sleepq_cmd(padapter);
@@ -2521,7 +2519,7 @@ sint xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fr
 
                                /* DBG_871X("enqueue, sq_len =%d, tim =%x\n", psta->sleepq_len, pstapriv->tim_bitmap); */
 
-                               if (update_tim == true)
+                               if (update_tim)
                                        /* DBG_871X("sleepq_len == 1, update BCNTIM\n"); */
                                        /* upate BCN for TIM IE */
                                        update_beacon(padapter, _TIM_IE_, NULL, true);
index eb6e07e..8e4caee 100644 (file)
@@ -1421,7 +1421,7 @@ static void halbtc8723b1ant_PsTdma(
 
 
        if (bTurnOn) {
-               if (pBtLinkInfo->bSlaveRole == true)
+               if (pBtLinkInfo->bSlaveRole)
                        psTdmaByte4Val = psTdmaByte4Val | 0x1;  /* 0x778 = 0x1 at wifi slot (no blocking BT Low-Pri pkts) */
 
 
@@ -2337,9 +2337,9 @@ static void halbtc8723b1ant_ActionWifiConnected(PBTC_COEXIST pBtCoexist)
                                        );
                        }
                } else if (
-                       (pCoexSta->bPanExist == false) &&
-                       (pCoexSta->bA2dpExist == false) &&
-                       (pCoexSta->bHidExist == false)
+                       (!pCoexSta->bPanExist) &&
+                       (!pCoexSta->bA2dpExist) &&
+                       (!pCoexSta->bHidExist)
                )
                        halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0);
                else
index cb62fc0..02da0a8 100644 (file)
@@ -7,6 +7,13 @@
 
 #include "Mp_Precomp.h"
 
+/* defines */
+#define HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(val)                            \
+do {                                                                         \
+       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, val);           \
+       pCoexDm->psTdmaDuAdjType = val;                                       \
+} while (0)
+
 /*  Global variables, these are static variables */
 static COEX_DM_8723B_2ANT GLCoexDm8723b2Ant;
 static PCOEX_DM_8723B_2ANT pCoexDm = &GLCoexDm8723b2Ant;
@@ -1599,63 +1606,43 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
                {
                        if (bScoHid) {
                                if (bTxPause) {
-                                       if (maxInterval == 1) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 13);
-                                               pCoexDm->psTdmaDuAdjType = 13;
-                                       } else if (maxInterval == 2) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14);
-                                               pCoexDm->psTdmaDuAdjType = 14;
-                                       } else if (maxInterval == 3) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
-                                               pCoexDm->psTdmaDuAdjType = 15;
-                                       } else {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
-                                               pCoexDm->psTdmaDuAdjType = 15;
-                                       }
+                                       if (maxInterval == 1)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(13);
+                                       else if (maxInterval == 2)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(14);
+                                       else if (maxInterval == 3)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+                                       else
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
                                } else {
-                                       if (maxInterval == 1) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9);
-                                               pCoexDm->psTdmaDuAdjType = 9;
-                                       } else if (maxInterval == 2) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10);
-                                               pCoexDm->psTdmaDuAdjType = 10;
-                                       } else if (maxInterval == 3) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
-                                               pCoexDm->psTdmaDuAdjType = 11;
-                                       } else {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
-                                               pCoexDm->psTdmaDuAdjType = 11;
-                                       }
+                                       if (maxInterval == 1)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(9);
+                                       else if (maxInterval == 2)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(10);
+                                       else if (maxInterval == 3)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+                                       else
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
                                }
                        } else {
                                if (bTxPause) {
-                                       if (maxInterval == 1) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5);
-                                               pCoexDm->psTdmaDuAdjType = 5;
-                                       } else if (maxInterval == 2) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6);
-                                               pCoexDm->psTdmaDuAdjType = 6;
-                                       } else if (maxInterval == 3) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
-                                               pCoexDm->psTdmaDuAdjType = 7;
-                                       } else {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
-                                               pCoexDm->psTdmaDuAdjType = 7;
-                                       }
+                                       if (maxInterval == 1)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(5);
+                                       else if (maxInterval == 2)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(6);
+                                       else if (maxInterval == 3)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+                                       else
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
                                } else {
-                                       if (maxInterval == 1) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 1);
-                                               pCoexDm->psTdmaDuAdjType = 1;
-                                       } else if (maxInterval == 2) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2);
-                                               pCoexDm->psTdmaDuAdjType = 2;
-                                       } else if (maxInterval == 3) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
-                                               pCoexDm->psTdmaDuAdjType = 3;
-                                       } else {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
-                                               pCoexDm->psTdmaDuAdjType = 3;
-                                       }
+                                       if (maxInterval == 1)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(1);
+                                       else if (maxInterval == 2)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(2);
+                                       else if (maxInterval == 3)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+                                       else
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
                                }
                        }
                }
@@ -1741,442 +1728,295 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
                        if (bTxPause) {
                                BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n"));
 
-                               if (pCoexDm->curPsTdma == 71) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5);
-                                       pCoexDm->psTdmaDuAdjType = 5;
-                               } else if (pCoexDm->curPsTdma == 1) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5);
-                                       pCoexDm->psTdmaDuAdjType = 5;
-                               } else if (pCoexDm->curPsTdma == 2) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6);
-                                       pCoexDm->psTdmaDuAdjType = 6;
-                               } else if (pCoexDm->curPsTdma == 3) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
-                                       pCoexDm->psTdmaDuAdjType = 7;
-                               } else if (pCoexDm->curPsTdma == 4) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8);
-                                       pCoexDm->psTdmaDuAdjType = 8;
-                               }
-
-                               if (pCoexDm->curPsTdma == 9) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 13);
-                                       pCoexDm->psTdmaDuAdjType = 13;
-                               } else if (pCoexDm->curPsTdma == 10) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14);
-                                       pCoexDm->psTdmaDuAdjType = 14;
-                               } else if (pCoexDm->curPsTdma == 11) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
-                                       pCoexDm->psTdmaDuAdjType = 15;
-                               } else if (pCoexDm->curPsTdma == 12) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16);
-                                       pCoexDm->psTdmaDuAdjType = 16;
-                               }
+                               if (pCoexDm->curPsTdma == 71)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(5);
+                               else if (pCoexDm->curPsTdma == 1)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(5);
+                               else if (pCoexDm->curPsTdma == 2)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(6);
+                               else if (pCoexDm->curPsTdma == 3)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+                               else if (pCoexDm->curPsTdma == 4)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(8);
+
+                               if (pCoexDm->curPsTdma == 9)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(13);
+                               else if (pCoexDm->curPsTdma == 10)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(14);
+                               else if (pCoexDm->curPsTdma == 11)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+                               else if (pCoexDm->curPsTdma == 12)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(16);
 
                                if (result == -1) {
-                                       if (pCoexDm->curPsTdma == 5) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6);
-                                               pCoexDm->psTdmaDuAdjType = 6;
-                                       } else if (pCoexDm->curPsTdma == 6) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
-                                               pCoexDm->psTdmaDuAdjType = 7;
-                                       } else if (pCoexDm->curPsTdma == 7) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8);
-                                               pCoexDm->psTdmaDuAdjType = 8;
-                                       } else if (pCoexDm->curPsTdma == 13) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14);
-                                               pCoexDm->psTdmaDuAdjType = 14;
-                                       } else if (pCoexDm->curPsTdma == 14) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
-                                               pCoexDm->psTdmaDuAdjType = 15;
-                                       } else if (pCoexDm->curPsTdma == 15) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16);
-                                               pCoexDm->psTdmaDuAdjType = 16;
-                                       }
+                                       if (pCoexDm->curPsTdma == 5)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(6);
+                                       else if (pCoexDm->curPsTdma == 6)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+                                       else if (pCoexDm->curPsTdma == 7)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(8);
+                                       else if (pCoexDm->curPsTdma == 13)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(14);
+                                       else if (pCoexDm->curPsTdma == 14)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+                                       else if (pCoexDm->curPsTdma == 15)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(16);
                                } else if (result == 1) {
-                                       if (pCoexDm->curPsTdma == 8) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
-                                               pCoexDm->psTdmaDuAdjType = 7;
-                                       } else if (pCoexDm->curPsTdma == 7) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6);
-                                               pCoexDm->psTdmaDuAdjType = 6;
-                                       } else if (pCoexDm->curPsTdma == 6) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5);
-                                               pCoexDm->psTdmaDuAdjType = 5;
-                                       } else if (pCoexDm->curPsTdma == 16) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
-                                               pCoexDm->psTdmaDuAdjType = 15;
-                                       } else if (pCoexDm->curPsTdma == 15) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14);
-                                               pCoexDm->psTdmaDuAdjType = 14;
-                                       } else if (pCoexDm->curPsTdma == 14) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 13);
-                                               pCoexDm->psTdmaDuAdjType = 13;
-                                       }
+                                       if (pCoexDm->curPsTdma == 8)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+                                       else if (pCoexDm->curPsTdma == 7)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(6);
+                                       else if (pCoexDm->curPsTdma == 6)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(5);
+                                       else if (pCoexDm->curPsTdma == 16)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+                                       else if (pCoexDm->curPsTdma == 15)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(14);
+                                       else if (pCoexDm->curPsTdma == 14)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(13);
                                }
                        } else {
                                BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n"));
-                               if (pCoexDm->curPsTdma == 5) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 71);
-                                       pCoexDm->psTdmaDuAdjType = 71;
-                               } else if (pCoexDm->curPsTdma == 6) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2);
-                                       pCoexDm->psTdmaDuAdjType = 2;
-                               } else if (pCoexDm->curPsTdma == 7) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
-                                       pCoexDm->psTdmaDuAdjType = 3;
-                               } else if (pCoexDm->curPsTdma == 8) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4);
-                                       pCoexDm->psTdmaDuAdjType = 4;
-                               }
-
-                               if (pCoexDm->curPsTdma == 13) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9);
-                                       pCoexDm->psTdmaDuAdjType = 9;
-                               } else if (pCoexDm->curPsTdma == 14) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10);
-                                       pCoexDm->psTdmaDuAdjType = 10;
-                               } else if (pCoexDm->curPsTdma == 15) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
-                                       pCoexDm->psTdmaDuAdjType = 11;
-                               } else if (pCoexDm->curPsTdma == 16) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12);
-                                       pCoexDm->psTdmaDuAdjType = 12;
-                               }
+                               if (pCoexDm->curPsTdma == 5)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(71);
+                               else if (pCoexDm->curPsTdma == 6)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(2);
+                               else if (pCoexDm->curPsTdma == 7)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+                               else if (pCoexDm->curPsTdma == 8)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(4);
+
+                               if (pCoexDm->curPsTdma == 13)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(9);
+                               else if (pCoexDm->curPsTdma == 14)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(10);
+                               else if (pCoexDm->curPsTdma == 15)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+                               else if (pCoexDm->curPsTdma == 16)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(12);
 
                                if (result == -1) {
-                                       if (pCoexDm->curPsTdma == 71) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 1);
-                                               pCoexDm->psTdmaDuAdjType = 1;
-                                       } else if (pCoexDm->curPsTdma == 1) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2);
-                                               pCoexDm->psTdmaDuAdjType = 2;
-                                       } else if (pCoexDm->curPsTdma == 2) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
-                                               pCoexDm->psTdmaDuAdjType = 3;
-                                       } else if (pCoexDm->curPsTdma == 3) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4);
-                                               pCoexDm->psTdmaDuAdjType = 4;
-                                       } else if (pCoexDm->curPsTdma == 9) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10);
-                                               pCoexDm->psTdmaDuAdjType = 10;
-                                       } else if (pCoexDm->curPsTdma == 10) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
-                                               pCoexDm->psTdmaDuAdjType = 11;
-                                       } else if (pCoexDm->curPsTdma == 11) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12);
-                                               pCoexDm->psTdmaDuAdjType = 12;
-                                       }
+                                       if (pCoexDm->curPsTdma == 71)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(1);
+                                       else if (pCoexDm->curPsTdma == 1)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(2);
+                                       else if (pCoexDm->curPsTdma == 2)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+                                       else if (pCoexDm->curPsTdma == 3)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(4);
+                                       else if (pCoexDm->curPsTdma == 9)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(10);
+                                       else if (pCoexDm->curPsTdma == 10)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+                                       else if (pCoexDm->curPsTdma == 11)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(12);
                                } else if (result == 1) {
-                                       if (pCoexDm->curPsTdma == 4) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
-                                               pCoexDm->psTdmaDuAdjType = 3;
-                                       } else if (pCoexDm->curPsTdma == 3) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2);
-                                               pCoexDm->psTdmaDuAdjType = 2;
-                                       } else if (pCoexDm->curPsTdma == 2) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 1);
-                                               pCoexDm->psTdmaDuAdjType = 1;
-                                       } else if (pCoexDm->curPsTdma == 1) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 71);
-                                               pCoexDm->psTdmaDuAdjType = 71;
-                                       } else if (pCoexDm->curPsTdma == 12) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
-                                               pCoexDm->psTdmaDuAdjType = 11;
-                                       } else if (pCoexDm->curPsTdma == 11) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10);
-                                               pCoexDm->psTdmaDuAdjType = 10;
-                                       } else if (pCoexDm->curPsTdma == 10) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9);
-                                               pCoexDm->psTdmaDuAdjType = 9;
-                                       }
+                                       if (pCoexDm->curPsTdma == 4)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+                                       else if (pCoexDm->curPsTdma == 3)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(2);
+                                       else if (pCoexDm->curPsTdma == 2)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(1);
+                                       else if (pCoexDm->curPsTdma == 1)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(71);
+                                       else if (pCoexDm->curPsTdma == 12)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+                                       else if (pCoexDm->curPsTdma == 11)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(10);
+                                       else if (pCoexDm->curPsTdma == 10)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(9);
                                }
                        }
                } else if (maxInterval == 2) {
                        if (bTxPause) {
                                BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n"));
-                               if (pCoexDm->curPsTdma == 1) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6);
-                                       pCoexDm->psTdmaDuAdjType = 6;
-                               } else if (pCoexDm->curPsTdma == 2) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6);
-                                       pCoexDm->psTdmaDuAdjType = 6;
-                               } else if (pCoexDm->curPsTdma == 3) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
-                                       pCoexDm->psTdmaDuAdjType = 7;
-                               } else if (pCoexDm->curPsTdma == 4) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8);
-                                       pCoexDm->psTdmaDuAdjType = 8;
-                               }
-
-                               if (pCoexDm->curPsTdma == 9) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14);
-                                       pCoexDm->psTdmaDuAdjType = 14;
-                               } else if (pCoexDm->curPsTdma == 10) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14);
-                                       pCoexDm->psTdmaDuAdjType = 14;
-                               } else if (pCoexDm->curPsTdma == 11) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
-                                       pCoexDm->psTdmaDuAdjType = 15;
-                               } else if (pCoexDm->curPsTdma == 12) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16);
-                                       pCoexDm->psTdmaDuAdjType = 16;
-                               }
+                               if (pCoexDm->curPsTdma == 1)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(6);
+                               else if (pCoexDm->curPsTdma == 2)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(6);
+                               else if (pCoexDm->curPsTdma == 3)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+                               else if (pCoexDm->curPsTdma == 4)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(8);
+
+                               if (pCoexDm->curPsTdma == 9)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(14);
+                               else if (pCoexDm->curPsTdma == 10)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(14);
+                               else if (pCoexDm->curPsTdma == 11)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+                               else if (pCoexDm->curPsTdma == 12)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(16);
 
                                if (result == -1) {
-                                       if (pCoexDm->curPsTdma == 5) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6);
-                                               pCoexDm->psTdmaDuAdjType = 6;
-                                       } else if (pCoexDm->curPsTdma == 6) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
-                                               pCoexDm->psTdmaDuAdjType = 7;
-                                       } else if (pCoexDm->curPsTdma == 7) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8);
-                                               pCoexDm->psTdmaDuAdjType = 8;
-                                       } else if (pCoexDm->curPsTdma == 13) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14);
-                                               pCoexDm->psTdmaDuAdjType = 14;
-                                       } else if (pCoexDm->curPsTdma == 14) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
-                                               pCoexDm->psTdmaDuAdjType = 15;
-                                       } else if (pCoexDm->curPsTdma == 15) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16);
-                                               pCoexDm->psTdmaDuAdjType = 16;
-                                       }
+                                       if (pCoexDm->curPsTdma == 5)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(6);
+                                       else if (pCoexDm->curPsTdma == 6)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+                                       else if (pCoexDm->curPsTdma == 7)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(8);
+                                       else if (pCoexDm->curPsTdma == 13)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(14);
+                                       else if (pCoexDm->curPsTdma == 14)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+                                       else if (pCoexDm->curPsTdma == 15)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(16);
                                } else if (result == 1) {
-                                       if (pCoexDm->curPsTdma == 8) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
-                                               pCoexDm->psTdmaDuAdjType = 7;
-                                       } else if (pCoexDm->curPsTdma == 7) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6);
-                                               pCoexDm->psTdmaDuAdjType = 6;
-                                       } else if (pCoexDm->curPsTdma == 6) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6);
-                                               pCoexDm->psTdmaDuAdjType = 6;
-                                       } else if (pCoexDm->curPsTdma == 16) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
-                                               pCoexDm->psTdmaDuAdjType = 15;
-                                       } else if (pCoexDm->curPsTdma == 15) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14);
-                                               pCoexDm->psTdmaDuAdjType = 14;
-                                       } else if (pCoexDm->curPsTdma == 14) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14);
-                                               pCoexDm->psTdmaDuAdjType = 14;
-                                       }
+                                       if (pCoexDm->curPsTdma == 8)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+                                       else if (pCoexDm->curPsTdma == 7)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(6);
+                                       else if (pCoexDm->curPsTdma == 6)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(6);
+                                       else if (pCoexDm->curPsTdma == 16)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+                                       else if (pCoexDm->curPsTdma == 15)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(14);
+                                       else if (pCoexDm->curPsTdma == 14)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(14);
                                }
                        } else {
                                BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n"));
-                               if (pCoexDm->curPsTdma == 5) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2);
-                                       pCoexDm->psTdmaDuAdjType = 2;
-                               } else if (pCoexDm->curPsTdma == 6) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2);
-                                       pCoexDm->psTdmaDuAdjType = 2;
-                               } else if (pCoexDm->curPsTdma == 7) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
-                                       pCoexDm->psTdmaDuAdjType = 3;
-                               } else if (pCoexDm->curPsTdma == 8) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4);
-                                       pCoexDm->psTdmaDuAdjType = 4;
-                               }
-
-                               if (pCoexDm->curPsTdma == 13) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10);
-                                       pCoexDm->psTdmaDuAdjType = 10;
-                               } else if (pCoexDm->curPsTdma == 14) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10);
-                                       pCoexDm->psTdmaDuAdjType = 10;
-                               } else if (pCoexDm->curPsTdma == 15) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
-                                       pCoexDm->psTdmaDuAdjType = 11;
-                               } else if (pCoexDm->curPsTdma == 16) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12);
-                                       pCoexDm->psTdmaDuAdjType = 12;
-                               }
+                               if (pCoexDm->curPsTdma == 5)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(2);
+                               else if (pCoexDm->curPsTdma == 6)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(2);
+                               else if (pCoexDm->curPsTdma == 7)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+                               else if (pCoexDm->curPsTdma == 8)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(4);
+
+                               if (pCoexDm->curPsTdma == 13)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(10);
+                               else if (pCoexDm->curPsTdma == 14)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(10);
+                               else if (pCoexDm->curPsTdma == 15)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+                               else if (pCoexDm->curPsTdma == 16)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(12);
 
                                if (result == -1) {
-                                       if (pCoexDm->curPsTdma == 1) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2);
-                                               pCoexDm->psTdmaDuAdjType = 2;
-                                       } else if (pCoexDm->curPsTdma == 2) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
-                                               pCoexDm->psTdmaDuAdjType = 3;
-                                       } else if (pCoexDm->curPsTdma == 3) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4);
-                                               pCoexDm->psTdmaDuAdjType = 4;
-                                       } else if (pCoexDm->curPsTdma == 9) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10);
-                                               pCoexDm->psTdmaDuAdjType = 10;
-                                       } else if (pCoexDm->curPsTdma == 10) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
-                                               pCoexDm->psTdmaDuAdjType = 11;
-                                       } else if (pCoexDm->curPsTdma == 11) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12);
-                                               pCoexDm->psTdmaDuAdjType = 12;
-                                       }
+                                       if (pCoexDm->curPsTdma == 1)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(2);
+                                       else if (pCoexDm->curPsTdma == 2)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+                                       else if (pCoexDm->curPsTdma == 3)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(4);
+                                       else if (pCoexDm->curPsTdma == 9)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(10);
+                                       else if (pCoexDm->curPsTdma == 10)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+                                       else if (pCoexDm->curPsTdma == 11)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(12);
                                } else if (result == 1) {
-                                       if (pCoexDm->curPsTdma == 4) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
-                                               pCoexDm->psTdmaDuAdjType = 3;
-                                       } else if (pCoexDm->curPsTdma == 3) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2);
-                                               pCoexDm->psTdmaDuAdjType = 2;
-                                       } else if (pCoexDm->curPsTdma == 2) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2);
-                                               pCoexDm->psTdmaDuAdjType = 2;
-                                       } else if (pCoexDm->curPsTdma == 12) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
-                                               pCoexDm->psTdmaDuAdjType = 11;
-                                       } else if (pCoexDm->curPsTdma == 11) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10);
-                                               pCoexDm->psTdmaDuAdjType = 10;
-                                       } else if (pCoexDm->curPsTdma == 10) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10);
-                                               pCoexDm->psTdmaDuAdjType = 10;
-                                       }
+                                       if (pCoexDm->curPsTdma == 4)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+                                       else if (pCoexDm->curPsTdma == 3)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(2);
+                                       else if (pCoexDm->curPsTdma == 2)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(2);
+                                       else if (pCoexDm->curPsTdma == 12)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+                                       else if (pCoexDm->curPsTdma == 11)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(10);
+                                       else if (pCoexDm->curPsTdma == 10)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(10);
                                }
                        }
                } else if (maxInterval == 3) {
                        if (bTxPause) {
                                BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n"));
-                               if (pCoexDm->curPsTdma == 1) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
-                                       pCoexDm->psTdmaDuAdjType = 7;
-                               } else if (pCoexDm->curPsTdma == 2) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
-                                       pCoexDm->psTdmaDuAdjType = 7;
-                               } else if (pCoexDm->curPsTdma == 3) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
-                                       pCoexDm->psTdmaDuAdjType = 7;
-                               } else if (pCoexDm->curPsTdma == 4) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8);
-                                       pCoexDm->psTdmaDuAdjType = 8;
-                               }
-
-                               if (pCoexDm->curPsTdma == 9) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
-                                       pCoexDm->psTdmaDuAdjType = 15;
-                               } else if (pCoexDm->curPsTdma == 10) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
-                                       pCoexDm->psTdmaDuAdjType = 15;
-                               } else if (pCoexDm->curPsTdma == 11) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
-                                       pCoexDm->psTdmaDuAdjType = 15;
-                               } else if (pCoexDm->curPsTdma == 12) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16);
-                                       pCoexDm->psTdmaDuAdjType = 16;
-                               }
+                               if (pCoexDm->curPsTdma == 1)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+                               else if (pCoexDm->curPsTdma == 2)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+                               else if (pCoexDm->curPsTdma == 3)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+                               else if (pCoexDm->curPsTdma == 4)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(8);
+
+                               if (pCoexDm->curPsTdma == 9)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+                               else if (pCoexDm->curPsTdma == 10)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+                               else if (pCoexDm->curPsTdma == 11)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+                               else if (pCoexDm->curPsTdma == 12)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(16);
 
                                if (result == -1) {
-                                       if (pCoexDm->curPsTdma == 5) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
-                                               pCoexDm->psTdmaDuAdjType = 7;
-                                       } else if (pCoexDm->curPsTdma == 6) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
-                                               pCoexDm->psTdmaDuAdjType = 7;
-                                       } else if (pCoexDm->curPsTdma == 7) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8);
-                                               pCoexDm->psTdmaDuAdjType = 8;
-                                       } else if (pCoexDm->curPsTdma == 13) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
-                                               pCoexDm->psTdmaDuAdjType = 15;
-                                       } else if (pCoexDm->curPsTdma == 14) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
-                                               pCoexDm->psTdmaDuAdjType = 15;
-                                       } else if (pCoexDm->curPsTdma == 15) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16);
-                                               pCoexDm->psTdmaDuAdjType = 16;
-                                       }
+                                       if (pCoexDm->curPsTdma == 5)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+                                       else if (pCoexDm->curPsTdma == 6)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+                                       else if (pCoexDm->curPsTdma == 7)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(8);
+                                       else if (pCoexDm->curPsTdma == 13)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+                                       else if (pCoexDm->curPsTdma == 14)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+                                       else if (pCoexDm->curPsTdma == 15)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(16);
                                } else if (result == 1) {
-                                       if (pCoexDm->curPsTdma == 8) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
-                                               pCoexDm->psTdmaDuAdjType = 7;
-                                       } else if (pCoexDm->curPsTdma == 7) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
-                                               pCoexDm->psTdmaDuAdjType = 7;
-                                       } else if (pCoexDm->curPsTdma == 6) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
-                                               pCoexDm->psTdmaDuAdjType = 7;
-                                       } else if (pCoexDm->curPsTdma == 16) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
-                                               pCoexDm->psTdmaDuAdjType = 15;
-                                       } else if (pCoexDm->curPsTdma == 15) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
-                                               pCoexDm->psTdmaDuAdjType = 15;
-                                       } else if (pCoexDm->curPsTdma == 14) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
-                                               pCoexDm->psTdmaDuAdjType = 15;
-                                       }
+                                       if (pCoexDm->curPsTdma == 8)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+                                       else if (pCoexDm->curPsTdma == 7)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+                                       else if (pCoexDm->curPsTdma == 6)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+                                       else if (pCoexDm->curPsTdma == 16)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+                                       else if (pCoexDm->curPsTdma == 15)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+                                       else if (pCoexDm->curPsTdma == 14)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
                                }
                        } else {
                                BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n"));
-                               if (pCoexDm->curPsTdma == 5) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
-                                       pCoexDm->psTdmaDuAdjType = 3;
-                               } else if (pCoexDm->curPsTdma == 6) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
-                                       pCoexDm->psTdmaDuAdjType = 3;
-                               } else if (pCoexDm->curPsTdma == 7) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
-                                       pCoexDm->psTdmaDuAdjType = 3;
-                               } else if (pCoexDm->curPsTdma == 8) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4);
-                                       pCoexDm->psTdmaDuAdjType = 4;
-                               }
-
-                               if (pCoexDm->curPsTdma == 13) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
-                                       pCoexDm->psTdmaDuAdjType = 11;
-                               } else if (pCoexDm->curPsTdma == 14) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
-                                       pCoexDm->psTdmaDuAdjType = 11;
-                               } else if (pCoexDm->curPsTdma == 15) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
-                                       pCoexDm->psTdmaDuAdjType = 11;
-                               } else if (pCoexDm->curPsTdma == 16) {
-                                       halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12);
-                                       pCoexDm->psTdmaDuAdjType = 12;
-                               }
+                               if (pCoexDm->curPsTdma == 5)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+                               else if (pCoexDm->curPsTdma == 6)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+                               else if (pCoexDm->curPsTdma == 7)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+                               else if (pCoexDm->curPsTdma == 8)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(4);
+
+                               if (pCoexDm->curPsTdma == 13)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+                               else if (pCoexDm->curPsTdma == 14)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+                               else if (pCoexDm->curPsTdma == 15)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+                               else if (pCoexDm->curPsTdma == 16)
+                                       HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(12);
 
                                if (result == -1) {
-                                       if (pCoexDm->curPsTdma == 1) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
-                                               pCoexDm->psTdmaDuAdjType = 3;
-                                       } else if (pCoexDm->curPsTdma == 2) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
-                                               pCoexDm->psTdmaDuAdjType = 3;
-                                       } else if (pCoexDm->curPsTdma == 3) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4);
-                                               pCoexDm->psTdmaDuAdjType = 4;
-                                       } else if (pCoexDm->curPsTdma == 9) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
-                                               pCoexDm->psTdmaDuAdjType = 11;
-                                       } else if (pCoexDm->curPsTdma == 10) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
-                                               pCoexDm->psTdmaDuAdjType = 11;
-                                       } else if (pCoexDm->curPsTdma == 11) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12);
-                                               pCoexDm->psTdmaDuAdjType = 12;
-                                       }
+                                       if (pCoexDm->curPsTdma == 1)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+                                       else if (pCoexDm->curPsTdma == 2)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+                                       else if (pCoexDm->curPsTdma == 3)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(4);
+                                       else if (pCoexDm->curPsTdma == 9)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+                                       else if (pCoexDm->curPsTdma == 10)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+                                       else if (pCoexDm->curPsTdma == 11)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(12);
                                } else if (result == 1) {
-                                       if (pCoexDm->curPsTdma == 4) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
-                                               pCoexDm->psTdmaDuAdjType = 3;
-                                       } else if (pCoexDm->curPsTdma == 3) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
-                                               pCoexDm->psTdmaDuAdjType = 3;
-                                       } else if (pCoexDm->curPsTdma == 2) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
-                                               pCoexDm->psTdmaDuAdjType = 3;
-                                       } else if (pCoexDm->curPsTdma == 12) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
-                                               pCoexDm->psTdmaDuAdjType = 11;
-                                       } else if (pCoexDm->curPsTdma == 11) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
-                                               pCoexDm->psTdmaDuAdjType = 11;
-                                       } else if (pCoexDm->curPsTdma == 10) {
-                                               halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
-                                               pCoexDm->psTdmaDuAdjType = 11;
-                                       }
+                                       if (pCoexDm->curPsTdma == 4)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+                                       else if (pCoexDm->curPsTdma == 3)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+                                       else if (pCoexDm->curPsTdma == 2)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+                                       else if (pCoexDm->curPsTdma == 12)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+                                       else if (pCoexDm->curPsTdma == 11)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+                                       else if (pCoexDm->curPsTdma == 10)
+                                               HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
                                }
                        }
                }
index bae59e5..19856e8 100644 (file)
@@ -299,7 +299,7 @@ void ODM_ReadAndConfig_MP_8723B_AGC_TAB(PDM_ODM_T pDM_Odm)
                                READ_NEXT_PAIR(v1, v2, i);
                        }
 
-                       if (bMatched == false) {
+                       if (!bMatched) {
                                /*  Condition isn't matched.
                                *   Discard the following (offset, data) pairs.
                                */
@@ -568,7 +568,7 @@ void ODM_ReadAndConfig_MP_8723B_PHY_REG(PDM_ODM_T pDM_Odm)
                                READ_NEXT_PAIR(v1, v2, i);
                        }
 
-                       if (bMatched == false) {
+                       if (!bMatched) {
                                /*  Condition isn't matched.
                                *   Discard the following (offset, data) pairs.
                                */
index 3c8e26a..b80c5b1 100644 (file)
@@ -270,7 +270,7 @@ void ODM_ReadAndConfig_MP_8723B_MAC_REG(PDM_ODM_T pDM_Odm)
                                READ_NEXT_PAIR(v1, v2, i);
                        }
 
-                       if (bMatched == false) {
+                       if (!bMatched) {
                                /*  Condition isn't matched. Discard the following (offset, data) pairs. */
                                while (v1 < 0x40000000 && i < ArrayLen-2)
                                        READ_NEXT_PAIR(v1, v2, i);
index ba42b4d..426f68b 100644 (file)
@@ -301,7 +301,7 @@ void ODM_ReadAndConfig_MP_8723B_RadioA(PDM_ODM_T pDM_Odm)
                                READ_NEXT_PAIR(v1, v2, i);
                        }
 
-                       if (bMatched == false) {
+                       if (!bMatched) {
                                /*  Condition isn't matched.
                                *   Discard the following (offset, data) pairs.
                                */
index 53d3bdf..3239d37 100644 (file)
@@ -1292,7 +1292,7 @@ static void _PHY_SaveADDARegisters8723B(
        struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
        PDM_ODM_T pDM_Odm = &pHalData->odmpriv;
 
-       if (ODM_CheckPowerStatus(padapter) == false)
+       if (!ODM_CheckPowerStatus(padapter))
                return;
 
        ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Save ADDA parameters.\n"));
@@ -1363,7 +1363,7 @@ static void _PHY_PathADDAOn8723B(
        ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("ADDA ON.\n"));
 
        pathOn = 0x01c00014;
-       if (false == is2T) {
+       if (!is2T) {
                pathOn = 0x01c00014;
                PHY_SetBBReg(pDM_Odm->Adapter, ADDAReg[0], bMaskDWord, 0x01c00014);
        } else {
@@ -1811,7 +1811,7 @@ void PHY_IQCalibrate_8723B(
        u32             StartTime;
        s32                     ProgressingTime;
 
-       if (ODM_CheckPowerStatus(padapter) == false)
+       if (!ODM_CheckPowerStatus(padapter))
                return;
 
        if (!(pDM_Odm->SupportAbility & ODM_RF_CALIBRATION))
index 6caddd7..5257287 100644 (file)
@@ -112,9 +112,9 @@ void DBG_BT_INFO(u8 *dbgmsg)
 /*  */
 static u8 halbtcoutsrc_IsBtCoexistAvailable(PBTC_COEXIST pBtCoexist)
 {
-       if (!pBtCoexist->bBinded || !pBtCoexist->Adapter){
+       if (!pBtCoexist->bBinded || !pBtCoexist->Adapter)
                return false;
-       }
+
        return true;
 }
 
@@ -195,7 +195,6 @@ static void halbtcoutsrc_NormalLps(PBTC_COEXIST pBtCoexist)
 static void halbtcoutsrc_LeaveLowPower(PBTC_COEXIST pBtCoexist)
 {
        struct adapter *padapter;
-       struct hal_com_data *pHalData;
        s32 ready;
        unsigned long stime;
        unsigned long utime;
@@ -203,7 +202,6 @@ static void halbtcoutsrc_LeaveLowPower(PBTC_COEXIST pBtCoexist)
 
 
        padapter = pBtCoexist->Adapter;
-       pHalData = GET_HAL_DATA(padapter);
        ready = _FAIL;
 #ifdef LPS_RPWM_WAIT_MS
        timeout = LPS_RPWM_WAIT_MS;
@@ -256,13 +254,11 @@ static void halbtcoutsrc_AggregationCheck(PBTC_COEXIST pBtCoexist)
        padapter = pBtCoexist->Adapter;
        bNeedToAct = false;
 
-       if (pBtCoexist->btInfo.bRejectAggPkt)
+       if (pBtCoexist->btInfo.bRejectAggPkt) {
                rtw_btcoex_RejectApAggregatedPacket(padapter, true);
-       else {
-
+       } else {
                if (pBtCoexist->btInfo.bPreBtCtrlAggBufSize !=
-                       pBtCoexist->btInfo.bBtCtrlAggBufSize){
-
+                       pBtCoexist->btInfo.bBtCtrlAggBufSize) {
                        bNeedToAct = true;
                        pBtCoexist->btInfo.bPreBtCtrlAggBufSize = pBtCoexist->btInfo.bBtCtrlAggBufSize;
                }
@@ -292,7 +288,7 @@ static u8 halbtcoutsrc_IsWifiBusy(struct adapter *padapter)
        if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE) == true) {
                if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)
                        return true;
-               if (true == pmlmepriv->LinkDetectInfo.bBusyTraffic)
+               if (pmlmepriv->LinkDetectInfo.bBusyTraffic)
                        return true;
        }
 
@@ -312,12 +308,12 @@ static u32 _halbtcoutsrc_GetWifiLinkStatus(struct adapter *padapter)
 
        if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE) == true) {
                if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
-                       if (true == bp2p)
+                       if (bp2p)
                                portConnectedStatus |= WIFI_P2P_GO_CONNECTED;
                        else
                                portConnectedStatus |= WIFI_AP_CONNECTED;
                } else {
-                       if (true == bp2p)
+                       if (bp2p)
                                portConnectedStatus |= WIFI_P2P_GC_CONNECTED;
                        else
                                portConnectedStatus |= WIFI_STA_CONNECTED;
@@ -362,15 +358,9 @@ static u32 halbtcoutsrc_GetBtPatchVer(PBTC_COEXIST pBtCoexist)
 
 static s32 halbtcoutsrc_GetWifiRssi(struct adapter *padapter)
 {
-       struct hal_com_data *pHalData;
-       s32 UndecoratedSmoothedPWDB = 0;
+       struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
 
-
-       pHalData = GET_HAL_DATA(padapter);
-
-       UndecoratedSmoothedPWDB = pHalData->dmpriv.EntryMinUndecoratedSmoothedPWDB;
-
-       return UndecoratedSmoothedPWDB;
+       return pHalData->dmpriv.EntryMinUndecoratedSmoothedPWDB;
 }
 
 static u8 halbtcoutsrc_GetWifiScanAPNum(struct adapter *padapter)
@@ -380,7 +370,7 @@ static u8 halbtcoutsrc_GetWifiScanAPNum(struct adapter *padapter)
 
        pmlmeext = &padapter->mlmeextpriv;
 
-       if (GLBtcWiFiInScanState == false) {
+       if (!GLBtcWiFiInScanState) {
                if (pmlmeext->sitesurvey_res.bss_cnt > 0xFF)
                        scan_AP_num = 0xFF;
                else
@@ -566,18 +556,14 @@ static u8 halbtcoutsrc_Set(void *pBtcContext, u8 setType, void *pInBuf)
 {
        PBTC_COEXIST pBtCoexist;
        struct adapter *padapter;
-       struct hal_com_data *pHalData;
        u8 *pu8;
-       u8 *pU1Tmp;
        u32 *pU4Tmp;
        u8 ret;
 
 
        pBtCoexist = (PBTC_COEXIST)pBtcContext;
        padapter = pBtCoexist->Adapter;
-       pHalData = GET_HAL_DATA(padapter);
        pu8 = pInBuf;
-       pU1Tmp = pInBuf;
        pU4Tmp = pInBuf;
        ret = true;
 
@@ -620,11 +606,11 @@ static u8 halbtcoutsrc_Set(void *pBtcContext, u8 setType, void *pInBuf)
 
        /*  set some u8 type variables. */
        case BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON:
-               pBtCoexist->btInfo.rssiAdjustForAgcTableOn = *pU1Tmp;
+               pBtCoexist->btInfo.rssiAdjustForAgcTableOn = *pu8;
                break;
 
        case BTC_SET_U1_AGG_BUF_SIZE:
-               pBtCoexist->btInfo.aggBufSize = *pU1Tmp;
+               pBtCoexist->btInfo.aggBufSize = *pu8;
                break;
 
        /*  the following are some action which will be triggered */
@@ -639,15 +625,15 @@ static u8 halbtcoutsrc_Set(void *pBtcContext, u8 setType, void *pInBuf)
        /* 1Ant =========== */
        /*  set some u8 type variables. */
        case BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE:
-               pBtCoexist->btInfo.rssiAdjustFor1AntCoexType = *pU1Tmp;
+               pBtCoexist->btInfo.rssiAdjustFor1AntCoexType = *pu8;
                break;
 
        case BTC_SET_U1_LPS_VAL:
-               pBtCoexist->btInfo.lpsVal = *pU1Tmp;
+               pBtCoexist->btInfo.lpsVal = *pu8;
                break;
 
        case BTC_SET_U1_RPWM_VAL:
-               pBtCoexist->btInfo.rpwmVal = *pU1Tmp;
+               pBtCoexist->btInfo.rpwmVal = *pu8;
                break;
 
        /*  the following are some action which will be triggered */
@@ -822,11 +808,10 @@ static void halbtcoutsrc_WriteLocalReg1Byte(void *pBtcContext, u32 RegAddr, u8 D
        PBTC_COEXIST            pBtCoexist = (PBTC_COEXIST)pBtcContext;
        struct adapter *Adapter = pBtCoexist->Adapter;
 
-       if (BTC_INTF_SDIO == pBtCoexist->chipInterface) {
+       if (BTC_INTF_SDIO == pBtCoexist->chipInterface)
                rtw_write8(Adapter, SDIO_LOCAL_BASE | RegAddr, Data);
-       } else {
+       else
                rtw_write8(Adapter, RegAddr, Data);
-       }
 }
 
 static void halbtcoutsrc_SetBbReg(void *pBtcContext, u32 RegAddr, u32 BitMask, u32 Data)
@@ -1202,14 +1187,13 @@ void EXhalbtcoutsrc_SpecialPacketNotify(PBTC_COEXIST pBtCoexist, u8 pktType)
        if (pBtCoexist->bManualControl)
                return;
 
-       if (PACKET_DHCP == pktType)
+       if (PACKET_DHCP == pktType) {
                packetType = BTC_PACKET_DHCP;
-       else if (PACKET_EAPOL == pktType)
+       } else if (PACKET_EAPOL == pktType) {
                packetType = BTC_PACKET_EAPOL;
-       else if (PACKET_ARP == pktType)
+       } else if (PACKET_ARP == pktType) {
                packetType = BTC_PACKET_ARP;
-       else {
-               packetType = BTC_PACKET_UNKNOWN;
+       } else {
                return;
        }
 
@@ -1362,7 +1346,7 @@ u8 hal_btcoex_IsBtExist(struct adapter *padapter)
        return pHalData->bt_coexist.bBtExist;
 }
 
-u8 hal_btcoex_IsBtDisabled(struct adapter *padapter)
+bool hal_btcoex_IsBtDisabled(struct adapter *padapter)
 {
        if (!hal_btcoex_IsBtExist(padapter))
                return true;
@@ -1457,7 +1441,7 @@ void hal_btcoex_IQKNotify(struct adapter *padapter, u8 state)
 
 void hal_btcoex_BtInfoNotify(struct adapter *padapter, u8 length, u8 *tmpBuf)
 {
-       if (GLBtcWiFiInIQKState == true)
+       if (GLBtcWiFiInIQKState)
                return;
 
        EXhalbtcoutsrc_BtInfoNotify(&GLBtCoexist, tmpBuf, length);
@@ -1478,7 +1462,7 @@ void hal_btcoex_HaltNotify(struct adapter *padapter)
        EXhalbtcoutsrc_HaltNotify(&GLBtCoexist);
 }
 
-void hal_btcoex_Hanlder(struct adapter *padapter)
+void hal_btcoex_Handler(struct adapter *padapter)
 {
        EXhalbtcoutsrc_Periodical(&GLBtCoexist);
 }
index e5f1153..638b12a 100644 (file)
@@ -125,7 +125,7 @@ u8 hal_com_config_channel_plan(
        if (0xFF == hw_channel_plan)
                AutoLoadFail = true;
 
-       if (false == AutoLoadFail) {
+       if (!AutoLoadFail) {
                u8 hw_chnlPlan;
 
                hw_chnlPlan = hw_channel_plan & (~EEPROM_CHANNEL_PLAN_BY_HW_MASK);
@@ -963,12 +963,6 @@ exit:
        return ret;
 }
 
-
-u8  rtw_hal_networktype_to_raid(struct adapter *adapter, struct sta_info *psta)
-{
-       return networktype_to_raid_ex(adapter, psta);
-}
-
 u8 rtw_get_mgntframe_raid(struct adapter *adapter, unsigned char network_type)
 {
 
index 4a4d17b..acb2597 100644 (file)
@@ -400,11 +400,6 @@ bool rtw_hal_c2h_valid(struct adapter *adapter, u8 *buf)
        return c2h_evt_valid((struct c2h_evt_hdr_88xx *)buf);
 }
 
-s32 rtw_hal_c2h_evt_read(struct adapter *adapter, u8 *buf)
-{
-       return c2h_evt_read_88xx(adapter, buf);
-}
-
 s32 rtw_hal_c2h_handler(struct adapter *adapter, u8 *c2h_evt)
 {
        s32 ret = _FAIL;
index ebaefca..24a9d8f 100644 (file)
@@ -8,30 +8,6 @@
 
 #include <drv_types.h>
 
-/**
-* Function:    PHY_CalculateBitShift
-*
-* OverView:    Get shifted position of the BitMask
-*
-* Input:
-*              u32     BitMask,
-*
-* Output:      none
-* Return:              u32     Return the shift bit bit position of the mask
-*/
-u32 PHY_CalculateBitShift(u32 BitMask)
-{
-       u32 i;
-
-       for (i = 0; i <= 31; i++) {
-               if (((BitMask>>i) &  0x1) == 1)
-                       break;
-       }
-
-       return i;
-}
-
-
 /*  */
 /*  ==> RF shadow Operation API Code Section!!! */
 /*  */
@@ -179,38 +155,3 @@ void PHY_RFShadowCompareFlagSetAll(IN PADAPTER Adapter)
        }
 
 }      /* PHY_RFShadowCompareFlagSetAll */
-
-
-void PHY_RFShadowRecorverFlagSetAll(IN PADAPTER Adapter)
-{
-       u8 eRFPath = 0;
-       u32 Offset = 0, maxReg = GET_RF6052_REAL_MAX_REG(Adapter);
-
-       for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) {
-               for (Offset = 0; Offset < maxReg; Offset++) {
-                       /*  2008/11/20 MH For S3S4 test, we only check reg 26/27 now!!!! */
-                       if (Offset != 0x26 && Offset != 0x27)
-                               PHY_RFShadowRecorverFlagSet(Adapter, eRFPath, Offset, false);
-                       else
-                               PHY_RFShadowRecorverFlagSet(Adapter, eRFPath, Offset, true);
-               }
-       }
-
-}      /* PHY_RFShadowCompareFlagSetAll */
-
-void PHY_RFShadowRefresh(IN PADAPTER Adapter)
-{
-       u8 eRFPath = 0;
-       u32 Offset = 0, maxReg = GET_RF6052_REAL_MAX_REG(Adapter);
-
-       for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) {
-               for (Offset = 0; Offset < maxReg; Offset++) {
-                       RF_Shadow[eRFPath][Offset].Value = 0;
-                       RF_Shadow[eRFPath][Offset].Compare = false;
-                       RF_Shadow[eRFPath][Offset].Recorver  = false;
-                       RF_Shadow[eRFPath][Offset].ErrorOrNot = false;
-                       RF_Shadow[eRFPath][Offset].Driver_Write = false;
-               }
-       }
-
-}      /* PHY_RFShadowRead */
diff --git a/drivers/staging/rtl8723bs/hal/odm_AntDiv.c b/drivers/staging/rtl8723bs/hal/odm_AntDiv.c
deleted file mode 100644 (file)
index d5415ee..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- ******************************************************************************/
-
-//============================================================
-// include files
-//============================================================
-
-#include "odm_precomp.h"
-
-//======================================================
-// when antenna test utility is on or some testing
-// need to disable antenna diversity
-// call this function to disable all ODM related mechanisms
-// which will switch antenna.
-//======================================================
-void ODM_StopAntennaSwitchDm(PDM_ODM_T pDM_Odm)
-{
-       // disable ODM antenna diversity
-       pDM_Odm->SupportAbility &= ~ODM_BB_ANT_DIV;
-       ODM_RT_TRACE(
-               pDM_Odm,
-               ODM_COMP_ANT_DIV,
-               ODM_DBG_LOUD,
-               ("STOP Antenna Diversity\n")
-       );
-}
-
-void ODM_SetAntConfig(PDM_ODM_T pDM_Odm, u8 antSetting)// 0=A, 1=B, 2=C, ....
-{
-       if (antSetting == 0) // ant A
-               PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, 0x00000000);
-       else if (antSetting == 1)
-               PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, 0x00000280);
-}
-
-//======================================================
-
-
-void ODM_SwAntDivRestAfterLink(PDM_ODM_T pDM_Odm)
-{
-       pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table;
-       pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable;
-       u32 i;
-
-       pDM_Odm->RSSI_test = false;
-       pDM_SWAT_Table->try_flag = 0xff;
-       pDM_SWAT_Table->RSSI_Trying = 0;
-       pDM_SWAT_Table->Double_chk_flag = 0;
-
-       pDM_FatTable->RxIdleAnt = MAIN_ANT;
-
-       for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) {
-               pDM_FatTable->MainAnt_Sum[i] = 0;
-               pDM_FatTable->AuxAnt_Sum[i] = 0;
-               pDM_FatTable->MainAnt_Cnt[i] = 0;
-               pDM_FatTable->AuxAnt_Cnt[i] = 0;
-       }
-}
diff --git a/drivers/staging/rtl8723bs/hal/odm_AntDiv.h b/drivers/staging/rtl8723bs/hal/odm_AntDiv.h
deleted file mode 100644 (file)
index c9496d5..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- ******************************************************************************/
-
-#ifndef        __ODMANTDIV_H__
-#define    __ODMANTDIV_H__
-
-
-
-#define ANT1_2G 0 /*  = ANT2_5G */
-#define ANT2_2G 1 /*  = ANT1_5G */
-
-/* Antenna Diversty Control Type */
-#define        ODM_AUTO_ANT    0
-#define        ODM_FIX_MAIN_ANT        1
-#define        ODM_FIX_AUX_ANT 2
-
-#define        TX_BY_REG       0
-
-#define ANTDIV_ON 1
-#define ANTDIV_OFF 0
-
-#define INIT_ANTDIV_TIMMER 0
-#define CANCEL_ANTDIV_TIMMER 1
-#define RELEASE_ANTDIV_TIMMER 2
-
-#endif /* ifndef       __ODMANTDIV_H__ */
index 4fa6cd3..70d98c5 100644 (file)
@@ -496,13 +496,8 @@ void odm_DIGInit(void *pDM_VOID)
        /* To Initi BT30 IGI */
        pDM_DigTable->BT30_CurIGI = 0x32;
 
-       if (pDM_Odm->BoardType & (ODM_BOARD_EXT_PA|ODM_BOARD_EXT_LNA)) {
-               pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
-               pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC;
-       } else {
-               pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
-               pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC;
-       }
+       pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
+       pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC;
 
 }
 
@@ -525,7 +520,7 @@ void odm_DIG(void *pDM_VOID)
        bool bDFSBand = false;
        bool bPerformance = true, bFirstTpTarget = false, bFirstCoverage = false;
 
-       if (odm_DigAbort(pDM_Odm) == true)
+       if (odm_DigAbort(pDM_Odm))
                return;
 
        ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() ===========================>\n\n"));
index d802a1f..49fa814 100644 (file)
@@ -23,7 +23,7 @@ static u8 odm_QueryRxPwrPercentage(s8 AntPower)
 
 }
 
-static s32 odm_SignalScaleMapping_92CSeries(PDM_ODM_T pDM_Odm, s32 CurrSig)
+s32 odm_SignalScaleMapping(PDM_ODM_T pDM_Odm, s32 CurrSig)
 {
        s32 RetSig = 0;
 
@@ -49,11 +49,6 @@ static s32 odm_SignalScaleMapping_92CSeries(PDM_ODM_T pDM_Odm, s32 CurrSig)
        return RetSig;
 }
 
-s32 odm_SignalScaleMapping(PDM_ODM_T pDM_Odm, s32 CurrSig)
-{
-       return odm_SignalScaleMapping_92CSeries(pDM_Odm, CurrSig);
-}
-
 static u8 odm_EVMdbToPercentage(s8 Value)
 {
        /*  */
@@ -496,32 +491,3 @@ HAL_STATUS ODM_ConfigBBWithHeaderFile(
        return HAL_STATUS_SUCCESS;
 }
 
-HAL_STATUS ODM_ConfigMACWithHeaderFile(PDM_ODM_T pDM_Odm)
-{
-       u8 result = HAL_STATUS_SUCCESS;
-
-       ODM_RT_TRACE(
-               pDM_Odm,
-               ODM_COMP_INIT,
-               ODM_DBG_LOUD,
-               (
-                       "===>ODM_ConfigMACWithHeaderFile (%s)\n",
-                       (pDM_Odm->bIsMPChip) ? "MPChip" : "TestChip"
-               )
-       );
-       ODM_RT_TRACE(
-               pDM_Odm,
-               ODM_COMP_INIT,
-               ODM_DBG_LOUD,
-               (
-                       "pDM_Odm->SupportPlatform: 0x%X, pDM_Odm->SupportInterface: 0x%X, pDM_Odm->BoardType: 0x%X\n",
-                       pDM_Odm->SupportPlatform,
-                       pDM_Odm->SupportInterface,
-                       pDM_Odm->BoardType
-               )
-       );
-
-       READ_AND_CONFIG(8723B, _MAC_REG);
-
-       return result;
-}
index d3af1ca..945366b 100644 (file)
@@ -140,8 +140,6 @@ HAL_STATUS ODM_ConfigBBWithHeaderFile(
        PDM_ODM_T pDM_Odm, ODM_BB_Config_Type ConfigType
 );
 
-HAL_STATUS ODM_ConfigMACWithHeaderFile(PDM_ODM_T pDM_Odm);
-
 HAL_STATUS ODM_ConfigFWWithHeaderFile(
        PDM_ODM_T pDM_Odm,
        ODM_FW_Config_Type ConfigType,
index 12dfc58..07b5859 100644 (file)
@@ -7,51 +7,46 @@
 #ifndef __INC_ODM_REGCONFIG_H_8723B
 #define __INC_ODM_REGCONFIG_H_8723B
 
-void odm_ConfigRFReg_8723B(
-       PDM_ODM_T pDM_Odm,
-       u32 Addr,
-       u32 Data,
-       ODM_RF_RADIO_PATH_E RF_PATH,
-       u32 RegAddr
+void odm_ConfigRFReg_8723B(PDM_ODM_T pDM_Odm,
+                          u32 Addr,
+                          u32 Data,
+                          ODM_RF_RADIO_PATH_E RF_PATH,
+                          u32 RegAddr
 );
 
 void odm_ConfigRF_RadioA_8723B(PDM_ODM_T pDM_Odm, u32 Addr, u32 Data);
 
 void odm_ConfigMAC_8723B(PDM_ODM_T pDM_Odm, u32 Addr, u8 Data);
 
-void odm_ConfigBB_AGC_8723B(
-       PDM_ODM_T pDM_Odm,
-       u32 Addr,
-       u32 Bitmask,
-       u32 Data
+void odm_ConfigBB_AGC_8723B(PDM_ODM_T pDM_Odm,
+                           u32 Addr,
+                           u32 Bitmask,
+                           u32 Data
 );
 
-void odm_ConfigBB_PHY_REG_PG_8723B(
-       PDM_ODM_T pDM_Odm,
-       u32 Band,
-       u32 RfPath,
-       u32 TxNum,
-       u32 Addr,
-       u32 Bitmask,
-       u32 Data
+void odm_ConfigBB_PHY_REG_PG_8723B(PDM_ODM_T pDM_Odm,
+                                  u32 Band,
+                                  u32 RfPath,
+                                  u32 TxNum,
+                                  u32 Addr,
+                                  u32 Bitmask,
+                                  u32 Data
 );
 
-void odm_ConfigBB_PHY_8723B(
-       PDM_ODM_T pDM_Odm,
-       u32 Addr,
-       u32 Bitmask,
-       u32 Data
+void odm_ConfigBB_PHY_8723B(PDM_ODM_T pDM_Odm,
+                           u32 Addr,
+                           u32 Bitmask,
+                           u32 Data
 );
 
-void odm_ConfigBB_TXPWR_LMT_8723B(
-       PDM_ODM_T pDM_Odm,
-       u8 *Regulation,
-       u8 *Band,
-       u8 *Bandwidth,
-       u8 *RateSection,
-       u8 *RfPath,
-       u8 *Channel,
-       u8 *PowerLimit
+void odm_ConfigBB_TXPWR_LMT_8723B(PDM_ODM_T pDM_Odm,
+                                 u8 *Regulation,
+                                 u8 *Band,
+                                 u8 *Bandwidth,
+                                 u8 *RateSection,
+                                 u8 *RfPath,
+                                 u8 *Channel,
+                                 u8 *PowerLimit
 );
 
 #endif
index b5b0c0e..d48d681 100644 (file)
@@ -29,7 +29,6 @@
 #include "odm_HWConfig.h"
 #include "odm_debug.h"
 #include "odm_RegDefine11N.h"
-#include "odm_AntDiv.h"
 #include "odm_EdcaTurboCheck.h"
 #include "odm_DIG.h"
 #include "odm_PathDiv.h"
index fe38911..080e974 100644 (file)
@@ -73,7 +73,7 @@ s32 FillH2CCmd8723B(struct adapter *padapter, u8 ElementID, u32 CmdLen, u8 *pCmd
                goto exit;
        }
 
-       if (padapter->bSurpriseRemoved == true)
+       if (padapter->bSurpriseRemoved)
                goto exit;
 
        /* pay attention to if  race condition happened in  H2C cmd setting. */
@@ -297,7 +297,7 @@ static void ConstructNullFunctionData(
 
        SetSeqNum(pwlanhdr, 0);
 
-       if (bQoS == true) {
+       if (bQoS) {
                struct ieee80211_qos_hdr *pwlanqoshdr;
 
                SetFrameSubType(pframe, WIFI_QOS_DATA_NULL);
@@ -436,7 +436,7 @@ static void ConstructARPResponse(
                DBG_871X("%s(): Add MIC\n", __func__);
 
                psta = rtw_get_stainfo(&padapter->stapriv, get_my_bssid(&(pmlmeinfo->network)));
-               if (psta != NULL) {
+               if (psta) {
                        if (!memcmp(&psta->dot11tkiptxmickey.skey[0], null_key, 16)) {
                                DBG_871X("%s(): STA dot11tkiptxmickey == 0\n", __func__);
                        }
@@ -674,10 +674,6 @@ static void ConstructProbeReq(struct adapter *padapter, u8 *pframe, u32 *pLength
        u32 pktlen;
        unsigned char *mac;
        unsigned char bssrate[NumRates];
-       struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
-       struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
-       struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
-       struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
        int bssrate_len = 0;
        u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 
@@ -757,7 +753,7 @@ static void ConstructProbeRsp(struct adapter *padapter, u8 *pframe, u32 *pLength
                        cur_network->IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen);
 
        /* inerset & update wps_probe_resp_ie */
-       if ((pmlmepriv->wps_probe_resp_ie != NULL) && pwps_ie && (wps_ielen > 0)) {
+       if (pmlmepriv->wps_probe_resp_ie && pwps_ie && (wps_ielen > 0)) {
                uint wps_offset, remainder_ielen;
                u8 *premainder_ie;
 
@@ -995,7 +991,7 @@ void rtl8723b_set_FwMacIdConfig_cmd(struct adapter *padapter, u8 mac_id, u8 raid
        FillH2CCmd8723B(padapter, H2C_8723B_MACID_CFG, H2C_MACID_CFG_LEN, u1H2CMacIdConfigParm);
 }
 
-static void rtl8723b_set_FwRssiSetting_cmd(struct adapter *padapter, u8 *param)
+void rtl8723b_set_rssi_cmd(struct adapter *padapter, u8 *param)
 {
        u8 u1H2CRssiSettingParm[H2C_RSSI_SETTING_LEN] = {0};
        u8 mac_id = *param;
@@ -1048,9 +1044,9 @@ void rtl8723b_set_FwPwrMode_cmd(struct adapter *padapter, u8 psmode)
        }
 
        if (psmode > 0) {
-               if (rtw_btcoex_IsBtControlLps(padapter) == true) {
-                       PowerState = rtw_btcoex_RpwmVal(padapter);
-                       byte5 = rtw_btcoex_LpsVal(padapter);
+               if (hal_btcoex_IsBtControlLps(padapter) == true) {
+                       PowerState = hal_btcoex_RpwmVal(padapter);
+                       byte5 = hal_btcoex_LpsVal(padapter);
 
                        if ((rlbm == 2) && (byte5 & BIT(4))) {
                                /*  Keep awake interval to 1 to prevent from */
@@ -1075,7 +1071,7 @@ void rtl8723b_set_FwPwrMode_cmd(struct adapter *padapter, u8 psmode)
        SET_8723B_H2CCMD_PWRMODE_PARM_PWR_STATE(u1H2CPwrModeParm, PowerState);
        SET_8723B_H2CCMD_PWRMODE_PARM_BYTE5(u1H2CPwrModeParm, byte5);
        if (psmode != PS_MODE_ACTIVE) {
-               if (pmlmeext->adaptive_tsf_done == false && pmlmeext->bcn_cnt > 0) {
+               if (!pmlmeext->adaptive_tsf_done && pmlmeext->bcn_cnt > 0) {
                        u8 ratio_20_delay, ratio_80_delay;
 
                        /* byte 6 for adaptive_early_32k */
@@ -1137,7 +1133,7 @@ void rtl8723b_set_FwPwrMode_cmd(struct adapter *padapter, u8 psmode)
 
        }
 
-       rtw_btcoex_RecordPwrMode(padapter, u1H2CPwrModeParm, H2C_PWRMODE_LEN);
+       hal_btcoex_RecordPwrMode(padapter, u1H2CPwrModeParm, H2C_PWRMODE_LEN);
 
        RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CPwrModeParm:", u1H2CPwrModeParm, H2C_PWRMODE_LEN);
 
@@ -1256,7 +1252,7 @@ static void rtl8723b_set_FwRemoteWakeCtrl_Cmd(struct adapter *padapter, u8 benab
        FillH2CCmd8723B(padapter, H2C_8723B_REMOTE_WAKE_CTRL,
                H2C_REMOTE_WAKE_CTRL_LEN, u1H2CRemoteWakeCtrlParm);
 #ifdef CONFIG_PNO_SUPPORT
-       if (ppwrpriv->wowlan_pno_enable && ppwrpriv->pno_in_resume == false) {
+       if (ppwrpriv->wowlan_pno_enable && !ppwrpriv->pno_in_resume) {
                res = rtw_read8(padapter, REG_PNO_STATUS);
                DBG_871X("cmd: 0x81 REG_PNO_STATUS: 0x%02x\n", res);
                while (!(res&BIT(7)) && count < 25) {
@@ -1288,8 +1284,6 @@ static void rtl8723b_set_FwAOACGlobalInfo_Cmd(struct adapter *padapter,  u8 grou
 static void rtl8723b_set_FwScanOffloadInfo_cmd(struct adapter *padapter, PRSVDPAGE_LOC rsvdpageloc, u8 enable)
 {
        u8 u1H2CScanOffloadInfoParm[H2C_SCAN_OFFLOAD_CTRL_LEN] = {0};
-       u8 res = 0, count = 0;
-       struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
 
        DBG_871X("%s: loc_probe_packet:%d, loc_scan_info: %d loc_ssid_info:%d\n",
                __func__, rsvdpageloc->LocProbePacket, rsvdpageloc->LocScanInfo, rsvdpageloc->LocSSIDInfo);
@@ -1322,7 +1316,7 @@ static void rtl8723b_set_FwWoWlanRelated_cmd(struct adapter *padapter, u8 enable
 
                if (!(ppwrpriv->wowlan_pno_enable)) {
                        psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(pmlmepriv));
-                       if (psta != NULL)
+                       if (psta)
                                rtl8723b_set_FwMediaStatusRpt_cmd(padapter, RT_MEDIA_CONNECT, psta->mac_id);
                } else
                        DBG_871X("%s(): Disconnected, no FwMediaStatusRpt CONNECT\n", __func__);
@@ -1440,7 +1434,6 @@ static void rtl8723b_set_FwRsvdPagePkt(
        struct adapter *padapter, bool bDLFinished
 )
 {
-       struct hal_com_data *pHalData;
        struct xmit_frame *pcmdframe;
        struct pkt_attrib *pattrib;
        struct xmit_priv *pxmitpriv;
@@ -1470,7 +1463,6 @@ static void rtl8723b_set_FwRsvdPagePkt(
 
        /* DBG_871X("%s---->\n", __func__); */
 
-       pHalData = GET_HAL_DATA(padapter);
        pxmitpriv = &padapter->xmitpriv;
        pmlmeext = &padapter->mlmeextpriv;
        pmlmeinfo = &pmlmeext->mlmext_info;
@@ -1677,7 +1669,7 @@ static void rtl8723b_set_FwRsvdPagePkt(
 #endif /* CONFIG_WOWLAN */
        {
 #ifdef CONFIG_PNO_SUPPORT
-               if (pwrctl->pno_in_resume == false && pwrctl->pno_inited == true) {
+               if (!pwrctl->pno_in_resume && pwrctl->pno_inited) {
                        /* Probe Request */
                        RsvdPageLoc.LocProbePacket = TotalPageNum;
                        ConstructProbeReq(
@@ -2036,11 +2028,6 @@ void rtl8723b_download_rsvd_page(struct adapter *padapter, u8 mstatus)
        }
 }
 
-void rtl8723b_set_rssi_cmd(struct adapter *padapter, u8 *param)
-{
-       rtl8723b_set_FwRssiSetting_cmd(padapter, param);
-}
-
 void rtl8723b_set_FwJoinBssRpt_cmd(struct adapter *padapter, u8 mstatus)
 {
        if (mstatus == 1)
@@ -2125,7 +2112,7 @@ static void ConstructBtNullFunctionData(
        SetDuration(pwlanhdr, 0);
        SetSeqNum(pwlanhdr, 0);
 
-       if (bQoS == true) {
+       if (bQoS) {
                struct ieee80211_qos_hdr *pwlanqoshdr;
 
                SetFrameSubType(pframe, WIFI_QOS_DATA_NULL);
@@ -2313,7 +2300,7 @@ void rtl8723b_download_BTCoex_AP_mode_rsvd_page(struct adapter *padapter)
                } while (!bcn_valid && (poll%10) != 0 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped);
        } while (!bcn_valid && (DLBcnCount <= 100) && !padapter->bSurpriseRemoved && !padapter->bDriverStopped);
 
-       if (true == bcn_valid) {
+       if (bcn_valid) {
                struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter);
                pwrctl->fw_psmode_iface_id = padapter->iface_id;
                DBG_8192C(ADPT_FMT": DL RSVD page success! DLBcnCount:%d, poll:%d\n",
index 6578147..c514cb7 100644 (file)
@@ -173,7 +173,7 @@ void rtl8723b_HalDmWatchDog(struct adapter *Adapter)
        if (hw_init_completed == true) {
                u8 bLinked = false;
                u8 bsta_state = false;
-               u8 bBtDisabled = true;
+               bool bBtDisabled = true;
 
                if (rtw_linked_check(Adapter)) {
                        bLinked = true;
@@ -186,7 +186,7 @@ void rtl8723b_HalDmWatchDog(struct adapter *Adapter)
 
                /* ODM_CmnInfoUpdate(&pHalData->odmpriv , ODM_CMNINFO_RSSI_MIN, pdmpriv->MinUndecoratedPWDBForDM); */
 
-               bBtDisabled = rtw_btcoex_IsBtDisabled(Adapter);
+               bBtDisabled = hal_btcoex_IsBtDisabled(Adapter);
 
                ODM_CmnInfoUpdate(&pHalData->odmpriv, ODM_CMNINFO_BT_ENABLED, ((bBtDisabled == true)?false:true));
 
index caa8e2f..faeaf24 100644 (file)
@@ -217,7 +217,7 @@ void _8051Reset8723(struct adapter *padapter)
        DBG_8192C("%s: Finish\n", __func__);
 }
 
-u8 g_fwdl_chksum_fail = 0;
+u8 g_fwdl_chksum_fail;
 
 static s32 polling_fwdl_chksum(
        struct adapter *adapter, u32 min_cnt, u32 timeout_ms
@@ -262,7 +262,7 @@ exit:
        return ret;
 }
 
-u8 g_fwdl_wintint_rdy_fail = 0;
+u8 g_fwdl_wintint_rdy_fail;
 
 static s32 _FWFreeToGo(struct adapter *adapter, u32 min_cnt, u32 timeout_ms)
 {
@@ -742,7 +742,7 @@ static void Hal_BT_EfusePowerSwitch(
 )
 {
        u8 tempval;
-       if (PwrState == true) {
+       if (PwrState) {
                /*  enable BT power cut */
                /*  0x6A[14] = 1 */
                tempval = rtw_read8(padapter, 0x6B);
@@ -783,7 +783,7 @@ static void Hal_EfusePowerSwitch(
        u16 tmpV16;
 
 
-       if (PwrState == true) {
+       if (PwrState) {
                /*  To avoid cannot access efuse regsiters after disable/enable several times during DTM test. */
                /*  Suggested by SD1 IsaacHsu. 2013.07.08, added by tynli. */
                tempval = rtw_read8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HSUS_CTRL);
@@ -833,7 +833,7 @@ static void Hal_EfusePowerSwitch(
                        rtw_write16(padapter, REG_SYS_CLKR, tmpV16);
                }
 
-               if (bWrite == true) {
+               if (bWrite) {
                        /*  Enable LDO 2.5V before read/write action */
                        tempval = rtw_read8(padapter, EFUSE_TEST+3);
                        tempval &= 0x0F;
@@ -845,7 +845,7 @@ static void Hal_EfusePowerSwitch(
        } else {
                rtw_write8(padapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_OFF);
 
-               if (bWrite == true) {
+               if (bWrite) {
                        /*  Disable LDO 2.5V after read/write action */
                        tempval = rtw_read8(padapter, EFUSE_TEST+3);
                        rtw_write8(padapter, EFUSE_TEST+3, (tempval & 0x7F));
@@ -1023,7 +1023,7 @@ static void hal_ReadEFuse_BT(
        }
 
        efuseTbl = rtw_malloc(EFUSE_BT_MAP_LEN);
-       if (efuseTbl == NULL) {
+       if (!efuseTbl) {
                DBG_8192C("%s: efuseTbl malloc fail!\n", __func__);
                return;
        }
@@ -2139,7 +2139,7 @@ static void UpdateHalRAMask8723B(struct adapter *padapter, u32 mac_id, u8 rssi_l
                return;
 
        psta = pmlmeinfo->FW_sta_info[mac_id].psta;
-       if (psta == NULL)
+       if (!psta)
                return;
 
        shortGIrate = query_ra_short_GI(psta);
@@ -2153,7 +2153,7 @@ static void UpdateHalRAMask8723B(struct adapter *padapter, u32 mac_id, u8 rssi_l
 
        mask &= rate_bitmap;
 
-       rate_bitmap = rtw_btcoex_GetRaMask(padapter);
+       rate_bitmap = hal_btcoex_GetRaMask(padapter);
        mask &= ~rate_bitmap;
 
 #ifdef CONFIG_CMCC_TEST
@@ -2166,7 +2166,7 @@ static void UpdateHalRAMask8723B(struct adapter *padapter, u32 mac_id, u8 rssi_l
        }
 #endif
 
-       if (pHalData->fw_ractrl == true) {
+       if (pHalData->fw_ractrl) {
                rtl8723b_set_FwMacIdConfig_cmd(padapter, mac_id, psta->raid, psta->bw_mode, shortGIrate, mask);
        }
 
@@ -2428,7 +2428,7 @@ void Hal_InitPGData(struct adapter *padapter, u8 *PROMContent)
 {
        struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
 
-       if (false == pEEPROM->bautoload_fail_flag) { /*  autoload OK. */
+       if (!pEEPROM->bautoload_fail_flag) { /*  autoload OK. */
                if (!pEEPROM->EepromOrEfuse) {
                        /*  Read EFUSE real map to shadow. */
                        EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, false);
@@ -2436,7 +2436,7 @@ void Hal_InitPGData(struct adapter *padapter, u8 *PROMContent)
                }
        } else {/* autoload fail */
                RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("AutoLoad Fail reported from CR9346!!\n"));
-               if (false == pEEPROM->EepromOrEfuse)
+               if (!pEEPROM->EepromOrEfuse)
                        EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, false);
                memcpy((void *)PROMContent, (void *)pEEPROM->efuse_eeprom_data, HWSET_MAX_SIZE_8723B);
        }
@@ -2694,11 +2694,11 @@ void Hal_EfuseParseBTCoexistInfo_8723B(
                }
        }
 
-       rtw_btcoex_SetBTCoexist(padapter, pHalData->EEPROMBluetoothCoexist);
-       rtw_btcoex_SetChipType(padapter, pHalData->EEPROMBluetoothType);
-       rtw_btcoex_SetPGAntNum(padapter, pHalData->EEPROMBluetoothAntNum == Ant_x2 ? 2 : 1);
+       hal_btcoex_SetBTCoexist(padapter, pHalData->EEPROMBluetoothCoexist);
+       hal_btcoex_SetChipType(padapter, pHalData->EEPROMBluetoothType);
+       hal_btcoex_SetPgAntNum(padapter, pHalData->EEPROMBluetoothAntNum == Ant_x2 ? 2 : 1);
        if (pHalData->EEPROMBluetoothAntNum == Ant_x1)
-               rtw_btcoex_SetSingleAntPath(padapter, pHalData->ant_path);
+               hal_btcoex_SetSingleAntPath(padapter, pHalData->ant_path);
 
        DBG_8192C(
                "%s: %s BT-coex, ant_num =%d\n",
@@ -2842,12 +2842,12 @@ void Hal_EfuseParseThermalMeter_8723B(
        /*  */
        /*  ThermalMeter from EEPROM */
        /*  */
-       if (false == AutoLoadFail)
+       if (!AutoLoadFail)
                pHalData->EEPROMThermalMeter = PROMContent[EEPROM_THERMAL_METER_8723B];
        else
                pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_8723B;
 
-       if ((pHalData->EEPROMThermalMeter == 0xff) || (true == AutoLoadFail)) {
+       if ((pHalData->EEPROMThermalMeter == 0xff) || AutoLoadFail) {
                pHalData->bAPKThermalMeterIgnore = true;
                pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_8723B;
        }
@@ -3094,12 +3094,12 @@ static void rtl8723b_fill_default_txdesc(
                        (pattrib->dhcp_pkt != 1) &&
                        (drv_userate != 1)
 #ifdef CONFIG_AUTO_AP_MODE
-                       && (pattrib->pctrl != true)
+                       && (!pattrib->pctrl)
 #endif
                ) {
                        /*  Non EAP & ARP & DHCP type data packet */
 
-                       if (pattrib->ampdu_en == true) {
+                       if (pattrib->ampdu_en) {
                                ptxdesc->agg_en = 1; /*  AGG EN */
                                ptxdesc->max_agg_num = 0x1f;
                                ptxdesc->ampdu_density = pattrib->ampdu_spacing;
@@ -3110,7 +3110,7 @@ static void rtl8723b_fill_default_txdesc(
 
                        ptxdesc->data_ratefb_lmt = 0x1F;
 
-                       if (pHalData->fw_ractrl == false) {
+                       if (!pHalData->fw_ractrl) {
                                ptxdesc->userate = 1;
 
                                if (pHalData->dmpriv.INIDATA_RATE[pattrib->mac_id] & BIT(7))
@@ -3162,7 +3162,7 @@ static void rtl8723b_fill_default_txdesc(
                ptxdesc->mbssid = pattrib->mbssid & 0xF;
 
                ptxdesc->rty_lmt_en = 1; /*  retry limit enable */
-               if (pattrib->retry_ctrl == true) {
+               if (pattrib->retry_ctrl) {
                        ptxdesc->data_rt_lmt = 6;
                } else {
                        ptxdesc->data_rt_lmt = 12;
@@ -3265,14 +3265,14 @@ void rtl8723b_fill_fake_txdesc(
        SET_TX_DESC_QUEUE_SEL_8723B(pDesc, QSLT_MGNT); /*  Fixed queue of Mgnt queue */
 
        /*  Set NAVUSEHDR to prevent Ps-poll AId filed to be changed to error vlaue by Hw. */
-       if (true == IsPsPoll) {
+       if (IsPsPoll) {
                SET_TX_DESC_NAV_USE_HDR_8723B(pDesc, 1);
        } else {
                SET_TX_DESC_HWSEQ_EN_8723B(pDesc, 1); /*  Hw set sequence number */
                SET_TX_DESC_HWSEQ_SEL_8723B(pDesc, 0);
        }
 
-       if (true == IsBTQosNull) {
+       if (IsBTQosNull) {
                SET_TX_DESC_BT_INT_8723B(pDesc, 1);
        }
 
@@ -3284,7 +3284,7 @@ void rtl8723b_fill_fake_txdesc(
        /*  */
        /*  Encrypt the data frame if under security mode excepct null data. Suggested by CCW. */
        /*  */
-       if (true == bDataFrame) {
+       if (bDataFrame) {
                u32 EncAlg;
 
                EncAlg = padapter->securitypriv.dot11PrivacyAlgrthm;
@@ -3463,7 +3463,7 @@ static void hw_var_set_correct_tsf(struct adapter *padapter, u8 variable, u8 *va
        pmlmeext = &padapter->mlmeextpriv;
        pmlmeinfo = &pmlmeext->mlmext_info;
 
-       tsf = pmlmeext->TSFValue-rtw_modular64(pmlmeext->TSFValue, (pmlmeinfo->bcn_interval*1024))-1024; /* us */
+       tsf = pmlmeext->TSFValue-do_div(pmlmeext->TSFValue, (pmlmeinfo->bcn_interval*1024))-1024; /* us */
 
        if (
                ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) ||
@@ -3579,14 +3579,12 @@ static void hw_var_set_mlme_join(struct adapter *padapter, u8 variable, u8 *val)
        u32 val32;
        u8 RetryLimit;
        u8 type;
-       struct hal_com_data *pHalData;
        struct mlme_priv *pmlmepriv;
        struct eeprom_priv *pEEPROM;
 
 
        RetryLimit = 0x30;
        type = *(u8 *)val;
-       pHalData = GET_HAL_DATA(padapter);
        pmlmepriv = &padapter->mlmepriv;
        pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
 
@@ -3695,7 +3693,7 @@ s32 c2h_handler_8723b(struct adapter *padapter, u8 *buf)
                break;
 
        case C2H_8723B_BT_INFO:
-               rtw_btcoex_BtInfoNotify(padapter, pC2hEvent->plen, pC2hEvent->payload);
+               hal_btcoex_BtInfoNotify(padapter, pC2hEvent->plen, pC2hEvent->payload);
                break;
 
        default:
@@ -3744,7 +3742,7 @@ static void process_c2h_event(struct adapter *padapter, PC2H_EVT_HDR pC2hEvent,
                break;
 
        case C2H_8723B_BT_INFO:
-               rtw_btcoex_BtInfoNotify(padapter, pC2hEvent->CmdLen, c2hBuf);
+               hal_btcoex_BtInfoNotify(padapter, pC2hEvent->CmdLen, c2hBuf);
                break;
 
        default:
@@ -3759,7 +3757,7 @@ void C2HPacketHandler_8723B(struct adapter *padapter, u8 *pbuffer, u16 length)
 #ifdef CONFIG_WOWLAN
        struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
 
-       if (pwrpriv->wowlan_mode == true) {
+       if (pwrpriv->wowlan_mode) {
                DBG_871X("%s(): return because wowolan_mode ==true! CMDID =%d\n", __func__, pbuffer[0]);
                return;
        }
@@ -3878,7 +3876,7 @@ void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val)
        case HW_VAR_MLME_SITESURVEY:
                hw_var_set_mlme_sitesurvey(padapter, variable,  val);
 
-               rtw_btcoex_ScanNotify(padapter, *val?true:false);
+               hal_btcoex_ScanNotify(padapter, *val?true:false);
                break;
 
        case HW_VAR_MLME_JOIN:
@@ -3887,11 +3885,11 @@ void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val)
                switch (*val) {
                case 0:
                        /*  prepare to join */
-                       rtw_btcoex_ConnectNotify(padapter, true);
+                       hal_btcoex_ConnectNotify(padapter, true);
                        break;
                case 1:
                        /*  joinbss_event callback when join res < 0 */
-                       rtw_btcoex_ConnectNotify(padapter, false);
+                       hal_btcoex_ConnectNotify(padapter, false);
                        break;
                case 2:
                        /*  sta add event callback */
@@ -4119,7 +4117,7 @@ void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val)
                        /*  keep sn */
                        padapter->xmitpriv.nqos_ssn = rtw_read16(padapter, REG_NQOS_SEQ);
 
-                       if (pwrpriv->bkeepfwalive != true) {
+                       if (!pwrpriv->bkeepfwalive) {
                                /* RX DMA stop */
                                val32 = rtw_read32(padapter, REG_RXPKT_NUM);
                                val32 |= RW_RELEASE_EN;
@@ -4274,7 +4272,7 @@ void GetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val)
                        u32 valRCR;
 
                        if (
-                               (padapter->bSurpriseRemoved == true) ||
+                               padapter->bSurpriseRemoved  ||
                                (adapter_to_pwrctl(padapter)->rf_pwrstate == rf_off)
                        ) {
                                /*  If it is in HW/SW Radio OFF or IPS state, we do not check Fw LPS Leave, */
@@ -4345,11 +4343,8 @@ void GetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val)
  */
 u8 SetHalDefVar8723B(struct adapter *padapter, enum HAL_DEF_VARIABLE variable, void *pval)
 {
-       struct hal_com_data *pHalData;
        u8 bResult;
 
-
-       pHalData = GET_HAL_DATA(padapter);
        bResult = _SUCCESS;
 
        switch (variable) {
@@ -4367,11 +4362,8 @@ u8 SetHalDefVar8723B(struct adapter *padapter, enum HAL_DEF_VARIABLE variable, v
  */
 u8 GetHalDefVar8723B(struct adapter *padapter, enum HAL_DEF_VARIABLE variable, void *pval)
 {
-       struct hal_com_data *pHalData;
        u8 bResult;
 
-
-       pHalData = GET_HAL_DATA(padapter);
        bResult = _SUCCESS;
 
        switch (variable) {
index 4f2ad54..25c75b9 100644 (file)
@@ -45,7 +45,7 @@ static        u32 phy_CalculateBitShift(u32 BitMask)
 /**
 * Function:    PHY_QueryBBReg
 *
-* OverView:    Read "sepcific bits" from BB register
+* OverView:    Read "specific bits" from BB register
 *
 * Input:
 *              struct adapter *        Adapter,
@@ -375,7 +375,7 @@ s32 PHY_MACConfig8723B(struct adapter *Adapter)
        /*  */
        rtStatus = phy_ConfigMACWithParaFile(Adapter, pszMACRegFile);
        if (rtStatus == _FAIL) {
-               ODM_ConfigMACWithHeaderFile(&pHalData->odmpriv);
+               ODM_ReadAndConfig_MP_8723B_MAC_REG(&pHalData->odmpriv);
                rtStatus = _SUCCESS;
        }
 
index aa45a84..d0ffe0a 100644 (file)
@@ -114,12 +114,12 @@ static int phy_RF6052_Config_ParaFile(struct adapter *Adapter)
                        break;
                case RF_PATH_B:
                case RF_PATH_D:
-                       u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16);
+                       u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV << 16);
                        break;
                }
 
                /*----Set RF_ENV enable----*/
-               PHY_SetBBReg(Adapter, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1);
+               PHY_SetBBReg(Adapter, pPhyReg->rfintfe, bRFSI_RFENV << 16, 0x1);
                udelay(1);/* PlatformStallExecution(1); */
 
                /*----Set RF_ENV output high----*/
@@ -163,7 +163,7 @@ static int phy_RF6052_Config_ParaFile(struct adapter *Adapter)
                        break;
                case RF_PATH_B:
                case RF_PATH_D:
-                       PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16, u4RegValue);
+                       PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV << 16, u4RegValue);
                        break;
                }
 
@@ -194,7 +194,6 @@ phy_RF6052_Config_ParaFile_Fail:
 int PHY_RF6052_Config8723B(struct adapter *Adapter)
 {
        struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
-       int rtStatus = _SUCCESS;
 
        /*  */
        /*  Initialize general global value */
@@ -208,8 +207,7 @@ int PHY_RF6052_Config8723B(struct adapter *Adapter)
        /*  */
        /*  Config BB and RF */
        /*  */
-       rtStatus = phy_RF6052_Config_ParaFile(Adapter);
-       return rtStatus;
+       return phy_RF6052_Config_ParaFile(Adapter);
 
 }
 
index b269de5..e23b39a 100644 (file)
 #include <rtw_debug.h>
 #include <rtl8723b_hal.h>
 
-static s32 initrecvbuf(struct recv_buf *precvbuf, struct adapter *padapter)
+static void initrecvbuf(struct recv_buf *precvbuf, struct adapter *padapter)
 {
        INIT_LIST_HEAD(&precvbuf->list);
        spin_lock_init(&precvbuf->recvbuf_lock);
 
        precvbuf->adapter = padapter;
-
-       return _SUCCESS;
 }
 
 static void update_recvframe_attrib(struct adapter *padapter,
@@ -177,7 +175,7 @@ static void rtl8723bs_c2h_packet_handler(struct adapter *padapter,
 
        res = rtw_c2h_packet_wk_cmd(padapter, tmp, length);
 
-       if (res == false)
+       if (!res)
                kfree(tmp);
 
        /* DBG_871X("-%s res(%d)\n", __func__, res); */
@@ -435,9 +433,7 @@ s32 rtl8723bs_init_recv_priv(struct adapter *padapter)
        /*  init each recv buffer */
        precvbuf = (struct recv_buf *)precvpriv->precv_buf;
        for (i = 0; i < NR_RECVBUFF; i++) {
-               res = initrecvbuf(precvbuf, padapter);
-               if (res == _FAIL)
-                       break;
+               initrecvbuf(precvbuf, padapter);
 
                if (!precvbuf->pskb) {
                        SIZE_PTR tmpaddr = 0;
index 7b06aab..b44e902 100644 (file)
@@ -17,8 +17,8 @@ static u8 rtw_sdio_wait_enough_TxOQT_space(struct adapter *padapter, u8 agg_num)
 
        while (pHalData->SdioTxOQTFreeSpace < agg_num) {
                if (
-                       (padapter->bSurpriseRemoved == true) ||
-                       (padapter->bDriverStopped == true)
+                       (padapter->bSurpriseRemoved) ||
+                       (padapter->bDriverStopped)
                ) {
                        DBG_871X("%s: bSurpriseRemoved or bDriverStopped (wait TxOQT)\n", __func__);
                        return false;
@@ -58,7 +58,7 @@ static s32 rtl8723_dequeue_writeport(struct adapter *padapter)
 
        ret = ret || check_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
 
-       if (ret == true)
+       if (ret)
                pxmitbuf = dequeue_pending_xmitbuf_under_survey(pxmitpriv);
        else
                pxmitbuf = dequeue_pending_xmitbuf(pxmitpriv);
@@ -85,7 +85,7 @@ static s32 rtl8723_dequeue_writeport(struct adapter *padapter)
 
 query_free_page:
        /*  check if hardware tx fifo page is enough */
-       if (false == rtw_hal_sdio_query_tx_freepage(pri_padapter, PageIdx, pxmitbuf->pg_num)) {
+       if (!rtw_hal_sdio_query_tx_freepage(pri_padapter, PageIdx, pxmitbuf->pg_num)) {
                if (!bUpdatePageNum) {
                        /*  Total number of page is NOT available, so update current FIFO status */
                        HalQueryTxBufferStatus8723BSdio(padapter);
@@ -99,8 +99,8 @@ query_free_page:
        }
 
        if (
-               (padapter->bSurpriseRemoved == true) ||
-               (padapter->bDriverStopped == true)
+               (padapter->bSurpriseRemoved) ||
+               (padapter->bDriverStopped)
        ) {
                RT_TRACE(
                        _module_hal_xmit_c_,
@@ -153,7 +153,7 @@ s32 rtl8723bs_xmit_buf_handler(struct adapter *padapter)
                return _FAIL;
        }
 
-       ret = (padapter->bDriverStopped == true) || (padapter->bSurpriseRemoved == true);
+       ret = (padapter->bDriverStopped) || (padapter->bSurpriseRemoved);
        if (ret) {
                RT_TRACE(
                        _module_hal_xmit_c_,
@@ -170,7 +170,7 @@ s32 rtl8723bs_xmit_buf_handler(struct adapter *padapter)
 
        queue_pending = check_pending_xmitbuf(pxmitpriv);
 
-       if (queue_pending == false)
+       if (!queue_pending)
                return _SUCCESS;
 
        ret = rtw_register_tx_alive(padapter);
@@ -202,7 +202,7 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv
        s32 err, ret;
        u32 k = 0;
        struct hw_xmit *hwxmits, *phwxmit;
-       u8 no_res, idx, hwentry;
+       u8 idx, hwentry;
        struct tx_servq *ptxservq;
        struct list_head *sta_plist, *sta_phead, *frame_plist, *frame_phead;
        struct xmit_frame *pxmitframe;
@@ -213,7 +213,6 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv
        int inx[4];
 
        err = 0;
-       no_res = false;
        hwxmits = pxmitpriv->hwxmits;
        hwentry = pxmitpriv->hwxmit_entry;
        ptxservq = NULL;
@@ -236,8 +235,8 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv
                phwxmit = hwxmits + inx[idx];
 
                if (
-                       (check_pending_xmitbuf(pxmitpriv) == true) &&
-                       (padapter->mlmepriv.LinkDetectInfo.bHigherBusyTxTraffic == true)
+                       (check_pending_xmitbuf(pxmitpriv)) &&
+                       (padapter->mlmepriv.LinkDetectInfo.bHigherBusyTxTraffic)
                ) {
                        if ((phwxmit->accnt > 0) && (phwxmit->accnt < 5)) {
                                err = -2;
@@ -285,7 +284,7 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv
                                txlen = txdesc_size + rtw_wlan_pkt_size(pxmitframe);
                                if(     !pxmitbuf ||
                                        ((_RND(pxmitbuf->len, 8) + txlen) > max_xmit_len) ||
-                                       (k >= (rtw_hal_sdio_max_txoqt_free_space(padapter)-1))
+                                       (k >= (rtw_hal_sdio_max_txoqt_free_space(padapter) - 1))
                                ) {
                                        if (pxmitbuf) {
                                                /* pxmitbuf->priv_data will be NULL, and will crash here */
@@ -356,8 +355,8 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv
                                        rtw_count_tx_stats(padapter, pxmitframe, pxmitframe->attrib.last_txcmdsz);
 
                                        txlen = txdesc_size + pxmitframe->attrib.last_txcmdsz;
-                                       pxmitframe->pg_num = (txlen + 127)/128;
-                                       pxmitbuf->pg_num += (txlen + 127)/128;
+                                       pxmitframe->pg_num = (txlen + 127) / 128;
+                                       pxmitbuf->pg_num += (txlen + 127) / 128;
                                    /* if (k != 1) */
                                        /*      ((struct xmit_frame*)pxmitbuf->priv_data)->pg_num += pxmitframe->pg_num; */
                                        pxmitbuf->ptail += _RND(txlen, 8); /*  round to 8 bytes alignment */
@@ -426,8 +425,8 @@ static s32 rtl8723bs_xmit_handler(struct adapter *padapter)
 
 next:
        if (
-               (padapter->bDriverStopped == true) ||
-               (padapter->bSurpriseRemoved == true)
+               (padapter->bDriverStopped) ||
+               (padapter->bSurpriseRemoved)
        ) {
                RT_TRACE(
                        _module_hal_xmit_c_,
@@ -523,7 +522,7 @@ s32 rtl8723bs_mgnt_xmit(
        rtl8723b_update_txdesc(pmgntframe, pmgntframe->buf_addr);
 
        pxmitbuf->len = txdesc_size + pattrib->last_txcmdsz;
-       pxmitbuf->pg_num = (pxmitbuf->len + 127)/128; /*  128 is tx page size */
+       pxmitbuf->pg_num = (pxmitbuf->len + 127) / 128; /*  128 is tx page size */
        pxmitbuf->ptail = pmgntframe->buf_addr + pxmitbuf->len;
        pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pmgntframe);
 
@@ -570,7 +569,7 @@ s32 rtl8723bs_hal_xmit(
                (pxmitframe->attrib.ether_type != 0x888e) &&
                (pxmitframe->attrib.dhcp_pkt != 1)
        ) {
-               if (padapter->mlmepriv.LinkDetectInfo.bBusyTraffic == true)
+               if (padapter->mlmepriv.LinkDetectInfo.bBusyTraffic)
                        rtw_issue_addbareq_cmd(padapter, pxmitframe);
        }
 
@@ -637,7 +636,6 @@ s32 rtl8723bs_init_xmit_priv(struct adapter *padapter)
 
 void rtl8723bs_free_xmit_priv(struct adapter *padapter)
 {
-       struct hal_com_data *phal;
        struct xmit_priv *pxmitpriv;
        struct xmit_buf *pxmitbuf;
        struct __queue *pqueue;
@@ -645,7 +643,6 @@ void rtl8723bs_free_xmit_priv(struct adapter *padapter)
        struct list_head tmplist;
 
 
-       phal = GET_HAL_DATA(padapter);
        pxmitpriv = &padapter->xmitpriv;
        pqueue = &pxmitpriv->pending_xmitbuf_queue;
        phead = get_list_head(pqueue);
index 3c65a9c..0f5dd46 100644 (file)
@@ -26,7 +26,7 @@ static u8 CardEnable(struct adapter *padapter)
 
 
        rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
-       if (bMacPwrCtrlOn == false) {
+       if (!bMacPwrCtrlOn) {
                /*  RSV_CTRL 0x1C[7:0] = 0x00 */
                /*  unlock ISO/CLK/Power control register */
                rtw_write8(padapter, REG_RSV_CTRL, 0x0);
@@ -112,22 +112,22 @@ u8 _InitPowerOn_8723BS(struct adapter *padapter)
        /*  all of these MUST be configured before power on */
 #ifdef CONFIG_EXT_CLK
        /*  Use external crystal(XTAL) */
-       value8 = rtw_read8(padapter, REG_PAD_CTRL1_8723B+2);
+       value8 = rtw_read8(padapter, REG_PAD_CTRL1_8723B + 2);
        value8 |=  BIT(7);
-       rtw_write8(padapter, REG_PAD_CTRL1_8723B+2, value8);
+       rtw_write8(padapter, REG_PAD_CTRL1_8723B + 2, value8);
 
        /*  CLK_REQ High active or Low Active */
        /*  Request GPIO polarity: */
        /*  0: low active */
        /*  1: high active */
-       value8 = rtw_read8(padapter, REG_MULTI_FUNC_CTRL+1);
+       value8 = rtw_read8(padapter, REG_MULTI_FUNC_CTRL + 1);
        value8 |= BIT(5);
-       rtw_write8(padapter, REG_MULTI_FUNC_CTRL+1, value8);
+       rtw_write8(padapter, REG_MULTI_FUNC_CTRL + 1, value8);
 #endif /*  CONFIG_EXT_CLK */
 
        /*  only cmd52 can be used before power on(card enable) */
        ret = CardEnable(padapter);
-       if (ret == false) {
+       if (!ret) {
                RT_TRACE(
                        _module_hci_hal_init_c_,
                        _drv_emerg_,
@@ -137,12 +137,12 @@ u8 _InitPowerOn_8723BS(struct adapter *padapter)
        }
 
        /*  Radio-Off Pin Trigger */
-       value8 = rtw_read8(padapter, REG_GPIO_INTM+1);
+       value8 = rtw_read8(padapter, REG_GPIO_INTM + 1);
        value8 |= BIT(1); /*  Enable falling edge triggering interrupt */
-       rtw_write8(padapter, REG_GPIO_INTM+1, value8);
-       value8 = rtw_read8(padapter, REG_GPIO_IO_SEL_2+1);
+       rtw_write8(padapter, REG_GPIO_INTM + 1, value8);
+       value8 = rtw_read8(padapter, REG_GPIO_IO_SEL_2 + 1);
        value8 |= BIT(1);
-       rtw_write8(padapter, REG_GPIO_IO_SEL_2+1, value8);
+       rtw_write8(padapter, REG_GPIO_IO_SEL_2 + 1, value8);
 
        /*  Enable power down and GPIO interrupt */
        value16 = rtw_read16(padapter, REG_APS_FSMCO);
@@ -168,7 +168,7 @@ u8 _InitPowerOn_8723BS(struct adapter *padapter)
        );
        rtw_write16(padapter, REG_CR, value16);
 
-       rtw_btcoex_PowerOnSetting(padapter);
+       hal_btcoex_PowerOnSetting(padapter);
 
        /*  external switch to S1 */
        /*  0x38[11] = 0x1 */
@@ -203,13 +203,13 @@ static void _init_available_page_threshold(struct adapter *padapter, u8 numHQ, u
        u16 HQ_threshold, NQ_threshold, LQ_threshold;
 
        HQ_threshold = (numPubQ + numHQ + 1) >> 1;
-       HQ_threshold |= (HQ_threshold<<8);
+       HQ_threshold |= (HQ_threshold << 8);
 
        NQ_threshold = (numPubQ + numNQ + 1) >> 1;
-       NQ_threshold |= (NQ_threshold<<8);
+       NQ_threshold |= (NQ_threshold << 8);
 
        LQ_threshold = (numPubQ + numLQ + 1) >> 1;
-       LQ_threshold |= (LQ_threshold<<8);
+       LQ_threshold |= (LQ_threshold << 8);
 
        rtw_write16(padapter, 0x218, HQ_threshold);
        rtw_write16(padapter, 0x21A, NQ_threshold);
@@ -271,7 +271,7 @@ static void _InitTxBufferBoundary(struct adapter *padapter)
        rtw_write8(padapter, REG_TXPKTBUF_MGQ_BDNY_8723B, txpktbuf_bndy);
        rtw_write8(padapter, REG_TXPKTBUF_WMAC_LBK_BF_HD_8723B, txpktbuf_bndy);
        rtw_write8(padapter, REG_TRXFF_BNDY, txpktbuf_bndy);
-       rtw_write8(padapter, REG_TDECTRL+1, txpktbuf_bndy);
+       rtw_write8(padapter, REG_TDECTRL + 1, txpktbuf_bndy);
 }
 
 static void _InitNormalChipRegPriority(
@@ -397,7 +397,7 @@ static void _InitNormalChipThreeOutEpPriority(struct adapter *padapter)
        _InitNormalChipRegPriority(padapter, beQ, bkQ, viQ, voQ, mgtQ, hiQ);
 }
 
-static void _InitNormalChipQueuePriority(struct adapter *Adapter)
+static void _InitQueuePriority(struct adapter *Adapter)
 {
        struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
 
@@ -419,11 +419,6 @@ static void _InitNormalChipQueuePriority(struct adapter *Adapter)
 
 }
 
-static void _InitQueuePriority(struct adapter *padapter)
-{
-       _InitNormalChipQueuePriority(padapter);
-}
-
 static void _InitPageBoundary(struct adapter *padapter)
 {
        /*  RX Page Boundary */
@@ -569,7 +564,7 @@ static void HalRxAggr8723BSdio(struct adapter *padapter)
                valueDMAPageCount = 0x06;
        }
 
-       rtw_write8(padapter, REG_RXDMA_AGG_PG_TH+1, valueDMATimeout);
+       rtw_write8(padapter, REG_RXDMA_AGG_PG_TH + 1, valueDMATimeout);
        rtw_write8(padapter, REG_RXDMA_AGG_PG_TH, valueDMAPageCount);
 }
 
@@ -588,8 +583,8 @@ static void sdio_AggSettingRxUpdate(struct adapter *padapter)
        rtw_write8(padapter, REG_TRXDMA_CTRL, valueDMA);
 
        valueRxAggCtrl |= RXDMA_AGG_MODE_EN;
-       valueRxAggCtrl |= ((aggBurstNum<<2) & 0x0C);
-       valueRxAggCtrl |= ((aggBurstSize<<4) & 0x30);
+       valueRxAggCtrl |= ((aggBurstNum << 2) & 0x0C);
+       valueRxAggCtrl |= ((aggBurstSize << 4) & 0x30);
        rtw_write8(padapter, REG_RXDMA_MODE_CTRL_8723B, valueRxAggCtrl);/* RxAggLowThresh = 4*1K */
 }
 
@@ -611,12 +606,9 @@ static void _initSdioAggregationSetting(struct adapter *padapter)
 
 static void _InitOperationMode(struct adapter *padapter)
 {
-       struct hal_com_data *pHalData;
        struct mlme_ext_priv *pmlmeext;
        u8 regBwOpMode = 0;
-       u32 regRATR = 0, regRRSR = 0;
 
-       pHalData = GET_HAL_DATA(padapter);
        pmlmeext = &padapter->mlmeextpriv;
 
        /* 1 This part need to modified according to the rate set we filtered!! */
@@ -626,34 +618,24 @@ static void _InitOperationMode(struct adapter *padapter)
        switch (pmlmeext->cur_wireless_mode) {
        case WIRELESS_MODE_B:
                regBwOpMode = BW_OPMODE_20MHZ;
-               regRATR = RATE_ALL_CCK;
-               regRRSR = RATE_ALL_CCK;
                break;
        case WIRELESS_MODE_A:
 /*                     RT_ASSERT(false, ("Error wireless a mode\n")); */
                break;
        case WIRELESS_MODE_G:
                regBwOpMode = BW_OPMODE_20MHZ;
-               regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
-               regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
                break;
        case WIRELESS_MODE_AUTO:
                regBwOpMode = BW_OPMODE_20MHZ;
-               regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
-               regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
                break;
        case WIRELESS_MODE_N_24G:
                /*  It support CCK rate by default. */
                /*  CCK rate will be filtered out only when associated AP does not support it. */
                regBwOpMode = BW_OPMODE_20MHZ;
-               regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
-               regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
                break;
        case WIRELESS_MODE_N_5G:
 /*                     RT_ASSERT(false, ("Error wireless mode")); */
                regBwOpMode = BW_OPMODE_5G;
-               regRATR = RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
-               regRRSR = RATE_ALL_OFDM_AG;
                break;
 
        default: /* for MacOSX compiler warning. */
@@ -754,11 +736,11 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter)
                rtw_hal_get_hwreg(padapter, HW_VAR_CPWM, &cpwm_orig);
 
                /* ser rpwm */
-               val8 = rtw_read8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HRPWM1);
+               val8 = rtw_read8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HRPWM1);
                val8 &= 0x80;
                val8 += 0x80;
                val8 |= BIT(6);
-               rtw_write8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HRPWM1, val8);
+               rtw_write8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HRPWM1, val8);
                DBG_871X("%s: write rpwm =%02x\n", __func__, val8);
                adapter_to_pwrctl(padapter)->tog = (val8 + 0x80) & 0x80;
 
@@ -782,13 +764,13 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter)
 
                rtw_hal_set_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
 
-               rtw_btcoex_HAL_Initialize(padapter, false);
+               hal_btcoex_InitHwConfig(padapter, false);
 
                return _SUCCESS;
        }
 
 #ifdef CONFIG_WOWLAN
-       if (rtw_read8(padapter, REG_MCUFWDL)&BIT7) {
+       if (rtw_read8(padapter, REG_MCUFWDL) & BIT7) {
                u8 reg_val = 0;
                DBG_871X("+Reset Entry+\n");
                rtw_write8(padapter, REG_MCUFWDL, 0x00);
@@ -802,12 +784,12 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter)
                /* reset TRX path */
                rtw_write16(padapter, REG_CR, 0);
                /* reset MAC, Digital Core */
-               reg_val = rtw_read8(padapter, REG_SYS_FUNC_EN+1);
+               reg_val = rtw_read8(padapter, REG_SYS_FUNC_EN + 1);
                reg_val &= ~(BIT(4) | BIT(7));
-               rtw_write8(padapter, REG_SYS_FUNC_EN+1, reg_val);
-               reg_val = rtw_read8(padapter, REG_SYS_FUNC_EN+1);
+               rtw_write8(padapter, REG_SYS_FUNC_EN + 1, reg_val);
+               reg_val = rtw_read8(padapter, REG_SYS_FUNC_EN + 1);
                reg_val |= BIT(4) | BIT(7);
-               rtw_write8(padapter, REG_SYS_FUNC_EN+1, reg_val);
+               rtw_write8(padapter, REG_SYS_FUNC_EN + 1, reg_val);
                DBG_871X("-Reset Entry-\n");
        }
 #endif /* CONFIG_WOWLAN */
@@ -838,7 +820,7 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter)
 
 /*     SIC_Init(padapter); */
 
-       if (pwrctrlpriv->reg_rfoff == true)
+       if (pwrctrlpriv->reg_rfoff)
                pwrctrlpriv->rf_pwrstate = rf_off;
 
        /*  2010/08/09 MH We need to check if we need to turnon or off RF after detecting */
@@ -955,7 +937,7 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter)
        /*  Configure SDIO TxRx Control to enable Rx DMA timer masking. */
        /*  2010.02.24. */
        /*  */
-       rtw_write32(padapter, SDIO_LOCAL_BASE|SDIO_REG_TX_CTRL, 0);
+       rtw_write32(padapter, SDIO_LOCAL_BASE | SDIO_REG_TX_CTRL, 0);
 
        _RfPowerSave(padapter);
 
@@ -979,7 +961,7 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter)
        rtw_hal_set_hwreg(padapter, HW_VAR_NAV_UPPER, (u8 *)&NavUpper);
 
        /* ack for xmit mgmt frames. */
-       rtw_write32(padapter, REG_FWHW_TXQ_CTRL, rtw_read32(padapter, REG_FWHW_TXQ_CTRL)|BIT(12));
+       rtw_write32(padapter, REG_FWHW_TXQ_CTRL, rtw_read32(padapter, REG_FWHW_TXQ_CTRL) | BIT(12));
 
 /*     pHalData->PreRpwmVal = SdioLocalCmd52Read1Byte(padapter, SDIO_REG_HRPWM1) & 0x80; */
 
@@ -1009,14 +991,14 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter)
                                msleep(50);
                        } while (jiffies_to_msecs(jiffies - start_time) <= 400);
 
-                       rtw_btcoex_IQKNotify(padapter, true);
+                       hal_btcoex_IQKNotify(padapter, true);
 
                        restore_iqk_rst = pwrpriv->bips_processing;
                        b2Ant = pHalData->EEPROMBluetoothAntNum == Ant_x2;
                        PHY_IQCalibrate_8723B(padapter, false, restore_iqk_rst, b2Ant, pHalData->ant_path);
                        pHalData->odmpriv.RFCalibrateInfo.bIQKInitialized = true;
 
-                       rtw_btcoex_IQKNotify(padapter, false);
+                       hal_btcoex_IQKNotify(padapter, false);
 
                        /* Inform WiFi FW that it is the finish of IQK */
                        h2cCmdBuf = 0;
@@ -1027,7 +1009,7 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter)
        }
 
        /*  Init BT hw config. */
-       rtw_btcoex_HAL_Initialize(padapter, false);
+       hal_btcoex_InitHwConfig(padapter, false);
 
        RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("-%s\n", __func__));
 
@@ -1059,19 +1041,19 @@ static void CardDisableRTL8723BSdio(struct adapter *padapter)
                rtl8723b_FirmwareSelfReset(padapter);
 
        /*  Reset MCU 0x2[10]= 0. Suggested by Filen. 2011.01.26. by tynli. */
-       u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN+1);
+       u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN + 1);
        u1bTmp &= ~BIT(2);      /*  0x2[10], FEN_CPUEN */
-       rtw_write8(padapter, REG_SYS_FUNC_EN+1, u1bTmp);
+       rtw_write8(padapter, REG_SYS_FUNC_EN + 1, u1bTmp);
 
        /*  MCUFWDL 0x80[1:0]= 0 */
        /*  reset MCU ready status */
        rtw_write8(padapter, REG_MCUFWDL, 0);
 
        /*  Reset MCU IO Wrapper, added by Roger, 2011.08.30 */
-       u1bTmp = rtw_read8(padapter, REG_RSV_CTRL+1);
+       u1bTmp = rtw_read8(padapter, REG_RSV_CTRL + 1);
        u1bTmp &= ~BIT(0);
-       rtw_write8(padapter, REG_RSV_CTRL+1, u1bTmp);
-       u1bTmp = rtw_read8(padapter, REG_RSV_CTRL+1);
+       rtw_write8(padapter, REG_RSV_CTRL + 1, u1bTmp);
+       u1bTmp = rtw_read8(padapter, REG_RSV_CTRL + 1);
        u1bTmp |= BIT(0);
        rtw_write8(padapter, REG_RSV_CTRL+1, u1bTmp);
 
@@ -1081,7 +1063,7 @@ static void CardDisableRTL8723BSdio(struct adapter *padapter)
        ret = false;
        rtw_hal_set_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
        ret = HalPwrSeqCmdParsing(padapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, rtl8723B_card_disable_flow);
-       if (ret == false) {
+       if (!ret) {
                DBG_8192C(KERN_ERR "%s: run CARD DISABLE flow fail!\n", __func__);
        }
 }
@@ -1091,9 +1073,9 @@ static u32 rtl8723bs_hal_deinit(struct adapter *padapter)
        struct dvobj_priv *psdpriv = padapter->dvobj;
        struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
 
-       if (padapter->hw_init_completed == true) {
-               if (adapter_to_pwrctl(padapter)->bips_processing == true) {
-                       if (padapter->netif_up == true) {
+       if (padapter->hw_init_completed) {
+               if (adapter_to_pwrctl(padapter)->bips_processing) {
+                       if (padapter->netif_up) {
                                int cnt = 0;
                                u8 val8 = 0;
 
@@ -1110,10 +1092,10 @@ static u32 rtl8723bs_hal_deinit(struct adapter *padapter)
                                /* H2C done, enter 32k */
                                if (val8 == 0) {
                                        /* ser rpwm to enter 32k */
-                                       val8 = rtw_read8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HRPWM1);
+                                       val8 = rtw_read8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HRPWM1);
                                        val8 += 0x80;
                                        val8 |= BIT(0);
-                                       rtw_write8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HRPWM1, val8);
+                                       rtw_write8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HRPWM1, val8);
                                        DBG_871X("%s: write rpwm =%02x\n", __func__, val8);
                                        adapter_to_pwrctl(padapter)->tog = (val8 + 0x80) & 0x80;
                                        cnt = val8 = 0;
@@ -1205,7 +1187,7 @@ static void rtl8723bs_interface_configure(struct adapter *padapter)
 
        switch (pHalData->OutEpNumber) {
        case 3:
-               pHalData->OutEpQueueSel = TX_SELE_HQ | TX_SELE_LQ|TX_SELE_NQ;
+               pHalData->OutEpQueueSel = TX_SELE_HQ | TX_SELE_LQ | TX_SELE_NQ;
                break;
        case 2:
                pHalData->OutEpQueueSel = TX_SELE_HQ | TX_SELE_NQ;
@@ -1292,7 +1274,7 @@ static void Hal_EfuseParseBoardType_8723BS(
        if (!AutoLoadFail) {
                pHalData->BoardType = (hwinfo[EEPROM_RF_BOARD_OPTION_8723B] & 0xE0) >> 5;
                if (pHalData->BoardType == 0xFF)
-                       pHalData->BoardType = (EEPROM_DEFAULT_BOARD_OPTION&0xE0)>>5;
+                       pHalData->BoardType = (EEPROM_DEFAULT_BOARD_OPTION & 0xE0) >> 5;
        } else
                pHalData->BoardType = 0;
        RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Board Type: 0x%2x\n", pHalData->BoardType));
@@ -1387,7 +1369,7 @@ static s32 _ReadAdapterInfo8723BS(struct adapter *padapter)
        RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("+_ReadAdapterInfo8723BS\n"));
 
        /*  before access eFuse, make sure card enable has been called */
-       if (padapter->hw_init_completed == false)
+       if (!padapter->hw_init_completed)
                _InitPowerOn_8723BS(padapter);
 
 
@@ -1404,7 +1386,7 @@ static s32 _ReadAdapterInfo8723BS(struct adapter *padapter)
        _ReadPROMContent(padapter);
        _InitOtherVariable(padapter);
 
-       if (padapter->hw_init_completed == false) {
+       if (!padapter->hw_init_completed) {
                rtw_write8(padapter, 0x67, 0x00); /*  for BT, Switch Ant control to BT */
                CardDisableRTL8723BSdio(padapter);/* for the power consumption issue,  wifi ko module is loaded during booting, but wifi GUI is off */
        }
@@ -1429,7 +1411,6 @@ static void ReadAdapterInfo8723BS(struct adapter *padapter)
  */
 static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
 {
-       struct hal_com_data *pHalData;
        u8 val8;
 
 #if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN)
@@ -1449,8 +1430,6 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
 #endif
 #endif
 
-       pHalData = GET_HAL_DATA(padapter);
-
        switch (variable) {
        case HW_VAR_SET_RPWM:
                /*  rpwm value only use BIT0(clock bit) , BIT6(Ack bit), and BIT7(Toggle bit) */
@@ -1460,7 +1439,7 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
                {
                        val8 = *val;
                        val8 &= 0xC1;
-                       rtw_write8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HRPWM1, val8);
+                       rtw_write8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HRPWM1, val8);
                }
                break;
        case HW_VAR_SET_REQ_FW_PS:
@@ -1496,9 +1475,9 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
 
                        /*  2. RX DMA stop */
                        DBG_871X_LEVEL(_drv_always_, "Pause DMA\n");
-                       rtw_write32(padapter, REG_RXPKT_NUM, (rtw_read32(padapter, REG_RXPKT_NUM)|RW_RELEASE_EN));
+                       rtw_write32(padapter, REG_RXPKT_NUM, (rtw_read32(padapter, REG_RXPKT_NUM) | RW_RELEASE_EN));
                        do {
-                               if ((rtw_read32(padapter, REG_RXPKT_NUM)&RXDMA_IDLE)) {
+                               if ((rtw_read32(padapter, REG_RXPKT_NUM) & RXDMA_IDLE)) {
                                        DBG_871X_LEVEL(_drv_always_, "RX_DMA_IDLE is true\n");
                                        break;
                                } else {
@@ -1530,7 +1509,7 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
                        sdio_local_read(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp);
                        DBG_871X("DisableInterruptButCpwm28723BSdio(): Read SDIO_REG_HIMR: 0x%08x\n", tmp);
 
-                       himr = cpu_to_le32(SDIO_HIMR_DISABLED)|SDIO_HIMR_CPWM2_MSK;
+                       himr = cpu_to_le32(SDIO_HIMR_DISABLED) | SDIO_HIMR_CPWM2_MSK;
                        sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8 *)&himr);
 
                        sdio_local_read(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp);
@@ -1545,7 +1524,7 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
                                DBG_871X_LEVEL(_drv_always_, "Check EnableWoWlan CMD is ready\n");
                                mstatus = rtw_read8(padapter, REG_WOW_CTRL);
                                trycnt = 10;
-                               while (!(mstatus&BIT1) && trycnt > 1) {
+                               while (!(mstatus & BIT1) && trycnt > 1) {
                                        mstatus = rtw_read8(padapter, REG_WOW_CTRL);
                                        DBG_871X("Loop index: %d :0x%02x\n", trycnt, mstatus);
                                        trycnt--;
@@ -1558,7 +1537,7 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
                        DBG_871X_LEVEL(_drv_always_, "WOWLAN_DISABLE\n");
 
                        psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(pmlmepriv));
-                       if (psta != NULL)
+                       if (psta)
                                rtl8723b_set_FwMediaStatusRpt_cmd(padapter, RT_MEDIA_DISCONNECT, psta->mac_id);
                        else
                                DBG_871X("psta is null\n");
@@ -1603,7 +1582,7 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
                                DBG_871X_LEVEL(_drv_always_, "Check DisableWoWlan CMD is ready\n");
                                mstatus = rtw_read8(padapter, REG_WOW_CTRL);
                                trycnt = 50;
-                               while (mstatus&BIT1 && trycnt > 1) {
+                               while (mstatus & BIT1 && trycnt > 1) {
                                        mstatus = rtw_read8(padapter, REG_WOW_CTRL);
                                        DBG_871X_LEVEL(_drv_always_, "Loop index: %d :0x%02x\n", trycnt, mstatus);
                                        trycnt--;
@@ -1613,9 +1592,9 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
                                if (mstatus & BIT1) {
                                        DBG_871X_LEVEL(_drv_always_, "Disable WOW mode fail!!\n");
                                        DBG_871X("Set 0x690 = 0x00\n");
-                                       rtw_write8(padapter, REG_WOW_CTRL, (rtw_read8(padapter, REG_WOW_CTRL)&0xf0));
+                                       rtw_write8(padapter, REG_WOW_CTRL, (rtw_read8(padapter, REG_WOW_CTRL) & 0xf0));
                                        DBG_871X_LEVEL(_drv_always_, "Release RXDMA\n");
-                                       rtw_write32(padapter, REG_RXPKT_NUM, (rtw_read32(padapter, REG_RXPKT_NUM)&(~RW_RELEASE_EN)));
+                                       rtw_write32(padapter, REG_RXPKT_NUM, (rtw_read32(padapter, REG_RXPKT_NUM) & (~RW_RELEASE_EN)));
                                }
 
                                /*  3.1 read fw iv */
@@ -1673,7 +1652,7 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
                                (pwrctl->wowlan_wake_reason != Rx_DeAuth)
                        ) {
                                rtl8723b_set_FwJoinBssRpt_cmd(padapter, RT_MEDIA_CONNECT);
-                               if (psta != NULL)
+                               if (psta)
                                        rtl8723b_set_FwMediaStatusRpt_cmd(padapter, RT_MEDIA_CONNECT, psta->mac_id);
                        }
 #ifdef CONFIG_PNO_SUPPORT
@@ -1706,9 +1685,9 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
                        /*  2. RX DMA stop */
                        DBG_871X_LEVEL(_drv_always_, "Pause DMA\n");
                        rtw_write32(padapter, REG_RXPKT_NUM,
-                               (rtw_read32(padapter, REG_RXPKT_NUM)|RW_RELEASE_EN));
+                               (rtw_read32(padapter, REG_RXPKT_NUM) | RW_RELEASE_EN));
                        do {
-                               if ((rtw_read32(padapter, REG_RXPKT_NUM)&RXDMA_IDLE)) {
+                               if ((rtw_read32(padapter, REG_RXPKT_NUM) & RXDMA_IDLE)) {
                                        DBG_871X_LEVEL(_drv_always_, "RX_DMA_IDLE is true\n");
                                        break;
                                } else {
@@ -1742,7 +1721,7 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
                        sdio_local_read(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp);
                        DBG_871X("DisableInterruptButCpwm28723BSdio(): Read SDIO_REG_HIMR: 0x%08x\n", tmp);
 
-                       himr = cpu_to_le32(SDIO_HIMR_DISABLED)|SDIO_HIMR_CPWM2_MSK;
+                       himr = cpu_to_le32(SDIO_HIMR_DISABLED) | SDIO_HIMR_CPWM2_MSK;
                        sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8 *)&himr);
 
                        sdio_local_read(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp);
@@ -1808,7 +1787,7 @@ static void GetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
 {
        switch (variable) {
        case HW_VAR_CPWM:
-               *val = rtw_read8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HCPWM1_8723B);
+               *val = rtw_read8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HCPWM1_8723B);
                break;
 
        case HW_VAR_FW_PS_STATE:
index a601620..301d327 100644 (file)
@@ -214,7 +214,7 @@ static u32 sdio_read32(struct intf_hdl *intfhdl, u32 addr)
 
                ftaddr &= ~(u16)0x3;
                sd_read(intfhdl, ftaddr, 8, tmpbuf);
-               memcpy(&le_tmp, tmpbuf+shift, 4);
+               memcpy(&le_tmp, tmpbuf + shift, 4);
                val = le32_to_cpu(le_tmp);
 
                kfree(tmpbuf);
@@ -261,7 +261,7 @@ static s32 sdio_readN(struct intf_hdl *intfhdl, u32 addr, u32 cnt, u8 *buf)
 
                err = sd_read(intfhdl, ftaddr, n, tmpbuf);
                if (!err)
-                       memcpy(buf, tmpbuf+shift, cnt);
+                       memcpy(buf, tmpbuf + shift, cnt);
                kfree(tmpbuf);
        }
        return err;
@@ -366,7 +366,7 @@ static s32 sdio_writeN(struct intf_hdl *intfhdl, u32 addr, u32 cnt, u8 *buf)
                        kfree(tmpbuf);
                        return err;
                }
-               memcpy(tmpbuf+shift, buf, cnt);
+               memcpy(tmpbuf + shift, buf, cnt);
                err = sd_write(intfhdl, ftaddr, n, tmpbuf);
                kfree(tmpbuf);
        }
@@ -727,8 +727,8 @@ static s32 ReadInterrupt8723BSdio(struct adapter *adapter, u32 *phisr)
        hisr = 0;
        while (hisr_len != 0) {
                hisr_len--;
-               val8 = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_HISR+hisr_len);
-               hisr |= (val8 << (8*hisr_len));
+               val8 = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_HISR + hisr_len);
+               hisr |= (val8 << (8 * hisr_len));
        }
 
        *phisr = hisr;
@@ -795,38 +795,6 @@ void InitSysInterrupt8723BSdio(struct adapter *adapter)
                                                        0);
 }
 
-#ifdef CONFIG_WOWLAN
-/*  */
-/*     Description: */
-/*             Clear corresponding SDIO Host ISR interrupt service. */
-/*  */
-/*     Assumption: */
-/*             Using SDIO Local register ONLY for configuration. */
-/*  */
-/*     Created by Roger, 2011.02.11. */
-/*  */
-void clearinterrupt8723bsdio(struct adapter *adapter)
-{
-       struct hal_com_data *haldata;
-       u8 *clear;
-
-       if (adapter->bSurpriseRemoved)
-               return;
-
-       haldata = GET_HAL_DATA(adapter);
-       clear = rtw_zmalloc(4);
-
-       /*  Clear corresponding HISR Content if needed */
-       *(__le32 *)clear = cpu_to_le32(haldata->sdio_hisr & MASK_SDIO_HISR_CLEAR);
-       if (*(__le32 *)clear) {
-               /*  Perform write one clear operation */
-               sdio_local_write(padapter, SDIO_REG_HISR, 4, clear);
-       }
-
-       kfree(clear);
-}
-#endif
-
 /*  */
 /*     Description: */
 /*             Enalbe SDIO Host Interrupt Mask configuration on SDIO local domain. */
@@ -952,7 +920,7 @@ static struct recv_buf *sd_recv_rxfifo(struct adapter *adapter, u32 size)
                        recvbuf->pskb->dev = adapter->pnetdev;
 
                        tmpaddr = (SIZE_PTR)recvbuf->pskb->data;
-                       alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);
+                       alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1);
                        skb_reserve(recvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment));
                }
 
@@ -1045,21 +1013,19 @@ void sd_int_dpc(struct adapter *adapter)
                }
        }
 
-       if (hal->sdio_hisr & SDIO_HISR_TXBCNOK) {
+       if (hal->sdio_hisr & SDIO_HISR_TXBCNOK)
                DBG_8192C("%s: SDIO_HISR_TXBCNOK\n", __func__);
-       }
 
-       if (hal->sdio_hisr & SDIO_HISR_TXBCNERR) {
+       if (hal->sdio_hisr & SDIO_HISR_TXBCNERR)
                DBG_8192C("%s: SDIO_HISR_TXBCNERR\n", __func__);
-       }
 #ifndef CONFIG_C2H_PACKET_EN
        if (hal->sdio_hisr & SDIO_HISR_C2HCMD) {
                struct c2h_evt_hdr_88xx *c2h_evt;
 
                DBG_8192C("%s: C2H Command\n", __func__);
                c2h_evt = rtw_zmalloc(16);
-               if (c2h_evt != NULL) {
-                       if (rtw_hal_c2h_evt_read(adapter, (u8 *)c2h_evt) == _SUCCESS) {
+               if (c2h_evt) {
+                       if (c2h_evt_read_88xx(adapter, (u8 *)c2h_evt) == _SUCCESS) {
                                if (c2h_id_filter_ccx_8723b((u8 *)c2h_evt)) {
                                        /* Handle CCX report here */
                                        rtw_hal_c2h_handler(adapter, (u8 *)c2h_evt);
@@ -1077,13 +1043,12 @@ void sd_int_dpc(struct adapter *adapter)
        }
 #endif
 
-       if (hal->sdio_hisr & SDIO_HISR_RXFOVW) {
+       if (hal->sdio_hisr & SDIO_HISR_RXFOVW)
                DBG_8192C("%s: Rx Overflow\n", __func__);
-       }
 
-       if (hal->sdio_hisr & SDIO_HISR_RXERR) {
+       if (hal->sdio_hisr & SDIO_HISR_RXERR)
                DBG_8192C("%s: Rx Error\n", __func__);
-       }
+
 
        if (hal->sdio_hisr & SDIO_HISR_RX_REQUEST) {
                struct recv_buf *recvbuf;
@@ -1143,9 +1108,8 @@ void sd_int_hdl(struct adapter *adapter)
 
                /*  clear HISR */
                v32 = hal->sdio_hisr & MASK_SDIO_HISR_CLEAR;
-               if (v32) {
+               if (v32)
                        SdioLocalCmd52Write4Byte(adapter, SDIO_REG_HISR, v32);
-               }
 
                sd_int_dpc(adapter);
        } else {
@@ -1194,12 +1158,11 @@ u8 HalQueryTxBufferStatus8723BSdio(struct adapter *adapter)
 /*     Description: */
 /*             Query SDIO Local register to get the current number of TX OQT Free Space. */
 /*  */
-u8 HalQueryTxOQTBufferStatus8723BSdio(struct adapter *adapter)
+void HalQueryTxOQTBufferStatus8723BSdio(struct adapter *adapter)
 {
        struct hal_com_data *haldata = GET_HAL_DATA(adapter);
 
        haldata->SdioTxOQTFreeSpace = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_OQT_FREE_PG);
-       return true;
 }
 
 #if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN)
@@ -1207,7 +1170,6 @@ u8 RecvOnePkt(struct adapter *adapter, u32 size)
 {
        struct recv_buf *recvbuf;
        struct dvobj_priv *sddev;
-       struct sdio_data *psdio;
        struct sdio_func *func;
 
        u8 res = false;
index 0fd84c9..96346ce 100644 (file)
@@ -673,7 +673,7 @@ int rtw_config_gpio(struct net_device *netdev, int gpio_num, bool isOutput);
 #endif
 
 #ifdef CONFIG_WOWLAN
-int rtw_suspend_wow(struct adapter *padapter);
+void rtw_suspend_wow(struct adapter *padapter);
 int rtw_resume_process_wow(struct adapter *padapter);
 #endif
 
index 4066b0a..6f7514b 100644 (file)
@@ -23,7 +23,7 @@ void DBG_BT_INFO(u8 *dbgmsg);
 
 void hal_btcoex_SetBTCoexist(struct adapter *padapter, u8 bBtExist);
 u8 hal_btcoex_IsBtExist(struct adapter *padapter);
-u8 hal_btcoex_IsBtDisabled(struct adapter *);
+bool hal_btcoex_IsBtDisabled(struct adapter *);
 void hal_btcoex_SetChipType(struct adapter *padapter, u8 chipType);
 void hal_btcoex_SetPgAntNum(struct adapter *padapter, u8 antNum);
 void hal_btcoex_SetSingleAntPath(struct adapter *padapter, u8 singleAntPath);
@@ -43,7 +43,7 @@ void hal_btcoex_BtInfoNotify(struct adapter *padapter, u8 length, u8 *tmpBuf);
 void hal_btcoex_SuspendNotify(struct adapter *padapter, u8 state);
 void hal_btcoex_HaltNotify(struct adapter *padapter);
 
-void hal_btcoex_Hanlder(struct adapter *padapter);
+void hal_btcoex_Handler(struct adapter *padapter);
 
 s32 hal_btcoex_IsBTCoexCtrlAMPDUSize(struct adapter *padapter);
 void hal_btcoex_SetManualControl(struct adapter *padapter, u8 bmanual);
index d1c5b31..f5c3ce5 100644 (file)
@@ -232,7 +232,6 @@ void rtw_init_hal_com_default_value(struct adapter * Adapter);
 void c2h_evt_clear(struct adapter *adapter);
 s32 c2h_evt_read_88xx(struct adapter *adapter, u8 *buf);
 
-u8  rtw_hal_networktype_to_raid(struct adapter *adapter, struct sta_info *psta);
 u8 rtw_get_mgntframe_raid(struct adapter *adapter, unsigned char network_type);
 void rtw_hal_update_sta_rate_mask(struct adapter *padapter, struct sta_info *psta);
 
index 19ceb4a..3a0c3d0 100644 (file)
@@ -388,7 +388,6 @@ void rtw_hal_notch_filter(struct adapter * adapter, bool enable);
 void rtw_hal_reset_security_engine(struct adapter * adapter);
 
 bool rtw_hal_c2h_valid(struct adapter *adapter, u8 *buf);
-s32 rtw_hal_c2h_evt_read(struct adapter *adapter, u8 *buf);
 s32 rtw_hal_c2h_handler(struct adapter *adapter, u8 *c2h_evt);
 c2h_id_filter rtw_hal_c2h_id_filter_ccx(struct adapter *adapter);
 
index 74c028f..2110552 100644 (file)
@@ -1138,7 +1138,7 @@ int rtw_get_wapi_ie(u8 *in_ie, uint in_len, u8 *wapi_ie, u16 *wapi_len);
 int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x);
 int rtw_parse_wpa2_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x);
 
-int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len);
+void rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len);
 
 u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen);
 u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen);
index 0ea91a1..40313d1 100644 (file)
@@ -46,7 +46,7 @@ void devobj_deinit(struct dvobj_priv *pdvobj);
 
 u8 rtw_init_drv_sw(struct adapter *padapter);
 u8 rtw_free_drv_sw(struct adapter *padapter);
-u8 rtw_reset_drv_sw(struct adapter *padapter);
+void rtw_reset_drv_sw(struct adapter *padapter);
 void rtw_dev_unload(struct adapter *padapter);
 
 u32 rtw_start_drv_threads(struct adapter *padapter);
index 76d6195..d2616af 100644 (file)
@@ -178,8 +178,6 @@ extern int rtw_retrive_from_file(char *path, u8 *buf, u32 sz);
 extern void rtw_free_netdev(struct net_device * netdev);
 
 
-extern u64 rtw_modular64(u64 x, u64 y);
-
 /* Macros for handling unaligned memory accesses */
 
 #define RTW_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1]))
index 6fea0e9..1056f61 100644 (file)
@@ -22,14 +22,14 @@ 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_alloc(struct adapter *padapter, union recv_frame *precvframe);
+void rtw_os_recv_resource_alloc(struct adapter *padapter, union recv_frame *precvframe);
 void rtw_os_recv_resource_free(struct recv_priv *precvpriv);
 
 
 void rtw_os_free_recvframe(union recv_frame *precvframe);
 
 
-int rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *precvbuf);
+void rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *precvbuf);
 
 _pkt *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata);
 void rtw_os_recv_indicate_pkt(struct adapter *padapter, _pkt *pkt, struct rx_pkt_attrib *pattrib);
index fd56c9d..4a1ed9e 100644 (file)
@@ -19,7 +19,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf,  int len);
 void rtw_ap_restore_network(struct adapter *padapter);
 void rtw_set_macaddr_acl(struct adapter *padapter, int mode);
 int rtw_acl_add_sta(struct adapter *padapter, u8 *addr);
-int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr);
+void rtw_acl_remove_sta(struct adapter *padapter, u8 *addr);
 
 u8 rtw_ap_set_pairwise_key(struct adapter *padapter, struct sta_info *psta);
 int rtw_ap_set_group_key(struct adapter *padapter, u8 *key, u8 alg, int keyid);
@@ -31,7 +31,7 @@ u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta);
 void sta_info_update(struct adapter *padapter, struct sta_info *psta);
 void ap_sta_info_defer_update(struct adapter *padapter, struct sta_info *psta);
 u8 ap_free_sta(struct adapter *padapter, struct sta_info *psta, bool active, u16 reason);
-int rtw_sta_flush(struct adapter *padapter);
+void rtw_sta_flush(struct adapter *padapter);
 void start_ap_mode(struct adapter *padapter);
 void stop_ap_mode(struct adapter *padapter);
 
index 53f49c6..19764c8 100644 (file)
 #define        PACKET_ARP                              2
 #define        PACKET_EAPOL                    3
 
-void rtw_btcoex_Initialize(struct adapter *);
-void rtw_btcoex_PowerOnSetting(struct adapter *padapter);
-void rtw_btcoex_HAL_Initialize(struct adapter *padapter, u8 bWifiOnly);
-void rtw_btcoex_IpsNotify(struct adapter *, u8 type);
-void rtw_btcoex_LpsNotify(struct adapter *, u8 type);
-void rtw_btcoex_ScanNotify(struct adapter *, u8 type);
-void rtw_btcoex_ConnectNotify(struct adapter *, u8 action);
 void rtw_btcoex_MediaStatusNotify(struct adapter *, u8 mediaStatus);
-void rtw_btcoex_SpecialPacketNotify(struct adapter *, u8 pktType);
-void rtw_btcoex_IQKNotify(struct adapter *padapter, u8 state);
-void rtw_btcoex_BtInfoNotify(struct adapter *, u8 length, u8 *tmpBuf);
-void rtw_btcoex_SuspendNotify(struct adapter *, u8 state);
 void rtw_btcoex_HaltNotify(struct adapter *);
-u8 rtw_btcoex_IsBtDisabled(struct adapter *);
-void rtw_btcoex_Handler(struct adapter *);
-s32 rtw_btcoex_IsBTCoexCtrlAMPDUSize(struct adapter *);
-void rtw_btcoex_SetManualControl(struct adapter *, u8 bmanual);
-u8 rtw_btcoex_IsBtControlLps(struct adapter *);
-u8 rtw_btcoex_IsLpsOn(struct adapter *);
-u8 rtw_btcoex_RpwmVal(struct adapter *);
-u8 rtw_btcoex_LpsVal(struct adapter *);
-void rtw_btcoex_SetBTCoexist(struct adapter *, u8 bBtExist);
-void rtw_btcoex_SetChipType(struct adapter *, u8 chipType);
-void rtw_btcoex_SetPGAntNum(struct adapter *, u8 antNum);
-void rtw_btcoex_SetSingleAntPath(struct adapter *padapter, u8 singleAntPath);
-u32 rtw_btcoex_GetRaMask(struct adapter *);
-void rtw_btcoex_RecordPwrMode(struct adapter *, u8 *pCmdBuf, u8 cmdLen);
-void rtw_btcoex_DisplayBtCoexInfo(struct adapter *, u8 *pbuf, u32 bufsize);
-void rtw_btcoex_SetDBG(struct adapter *, u32 *pDbgModule);
-u32 rtw_btcoex_GetDBG(struct adapter *, u8 *pStrBuf, u32 bufSize);
 
 /*  ================================================== */
 /*  Below Functions are called by BT-Coex */
index 2693b55..d3c07d1 100644 (file)
@@ -589,7 +589,6 @@ extern void rtw_scan_timeout_handler(struct timer_list *t);
 extern void rtw_dynamic_check_timer_handler(struct adapter *adapter);
 bool rtw_is_scan_deny(struct adapter *adapter);
 void rtw_clear_scan_deny(struct adapter *adapter);
-void rtw_set_scan_deny_timer_hdl(struct adapter *adapter);
 void rtw_set_scan_deny(struct adapter *adapter, u32 ms);
 
 void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv);
@@ -607,8 +606,6 @@ extern void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_ne
 
 extern struct wlan_network* _rtw_find_network(struct __queue *scanned_queue, u8 *addr);
 
-extern void _rtw_free_network_queue(struct adapter *padapter, u8 isfreeall);
-
 extern sint rtw_if_up(struct adapter *padapter);
 
 sint rtw_linked_check(struct adapter *padapter);
index f6eabad..733bb94 100644 (file)
@@ -544,7 +544,7 @@ extern struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv);
 
 /* void fill_fwpriv(struct adapter *padapter, struct fw_priv *pfwpriv); */
 
-unsigned char networktype_to_raid_ex(struct adapter *adapter, struct sta_info *psta);
+u8 networktype_to_raid_ex(struct adapter *adapter, struct sta_info *psta);
 
 void get_rate_set(struct adapter *padapter, unsigned char *pbssrate, int *bssrate_len);
 void set_mcs_rate_by_mask(u8 *mcs_set, u32 mask);
index 0f117ff..6b0446b 100644 (file)
@@ -33,7 +33,7 @@ extern void InitSysInterrupt8723BSdio(struct adapter *padapter);
 extern void EnableInterrupt8723BSdio(struct adapter *padapter);
 extern void DisableInterrupt8723BSdio(struct adapter *padapter);
 extern u8 HalQueryTxBufferStatus8723BSdio(struct adapter *padapter);
-extern u8 HalQueryTxOQTBufferStatus8723BSdio(struct adapter *padapter);
+extern void HalQueryTxOQTBufferStatus8723BSdio(struct adapter *padapter);
 #if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN)
 extern void ClearInterrupt8723BSdio(struct adapter *padapter);
 #endif /* CONFIG_WOWLAN */
index db553f2..9bc6856 100644 (file)
@@ -1650,7 +1650,7 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy
        }
 
 check_need_indicate_scan_done:
-       if (true == need_indicate_scan_done)
+       if (need_indicate_scan_done)
        {
                rtw_cfg80211_surveydone_event_callback(padapter);
                rtw_cfg80211_indicate_scan_done(padapter, false);
@@ -2439,23 +2439,7 @@ void rtw_cfg80211_indicate_sta_disassoc(struct adapter *padapter, unsigned char
        cfg80211_del_sta(ndev, da, GFP_ATOMIC);
 }
 
-static int rtw_cfg80211_monitor_if_open(struct net_device *ndev)
-{
-       int ret = 0;
-
-       DBG_8192C("%s\n", __func__);
-
-       return ret;
-}
-
-static int rtw_cfg80211_monitor_if_close(struct net_device *ndev)
-{
-       int ret = 0;
-
-       DBG_8192C("%s\n", __func__);
 
-       return ret;
-}
 
 static netdev_tx_t rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struct net_device *ndev)
 {
@@ -2604,20 +2588,10 @@ fail:
 
 }
 
-static int rtw_cfg80211_monitor_if_set_mac_address(struct net_device *ndev, void *addr)
-{
-       int ret = 0;
 
-       DBG_8192C("%s\n", __func__);
-
-       return ret;
-}
 
 static const struct net_device_ops rtw_cfg80211_monitor_if_ops = {
-       .ndo_open = rtw_cfg80211_monitor_if_open,
-       .ndo_stop = rtw_cfg80211_monitor_if_close,
-       .ndo_start_xmit = rtw_cfg80211_monitor_if_xmit_entry,
-       .ndo_set_mac_address = rtw_cfg80211_monitor_if_set_mac_address,
+       .ndo_start_xmit = rtw_cfg80211_monitor_if_xmit_entry,
 };
 
 static int rtw_cfg80211_add_monitor_if (struct adapter *padapter, char *name, struct net_device **ndev)
@@ -2896,9 +2870,9 @@ static int cfg80211_rtw_del_station(struct wiphy *wiphy, struct net_device *ndev
 
                flush_all_cam_entry(padapter);  /* clear CAM */
 
-               ret = rtw_sta_flush(padapter);
+               rtw_sta_flush(padapter);
 
-               return ret;
+               return 0;
        }
 
 
index e3d3569..99e6b10 100644 (file)
@@ -10,6 +10,7 @@
 #include <drv_types.h>
 #include <rtw_debug.h>
 #include <rtw_mp.h>
+#include <hal_btcoex.h>
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
 
@@ -55,7 +56,7 @@ void rtw_indicate_wx_assoc_event(struct adapter *padapter)
        struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
        struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
-       struct wlan_bssid_ex            *pnetwork = (struct wlan_bssid_ex*)(&(pmlmeinfo->network));
+       struct wlan_bssid_ex            *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network));
 
        memset(&wrqu, 0, sizeof(union iwreq_data));
 
@@ -235,8 +236,7 @@ static char *translate_scan(struct adapter *padapter,
                u8 wpa_ie[255], rsn_ie[255];
                u16 wpa_len = 0, rsn_len = 0;
                u8 *p;
-               sint out_len = 0;
-               out_len =rtw_get_sec_ie(pnetwork->network.IEs , pnetwork->network.IELength, rsn_ie,&rsn_len, wpa_ie,&wpa_len);
+               rtw_get_sec_ie(pnetwork->network.IEs, pnetwork->network.IELength, rsn_ie, &rsn_len, wpa_ie, &wpa_len);
                RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan: ssid =%s\n", pnetwork->network.Ssid.Ssid));
                RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len));
 
@@ -478,14 +478,12 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
                if (wep_key_len > 0) {
                        wep_key_len = wep_key_len <= 5 ? 5 : 13;
                        wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial);
-                       pwep = rtw_malloc(wep_total_len);
+                       pwep = kzalloc(wep_total_len, GFP_KERNEL);
                        if (pwep == NULL) {
                                RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, (" wpa_set_encryption: pwep allocate fail !!!\n"));
                                goto exit;
                        }
 
-                       memset(pwep, 0, wep_total_len);
-
                        pwep->KeyLength = wep_key_len;
                        pwep->Length = wep_total_len;
 
@@ -617,7 +615,7 @@ exit:
 
 static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ielen)
 {
-       u8 *buf = NULL, *pos = NULL;
+       u8 *buf = NULL;
        int group_cipher = 0, pairwise_cipher = 0;
        int ret = 0;
        u8 null_addr[]= {0, 0, 0, 0, 0, 0};
@@ -647,7 +645,6 @@ static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ie
                                DBG_871X("0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n", buf[i], buf[i+1], buf[i+2], buf[i+3], buf[i+4], buf[i+5], buf[i+6], buf[i+7]);
                }
 
-               pos = buf;
                if (ielen < RSN_HEADER_LEN) {
                        RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("Ie len too short %d\n", ielen));
                        ret  = -1;
@@ -946,7 +943,7 @@ static int rtw_wx_set_pmkid(struct net_device *dev,
        u8          j, blInserted = false;
        int         intReturn = false;
        struct security_priv *psecuritypriv = &padapter->securitypriv;
-        struct iw_pmksa*  pPMK = (struct iw_pmksa*)extra;
+        struct iw_pmksa*  pPMK = (struct iw_pmksa *)extra;
         u8     strZeroMacAddress[ ETH_ALEN ] = { 0x00 };
         u8     strIssueBssid[ ETH_ALEN ] = { 0x00 };
 
@@ -1183,7 +1180,7 @@ static int rtw_wx_set_wap(struct net_device *dev,
                                spin_unlock_bh(&queue->lock);
                                goto exit;
                        }
-                               break;
+                       break;
                }
 
        }
@@ -1671,45 +1668,45 @@ static int rtw_wx_set_rate(struct net_device *dev,
        target_rate = target_rate/100000;
 
        switch (target_rate) {
-               case 10:
-                       ratevalue = 0;
-                       break;
-               case 20:
-                       ratevalue = 1;
-                       break;
-               case 55:
-                       ratevalue = 2;
-                       break;
-               case 60:
-                       ratevalue = 3;
-                       break;
-               case 90:
-                       ratevalue = 4;
-                       break;
-               case 110:
-                       ratevalue = 5;
-                       break;
-               case 120:
-                       ratevalue = 6;
-                       break;
-               case 180:
-                       ratevalue = 7;
-                       break;
-               case 240:
-                       ratevalue = 8;
-                       break;
-               case 360:
-                       ratevalue = 9;
-                       break;
-               case 480:
-                       ratevalue = 10;
-                       break;
-               case 540:
-                       ratevalue = 11;
-                       break;
-               default:
-                       ratevalue = 11;
-                       break;
+       case 10:
+               ratevalue = 0;
+               break;
+       case 20:
+               ratevalue = 1;
+               break;
+       case 55:
+               ratevalue = 2;
+               break;
+       case 60:
+               ratevalue = 3;
+               break;
+       case 90:
+               ratevalue = 4;
+               break;
+       case 110:
+               ratevalue = 5;
+               break;
+       case 120:
+               ratevalue = 6;
+               break;
+       case 180:
+               ratevalue = 7;
+               break;
+       case 240:
+               ratevalue = 8;
+               break;
+       case 360:
+               ratevalue = 9;
+               break;
+       case 480:
+               ratevalue = 10;
+               break;
+       case 540:
+               ratevalue = 11;
+               break;
+       default:
+               ratevalue = 11;
+               break;
        }
 
 set_rate:
@@ -2054,7 +2051,7 @@ static int rtw_wx_set_auth(struct net_device *dev,
                           union iwreq_data *wrqu, char *extra)
 {
        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
-       struct iw_param *param = (struct iw_param*)&(wrqu->param);
+       struct iw_param *param = (struct iw_param *)&(wrqu->param);
        int ret = 0;
 
        switch (param->flags & IW_AUTH_INDEX) {
@@ -2144,12 +2141,10 @@ static int rtw_wx_set_enc_ext(struct net_device *dev,
        int ret = 0;
 
        param_len = sizeof(struct ieee_param) + pext->key_len;
-       param = rtw_malloc(param_len);
+       param = kzalloc(param_len, GFP_KERNEL);
        if (param == NULL)
                return -1;
 
-       memset(param, 0, param_len);
-
        param->cmd = IEEE_CMD_SET_ENCRYPTION;
        memset(param->sta_addr, 0xff, ETH_ALEN);
 
@@ -2267,22 +2262,22 @@ static int rtw_wx_read32(struct net_device *dev,
        sscanf(ptmp, "%d,%x", &bytes, &addr);
 
        switch (bytes) {
-               case 1:
-                       data32 = rtw_read8(padapter, addr);
-                       sprintf(extra, "0x%02X", data32);
-                       break;
-               case 2:
-                       data32 = rtw_read16(padapter, addr);
-                       sprintf(extra, "0x%04X", data32);
-                       break;
-               case 4:
-                       data32 = rtw_read32(padapter, addr);
-                       sprintf(extra, "0x%08X", data32);
-                       break;
-               default:
-                       DBG_871X(KERN_INFO "%s: usage> read [bytes],[address(hex)]\n", __func__);
-                       ret = -EINVAL;
-                       goto exit;
+       case 1:
+               data32 = rtw_read8(padapter, addr);
+               sprintf(extra, "0x%02X", data32);
+               break;
+       case 2:
+               data32 = rtw_read16(padapter, addr);
+               sprintf(extra, "0x%04X", data32);
+               break;
+       case 4:
+               data32 = rtw_read32(padapter, addr);
+               sprintf(extra, "0x%08X", data32);
+               break;
+       default:
+               DBG_871X(KERN_INFO "%s: usage> read [bytes],[address(hex)]\n", __func__);
+               ret = -EINVAL;
+               goto exit;
        }
        DBG_871X(KERN_INFO "%s: addr = 0x%08X data =%s\n", __func__, addr, extra);
 
@@ -2309,21 +2304,21 @@ static int rtw_wx_write32(struct net_device *dev,
        sscanf(extra, "%d,%x,%x", &bytes, &addr, &data32);
 
        switch (bytes) {
-               case 1:
-                       rtw_write8(padapter, addr, (u8)data32);
-                       DBG_871X(KERN_INFO "%s: addr = 0x%08X data = 0x%02X\n", __func__, addr, (u8)data32);
-                       break;
-               case 2:
-                       rtw_write16(padapter, addr, (u16)data32);
-                       DBG_871X(KERN_INFO "%s: addr = 0x%08X data = 0x%04X\n", __func__, addr, (u16)data32);
-                       break;
-               case 4:
-                       rtw_write32(padapter, addr, data32);
-                       DBG_871X(KERN_INFO "%s: addr = 0x%08X data = 0x%08X\n", __func__, addr, data32);
-                       break;
-               default:
-                       DBG_871X(KERN_INFO "%s: usage> write [bytes],[address(hex)],[data(hex)]\n", __func__);
-                       return -EINVAL;
+       case 1:
+               rtw_write8(padapter, addr, (u8)data32);
+               DBG_871X(KERN_INFO "%s: addr = 0x%08X data = 0x%02X\n", __func__, addr, (u8)data32);
+               break;
+       case 2:
+               rtw_write16(padapter, addr, (u16)data32);
+               DBG_871X(KERN_INFO "%s: addr = 0x%08X data = 0x%04X\n", __func__, addr, (u16)data32);
+               break;
+       case 4:
+               rtw_write32(padapter, addr, data32);
+               DBG_871X(KERN_INFO "%s: addr = 0x%08X data = 0x%08X\n", __func__, addr, data32);
+               break;
+       default:
+               DBG_871X(KERN_INFO "%s: usage> write [bytes],[address(hex)],[data(hex)]\n", __func__);
+               return -EINVAL;
        }
 
        return 0;
@@ -2337,8 +2332,8 @@ static int rtw_wx_read_rf(struct net_device *dev,
        u32 path, addr, data32;
 
 
-       path = *(u32*)extra;
-       addr = *((u32*)extra + 1);
+       path = *(u32 *)extra;
+       addr = *((u32 *)extra + 1);
        data32 = rtw_hal_read_rfreg(padapter, path, addr, 0xFFFFF);
        /*
         * IMPORTANT!!
@@ -2358,9 +2353,9 @@ static int rtw_wx_write_rf(struct net_device *dev,
        u32 path, addr, data32;
 
 
-       path = *(u32*)extra;
-       addr = *((u32*)extra + 1);
-       data32 = *((u32*)extra + 2);
+       path = *(u32 *)extra;
+       addr = *((u32 *)extra + 1);
+       data32 = *((u32 *)extra + 2);
 /*     DBG_871X("%s: path =%d addr = 0x%02x data = 0x%05x\n", __func__, path, addr, data32); */
        rtw_hal_write_rfreg(padapter, path, addr, 0xFFFFF, data32);
 
@@ -2584,7 +2579,7 @@ static int rtw_wps_start(struct net_device *dev,
                goto exit;
        }
 
-       uintRet = copy_from_user((void*)&u32wps_start, pdata->pointer, 4);
+       uintRet = copy_from_user((void *)&u32wps_start, pdata->pointer, 4);
        if (u32wps_start == 0)
                u32wps_start = *extra;
 
@@ -2601,9 +2596,7 @@ static int rtw_p2p_set(struct net_device *dev,
                                union iwreq_data *wrqu, char *extra)
 {
 
-       int ret = 0;
-
-       return ret;
+       return 0;
 
 }
 
@@ -2612,9 +2605,7 @@ static int rtw_p2p_get(struct net_device *dev,
                                union iwreq_data *wrqu, char *extra)
 {
 
-       int ret = 0;
-
-       return ret;
+       return 0;
 
 }
 
@@ -2623,9 +2614,7 @@ static int rtw_p2p_get2(struct net_device *dev,
                                                union iwreq_data *wrqu, char *extra)
 {
 
-       int ret = 0;
-
-       return ret;
+       return 0;
 
 }
 
@@ -2682,7 +2671,6 @@ static int rtw_dbg_port(struct net_device *dev,
                                struct iw_request_info *info,
                                union iwreq_data *wrqu, char *extra)
 {
-       int ret = 0;
        u8 major_cmd, minor_cmd;
        u16 arg;
        u32 extra_arg, *pdata, val32;
@@ -2695,7 +2683,7 @@ static int rtw_dbg_port(struct net_device *dev,
        struct sta_priv *pstapriv = &padapter->stapriv;
 
 
-       pdata = (u32*)&wrqu->data;
+       pdata = (u32 *)&wrqu->data;
 
        val32 = *pdata;
        arg = (u16)(val32&0x0000ffff);
@@ -3097,7 +3085,7 @@ static int rtw_dbg_port(struct net_device *dev,
 
                                                        DBG_871X("enable driver ctrl ampdu density = %d\n", extra_arg);
 
-                                                       if ((extra_arg & 0x07) > 0x07)
+                                                       if (extra_arg > 0x07)
                                                                padapter->driver_ampdu_spacing = 0xFF;
                                                        else
                                                                padapter->driver_ampdu_spacing = extra_arg;
@@ -3263,7 +3251,7 @@ static int rtw_dbg_port(struct net_device *dev,
        }
 
 
-       return ret;
+       return 0;
 
 }
 
@@ -3366,23 +3354,23 @@ static int wpa_mlme(struct net_device *dev, u32 command, u32 reason)
        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
 
        switch (command) {
-               case IEEE_MLME_STA_DEAUTH:
+       case IEEE_MLME_STA_DEAUTH:
 
-                       if (!rtw_set_802_11_disassociate(padapter))
-                               ret = -1;
+               if (!rtw_set_802_11_disassociate(padapter))
+                       ret = -1;
 
-                       break;
+               break;
 
-               case IEEE_MLME_STA_DISASSOC:
+       case IEEE_MLME_STA_DISASSOC:
 
-                       if (!rtw_set_802_11_disassociate(padapter))
-                               ret = -1;
+               if (!rtw_set_802_11_disassociate(padapter))
+                       ret = -1;
 
-                       break;
+               break;
 
-               default:
-                       ret = -EOPNOTSUPP;
-                       break;
+       default:
+               ret = -EOPNOTSUPP;
+               break;
        }
 
        return ret;
@@ -3421,7 +3409,7 @@ static int wpa_supplicant_ioctl(struct net_device *dev, struct iw_point *p)
 
        case IEEE_CMD_SET_WPA_IE:
                /* ret = wpa_set_wpa_ie(dev, param, p->length); */
-               ret =  rtw_set_wpa_ie((struct adapter *)rtw_netdev_priv(dev), (char*)param->u.wpa_ie.data, (u16)param->u.wpa_ie.len);
+               ret =  rtw_set_wpa_ie((struct adapter *)rtw_netdev_priv(dev), (char *)param->u.wpa_ie.data, (u16)param->u.wpa_ie.len);
                break;
 
        case IEEE_CMD_SET_ENCRYPTION:
@@ -3522,14 +3510,12 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
                if (wep_key_len > 0) {
                        wep_key_len = wep_key_len <= 5 ? 5 : 13;
                        wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial);
-                       pwep = rtw_malloc(wep_total_len);
+                       pwep = kzalloc(wep_total_len, GFP_KERNEL);
                        if (pwep == NULL) {
                                DBG_871X(" r871x_set_encryption: pwep allocate fail !!!\n");
                                goto exit;
                        }
 
-                       memset(pwep, 0, wep_total_len);
-
                        pwep->KeyLength = wep_key_len;
                        pwep->Length = wep_total_len;
 
@@ -3754,7 +3740,7 @@ static int rtw_set_beacon(struct net_device *dev, struct ieee_param *param, int
 
 }
 
-static int rtw_hostapd_sta_flush(struct net_device *dev)
+static void rtw_hostapd_sta_flush(struct net_device *dev)
 {
        /* _irqL irqL; */
        /* struct list_head     *phead, *plist; */
@@ -3766,8 +3752,7 @@ static int rtw_hostapd_sta_flush(struct net_device *dev)
 
        flush_all_cam_entry(padapter);  /* clear CAM */
 
-       return rtw_sta_flush(padapter);
-
+       rtw_sta_flush(padapter);
 }
 
 static int rtw_add_sta(struct net_device *dev, struct ieee_param *param)
@@ -3826,7 +3811,7 @@ static int rtw_add_sta(struct net_device *dev, struct ieee_param *param)
                if (WLAN_STA_HT&flags) {
                        psta->htpriv.ht_option = true;
                        psta->qos_option = 1;
-                       memcpy((void*)&psta->htpriv.ht_cap, (void*)&param->u.add_sta.ht_cap, sizeof(struct rtw_ieee80211_ht_cap));
+                       memcpy((void *)&psta->htpriv.ht_cap, (void *)&param->u.add_sta.ht_cap, sizeof(struct rtw_ieee80211_ht_cap));
                } else {
                        psta->htpriv.ht_option = false;
                }
@@ -4176,7 +4161,8 @@ static int rtw_ioctl_acl_remove_sta(struct net_device *dev, struct ieee_param *p
                return -EINVAL;
        }
 
-       return rtw_acl_remove_sta(padapter, param->sta_addr);
+       rtw_acl_remove_sta(padapter, param->sta_addr);
+       return 0;
 
 }
 
@@ -4252,94 +4238,94 @@ static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p)
        /* DBG_871X("%s, cmd =%d\n", __func__, param->cmd); */
 
        switch (param->cmd) {
-               case RTL871X_HOSTAPD_FLUSH:
+       case RTL871X_HOSTAPD_FLUSH:
 
-                       ret = rtw_hostapd_sta_flush(dev);
+               rtw_hostapd_sta_flush(dev);
 
-                       break;
+               break;
 
-               case RTL871X_HOSTAPD_ADD_STA:
+       case RTL871X_HOSTAPD_ADD_STA:
 
-                       ret = rtw_add_sta(dev, param);
+               ret = rtw_add_sta(dev, param);
 
-                       break;
+               break;
 
-               case RTL871X_HOSTAPD_REMOVE_STA:
+       case RTL871X_HOSTAPD_REMOVE_STA:
 
-                       ret = rtw_del_sta(dev, param);
+               ret = rtw_del_sta(dev, param);
 
-                       break;
+               break;
 
-               case RTL871X_HOSTAPD_SET_BEACON:
+       case RTL871X_HOSTAPD_SET_BEACON:
 
-                       ret = rtw_set_beacon(dev, param, p->length);
+               ret = rtw_set_beacon(dev, param, p->length);
 
-                       break;
+               break;
 
-               case RTL871X_SET_ENCRYPTION:
+       case RTL871X_SET_ENCRYPTION:
 
-                       ret = rtw_set_encryption(dev, param, p->length);
+               ret = rtw_set_encryption(dev, param, p->length);
 
-                       break;
+               break;
 
-               case RTL871X_HOSTAPD_GET_WPAIE_STA:
+       case RTL871X_HOSTAPD_GET_WPAIE_STA:
 
-                       ret = rtw_get_sta_wpaie(dev, param);
+               ret = rtw_get_sta_wpaie(dev, param);
 
-                       break;
+               break;
 
-               case RTL871X_HOSTAPD_SET_WPS_BEACON:
+       case RTL871X_HOSTAPD_SET_WPS_BEACON:
 
-                       ret = rtw_set_wps_beacon(dev, param, p->length);
+               ret = rtw_set_wps_beacon(dev, param, p->length);
 
-                       break;
+               break;
 
-               case RTL871X_HOSTAPD_SET_WPS_PROBE_RESP:
+       case RTL871X_HOSTAPD_SET_WPS_PROBE_RESP:
 
-                       ret = rtw_set_wps_probe_resp(dev, param, p->length);
+               ret = rtw_set_wps_probe_resp(dev, param, p->length);
 
-                       break;
+               break;
 
-               case RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP:
+       case RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP:
 
-                       ret = rtw_set_wps_assoc_resp(dev, param, p->length);
+               ret = rtw_set_wps_assoc_resp(dev, param, p->length);
 
-                       break;
+               break;
 
-               case RTL871X_HOSTAPD_SET_HIDDEN_SSID:
+       case RTL871X_HOSTAPD_SET_HIDDEN_SSID:
 
-                       ret = rtw_set_hidden_ssid(dev, param, p->length);
+               ret = rtw_set_hidden_ssid(dev, param, p->length);
 
-                       break;
+               break;
 
-               case RTL871X_HOSTAPD_GET_INFO_STA:
+       case RTL871X_HOSTAPD_GET_INFO_STA:
 
-                       ret = rtw_ioctl_get_sta_data(dev, param, p->length);
+               ret = rtw_ioctl_get_sta_data(dev, param, p->length);
 
-                       break;
+               break;
 
-               case RTL871X_HOSTAPD_SET_MACADDR_ACL:
+       case RTL871X_HOSTAPD_SET_MACADDR_ACL:
 
-                       ret = rtw_ioctl_set_macaddr_acl(dev, param, p->length);
+               ret = rtw_ioctl_set_macaddr_acl(dev, param, p->length);
 
-                       break;
+               break;
 
-               case RTL871X_HOSTAPD_ACL_ADD_STA:
+       case RTL871X_HOSTAPD_ACL_ADD_STA:
 
-                       ret = rtw_ioctl_acl_add_sta(dev, param, p->length);
+               ret = rtw_ioctl_acl_add_sta(dev, param, p->length);
 
-                       break;
+               break;
 
-               case RTL871X_HOSTAPD_ACL_REMOVE_STA:
+       case RTL871X_HOSTAPD_ACL_REMOVE_STA:
 
-                       ret = rtw_ioctl_acl_remove_sta(dev, param, p->length);
+               ret = rtw_ioctl_acl_remove_sta(dev, param, p->length);
 
-                       break;
+               break;
 
-               default:
-                       DBG_871X("Unknown hostapd request: %d\n", param->cmd);
-                       ret = -EOPNOTSUPP;
-                       break;
+       default:
+               DBG_871X("Unknown hostapd request: %d\n", param->cmd);
+               ret = -EOPNOTSUPP;
+               break;
 
        }
 
@@ -4370,7 +4356,7 @@ static int rtw_wx_set_priv(struct net_device *dev,
        char *ext;
 
        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
-       struct iw_point *dwrq = (struct iw_point*)awrq;
+       struct iw_point *dwrq = (struct iw_point *)awrq;
 
        /* RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_notice_, ("+rtw_wx_set_priv\n")); */
        if (dwrq->length == 0)
@@ -4542,7 +4528,7 @@ static int rtw_test(
        }
        DBG_871X("%s: string =\"%s\"\n", __func__, pbuf);
 
-       ptmp = (char*)pbuf;
+       ptmp = (char *)pbuf;
        pch = strsep(&ptmp, delim);
        if ((pch == NULL) || (strlen(pch) == 0)) {
                kfree(pbuf);
@@ -4551,10 +4537,10 @@ static int rtw_test(
        }
 
        if (strcmp(pch, "bton") == 0)
-               rtw_btcoex_SetManualControl(padapter, false);
+               hal_btcoex_SetManualControl(padapter, false);
 
        if (strcmp(pch, "btoff") == 0)
-               rtw_btcoex_SetManualControl(padapter, true);
+               hal_btcoex_SetManualControl(padapter, true);
 
        if (strcmp(pch, "h2c") == 0) {
                u8 param[8];
@@ -5015,62 +5001,62 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_
                u8 *str;
 
                switch (priv_args[k].set_args & IW_PRIV_TYPE_MASK) {
-                       case IW_PRIV_TYPE_BYTE:
-                               /* Fetch args */
-                               count = 0;
-                               do {
-                                       str = strsep(&ptr, delim);
-                                       if (NULL == str) break;
-                                       sscanf(str, "%i", &temp);
-                                       buffer[count++] = (u8)temp;
-                               } while (1);
-                               buffer_len = count;
-
-                               /* Number of args to fetch */
-                               wdata.data.length = count;
-                               if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
-                                       wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
+               case IW_PRIV_TYPE_BYTE:
+                       /* Fetch args */
+                       count = 0;
+                       do {
+                               str = strsep(&ptr, delim);
+                               if (NULL == str) break;
+                               sscanf(str, "%i", &temp);
+                               buffer[count++] = (u8)temp;
+                       } while (1);
+                       buffer_len = count;
+
+                       /* Number of args to fetch */
+                       wdata.data.length = count;
+                       if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
+                               wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
 
-                               break;
+                       break;
 
-                       case IW_PRIV_TYPE_INT:
-                               /* Fetch args */
-                               count = 0;
-                               do {
-                                       str = strsep(&ptr, delim);
-                                       if (NULL == str) break;
-                                       sscanf(str, "%i", &temp);
-                                       ((s32*)buffer)[count++] = (s32)temp;
-                               } while (1);
-                               buffer_len = count * sizeof(s32);
-
-                               /* Number of args to fetch */
-                               wdata.data.length = count;
-                               if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
-                                       wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
+               case IW_PRIV_TYPE_INT:
+                       /* Fetch args */
+                       count = 0;
+                       do {
+                               str = strsep(&ptr, delim);
+                               if (NULL == str) break;
+                               sscanf(str, "%i", &temp);
+                               ((s32 *)buffer)[count++] = (s32)temp;
+                       } while (1);
+                       buffer_len = count * sizeof(s32);
+
+                       /* Number of args to fetch */
+                       wdata.data.length = count;
+                       if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
+                               wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
 
-                               break;
+                       break;
 
-                       case IW_PRIV_TYPE_CHAR:
-                               if (len > 0) {
-                                       /* Size of the string to fetch */
-                                       wdata.data.length = len;
-                                       if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
-                                               wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
+               case IW_PRIV_TYPE_CHAR:
+                       if (len > 0) {
+                               /* Size of the string to fetch */
+                               wdata.data.length = len;
+                               if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
+                                       wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
 
-                                       /* Fetch string */
-                                       memcpy(buffer, ptr, wdata.data.length);
-                               } else {
-                                       wdata.data.length = 1;
-                                       buffer[0] = '\0';
-                               }
-                               buffer_len = wdata.data.length;
-                               break;
+                               /* Fetch string */
+                               memcpy(buffer, ptr, wdata.data.length);
+                       } else {
+                               wdata.data.length = 1;
+                               buffer[0] = '\0';
+                       }
+                       buffer_len = wdata.data.length;
+                       break;
 
-                       default:
-                               DBG_8192C("%s: Not yet implemented...\n", __func__);
-                               err = -1;
-                               goto exit;
+               default:
+                       DBG_8192C("%s: Not yet implemented...\n", __func__);
+                       err = -1;
+                       goto exit;
                }
 
                if ((priv_args[k].set_args & IW_PRIV_SIZE_FIXED) &&
@@ -5162,43 +5148,43 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_
                }
 
                switch (priv_args[k].get_args & IW_PRIV_TYPE_MASK) {
-                       case IW_PRIV_TYPE_BYTE:
-                               /* Display args */
-                               for (j = 0; j < n; j++) {
-                                       sprintf(str, "%d  ", extra[j]);
-                                       len = strlen(str);
-                                       output_len = strlen(output);
-                                       if ((output_len + len + 1) > 4096) {
-                                               err = -E2BIG;
-                                               goto exit;
-                                       }
-                                       memcpy(output+output_len, str, len);
+               case IW_PRIV_TYPE_BYTE:
+                       /* Display args */
+                       for (j = 0; j < n; j++) {
+                               sprintf(str, "%d  ", extra[j]);
+                               len = strlen(str);
+                               output_len = strlen(output);
+                               if ((output_len + len + 1) > 4096) {
+                                       err = -E2BIG;
+                                       goto exit;
                                }
-                               break;
+                               memcpy(output+output_len, str, len);
+                       }
+                       break;
 
-                       case IW_PRIV_TYPE_INT:
-                               /* Display args */
-                               for (j = 0; j < n; j++) {
-                                       sprintf(str, "%d  ", ((__s32*)extra)[j]);
-                                       len = strlen(str);
-                                       output_len = strlen(output);
-                                       if ((output_len + len + 1) > 4096) {
-                                               err = -E2BIG;
-                                               goto exit;
-                                       }
-                                       memcpy(output+output_len, str, len);
+               case IW_PRIV_TYPE_INT:
+                       /* Display args */
+                       for (j = 0; j < n; j++) {
+                               sprintf(str, "%d  ", ((__s32 *)extra)[j]);
+                               len = strlen(str);
+                               output_len = strlen(output);
+                               if ((output_len + len + 1) > 4096) {
+                                       err = -E2BIG;
+                                       goto exit;
                                }
-                               break;
+                               memcpy(output+output_len, str, len);
+                       }
+                       break;
 
-                       case IW_PRIV_TYPE_CHAR:
-                               /* Display args */
-                               memcpy(output, extra, n);
-                               break;
+               case IW_PRIV_TYPE_CHAR:
+                       /* Display args */
+                       memcpy(output, extra, n);
+                       break;
 
-                       default:
-                               DBG_8192C("%s: Not yet implemented...\n", __func__);
-                               err = -1;
-                               goto exit;
+               default:
+                       DBG_8192C("%s: Not yet implemented...\n", __func__);
+                       err = -1;
+                       goto exit;
                }
 
                output_len = strlen(output) + 1;
@@ -5225,18 +5211,18 @@ int rtw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        int ret = 0;
 
        switch (cmd) {
-               case RTL_IOCTL_WPA_SUPPLICANT:
-                       ret = wpa_supplicant_ioctl(dev, &wrq->u.data);
-                       break;
-               case RTL_IOCTL_HOSTAPD:
-                       ret = rtw_hostapd_ioctl(dev, &wrq->u.data);
-                       break;
-               case SIOCDEVPRIVATE:
-                       ret = rtw_ioctl_wext_private(dev, &wrq->u);
-                       break;
-               default:
-                       ret = -EOPNOTSUPP;
-                       break;
+       case RTL_IOCTL_WPA_SUPPLICANT:
+               ret = wpa_supplicant_ioctl(dev, &wrq->u.data);
+               break;
+       case RTL_IOCTL_HOSTAPD:
+               ret = rtw_hostapd_ioctl(dev, &wrq->u.data);
+               break;
+       case SIOCDEVPRIVATE:
+               ret = rtw_ioctl_wext_private(dev, &wrq->u);
+               break;
+       default:
+               ret = -EOPNOTSUPP;
+               break;
        }
 
        return ret;
index da4bd52..52a5b31 100644 (file)
@@ -26,7 +26,7 @@ static void _rtw_set_scan_deny_timer_hdl(struct timer_list *t)
        struct adapter *adapter =
                from_timer(adapter, t, mlmepriv.set_scan_deny_timer);
 
-       rtw_set_scan_deny_timer_hdl(adapter);
+       rtw_clear_scan_deny(adapter);
 }
 
 void rtw_init_mlme_timer(struct adapter *padapter)
@@ -46,11 +46,9 @@ void rtw_os_indicate_connect(struct adapter *adapter)
        struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
 
        if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) ||
-               (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true))
-       {
+               (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) {
                rtw_cfg80211_ibss_indicate_connect(adapter);
-       }
-       else
+       } else
                rtw_cfg80211_indicate_connect(adapter);
 
        rtw_indicate_wx_assoc_event(adapter);
@@ -77,8 +75,8 @@ void rtw_reset_securitypriv(struct adapter *adapter)
 
        spin_lock_bh(&adapter->security_key_mutex);
 
-       if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)/* 802.1x */
-       {
+       if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) {
+               /* 802.1x */
                /*  Added by Albert 2009/02/18 */
                /*  We have to backup the PMK information for WiFi PMK Caching test item. */
                /*  */
@@ -105,9 +103,8 @@ void rtw_reset_securitypriv(struct adapter *adapter)
                adapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
                adapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled;
 
-       }
-       else /* reset values in securitypriv */
-       {
+       } else {
+               /* reset values in securitypriv */
                /* if (adapter->mlmepriv.fw_state & WIFI_STATION_STATE) */
                /*  */
                struct security_priv *psec_priv = &adapter->securitypriv;
@@ -150,8 +147,7 @@ void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie)
        RT_TRACE(_module_mlme_osdep_c_, _drv_info_, ("+rtw_report_sec_ie, authmode =%d\n", authmode));
 
        buff = NULL;
-       if (authmode == _WPA_IE_ID_)
-       {
+       if (authmode == _WPA_IE_ID_) {
                RT_TRACE(_module_mlme_osdep_c_, _drv_info_, ("rtw_report_sec_ie, authmode =%d\n", authmode));
 
                buff = rtw_zmalloc(IW_CUSTOM_MAX);
index 8a9d838..544e799 100644 (file)
@@ -223,9 +223,8 @@ int _netdev_open(struct net_device *pnetdev);
 int netdev_open (struct net_device *pnetdev);
 static int netdev_close (struct net_device *pnetdev);
 
-static uint loadparam(struct adapter *padapter, _nic_hdl pnetdev)
+static void loadparam(struct adapter *padapter, _nic_hdl pnetdev)
 {
-       uint status = _SUCCESS;
        struct registry_priv  *registry_par = &padapter->registrypriv;
 
        registry_par->chip_version = (u8)rtw_chip_version;
@@ -330,7 +329,6 @@ static uint loadparam(struct adapter *padapter, _nic_hdl pnetdev)
        registry_par->qos_opt_enable = (u8)rtw_qos_opt_enable;
 
        registry_par->hiq_filter = (u8)rtw_hiq_filter;
-       return status;
 }
 
 static int rtw_net_set_mac_address(struct net_device *pnetdev, void *p)
@@ -601,9 +599,8 @@ void rtw_stop_drv_threads (struct adapter *padapter)
        rtw_hal_stop_thread(padapter);
 }
 
-static u8 rtw_init_default_value(struct adapter *padapter)
+static void rtw_init_default_value(struct adapter *padapter)
 {
-       u8 ret  = _SUCCESS;
        struct registry_priv *pregistrypriv = &padapter->registrypriv;
        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
@@ -665,7 +662,6 @@ static u8 rtw_init_default_value(struct adapter *padapter)
        padapter->driver_ampdu_spacing = 0xFF;
        padapter->driver_rx_ampdu_factor =  0xFF;
 
-       return ret;
 }
 
 struct dvobj_priv *devobj_init(void)
@@ -707,9 +703,8 @@ void devobj_deinit(struct dvobj_priv *pdvobj)
        kfree(pdvobj);
 }
 
-u8 rtw_reset_drv_sw(struct adapter *padapter)
+void rtw_reset_drv_sw(struct adapter *padapter)
 {
-       u8 ret8 = _SUCCESS;
        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
        struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter);
 
@@ -739,7 +734,6 @@ u8 rtw_reset_drv_sw(struct adapter *padapter)
 
        rtw_set_signal_stat_timer(&padapter->recvpriv);
 
-       return ret8;
 }
 
 
@@ -749,7 +743,7 @@ u8 rtw_init_drv_sw(struct adapter *padapter)
 
        RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_init_drv_sw\n"));
 
-       ret8 = rtw_init_default_value(padapter);
+       rtw_init_default_value(padapter);
 
        rtw_init_hal_com_default_value(padapter);
 
@@ -1214,7 +1208,7 @@ void rtw_dev_unload(struct adapter *padapter)
                }
 
                if (padapter->bSurpriseRemoved == false) {
-                       rtw_btcoex_IpsNotify(padapter, pwrctl->ips_mode_req);
+                       hal_btcoex_IpsNotify(padapter, pwrctl->ips_mode_req);
 #ifdef CONFIG_WOWLAN
                        if (pwrctl->bSupportRemoteWakeup == true &&
                                pwrctl->wowlan_mode == true) {
@@ -1289,14 +1283,13 @@ static int rtw_suspend_free_assoc_resource(struct adapter *padapter)
 }
 
 #ifdef CONFIG_WOWLAN
-int rtw_suspend_wow(struct adapter *padapter)
+void rtw_suspend_wow(struct adapter *padapter)
 {
        u8 ch, bw, offset;
        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
        struct net_device *pnetdev = padapter->pnetdev;
        struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
        struct wowlan_ioctl_param poidparam;
-       int ret = _SUCCESS;
 
        DBG_871X("==> " FUNC_ADPT_FMT " entry....\n", FUNC_ADPT_ARG(padapter));
 
@@ -1364,7 +1357,6 @@ int rtw_suspend_wow(struct adapter *padapter)
                DBG_871X_LEVEL(_drv_always_, "%s: ### ERROR ### wowlan_mode =%d\n", __func__, pwrpriv->wowlan_mode);
        }
        DBG_871X("<== " FUNC_ADPT_FMT " exit....\n", FUNC_ADPT_ARG(padapter));
-       return ret;
 }
 #endif /* ifdef CONFIG_WOWLAN */
 
@@ -1422,10 +1414,9 @@ int rtw_suspend_ap_wow(struct adapter *padapter)
 #endif /* ifdef CONFIG_AP_WOWLAN */
 
 
-static int rtw_suspend_normal(struct adapter *padapter)
+static void rtw_suspend_normal(struct adapter *padapter)
 {
        struct net_device *pnetdev = padapter->pnetdev;
-       int ret = _SUCCESS;
 
        DBG_871X("==> " FUNC_ADPT_FMT " entry....\n", FUNC_ADPT_ARG(padapter));
        if (pnetdev) {
@@ -1447,7 +1438,6 @@ static int rtw_suspend_normal(struct adapter *padapter)
                padapter->intf_deinit(adapter_to_dvobj(padapter));
 
        DBG_871X("<== " FUNC_ADPT_FMT " exit....\n", FUNC_ADPT_ARG(padapter));
-       return ret;
 }
 
 int rtw_suspend_common(struct adapter *padapter)
@@ -1485,10 +1475,10 @@ int rtw_suspend_common(struct adapter *padapter)
 
        /*  wait for the latest FW to remove this condition. */
        if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
-               rtw_btcoex_SuspendNotify(padapter, 0);
+               hal_btcoex_SuspendNotify(padapter, 0);
                DBG_871X("WIFI_AP_STATE\n");
        } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) {
-               rtw_btcoex_SuspendNotify(padapter, 1);
+               hal_btcoex_SuspendNotify(padapter, 1);
                DBG_871X("STATION\n");
        }
 
@@ -1839,7 +1829,7 @@ int rtw_resume_common(struct adapter *padapter)
                rtw_resume_process_normal(padapter);
        }
 
-       rtw_btcoex_SuspendNotify(padapter, 0);
+       hal_btcoex_SuspendNotify(padapter, 0);
 
        if (pwrpriv) {
                pwrpriv->bInSuspend = false;
index a5a5a5c..62fdd24 100644 (file)
@@ -77,13 +77,13 @@ static int openFile(struct file **fpp, char *path, int flag, int mode)
 {
        struct file *fp;
 
-       fp =filp_open(path, flag, mode);
+       fp = filp_open(path, flag, mode);
        if (IS_ERR(fp)) {
                *fpp = NULL;
                return PTR_ERR(fp);
        }
        else {
-               *fpp =fp;
+               *fpp = fp;
                return 0;
        }
 }
@@ -106,10 +106,10 @@ static int readFile(struct file *fp, char *buf, int len)
        if (!fp->f_op || !fp->f_op->read)
                return -EPERM;
 
-       while (sum<len) {
+       while (sum < len) {
                rlen = kernel_read(fp, buf + sum, len - sum, &fp->f_pos);
-               if (rlen>0)
-                       sum+=rlen;
+               if (rlen > 0)
+                       sum += rlen;
                else if (0 != rlen)
                        return rlen;
                else
@@ -131,7 +131,7 @@ static int isFileReadable(char *path)
        int ret = 0;
        char buf;
 
-       fp =filp_open(path, O_RDONLY, 0);
+       fp = filp_open(path, O_RDONLY, 0);
        if (IS_ERR(fp))
                return PTR_ERR(fp);
 
@@ -151,7 +151,7 @@ static int isFileReadable(char *path)
 */
 static int retriveFromFile(char *path, u8 *buf, u32 sz)
 {
-       int ret =-1;
+       int ret = -1;
        struct file *fp;
 
        if (path && buf) {
@@ -160,7 +160,7 @@ static int retriveFromFile(char *path, u8 *buf, u32 sz)
                if (ret == 0) {
                        DBG_871X("%s openFile path:%s fp =%p\n", __func__, path , fp);
 
-                       ret =readFile(fp, buf, sz);
+                       ret = readFile(fp, buf, sz);
                        closeFile(fp);
 
                        DBG_871X("%s readFile, ret:%d\n", __func__, ret);
@@ -197,8 +197,8 @@ int rtw_is_file_readable(char *path)
 */
 int rtw_retrive_from_file(char *path, u8 *buf, u32 sz)
 {
-       int ret =retriveFromFile(path, buf, sz);
-       return ret>= 0?ret:0;
+       int ret = retriveFromFile(path, buf, sz);
+       return ret >= 0 ? ret : 0;
 }
 
 struct net_device *rtw_alloc_etherdev_with_old_priv(int sizeof_priv, void *old_priv)
@@ -211,8 +211,8 @@ struct net_device *rtw_alloc_etherdev_with_old_priv(int sizeof_priv, void *old_p
                goto RETURN;
 
        pnpi = netdev_priv(pnetdev);
-       pnpi->priv =old_priv;
-       pnpi->sizeof_priv =sizeof_priv;
+       pnpi->priv = old_priv;
+       pnpi->sizeof_priv = sizeof_priv;
 
 RETURN:
        return pnetdev;
@@ -236,7 +236,7 @@ struct net_device *rtw_alloc_etherdev(int sizeof_priv)
                goto RETURN;
        }
 
-       pnpi->sizeof_priv =sizeof_priv;
+       pnpi->sizeof_priv = sizeof_priv;
 RETURN:
        return pnetdev;
 }
@@ -284,7 +284,7 @@ int rtw_change_ifname(struct adapter *padapter, const char *ifname)
        else
                unregister_netdevice(cur_pnetdev);
 
-       rereg_priv->old_pnetdev =cur_pnetdev;
+       rereg_priv->old_pnetdev = cur_pnetdev;
 
        pnetdev = rtw_init_netdev(padapter);
        if (!pnetdev)  {
@@ -316,11 +316,6 @@ error:
 
 }
 
-u64 rtw_modular64(u64 x, u64 y)
-{
-       return do_div(x, y);
-}
-
 void rtw_buf_free(u8 **buf, u32 *buf_len)
 {
        u32 ori_len;
@@ -379,7 +374,7 @@ keep_ori:
  */
 inline bool rtw_cbuf_full(struct rtw_cbuf *cbuf)
 {
-       return (cbuf->write == cbuf->read-1)? true : false;
+       return (cbuf->write == cbuf->read - 1) ? true : false;
 }
 
 /**
@@ -390,7 +385,7 @@ inline bool rtw_cbuf_full(struct rtw_cbuf *cbuf)
  */
 inline bool rtw_cbuf_empty(struct rtw_cbuf *cbuf)
 {
-       return (cbuf->write == cbuf->read)? true : false;
+       return (cbuf->write == cbuf->read) ? true : false;
 }
 
 /**
@@ -408,7 +403,7 @@ bool rtw_cbuf_push(struct rtw_cbuf *cbuf, void *buf)
 
        DBG_871X("%s on %u\n", __func__, cbuf->write);
        cbuf->bufs[cbuf->write] = buf;
-       cbuf->write = (cbuf->write+1)%cbuf->size;
+       cbuf->write = (cbuf->write + 1) % cbuf->size;
 
        return _SUCCESS;
 }
@@ -428,7 +423,7 @@ void *rtw_cbuf_pop(struct rtw_cbuf *cbuf)
 
         DBG_871X("%s on %u\n", __func__, cbuf->read);
        buf = cbuf->bufs[cbuf->read];
-       cbuf->read = (cbuf->read+1)%cbuf->size;
+       cbuf->read = (cbuf->read + 1) % cbuf->size;
 
        return buf;
 }
index 67ec336..643cacc 100644 (file)
@@ -12,8 +12,7 @@
 
 void rtw_os_free_recvframe(union recv_frame *precvframe)
 {
-       if (precvframe->u.hdr.pkt)
-       {
+       if (precvframe->u.hdr.pkt) {
                dev_kfree_skb_any(precvframe->u.hdr.pkt);/* free skb by driver */
 
                precvframe->u.hdr.pkt = NULL;
@@ -21,13 +20,9 @@ void rtw_os_free_recvframe(union recv_frame *precvframe)
 }
 
 /* alloc os related resource in union recv_frame */
-int rtw_os_recv_resource_alloc(struct adapter *padapter, union recv_frame *precvframe)
+void rtw_os_recv_resource_alloc(struct adapter *padapter, union recv_frame *precvframe)
 {
-       int     res = _SUCCESS;
-
        precvframe->u.hdr.pkt_newalloc = precvframe->u.hdr.pkt = NULL;
-
-       return res;
 }
 
 /* free os related resource in union recv_frame */
@@ -38,10 +33,8 @@ void rtw_os_recv_resource_free(struct recv_priv *precvpriv)
 
        precvframe = (union recv_frame*) precvpriv->precv_frame_buf;
 
-       for (i = 0; i < NR_RECVFRAME; i++)
-       {
-               if (precvframe->u.hdr.pkt)
-               {
+       for (i = 0; i < NR_RECVFRAME; i++) {
+               if (precvframe->u.hdr.pkt) {
                        dev_kfree_skb_any(precvframe->u.hdr.pkt);/* free skb by driver */
                        precvframe->u.hdr.pkt = NULL;
                }
@@ -50,16 +43,11 @@ void rtw_os_recv_resource_free(struct recv_priv *precvpriv)
 }
 
 /* free os related resource in struct recv_buf */
-int rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *precvbuf)
+void rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *precvbuf)
 {
-       int ret = _SUCCESS;
-
-       if (precvbuf->pskb)
-       {
+       if (precvbuf->pskb) {
                dev_kfree_skb_any(precvbuf->pskb);
        }
-       return ret;
-
 }
 
 _pkt *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata)
@@ -71,22 +59,16 @@ _pkt *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8
        pattrib = &prframe->u.hdr.attrib;
 
        sub_skb = rtw_skb_alloc(nSubframe_Length + 12);
-       if (sub_skb)
-       {
+       if (sub_skb) {
                skb_reserve(sub_skb, 12);
                skb_put_data(sub_skb, (pdata + ETH_HLEN), nSubframe_Length);
-       }
-       else
-       {
+       } else {
                sub_skb = rtw_skb_clone(prframe->u.hdr.pkt);
-               if (sub_skb)
-               {
+               if (sub_skb) {
                        sub_skb->data = pdata + ETH_HLEN;
                        sub_skb->len = nSubframe_Length;
                        skb_set_tail_pointer(sub_skb, nSubframe_Length);
-               }
-               else
-               {
+               } else {
                        DBG_871X("%s(): rtw_skb_clone() Fail!!!\n", __func__);
                        return NULL;
                }
@@ -121,8 +103,7 @@ void rtw_os_recv_indicate_pkt(struct adapter *padapter, _pkt *pkt, struct rx_pkt
 
        /* Indicat the packets to upper layer */
        if (pkt) {
-               if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)
-               {
+               if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
                        _pkt *pskb2 = NULL;
                        struct sta_info *psta = NULL;
                        struct sta_priv *pstapriv = &padapter->stapriv;
@@ -130,20 +111,17 @@ void rtw_os_recv_indicate_pkt(struct adapter *padapter, _pkt *pkt, struct rx_pkt
 
                        /* DBG_871X("bmcast =%d\n", bmcast); */
 
-                       if (memcmp(pattrib->dst, myid(&padapter->eeprompriv), ETH_ALEN))
-                       {
+                       if (memcmp(pattrib->dst, myid(&padapter->eeprompriv), ETH_ALEN)) {
                                /* DBG_871X("not ap psta =%p, addr =%pM\n", psta, pattrib->dst); */
 
-                               if (bmcast)
-                               {
+                               if (bmcast) {
                                        psta = rtw_get_bcmc_stainfo(padapter);
                                        pskb2 = rtw_skb_clone(pkt);
                                } else {
                                        psta = rtw_get_stainfo(pstapriv, pattrib->dst);
                                }
 
-                               if (psta)
-                               {
+                               if (psta) {
                                        struct net_device *pnetdev = (struct net_device*)padapter->pnetdev;
 
                                        /* DBG_871X("directly forwarding to the rtw_xmit_entry\n"); */
@@ -162,9 +140,8 @@ void rtw_os_recv_indicate_pkt(struct adapter *padapter, _pkt *pkt, struct rx_pkt
                                                return;
                                        }
                                }
-                       }
-                       else/*  to APself */
-                       {
+                       } else {
+                               /*  to APself */
                                /* DBG_871X("to APSelf\n"); */
                                DBG_COUNTER(padapter->rx_logs.os_indicate_ap_self);
                        }
@@ -200,32 +177,23 @@ void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup)
        struct security_priv *psecuritypriv = &padapter->securitypriv;
        unsigned long cur_time = 0;
 
-       if (psecuritypriv->last_mic_err_time == 0)
-       {
+       if (psecuritypriv->last_mic_err_time == 0) {
                psecuritypriv->last_mic_err_time = jiffies;
-       }
-       else
-       {
+       } else {
                cur_time = jiffies;
 
-               if (cur_time - psecuritypriv->last_mic_err_time < 60*HZ)
-               {
+               if (cur_time - psecuritypriv->last_mic_err_time < 60*HZ) {
                        psecuritypriv->btkip_countermeasure = true;
                        psecuritypriv->last_mic_err_time = 0;
                        psecuritypriv->btkip_countermeasure_time = cur_time;
-               }
-               else
-               {
+               } else {
                        psecuritypriv->last_mic_err_time = jiffies;
                }
        }
 
-       if (bgroup)
-       {
+       if (bgroup) {
                key_type |= NL80211_KEYTYPE_GROUP;
-       }
-       else
-       {
+       } else {
                key_type |= NL80211_KEYTYPE_PAIRWISE;
        }
 
@@ -233,13 +201,10 @@ void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup)
                NULL, GFP_ATOMIC);
 
        memset(&ev, 0x00, sizeof(ev));
-       if (bgroup)
-       {
-           ev.flags |= IW_MICFAILURE_GROUP;
-       }
-       else
-       {
-           ev.flags |= IW_MICFAILURE_PAIRWISE;
+       if (bgroup) {
+               ev.flags |= IW_MICFAILURE_GROUP;
+       } else {
+               ev.flags |= IW_MICFAILURE_PAIRWISE;
        }
 
        ev.src_addr.sa_family = ARPHRD_ETHER;
@@ -258,8 +223,7 @@ static void rtw_os_ksocket_send(struct adapter *padapter, union recv_frame *prec
 
        DBG_871X("eth rx: got eth_type = 0x%x\n", pattrib->eth_type);
 
-       if (psta && psta->isrc && psta->pid>0)
-       {
+       if (psta && psta->isrc && psta->pid>0) {
                u16 rx_pid;
 
                rx_pid = *(u16*)(skb->data+ETH_HLEN);
@@ -267,8 +231,7 @@ static void rtw_os_ksocket_send(struct adapter *padapter, union recv_frame *prec
                DBG_871X("eth rx(pid = 0x%x): sta("MAC_FMT") pid = 0x%x\n",
                        rx_pid, MAC_ARG(psta->hwaddr), psta->pid);
 
-               if (rx_pid == psta->pid)
-               {
+               if (rx_pid == psta->pid) {
                        int i;
                        u16 len = *(u16*)(skb->data+ETH_HLEN+2);
                        /* u16 ctrl_type = *(u16*)(skb->data+ETH_HLEN+4); */
@@ -301,8 +264,7 @@ int rtw_recv_indicatepkt(struct adapter *padapter, union recv_frame *precv_frame
        pfree_recv_queue = &(precvpriv->free_recv_queue);
 
        skb = precv_frame->u.hdr.pkt;
-       if (skb == NULL)
-       {
+       if (skb == NULL) {
                RT_TRACE(_module_recv_osdep_c_, _drv_err_, ("rtw_recv_indicatepkt():skb == NULL something wrong!!!!\n"));
                goto _recv_indicatepkt_drop;
        }
@@ -320,8 +282,7 @@ int rtw_recv_indicatepkt(struct adapter *padapter, union recv_frame *precv_frame
        RT_TRACE(_module_recv_osdep_c_, _drv_info_, ("\n skb->head =%p skb->data =%p skb->tail =%p skb->end =%p skb->len =%d\n", skb->head, skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), skb->len));
 
 #ifdef CONFIG_AUTO_AP_MODE
-       if (0x8899 == pattrib->eth_type)
-       {
+       if (0x8899 == pattrib->eth_type) {
                rtw_os_ksocket_send(padapter, precv_frame);
 
                /* goto _recv_indicatepkt_drop; */
@@ -336,7 +297,7 @@ int rtw_recv_indicatepkt(struct adapter *padapter, union recv_frame *precv_frame
 
        RT_TRACE(_module_recv_osdep_c_, _drv_info_, ("\n rtw_recv_indicatepkt :after rtw_os_recv_indicate_pkt!!!!\n"));
 
-        return _SUCCESS;
+       return _SUCCESS;
 
 _recv_indicatepkt_drop:
 
index d8e7ad1..5f950fd 100644 (file)
@@ -63,8 +63,7 @@ static ssize_t proc_set_log_level(struct file *file, const char __user *buffer,
 
        if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
                sscanf(tmp, "%d ", &log_level);
-               if (log_level >= _drv_always_ && log_level <= _drv_debug_)
-               {
+               if (log_level >= _drv_always_ && log_level <= _drv_debug_) {
                        GlobalDebugLevel = log_level;
                        printk("%d\n", GlobalDebugLevel);
                }
@@ -122,14 +121,14 @@ int rtw_drv_proc_init(void)
        ssize_t i;
        struct proc_dir_entry *entry = NULL;
 
-       if (rtw_proc != NULL) {
+       if (rtw_proc) {
                rtw_warn_on(1);
                goto exit;
        }
 
        rtw_proc = rtw_proc_create_dir(RTW_PROC_NAME, get_proc_net, NULL);
 
-       if (rtw_proc == NULL) {
+       if (!rtw_proc) {
                rtw_warn_on(1);
                goto exit;
        }
@@ -152,7 +151,7 @@ void rtw_drv_proc_deinit(void)
 {
        int i;
 
-       if (rtw_proc == NULL)
+       if (!rtw_proc)
                return;
 
        for (i = 0; i < drv_proc_hdls_num; i++)
@@ -224,8 +223,7 @@ static ssize_t proc_set_linked_info_dump(struct file *file, const char __user *b
                return -EFAULT;
 
        if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
-               if (padapter)
-               {
+               if (padapter) {
                        /* padapter->bLinkInfoDump = mode; */
                        /* DBG_871X("linked_info_dump =%s\n", (padapter->bLinkInfoDump)?"enable":"disable"); */
                         linked_info_dump(padapter, mode);
@@ -637,18 +635,18 @@ static struct proc_dir_entry *rtw_odm_proc_init(struct net_device *dev)
        struct adapter  *adapter = rtw_netdev_priv(dev);
        ssize_t i;
 
-       if (adapter->dir_dev == NULL) {
+       if (!adapter->dir_dev) {
                rtw_warn_on(1);
                goto exit;
        }
 
-       if (adapter->dir_odm != NULL) {
+       if (adapter->dir_odm) {
                rtw_warn_on(1);
                goto exit;
        }
 
        dir_odm = rtw_proc_create_dir("odm", adapter->dir_dev, dev);
-       if (dir_odm == NULL) {
+       if (!dir_odm) {
                rtw_warn_on(1);
                goto exit;
        }
@@ -674,7 +672,7 @@ static void rtw_odm_proc_deinit(struct adapter      *adapter)
 
        dir_odm = adapter->dir_odm;
 
-       if (dir_odm == NULL) {
+       if (!dir_odm) {
                rtw_warn_on(1);
                return;
        }
@@ -695,18 +693,18 @@ struct proc_dir_entry *rtw_adapter_proc_init(struct net_device *dev)
        struct adapter *adapter = rtw_netdev_priv(dev);
        ssize_t i;
 
-       if (drv_proc == NULL) {
+       if (!drv_proc) {
                rtw_warn_on(1);
                goto exit;
        }
 
-       if (adapter->dir_dev != NULL) {
+       if (adapter->dir_dev) {
                rtw_warn_on(1);
                goto exit;
        }
 
        dir_dev = rtw_proc_create_dir(dev->name, drv_proc, dev);
-       if (dir_dev == NULL) {
+       if (!dir_dev) {
                rtw_warn_on(1);
                goto exit;
        }
@@ -736,7 +734,7 @@ void rtw_adapter_proc_deinit(struct net_device *dev)
 
        dir_dev = adapter->dir_dev;
 
-       if (dir_dev == NULL) {
+       if (!dir_dev) {
                rtw_warn_on(1);
                return;
        }
@@ -760,7 +758,7 @@ void rtw_adapter_proc_replace(struct net_device *dev)
 
        dir_dev = adapter->dir_dev;
 
-       if (dir_dev == NULL) {
+       if (!dir_dev) {
                rtw_warn_on(1);
                return;
        }
index 0524825..540a7ee 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <drv_types.h>
 #include <rtw_debug.h>
+#include <hal_btcoex.h>
 #include <linux/jiffies.h>
 
 #ifndef dev_to_sdio_func
@@ -84,13 +85,10 @@ static int sdio_alloc_irq(struct dvobj_priv *dvobj)
        sdio_claim_host(func);
 
        err = sdio_claim_irq(func, &sd_sync_int_hdl);
-       if (err)
-       {
+       if (err) {
                dvobj->drv_dbg.dbg_sdio_alloc_irq_error_cnt++;
                printk(KERN_CRIT "%s: sdio_claim_irq FAIL(%d)!\n", __func__, err);
-       }
-       else
-       {
+       } else {
                dvobj->drv_dbg.dbg_sdio_alloc_irq_cnt++;
                dvobj->irq_alloc = 1;
        }
@@ -102,28 +100,26 @@ static int sdio_alloc_irq(struct dvobj_priv *dvobj)
 
 static void sdio_free_irq(struct dvobj_priv *dvobj)
 {
-    struct sdio_data *psdio_data;
-    struct sdio_func *func;
-    int err;
-
-    if (dvobj->irq_alloc) {
-        psdio_data = &dvobj->intf_data;
-        func = psdio_data->func;
-
-        if (func) {
-            sdio_claim_host(func);
-            err = sdio_release_irq(func);
-            if (err)
-            {
+       struct sdio_data *psdio_data;
+       struct sdio_func *func;
+       int err;
+
+       if (dvobj->irq_alloc) {
+               psdio_data = &dvobj->intf_data;
+               func = psdio_data->func;
+
+               if (func) {
+                       sdio_claim_host(func);
+                       err = sdio_release_irq(func);
+                       if (err) {
                                dvobj->drv_dbg.dbg_sdio_free_irq_error_cnt++;
                                DBG_871X_LEVEL(_drv_err_,"%s: sdio_release_irq FAIL(%d)!\n", __func__, err);
-            }
-            else
-               dvobj->drv_dbg.dbg_sdio_free_irq_cnt++;
-            sdio_release_host(func);
-        }
-        dvobj->irq_alloc = 0;
-    }
+                       } else
+                               dvobj->drv_dbg.dbg_sdio_free_irq_cnt++;
+                       sdio_release_host(func);
+               }
+               dvobj->irq_alloc = 0;
+       }
 }
 
 #ifdef CONFIG_GPIO_WAKEUP
@@ -224,20 +220,17 @@ static void sdio_deinit(struct dvobj_priv *dvobj)
        if (func) {
                sdio_claim_host(func);
                err = sdio_disable_func(func);
-               if (err)
-               {
+               if (err) {
                        dvobj->drv_dbg.dbg_sdio_deinit_error_cnt++;
                        DBG_8192C(KERN_ERR "%s: sdio_disable_func(%d)\n", __func__, err);
                }
 
                if (dvobj->irq_alloc) {
                        err = sdio_release_irq(func);
-                       if (err)
-                       {
+                       if (err) {
                                dvobj->drv_dbg.dbg_sdio_free_irq_error_cnt++;
                                DBG_8192C(KERN_ERR "%s: sdio_release_irq(%d)\n", __func__, err);
-                       }
-                       else
+                       } else
                                dvobj->drv_dbg.dbg_sdio_free_irq_cnt++;
                }
 
@@ -368,8 +361,7 @@ static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct
        padapter->intf_alloc_irq = &sdio_alloc_irq;
        padapter->intf_free_irq = &sdio_free_irq;
 
-       if (rtw_init_io_priv(padapter, sdio_set_intf_ops) == _FAIL)
-       {
+       if (rtw_init_io_priv(padapter, sdio_set_intf_ops) == _FAIL) {
                RT_TRACE(_module_hci_intfs_c_, _drv_err_,
                        ("rtw_drv_init: Can't init io_priv\n"));
                goto free_hal_data;
@@ -379,7 +371,7 @@ static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct
 
        rtw_hal_chip_configure(padapter);
 
-       rtw_btcoex_Initialize(padapter);
+       hal_btcoex_Initialize(padapter);
 
        /* 3 6. read efuse/eeprom data */
        rtw_hal_read_chip_info(padapter);
@@ -489,9 +481,8 @@ static int rtw_drv_init(
 
        /* dev_alloc_name && register_netdev */
        status = rtw_drv_register_netdev(if1);
-       if (status != _SUCCESS) {
+       if (status != _SUCCESS)
                goto free_if2;
-       }
 
        if (sdio_alloc_irq(dvobj) != _SUCCESS)
                goto free_if2;
@@ -569,14 +560,12 @@ static int rtw_sdio_suspend(struct device *dev)
        struct adapter *padapter = psdpriv->if1;
        struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
 
-       if (padapter->bDriverStopped == true)
-       {
+       if (padapter->bDriverStopped == true) {
                DBG_871X("%s bDriverStopped = %d\n", __func__, padapter->bDriverStopped);
                return 0;
        }
 
-       if (pwrpriv->bInSuspend == true)
-       {
+       if (pwrpriv->bInSuspend == true) {
                DBG_871X("%s bInSuspend = %d\n", __func__, pwrpriv->bInSuspend);
                pdbgpriv->dbg_suspend_error_cnt++;
                return 0;
@@ -591,8 +580,7 @@ static int rtw_resume_process(struct adapter *padapter)
        struct dvobj_priv *psdpriv = padapter->dvobj;
        struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
 
-       if (pwrpriv->bInSuspend == false)
-       {
+       if (pwrpriv->bInSuspend == false) {
                pdbgpriv->dbg_resume_error_cnt++;
                DBG_871X("%s bInSuspend = %d\n", __func__, pwrpriv->bInSuspend);
                return -1;
@@ -635,8 +623,7 @@ static int __init rtw_drv_entry(void)
        rtw_drv_proc_init();
 
        ret = sdio_register_driver(&sdio_drvpriv.r871xs_drv);
-       if (ret != 0)
-       {
+       if (ret != 0) {
                sdio_drvpriv.drv_registered = false;
                rtw_drv_proc_deinit();
                rtw_ndev_notifier_unregister();
index 1787534..50b8934 100644 (file)
@@ -257,15 +257,13 @@ u32 sd_read32(struct intf_hdl *pintfhdl, u32 addr, s32 *err)
        if (claim_needed)
                sdio_release_host(func);
 
-       if (err && *err)
-       {
+       if (err && *err) {
                int i;
 
                DBG_871X(KERN_ERR "%s: (%d) addr = 0x%05x, val = 0x%x\n", __func__, *err, addr, v);
 
                *err = 0;
-               for (i = 0; i < SD_IO_TRY_CNT; i++)
-               {
+               for (i = 0; i < SD_IO_TRY_CNT; i++) {
                        if (claim_needed) sdio_claim_host(func);
                        v = sdio_readl(func, addr, err);
                        if (claim_needed) sdio_release_host(func);
@@ -350,15 +348,13 @@ void sd_write32(struct intf_hdl *pintfhdl, u32 addr, u32 v, s32 *err)
        if (claim_needed)
                sdio_release_host(func);
 
-       if (err && *err)
-       {
+       if (err && *err) {
                int i;
 
                DBG_871X(KERN_ERR "%s: (%d) addr = 0x%05x val = 0x%08x\n", __func__, *err, addr, v);
 
                *err = 0;
-               for (i = 0; i < SD_IO_TRY_CNT; i++)
-               {
+               for (i = 0; i < SD_IO_TRY_CNT; i++) {
                        if (claim_needed) sdio_claim_host(func);
                        sdio_writel(func, v, addr, err);
                        if (claim_needed) sdio_release_host(func);
@@ -420,13 +416,11 @@ s32 _sd_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata)
 
        func = psdio->func;
 
-       if (unlikely((cnt == 1) || (cnt == 2)))
-       {
+       if (unlikely((cnt == 1) || (cnt == 2))) {
                int i;
                u8 *pbuf = pdata;
 
-               for (i = 0; i < cnt; i++)
-               {
+               for (i = 0; i < cnt; i++) {
                        *(pbuf+i) = sdio_readb(func, addr+i, &err);
 
                        if (err) {
@@ -523,13 +517,11 @@ s32 _sd_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata)
        func = psdio->func;
 /*     size = sdio_align_size(func, cnt); */
 
-       if (unlikely((cnt == 1) || (cnt == 2)))
-       {
+       if (unlikely((cnt == 1) || (cnt == 2))) {
                int i;
                u8 *pbuf = pdata;
 
-               for (i = 0; i < cnt; i++)
-               {
+               for (i = 0; i < cnt; i++) {
                        sdio_writeb(func, *(pbuf+i), addr+i, &err);
                        if (err) {
                                DBG_871X(KERN_ERR "%s: FAIL!(%d) addr = 0x%05x val = 0x%02x\n", __func__, err, addr, *(pbuf+i));
index 4e4e565..4e81bc1 100644 (file)
@@ -32,7 +32,7 @@ uint _rtw_pktfile_read (struct pkt_file *pfile, u8 *rmem, uint rlen)
        len = (rlen > len) ? len : rlen;
 
        if (rmem)
-               skb_copy_bits(pfile->pkt, pfile->buf_len-pfile->pkt_len, rmem, len);
+               skb_copy_bits(pfile->pkt, pfile->buf_len - pfile->pkt_len, rmem, len);
 
        pfile->cur_addr += len;
        pfile->pkt_len -= len;
@@ -50,7 +50,7 @@ int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitb
 {
        if (alloc_sz > 0) {
                pxmitbuf->pallocated_buf = rtw_zmalloc(alloc_sz);
-               if (pxmitbuf->pallocated_buf == NULL)
+               if (!pxmitbuf->pallocated_buf)
                        return _FAIL;
 
                pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ);
@@ -65,7 +65,7 @@ void rtw_os_xmit_resource_free(struct adapter *padapter, struct xmit_buf *pxmitb
                kfree(pxmitbuf->pallocated_buf);
 }
 
-#define WMM_XMIT_THRESHOLD     (NR_XMITFRAME*2/5)
+#define WMM_XMIT_THRESHOLD     (NR_XMITFRAME * 2 / 5)
 
 void rtw_os_pkt_complete(struct adapter *padapter, _pkt *pkt)
 {
@@ -229,9 +229,9 @@ int _rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev)
                        #endif
                        )
                && padapter->registrypriv.wifi_spec == 0) {
-               if (pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME/4)) {
+               if (pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME / 4)) {
                        res = rtw_mlcst2unicst(padapter, pkt);
-                       if (res == true)
+                       if (res)
                                goto exit;
                } else {
                        /* DBG_871X("Stop M2U(%d, %d)! ", pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmitbuf_cnt); */
index 57bcf58..9cec0d8 100644 (file)
@@ -4,4 +4,4 @@ TODO:
 - We will use the stack in drivers/mmc to implement
   rts5208/5288 in the future
 
-Micky Ching <micky_ching@realsil.com.cn>
\ No newline at end of file
+Micky Ching <micky_ching@realsil.com.cn>
index 76c35f3..17c4131 100644 (file)
@@ -598,38 +598,38 @@ nextcard:
        return STATUS_SUCCESS;
 }
 
-static inline int check_sd_speed_prior(u32 sd_speed_prior)
+static inline int valid_sd_speed_prior(u32 sd_speed_prior)
 {
-       bool fake_para = false;
+       bool valid_para = true;
        int i;
 
        for (i = 0; i < 4; i++) {
                u8 tmp = (u8)(sd_speed_prior >> (i * 8));
 
                if ((tmp < 0x01) || (tmp > 0x04)) {
-                       fake_para = true;
+                       valid_para = false;
                        break;
                }
        }
 
-       return !fake_para;
+       return valid_para;
 }
 
-static inline int check_sd_current_prior(u32 sd_current_prior)
+static inline int valid_sd_current_prior(u32 sd_current_prior)
 {
-       bool fake_para = false;
+       bool valid_para = true;
        int i;
 
        for (i = 0; i < 4; i++) {
                u8 tmp = (u8)(sd_current_prior >> (i * 8));
 
                if (tmp > 0x03) {
-                       fake_para = true;
+                       valid_para = false;
                        break;
                }
        }
 
-       return !fake_para;
+       return valid_para;
 }
 
 static int rts5208_init(struct rtsx_chip *chip)
@@ -796,13 +796,13 @@ int rtsx_init_chip(struct rtsx_chip *chip)
                chip->rw_fail_cnt[i] = 0;
        }
 
-       if (!check_sd_speed_prior(chip->sd_speed_prior))
+       if (!valid_sd_speed_prior(chip->sd_speed_prior))
                chip->sd_speed_prior = 0x01040203;
 
        dev_dbg(rtsx_dev(chip), "sd_speed_prior = 0x%08x\n",
                chip->sd_speed_prior);
 
-       if (!check_sd_current_prior(chip->sd_current_prior))
+       if (!valid_sd_current_prior(chip->sd_current_prior))
                chip->sd_current_prior = 0x00010203;
 
        dev_dbg(rtsx_dev(chip), "sd_current_prior = 0x%08x\n",
index c256a23..a060453 100644 (file)
@@ -3580,11 +3580,6 @@ RW_FAIL:
 }
 
 #ifdef SUPPORT_CPRM
-int soft_reset_sd_card(struct rtsx_chip *chip)
-{
-       return reset_sd(chip);
-}
-
 int ext_sd_send_cmd_get_rsp(struct rtsx_chip *chip, u8 cmd_idx, u32 arg,
                            u8 rsp_type, u8 *rsp, int rsp_len,
                            bool special_check)
@@ -4512,20 +4507,19 @@ int sd_execute_write_data(struct scsi_cmnd *srb, struct rtsx_chip *chip)
                        sd_lock_state, sd_card->sd_lock_status);
                if (sd_lock_state ^ (sd_card->sd_lock_status & SD_LOCKED)) {
                        sd_card->sd_lock_notify = 1;
-                       if (sd_lock_state) {
-                               if (sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) {
-                                       sd_card->sd_lock_status |= (
-                                               SD_UNLOCK_POW_ON | SD_SDR_RST);
-                                       if (CHK_SD(sd_card)) {
-                                               retval = reset_sd(chip);
-                                               if (retval != STATUS_SUCCESS) {
-                                                       sd_card->sd_lock_status &= ~(SD_UNLOCK_POW_ON | SD_SDR_RST);
-                                                       goto sd_execute_write_cmd_failed;
-                                               }
+                       if (sd_lock_state &&
+                           (sd_card->sd_lock_status & SD_LOCK_1BIT_MODE)) {
+                               sd_card->sd_lock_status |= (
+                                       SD_UNLOCK_POW_ON | SD_SDR_RST);
+                               if (CHK_SD(sd_card)) {
+                                       retval = reset_sd(chip);
+                                       if (retval != STATUS_SUCCESS) {
+                                               sd_card->sd_lock_status &= ~(SD_UNLOCK_POW_ON | SD_SDR_RST);
+                                               goto sd_execute_write_cmd_failed;
                                        }
-
-                                       sd_card->sd_lock_status &= ~(SD_UNLOCK_POW_ON | SD_SDR_RST);
                                }
+
+                               sd_card->sd_lock_status &= ~(SD_UNLOCK_POW_ON | SD_SDR_RST);
                        }
                }
        }
@@ -4639,7 +4633,7 @@ int sd_hw_rst(struct scsi_cmnd *srb, struct rtsx_chip *chip)
                break;
 
        case 1:
-               retval = soft_reset_sd_card(chip);
+               retval = reset_sd(chip);
                if (retval != STATUS_SUCCESS) {
                        set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
                        sd_card->pre_cmd_err = 1;
index e124526..dc9e8ca 100644 (file)
@@ -273,7 +273,6 @@ void sd_cleanup_work(struct rtsx_chip *chip);
 int sd_power_off_card3v3(struct rtsx_chip *chip);
 int release_sd_card(struct rtsx_chip *chip);
 #ifdef SUPPORT_CPRM
-int soft_reset_sd_card(struct rtsx_chip *chip);
 int ext_sd_send_cmd_get_rsp(struct rtsx_chip *chip, u8 cmd_idx,
                            u32 arg, u8 rsp_type, u8 *rsp, int rsp_len,
                            bool special_check);
index c5ee04e..f3dc96a 100644 (file)
@@ -1155,10 +1155,10 @@ static int xd_copy_page(struct rtsx_chip *chip, u32 old_blk, u32 new_blk,
                                        return STATUS_FAIL;
                                }
 
-                               if (((reg & (XD_ECC1_ERROR | XD_ECC1_UNCORRECTABLE)) ==
-                                               (XD_ECC1_ERROR | XD_ECC1_UNCORRECTABLE)) ||
-                                       ((reg & (XD_ECC2_ERROR | XD_ECC2_UNCORRECTABLE)) ==
-                                               (XD_ECC2_ERROR | XD_ECC2_UNCORRECTABLE))) {
+                               if (((reg & XD_ECC1_ERROR) &&
+                                    (reg & XD_ECC1_UNCORRECTABLE)) ||
+                                   ((reg & XD_ECC2_ERROR) &&
+                                    (reg & XD_ECC2_UNCORRECTABLE))) {
                                        rtsx_write_register(chip,
                                                            XD_PAGE_STATUS,
                                                            0xFF,
index aa691e4..6f8f86f 100644 (file)
@@ -4,9 +4,6 @@
 
 #include <linux/serial.h>      /* for rs_table, serial constants */
 #include <linux/serial_reg.h>  /* for more serial constants */
-#ifndef __sparc__
-#include <linux/serial.h>
-#endif
 #include <linux/serial_core.h>
 
 #include "spk_priv.h"
index dc5e1bd..43fe1ce 100644 (file)
@@ -4,8 +4,8 @@
 #
 menuconfig UNISYSSPAR
        bool "Unisys SPAR driver support"
-       ---help---
-       Support for the Unisys SPAR drivers
+       help
+         Support for the Unisys SPAR drivers
 
 if UNISYSSPAR
 
index 2dad36a..dd979ee 100644 (file)
@@ -871,12 +871,11 @@ static void do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp,
                        return;
                }
 
-               sg = scsi_sglist(scsicmd);
-               for (i = 0; i < scsi_sg_count(scsicmd); i++) {
-                       this_page_orig = kmap_atomic(sg_page(sg + i));
+               scsi_for_each_sg(scsicmd, sg, scsi_sg_count(scsicmd), i) {
+                       this_page_orig = kmap_atomic(sg_page(sg));
                        this_page = (void *)((unsigned long)this_page_orig |
-                                            sg[i].offset);
-                       memcpy(this_page, buf + bufind, sg[i].length);
+                                            sg->offset);
+                       memcpy(this_page, buf + bufind, sg->length);
                        kunmap_atomic(this_page_orig);
                }
                kfree(buf);
index 1c1a470..9d4f1da 100644 (file)
@@ -1861,12 +1861,12 @@ static int visornic_probe(struct visor_device *dev)
        skb_queue_head_init(&devdata->xmitbufhead);
 
        /* create a cmdrsp we can use to post and unpost rcv buffers */
-       devdata->cmdrsp_rcv = kmalloc(SIZEOF_CMDRSP, GFP_ATOMIC);
+       devdata->cmdrsp_rcv = kmalloc(SIZEOF_CMDRSP, GFP_KERNEL);
        if (!devdata->cmdrsp_rcv) {
                err = -ENOMEM;
                goto cleanup_rcvbuf;
        }
-       devdata->xmit_cmdrsp = kmalloc(SIZEOF_CMDRSP, GFP_ATOMIC);
+       devdata->xmit_cmdrsp = kmalloc(SIZEOF_CMDRSP, GFP_KERNEL);
        if (!devdata->xmit_cmdrsp) {
                err = -ENOMEM;
                goto cleanup_cmdrsp_rcv;
index 49d0470..ea54cc2 100644 (file)
@@ -4,10 +4,11 @@
  *
  * Copyright © 2013 Raspberry Pi (Trading) Ltd.
  *
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- *          Dave Stevenson <dsteve@broadcom.com>
- *          Simon Mellor <simellor@broadcom.com>
- *          Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ *          Dave Stevenson @ Broadcom
+ *             (now dave.stevenson@raspberrypi.org)
+ *          Simon Mellor @ Broadcom
+ *          Luke Diamand @ Broadcom
  */
 
 #include <linux/errno.h>
@@ -79,7 +80,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_I420,
                .depth = 12,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 1,
                .remove_padding = 1,
        }, {
@@ -88,7 +89,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_YUYV,
                .depth = 16,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 2,
                .remove_padding = 0,
        }, {
@@ -97,7 +98,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_RGB24,
                .depth = 24,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 3,
                .remove_padding = 0,
        }, {
@@ -106,7 +107,7 @@ static struct mmal_fmt formats[] = {
                .flags = V4L2_FMT_FLAG_COMPRESSED,
                .mmal = MMAL_ENCODING_JPEG,
                .depth = 8,
-               .mmal_component = MMAL_COMPONENT_IMAGE_ENCODE,
+               .mmal_component = COMP_IMAGE_ENCODE,
                .ybbp = 0,
                .remove_padding = 0,
        }, {
@@ -115,7 +116,7 @@ static struct mmal_fmt formats[] = {
                .flags = V4L2_FMT_FLAG_COMPRESSED,
                .mmal = MMAL_ENCODING_H264,
                .depth = 8,
-               .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
+               .mmal_component = COMP_VIDEO_ENCODE,
                .ybbp = 0,
                .remove_padding = 0,
        }, {
@@ -124,7 +125,7 @@ static struct mmal_fmt formats[] = {
                .flags = V4L2_FMT_FLAG_COMPRESSED,
                .mmal = MMAL_ENCODING_MJPEG,
                .depth = 8,
-               .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
+               .mmal_component = COMP_VIDEO_ENCODE,
                .ybbp = 0,
                .remove_padding = 0,
        }, {
@@ -133,7 +134,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_YVYU,
                .depth = 16,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 2,
                .remove_padding = 0,
        }, {
@@ -142,7 +143,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_VYUY,
                .depth = 16,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 2,
                .remove_padding = 0,
        }, {
@@ -151,7 +152,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_UYVY,
                .depth = 16,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 2,
                .remove_padding = 0,
        }, {
@@ -160,7 +161,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_NV12,
                .depth = 12,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 1,
                .remove_padding = 1,
        }, {
@@ -169,7 +170,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_BGR24,
                .depth = 24,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 3,
                .remove_padding = 0,
        }, {
@@ -178,7 +179,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_YV12,
                .depth = 12,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 1,
                .remove_padding = 1,
        }, {
@@ -187,7 +188,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_NV21,
                .depth = 12,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 1,
                .remove_padding = 1,
        }, {
@@ -196,7 +197,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_BGRA,
                .depth = 32,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 4,
                .remove_padding = 0,
        },
@@ -235,6 +236,22 @@ static int queue_setup(struct vb2_queue *vq,
                return -EINVAL;
        }
 
+       /* Handle CREATE_BUFS situation - *nplanes != 0 */
+       if (*nplanes) {
+               if (*nplanes != 1 ||
+                   sizes[0] < dev->capture.port->current_buffer.size) {
+                       v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+                                "%s: dev:%p Invalid buffer request from CREATE_BUFS, size %u < %u, nplanes %u != 1\n",
+                                __func__, dev, sizes[0],
+                                dev->capture.port->current_buffer.size,
+                                *nplanes);
+                       return -EINVAL;
+               } else {
+                       return 0;
+               }
+       }
+
+       /* Handle REQBUFS situation */
        size = dev->capture.port->current_buffer.size;
        if (size == 0) {
                v4l2_err(&dev->v4l2_dev,
@@ -312,7 +329,7 @@ static void buffer_cleanup(struct vb2_buffer *vb)
 static inline bool is_capturing(struct bm2835_mmal_dev *dev)
 {
        return dev->capture.camera_port ==
-           &dev->component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_CAPTURE];
+           &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
 }
 
 static void buffer_cb(struct vchiq_mmal_instance *instance,
@@ -327,25 +344,24 @@ static void buffer_cb(struct vchiq_mmal_instance *instance,
                 "%s: status:%d, buf:%p, length:%lu, flags %u, pts %lld\n",
                 __func__, status, buf, length, mmal_flags, pts);
 
-       if (status != 0) {
+       if (status) {
                /* error in transfer */
                if (buf) {
                        /* there was a buffer with the error so return it */
                        vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
                }
                return;
-       } else if (length == 0) {
+       }
+
+       if (length == 0) {
                /* stream ended */
-               if (buf) {
-                       /* this should only ever happen if the port is
-                        * disabled and there are buffers still queued
+               if (dev->capture.frame_count) {
+                       /* empty buffer whilst capturing - expected to be an
+                        * EOS, so grab another frame
                         */
-                       vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
-                       pr_debug("Empty buffer");
-               } else if (dev->capture.frame_count) {
-                       /* grab another frame */
                        if (is_capturing(dev)) {
-                               pr_debug("Grab another frame");
+                               v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+                                        "Grab another frame");
                                vchiq_mmal_port_parameter_set(
                                        instance,
                                        dev->capture.camera_port,
@@ -353,48 +369,60 @@ static void buffer_cb(struct vchiq_mmal_instance *instance,
                                        &dev->capture.frame_count,
                                        sizeof(dev->capture.frame_count));
                        }
+                       if (vchiq_mmal_submit_buffer(instance, port, buf))
+                               v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+                                        "Failed to return EOS buffer");
                } else {
-                       /* signal frame completion */
+                       /* stopping streaming.
+                        * return buffer, and signal frame completion
+                        */
+                       vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
                        complete(&dev->capture.frame_cmplt);
                }
+               return;
+       }
+
+       if (!dev->capture.frame_count) {
+               /* signal frame completion */
+               vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+               complete(&dev->capture.frame_cmplt);
+               return;
+       }
+
+       if (dev->capture.vc_start_timestamp != -1 && pts) {
+               ktime_t timestamp;
+               s64 runtime_us = pts -
+                   dev->capture.vc_start_timestamp;
+               timestamp = ktime_add_us(dev->capture.kernel_start_ts,
+                                        runtime_us);
+               v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+                        "Convert start time %llu and %llu with offset %llu to %llu\n",
+                        ktime_to_ns(dev->capture.kernel_start_ts),
+                        dev->capture.vc_start_timestamp, pts,
+                        ktime_to_ns(timestamp));
+               buf->vb.vb2_buf.timestamp = ktime_to_ns(timestamp);
        } else {
-               if (dev->capture.frame_count) {
-                       if (dev->capture.vc_start_timestamp != -1 &&
-                           pts != 0) {
-                               ktime_t timestamp;
-                               s64 runtime_us = pts -
-                                   dev->capture.vc_start_timestamp;
-                               timestamp = ktime_add_us(dev->capture.kernel_start_ts,
-                                                        runtime_us);
-                               v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-                                        "Convert start time %llu and %llu with offset %llu to %llu\n",
-                                        ktime_to_ns(dev->capture.kernel_start_ts),
-                                        dev->capture.vc_start_timestamp, pts,
-                                        ktime_to_ns(timestamp));
-                               buf->vb.vb2_buf.timestamp = ktime_to_ns(timestamp);
-                       } else {
-                               buf->vb.vb2_buf.timestamp = ktime_get_ns();
-                       }
+               buf->vb.vb2_buf.timestamp = ktime_get_ns();
+       }
+       buf->vb.sequence = dev->capture.sequence++;
+       buf->vb.field = V4L2_FIELD_NONE;
 
-                       vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
-                       vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+       vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
+       if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
+               buf->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
 
-                       if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
-                           is_capturing(dev)) {
-                               v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-                                        "Grab another frame as buffer has EOS");
-                               vchiq_mmal_port_parameter_set(
-                                       instance,
-                                       dev->capture.camera_port,
-                                       MMAL_PARAMETER_CAPTURE,
-                                       &dev->capture.frame_count,
-                                       sizeof(dev->capture.frame_count));
-                       }
-               } else {
-                       /* signal frame completion */
-                       vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
-                       complete(&dev->capture.frame_cmplt);
-               }
+       vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+
+       if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
+           is_capturing(dev)) {
+               v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+                        "Grab another frame as buffer has EOS");
+               vchiq_mmal_port_parameter_set(
+                       instance,
+                       dev->capture.camera_port,
+                       MMAL_PARAMETER_CAPTURE,
+                       &dev->capture.frame_count,
+                       sizeof(dev->capture.frame_count));
        }
 }
 
@@ -405,7 +433,7 @@ static int enable_camera(struct bm2835_mmal_dev *dev)
        if (!dev->camera_use_count) {
                ret = vchiq_mmal_port_parameter_set(
                        dev->instance,
-                       &dev->component[MMAL_COMPONENT_CAMERA]->control,
+                       &dev->component[COMP_CAMERA]->control,
                        MMAL_PARAMETER_CAMERA_NUM, &dev->camera_num,
                        sizeof(dev->camera_num));
                if (ret < 0) {
@@ -416,7 +444,7 @@ static int enable_camera(struct bm2835_mmal_dev *dev)
 
                ret = vchiq_mmal_component_enable(
                                dev->instance,
-                               dev->component[MMAL_COMPONENT_CAMERA]);
+                               dev->component[COMP_CAMERA]);
                if (ret < 0) {
                        v4l2_err(&dev->v4l2_dev,
                                 "Failed enabling camera, ret %d\n", ret);
@@ -448,7 +476,7 @@ static int disable_camera(struct bm2835_mmal_dev *dev)
                ret =
                    vchiq_mmal_component_disable(
                                dev->instance,
-                               dev->component[MMAL_COMPONENT_CAMERA]);
+                               dev->component[COMP_CAMERA]);
                if (ret < 0) {
                        v4l2_err(&dev->v4l2_dev,
                                 "Failed disabling camera, ret %d\n", ret);
@@ -456,7 +484,7 @@ static int disable_camera(struct bm2835_mmal_dev *dev)
                }
                vchiq_mmal_port_parameter_set(
                        dev->instance,
-                       &dev->component[MMAL_COMPONENT_CAMERA]->control,
+                       &dev->component[COMP_CAMERA]->control,
                        MMAL_PARAMETER_CAMERA_NUM, &i,
                        sizeof(i));
        }
@@ -505,10 +533,13 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
        /* enable frame capture */
        dev->capture.frame_count = 1;
 
+       /* reset sequence number */
+       dev->capture.sequence = 0;
+
        /* if the preview is not already running, wait for a few frames for AGC
         * to settle down.
         */
-       if (!dev->component[MMAL_COMPONENT_PREVIEW]->enabled)
+       if (!dev->component[COMP_PREVIEW]->enabled)
                msleep(300);
 
        /* enable the connection from camera to encoder (if applicable) */
@@ -536,10 +567,11 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
 
                /* Flag to indicate just to rely on kernel timestamps */
                dev->capture.vc_start_timestamp = -1;
-       } else
+       } else {
                v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
                         "Start time %lld size %d\n",
                         dev->capture.vc_start_timestamp, parameter_size);
+       }
 
        dev->capture.kernel_start_ts = ktime_get();
 
@@ -549,8 +581,8 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
            vchiq_mmal_port_enable(dev->instance, dev->capture.port, buffer_cb);
        if (ret) {
                v4l2_err(&dev->v4l2_dev,
-                       "Failed to enable capture port - error %d. Disabling camera port again\n",
-                       ret);
+                        "Failed to enable capture port - error %d. Disabling camera port again\n",
+                        ret);
 
                vchiq_mmal_port_disable(dev->instance,
                                        dev->capture.camera_port);
@@ -576,6 +608,7 @@ static void stop_streaming(struct vb2_queue *vq)
        int ret;
        unsigned long timeout;
        struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
+       struct vchiq_mmal_port *port = dev->capture.port;
 
        v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
                 __func__, dev);
@@ -599,12 +632,6 @@ static void stop_streaming(struct vb2_queue *vq)
                                      &dev->capture.frame_count,
                                      sizeof(dev->capture.frame_count));
 
-       /* wait for last frame to complete */
-       timeout = wait_for_completion_timeout(&dev->capture.frame_cmplt, HZ);
-       if (timeout == 0)
-               v4l2_err(&dev->v4l2_dev,
-                        "timed out waiting for frame completion\n");
-
        v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
                 "disabling connection\n");
 
@@ -619,6 +646,21 @@ static void stop_streaming(struct vb2_queue *vq)
                         ret);
        }
 
+       /* wait for all buffers to be returned */
+       while (atomic_read(&port->buffers_with_vpu)) {
+               v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+                        "%s: Waiting for buffers to be returned - %d outstanding\n",
+                        __func__, atomic_read(&port->buffers_with_vpu));
+               timeout = wait_for_completion_timeout(&dev->capture.frame_cmplt,
+                                                     HZ);
+               if (timeout == 0) {
+                       v4l2_err(&dev->v4l2_dev, "%s: Timeout waiting for buffers to be returned - %d outstanding\n",
+                                __func__,
+                                atomic_read(&port->buffers_with_vpu));
+                       break;
+               }
+       }
+
        if (disable_camera(dev) < 0)
                v4l2_err(&dev->v4l2_dev, "Failed to disable camera\n");
 }
@@ -730,9 +772,9 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *priv,
        vidioc_try_fmt_vid_overlay(file, priv, f);
 
        dev->overlay = f->fmt.win;
-       if (dev->component[MMAL_COMPONENT_PREVIEW]->enabled) {
+       if (dev->component[COMP_PREVIEW]->enabled) {
                set_overlay_params(dev,
-                                  &dev->component[MMAL_COMPONENT_PREVIEW]->input[0]);
+                                  &dev->component[COMP_PREVIEW]->input[0]);
        }
 
        return 0;
@@ -745,12 +787,12 @@ static int vidioc_overlay(struct file *file, void *f, unsigned int on)
        struct vchiq_mmal_port *src;
        struct vchiq_mmal_port *dst;
 
-       if ((on && dev->component[MMAL_COMPONENT_PREVIEW]->enabled) ||
-           (!on && !dev->component[MMAL_COMPONENT_PREVIEW]->enabled))
+       if ((on && dev->component[COMP_PREVIEW]->enabled) ||
+           (!on && !dev->component[COMP_PREVIEW]->enabled))
                return 0;       /* already in requested state */
 
        src =
-           &dev->component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_PREVIEW];
+           &dev->component[COMP_CAMERA]->output[CAM_PORT_PREVIEW];
 
        if (!on) {
                /* disconnect preview ports and disable component */
@@ -762,39 +804,39 @@ static int vidioc_overlay(struct file *file, void *f, unsigned int on)
                if (ret >= 0)
                        ret = vchiq_mmal_component_disable(
                                        dev->instance,
-                                       dev->component[MMAL_COMPONENT_PREVIEW]);
+                                       dev->component[COMP_PREVIEW]);
 
                disable_camera(dev);
                return ret;
        }
 
        /* set preview port format and connect it to output */
-       dst = &dev->component[MMAL_COMPONENT_PREVIEW]->input[0];
+       dst = &dev->component[COMP_PREVIEW]->input[0];
 
        ret = vchiq_mmal_port_set_format(dev->instance, src);
        if (ret < 0)
-               goto error;
+               return ret;
 
        ret = set_overlay_params(dev, dst);
        if (ret < 0)
-               goto error;
+               return ret;
 
        if (enable_camera(dev) < 0)
-               goto error;
+               return -EINVAL;
 
        ret = vchiq_mmal_component_enable(
                        dev->instance,
-                       dev->component[MMAL_COMPONENT_PREVIEW]);
+                       dev->component[COMP_PREVIEW]);
        if (ret < 0)
-               goto error;
+               return ret;
 
        v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "connecting %p to %p\n",
                 src, dst);
        ret = vchiq_mmal_port_connect_tunnel(dev->instance, src, dst);
-       if (!ret)
-               ret = vchiq_mmal_port_enable(dev->instance, src, NULL);
-error:
-       return ret;
+       if (ret)
+               return ret;
+
+       return vchiq_mmal_port_enable(dev->instance, src, NULL);
 }
 
 static int vidioc_g_fbuf(struct file *file, void *fh,
@@ -805,7 +847,7 @@ static int vidioc_g_fbuf(struct file *file, void *fh,
         */
        struct bm2835_mmal_dev *dev = video_drvdata(file);
        struct vchiq_mmal_port *preview_port =
-                   &dev->component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_PREVIEW];
+               &dev->component[COMP_CAMERA]->output[CAM_PORT_PREVIEW];
 
        a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
                        V4L2_FBUF_CAP_GLOBAL_ALPHA;
@@ -826,7 +868,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
                             struct v4l2_input *inp)
 {
        /* only a single camera input */
-       if (inp->index != 0)
+       if (inp->index)
                return -EINVAL;
 
        inp->type = V4L2_INPUT_TYPE_CAMERA;
@@ -842,7 +884,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
 
 static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 {
-       if (i != 0)
+       if (i)
                return -EINVAL;
 
        return 0;
@@ -935,14 +977,27 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                              1, 0);
        f->fmt.pix.bytesperline = f->fmt.pix.width * mfmt->ybbp;
        if (!mfmt->remove_padding) {
-               int align_mask = ((32 * mfmt->depth) >> 3) - 1;
-               /* GPU isn't removing padding, so stride is aligned to 32 */
-               f->fmt.pix.bytesperline =
-                       (f->fmt.pix.bytesperline + align_mask) & ~align_mask;
+               if (mfmt->depth == 24) {
+                       /*
+                        * 24bpp is a pain as we can't use simple masking.
+                        * Min stride is width aligned to 16, times 24bpp.
+                        */
+                       f->fmt.pix.bytesperline =
+                               ((f->fmt.pix.width + 15) & ~15) * 3;
+               } else {
+                       /*
+                        * GPU isn't removing padding, so stride is aligned to
+                        * 32
+                        */
+                       int align_mask = ((32 * mfmt->depth) >> 3) - 1;
+
+                       f->fmt.pix.bytesperline =
+                               (f->fmt.pix.bytesperline + align_mask) &
+                                                       ~align_mask;
+               }
                v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-                        "Not removing padding, so bytes/line = %d, "
-                        "(align_mask %d)\n",
-                        f->fmt.pix.bytesperline, align_mask);
+                        "Not removing padding, so bytes/line = %d\n",
+                        f->fmt.pix.bytesperline);
        }
 
        /* Image buffer has to be padded to allow for alignment, even though
@@ -1003,27 +1058,28 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev,
        }
        /* format dependent port setup */
        switch (mfmt->mmal_component) {
-       case MMAL_COMPONENT_CAMERA:
+       case COMP_CAMERA:
                /* Make a further decision on port based on resolution */
                if (f->fmt.pix.width <= max_video_width &&
                    f->fmt.pix.height <= max_video_height)
-                       camera_port = port =
-                           &dev->component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_VIDEO];
+                       camera_port =
+                           &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO];
                else
-                       camera_port = port =
-                           &dev->component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_CAPTURE];
+                       camera_port =
+                           &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
+               port = camera_port;
                break;
-       case MMAL_COMPONENT_IMAGE_ENCODE:
-               encode_component = dev->component[MMAL_COMPONENT_IMAGE_ENCODE];
-               port = &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->output[0];
+       case COMP_IMAGE_ENCODE:
+               encode_component = dev->component[COMP_IMAGE_ENCODE];
+               port = &dev->component[COMP_IMAGE_ENCODE]->output[0];
                camera_port =
-                   &dev->component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_CAPTURE];
+                   &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
                break;
-       case MMAL_COMPONENT_VIDEO_ENCODE:
-               encode_component = dev->component[MMAL_COMPONENT_VIDEO_ENCODE];
-               port = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
+       case COMP_VIDEO_ENCODE:
+               encode_component = dev->component[COMP_VIDEO_ENCODE];
+               port = &dev->component[COMP_VIDEO_ENCODE]->output[0];
                camera_port =
-                   &dev->component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_VIDEO];
+                   &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO];
                break;
        default:
                break;
@@ -1063,13 +1119,13 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev,
 
        ret = vchiq_mmal_port_set_format(dev->instance, camera_port);
 
-       if (!ret &&
-           camera_port ==
-           &dev->component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_VIDEO]) {
+       if (!ret
+           && camera_port ==
+           &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO]) {
                bool overlay_enabled =
-                   !!dev->component[MMAL_COMPONENT_PREVIEW]->enabled;
+                   !!dev->component[COMP_PREVIEW]->enabled;
                struct vchiq_mmal_port *preview_port =
-                   &dev->component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_PREVIEW];
+                   &dev->component[COMP_CAMERA]->output[CAM_PORT_PREVIEW];
                /* Preview and encode ports need to match on resolution */
                if (overlay_enabled) {
                        /* Need to disable the overlay before we can update
@@ -1100,7 +1156,7 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev,
                        ret = vchiq_mmal_port_connect_tunnel(
                                dev->instance,
                                preview_port,
-                               &dev->component[MMAL_COMPONENT_PREVIEW]->input[0]);
+                               &dev->component[COMP_PREVIEW]->input[0]);
                        if (!ret)
                                ret = vchiq_mmal_port_enable(dev->instance,
                                                             preview_port,
@@ -1154,11 +1210,11 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev,
                                port->format.encoding_variant = 0;
                                /* Set any encoding specific parameters */
                                switch (mfmt->mmal_component) {
-                               case MMAL_COMPONENT_VIDEO_ENCODE:
+                               case COMP_VIDEO_ENCODE:
                                        port->format.bitrate =
                                            dev->capture.encode_bitrate;
                                        break;
-                               case MMAL_COMPONENT_IMAGE_ENCODE:
+                               case COMP_IMAGE_ENCODE:
                                        /* Could set EXIF parameters here */
                                        break;
                                default:
@@ -1202,9 +1258,8 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev,
                                                 port->current_buffer.size);
                                        port->current_buffer.size =
                                            (f->fmt.pix.sizeimage <
-                                            (100 << 10))
-                                           ? (100 << 10)
-                                           : f->fmt.pix.sizeimage;
+                                            (100 << 10)) ?
+                                           (100 << 10) : f->fmt.pix.sizeimage;
                                }
                                v4l2_dbg(1, bcm2835_v4l2_debug,
                                         &dev->v4l2_dev,
@@ -1277,7 +1332,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        }
 
        ret = mmal_setup_components(dev, f);
-       if (ret != 0) {
+       if (ret) {
                v4l2_err(&dev->v4l2_dev,
                         "%s: failed to setup mmal components: %d\n",
                         __func__, ret);
@@ -1288,7 +1343,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 }
 
 static int vidioc_enum_framesizes(struct file *file, void *fh,
-                          struct v4l2_frmsizeenum *fsize)
+                                 struct v4l2_frmsizeenum *fsize)
 {
        struct bm2835_mmal_dev *dev = video_drvdata(file);
        static const struct v4l2_frmsize_stepwise sizes = {
@@ -1529,14 +1584,14 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
 
        /* get the camera component ready */
        ret = vchiq_mmal_component_init(dev->instance, "ril.camera",
-                                       &dev->component[MMAL_COMPONENT_CAMERA]);
+                                       &dev->component[COMP_CAMERA]);
        if (ret < 0)
                goto unreg_mmal;
 
-       camera = dev->component[MMAL_COMPONENT_CAMERA];
-       if (camera->outputs < MMAL_CAMERA_PORT_COUNT) {
+       camera = dev->component[COMP_CAMERA];
+       if (camera->outputs < CAM_PORT_COUNT) {
                v4l2_err(&dev->v4l2_dev, "%s: too few camera outputs %d needed %d\n",
-                        __func__, camera->outputs, MMAL_CAMERA_PORT_COUNT);
+                        __func__, camera->outputs, CAM_PORT_COUNT);
                ret = -EINVAL;
                goto unreg_camera;
        }
@@ -1558,7 +1613,7 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
        dev->rgb_bgr_swapped = true;
        param_size = sizeof(supported_encodings);
        ret = vchiq_mmal_port_parameter_get(dev->instance,
-                                           &camera->output[MMAL_CAMERA_PORT_CAPTURE],
+                                           &camera->output[CAM_PORT_CAPTURE],
                                            MMAL_PARAMETER_SUPPORTED_ENCODINGS,
                                            &supported_encodings,
                                            &param_size);
@@ -1579,7 +1634,7 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
                        }
                }
        }
-       format = &camera->output[MMAL_CAMERA_PORT_PREVIEW].format;
+       format = &camera->output[CAM_PORT_PREVIEW].format;
 
        format->encoding = MMAL_ENCODING_OPAQUE;
        format->encoding_variant = MMAL_ENCODING_I420;
@@ -1593,7 +1648,7 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
        format->es->video.frame_rate.num = 0; /* Rely on fps_range */
        format->es->video.frame_rate.den = 1;
 
-       format = &camera->output[MMAL_CAMERA_PORT_VIDEO].format;
+       format = &camera->output[CAM_PORT_VIDEO].format;
 
        format->encoding = MMAL_ENCODING_OPAQUE;
        format->encoding_variant = MMAL_ENCODING_I420;
@@ -1607,7 +1662,7 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
        format->es->video.frame_rate.num = 0; /* Rely on fps_range */
        format->es->video.frame_rate.den = 1;
 
-       format = &camera->output[MMAL_CAMERA_PORT_CAPTURE].format;
+       format = &camera->output[CAM_PORT_CAPTURE].format;
 
        format->encoding = MMAL_ENCODING_OPAQUE;
 
@@ -1631,49 +1686,49 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
        /* get the preview component ready */
        ret = vchiq_mmal_component_init(
                        dev->instance, "ril.video_render",
-                       &dev->component[MMAL_COMPONENT_PREVIEW]);
+                       &dev->component[COMP_PREVIEW]);
        if (ret < 0)
                goto unreg_camera;
 
-       if (dev->component[MMAL_COMPONENT_PREVIEW]->inputs < 1) {
+       if (dev->component[COMP_PREVIEW]->inputs < 1) {
                ret = -EINVAL;
                v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
-                        __func__, dev->component[MMAL_COMPONENT_PREVIEW]->inputs, 1);
+                        __func__, dev->component[COMP_PREVIEW]->inputs, 1);
                goto unreg_preview;
        }
 
        /* get the image encoder component ready */
        ret = vchiq_mmal_component_init(
                dev->instance, "ril.image_encode",
-               &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]);
+               &dev->component[COMP_IMAGE_ENCODE]);
        if (ret < 0)
                goto unreg_preview;
 
-       if (dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs < 1) {
+       if (dev->component[COMP_IMAGE_ENCODE]->inputs < 1) {
                ret = -EINVAL;
                v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
-                        __func__, dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs,
+                        __func__, dev->component[COMP_IMAGE_ENCODE]->inputs,
                         1);
                goto unreg_image_encoder;
        }
 
        /* get the video encoder component ready */
        ret = vchiq_mmal_component_init(dev->instance, "ril.video_encode",
-                                       &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]);
+                                       &dev->component[COMP_VIDEO_ENCODE]);
        if (ret < 0)
                goto unreg_image_encoder;
 
-       if (dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs < 1) {
+       if (dev->component[COMP_VIDEO_ENCODE]->inputs < 1) {
                ret = -EINVAL;
                v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
-                        __func__, dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs,
+                        __func__, dev->component[COMP_VIDEO_ENCODE]->inputs,
                         1);
                goto unreg_vid_encoder;
        }
 
        {
                struct vchiq_mmal_port *encoder_port =
-                       &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
+                       &dev->component[COMP_VIDEO_ENCODE]->output[0];
                encoder_port->format.encoding = MMAL_ENCODING_H264;
                ret = vchiq_mmal_port_set_format(dev->instance,
                                                 encoder_port);
@@ -1684,12 +1739,12 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
 
                vchiq_mmal_port_parameter_set(
                        dev->instance,
-                       &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
+                       &dev->component[COMP_VIDEO_ENCODE]->control,
                        MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,
                        &enable, sizeof(enable));
 
                vchiq_mmal_port_parameter_set(dev->instance,
-                                             &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
+                                             &dev->component[COMP_VIDEO_ENCODE]->control,
                                              MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
                                              &enable,
                                              sizeof(enable));
@@ -1707,23 +1762,23 @@ unreg_vid_encoder:
        pr_err("Cleanup: Destroy video encoder\n");
        vchiq_mmal_component_finalise(
                dev->instance,
-               dev->component[MMAL_COMPONENT_VIDEO_ENCODE]);
+               dev->component[COMP_VIDEO_ENCODE]);
 
 unreg_image_encoder:
        pr_err("Cleanup: Destroy image encoder\n");
        vchiq_mmal_component_finalise(
                dev->instance,
-               dev->component[MMAL_COMPONENT_IMAGE_ENCODE]);
+               dev->component[COMP_IMAGE_ENCODE]);
 
 unreg_preview:
        pr_err("Cleanup: Destroy video render\n");
        vchiq_mmal_component_finalise(dev->instance,
-                                     dev->component[MMAL_COMPONENT_PREVIEW]);
+                                     dev->component[COMP_PREVIEW]);
 
 unreg_camera:
        pr_err("Cleanup: Destroy camera\n");
        vchiq_mmal_component_finalise(dev->instance,
-                                     dev->component[MMAL_COMPONENT_CAMERA]);
+                                     dev->component[COMP_CAMERA]);
 
 unreg_mmal:
        vchiq_mmal_finalise(dev->instance);
@@ -1779,19 +1834,19 @@ static void bcm2835_cleanup_instance(struct bm2835_mmal_dev *dev)
                                             dev->capture.encode_component);
        }
        vchiq_mmal_component_disable(dev->instance,
-                                    dev->component[MMAL_COMPONENT_CAMERA]);
+                                    dev->component[COMP_CAMERA]);
 
        vchiq_mmal_component_finalise(dev->instance,
-                                     dev->component[MMAL_COMPONENT_VIDEO_ENCODE]);
+                                     dev->component[COMP_VIDEO_ENCODE]);
 
        vchiq_mmal_component_finalise(dev->instance,
-                                     dev->component[MMAL_COMPONENT_IMAGE_ENCODE]);
+                                     dev->component[COMP_IMAGE_ENCODE]);
 
        vchiq_mmal_component_finalise(dev->instance,
-                                     dev->component[MMAL_COMPONENT_PREVIEW]);
+                                     dev->component[COMP_PREVIEW]);
 
        vchiq_mmal_component_finalise(dev->instance,
-                                     dev->component[MMAL_COMPONENT_CAMERA]);
+                                     dev->component[COMP_CAMERA]);
 
        v4l2_ctrl_handler_free(&dev->ctrl_handler);
 
index 2b5679e..b5fce38 100644 (file)
@@ -4,10 +4,11 @@
  *
  * Copyright © 2013 Raspberry Pi (Trading) Ltd.
  *
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- *          Dave Stevenson <dsteve@broadcom.com>
- *          Simon Mellor <simellor@broadcom.com>
- *          Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ *          Dave Stevenson @ Broadcom
+ *             (now dave.stevenson@raspberrypi.org)
+ *          Simon Mellor @ Broadcom
+ *          Luke Diamand @ Broadcom
  *
  * core driver device
  */
 #define V4L2_CTRL_COUNT 29 /* number of v4l controls */
 
 enum {
-       MMAL_COMPONENT_CAMERA = 0,
-       MMAL_COMPONENT_PREVIEW,
-       MMAL_COMPONENT_IMAGE_ENCODE,
-       MMAL_COMPONENT_VIDEO_ENCODE,
-       MMAL_COMPONENT_COUNT
+       COMP_CAMERA = 0,
+       COMP_PREVIEW,
+       COMP_IMAGE_ENCODE,
+       COMP_VIDEO_ENCODE,
+       COMP_COUNT
 };
 
 enum {
-       MMAL_CAMERA_PORT_PREVIEW = 0,
-       MMAL_CAMERA_PORT_VIDEO,
-       MMAL_CAMERA_PORT_CAPTURE,
-       MMAL_CAMERA_PORT_COUNT
+       CAM_PORT_PREVIEW = 0,
+       CAM_PORT_VIDEO,
+       CAM_PORT_CAPTURE,
+       CAM_PORT_COUNT
 };
 
 #define PREVIEW_LAYER      2
@@ -60,7 +61,7 @@ struct bm2835_mmal_dev {
 
        /* allocated mmal instance and components */
        struct vchiq_mmal_instance   *instance;
-       struct vchiq_mmal_component  *component[MMAL_COMPONENT_COUNT];
+       struct vchiq_mmal_component  *component[COMP_COUNT];
        int camera_use_count;
 
        struct v4l2_window overlay;
@@ -90,6 +91,8 @@ struct bm2835_mmal_dev {
                s64         vc_start_timestamp;
                /* Kernel start timestamp for streaming */
                ktime_t kernel_start_ts;
+               /* Sequence number of last buffer */
+               u32             sequence;
 
                struct vchiq_mmal_port  *port; /* port being used for capture */
                /* camera port being used for capture */
@@ -127,6 +130,7 @@ int set_framerate_params(struct bm2835_mmal_dev *dev);
                (pix_fmt)->pixelformat, (pix_fmt)->bytesperline,        \
                (pix_fmt)->sizeimage, (pix_fmt)->colorspace, (pix_fmt)->priv); \
 }
+
 #define v4l2_dump_win_format(level, debug, dev, win_fmt, desc) \
 {      \
        v4l2_dbg(level, debug, dev,     \
index dade797..89786c2 100644 (file)
@@ -4,10 +4,11 @@
  *
  * Copyright © 2013 Raspberry Pi (Trading) Ltd.
  *
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- *          Dave Stevenson <dsteve@broadcom.com>
- *          Simon Mellor <simellor@broadcom.com>
- *          Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ *          Dave Stevenson @ Broadcom
+ *             (now dave.stevenson@raspberrypi.org)
+ *          Simon Mellor @ Broadcom
+ *          Luke Diamand @ Broadcom
  */
 
 #include <linux/errno.h>
@@ -52,21 +53,9 @@ static const s64 ev_bias_qmenu[] = {
 static const s64 iso_qmenu[] = {
        0, 100000, 200000, 400000, 800000,
 };
-static const uint32_t iso_values[] = {
-       0, 100, 200, 400, 800,
-};
 
-static const s64 mains_freq_qmenu[] = {
-       V4L2_CID_POWER_LINE_FREQUENCY_DISABLED,
-       V4L2_CID_POWER_LINE_FREQUENCY_50HZ,
-       V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
-       V4L2_CID_POWER_LINE_FREQUENCY_AUTO
-};
-
-/* Supported video encode modes */
-static const s64 bitrate_mode_qmenu[] = {
-       (s64)V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
-       (s64)V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+static const u32 iso_values[] = {
+       0, 100, 200, 400, 800,
 };
 
 enum bm2835_mmal_ctrl_type {
@@ -89,10 +78,10 @@ struct bm2835_mmal_v4l2_ctrl {
        /* control minimum value or
         * mask for MMAL_CONTROL_TYPE_STD_MENU
         */
-       s32 min;
-       s32 max; /* maximum value of control */
-       s32 def;  /* default value of control */
-       s32 step; /* step size of the control */
+       s64 min;
+       s64 max; /* maximum value of control */
+       s64 def;  /* default value of control */
+       u64 step; /* step size of the control */
        const s64 *imenu; /* integer menu array */
        u32 mmal_id; /* mmal parameter id */
        bm2835_mmal_v4l2_ctrl_cb *setter;
@@ -175,7 +164,7 @@ static int ctrl_set_rational(struct bm2835_mmal_dev *dev,
        struct mmal_parameter_rational rational_value;
        struct vchiq_mmal_port *control;
 
-       control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+       control = &dev->component[COMP_CAMERA]->control;
 
        rational_value.num = ctrl->val;
        rational_value.den = 100;
@@ -193,7 +182,7 @@ static int ctrl_set_value(struct bm2835_mmal_dev *dev,
        u32 u32_value;
        struct vchiq_mmal_port *control;
 
-       control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+       control = &dev->component[COMP_CAMERA]->control;
 
        u32_value = ctrl->val;
 
@@ -218,7 +207,7 @@ static int ctrl_set_iso(struct bm2835_mmal_dev *dev,
                dev->manual_iso_enabled =
                                (ctrl->val == V4L2_ISO_SENSITIVITY_MANUAL);
 
-       control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+       control = &dev->component[COMP_CAMERA]->control;
 
        if (dev->manual_iso_enabled)
                u32_value = dev->iso;
@@ -237,7 +226,7 @@ static int ctrl_set_value_ev(struct bm2835_mmal_dev *dev,
        s32 s32_value;
        struct vchiq_mmal_port *control;
 
-       control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+       control = &dev->component[COMP_CAMERA]->control;
 
        s32_value = (ctrl->val - 12) * 2;       /* Convert from index to 1/6ths */
 
@@ -254,7 +243,7 @@ static int ctrl_set_rotate(struct bm2835_mmal_dev *dev,
        u32 u32_value;
        struct vchiq_mmal_component *camera;
 
-       camera = dev->component[MMAL_COMPONENT_CAMERA];
+       camera = dev->component[COMP_CAMERA];
 
        u32_value = ((ctrl->val % 360) / 90) * 90;
 
@@ -288,7 +277,7 @@ static int ctrl_set_flip(struct bm2835_mmal_dev *dev,
        else
                dev->vflip = ctrl->val;
 
-       camera = dev->component[MMAL_COMPONENT_CAMERA];
+       camera = dev->component[COMP_CAMERA];
 
        if (dev->hflip && dev->vflip)
                u32_value = MMAL_PARAM_MIRROR_BOTH;
@@ -325,7 +314,7 @@ static int ctrl_set_exposure(struct bm2835_mmal_dev *dev,
        struct vchiq_mmal_port *control;
        int ret = 0;
 
-       control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+       control = &dev->component[COMP_CAMERA]->control;
 
        if (mmal_ctrl->mmal_id == MMAL_PARAMETER_SHUTTER_SPEED) {
                /* V4L2 is in 100usec increments.
@@ -400,13 +389,14 @@ static int ctrl_set_metering_mode(struct bm2835_mmal_dev *dev,
                struct vchiq_mmal_port *control;
                u32 u32_value = dev->metering_mode;
 
-               control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+               control = &dev->component[COMP_CAMERA]->control;
 
                return vchiq_mmal_port_parameter_set(dev->instance, control,
                                             mmal_ctrl->mmal_id,
                                             &u32_value, sizeof(u32_value));
-       } else
+       } else {
                return 0;
+       }
 }
 
 static int ctrl_set_flicker_avoidance(struct bm2835_mmal_dev *dev,
@@ -416,7 +406,7 @@ static int ctrl_set_flicker_avoidance(struct bm2835_mmal_dev *dev,
        u32 u32_value;
        struct vchiq_mmal_port *control;
 
-       control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+       control = &dev->component[COMP_CAMERA]->control;
 
        switch (ctrl->val) {
        case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED:
@@ -445,7 +435,7 @@ static int ctrl_set_awb_mode(struct bm2835_mmal_dev *dev,
        u32 u32_value;
        struct vchiq_mmal_port *control;
 
-       control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+       control = &dev->component[COMP_CAMERA]->control;
 
        switch (ctrl->val) {
        case V4L2_WHITE_BALANCE_MANUAL:
@@ -501,7 +491,7 @@ static int ctrl_set_awb_gains(struct bm2835_mmal_dev *dev,
        struct vchiq_mmal_port *control;
        struct mmal_parameter_awbgains gains;
 
-       control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+       control = &dev->component[COMP_CAMERA]->control;
 
        if (ctrl->id == V4L2_CID_RED_BALANCE)
                dev->red_gain = ctrl->val;
@@ -549,7 +539,7 @@ static int ctrl_set_image_effect(struct bm2835_mmal_dev *dev,
                                        v4l2_to_mmal_effects_values[i].v;
                        }
 
-                       control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+                       control = &dev->component[COMP_CAMERA]->control;
 
                        ret = vchiq_mmal_port_parameter_set(
                                        dev->instance, control,
@@ -579,13 +569,13 @@ static int ctrl_set_colfx(struct bm2835_mmal_dev *dev,
                          struct v4l2_ctrl *ctrl,
                          const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
 {
-       int ret = -EINVAL;
+       int ret;
        struct vchiq_mmal_port *control;
 
-       control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+       control = &dev->component[COMP_CAMERA]->control;
 
-       dev->colourfx.enable = (ctrl->val & 0xff00) >> 8;
-       dev->colourfx.enable = ctrl->val & 0xff;
+       dev->colourfx.u = (ctrl->val & 0xff00) >> 8;
+       dev->colourfx.v = ctrl->val & 0xff;
 
        ret = vchiq_mmal_port_parameter_set(dev->instance, control,
                                            MMAL_PARAMETER_COLOUR_EFFECT,
@@ -603,15 +593,28 @@ static int ctrl_set_bitrate(struct bm2835_mmal_dev *dev,
                            struct v4l2_ctrl *ctrl,
                            const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
 {
+       int ret;
        struct vchiq_mmal_port *encoder_out;
 
        dev->capture.encode_bitrate = ctrl->val;
 
-       encoder_out = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
+       encoder_out = &dev->component[COMP_VIDEO_ENCODE]->output[0];
 
-       return vchiq_mmal_port_parameter_set(dev->instance, encoder_out,
-                                            mmal_ctrl->mmal_id, &ctrl->val,
-                                            sizeof(ctrl->val));
+       ret = vchiq_mmal_port_parameter_set(dev->instance, encoder_out,
+                                           mmal_ctrl->mmal_id, &ctrl->val,
+                                           sizeof(ctrl->val));
+
+       v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+                "%s: After: mmal_ctrl:%p ctrl id:0x%x ctrl val:%d ret %d(%d)\n",
+                __func__, mmal_ctrl, ctrl->id, ctrl->val, ret,
+                (ret == 0 ? 0 : -EINVAL));
+
+       /*
+        * Older firmware versions (pre July 2019) have a bug in handling
+        * MMAL_PARAMETER_VIDEO_BIT_RATE that result in the call
+        * returning -MMAL_MSG_STATUS_EINVAL. So ignore errors from this call.
+        */
+       return 0;
 }
 
 static int ctrl_set_bitrate_mode(struct bm2835_mmal_dev *dev,
@@ -621,7 +624,7 @@ static int ctrl_set_bitrate_mode(struct bm2835_mmal_dev *dev,
        u32 bitrate_mode;
        struct vchiq_mmal_port *encoder_out;
 
-       encoder_out = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
+       encoder_out = &dev->component[COMP_VIDEO_ENCODE]->output[0];
 
        dev->capture.encode_bitrate_mode = ctrl->val;
        switch (ctrl->val) {
@@ -648,7 +651,7 @@ static int ctrl_set_image_encode_output(struct bm2835_mmal_dev *dev,
        u32 u32_value;
        struct vchiq_mmal_port *jpeg_out;
 
-       jpeg_out = &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->output[0];
+       jpeg_out = &dev->component[COMP_IMAGE_ENCODE]->output[0];
 
        u32_value = ctrl->val;
 
@@ -664,7 +667,7 @@ static int ctrl_set_video_encode_param_output(struct bm2835_mmal_dev *dev,
        u32 u32_value;
        struct vchiq_mmal_port *vid_enc_ctl;
 
-       vid_enc_ctl = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
+       vid_enc_ctl = &dev->component[COMP_VIDEO_ENCODE]->output[0];
 
        u32_value = ctrl->val;
 
@@ -777,7 +780,7 @@ static int ctrl_set_video_encode_profile_level(struct bm2835_mmal_dev *dev,
                }
 
                ret = vchiq_mmal_port_parameter_set(dev->instance,
-                                                   &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0],
+                                                   &dev->component[COMP_VIDEO_ENCODE]->output[0],
                        mmal_ctrl->mmal_id,
                        &param, sizeof(param));
        }
@@ -795,7 +798,7 @@ static int ctrl_set_scene_mode(struct bm2835_mmal_dev *dev,
        v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev,
                 "scene mode selected %d, was %d\n", ctrl->val,
                 dev->scene_mode);
-       control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+       control = &dev->component[COMP_CAMERA]->control;
 
        if (ctrl->val == dev->scene_mode)
                return 0;
@@ -956,8 +959,8 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
        },
        {
                V4L2_CID_ISO_SENSITIVITY_AUTO, MMAL_CONTROL_TYPE_STD_MENU,
-               0, 1, V4L2_ISO_SENSITIVITY_AUTO, 1, NULL,
-               MMAL_PARAMETER_ISO,
+               0, V4L2_ISO_SENSITIVITY_AUTO, V4L2_ISO_SENSITIVITY_AUTO, 1,
+               NULL, MMAL_PARAMETER_ISO,
                ctrl_set_iso,
                false
        },
@@ -968,22 +971,13 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
                ctrl_set_value,
                false
        },
-/*     {
- *             0, MMAL_CONTROL_TYPE_CLUSTER, 3, 1, 0, NULL, 0, NULL
- *     },
- */
        {
                V4L2_CID_EXPOSURE_AUTO, MMAL_CONTROL_TYPE_STD_MENU,
-               ~0x03, 3, V4L2_EXPOSURE_AUTO, 0, NULL,
-               MMAL_PARAMETER_EXPOSURE_MODE,
+               ~0x03, V4L2_EXPOSURE_APERTURE_PRIORITY, V4L2_EXPOSURE_AUTO, 0,
+               NULL, MMAL_PARAMETER_EXPOSURE_MODE,
                ctrl_set_exposure,
                false
        },
-/* todo this needs mixing in with set exposure
- *     {
- *             V4L2_CID_SCENE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
- *     },
- */
        {
                V4L2_CID_EXPOSURE_ABSOLUTE, MMAL_CONTROL_TYPE_STD,
                /* Units of 100usecs */
@@ -1011,7 +1005,8 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
        {
                V4L2_CID_EXPOSURE_METERING,
                MMAL_CONTROL_TYPE_STD_MENU,
-               ~0x7, 2, V4L2_EXPOSURE_METERING_AVERAGE, 0, NULL,
+               ~0x7, V4L2_EXPOSURE_METERING_SPOT,
+               V4L2_EXPOSURE_METERING_AVERAGE, 0, NULL,
                MMAL_PARAMETER_EXP_METERING_MODE,
                ctrl_set_metering_mode,
                false
@@ -1019,7 +1014,8 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
        {
                V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
                MMAL_CONTROL_TYPE_STD_MENU,
-               ~0x3ff, 9, V4L2_WHITE_BALANCE_AUTO, 0, NULL,
+               ~0x3ff, V4L2_WHITE_BALANCE_SHADE, V4L2_WHITE_BALANCE_AUTO, 0,
+               NULL,
                MMAL_PARAMETER_AWB_MODE,
                ctrl_set_awb_mode,
                false
@@ -1040,7 +1036,7 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
        },
        {
                V4L2_CID_COLORFX, MMAL_CONTROL_TYPE_STD_MENU,
-               0, 15, V4L2_COLORFX_NONE, 0, NULL,
+               0, V4L2_COLORFX_SET_CBCR, V4L2_COLORFX_NONE, 0, NULL,
                MMAL_PARAMETER_IMAGE_EFFECT,
                ctrl_set_image_effect,
                false
@@ -1075,8 +1071,8 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
        },
        {
                V4L2_CID_MPEG_VIDEO_BITRATE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
-               0, ARRAY_SIZE(bitrate_mode_qmenu) - 1,
-               0, 0, bitrate_mode_qmenu,
+               0, V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+               0, 0, NULL,
                MMAL_PARAMETER_RATECONTROL,
                ctrl_set_bitrate_mode,
                false
@@ -1098,8 +1094,8 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
        },
        {
                V4L2_CID_POWER_LINE_FREQUENCY, MMAL_CONTROL_TYPE_STD_MENU,
-               0, ARRAY_SIZE(mains_freq_qmenu) - 1,
-               1, 1, mains_freq_qmenu,
+               0, V4L2_CID_POWER_LINE_FREQUENCY_AUTO,
+               1, 1, NULL,
                MMAL_PARAMETER_FLICKER_AVOID,
                ctrl_set_flicker_avoidance,
                false
@@ -1110,15 +1106,15 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
                0, 1, NULL,
                MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER,
                ctrl_set_video_encode_param_output,
-               true    /* Errors ignored as requires latest firmware to work */
+               false
        },
        {
                V4L2_CID_MPEG_VIDEO_H264_PROFILE,
                MMAL_CONTROL_TYPE_STD_MENU,
-               ~((1<<V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
-                       (1<<V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
-                       (1<<V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
-                       (1<<V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
+               ~(BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
+                 BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
+                 BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
+                 BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
                V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
                V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, 1, NULL,
                MMAL_PARAMETER_PROFILE,
@@ -1127,18 +1123,18 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
        },
        {
                V4L2_CID_MPEG_VIDEO_H264_LEVEL, MMAL_CONTROL_TYPE_STD_MENU,
-               ~((1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
-                       (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
-                       (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
-                       (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
-                       (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
-                       (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
-                       (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
-                       (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
-                       (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
-                       (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
-                       (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
-                       (1<<V4L2_MPEG_VIDEO_H264_LEVEL_4_0)),
+               ~(BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
+                 BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
+                 BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
+                 BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
+                 BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
+                 BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
+                 BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
+                 BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
+                 BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
+                 BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
+                 BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
+                 BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0)),
                V4L2_MPEG_VIDEO_H264_LEVEL_4_0,
                V4L2_MPEG_VIDEO_H264_LEVEL_4_0, 1, NULL,
                MMAL_PARAMETER_PROFILE,
@@ -1147,7 +1143,7 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
        },
        {
                V4L2_CID_SCENE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
-               -1,     /* Min is computed at runtime */
+               -1,     /* Min (mask) is computed at runtime */
                V4L2_SCENE_MODE_TEXT,
                V4L2_SCENE_MODE_NONE, 1, NULL,
                MMAL_PARAMETER_PROFILE,
@@ -1213,18 +1209,15 @@ int set_framerate_params(struct bm2835_mmal_dev *dev)
                 fps_range.fps_high.den);
 
        ret = vchiq_mmal_port_parameter_set(dev->instance,
-                                           &dev->component[MMAL_COMPONENT_CAMERA]->
-                                           output[MMAL_CAMERA_PORT_PREVIEW],
+                                           &dev->component[COMP_CAMERA]->output[CAM_PORT_PREVIEW],
                                            MMAL_PARAMETER_FPS_RANGE,
                                            &fps_range, sizeof(fps_range));
        ret += vchiq_mmal_port_parameter_set(dev->instance,
-                                            &dev->component[MMAL_COMPONENT_CAMERA]->
-                                            output[MMAL_CAMERA_PORT_VIDEO],
+                                            &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO],
                                             MMAL_PARAMETER_FPS_RANGE,
                                             &fps_range, sizeof(fps_range));
        ret += vchiq_mmal_port_parameter_set(dev->instance,
-                                            &dev->component[MMAL_COMPONENT_CAMERA]->
-                                            output[MMAL_CAMERA_PORT_CAPTURE],
+                                            &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE],
                                             MMAL_PARAMETER_FPS_RANGE,
                                             &fps_range, sizeof(fps_range));
        if (ret)
@@ -1247,14 +1240,17 @@ int bm2835_mmal_init_controls(struct bm2835_mmal_dev *dev,
 
                switch (ctrl->type) {
                case MMAL_CONTROL_TYPE_STD:
-                       dev->ctrls[c] = v4l2_ctrl_new_std(hdl,
-                               &bm2835_mmal_ctrl_ops, ctrl->id,
-                               ctrl->min, ctrl->max, ctrl->step, ctrl->def);
+                       dev->ctrls[c] =
+                               v4l2_ctrl_new_std(hdl,
+                                                 &bm2835_mmal_ctrl_ops,
+                                                 ctrl->id, ctrl->min,
+                                                 ctrl->max, ctrl->step,
+                                                 ctrl->def);
                        break;
 
                case MMAL_CONTROL_TYPE_STD_MENU:
                {
-                       int mask = ctrl->min;
+                       u64 mask = ctrl->min;
 
                        if (ctrl->id == V4L2_CID_SCENE_MODE) {
                                /* Special handling to work out the mask
@@ -1264,25 +1260,29 @@ int bm2835_mmal_init_controls(struct bm2835_mmal_dev *dev,
                                 */
                                int i;
 
-                               mask = 1 << V4L2_SCENE_MODE_NONE;
+                               mask = BIT(V4L2_SCENE_MODE_NONE);
                                for (i = 0;
                                     i < ARRAY_SIZE(scene_configs);
                                     i++) {
-                                       mask |= 1 << scene_configs[i].v4l2_scene;
+                                       mask |= BIT(scene_configs[i].v4l2_scene);
                                }
                                mask = ~mask;
                        }
 
-                       dev->ctrls[c] = v4l2_ctrl_new_std_menu(hdl,
-                       &bm2835_mmal_ctrl_ops, ctrl->id,
-                       ctrl->max, mask, ctrl->def);
+                       dev->ctrls[c] =
+                               v4l2_ctrl_new_std_menu(hdl,
+                                                      &bm2835_mmal_ctrl_ops,
+                                                      ctrl->id, ctrl->max,
+                                                      mask, ctrl->def);
                        break;
                }
 
                case MMAL_CONTROL_TYPE_INT_MENU:
-                       dev->ctrls[c] = v4l2_ctrl_new_int_menu(hdl,
-                               &bm2835_mmal_ctrl_ops, ctrl->id,
-                               ctrl->max, ctrl->def, ctrl->imenu);
+                       dev->ctrls[c] =
+                               v4l2_ctrl_new_int_menu(hdl,
+                                                      &bm2835_mmal_ctrl_ops,
+                                                      ctrl->id, ctrl->max,
+                                                      ctrl->def, ctrl->imenu);
                        break;
 
                case MMAL_CONTROL_TYPE_CLUSTER:
index a20bf27..6f56c51 100644 (file)
@@ -4,14 +4,17 @@
  *
  * Copyright © 2013 Raspberry Pi (Trading) Ltd.
  *
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- *          Dave Stevenson <dsteve@broadcom.com>
- *          Simon Mellor <simellor@broadcom.com>
- *          Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ *          Dave Stevenson @ Broadcom
+ *             (now dave.stevenson@raspberrypi.org)
+ *          Simon Mellor @ Broadcom
+ *          Luke Diamand @ Broadcom
  *
  * MMAL structures
  *
  */
+#ifndef MMAL_COMMON_H
+#define MMAL_COMMON_H
 
 #define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24))
 #define MMAL_MAGIC MMAL_FOURCC('m', 'm', 'a', 'l')
@@ -55,3 +58,4 @@ struct mmal_colourfx {
        u32 u;
        u32 v;
 };
+#endif
index 1292035..2be9941 100644 (file)
@@ -4,10 +4,11 @@
  *
  * Copyright © 2013 Raspberry Pi (Trading) Ltd.
  *
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- *          Dave Stevenson <dsteve@broadcom.com>
- *          Simon Mellor <simellor@broadcom.com>
- *          Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ *          Dave Stevenson @ Broadcom
+ *             (now dave.stevenson@raspberrypi.org)
+ *          Simon Mellor @ Broadcom
+ *          Luke Diamand @ Broadcom
  */
 #ifndef MMAL_ENCODINGS_H
 #define MMAL_ENCODINGS_H
index ec84556..342c9b6 100644 (file)
@@ -4,10 +4,11 @@
  *
  * Copyright © 2013 Raspberry Pi (Trading) Ltd.
  *
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- *          Dave Stevenson <dsteve@broadcom.com>
- *          Simon Mellor <simellor@broadcom.com>
- *          Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ *          Dave Stevenson @ Broadcom
+ *             (now dave.stevenson@raspberrypi.org)
+ *          Simon Mellor @ Broadcom
+ *          Luke Diamand @ Broadcom
  */
 
 #ifndef MMAL_MSG_COMMON_H
index c9d6fbe..a118efd 100644 (file)
@@ -4,10 +4,11 @@
  *
  * Copyright © 2013 Raspberry Pi (Trading) Ltd.
  *
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- *          Dave Stevenson <dsteve@broadcom.com>
- *          Simon Mellor <simellor@broadcom.com>
- *          Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ *          Dave Stevenson @ Broadcom
+ *             (now dave.stevenson@raspberrypi.org)
+ *          Simon Mellor @ Broadcom
+ *          Luke Diamand @ Broadcom
  */
 
 #ifndef MMAL_MSG_FORMAT_H
 /* MMAL_ES_FORMAT_T */
 
 struct mmal_audio_format {
-       u32 channels;           /**< Number of audio channels */
-       u32 sample_rate;        /**< Sample rate */
+       u32 channels;           /* Number of audio channels */
+       u32 sample_rate;        /* Sample rate */
 
-       u32 bits_per_sample;    /**< Bits per sample */
-       u32 block_align;        /**< Size of a block of data */
+       u32 bits_per_sample;    /* Bits per sample */
+       u32 block_align;        /* Size of a block of data */
 };
 
 struct mmal_video_format {
-       u32 width;        /**< Width of frame in pixels */
-       u32 height;       /**< Height of frame in rows of pixels */
-       struct mmal_rect crop;         /**< Visible region of the frame */
-       struct mmal_rational frame_rate;   /**< Frame rate */
-       struct mmal_rational par;          /**< Pixel aspect ratio */
-
-       /* FourCC specifying the color space of the video stream. See the
-        * \ref MmalColorSpace "pre-defined color spaces" for some examples.
+       u32 width;              /* Width of frame in pixels */
+       u32 height;             /* Height of frame in rows of pixels */
+       struct mmal_rect crop;  /* Visible region of the frame */
+       struct mmal_rational frame_rate;        /* Frame rate */
+       struct mmal_rational par;               /* Pixel aspect ratio */
+
+       /*
+        * FourCC specifying the color space of the video stream. See the
+        * MmalColorSpace "pre-defined color spaces" for some examples.
         */
        u32 color_space;
 };
@@ -49,48 +51,56 @@ union mmal_es_specific_format {
        struct mmal_subpicture_format subpicture;
 };
 
-/** Definition of an elementary stream format (MMAL_ES_FORMAT_T) */
+/* Definition of an elementary stream format (MMAL_ES_FORMAT_T) */
 struct mmal_es_format_local {
-       u32 type;      /* enum mmal_es_type */
-
-       u32 encoding;  /* FourCC specifying encoding of the elementary stream.*/
-       u32 encoding_variant; /* FourCC specifying the specific
-                              * encoding variant of the elementary
-                              * stream.
-                              */
-
-       union mmal_es_specific_format *es;  /* Type specific
-                                            * information for the
-                                            * elementary stream
-                                            */
-
-       u32 bitrate;        /**< Bitrate in bits per second */
-       u32 flags; /**< Flags describing properties of the elementary stream. */
-
-       u32 extradata_size;       /**< Size of the codec specific data */
-       u8  *extradata;           /**< Codec specific data */
+       u32 type;       /* enum mmal_es_type */
+
+       u32 encoding;   /* FourCC specifying encoding of the elementary
+                        * stream.
+                        */
+       u32 encoding_variant;   /* FourCC specifying the specific
+                                * encoding variant of the elementary
+                                * stream.
+                                */
+
+       union mmal_es_specific_format *es;      /* Type specific
+                                                * information for the
+                                                * elementary stream
+                                                */
+
+       u32 bitrate;    /* Bitrate in bits per second */
+       u32 flags;      /* Flags describing properties of the elementary
+                        * stream.
+                        */
+
+       u32 extradata_size;     /* Size of the codec specific data */
+       u8  *extradata;         /* Codec specific data */
 };
 
-/** Remote definition of an elementary stream format (MMAL_ES_FORMAT_T) */
+/* Remote definition of an elementary stream format (MMAL_ES_FORMAT_T) */
 struct mmal_es_format {
-       u32 type;      /* enum mmal_es_type */
+       u32 type;       /* enum mmal_es_type */
 
-       u32 encoding;  /* FourCC specifying encoding of the elementary stream.*/
-       u32 encoding_variant; /* FourCC specifying the specific
-                              * encoding variant of the elementary
-                              * stream.
-                              */
+       u32 encoding;   /* FourCC specifying encoding of the elementary
+                        * stream.
+                        */
+       u32 encoding_variant;   /* FourCC specifying the specific
+                                * encoding variant of the elementary
+                                * stream.
+                                */
 
-       u32 es; /* Type specific
+       u32 es; /* Type specific
                 * information for the
                 * elementary stream
                 */
 
-       u32 bitrate;        /**< Bitrate in bits per second */
-       u32 flags; /**< Flags describing properties of the elementary stream. */
+       u32 bitrate;    /* Bitrate in bits per second */
+       u32 flags;      /* Flags describing properties of the elementary
+                        * stream.
+                        */
 
-       u32 extradata_size;       /**< Size of the codec specific data */
-       u32 extradata;           /**< Codec specific data */
+       u32 extradata_size;     /* Size of the codec specific data */
+       u32 extradata;          /* Codec specific data */
 };
 
 #endif /* MMAL_MSG_FORMAT_H */
index 3b3ed79..3fa3f2a 100644 (file)
@@ -4,36 +4,40 @@
  *
  * Copyright © 2013 Raspberry Pi (Trading) Ltd.
  *
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- *          Dave Stevenson <dsteve@broadcom.com>
- *          Simon Mellor <simellor@broadcom.com>
- *          Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ *          Dave Stevenson @ Broadcom
+ *             (now dave.stevenson@raspberrypi.org)
+ *          Simon Mellor @ Broadcom
+ *          Luke Diamand @ Broadcom
  */
 
 /* MMAL_PORT_TYPE_T */
 enum mmal_port_type {
-       MMAL_PORT_TYPE_UNKNOWN = 0,  /**< Unknown port type */
-       MMAL_PORT_TYPE_CONTROL,      /**< Control port */
-       MMAL_PORT_TYPE_INPUT,        /**< Input port */
-       MMAL_PORT_TYPE_OUTPUT,       /**< Output port */
-       MMAL_PORT_TYPE_CLOCK,        /**< Clock port */
+       MMAL_PORT_TYPE_UNKNOWN = 0,     /* Unknown port type */
+       MMAL_PORT_TYPE_CONTROL,         /* Control port */
+       MMAL_PORT_TYPE_INPUT,           /* Input port */
+       MMAL_PORT_TYPE_OUTPUT,          /* Output port */
+       MMAL_PORT_TYPE_CLOCK,           /* Clock port */
 };
 
-/** The port is pass-through and doesn't need buffer headers allocated */
+/* The port is pass-through and doesn't need buffer headers allocated */
 #define MMAL_PORT_CAPABILITY_PASSTHROUGH                       0x01
-/** The port wants to allocate the buffer payloads.
+/*
+ *The port wants to allocate the buffer payloads.
  * This signals a preference that payload allocation should be done
  * on this port for efficiency reasons.
  */
 #define MMAL_PORT_CAPABILITY_ALLOCATION                        0x02
-/** The port supports format change events.
+/*
+ * The port supports format change events.
  * This applies to input ports and is used to let the client know
  * whether the port supports being reconfigured via a format
  * change event (i.e. without having to disable the port).
  */
 #define MMAL_PORT_CAPABILITY_SUPPORTS_EVENT_FORMAT_CHANGE      0x04
 
-/* mmal port structure (MMAL_PORT_T)
+/*
+ * mmal port structure (MMAL_PORT_T)
  *
  * most elements are informational only, the pointer values for
  * interogation messages are generally provided as additional
@@ -41,50 +45,50 @@ enum mmal_port_type {
  * buffer_num, buffer_size and userdata parameters are writable.
  */
 struct mmal_port {
-       u32 priv; /* Private member used by the framework */
-       u32 name; /* Port name. Used for debugging purposes (RO) */
-
-       u32 type;      /* Type of the port (RO) enum mmal_port_type */
-       u16 index;     /* Index of the port in its type list (RO) */
-       u16 index_all; /* Index of the port in the list of all ports (RO) */
-
-       u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */
-       u32 format; /* Format of the elementary stream */
-
-       u32 buffer_num_min; /* Minimum number of buffers the port
-                            *   requires (RO).  This is set by the
-                            *   component.
-                            */
-
-       u32 buffer_size_min; /* Minimum size of buffers the port
-                             * requires (RO).  This is set by the
-                             * component.
-                             */
-
-       u32 buffer_alignment_min; /* Minimum alignment requirement for
-                                  * the buffers (RO).  A value of
-                                  * zero means no special alignment
-                                  * requirements.  This is set by the
-                                  * component.
-                                  */
-
-       u32 buffer_num_recommended;  /* Number of buffers the port
-                                     * recommends for optimal
-                                     * performance (RO).  A value of
-                                     * zero means no special
-                                     * recommendation.  This is set
-                                     * by the component.
-                                     */
-
-       u32 buffer_size_recommended; /* Size of buffers the port
-                                     * recommends for optimal
-                                     * performance (RO).  A value of
-                                     * zero means no special
-                                     * recommendation.  This is set
-                                     * by the component.
-                                     */
-
-       u32 buffer_num; /* Actual number of buffers the port will use.
+       u32 priv;       /* Private member used by the framework */
+       u32 name;       /* Port name. Used for debugging purposes (RO) */
+
+       u32 type;       /* Type of the port (RO) enum mmal_port_type */
+       u16 index;      /* Index of the port in its type list (RO) */
+       u16 index_all;  /* Index of the port in the list of all ports (RO) */
+
+       u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */
+       u32 format;     /* Format of the elementary stream */
+
+       u32 buffer_num_min;     /* Minimum number of buffers the port
+                                *   requires (RO).  This is set by the
+                                *   component.
+                                */
+
+       u32 buffer_size_min;    /* Minimum size of buffers the port
+                                * requires (RO).  This is set by the
+                                * component.
+                                */
+
+       u32 buffer_alignment_min;/* Minimum alignment requirement for
+                                 * the buffers (RO).  A value of
+                                 * zero means no special alignment
+                                 * requirements.  This is set by the
+                                 * component.
+                                 */
+
+       u32 buffer_num_recommended;     /* Number of buffers the port
+                                        * recommends for optimal
+                                        * performance (RO).  A value of
+                                        * zero means no special
+                                        * recommendation.  This is set
+                                        * by the component.
+                                        */
+
+       u32 buffer_size_recommended;    /* Size of buffers the port
+                                        * recommends for optimal
+                                        * performance (RO).  A value of
+                                        * zero means no special
+                                        * recommendation.  This is set
+                                        * by the component.
+                                        */
+
+       u32 buffer_num; /* Actual number of buffers the port will use.
                         * This is set by the client.
                         */
 
@@ -93,14 +97,13 @@ struct mmal_port {
                          * the client.
                          */
 
-       u32 component; /* Component this port belongs to (Read Only) */
-
-       u32 userdata; /* Field reserved for use by the client */
+       u32 component;  /* Component this port belongs to (Read Only) */
 
-       u32 capabilities; /* Flags describing the capabilities of a
-                          * port (RO).  Bitwise combination of \ref
-                          * portcapabilities "Port capabilities"
-                          * values.
-                          */
+       u32 userdata;   /* Field reserved for use by the client */
 
+       u32 capabilities;       /* Flags describing the capabilities of a
+                                * port (RO).  Bitwise combination of \ref
+                                * portcapabilities "Port capabilities"
+                                * values.
+                                */
 };
index d1c57ed..43cc593 100644 (file)
@@ -4,13 +4,15 @@
  *
  * Copyright © 2013 Raspberry Pi (Trading) Ltd.
  *
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- *          Dave Stevenson <dsteve@broadcom.com>
- *          Simon Mellor <simellor@broadcom.com>
- *          Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ *          Dave Stevenson @ Broadcom
+ *             (now dave.stevenson@raspberrypi.org)
+ *          Simon Mellor @ Broadcom
+ *          Luke Diamand @ Broadcom
  */
 
-/* all the data structures which serialise the MMAL protocol. note
+/*
+ * all the data structures which serialise the MMAL protocol. note
  * these are directly mapped onto the recived message data.
  *
  * BEWARE: They seem to *assume* pointers are u32 and that there is no
@@ -21,6 +23,8 @@
  * implementation uses fixed size types and not the enums (though the
  * comments have the actual enum type
  */
+#ifndef MMAL_MSG_H
+#define MMAL_MSG_H
 
 #define VC_MMAL_VER 15
 #define VC_MMAL_MIN_VER 10
@@ -40,51 +44,51 @@ enum mmal_msg_type {
        MMAL_MSG_TYPE_SERVICE_CLOSED,
        MMAL_MSG_TYPE_GET_VERSION,
        MMAL_MSG_TYPE_COMPONENT_CREATE,
-       MMAL_MSG_TYPE_COMPONENT_DESTROY, /* 5 */
+       MMAL_MSG_TYPE_COMPONENT_DESTROY,        /* 5 */
        MMAL_MSG_TYPE_COMPONENT_ENABLE,
        MMAL_MSG_TYPE_COMPONENT_DISABLE,
        MMAL_MSG_TYPE_PORT_INFO_GET,
        MMAL_MSG_TYPE_PORT_INFO_SET,
-       MMAL_MSG_TYPE_PORT_ACTION, /* 10 */
+       MMAL_MSG_TYPE_PORT_ACTION,              /* 10 */
        MMAL_MSG_TYPE_BUFFER_FROM_HOST,
        MMAL_MSG_TYPE_BUFFER_TO_HOST,
        MMAL_MSG_TYPE_GET_STATS,
        MMAL_MSG_TYPE_PORT_PARAMETER_SET,
-       MMAL_MSG_TYPE_PORT_PARAMETER_GET, /* 15 */
+       MMAL_MSG_TYPE_PORT_PARAMETER_GET,       /* 15 */
        MMAL_MSG_TYPE_EVENT_TO_HOST,
        MMAL_MSG_TYPE_GET_CORE_STATS_FOR_PORT,
        MMAL_MSG_TYPE_OPAQUE_ALLOCATOR,
        MMAL_MSG_TYPE_CONSUME_MEM,
-       MMAL_MSG_TYPE_LMK, /* 20 */
+       MMAL_MSG_TYPE_LMK,                      /* 20 */
        MMAL_MSG_TYPE_OPAQUE_ALLOCATOR_DESC,
        MMAL_MSG_TYPE_DRM_GET_LHS32,
        MMAL_MSG_TYPE_DRM_GET_TIME,
        MMAL_MSG_TYPE_BUFFER_FROM_HOST_ZEROLEN,
-       MMAL_MSG_TYPE_PORT_FLUSH, /* 25 */
+       MMAL_MSG_TYPE_PORT_FLUSH,               /* 25 */
        MMAL_MSG_TYPE_HOST_LOG,
        MMAL_MSG_TYPE_MSG_LAST
 };
 
 /* port action request messages differ depending on the action type */
 enum mmal_msg_port_action_type {
-       MMAL_MSG_PORT_ACTION_TYPE_UNKNOWN = 0,      /* Unknown action */
-       MMAL_MSG_PORT_ACTION_TYPE_ENABLE,           /* Enable a port */
-       MMAL_MSG_PORT_ACTION_TYPE_DISABLE,          /* Disable a port */
-       MMAL_MSG_PORT_ACTION_TYPE_FLUSH,            /* Flush a port */
-       MMAL_MSG_PORT_ACTION_TYPE_CONNECT,          /* Connect ports */
-       MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT,       /* Disconnect ports */
+       MMAL_MSG_PORT_ACTION_TYPE_UNKNOWN = 0,  /* Unknown action */
+       MMAL_MSG_PORT_ACTION_TYPE_ENABLE,       /* Enable a port */
+       MMAL_MSG_PORT_ACTION_TYPE_DISABLE,      /* Disable a port */
+       MMAL_MSG_PORT_ACTION_TYPE_FLUSH,        /* Flush a port */
+       MMAL_MSG_PORT_ACTION_TYPE_CONNECT,      /* Connect ports */
+       MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT,   /* Disconnect ports */
        MMAL_MSG_PORT_ACTION_TYPE_SET_REQUIREMENTS, /* Set buffer requirements*/
 };
 
 struct mmal_msg_header {
        u32 magic;
-       u32 type; /** enum mmal_msg_type */
+       u32 type;       /* enum mmal_msg_type */
 
        /* Opaque handle to the control service */
        u32 control_service;
 
-       u32 context; /** a u32 per message context */
-       u32 status; /** The status of the vchiq operation */
+       u32 context;    /* a u32 per message context */
+       u32 status;     /* The status of the vchiq operation */
        u32 padding;
 };
 
@@ -98,9 +102,9 @@ struct mmal_msg_version {
 
 /* request to VC to create component */
 struct mmal_msg_component_create {
-       u32 client_component; /* component context */
+       u32 client_component;   /* component context */
        char name[128];
-       u32 pid;                /* For debug */
+       u32 pid;                /* For debug */
 };
 
 /* reply from VC to component creation request */
@@ -120,7 +124,7 @@ struct mmal_msg_component_destroy {
 };
 
 struct mmal_msg_component_destroy_reply {
-       u32 status; /** The component destruction status */
+       u32 status; /* The component destruction status */
 };
 
 /* request and reply to VC to enable a component */
@@ -129,7 +133,7 @@ struct mmal_msg_component_enable {
 };
 
 struct mmal_msg_component_enable_reply {
-       u32 status; /** The component enable status */
+       u32 status; /* The component enable status */
 };
 
 /* request and reply to VC to disable a component */
@@ -138,7 +142,7 @@ struct mmal_msg_component_disable {
 };
 
 struct mmal_msg_component_disable_reply {
-       u32 status; /** The component disable status */
+       u32 status; /* The component disable status */
 };
 
 /* request to VC to get port information */
@@ -150,12 +154,12 @@ struct mmal_msg_port_info_get {
 
 /* reply from VC to get port info request */
 struct mmal_msg_port_info_get_reply {
-       u32 status; /** enum mmal_msg_status */
-       u32 component_handle;  /* component handle port is associated with */
-       u32 port_type;         /* enum mmal_msg_port_type */
-       u32 port_index;        /* port indexed in query */
-       s32 found;             /* unused */
-       u32 port_handle;               /**< Handle to use for this port */
+       u32 status;             /* enum mmal_msg_status */
+       u32 component_handle;   /* component handle port is associated with */
+       u32 port_type;          /* enum mmal_msg_port_type */
+       u32 port_index;         /* port indexed in query */
+       s32 found;              /* unused */
+       u32 port_handle;        /* Handle to use for this port */
        struct mmal_port port;
        struct mmal_es_format format; /* elementary stream format */
        union mmal_es_specific_format es; /* es type specific data */
@@ -165,8 +169,8 @@ struct mmal_msg_port_info_get_reply {
 /* request to VC to set port information */
 struct mmal_msg_port_info_set {
        u32 component_handle;
-       u32 port_type;         /* enum mmal_msg_port_type */
-       u32 port_index;           /* port indexed in query */
+       u32 port_type;          /* enum mmal_msg_port_type */
+       u32 port_index;         /* port indexed in query */
        struct mmal_port port;
        struct mmal_es_format format;
        union mmal_es_specific_format es;
@@ -176,11 +180,11 @@ struct mmal_msg_port_info_set {
 /* reply from VC to port info set request */
 struct mmal_msg_port_info_set_reply {
        u32 status;
-       u32 component_handle;  /* component handle port is associated with */
-       u32 port_type;         /* enum mmal_msg_port_type */
-       u32 index;             /* port indexed in query */
-       s32 found;             /* unused */
-       u32 port_handle;               /**< Handle to use for this port */
+       u32 component_handle;   /* component handle port is associated with */
+       u32 port_type;          /* enum mmal_msg_port_type */
+       u32 index;              /* port indexed in query */
+       s32 found;              /* unused */
+       u32 port_handle;        /* Handle to use for this port */
        struct mmal_port port;
        struct mmal_es_format format;
        union mmal_es_specific_format es;
@@ -191,7 +195,7 @@ struct mmal_msg_port_info_set_reply {
 struct mmal_msg_port_action_port {
        u32 component_handle;
        u32 port_handle;
-       u32 action; /* enum mmal_msg_port_action_type */
+       u32 action;             /* enum mmal_msg_port_action_type */
        struct mmal_port port;
 };
 
@@ -199,50 +203,54 @@ struct mmal_msg_port_action_port {
 struct mmal_msg_port_action_handle {
        u32 component_handle;
        u32 port_handle;
-       u32 action; /* enum mmal_msg_port_action_type */
+       u32 action;             /* enum mmal_msg_port_action_type */
        u32 connect_component_handle;
        u32 connect_port_handle;
 };
 
 struct mmal_msg_port_action_reply {
-       u32 status; /** The port action operation status */
+       u32 status;     /* The port action operation status */
 };
 
 /* MMAL buffer transfer */
 
-/** Size of space reserved in a buffer message for short messages. */
+/* Size of space reserved in a buffer message for short messages. */
 #define MMAL_VC_SHORT_DATA 128
 
-/** Signals that the current payload is the end of the stream of data */
+/* Signals that the current payload is the end of the stream of data */
 #define MMAL_BUFFER_HEADER_FLAG_EOS                    BIT(0)
-/** Signals that the start of the current payload starts a frame */
+/* Signals that the start of the current payload starts a frame */
 #define MMAL_BUFFER_HEADER_FLAG_FRAME_START            BIT(1)
-/** Signals that the end of the current payload ends a frame */
+/* Signals that the end of the current payload ends a frame */
 #define MMAL_BUFFER_HEADER_FLAG_FRAME_END              BIT(2)
-/** Signals that the current payload contains only complete frames (>1) */
+/* Signals that the current payload contains only complete frames (>1) */
 #define MMAL_BUFFER_HEADER_FLAG_FRAME                  \
-       (MMAL_BUFFER_HEADER_FLAG_FRAME_START|MMAL_BUFFER_HEADER_FLAG_FRAME_END)
-/** Signals that the current payload is a keyframe (i.e. self decodable) */
+       (MMAL_BUFFER_HEADER_FLAG_FRAME_START | \
+        MMAL_BUFFER_HEADER_FLAG_FRAME_END)
+/* Signals that the current payload is a keyframe (i.e. self decodable) */
 #define MMAL_BUFFER_HEADER_FLAG_KEYFRAME               BIT(3)
-/** Signals a discontinuity in the stream of data (e.g. after a seek).
+/*
+ * Signals a discontinuity in the stream of data (e.g. after a seek).
  * Can be used for instance by a decoder to reset its state
  */
 #define MMAL_BUFFER_HEADER_FLAG_DISCONTINUITY          BIT(4)
-/** Signals a buffer containing some kind of config data for the component
+/*
+ * Signals a buffer containing some kind of config data for the component
  * (e.g. codec config data)
  */
 #define MMAL_BUFFER_HEADER_FLAG_CONFIG                 BIT(5)
-/** Signals an encrypted payload */
+/* Signals an encrypted payload */
 #define MMAL_BUFFER_HEADER_FLAG_ENCRYPTED              BIT(6)
-/** Signals a buffer containing side information */
+/* Signals a buffer containing side information */
 #define MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO          BIT(7)
-/** Signals a buffer which is the snapshot/postview image from a stills
+/*
+ * Signals a buffer which is the snapshot/postview image from a stills
  * capture
  */
 #define MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT              BIT(8)
-/** Signals a buffer which contains data known to be corrupted */
+/* Signals a buffer which contains data known to be corrupted */
 #define MMAL_BUFFER_HEADER_FLAG_CORRUPTED              BIT(9)
-/** Signals that a buffer failed to be transmitted */
+/* Signals that a buffer failed to be transmitted */
 #define MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED    BIT(10)
 
 struct mmal_driver_buffer {
@@ -254,8 +262,8 @@ struct mmal_driver_buffer {
 
 /* buffer header */
 struct mmal_buffer_header {
-       u32 next; /* next header */
-       u32 priv; /* framework private data */
+       u32 next;       /* next header */
+       u32 priv;       /* framework private data */
        u32 cmd;
        u32 data;
        u32 alloc_size;
@@ -280,7 +288,8 @@ struct mmal_buffer_header_type_specific {
 };
 
 struct mmal_msg_buffer_from_host {
-       /* The front 32 bytes of the buffer header are copied
+       /*
+        *The front 32 bytes of the buffer header are copied
         * back to us in the reply to allow for context. This
         * area is used to store two mmal_driver_buffer structures to
         * allow for multiple concurrent service users.
@@ -295,7 +304,7 @@ struct mmal_msg_buffer_from_host {
        s32 is_zero_copy;
        s32 has_reference;
 
-       /** allows short data to be xfered in control message */
+       /* allows short data to be xfered in control message */
        u32 payload_in_message;
        u8 short_data[MMAL_VC_SHORT_DATA];
 };
@@ -305,11 +314,11 @@ struct mmal_msg_buffer_from_host {
 #define MMAL_WORKER_PORT_PARAMETER_SPACE      96
 
 struct mmal_msg_port_parameter_set {
-       u32 component_handle; /* component */
-       u32 port_handle;      /* port */
-       u32 id;     /* Parameter ID  */
-       u32 size;      /* Parameter size */
-       uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
+       u32 component_handle;   /* component */
+       u32 port_handle;        /* port */
+       u32 id;                 /* Parameter ID  */
+       u32 size;               /* Parameter size */
+       u32 value[MMAL_WORKER_PORT_PARAMETER_SPACE];
 };
 
 struct mmal_msg_port_parameter_set_reply {
@@ -321,24 +330,24 @@ struct mmal_msg_port_parameter_set_reply {
 /* port parameter getting */
 
 struct mmal_msg_port_parameter_get {
-       u32 component_handle; /* component */
-       u32 port_handle;      /* port */
-       u32 id;     /* Parameter ID  */
-       u32 size;      /* Parameter size */
+       u32 component_handle;   /* component */
+       u32 port_handle;        /* port */
+       u32 id;                 /* Parameter ID  */
+       u32 size;               /* Parameter size */
 };
 
 struct mmal_msg_port_parameter_get_reply {
-       u32 status;           /* Status of mmal_port_parameter_get call */
-       u32 id;     /* Parameter ID  */
-       u32 size;      /* Parameter size */
-       uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
+       u32 status;             /* Status of mmal_port_parameter_get call */
+       u32 id;                 /* Parameter ID  */
+       u32 size;               /* Parameter size */
+       u32 value[MMAL_WORKER_PORT_PARAMETER_SPACE];
 };
 
 /* event messages */
 #define MMAL_WORKER_EVENT_SPACE 256
 
 struct mmal_msg_event_to_host {
-       u32 client_component; /* component context */
+       u32 client_component;   /* component context */
 
        u32 port_type;
        u32 port_num;
@@ -394,3 +403,4 @@ struct mmal_msg {
                u8 payload[MMAL_MSG_MAX_PAYLOAD];
        } u;
 };
+#endif
index 184024d..80a9912 100644 (file)
@@ -4,10 +4,11 @@
  *
  * Copyright © 2013 Raspberry Pi (Trading) Ltd.
  *
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- *          Dave Stevenson <dsteve@broadcom.com>
- *          Simon Mellor <simellor@broadcom.com>
- *          Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ *          Dave Stevenson @ Broadcom
+ *             (now dave.stevenson@raspberrypi.org)
+ *          Simon Mellor @ Broadcom
+ *          Luke Diamand @ Broadcom
  */
 
 /* common parameters */
  * @{
  */
 
-#ifndef __MMAL_PARAMETERS_H
-#define __MMAL_PARAMETERS_H
+#ifndef MMAL_PARAMETERS_H
+#define MMAL_PARAMETERS_H
 
 /** Common parameter ID group, used with many types of component. */
-#define MMAL_PARAMETER_GROUP_COMMON            (0<<16)
+#define MMAL_PARAMETER_GROUP_COMMON            (0 << 16)
 /** Camera-specific parameter ID group. */
-#define MMAL_PARAMETER_GROUP_CAMERA            (1<<16)
+#define MMAL_PARAMETER_GROUP_CAMERA            (1 << 16)
 /** Video-specific parameter ID group. */
-#define MMAL_PARAMETER_GROUP_VIDEO             (2<<16)
+#define MMAL_PARAMETER_GROUP_VIDEO             (2 << 16)
 /** Audio-specific parameter ID group. */
-#define MMAL_PARAMETER_GROUP_AUDIO             (3<<16)
+#define MMAL_PARAMETER_GROUP_AUDIO             (3 << 16)
 /** Clock-specific parameter ID group. */
-#define MMAL_PARAMETER_GROUP_CLOCK             (4<<16)
+#define MMAL_PARAMETER_GROUP_CLOCK             (4 << 16)
 /** Miracast-specific parameter ID group. */
-#define MMAL_PARAMETER_GROUP_MIRACAST       (5<<16)
+#define MMAL_PARAMETER_GROUP_MIRACAST       (5 << 16)
 
 /* Common parameters */
 enum mmal_parameter_common_type {
-       MMAL_PARAMETER_UNUSED  /**< Never a valid parameter ID */
-               = MMAL_PARAMETER_GROUP_COMMON,
-       MMAL_PARAMETER_SUPPORTED_ENCODINGS, /**< MMAL_PARAMETER_ENCODING_T */
-       MMAL_PARAMETER_URI, /**< MMAL_PARAMETER_URI_T */
-
-       /** MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */
+               /**< Never a valid parameter ID */
+       MMAL_PARAMETER_UNUSED = MMAL_PARAMETER_GROUP_COMMON,
+
+               /**< MMAL_PARAMETER_ENCODING_T */
+       MMAL_PARAMETER_SUPPORTED_ENCODINGS,
+               /**< MMAL_PARAMETER_URI_T */
+       MMAL_PARAMETER_URI,
+               /** MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */
        MMAL_PARAMETER_CHANGE_EVENT_REQUEST,
-
-       /** MMAL_PARAMETER_BOOLEAN_T */
+               /** MMAL_PARAMETER_BOOLEAN_T */
        MMAL_PARAMETER_ZERO_COPY,
-
-       /**< MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */
+               /**< MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */
        MMAL_PARAMETER_BUFFER_REQUIREMENTS,
-
-       MMAL_PARAMETER_STATISTICS, /**< MMAL_PARAMETER_STATISTICS_T */
-       MMAL_PARAMETER_CORE_STATISTICS, /**< MMAL_PARAMETER_CORE_STATISTICS_T */
-       MMAL_PARAMETER_MEM_USAGE, /**< MMAL_PARAMETER_MEM_USAGE_T */
-       MMAL_PARAMETER_BUFFER_FLAG_FILTER, /**< MMAL_PARAMETER_UINT32_T */
-       MMAL_PARAMETER_SEEK, /**< MMAL_PARAMETER_SEEK_T */
-       MMAL_PARAMETER_POWERMON_ENABLE, /**< MMAL_PARAMETER_BOOLEAN_T */
-       MMAL_PARAMETER_LOGGING, /**< MMAL_PARAMETER_LOGGING_T */
-       MMAL_PARAMETER_SYSTEM_TIME, /**< MMAL_PARAMETER_UINT64_T */
-       MMAL_PARAMETER_NO_IMAGE_PADDING  /**< MMAL_PARAMETER_BOOLEAN_T */
+               /**< MMAL_PARAMETER_STATISTICS_T */
+       MMAL_PARAMETER_STATISTICS,
+               /**< MMAL_PARAMETER_CORE_STATISTICS_T */
+       MMAL_PARAMETER_CORE_STATISTICS,
+               /**< MMAL_PARAMETER_MEM_USAGE_T */
+       MMAL_PARAMETER_MEM_USAGE,
+               /**< MMAL_PARAMETER_UINT32_T */
+       MMAL_PARAMETER_BUFFER_FLAG_FILTER,
+               /**< MMAL_PARAMETER_SEEK_T */
+       MMAL_PARAMETER_SEEK,
+               /**< MMAL_PARAMETER_BOOLEAN_T */
+       MMAL_PARAMETER_POWERMON_ENABLE,
+               /**< MMAL_PARAMETER_LOGGING_T */
+       MMAL_PARAMETER_LOGGING,
+               /**< MMAL_PARAMETER_UINT64_T */
+       MMAL_PARAMETER_SYSTEM_TIME,
+               /**< MMAL_PARAMETER_BOOLEAN_T */
+       MMAL_PARAMETER_NO_IMAGE_PADDING,
 };
 
 /* camera parameters */
 
 enum mmal_parameter_camera_type {
        /* 0 */
-       /** @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */
-       MMAL_PARAMETER_THUMBNAIL_CONFIGURATION
-               = MMAL_PARAMETER_GROUP_CAMERA,
-       MMAL_PARAMETER_CAPTURE_QUALITY, /**< Unused? */
-       MMAL_PARAMETER_ROTATION, /**< @ref MMAL_PARAMETER_INT32_T */
-       MMAL_PARAMETER_EXIF_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-       MMAL_PARAMETER_EXIF, /**< @ref MMAL_PARAMETER_EXIF_T */
-       MMAL_PARAMETER_AWB_MODE, /**< @ref MMAL_PARAM_AWBMODE_T */
-       MMAL_PARAMETER_IMAGE_EFFECT, /**< @ref MMAL_PARAMETER_IMAGEFX_T */
-       MMAL_PARAMETER_COLOUR_EFFECT, /**< @ref MMAL_PARAMETER_COLOURFX_T */
-       MMAL_PARAMETER_FLICKER_AVOID, /**< @ref MMAL_PARAMETER_FLICKERAVOID_T */
-       MMAL_PARAMETER_FLASH, /**< @ref MMAL_PARAMETER_FLASH_T */
-       MMAL_PARAMETER_REDEYE, /**< @ref MMAL_PARAMETER_REDEYE_T */
-       MMAL_PARAMETER_FOCUS, /**< @ref MMAL_PARAMETER_FOCUS_T */
-       MMAL_PARAMETER_FOCAL_LENGTHS, /**< Unused? */
-       MMAL_PARAMETER_EXPOSURE_COMP, /**< @ref MMAL_PARAMETER_INT32_T */
-       MMAL_PARAMETER_ZOOM, /**< @ref MMAL_PARAMETER_SCALEFACTOR_T */
-       MMAL_PARAMETER_MIRROR, /**< @ref MMAL_PARAMETER_MIRROR_T */
+               /** @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */
+       MMAL_PARAMETER_THUMBNAIL_CONFIGURATION =
+               MMAL_PARAMETER_GROUP_CAMERA,
+               /**< Unused? */
+       MMAL_PARAMETER_CAPTURE_QUALITY,
+               /**< @ref MMAL_PARAMETER_INT32_T */
+       MMAL_PARAMETER_ROTATION,
+               /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+       MMAL_PARAMETER_EXIF_DISABLE,
+               /**< @ref MMAL_PARAMETER_EXIF_T */
+       MMAL_PARAMETER_EXIF,
+               /**< @ref MMAL_PARAM_AWBMODE_T */
+       MMAL_PARAMETER_AWB_MODE,
+               /**< @ref MMAL_PARAMETER_IMAGEFX_T */
+       MMAL_PARAMETER_IMAGE_EFFECT,
+               /**< @ref MMAL_PARAMETER_COLOURFX_T */
+       MMAL_PARAMETER_COLOUR_EFFECT,
+               /**< @ref MMAL_PARAMETER_FLICKERAVOID_T */
+       MMAL_PARAMETER_FLICKER_AVOID,
+               /**< @ref MMAL_PARAMETER_FLASH_T */
+       MMAL_PARAMETER_FLASH,
+               /**< @ref MMAL_PARAMETER_REDEYE_T */
+       MMAL_PARAMETER_REDEYE,
+               /**< @ref MMAL_PARAMETER_FOCUS_T */
+       MMAL_PARAMETER_FOCUS,
+               /**< Unused? */
+       MMAL_PARAMETER_FOCAL_LENGTHS,
+               /**< @ref MMAL_PARAMETER_INT32_T */
+       MMAL_PARAMETER_EXPOSURE_COMP,
+               /**< @ref MMAL_PARAMETER_SCALEFACTOR_T */
+       MMAL_PARAMETER_ZOOM,
+               /**< @ref MMAL_PARAMETER_MIRROR_T */
+       MMAL_PARAMETER_MIRROR,
 
        /* 0x10 */
-       MMAL_PARAMETER_CAMERA_NUM, /**< @ref MMAL_PARAMETER_UINT32_T */
-       MMAL_PARAMETER_CAPTURE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-       MMAL_PARAMETER_EXPOSURE_MODE, /**< @ref MMAL_PARAMETER_EXPOSUREMODE_T */
-       MMAL_PARAMETER_EXP_METERING_MODE, /**< @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */
-       MMAL_PARAMETER_FOCUS_STATUS, /**< @ref MMAL_PARAMETER_FOCUS_STATUS_T */
-       MMAL_PARAMETER_CAMERA_CONFIG, /**< @ref MMAL_PARAMETER_CAMERA_CONFIG_T */
-       MMAL_PARAMETER_CAPTURE_STATUS, /**< @ref MMAL_PARAMETER_CAPTURE_STATUS_T */
-       MMAL_PARAMETER_FACE_TRACK, /**< @ref MMAL_PARAMETER_FACE_TRACK_T */
-       MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-       MMAL_PARAMETER_JPEG_Q_FACTOR, /**< @ref MMAL_PARAMETER_UINT32_T */
-       MMAL_PARAMETER_FRAME_RATE, /**< @ref MMAL_PARAMETER_FRAME_RATE_T */
-       MMAL_PARAMETER_USE_STC, /**< @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */
-       MMAL_PARAMETER_CAMERA_INFO, /**< @ref MMAL_PARAMETER_CAMERA_INFO_T */
-       MMAL_PARAMETER_VIDEO_STABILISATION, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-       MMAL_PARAMETER_FACE_TRACK_RESULTS, /**< @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */
-       MMAL_PARAMETER_ENABLE_RAW_CAPTURE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+               /**< @ref MMAL_PARAMETER_UINT32_T */
+       MMAL_PARAMETER_CAMERA_NUM,
+               /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+       MMAL_PARAMETER_CAPTURE,
+               /**< @ref MMAL_PARAMETER_EXPOSUREMODE_T */
+       MMAL_PARAMETER_EXPOSURE_MODE,
+               /**< @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */
+       MMAL_PARAMETER_EXP_METERING_MODE,
+               /**< @ref MMAL_PARAMETER_FOCUS_STATUS_T */
+       MMAL_PARAMETER_FOCUS_STATUS,
+               /**< @ref MMAL_PARAMETER_CAMERA_CONFIG_T */
+       MMAL_PARAMETER_CAMERA_CONFIG,
+               /**< @ref MMAL_PARAMETER_CAPTURE_STATUS_T */
+       MMAL_PARAMETER_CAPTURE_STATUS,
+               /**< @ref MMAL_PARAMETER_FACE_TRACK_T */
+       MMAL_PARAMETER_FACE_TRACK,
+               /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+       MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS,
+               /**< @ref MMAL_PARAMETER_UINT32_T */
+       MMAL_PARAMETER_JPEG_Q_FACTOR,
+               /**< @ref MMAL_PARAMETER_FRAME_RATE_T */
+       MMAL_PARAMETER_FRAME_RATE,
+               /**< @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */
+       MMAL_PARAMETER_USE_STC,
+               /**< @ref MMAL_PARAMETER_CAMERA_INFO_T */
+       MMAL_PARAMETER_CAMERA_INFO,
+               /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+       MMAL_PARAMETER_VIDEO_STABILISATION,
+               /**< @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */
+       MMAL_PARAMETER_FACE_TRACK_RESULTS,
+               /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+       MMAL_PARAMETER_ENABLE_RAW_CAPTURE,
 
        /* 0x20 */
-       MMAL_PARAMETER_DPF_FILE, /**< @ref MMAL_PARAMETER_URI_T */
-       MMAL_PARAMETER_ENABLE_DPF_FILE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-       MMAL_PARAMETER_DPF_FAIL_IS_FATAL, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-       MMAL_PARAMETER_CAPTURE_MODE, /**< @ref MMAL_PARAMETER_CAPTUREMODE_T */
-       MMAL_PARAMETER_FOCUS_REGIONS, /**< @ref MMAL_PARAMETER_FOCUS_REGIONS_T */
-       MMAL_PARAMETER_INPUT_CROP, /**< @ref MMAL_PARAMETER_INPUT_CROP_T */
-       MMAL_PARAMETER_SENSOR_INFORMATION, /**< @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */
-       MMAL_PARAMETER_FLASH_SELECT, /**< @ref MMAL_PARAMETER_FLASH_SELECT_T */
-       MMAL_PARAMETER_FIELD_OF_VIEW, /**< @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */
-       MMAL_PARAMETER_HIGH_DYNAMIC_RANGE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-       MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION, /**< @ref MMAL_PARAMETER_DRC_T */
-       MMAL_PARAMETER_ALGORITHM_CONTROL, /**< @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */
-       MMAL_PARAMETER_SHARPNESS, /**< @ref MMAL_PARAMETER_RATIONAL_T */
-       MMAL_PARAMETER_CONTRAST, /**< @ref MMAL_PARAMETER_RATIONAL_T */
-       MMAL_PARAMETER_BRIGHTNESS, /**< @ref MMAL_PARAMETER_RATIONAL_T */
-       MMAL_PARAMETER_SATURATION, /**< @ref MMAL_PARAMETER_RATIONAL_T */
+               /**< @ref MMAL_PARAMETER_URI_T */
+       MMAL_PARAMETER_DPF_FILE,
+               /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+       MMAL_PARAMETER_ENABLE_DPF_FILE,
+               /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+       MMAL_PARAMETER_DPF_FAIL_IS_FATAL,
+               /**< @ref MMAL_PARAMETER_CAPTUREMODE_T */
+       MMAL_PARAMETER_CAPTURE_MODE,
+               /**< @ref MMAL_PARAMETER_FOCUS_REGIONS_T */
+       MMAL_PARAMETER_FOCUS_REGIONS,
+               /**< @ref MMAL_PARAMETER_INPUT_CROP_T */
+       MMAL_PARAMETER_INPUT_CROP,
+               /**< @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */
+       MMAL_PARAMETER_SENSOR_INFORMATION,
+               /**< @ref MMAL_PARAMETER_FLASH_SELECT_T */
+       MMAL_PARAMETER_FLASH_SELECT,
+               /**< @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */
+       MMAL_PARAMETER_FIELD_OF_VIEW,
+               /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+       MMAL_PARAMETER_HIGH_DYNAMIC_RANGE,
+               /**< @ref MMAL_PARAMETER_DRC_T */
+       MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION,
+               /**< @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */
+       MMAL_PARAMETER_ALGORITHM_CONTROL,
+               /**< @ref MMAL_PARAMETER_RATIONAL_T */
+       MMAL_PARAMETER_SHARPNESS,
+               /**< @ref MMAL_PARAMETER_RATIONAL_T */
+       MMAL_PARAMETER_CONTRAST,
+               /**< @ref MMAL_PARAMETER_RATIONAL_T */
+       MMAL_PARAMETER_BRIGHTNESS,
+               /**< @ref MMAL_PARAMETER_RATIONAL_T */
+       MMAL_PARAMETER_SATURATION,
 
        /* 0x30 */
-       MMAL_PARAMETER_ISO, /**< @ref MMAL_PARAMETER_UINT32_T */
-       MMAL_PARAMETER_ANTISHAKE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-
-       /** @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */
+               /**< @ref MMAL_PARAMETER_UINT32_T */
+       MMAL_PARAMETER_ISO,
+               /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+       MMAL_PARAMETER_ANTISHAKE,
+               /** @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */
        MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,
-
-       /** @ref MMAL_PARAMETER_BOOLEAN_T */
+               /** @ref MMAL_PARAMETER_BOOLEAN_T */
        MMAL_PARAMETER_CAMERA_BURST_CAPTURE,
-
-       /** @ref MMAL_PARAMETER_UINT32_T */
+               /** @ref MMAL_PARAMETER_UINT32_T */
        MMAL_PARAMETER_CAMERA_MIN_ISO,
-
-       /** @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */
+               /** @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */
        MMAL_PARAMETER_CAMERA_USE_CASE,
-
-       /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+               /**< @ref MMAL_PARAMETER_BOOLEAN_T */
        MMAL_PARAMETER_CAPTURE_STATS_PASS,
-
-       /** @ref MMAL_PARAMETER_UINT32_T */
+               /** @ref MMAL_PARAMETER_UINT32_T */
        MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG,
-
-       /** @ref MMAL_PARAMETER_BOOLEAN_T */
+               /** @ref MMAL_PARAMETER_BOOLEAN_T */
        MMAL_PARAMETER_ENABLE_REGISTER_FILE,
-
-       /** @ref MMAL_PARAMETER_BOOLEAN_T */
+               /** @ref MMAL_PARAMETER_BOOLEAN_T */
        MMAL_PARAMETER_REGISTER_FAIL_IS_FATAL,
-
-       /** @ref MMAL_PARAMETER_CONFIGFILE_T */
+               /** @ref MMAL_PARAMETER_CONFIGFILE_T */
        MMAL_PARAMETER_CONFIGFILE_REGISTERS,
-
-       /** @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */
+               /** @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */
        MMAL_PARAMETER_CONFIGFILE_CHUNK_REGISTERS,
-       MMAL_PARAMETER_JPEG_ATTACH_LOG, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-       MMAL_PARAMETER_ZERO_SHUTTER_LAG, /**< @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */
-       MMAL_PARAMETER_FPS_RANGE, /**< @ref MMAL_PARAMETER_FPS_RANGE_T */
-       MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP, /**< @ref MMAL_PARAMETER_INT32_T */
+               /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+       MMAL_PARAMETER_JPEG_ATTACH_LOG,
+               /**< @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */
+       MMAL_PARAMETER_ZERO_SHUTTER_LAG,
+               /**< @ref MMAL_PARAMETER_FPS_RANGE_T */
+       MMAL_PARAMETER_FPS_RANGE,
+               /**< @ref MMAL_PARAMETER_INT32_T */
+       MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP,
 
        /* 0x40 */
-       MMAL_PARAMETER_SW_SHARPEN_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-       MMAL_PARAMETER_FLASH_REQUIRED, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-       MMAL_PARAMETER_SW_SATURATION_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-       MMAL_PARAMETER_SHUTTER_SPEED,             /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
-       MMAL_PARAMETER_CUSTOM_AWB_GAINS,          /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */
+               /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+       MMAL_PARAMETER_SW_SHARPEN_DISABLE,
+               /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+       MMAL_PARAMETER_FLASH_REQUIRED,
+               /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+       MMAL_PARAMETER_SW_SATURATION_DISABLE,
+               /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
+       MMAL_PARAMETER_SHUTTER_SPEED,
+               /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */
+       MMAL_PARAMETER_CUSTOM_AWB_GAINS,
 };
 
 struct mmal_parameter_rational {
@@ -410,7 +467,8 @@ enum mmal_parameter_video_type {
        MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
 
        /** @ref MMAL_PARAMETER_UINT32_T.
-        * Setting the value to zero resets to the default (one slice per frame).
+        * Setting the value to zero resets to the default (one slice per
+        * frame).
         */
        MMAL_PARAMETER_MB_ROWS_PER_SLICE,
 
index 16af735..1c180ea 100644 (file)
@@ -4,10 +4,11 @@
  *
  * Copyright © 2013 Raspberry Pi (Trading) Ltd.
  *
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- *          Dave Stevenson <dsteve@broadcom.com>
- *          Simon Mellor <simellor@broadcom.com>
- *          Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ *          Dave Stevenson @ Broadcom
+ *             (now dave.stevenson@raspberrypi.org)
+ *          Simon Mellor @ Broadcom
+ *          Luke Diamand @ Broadcom
  *
  * V4L2 driver MMAL vchiq interface code
  */
@@ -117,8 +118,10 @@ struct mmal_msg_context {
 
        union {
                struct {
-                       /* work struct for defered callback - must come first */
+                       /* work struct for buffer_cb callback */
                        struct work_struct work;
+                       /* work struct for deferred callback */
+                       struct work_struct buffer_to_host_work;
                        /* mmal instance */
                        struct vchiq_mmal_instance *instance;
                        /* mmal port */
@@ -161,11 +164,15 @@ struct vchiq_mmal_instance {
        void *bulk_scratch;
 
        struct idr context_map;
-       spinlock_t context_map_lock;
+       /* protect accesses to context_map */
+       struct mutex context_map_lock;
 
        /* component to use next */
        int component_idx;
        struct vchiq_mmal_component component[VCHIQ_MMAL_MAX_COMPONENTS];
+
+       /* ordered workqueue to process all bulk operations */
+       struct workqueue_struct *bulk_wq;
 };
 
 static struct mmal_msg_context *
@@ -184,10 +191,10 @@ get_msg_context(struct vchiq_mmal_instance *instance)
         * that when we service the VCHI reply, we can look up what
         * message is being replied to.
         */
-       spin_lock(&instance->context_map_lock);
+       mutex_lock(&instance->context_map_lock);
        handle = idr_alloc(&instance->context_map, msg_context,
                           0, 0, GFP_KERNEL);
-       spin_unlock(&instance->context_map_lock);
+       mutex_unlock(&instance->context_map_lock);
 
        if (handle < 0) {
                kfree(msg_context);
@@ -211,9 +218,9 @@ release_msg_context(struct mmal_msg_context *msg_context)
 {
        struct vchiq_mmal_instance *instance = msg_context->instance;
 
-       spin_lock(&instance->context_map_lock);
+       mutex_lock(&instance->context_map_lock);
        idr_remove(&instance->context_map, msg_context->handle);
-       spin_unlock(&instance->context_map_lock);
+       mutex_unlock(&instance->context_map_lock);
        kfree(msg_context);
 }
 
@@ -239,6 +246,8 @@ static void buffer_work_cb(struct work_struct *work)
        struct mmal_msg_context *msg_context =
                container_of(work, struct mmal_msg_context, u.bulk.work);
 
+       atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu);
+
        msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance,
                                            msg_context->u.bulk.port,
                                            msg_context->u.bulk.status,
@@ -247,7 +256,44 @@ static void buffer_work_cb(struct work_struct *work)
                                            msg_context->u.bulk.mmal_flags,
                                            msg_context->u.bulk.dts,
                                            msg_context->u.bulk.pts);
+}
+
+/* workqueue scheduled callback to handle receiving buffers
+ *
+ * VCHI will allow up to 4 bulk receives to be scheduled before blocking.
+ * If we block in the service_callback context then we can't process the
+ * VCHI_CALLBACK_BULK_RECEIVED message that would otherwise allow the blocked
+ * vchi_bulk_queue_receive() call to complete.
+ */
+static void buffer_to_host_work_cb(struct work_struct *work)
+{
+       struct mmal_msg_context *msg_context =
+               container_of(work, struct mmal_msg_context,
+                            u.bulk.buffer_to_host_work);
+       struct vchiq_mmal_instance *instance = msg_context->instance;
+       unsigned long len = msg_context->u.bulk.buffer_used;
+       int ret;
 
+       if (!len)
+               /* Dummy receive to ensure the buffers remain in order */
+               len = 8;
+       /* queue the bulk submission */
+       vchi_service_use(instance->handle);
+       ret = vchi_bulk_queue_receive(instance->handle,
+                                     msg_context->u.bulk.buffer->buffer,
+                                     /* Actual receive needs to be a multiple
+                                      * of 4 bytes
+                                      */
+                                     (len + 3) & ~3,
+                                     VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
+                                     VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
+                                     msg_context);
+
+       vchi_service_release(instance->handle);
+
+       if (ret != 0)
+               pr_err("%s: ctx: %p, vchi_bulk_queue_receive failed %d\n",
+                      __func__, msg_context, ret);
 }
 
 /* enqueue a bulk receive for a given message context */
@@ -256,7 +302,6 @@ static int bulk_receive(struct vchiq_mmal_instance *instance,
                        struct mmal_msg_context *msg_context)
 {
        unsigned long rd_len;
-       int ret;
 
        rd_len = msg->u.buffer_from_host.buffer_header.length;
 
@@ -287,50 +332,13 @@ static int bulk_receive(struct vchiq_mmal_instance *instance,
 
        /* store length */
        msg_context->u.bulk.buffer_used = rd_len;
-       msg_context->u.bulk.mmal_flags =
-           msg->u.buffer_from_host.buffer_header.flags;
        msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts;
        msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts;
 
-       /* queue the bulk submission */
-       vchi_service_use(instance->handle);
-       ret = vchi_bulk_queue_receive(instance->handle,
-                                     msg_context->u.bulk.buffer->buffer,
-                                     /* Actual receive needs to be a multiple
-                                      * of 4 bytes
-                                      */
-                                     (rd_len + 3) & ~3,
-                                     VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
-                                     VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
-                                     msg_context);
-
-       vchi_service_release(instance->handle);
-
-       return ret;
-}
-
-/* enque a dummy bulk receive for a given message context */
-static int dummy_bulk_receive(struct vchiq_mmal_instance *instance,
-                             struct mmal_msg_context *msg_context)
-{
-       int ret;
-
-       /* zero length indicates this was a dummy transfer */
-       msg_context->u.bulk.buffer_used = 0;
-
-       /* queue the bulk submission */
-       vchi_service_use(instance->handle);
-
-       ret = vchi_bulk_queue_receive(instance->handle,
-                                     instance->bulk_scratch,
-                                     8,
-                                     VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
-                                     VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
-                                     msg_context);
+       queue_work(msg_context->instance->bulk_wq,
+                  &msg_context->u.bulk.buffer_to_host_work);
 
-       vchi_service_release(instance->handle);
-
-       return ret;
+       return 0;
 }
 
 /* data in message, memcpy from packet into output buffer */
@@ -378,6 +386,10 @@ buffer_from_host(struct vchiq_mmal_instance *instance,
 
        /* initialise work structure ready to schedule callback */
        INIT_WORK(&msg_context->u.bulk.work, buffer_work_cb);
+       INIT_WORK(&msg_context->u.bulk.buffer_to_host_work,
+                 buffer_to_host_work_cb);
+
+       atomic_inc(&port->buffers_with_vpu);
 
        /* prep the buffer from host message */
        memset(&m, 0xbc, sizeof(m));    /* just to make debug clearer */
@@ -447,6 +459,9 @@ static void buffer_to_host_cb(struct vchiq_mmal_instance *instance,
                return;
        }
 
+       msg_context->u.bulk.mmal_flags =
+                               msg->u.buffer_from_host.buffer_header.flags;
+
        if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) {
                /* message reception had an error */
                pr_warn("error %d in reply\n", msg->h.status);
@@ -458,7 +473,7 @@ static void buffer_to_host_cb(struct vchiq_mmal_instance *instance,
                if (msg->u.buffer_from_host.buffer_header.flags &
                    MMAL_BUFFER_HEADER_FLAG_EOS) {
                        msg_context->u.bulk.status =
-                           dummy_bulk_receive(instance, msg_context);
+                           bulk_receive(instance, msg, msg_context);
                        if (msg_context->u.bulk.status == 0)
                                return; /* successful bulk submission, bulk
                                         * completion will trigger callback
@@ -635,7 +650,7 @@ static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance,
        if (payload_len >
            (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header))) {
                pr_err("payload length %d exceeds max:%d\n", payload_len,
-                     (int)(MMAL_MSG_MAX_SIZE -
+                      (int)(MMAL_MSG_MAX_SIZE -
                            sizeof(struct mmal_msg_header)));
                return -EINVAL;
        }
@@ -838,9 +853,9 @@ static int port_info_get(struct vchiq_mmal_instance *instance,
                goto release_msg;
 
        if (rmsg->u.port_info_get_reply.port.is_enabled == 0)
-               port->enabled = false;
+               port->enabled = 0;
        else
-               port->enabled = true;
+               port->enabled = 1;
 
        /* copy the values out of the message */
        port->handle = rmsg->u.port_info_get_reply.port_handle;
@@ -1252,9 +1267,10 @@ static int port_parameter_get(struct vchiq_mmal_instance *instance,
                memcpy(value, &rmsg->u.port_parameter_get_reply.value,
                       *value_size);
                *value_size = rmsg->u.port_parameter_get_reply.size;
-       } else
+       } else {
                memcpy(value, &rmsg->u.port_parameter_get_reply.value,
                       rmsg->u.port_parameter_get_reply.size);
+       }
 
        pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__,
                 ret, port->component->handle, port->handle, parameter_id);
@@ -1276,7 +1292,7 @@ static int port_disable(struct vchiq_mmal_instance *instance,
        if (!port->enabled)
                return 0;
 
-       port->enabled = false;
+       port->enabled = 0;
 
        ret = port_action_port(instance, port,
                               MMAL_MSG_PORT_ACTION_TYPE_DISABLE);
@@ -1323,22 +1339,12 @@ static int port_enable(struct vchiq_mmal_instance *instance,
        if (port->enabled)
                return 0;
 
-       /* ensure there are enough buffers queued to cover the buffer headers */
-       if (port->buffer_cb) {
-               hdr_count = 0;
-               list_for_each(buf_head, &port->buffers) {
-                       hdr_count++;
-               }
-               if (hdr_count < port->current_buffer.num)
-                       return -ENOSPC;
-       }
-
        ret = port_action_port(instance, port,
                               MMAL_MSG_PORT_ACTION_TYPE_ENABLE);
        if (ret)
                goto done;
 
-       port->enabled = true;
+       port->enabled = 1;
 
        if (port->buffer_cb) {
                /* send buffer headers to videocore */
@@ -1505,7 +1511,7 @@ int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
                        pr_err("failed disconnecting src port\n");
                        goto release_unlock;
                }
-               src->connected->enabled = false;
+               src->connected->enabled = 0;
                src->connected = NULL;
        }
 
@@ -1752,7 +1758,7 @@ int vchiq_mmal_component_disable(struct vchiq_mmal_instance *instance,
 
        ret = disable_component(instance, component);
        if (ret == 0)
-               component->enabled = false;
+               component->enabled = 0;
 
        mutex_unlock(&instance->vchiq_mutex);
 
@@ -1792,6 +1798,9 @@ int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance)
 
        mutex_unlock(&instance->vchiq_mutex);
 
+       flush_workqueue(instance->bulk_wq);
+       destroy_workqueue(instance->bulk_wq);
+
        vfree(instance->bulk_scratch);
 
        idr_destroy(&instance->context_map);
@@ -1849,11 +1858,16 @@ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
 
        instance->bulk_scratch = vmalloc(PAGE_SIZE);
 
-       spin_lock_init(&instance->context_map_lock);
+       mutex_init(&instance->context_map_lock);
        idr_init_base(&instance->context_map, 1);
 
        params.callback_param = instance;
 
+       instance->bulk_wq = alloc_ordered_workqueue("mmal-vchiq",
+                                                   WQ_MEM_RECLAIM);
+       if (!instance->bulk_wq)
+               goto err_free;
+
        status = vchi_service_open(vchi_instance, &params, &instance->handle);
        if (status) {
                pr_err("Failed to open VCHI service connection (status=%d)\n",
@@ -1868,8 +1882,9 @@ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
        return 0;
 
 err_close_services:
-
        vchi_service_close(instance->handle);
+       destroy_workqueue(instance->bulk_wq);
+err_free:
        vfree(instance->bulk_scratch);
        kfree(instance);
        return -ENODEV;
index 22b839e..f738e7f 100644 (file)
@@ -4,10 +4,11 @@
  *
  * Copyright © 2013 Raspberry Pi (Trading) Ltd.
  *
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- *          Dave Stevenson <dsteve@broadcom.com>
- *          Simon Mellor <simellor@broadcom.com>
- *          Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ *          Dave Stevenson @ Broadcom
+ *             (now dave.stevenson@raspberrypi.org)
+ *          Simon Mellor @ Broadcom
+ *          Luke Diamand @ Broadcom
  *
  * MMAL interface to VCHIQ message passing
  */
@@ -47,7 +48,7 @@ typedef void (*vchiq_mmal_buffer_cb)(
                unsigned long length, u32 mmal_flags, s64 dts, s64 pts);
 
 struct vchiq_mmal_port {
-       bool enabled;
+       u32 enabled:1;
        u32 handle;
        u32 type; /* port type, cached to use on port info set */
        u32 index; /* port index, cached to use on port info set */
@@ -71,6 +72,9 @@ struct vchiq_mmal_port {
        struct list_head buffers;
        /* lock to serialise adding and removing buffers from list */
        spinlock_t slock;
+
+       /* Count of buffers the VPU has yet to return */
+       atomic_t buffers_with_vpu;
        /* callback on buffer completion */
        vchiq_mmal_buffer_cb buffer_cb;
        /* callback context */
@@ -78,7 +82,7 @@ struct vchiq_mmal_port {
 };
 
 struct vchiq_mmal_component {
-       bool enabled;
+       u32 enabled:1;
        u32 handle;  /* VideoCore handle for component */
        u32 inputs;  /* Number of input ports */
        u32 outputs; /* Number of output ports */
@@ -127,7 +131,7 @@ int vchiq_mmal_port_enable(
  * disable a port will dequeue any pending buffers
  */
 int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
-                          struct vchiq_mmal_port *port);
+                           struct vchiq_mmal_port *port);
 
 int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
                                  struct vchiq_mmal_port *port,
@@ -145,8 +149,8 @@ int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance,
                               struct vchiq_mmal_port *port);
 
 int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
-                           struct vchiq_mmal_port *src,
-                           struct vchiq_mmal_port *dst);
+                                  struct vchiq_mmal_port *src,
+                                  struct vchiq_mmal_port *dst);
 
 int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
                       u32 *major_out,
index c557c99..61c69f3 100644 (file)
@@ -523,7 +523,7 @@ create_pagelist(char __user *buf, size_t count, unsigned short type)
                (g_cache_line_size - 1)))) {
                char *fragments;
 
-               if (down_killable(&g_free_fragments_sema)) {
+               if (down_interruptible(&g_free_fragments_sema)) {
                        cleanup_pagelistinfo(pagelistinfo);
                        return NULL;
                }
index ab7d6a0..cc4383d 100644 (file)
@@ -238,7 +238,7 @@ VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance)
        vchiq_log_trace(vchiq_core_log_level,
                "%s(%p) called", __func__, instance);
 
-       if (mutex_lock_killable(&state->mutex) != 0)
+       if (mutex_lock_killable(&state->mutex))
                return VCHIQ_RETRY;
 
        /* Remove all services */
@@ -280,7 +280,7 @@ VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance)
        vchiq_log_trace(vchiq_core_log_level,
                "%s(%p) called", __func__, instance);
 
-       if (mutex_lock_killable(&state->mutex) != 0) {
+       if (mutex_lock_killable(&state->mutex)) {
                vchiq_log_trace(vchiq_core_log_level,
                        "%s: call to mutex_lock failed", __func__);
                status = VCHIQ_RETRY;
@@ -532,7 +532,8 @@ add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason,
                vchiq_log_trace(vchiq_arm_log_level,
                        "%s - completion queue full", __func__);
                DEBUG_COUNT(COMPLETION_QUEUE_FULL_COUNT);
-               if (wait_for_completion_killable(&instance->remove_event)) {
+               if (wait_for_completion_interruptible(
+                                       &instance->remove_event)) {
                        vchiq_log_info(vchiq_arm_log_level,
                                "service_callback interrupted");
                        return VCHIQ_RETRY;
@@ -643,9 +644,8 @@ service_callback(VCHIQ_REASON_T reason, struct vchiq_header *header,
                        }
 
                        DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-                       if (wait_for_completion_killable(
-                                               &user_service->remove_event)
-                               != 0) {
+                       if (wait_for_completion_interruptible(
+                                               &user_service->remove_event)) {
                                vchiq_log_info(vchiq_arm_log_level,
                                        "%s interrupted", __func__);
                                DEBUG_TRACE(SERVICE_CALLBACK_LINE);
@@ -849,7 +849,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        break;
                }
                rc = mutex_lock_killable(&instance->state->mutex);
-               if (rc != 0) {
+               if (rc) {
                        vchiq_log_error(vchiq_arm_log_level,
                                "vchiq: connect: could not lock mutex for "
                                "state %d: %d",
@@ -873,9 +873,8 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                void *userdata;
                int srvstate;
 
-               if (copy_from_user
-                        (&args, (const void __user *)arg,
-                         sizeof(args)) != 0) {
+               if (copy_from_user(&args, (const void __user *)arg,
+                                  sizeof(args))) {
                        ret = -EFAULT;
                        break;
                }
@@ -939,7 +938,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                &(((struct vchiq_create_service __user *)
                                        arg)->handle),
                                (const void *)&service->handle,
-                               sizeof(service->handle)) != 0) {
+                               sizeof(service->handle))) {
                                ret = -EFAULT;
                                vchiq_remove_service(service->handle);
                        }
@@ -978,7 +977,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                   has been closed until the client library calls the
                   CLOSE_DELIVERED ioctl, signalling close_event. */
                if (user_service->close_pending &&
-                       wait_for_completion_killable(
+                       wait_for_completion_interruptible(
                                &user_service->close_event))
                        status = VCHIQ_RETRY;
                break;
@@ -1014,9 +1013,8 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case VCHIQ_IOC_QUEUE_MESSAGE: {
                struct vchiq_queue_message args;
 
-               if (copy_from_user
-                        (&args, (const void __user *)arg,
-                         sizeof(args)) != 0) {
+               if (copy_from_user(&args, (const void __user *)arg,
+                                  sizeof(args))) {
                        ret = -EFAULT;
                        break;
                }
@@ -1048,9 +1046,8 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        (cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT) ?
                        VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
 
-               if (copy_from_user
-                       (&args, (const void __user *)arg,
-                       sizeof(args)) != 0) {
+               if (copy_from_user(&args, (const void __user *)arg,
+                                  sizeof(args))) {
                        ret = -EFAULT;
                        break;
                }
@@ -1124,7 +1121,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                &(((struct vchiq_queue_bulk_transfer __user *)
                                        arg)->mode),
                                (const void *)&mode_waiting,
-                               sizeof(mode_waiting)) != 0)
+                               sizeof(mode_waiting)))
                                ret = -EFAULT;
                }
        } break;
@@ -1139,7 +1136,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                }
 
                if (copy_from_user(&args, (const void __user *)arg,
-                       sizeof(args)) != 0) {
+                       sizeof(args))) {
                        ret = -EFAULT;
                        break;
                }
@@ -1154,10 +1151,10 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
                        DEBUG_TRACE(AWAIT_COMPLETION_LINE);
                        mutex_unlock(&instance->completion_mutex);
-                       rc = wait_for_completion_killable(
+                       rc = wait_for_completion_interruptible(
                                                &instance->insert_event);
                        mutex_lock(&instance->completion_mutex);
-                       if (rc != 0) {
+                       if (rc) {
                                DEBUG_TRACE(AWAIT_COMPLETION_LINE);
                                vchiq_log_info(vchiq_arm_log_level,
                                        "AWAIT_COMPLETION interrupted");
@@ -1223,7 +1220,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                        if (copy_from_user(&msgbuf,
                                                (const void __user *)
                                                &args.msgbufs[msgbufcount],
-                                               sizeof(msgbuf)) != 0) {
+                                               sizeof(msgbuf))) {
                                                if (ret == 0)
                                                        ret = -EFAULT;
                                                break;
@@ -1231,7 +1228,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
                                        /* Copy the message to user space */
                                        if (copy_to_user(msgbuf, header,
-                                               msglen) != 0) {
+                                               msglen)) {
                                                if (ret == 0)
                                                        ret = -EFAULT;
                                                break;
@@ -1256,8 +1253,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                        (size_t)args.buf + ret *
                                        sizeof(struct vchiq_completion_data)),
                                        completion,
-                                       sizeof(struct vchiq_completion_data))
-                                                                       != 0) {
+                                       sizeof(struct vchiq_completion_data))) {
                                                if (ret == 0)
                                                        ret = -EFAULT;
                                        break;
@@ -1277,13 +1273,13 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                        &((struct vchiq_await_completion *)arg)
                                                ->msgbufcount,
                                        &msgbufcount,
-                                       sizeof(msgbufcount)) != 0) {
+                                       sizeof(msgbufcount))) {
                                        ret = -EFAULT;
                                }
                        }
                }
 
-               if (ret != 0)
+               if (ret)
                        complete(&instance->remove_event);
                mutex_unlock(&instance->completion_mutex);
                DEBUG_TRACE(AWAIT_COMPLETION_LINE);
@@ -1295,9 +1291,8 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                struct vchiq_header *header;
 
                DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
-               if (copy_from_user
-                        (&args, (const void __user *)arg,
-                         sizeof(args)) != 0) {
+               if (copy_from_user(&args, (const void __user *)arg,
+                                  sizeof(args))) {
                        ret = -EFAULT;
                        break;
                }
@@ -1324,7 +1319,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        do {
                                spin_unlock(&msg_queue_spinlock);
                                DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
-                               if (wait_for_completion_killable(
+                               if (wait_for_completion_interruptible(
                                        &user_service->insert_event)) {
                                        vchiq_log_info(vchiq_arm_log_level,
                                                "DEQUEUE_MESSAGE interrupted");
@@ -1383,7 +1378,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                struct vchiq_config config;
 
                if (copy_from_user(&args, (const void __user *)arg,
-                       sizeof(args)) != 0) {
+                                  sizeof(args))) {
                        ret = -EFAULT;
                        break;
                }
@@ -1402,9 +1397,8 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case VCHIQ_IOC_SET_SERVICE_OPTION: {
                struct vchiq_set_service_option args;
 
-               if (copy_from_user(
-                       &args, (const void __user *)arg,
-                       sizeof(args)) != 0) {
+               if (copy_from_user(&args, (const void __user *)arg,
+                                  sizeof(args))) {
                        ret = -EFAULT;
                        break;
                }
@@ -2328,8 +2322,7 @@ vchiq_keepalive_thread_func(void *v)
        while (1) {
                long rc = 0, uc = 0;
 
-               if (wait_for_completion_killable(&arm_state->ka_evt)
-                               != 0) {
+               if (wait_for_completion_interruptible(&arm_state->ka_evt)) {
                        vchiq_log_error(vchiq_susp_log_level,
                                "%s interrupted", __func__);
                        flush_signals(current);
@@ -2561,72 +2554,6 @@ need_resume(struct vchiq_state *state)
                        vchiq_videocore_wanted(state);
 }
 
-static int
-block_resume(struct vchiq_arm_state *arm_state)
-{
-       int status = VCHIQ_SUCCESS;
-       const unsigned long timeout_val =
-                               msecs_to_jiffies(FORCE_SUSPEND_TIMEOUT_MS);
-       int resume_count = 0;
-
-       /* Allow any threads which were blocked by the last force suspend to
-        * complete if they haven't already.  Only give this one shot; if
-        * blocked_count is incremented after blocked_blocker is completed
-        * (which only happens when blocked_count hits 0) then those threads
-        * will have to wait until next time around */
-       if (arm_state->blocked_count) {
-               reinit_completion(&arm_state->blocked_blocker);
-               write_unlock_bh(&arm_state->susp_res_lock);
-               vchiq_log_info(vchiq_susp_log_level, "%s wait for previously "
-                       "blocked clients", __func__);
-               if (wait_for_completion_killable_timeout(
-                               &arm_state->blocked_blocker, timeout_val)
-                                       <= 0) {
-                       vchiq_log_error(vchiq_susp_log_level, "%s wait for "
-                               "previously blocked clients failed", __func__);
-                       status = VCHIQ_ERROR;
-                       write_lock_bh(&arm_state->susp_res_lock);
-                       goto out;
-               }
-               vchiq_log_info(vchiq_susp_log_level, "%s previously blocked "
-                       "clients resumed", __func__);
-               write_lock_bh(&arm_state->susp_res_lock);
-       }
-
-       /* We need to wait for resume to complete if it's in process */
-       while (arm_state->vc_resume_state != VC_RESUME_RESUMED &&
-                       arm_state->vc_resume_state > VC_RESUME_IDLE) {
-               if (resume_count > 1) {
-                       status = VCHIQ_ERROR;
-                       vchiq_log_error(vchiq_susp_log_level, "%s waited too "
-                               "many times for resume", __func__);
-                       goto out;
-               }
-               write_unlock_bh(&arm_state->susp_res_lock);
-               vchiq_log_info(vchiq_susp_log_level, "%s wait for resume",
-                       __func__);
-               if (wait_for_completion_killable_timeout(
-                               &arm_state->vc_resume_complete, timeout_val)
-                                       <= 0) {
-                       vchiq_log_error(vchiq_susp_log_level, "%s wait for "
-                               "resume failed (%s)", __func__,
-                               resume_state_names[arm_state->vc_resume_state +
-                                                       VC_RESUME_NUM_OFFSET]);
-                       status = VCHIQ_ERROR;
-                       write_lock_bh(&arm_state->susp_res_lock);
-                       goto out;
-               }
-               vchiq_log_info(vchiq_susp_log_level, "%s resumed", __func__);
-               write_lock_bh(&arm_state->susp_res_lock);
-               resume_count++;
-       }
-       reinit_completion(&arm_state->resume_blocker);
-       arm_state->resume_blocked = 1;
-
-out:
-       return status;
-}
-
 static inline void
 unblock_resume(struct vchiq_arm_state *arm_state)
 {
@@ -2712,162 +2639,6 @@ out:
        return;
 }
 
-static void
-output_timeout_error(struct vchiq_state *state)
-{
-       struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state);
-       char err[50] = "";
-       int vc_use_count = arm_state->videocore_use_count;
-       int active_services = state->unused_service;
-       int i;
-
-       if (!arm_state->videocore_use_count) {
-               snprintf(err, sizeof(err), " Videocore usecount is 0");
-               goto output_msg;
-       }
-       for (i = 0; i < active_services; i++) {
-               struct vchiq_service *service_ptr = state->services[i];
-
-               if (service_ptr && service_ptr->service_use_count &&
-                       (service_ptr->srvstate != VCHIQ_SRVSTATE_FREE)) {
-                       snprintf(err, sizeof(err), " %c%c%c%c(%d) service has "
-                               "use count %d%s", VCHIQ_FOURCC_AS_4CHARS(
-                                       service_ptr->base.fourcc),
-                                service_ptr->client_id,
-                                service_ptr->service_use_count,
-                                service_ptr->service_use_count ==
-                                        vc_use_count ? "" : " (+ more)");
-                       break;
-               }
-       }
-
-output_msg:
-       vchiq_log_error(vchiq_susp_log_level,
-               "timed out waiting for vc suspend (%d).%s",
-                arm_state->autosuspend_override, err);
-
-}
-
-/* Try to get videocore into suspended state, regardless of autosuspend state.
-** We don't actually force suspend, since videocore may get into a bad state
-** if we force suspend at a bad time.  Instead, we wait for autosuspend to
-** determine a good point to suspend.  If this doesn't happen within 100ms we
-** report failure.
-**
-** Returns VCHIQ_SUCCESS if videocore suspended successfully, VCHIQ_RETRY if
-** videocore failed to suspend in time or VCHIQ_ERROR if interrupted.
-*/
-VCHIQ_STATUS_T
-vchiq_arm_force_suspend(struct vchiq_state *state)
-{
-       struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state);
-       VCHIQ_STATUS_T status = VCHIQ_ERROR;
-       long rc = 0;
-       int repeat = -1;
-
-       if (!arm_state)
-               goto out;
-
-       vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-
-       write_lock_bh(&arm_state->susp_res_lock);
-
-       status = block_resume(arm_state);
-       if (status != VCHIQ_SUCCESS)
-               goto unlock;
-       if (arm_state->vc_suspend_state == VC_SUSPEND_SUSPENDED) {
-               /* Already suspended - just block resume and exit */
-               vchiq_log_info(vchiq_susp_log_level, "%s already suspended",
-                       __func__);
-               status = VCHIQ_SUCCESS;
-               goto unlock;
-       } else if (arm_state->vc_suspend_state <= VC_SUSPEND_IDLE) {
-               /* initiate suspend immediately in the case that we're waiting
-                * for the timeout */
-               stop_suspend_timer(arm_state);
-               if (!vchiq_videocore_wanted(state)) {
-                       vchiq_log_info(vchiq_susp_log_level, "%s videocore "
-                               "idle, initiating suspend", __func__);
-                       status = vchiq_arm_vcsuspend(state);
-               } else if (arm_state->autosuspend_override <
-                                               FORCE_SUSPEND_FAIL_MAX) {
-                       vchiq_log_info(vchiq_susp_log_level, "%s letting "
-                               "videocore go idle", __func__);
-                       status = VCHIQ_SUCCESS;
-               } else {
-                       vchiq_log_warning(vchiq_susp_log_level, "%s failed too "
-                               "many times - attempting suspend", __func__);
-                       status = vchiq_arm_vcsuspend(state);
-               }
-       } else {
-               vchiq_log_info(vchiq_susp_log_level, "%s videocore suspend "
-                       "in progress - wait for completion", __func__);
-               status = VCHIQ_SUCCESS;
-       }
-
-       /* Wait for suspend to happen due to system idle (not forced..) */
-       if (status != VCHIQ_SUCCESS)
-               goto unblock_resume;
-
-       do {
-               write_unlock_bh(&arm_state->susp_res_lock);
-
-               rc = wait_for_completion_killable_timeout(
-                               &arm_state->vc_suspend_complete,
-                               msecs_to_jiffies(FORCE_SUSPEND_TIMEOUT_MS));
-
-               write_lock_bh(&arm_state->susp_res_lock);
-               if (rc < 0) {
-                       vchiq_log_warning(vchiq_susp_log_level, "%s "
-                               "interrupted waiting for suspend", __func__);
-                       status = VCHIQ_ERROR;
-                       goto unblock_resume;
-               } else if (rc == 0) {
-                       if (arm_state->vc_suspend_state > VC_SUSPEND_IDLE) {
-                               /* Repeat timeout once if in progress */
-                               if (repeat < 0) {
-                                       repeat = 1;
-                                       continue;
-                               }
-                       }
-                       arm_state->autosuspend_override++;
-                       output_timeout_error(state);
-
-                       status = VCHIQ_RETRY;
-                       goto unblock_resume;
-               }
-       } while (0 < (repeat--));
-
-       /* Check and report state in case we need to abort ARM suspend */
-       if (arm_state->vc_suspend_state != VC_SUSPEND_SUSPENDED) {
-               status = VCHIQ_RETRY;
-               vchiq_log_error(vchiq_susp_log_level,
-                       "%s videocore suspend failed (state %s)", __func__,
-                       suspend_state_names[arm_state->vc_suspend_state +
-                                               VC_SUSPEND_NUM_OFFSET]);
-               /* Reset the state only if it's still in an error state.
-                * Something could have already initiated another suspend. */
-               if (arm_state->vc_suspend_state < VC_SUSPEND_IDLE)
-                       set_suspend_state(arm_state, VC_SUSPEND_IDLE);
-
-               goto unblock_resume;
-       }
-
-       /* successfully suspended - unlock and exit */
-       goto unlock;
-
-unblock_resume:
-       /* all error states need to unblock resume before exit */
-       unblock_resume(arm_state);
-
-unlock:
-       write_unlock_bh(&arm_state->susp_res_lock);
-
-out:
-       vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, status);
-       return status;
-}
-
 void
 vchiq_check_suspend(struct vchiq_state *state)
 {
@@ -2890,49 +2661,6 @@ out:
        vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__);
 }
 
-int
-vchiq_arm_allow_resume(struct vchiq_state *state)
-{
-       struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state);
-       int resume = 0;
-       int ret = -1;
-
-       if (!arm_state)
-               goto out;
-
-       vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-
-       write_lock_bh(&arm_state->susp_res_lock);
-       unblock_resume(arm_state);
-       resume = vchiq_check_resume(state);
-       write_unlock_bh(&arm_state->susp_res_lock);
-
-       if (resume) {
-               if (wait_for_completion_killable(
-                       &arm_state->vc_resume_complete) < 0) {
-                       vchiq_log_error(vchiq_susp_log_level,
-                               "%s interrupted", __func__);
-                       /* failed, cannot accurately derive suspend
-                        * state, so exit early. */
-                       goto out;
-               }
-       }
-
-       read_lock_bh(&arm_state->susp_res_lock);
-       if (arm_state->vc_suspend_state == VC_SUSPEND_SUSPENDED) {
-               vchiq_log_info(vchiq_susp_log_level,
-                               "%s: Videocore remains suspended", __func__);
-       } else {
-               vchiq_log_info(vchiq_susp_log_level,
-                               "%s: Videocore resumed", __func__);
-               ret = 0;
-       }
-       read_unlock_bh(&arm_state->susp_res_lock);
-out:
-       vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, ret);
-       return ret;
-}
-
 /* This function should be called with the write lock held */
 int
 vchiq_check_resume(struct vchiq_state *state)
@@ -3010,7 +2738,7 @@ vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service,
                        vchiq_log_info(vchiq_susp_log_level, "%s %s resume "
                                "blocked - waiting...", __func__, entity);
                        if (wait_for_completion_killable(
-                                       &arm_state->resume_blocker) != 0) {
+                                       &arm_state->resume_blocker)) {
                                vchiq_log_error(vchiq_susp_log_level, "%s %s "
                                        "wait for resume blocker interrupted",
                                        __func__, entity);
@@ -3059,7 +2787,7 @@ vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service,
                vchiq_log_info(vchiq_susp_log_level, "%s %s wait for resume",
                        __func__, entity);
                if (wait_for_completion_killable(
-                               &arm_state->vc_resume_complete) != 0) {
+                               &arm_state->vc_resume_complete)) {
                        vchiq_log_error(vchiq_susp_log_level, "%s %s wait for "
                                "resume interrupted", __func__, entity);
                        ret = VCHIQ_ERROR;
@@ -3242,20 +2970,6 @@ static void suspend_timer_callback(struct timer_list *t)
        vchiq_check_suspend(state);
 }
 
-VCHIQ_STATUS_T
-vchiq_use_service_no_resume(VCHIQ_SERVICE_HANDLE_T handle)
-{
-       VCHIQ_STATUS_T ret = VCHIQ_ERROR;
-       struct vchiq_service *service = find_service_by_handle(handle);
-
-       if (service) {
-               ret = vchiq_use_internal(service->state, service,
-                               USE_TYPE_SERVICE_NO_RESUME);
-               unlock_service(service);
-       }
-       return ret;
-}
-
 VCHIQ_STATUS_T
 vchiq_use_service(VCHIQ_SERVICE_HANDLE_T handle)
 {
@@ -3504,13 +3218,13 @@ static int vchiq_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, drvdata);
 
        err = vchiq_platform_init(pdev, &g_state);
-       if (err != 0)
+       if (err)
                goto failed_platform_init;
 
        cdev_init(&vchiq_cdev, &vchiq_fops);
        vchiq_cdev.owner = THIS_MODULE;
        err = cdev_add(&vchiq_cdev, vchiq_devid, 1);
-       if (err != 0) {
+       if (err) {
                vchiq_log_error(vchiq_arm_log_level,
                        "Unable to register device");
                goto failed_platform_init;
index c1d5a9d..b424323 100644 (file)
@@ -112,12 +112,6 @@ vchiq_get_state(void);
 extern VCHIQ_STATUS_T
 vchiq_arm_vcsuspend(struct vchiq_state *state);
 
-extern VCHIQ_STATUS_T
-vchiq_arm_force_suspend(struct vchiq_state *state);
-
-extern int
-vchiq_arm_allow_resume(struct vchiq_state *state);
-
 extern VCHIQ_STATUS_T
 vchiq_arm_vcresume(struct vchiq_state *state);
 
index e87e661..1640906 100644 (file)
@@ -41,7 +41,7 @@ void vchiq_add_connected_callback(VCHIQ_CONNECTED_CALLBACK_T callback)
 {
        connected_init();
 
-       if (mutex_lock_killable(&g_connected_mutex) != 0)
+       if (mutex_lock_killable(&g_connected_mutex))
                return;
 
        if (g_connected)
@@ -76,7 +76,7 @@ void vchiq_call_connected_callbacks(void)
 
        connected_init();
 
-       if (mutex_lock_killable(&g_connected_mutex) != 0)
+       if (mutex_lock_killable(&g_connected_mutex))
                return;
 
        for (i = 0; i <  g_num_deferred_callbacks; i++)
index 0c387b6..183f5cf 100644 (file)
@@ -395,13 +395,21 @@ remote_event_create(wait_queue_head_t *wq, struct remote_event *event)
        init_waitqueue_head(wq);
 }
 
+/*
+ * All the event waiting routines in VCHIQ used a custom semaphore
+ * implementation that filtered most signals. This achieved a behaviour similar
+ * to the "killable" family of functions. While cleaning up this code all the
+ * routines where switched to the "interruptible" family of functions, as the
+ * former was deemed unjustified and the use "killable" set all VCHIQ's
+ * threads in D state.
+ */
 static inline int
 remote_event_wait(wait_queue_head_t *wq, struct remote_event *event)
 {
        if (!event->fired) {
                event->armed = 1;
                dsb(sy);
-               if (wait_event_killable(*wq, event->fired)) {
+               if (wait_event_interruptible(*wq, event->fired)) {
                        event->armed = 0;
                        return 0;
                }
@@ -560,7 +568,7 @@ reserve_space(struct vchiq_state *state, size_t space, int is_blocking)
                        remote_event_signal(&state->remote->trigger);
 
                        if (!is_blocking ||
-                               (wait_for_completion_killable(
+                               (wait_for_completion_interruptible(
                                &state->slot_available_event)))
                                return NULL; /* No space available */
                }
@@ -792,7 +800,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
        WARN_ON(!(stride <= VCHIQ_SLOT_SIZE));
 
        if (!(flags & QMFLAGS_NO_MUTEX_LOCK) &&
-               (mutex_lock_killable(&state->slot_mutex) != 0))
+           mutex_lock_killable(&state->slot_mutex))
                return VCHIQ_RETRY;
 
        if (type == VCHIQ_MSG_DATA) {
@@ -804,8 +812,8 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
                        return VCHIQ_ERROR;
                }
 
-               WARN_ON((flags & (QMFLAGS_NO_MUTEX_LOCK |
-                                 QMFLAGS_NO_MUTEX_UNLOCK)) != 0);
+               WARN_ON(flags & (QMFLAGS_NO_MUTEX_LOCK |
+                                QMFLAGS_NO_MUTEX_UNLOCK));
 
                if (service->closing) {
                        /* The service has been closed */
@@ -830,7 +838,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
                        spin_unlock(&quota_spinlock);
                        mutex_unlock(&state->slot_mutex);
 
-                       if (wait_for_completion_killable(
+                       if (wait_for_completion_interruptible(
                                                &state->data_quota_event))
                                return VCHIQ_RETRY;
 
@@ -861,12 +869,12 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
                                service_quota->slot_use_count);
                        VCHIQ_SERVICE_STATS_INC(service, quota_stalls);
                        mutex_unlock(&state->slot_mutex);
-                       if (wait_for_completion_killable(
+                       if (wait_for_completion_interruptible(
                                                &service_quota->quota_event))
                                return VCHIQ_RETRY;
                        if (service->closing)
                                return VCHIQ_ERROR;
-                       if (mutex_lock_killable(&state->slot_mutex) != 0)
+                       if (mutex_lock_killable(&state->slot_mutex))
                                return VCHIQ_RETRY;
                        if (service->srvstate != VCHIQ_SRVSTATE_OPEN) {
                                /* The service has been closed */
@@ -904,8 +912,8 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
                        header, size, VCHIQ_MSG_SRCPORT(msgid),
                        VCHIQ_MSG_DSTPORT(msgid));
 
-               WARN_ON((flags & (QMFLAGS_NO_MUTEX_LOCK |
-                                 QMFLAGS_NO_MUTEX_UNLOCK)) != 0);
+               WARN_ON(flags & (QMFLAGS_NO_MUTEX_LOCK |
+                                QMFLAGS_NO_MUTEX_UNLOCK));
 
                callback_result =
                        copy_message_data(copy_callback, context,
@@ -1032,8 +1040,8 @@ queue_message_sync(struct vchiq_state *state, struct vchiq_service *service,
 
        local = state->local;
 
-       if ((VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_RESUME) &&
-               (mutex_lock_killable(&state->sync_mutex) != 0))
+       if (VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_RESUME &&
+           mutex_lock_killable(&state->sync_mutex))
                return VCHIQ_RETRY;
 
        remote_event_wait(&state->sync_release_event, &local->sync_release);
@@ -2428,7 +2436,7 @@ vchiq_open_service_internal(struct vchiq_service *service, int client_id)
                               QMFLAGS_IS_BLOCKING);
        if (status == VCHIQ_SUCCESS) {
                /* Wait for the ACK/NAK */
-               if (wait_for_completion_killable(&service->remove_event)) {
+               if (wait_for_completion_interruptible(&service->remove_event)) {
                        status = VCHIQ_RETRY;
                        vchiq_release_service_internal(service);
                } else if ((service->srvstate != VCHIQ_SRVSTATE_OPEN) &&
@@ -2514,7 +2522,7 @@ do_abort_bulks(struct vchiq_service *service)
        VCHIQ_STATUS_T status;
 
        /* Abort any outstanding bulk transfers */
-       if (mutex_lock_killable(&service->bulk_mutex) != 0)
+       if (mutex_lock_killable(&service->bulk_mutex))
                return 0;
        abort_outstanding_bulks(service, &service->bulk_tx);
        abort_outstanding_bulks(service, &service->bulk_rx);
@@ -2795,7 +2803,7 @@ vchiq_connect_internal(struct vchiq_state *state, VCHIQ_INSTANCE_T instance)
        }
 
        if (state->conn_state == VCHIQ_CONNSTATE_CONNECTING) {
-               if (wait_for_completion_killable(&state->connect))
+               if (wait_for_completion_interruptible(&state->connect))
                        return VCHIQ_RETRY;
 
                vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
@@ -2822,45 +2830,6 @@ vchiq_shutdown_internal(struct vchiq_state *state, VCHIQ_INSTANCE_T instance)
        return VCHIQ_SUCCESS;
 }
 
-VCHIQ_STATUS_T
-vchiq_pause_internal(struct vchiq_state *state)
-{
-       VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-
-       switch (state->conn_state) {
-       case VCHIQ_CONNSTATE_CONNECTED:
-               /* Request a pause */
-               vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSING);
-               request_poll(state, NULL, 0);
-               break;
-       default:
-               vchiq_log_error(vchiq_core_log_level,
-                       "%s in state %s\n",
-                       __func__, conn_state_names[state->conn_state]);
-               status = VCHIQ_ERROR;
-               VCHIQ_STATS_INC(state, error_count);
-               break;
-       }
-
-       return status;
-}
-
-VCHIQ_STATUS_T
-vchiq_resume_internal(struct vchiq_state *state)
-{
-       VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-
-       if (state->conn_state == VCHIQ_CONNSTATE_PAUSED) {
-               vchiq_set_conn_state(state, VCHIQ_CONNSTATE_RESUMING);
-               request_poll(state, NULL, 0);
-       } else {
-               status = VCHIQ_ERROR;
-               VCHIQ_STATS_INC(state, error_count);
-       }
-
-       return status;
-}
-
 VCHIQ_STATUS_T
 vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle)
 {
@@ -2894,7 +2863,7 @@ vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle)
        }
 
        while (1) {
-               if (wait_for_completion_killable(&service->remove_event)) {
+               if (wait_for_completion_interruptible(&service->remove_event)) {
                        status = VCHIQ_RETRY;
                        break;
                }
@@ -2955,7 +2924,7 @@ vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T handle)
                request_poll(service->state, service, VCHIQ_POLL_REMOVE);
        }
        while (1) {
-               if (wait_for_completion_killable(&service->remove_event)) {
+               if (wait_for_completion_interruptible(&service->remove_event)) {
                        status = VCHIQ_RETRY;
                        break;
                }
@@ -3029,7 +2998,7 @@ VCHIQ_STATUS_T vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
        queue = (dir == VCHIQ_BULK_TRANSMIT) ?
                &service->bulk_tx : &service->bulk_rx;
 
-       if (mutex_lock_killable(&service->bulk_mutex) != 0) {
+       if (mutex_lock_killable(&service->bulk_mutex)) {
                status = VCHIQ_RETRY;
                goto error_exit;
        }
@@ -3038,13 +3007,12 @@ VCHIQ_STATUS_T vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
                VCHIQ_SERVICE_STATS_INC(service, bulk_stalls);
                do {
                        mutex_unlock(&service->bulk_mutex);
-                       if (wait_for_completion_killable(
+                       if (wait_for_completion_interruptible(
                                                &service->bulk_remove_event)) {
                                status = VCHIQ_RETRY;
                                goto error_exit;
                        }
-                       if (mutex_lock_killable(&service->bulk_mutex)
-                               != 0) {
+                       if (mutex_lock_killable(&service->bulk_mutex)) {
                                status = VCHIQ_RETRY;
                                goto error_exit;
                        }
@@ -3072,7 +3040,7 @@ VCHIQ_STATUS_T vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
 
        /* The slot mutex must be held when the service is being closed, so
           claim it here to ensure that isn't happening */
-       if (mutex_lock_killable(&state->slot_mutex) != 0) {
+       if (mutex_lock_killable(&state->slot_mutex)) {
                status = VCHIQ_RETRY;
                goto cancel_bulk_error_exit;
        }
@@ -3093,9 +3061,8 @@ VCHIQ_STATUS_T vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
                               QMFLAGS_IS_BLOCKING |
                               QMFLAGS_NO_MUTEX_LOCK |
                               QMFLAGS_NO_MUTEX_UNLOCK);
-       if (status != VCHIQ_SUCCESS) {
+       if (status != VCHIQ_SUCCESS)
                goto unlock_both_error_exit;
-       }
 
        queue->local_insert++;
 
@@ -3115,7 +3082,7 @@ waiting:
 
        if (bulk_waiter) {
                bulk_waiter->bulk = bulk;
-               if (wait_for_completion_killable(&bulk_waiter->event))
+               if (wait_for_completion_interruptible(&bulk_waiter->event))
                        status = VCHIQ_RETRY;
                else if (bulk_waiter->actual == VCHIQ_BULK_ACTUAL_ABORTED)
                        status = VCHIQ_ERROR;
@@ -3571,17 +3538,6 @@ VCHIQ_STATUS_T vchiq_send_remote_use(struct vchiq_state *state)
        return status;
 }
 
-VCHIQ_STATUS_T vchiq_send_remote_release(struct vchiq_state *state)
-{
-       VCHIQ_STATUS_T status = VCHIQ_RETRY;
-
-       if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED)
-               status = queue_message(state, NULL,
-                       VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_RELEASE, 0, 0),
-                       NULL, NULL, 0, 0);
-       return status;
-}
-
 VCHIQ_STATUS_T vchiq_send_remote_use_active(struct vchiq_state *state)
 {
        VCHIQ_STATUS_T status = VCHIQ_RETRY;
index aee2d36..63f71b2 100644 (file)
@@ -518,12 +518,6 @@ vchiq_free_service_internal(struct vchiq_service *service);
 extern VCHIQ_STATUS_T
 vchiq_shutdown_internal(struct vchiq_state *state, VCHIQ_INSTANCE_T instance);
 
-extern VCHIQ_STATUS_T
-vchiq_pause_internal(struct vchiq_state *state);
-
-extern VCHIQ_STATUS_T
-vchiq_resume_internal(struct vchiq_state *state);
-
 extern void
 remote_event_pollall(struct vchiq_state *state);
 
@@ -645,9 +639,6 @@ vchiq_on_remote_use_active(struct vchiq_state *state);
 extern VCHIQ_STATUS_T
 vchiq_send_remote_use(struct vchiq_state *state);
 
-extern VCHIQ_STATUS_T
-vchiq_send_remote_release(struct vchiq_state *state);
-
 extern VCHIQ_STATUS_T
 vchiq_send_remote_use_active(struct vchiq_state *state);
 
index 2bb9120..f217b78 100644 (file)
@@ -86,7 +86,7 @@ static ssize_t debugfs_log_write(struct file *file,
        if (count >= DEBUGFS_WRITE_BUF_SIZE)
                count = DEBUGFS_WRITE_BUF_SIZE;
 
-       if (copy_from_user(kbuf, buffer, count) != 0)
+       if (copy_from_user(kbuf, buffer, count))
                return -EFAULT;
        kbuf[count - 1] = 0;
 
@@ -151,7 +151,7 @@ static ssize_t debugfs_trace_write(struct file *file,
        VCHIQ_INSTANCE_T instance = f->private;
        char firstchar;
 
-       if (copy_from_user(&firstchar, buffer, 1) != 0)
+       if (copy_from_user(&firstchar, buffer, 1))
                return -EFAULT;
 
        switch (firstchar) {
index 5445f20..c23bd10 100644 (file)
@@ -107,8 +107,6 @@ extern VCHIQ_STATUS_T vchiq_open_service(VCHIQ_INSTANCE_T instance,
 extern VCHIQ_STATUS_T vchiq_close_service(VCHIQ_SERVICE_HANDLE_T service);
 extern VCHIQ_STATUS_T vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T service);
 extern VCHIQ_STATUS_T vchiq_use_service(VCHIQ_SERVICE_HANDLE_T service);
-extern VCHIQ_STATUS_T vchiq_use_service_no_resume(
-       VCHIQ_SERVICE_HANDLE_T service);
 extern VCHIQ_STATUS_T vchiq_release_service(VCHIQ_SERVICE_HANDLE_T service);
 extern VCHIQ_STATUS_T
 vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle,
index 13910d2..17a4f2c 100644 (file)
@@ -639,10 +639,8 @@ int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)
 
        if (service) {
                VCHIQ_STATUS_T status = vchiq_close_service(service->handle);
-               if (status == VCHIQ_SUCCESS) {
+               if (status == VCHIQ_SUCCESS)
                        service_free(service);
-                       service = NULL;
-               }
 
                ret = vchiq_status_to_vchi(status);
        }
index 6c519d8..5e6d303 100644 (file)
@@ -39,18 +39,13 @@ int vchiu_queue_is_empty(struct vchiu_queue *queue)
        return queue->read == queue->write;
 }
 
-int vchiu_queue_is_full(struct vchiu_queue *queue)
-{
-       return queue->write == queue->read + queue->size;
-}
-
 void vchiu_queue_push(struct vchiu_queue *queue, struct vchiq_header *header)
 {
        if (!queue->initialized)
                return;
 
        while (queue->write == queue->read + queue->size) {
-               if (wait_for_completion_killable(&queue->pop))
+               if (wait_for_completion_interruptible(&queue->pop))
                        flush_signals(current);
        }
 
@@ -63,7 +58,7 @@ void vchiu_queue_push(struct vchiu_queue *queue, struct vchiq_header *header)
 struct vchiq_header *vchiu_queue_peek(struct vchiu_queue *queue)
 {
        while (queue->write == queue->read) {
-               if (wait_for_completion_killable(&queue->push))
+               if (wait_for_completion_interruptible(&queue->push))
                        flush_signals(current);
        }
 
@@ -77,7 +72,7 @@ struct vchiq_header *vchiu_queue_pop(struct vchiu_queue *queue)
        struct vchiq_header *header;
 
        while (queue->write == queue->read) {
-               if (wait_for_completion_killable(&queue->push))
+               if (wait_for_completion_interruptible(&queue->push))
                        flush_signals(current);
        }
 
index ee14594..f03a425 100644 (file)
@@ -40,7 +40,6 @@ extern int  vchiu_queue_init(struct vchiu_queue *queue, int size);
 extern void vchiu_queue_delete(struct vchiu_queue *queue);
 
 extern int vchiu_queue_is_empty(struct vchiu_queue *queue);
-extern int vchiu_queue_is_full(struct vchiu_queue *queue);
 
 extern void vchiu_queue_push(struct vchiu_queue *queue,
                             struct vchiq_header *header);
index e4b224f..d1cd5de 100644 (file)
@@ -2,6 +2,5 @@
 config VT6655
    tristate "VIA Technologies VT6655 support"
    depends on PCI && MAC80211 && m
-   ---help---
-   This is a vendor-written driver for VIA VT6655.
-
+   help
+     This is a vendor-written driver for VIA VT6655.
index 6ecbe92..eba4ee0 100644 (file)
@@ -409,14 +409,11 @@ bool CARDbSetBeaconPeriod(struct vnt_private *priv,
  *  Out:
  *      none
  *
- * Return Value: true if success; otherwise false
  */
-bool CARDbRadioPowerOff(struct vnt_private *priv)
+void CARDbRadioPowerOff(struct vnt_private *priv)
 {
-       bool bResult = true;
-
        if (priv->bRadioOff)
-               return true;
+               return;
 
        switch (priv->byRFType) {
        case RF_RFMD2959:
@@ -444,7 +441,6 @@ bool CARDbRadioPowerOff(struct vnt_private *priv)
        pr_debug("chester power off\n");
        MACvRegBitsOn(priv->PortOffset, MAC_REG_GPIOCTL0,
                      LED_ACTSET);  /* LED issue */
-       return bResult;
 }
 
 /*
index f422fb3..887c169 100644 (file)
@@ -57,7 +57,7 @@ u64 CARDqGetTSFOffset(unsigned char byRxRate, u64 qwTSF1, u64 qwTSF2);
 unsigned char CARDbyGetPktType(struct vnt_private *priv);
 void CARDvSafeResetTx(struct vnt_private *priv);
 void CARDvSafeResetRx(struct vnt_private *priv);
-bool CARDbRadioPowerOff(struct vnt_private *priv);
+void CARDbRadioPowerOff(struct vnt_private *priv);
 bool CARDbRadioPowerOn(struct vnt_private *priv);
 bool CARDbSetPhyParameter(struct vnt_private *priv, u8 bb_type);
 bool CARDbUpdateTSF(struct vnt_private *priv, unsigned char byRxRate,
index 039f7d7..ba6dec7 100644 (file)
@@ -6,4 +6,4 @@ KSP :=  /lib/modules/$(shell uname -r)/build \
 #      /usr/src/linux-$(shell uname -r | sed 's/\([0-9]*\.[0-9]*\)\..*/\1/') \
 #      /usr/src/linux   /home/plice
 test_dir = $(shell [ -e $(dir)/include/linux ] && echo $(dir))
-KSP := $(foreach dir, $(KSP), $(test_dir))
\ No newline at end of file
+KSP := $(foreach dir, $(KSP), $(test_dir))
index 51e2952..f52a3f1 100644 (file)
@@ -3,6 +3,5 @@ config VT6656
        tristate "VIA Technologies VT6656 support"
        depends on MAC80211 && USB && WLAN && m
        select FW_LOADER
-       ---help---
-       This is a vendor-written driver for VIA VT6656.
-
+       help
+         This is a vendor-written driver for VIA VT6656.
index b29ba23..8d19ae7 100644 (file)
@@ -329,7 +329,7 @@ void vnt_get_phy_field(struct vnt_private *priv, u32 frame_length,
  * Return Value: none
  *
  */
-void vnt_set_antenna_mode(struct vnt_private *priv, u8 antenna_mode)
+int vnt_set_antenna_mode(struct vnt_private *priv, u8 antenna_mode)
 {
        switch (antenna_mode) {
        case ANT_TXA:
@@ -344,8 +344,8 @@ void vnt_set_antenna_mode(struct vnt_private *priv, u8 antenna_mode)
                break;
        }
 
-       vnt_control_out(priv, MESSAGE_TYPE_SET_ANTMD,
-                       (u16)antenna_mode, 0, 0, NULL);
+       return vnt_control_out(priv, MESSAGE_TYPE_SET_ANTMD,
+                              (u16)antenna_mode, 0, 0, NULL);
 }
 
 /*
@@ -364,7 +364,7 @@ void vnt_set_antenna_mode(struct vnt_private *priv, u8 antenna_mode)
 
 int vnt_vt3184_init(struct vnt_private *priv)
 {
-       int status;
+       int ret = 0;
        u16 length;
        u8 *addr;
        u8 *agc;
@@ -372,11 +372,10 @@ int vnt_vt3184_init(struct vnt_private *priv)
        u8 array[256];
        u8 data;
 
-       status = vnt_control_in(priv, MESSAGE_TYPE_READ, 0,
-                               MESSAGE_REQUEST_EEPROM, EEP_MAX_CONTEXT_SIZE,
-                                               priv->eeprom);
-       if (status != STATUS_SUCCESS)
-               return false;
+       ret = vnt_control_in(priv, MESSAGE_TYPE_READ, 0, MESSAGE_REQUEST_EEPROM,
+                            EEP_MAX_CONTEXT_SIZE, priv->eeprom);
+       if (ret)
+               goto end;
 
        priv->rf_type = priv->eeprom[EEP_OFS_RFTYPE];
 
@@ -423,8 +422,10 @@ int vnt_vt3184_init(struct vnt_private *priv)
                priv->bb_vga[3] = 0x0;
 
                /* Fix VT3226 DFC system timing issue */
-               vnt_mac_reg_bits_on(priv, MAC_REG_SOFTPWRCTL2,
-                                   SOFTPWRCTL_RFLEOPT);
+               ret = vnt_mac_reg_bits_on(priv, MAC_REG_SOFTPWRCTL2,
+                                         SOFTPWRCTL_RFLEOPT);
+               if (ret)
+                       goto end;
        } else if (priv->rf_type == RF_VT3342A0) {
                priv->bb_rx_conf = vnt_vt3184_vt3226d0[10];
                length = sizeof(vnt_vt3184_vt3226d0);
@@ -438,48 +439,74 @@ int vnt_vt3184_init(struct vnt_private *priv)
                priv->bb_vga[3] = 0x0;
 
                /* Fix VT3226 DFC system timing issue */
-               vnt_mac_reg_bits_on(priv, MAC_REG_SOFTPWRCTL2,
-                                   SOFTPWRCTL_RFLEOPT);
+               ret = vnt_mac_reg_bits_on(priv, MAC_REG_SOFTPWRCTL2,
+                                         SOFTPWRCTL_RFLEOPT);
+               if (ret)
+                       goto end;
        } else {
-               return true;
+               goto end;
        }
 
        memcpy(array, addr, length);
 
-       vnt_control_out(priv, MESSAGE_TYPE_WRITE, 0,
-                       MESSAGE_REQUEST_BBREG, length, array);
+       ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, 0,
+                             MESSAGE_REQUEST_BBREG, length, array);
+       if (ret)
+               goto end;
 
        memcpy(array, agc, length_agc);
 
-       vnt_control_out(priv, MESSAGE_TYPE_WRITE, 0,
-                       MESSAGE_REQUEST_BBAGC, length_agc, array);
+       ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, 0,
+                             MESSAGE_REQUEST_BBAGC, length_agc, array);
+       if (ret)
+               goto end;
 
        if ((priv->rf_type == RF_VT3226) ||
            (priv->rf_type == RF_VT3342A0)) {
-               vnt_control_out_u8(priv, MESSAGE_REQUEST_MACREG,
-                                  MAC_REG_ITRTMSET, 0x23);
-               vnt_mac_reg_bits_on(priv, MAC_REG_PAPEDELAY, 0x01);
+               ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_MACREG,
+                                        MAC_REG_ITRTMSET, 0x23);
+               if (ret)
+                       goto end;
+
+               ret = vnt_mac_reg_bits_on(priv, MAC_REG_PAPEDELAY, 0x01);
+               if (ret)
+                       goto end;
        } else if (priv->rf_type == RF_VT3226D0) {
-               vnt_control_out_u8(priv, MESSAGE_REQUEST_MACREG,
-                                  MAC_REG_ITRTMSET, 0x11);
-               vnt_mac_reg_bits_on(priv, MAC_REG_PAPEDELAY, 0x01);
+               ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_MACREG,
+                                        MAC_REG_ITRTMSET, 0x11);
+               if (ret)
+                       goto end;
+
+               ret = vnt_mac_reg_bits_on(priv, MAC_REG_PAPEDELAY, 0x01);
+               if (ret)
+                       goto end;
        }
 
-       vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x04, 0x7f);
-       vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0d, 0x01);
+       ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x04, 0x7f);
+       if (ret)
+               goto end;
 
-       vnt_rf_table_download(priv);
+       ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0d, 0x01);
+       if (ret)
+               goto end;
+
+       ret = vnt_rf_table_download(priv);
+       if (ret)
+               goto end;
 
        /* Fix for TX USB resets from vendors driver */
-       vnt_control_in(priv, MESSAGE_TYPE_READ, USB_REG4,
-                      MESSAGE_REQUEST_MEM, sizeof(data), &data);
+       ret = vnt_control_in(priv, MESSAGE_TYPE_READ, USB_REG4,
+                            MESSAGE_REQUEST_MEM, sizeof(data), &data);
+       if (ret)
+               goto end;
 
        data |= 0x2;
 
-       vnt_control_out(priv, MESSAGE_TYPE_WRITE, USB_REG4,
-                       MESSAGE_REQUEST_MEM, sizeof(data), &data);
+       ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, USB_REG4,
+                             MESSAGE_REQUEST_MEM, sizeof(data), &data);
 
-       return true;
+end:
+       return ret;
 }
 
 /*
@@ -494,8 +521,9 @@ int vnt_vt3184_init(struct vnt_private *priv)
  * Return Value: none
  *
  */
-void vnt_set_short_slot_time(struct vnt_private *priv)
+int vnt_set_short_slot_time(struct vnt_private *priv)
 {
+       int ret = 0;
        u8 bb_vga = 0;
 
        if (priv->short_slot_time)
@@ -503,12 +531,18 @@ void vnt_set_short_slot_time(struct vnt_private *priv)
        else
                priv->bb_rx_conf |= 0x20;
 
-       vnt_control_in_u8(priv, MESSAGE_REQUEST_BBREG, 0xe7, &bb_vga);
+       ret = vnt_control_in_u8(priv, MESSAGE_REQUEST_BBREG, 0xe7, &bb_vga);
+       if (ret)
+               goto end;
 
        if (bb_vga == priv->bb_vga[0])
                priv->bb_rx_conf |= 0x20;
 
-       vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0a, priv->bb_rx_conf);
+       ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0a,
+                                priv->bb_rx_conf);
+
+end:
+       return ret;
 }
 
 void vnt_set_vga_gain_offset(struct vnt_private *priv, u8 data)
@@ -536,16 +570,30 @@ void vnt_set_vga_gain_offset(struct vnt_private *priv, u8 data)
  * Return Value: none
  *
  */
-void vnt_set_deep_sleep(struct vnt_private *priv)
+int vnt_set_deep_sleep(struct vnt_private *priv)
 {
-       vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0c, 0x17);/* CR12 */
-       vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0d, 0xB9);/* CR13 */
+       int ret = 0;
+
+       /* CR12 */
+       ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0c, 0x17);
+       if (ret)
+               return ret;
+
+       /* CR13 */
+       return vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0d, 0xB9);
 }
 
-void vnt_exit_deep_sleep(struct vnt_private *priv)
+int vnt_exit_deep_sleep(struct vnt_private *priv)
 {
-       vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0c, 0x00);/* CR12 */
-       vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0d, 0x01);/* CR13 */
+       int ret = 0;
+
+       /* CR12 */
+       ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0c, 0x00);
+       if (ret)
+               return ret;
+
+       /* CR13 */
+       return vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0d, 0x01);
 }
 
 void vnt_update_pre_ed_threshold(struct vnt_private *priv, int scanning)
index c3b8bbd..dc42aa6 100644 (file)
@@ -79,12 +79,12 @@ unsigned int vnt_get_frame_time(u8 preamble_type, u8 pkt_type,
 void vnt_get_phy_field(struct vnt_private *priv, u32 frame_length,
                       u16 tx_rate, u8 pkt_type, struct vnt_phy_field *phy);
 
-void vnt_set_short_slot_time(struct vnt_private *priv);
+int vnt_set_short_slot_time(struct vnt_private *priv);
 void vnt_set_vga_gain_offset(struct vnt_private *priv, u8 data);
-void vnt_set_antenna_mode(struct vnt_private *priv, u8 antenna_mode);
+int vnt_set_antenna_mode(struct vnt_private *priv, u8 antenna_mode);
 int vnt_vt3184_init(struct vnt_private *priv);
-void vnt_set_deep_sleep(struct vnt_private *priv);
-void vnt_exit_deep_sleep(struct vnt_private *priv);
+int vnt_set_deep_sleep(struct vnt_private *priv);
+int vnt_exit_deep_sleep(struct vnt_private *priv);
 void vnt_update_pre_ed_threshold(struct vnt_private *priv, int scanning);
 
 #endif /* __BASEBAND_H__ */
index 501f482..56cd77f 100644 (file)
@@ -166,7 +166,7 @@ static void vnt_calculate_ofdm_rate(u16 rate, u8 bb_type,
                        *tx_rate = 0x8b;
                        *rsv_time = 30;
                }
-                       break;
+               break;
        case RATE_9M:
                if (bb_type == BB_TYPE_11A) {
                        *tx_rate = 0x9f;
@@ -674,7 +674,7 @@ void vnt_update_next_tbtt(struct vnt_private *priv, u64 tsf,
  */
 int vnt_radio_power_off(struct vnt_private *priv)
 {
-       int ret = true;
+       int ret = 0;
 
        switch (priv->rf_type) {
        case RF_AL2230:
@@ -683,17 +683,25 @@ int vnt_radio_power_off(struct vnt_private *priv)
        case RF_VT3226:
        case RF_VT3226D0:
        case RF_VT3342A0:
-               vnt_mac_reg_bits_off(priv, MAC_REG_SOFTPWRCTL,
-                                    (SOFTPWRCTL_SWPE2 | SOFTPWRCTL_SWPE3));
+               ret = vnt_mac_reg_bits_off(priv, MAC_REG_SOFTPWRCTL,
+                                       (SOFTPWRCTL_SWPE2 | SOFTPWRCTL_SWPE3));
                break;
        }
 
-       vnt_mac_reg_bits_off(priv, MAC_REG_HOSTCR, HOSTCR_RXON);
+       if (ret)
+               goto end;
+
+       ret = vnt_mac_reg_bits_off(priv, MAC_REG_HOSTCR, HOSTCR_RXON);
+       if (ret)
+               goto end;
 
-       vnt_set_deep_sleep(priv);
+       ret = vnt_set_deep_sleep(priv);
+       if (ret)
+               goto end;
 
-       vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL1, GPIO3_INTMD);
+       ret = vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL1, GPIO3_INTMD);
 
+end:
        return ret;
 }
 
index 38521c3..60a00af 100644 (file)
@@ -30,98 +30,87 @@ int vnt_download_firmware(struct vnt_private *priv)
 {
        struct device *dev = &priv->usb->dev;
        const struct firmware *fw;
-       int status;
        void *buffer = NULL;
-       bool result = false;
        u16 length;
-       int ii, rc;
+       int ii;
+       int ret = 0;
 
        dev_dbg(dev, "---->Download firmware\n");
 
-       rc = request_firmware(&fw, FIRMWARE_NAME, dev);
-       if (rc) {
+       ret = request_firmware(&fw, FIRMWARE_NAME, dev);
+       if (ret) {
                dev_err(dev, "firmware file %s request failed (%d)\n",
-                       FIRMWARE_NAME, rc);
-                       goto out;
+                       FIRMWARE_NAME, ret);
+               goto end;
        }
 
        buffer = kmalloc(FIRMWARE_CHUNK_SIZE, GFP_KERNEL);
-       if (!buffer)
+       if (!buffer) {
+               ret = -ENOMEM;
                goto free_fw;
+       }
 
        for (ii = 0; ii < fw->size; ii += FIRMWARE_CHUNK_SIZE) {
                length = min_t(int, fw->size - ii, FIRMWARE_CHUNK_SIZE);
                memcpy(buffer, fw->data + ii, length);
 
-               status = vnt_control_out(priv,
-                                        0,
-                                        0x1200 + ii,
-                                        0x0000,
-                                        length,
-                                        buffer);
+               ret = vnt_control_out(priv, 0, 0x1200 + ii, 0x0000, length,
+                                     buffer);
+               if (ret)
+                       goto free_buffer;
 
                dev_dbg(dev, "Download firmware...%d %zu\n", ii, fw->size);
-
-               if (status != STATUS_SUCCESS)
-                       goto free_fw;
        }
 
-       result = true;
+free_buffer:
+       kfree(buffer);
 free_fw:
        release_firmware(fw);
-
-out:
-       kfree(buffer);
-
-       return result;
+end:
+       return ret;
 }
 MODULE_FIRMWARE(FIRMWARE_NAME);
 
 int vnt_firmware_branch_to_sram(struct vnt_private *priv)
 {
-       int status;
-
        dev_dbg(&priv->usb->dev, "---->Branch to Sram\n");
 
-       status = vnt_control_out(priv,
-                                1,
-                                0x1200,
-                                0x0000,
-                                0,
-                                NULL);
-       return status == STATUS_SUCCESS;
+       return vnt_control_out(priv, 1, 0x1200, 0x0000, 0, NULL);
 }
 
 int vnt_check_firmware_version(struct vnt_private *priv)
 {
-       int status;
-
-       status = vnt_control_in(priv,
-                               MESSAGE_TYPE_READ,
-                               0,
-                               MESSAGE_REQUEST_VERSION,
-                               2,
-                               (u8 *)&priv->firmware_version);
+       int ret = 0;
+
+       ret = vnt_control_in(priv, MESSAGE_TYPE_READ, 0,
+                            MESSAGE_REQUEST_VERSION, 2,
+                            (u8 *)&priv->firmware_version);
+       if (ret) {
+               dev_dbg(&priv->usb->dev,
+                       "Could not get firmware version: %d.\n", ret);
+               goto end;
+       }
 
        dev_dbg(&priv->usb->dev, "Firmware Version [%04x]\n",
                priv->firmware_version);
 
-       if (status != STATUS_SUCCESS) {
-               dev_dbg(&priv->usb->dev, "Firmware Invalid.\n");
-               return false;
-       }
        if (priv->firmware_version == 0xFFFF) {
                dev_dbg(&priv->usb->dev, "In Loader.\n");
-               return false;
+               ret = -EINVAL;
+               goto end;
        }
 
-       dev_dbg(&priv->usb->dev, "Firmware Version [%04x]\n",
-               priv->firmware_version);
-
        if (priv->firmware_version < FIRMWARE_VERSION) {
                /* branch to loader for download new firmware */
-               vnt_firmware_branch_to_sram(priv);
-               return false;
+               ret = vnt_firmware_branch_to_sram(priv);
+               if (ret) {
+                       dev_dbg(&priv->usb->dev,
+                               "Could not branch to SRAM: %d.\n", ret);
+               } else {
+                       ret = -EINVAL;
+               }
        }
-       return true;
+
+end:
+       return ret;
 }
index 504424b..f409479 100644 (file)
@@ -39,18 +39,20 @@ static const u8 fallback_rate1[5][5] = {
        {RATE_54M, RATE_54M, RATE_36M, RATE_18M, RATE_18M}
 };
 
-void vnt_int_start_interrupt(struct vnt_private *priv)
+int vnt_int_start_interrupt(struct vnt_private *priv)
 {
+       int ret = 0;
        unsigned long flags;
-       int status;
 
        dev_dbg(&priv->usb->dev, "---->Interrupt Polling Thread\n");
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       status = vnt_start_interrupt_urb(priv);
+       ret = vnt_start_interrupt_urb(priv);
 
        spin_unlock_irqrestore(&priv->lock, flags);
+
+       return ret;
 }
 
 static int vnt_int_report_rate(struct vnt_private *priv, u8 pkt_no, u8 tsr)
index 987c454..8a6d605 100644 (file)
@@ -41,7 +41,7 @@ struct vnt_interrupt_data {
        u8 sw[2];
 } __packed;
 
-void vnt_int_start_interrupt(struct vnt_private *priv);
+int vnt_int_start_interrupt(struct vnt_private *priv);
 void vnt_int_process_data(struct vnt_private *priv);
 
 #endif /* __INT_H__ */
index 0b54385..5cacf6e 100644 (file)
@@ -129,27 +129,26 @@ void vnt_mac_set_keyentry(struct vnt_private *priv, u16 key_ctl, u32 entry_idx,
                        (u8 *)&set_key);
 }
 
-void vnt_mac_reg_bits_off(struct vnt_private *priv, u8 reg_ofs, u8 bits)
+int vnt_mac_reg_bits_off(struct vnt_private *priv, u8 reg_ofs, u8 bits)
 {
        u8 data[2];
 
        data[0] = 0;
        data[1] = bits;
 
-       vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK,
-                       reg_ofs, MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data),
-                       data);
+       return vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, reg_ofs,
+                              MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
 }
 
-void vnt_mac_reg_bits_on(struct vnt_private *priv, u8 reg_ofs, u8 bits)
+int vnt_mac_reg_bits_on(struct vnt_private *priv, u8 reg_ofs, u8 bits)
 {
        u8 data[2];
 
        data[0] = bits;
        data[1] = bits;
 
-       vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, reg_ofs,
-                       MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
+       return vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, reg_ofs,
+                              MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
 }
 
 void vnt_mac_write_word(struct vnt_private *priv, u8 reg_ofs, u16 word)
@@ -224,13 +223,13 @@ void vnt_mac_set_beacon_interval(struct vnt_private *priv, u16 interval)
                        MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
 }
 
-void vnt_mac_set_led(struct vnt_private *priv, u8 state, u8 led)
+int vnt_mac_set_led(struct vnt_private *priv, u8 state, u8 led)
 {
        u8 data[2];
 
        data[0] = led;
        data[1] = state;
 
-       vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, MAC_REG_PAPEDELAY,
-                       MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
+       return vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, MAC_REG_PAPEDELAY,
+                              MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
 }
index 3fd87f9..0a42308 100644 (file)
@@ -360,8 +360,8 @@ void vnt_mac_set_bb_type(struct vnt_private *priv, u8 type);
 void vnt_mac_disable_keyentry(struct vnt_private *priv, u8 entry_idx);
 void vnt_mac_set_keyentry(struct vnt_private *priv, u16 key_ctl, u32 entry_idx,
                          u32 key_idx, u8 *addr, u8 *key);
-void vnt_mac_reg_bits_off(struct vnt_private *priv, u8 reg_ofs, u8 bits);
-void vnt_mac_reg_bits_on(struct vnt_private *priv, u8 reg_ofs, u8 bits);
+int vnt_mac_reg_bits_off(struct vnt_private *priv, u8 reg_ofs, u8 bits);
+int vnt_mac_reg_bits_on(struct vnt_private *priv, u8 reg_ofs, u8 bits);
 void vnt_mac_write_word(struct vnt_private *priv, u8 reg_ofs, u16 word);
 void vnt_mac_set_bssid_addr(struct vnt_private *priv, u8 *addr);
 void vnt_mac_enable_protect_mode(struct vnt_private *priv);
@@ -369,6 +369,6 @@ void vnt_mac_disable_protect_mode(struct vnt_private *priv);
 void vnt_mac_enable_barker_preamble_mode(struct vnt_private *priv);
 void vnt_mac_disable_barker_preamble_mode(struct vnt_private *priv);
 void vnt_mac_set_beacon_interval(struct vnt_private *priv, u16 interval);
-void vnt_mac_set_led(struct vnt_private *privpriv, u8 state, u8 led);
+int vnt_mac_set_led(struct vnt_private *privpriv, u8 state, u8 led);
 
 #endif /* __MAC_H__ */
index ccafcc2..856ba97 100644 (file)
@@ -109,33 +109,38 @@ static void vnt_set_options(struct vnt_private *priv)
  */
 static int vnt_init_registers(struct vnt_private *priv)
 {
+       int ret = 0;
        struct vnt_cmd_card_init *init_cmd = &priv->init_command;
        struct vnt_rsp_card_init *init_rsp = &priv->init_response;
        u8 antenna;
        int ii;
-       int status = STATUS_SUCCESS;
        u8 tmp;
        u8 calib_tx_iq = 0, calib_tx_dc = 0, calib_rx_iq = 0;
 
        dev_dbg(&priv->usb->dev, "---->INIbInitAdapter. [%d][%d]\n",
                DEVICE_INIT_COLD, priv->packet_type);
 
-       if (!vnt_check_firmware_version(priv)) {
-               if (vnt_download_firmware(priv) == true) {
-                       if (vnt_firmware_branch_to_sram(priv) == false) {
-                               dev_dbg(&priv->usb->dev,
-                                       " vnt_firmware_branch_to_sram fail\n");
-                               return false;
-                       }
-               } else {
-                       dev_dbg(&priv->usb->dev, "FIRMWAREbDownload fail\n");
-                       return false;
+       ret = vnt_check_firmware_version(priv);
+       if (ret) {
+               ret = vnt_download_firmware(priv);
+               if (ret) {
+                       dev_dbg(&priv->usb->dev,
+                               "Could not download firmware: %d.\n", ret);
+                       goto end;
+               }
+
+               ret = vnt_firmware_branch_to_sram(priv);
+               if (ret) {
+                       dev_dbg(&priv->usb->dev,
+                               "Could not branch to SRAM: %d.\n", ret);
+                       goto end;
                }
        }
 
-       if (!vnt_vt3184_init(priv)) {
+       ret = vnt_vt3184_init(priv);
+       if (ret) {
                dev_dbg(&priv->usb->dev, "vnt_vt3184_init fail\n");
-               return false;
+               goto end;
        }
 
        init_cmd->init_class = DEVICE_INIT_COLD;
@@ -146,28 +151,27 @@ static int vnt_init_registers(struct vnt_private *priv)
        init_cmd->long_retry_limit = priv->long_retry_limit;
 
        /* issue card_init command to device */
-       status = vnt_control_out(priv, MESSAGE_TYPE_CARDINIT, 0, 0,
-                                sizeof(struct vnt_cmd_card_init),
-                                (u8 *)init_cmd);
-       if (status != STATUS_SUCCESS) {
+       ret = vnt_control_out(priv, MESSAGE_TYPE_CARDINIT, 0, 0,
+                             sizeof(struct vnt_cmd_card_init),
+                             (u8 *)init_cmd);
+       if (ret) {
                dev_dbg(&priv->usb->dev, "Issue Card init fail\n");
-               return false;
+               goto end;
        }
 
-       status = vnt_control_in(priv, MESSAGE_TYPE_INIT_RSP, 0, 0,
-                               sizeof(struct vnt_rsp_card_init),
-                               (u8 *)init_rsp);
-       if (status != STATUS_SUCCESS) {
-               dev_dbg(&priv->usb->dev,
-                       "Cardinit request in status fail!\n");
-               return false;
+       ret = vnt_control_in(priv, MESSAGE_TYPE_INIT_RSP, 0, 0,
+                            sizeof(struct vnt_rsp_card_init),
+                            (u8 *)init_rsp);
+       if (ret) {
+               dev_dbg(&priv->usb->dev, "Cardinit request in status fail!\n");
+               goto end;
        }
 
        /* local ID for AES functions */
-       status = vnt_control_in(priv, MESSAGE_TYPE_READ, MAC_REG_LOCALID,
-                               MESSAGE_REQUEST_MACREG, 1, &priv->local_id);
-       if (status != STATUS_SUCCESS)
-               return false;
+       ret = vnt_control_in(priv, MESSAGE_TYPE_READ, MAC_REG_LOCALID,
+                            MESSAGE_REQUEST_MACREG, 1, &priv->local_id);
+       if (ret)
+               goto end;
 
        /* do MACbSoftwareReset in MACvInitialize */
 
@@ -253,7 +257,9 @@ static int vnt_init_registers(struct vnt_private *priv)
        }
 
        /* Set initial antenna mode */
-       vnt_set_antenna_mode(priv, priv->rx_antenna_mode);
+       ret = vnt_set_antenna_mode(priv, priv->rx_antenna_mode);
+       if (ret)
+               goto end;
 
        /* get Auto Fall Back type */
        priv->auto_fb_ctrl = AUTO_FB_0;
@@ -275,33 +281,41 @@ static int vnt_init_registers(struct vnt_private *priv)
                                /* CR255, enable TX/RX IQ and
                                 * DC compensation mode
                                 */
-                               vnt_control_out_u8(priv,
-                                                  MESSAGE_REQUEST_BBREG,
-                                                  0xff,
-                                                  0x03);
+                               ret = vnt_control_out_u8(priv,
+                                                        MESSAGE_REQUEST_BBREG,
+                                                        0xff, 0x03);
+                               if (ret)
+                                       goto end;
+
                                /* CR251, TX I/Q Imbalance Calibration */
-                               vnt_control_out_u8(priv,
-                                                  MESSAGE_REQUEST_BBREG,
-                                                  0xfb,
-                                                  calib_tx_iq);
+                               ret = vnt_control_out_u8(priv,
+                                                        MESSAGE_REQUEST_BBREG,
+                                                        0xfb, calib_tx_iq);
+                               if (ret)
+                                       goto end;
+
                                /* CR252, TX DC-Offset Calibration */
-                               vnt_control_out_u8(priv,
-                                                  MESSAGE_REQUEST_BBREG,
-                                                  0xfC,
-                                                  calib_tx_dc);
+                               ret = vnt_control_out_u8(priv,
+                                                        MESSAGE_REQUEST_BBREG,
+                                                        0xfC, calib_tx_dc);
+                               if (ret)
+                                       goto end;
+
                                /* CR253, RX I/Q Imbalance Calibration */
-                               vnt_control_out_u8(priv,
-                                                  MESSAGE_REQUEST_BBREG,
-                                                  0xfd,
-                                                  calib_rx_iq);
+                               ret = vnt_control_out_u8(priv,
+                                                        MESSAGE_REQUEST_BBREG,
+                                                        0xfd, calib_rx_iq);
+                               if (ret)
+                                       goto end;
                        } else {
                                /* CR255, turn off
                                 * BB Calibration compensation
                                 */
-                               vnt_control_out_u8(priv,
-                                                  MESSAGE_REQUEST_BBREG,
-                                                  0xff,
-                                                  0x0);
+                               ret = vnt_control_out_u8(priv,
+                                                        MESSAGE_REQUEST_BBREG,
+                                                        0xff, 0x0);
+                               if (ret)
+                                       goto end;
                        }
                }
        }
@@ -323,37 +337,52 @@ static int vnt_init_registers(struct vnt_private *priv)
        else
                priv->short_slot_time = false;
 
-       vnt_set_short_slot_time(priv);
+       ret = vnt_set_short_slot_time(priv);
+       if (ret)
+               goto end;
 
        priv->radio_ctl = priv->eeprom[EEP_OFS_RADIOCTL];
 
        if ((priv->radio_ctl & EEP_RADIOCTL_ENABLE) != 0) {
-               status = vnt_control_in(priv, MESSAGE_TYPE_READ,
-                                       MAC_REG_GPIOCTL1,
-                                       MESSAGE_REQUEST_MACREG, 1, &tmp);
-
-               if (status != STATUS_SUCCESS)
-                       return false;
+               ret = vnt_control_in(priv, MESSAGE_TYPE_READ,
+                                    MAC_REG_GPIOCTL1, MESSAGE_REQUEST_MACREG,
+                                    1, &tmp);
+               if (ret)
+                       goto end;
+
+               if ((tmp & GPIO3_DATA) == 0) {
+                       ret = vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL1,
+                                                 GPIO3_INTMD);
+               } else {
+                       ret = vnt_mac_reg_bits_off(priv, MAC_REG_GPIOCTL1,
+                                                  GPIO3_INTMD);
+               }
 
-               if ((tmp & GPIO3_DATA) == 0)
-                       vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL1,
-                                           GPIO3_INTMD);
-               else
-                       vnt_mac_reg_bits_off(priv, MAC_REG_GPIOCTL1,
-                                            GPIO3_INTMD);
+               if (ret)
+                       goto end;
        }
 
-       vnt_mac_set_led(priv, LEDSTS_TMLEN, 0x38);
 
-       vnt_mac_set_led(priv, LEDSTS_STS, LEDSTS_SLOW);
+       ret = vnt_mac_set_led(priv, LEDSTS_TMLEN, 0x38);
+       if (ret)
+               goto end;
+
+       ret = vnt_mac_set_led(priv, LEDSTS_STS, LEDSTS_SLOW);
+       if (ret)
+               goto end;
 
-       vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL0, 0x01);
+       ret = vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL0, 0x01);
+       if (ret)
+               goto end;
 
-       vnt_radio_power_on(priv);
+       ret = vnt_radio_power_on(priv);
+       if (ret)
+               goto end;
 
        dev_dbg(&priv->usb->dev, "<----INIbInitAdapter Exit\n");
 
-       return true;
+end:
+       return ret;
 }
 
 static void vnt_free_tx_bufs(struct vnt_private *priv)
@@ -363,6 +392,9 @@ static void vnt_free_tx_bufs(struct vnt_private *priv)
 
        for (ii = 0; ii < priv->num_tx_context; ii++) {
                tx_context = priv->tx_context[ii];
+               if (!tx_context)
+                       continue;
+
                /* deallocate URBs */
                if (tx_context->urb) {
                        usb_kill_urb(tx_context->urb);
@@ -402,16 +434,19 @@ static void vnt_free_int_bufs(struct vnt_private *priv)
        kfree(priv->int_buf.data_buf);
 }
 
-static bool vnt_alloc_bufs(struct vnt_private *priv)
+static int vnt_alloc_bufs(struct vnt_private *priv)
 {
+       int ret = 0;
        struct vnt_usb_send_context *tx_context;
        struct vnt_rcb *rcb;
        int ii;
 
        for (ii = 0; ii < priv->num_tx_context; ii++) {
                tx_context = kmalloc(sizeof(*tx_context), GFP_KERNEL);
-               if (!tx_context)
+               if (!tx_context) {
+                       ret = -ENOMEM;
                        goto free_tx;
+               }
 
                priv->tx_context[ii] = tx_context;
                tx_context->priv = priv;
@@ -419,16 +454,20 @@ static bool vnt_alloc_bufs(struct vnt_private *priv)
 
                /* allocate URBs */
                tx_context->urb = usb_alloc_urb(0, GFP_KERNEL);
-               if (!tx_context->urb)
+               if (!tx_context->urb) {
+                       ret = -ENOMEM;
                        goto free_tx;
+               }
 
                tx_context->in_use = false;
        }
 
        for (ii = 0; ii < priv->num_rcb; ii++) {
                priv->rcb[ii] = kzalloc(sizeof(*priv->rcb[ii]), GFP_KERNEL);
-               if (!priv->rcb[ii])
+               if (!priv->rcb[ii]) {
+                       ret = -ENOMEM;
                        goto free_rx_tx;
+               }
 
                rcb = priv->rcb[ii];
 
@@ -436,39 +475,46 @@ static bool vnt_alloc_bufs(struct vnt_private *priv)
 
                /* allocate URBs */
                rcb->urb = usb_alloc_urb(0, GFP_KERNEL);
-               if (!rcb->urb)
+               if (!rcb->urb) {
+                       ret = -ENOMEM;
                        goto free_rx_tx;
+               }
 
                rcb->skb = dev_alloc_skb(priv->rx_buf_sz);
-               if (!rcb->skb)
+               if (!rcb->skb) {
+                       ret = -ENOMEM;
                        goto free_rx_tx;
+               }
 
                rcb->in_use = false;
 
                /* submit rx urb */
-               if (vnt_submit_rx_urb(priv, rcb))
+               ret = vnt_submit_rx_urb(priv, rcb);
+               if (ret)
                        goto free_rx_tx;
        }
 
        priv->interrupt_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!priv->interrupt_urb)
+       if (!priv->interrupt_urb) {
+               ret = -ENOMEM;
                goto free_rx_tx;
+       }
 
        priv->int_buf.data_buf = kmalloc(MAX_INTERRUPT_SIZE, GFP_KERNEL);
        if (!priv->int_buf.data_buf) {
-               usb_free_urb(priv->interrupt_urb);
-               goto free_rx_tx;
+               ret = -ENOMEM;
+               goto free_rx_tx_urb;
        }
 
-       return true;
+       return 0;
 
+free_rx_tx_urb:
+       usb_free_urb(priv->interrupt_urb);
 free_rx_tx:
        vnt_free_rx_bufs(priv);
-
 free_tx:
        vnt_free_tx_bufs(priv);
-
-       return false;
+       return ret;
 }
 
 static void vnt_tx_80211(struct ieee80211_hw *hw,
@@ -483,28 +529,34 @@ static void vnt_tx_80211(struct ieee80211_hw *hw,
 
 static int vnt_start(struct ieee80211_hw *hw)
 {
+       int ret = 0;
        struct vnt_private *priv = hw->priv;
 
        priv->rx_buf_sz = MAX_TOTAL_SIZE_WITH_ALL_HEADERS;
 
-       if (!vnt_alloc_bufs(priv)) {
+       ret = vnt_alloc_bufs(priv);
+       if (ret) {
                dev_dbg(&priv->usb->dev, "vnt_alloc_bufs fail...\n");
-               return -ENOMEM;
+               goto err;
        }
 
        clear_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags);
 
-       if (vnt_init_registers(priv) == false) {
+       ret = vnt_init_registers(priv);
+       if (ret) {
                dev_dbg(&priv->usb->dev, " init register fail\n");
                goto free_all;
        }
 
-       if (vnt_key_init_table(priv))
+       ret = vnt_key_init_table(priv);
+       if (ret)
                goto free_all;
 
        priv->int_interval = 1;  /* bInterval is set to 1 */
 
-       vnt_int_start_interrupt(priv);
+       ret = vnt_int_start_interrupt(priv);
+       if (ret)
+               goto free_all;
 
        ieee80211_wake_queues(hw);
 
@@ -517,8 +569,8 @@ free_all:
 
        usb_kill_urb(priv->interrupt_urb);
        usb_free_urb(priv->interrupt_urb);
-
-       return -ENOMEM;
+err:
+       return ret;
 }
 
 static void vnt_stop(struct ieee80211_hw *hw)
index 18f75dc..43237b7 100644 (file)
@@ -811,8 +811,9 @@ void vnt_rf_rssi_to_dbm(struct vnt_private *priv, u8 rssi, long *dbm)
        *dbm = -1 * (a + b * 2);
 }
 
-void vnt_rf_table_download(struct vnt_private *priv)
+int vnt_rf_table_download(struct vnt_private *priv)
 {
+       int ret = 0;
        u16 length1 = 0, length2 = 0, length3 = 0;
        u8 *addr1 = NULL, *addr2 = NULL, *addr3 = NULL;
        u16 length, value;
@@ -865,8 +866,10 @@ void vnt_rf_table_download(struct vnt_private *priv)
        /* Init Table */
        memcpy(array, addr1, length1);
 
-       vnt_control_out(priv, MESSAGE_TYPE_WRITE, 0,
-                       MESSAGE_REQUEST_RF_INIT, length1, array);
+       ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, 0,
+                             MESSAGE_REQUEST_RF_INIT, length1, array);
+       if (ret)
+               goto end;
 
        /* Channel Table 0 */
        value = 0;
@@ -878,8 +881,10 @@ void vnt_rf_table_download(struct vnt_private *priv)
 
                memcpy(array, addr2, length);
 
-               vnt_control_out(priv, MESSAGE_TYPE_WRITE,
-                               value, MESSAGE_REQUEST_RF_CH0, length, array);
+               ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, value,
+                                     MESSAGE_REQUEST_RF_CH0, length, array);
+               if (ret)
+                       goto end;
 
                length2 -= length;
                value += length;
@@ -896,8 +901,10 @@ void vnt_rf_table_download(struct vnt_private *priv)
 
                memcpy(array, addr3, length);
 
-               vnt_control_out(priv, MESSAGE_TYPE_WRITE,
-                               value, MESSAGE_REQUEST_RF_CH1, length, array);
+               ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, value,
+                                     MESSAGE_REQUEST_RF_CH1, length, array);
+               if (ret)
+                       goto end;
 
                length3 -= length;
                value += length;
@@ -913,8 +920,10 @@ void vnt_rf_table_download(struct vnt_private *priv)
                memcpy(array, addr1, length1);
 
                /* Init Table 2 */
-               vnt_control_out(priv, MESSAGE_TYPE_WRITE,
-                               0, MESSAGE_REQUEST_RF_INIT2, length1, array);
+               ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, 0,
+                                     MESSAGE_REQUEST_RF_INIT2, length1, array);
+               if (ret)
+                       goto end;
 
                /* Channel Table 0 */
                value = 0;
@@ -926,13 +935,18 @@ void vnt_rf_table_download(struct vnt_private *priv)
 
                        memcpy(array, addr2, length);
 
-                       vnt_control_out(priv, MESSAGE_TYPE_WRITE,
-                                       value, MESSAGE_REQUEST_RF_CH2,
-                                       length, array);
+                       ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, value,
+                                             MESSAGE_REQUEST_RF_CH2, length,
+                                             array);
+                       if (ret)
+                               goto end;
 
                        length2 -= length;
                        value += length;
                        addr2 += length;
                }
        }
+
+end:
+       return ret;
 }
index 6103117..7494546 100644 (file)
@@ -44,6 +44,6 @@ int vnt_rf_write_embedded(struct vnt_private *priv, u32 data);
 int vnt_rf_setpower(struct vnt_private *priv, u32 rate, u32 channel);
 int vnt_rf_set_txpower(struct vnt_private *priv, u8 power, u32 rate);
 void vnt_rf_rssi_to_dbm(struct vnt_private *priv, u8 rssi, long *dbm);
-void vnt_rf_table_download(struct vnt_private *priv);
+int vnt_rf_table_download(struct vnt_private *priv);
 
 #endif /* __RF_H__ */
index 5bbc56f..ff351a7 100644 (file)
 int vnt_control_out(struct vnt_private *priv, u8 request, u16 value,
                    u16 index, u16 length, u8 *buffer)
 {
-       int status = 0;
+       int ret = 0;
        u8 *usb_buffer;
 
-       if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags))
-               return STATUS_FAILURE;
+       if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) {
+               ret = -EINVAL;
+               goto end;
+       }
 
        mutex_lock(&priv->usb_lock);
 
        usb_buffer = kmemdup(buffer, length, GFP_KERNEL);
        if (!usb_buffer) {
-               mutex_unlock(&priv->usb_lock);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto end_unlock;
        }
 
-       status = usb_control_msg(priv->usb,
-                                usb_sndctrlpipe(priv->usb, 0),
-                                request, 0x40, value,
-                                index, usb_buffer, length, USB_CTL_WAIT);
+       ret = usb_control_msg(priv->usb,
+                             usb_sndctrlpipe(priv->usb, 0),
+                             request, 0x40, value,
+                             index, usb_buffer, length, USB_CTL_WAIT);
 
        kfree(usb_buffer);
 
-       mutex_unlock(&priv->usb_lock);
+       if (ret >= 0 && ret < (int)length)
+               ret = -EIO;
 
-       if (status < (int)length)
-               return STATUS_FAILURE;
-
-       return STATUS_SUCCESS;
+end_unlock:
+       mutex_unlock(&priv->usb_lock);
+end:
+       return ret;
 }
 
-void vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 data)
+int vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 data)
 {
-       vnt_control_out(priv, MESSAGE_TYPE_WRITE,
-                       reg_off, reg, sizeof(u8), &data);
+       return vnt_control_out(priv, MESSAGE_TYPE_WRITE,
+                              reg_off, reg, sizeof(u8), &data);
 }
 
 int vnt_control_in(struct vnt_private *priv, u8 request, u16 value,
                   u16 index, u16 length, u8 *buffer)
 {
-       int status;
+       int ret = 0;
        u8 *usb_buffer;
 
-       if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags))
-               return STATUS_FAILURE;
+       if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) {
+               ret = -EINVAL;
+               goto end;
+       }
 
        mutex_lock(&priv->usb_lock);
 
        usb_buffer = kmalloc(length, GFP_KERNEL);
        if (!usb_buffer) {
-               mutex_unlock(&priv->usb_lock);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto end_unlock;
        }
 
-       status = usb_control_msg(priv->usb,
-                                usb_rcvctrlpipe(priv->usb, 0),
-                                request, 0xc0, value,
-                                index, usb_buffer, length, USB_CTL_WAIT);
+       ret = usb_control_msg(priv->usb,
+                             usb_rcvctrlpipe(priv->usb, 0),
+                             request, 0xc0, value,
+                             index, usb_buffer, length, USB_CTL_WAIT);
 
-       if (status == length)
+       if (ret == length)
                memcpy(buffer, usb_buffer, length);
 
        kfree(usb_buffer);
 
-       mutex_unlock(&priv->usb_lock);
+       if (ret >= 0 && ret < (int)length)
+               ret = -EIO;
 
-       if (status < (int)length)
-               return STATUS_FAILURE;
-
-       return STATUS_SUCCESS;
+end_unlock:
+       mutex_unlock(&priv->usb_lock);
+end:
+       return ret;
 }
 
-void vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data)
+int vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data)
 {
-       vnt_control_in(priv, MESSAGE_TYPE_READ,
-                      reg_off, reg, sizeof(u8), data);
+       return vnt_control_in(priv, MESSAGE_TYPE_READ,
+                             reg_off, reg, sizeof(u8), data);
 }
 
 static void vnt_start_interrupt_urb_complete(struct urb *urb)
@@ -147,10 +153,12 @@ static void vnt_start_interrupt_urb_complete(struct urb *urb)
 
 int vnt_start_interrupt_urb(struct vnt_private *priv)
 {
-       int status = STATUS_FAILURE;
+       int ret = 0;
 
-       if (priv->int_buf.in_use)
-               return STATUS_FAILURE;
+       if (priv->int_buf.in_use) {
+               ret = -EBUSY;
+               goto err;
+       }
 
        priv->int_buf.in_use = true;
 
@@ -163,13 +171,18 @@ int vnt_start_interrupt_urb(struct vnt_private *priv)
                         priv,
                         priv->int_interval);
 
-       status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC);
-       if (status) {
-               dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status);
-               priv->int_buf.in_use = false;
+       ret = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC);
+       if (ret) {
+               dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", ret);
+               goto err_submit;
        }
 
-       return status;
+       return 0;
+
+err_submit:
+       priv->int_buf.in_use = false;
+err:
+       return ret;
 }
 
 static void vnt_submit_rx_urb_complete(struct urb *urb)
@@ -215,12 +228,13 @@ static void vnt_submit_rx_urb_complete(struct urb *urb)
 
 int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb)
 {
-       int status = 0;
+       int ret = 0;
        struct urb *urb = rcb->urb;
 
        if (!rcb->skb) {
                dev_dbg(&priv->usb->dev, "rcb->skb is null\n");
-               return status;
+               ret = -EINVAL;
+               goto end;
        }
 
        usb_fill_bulk_urb(urb,
@@ -231,15 +245,16 @@ int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb)
                          vnt_submit_rx_urb_complete,
                          rcb);
 
-       status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (status) {
-               dev_dbg(&priv->usb->dev, "Submit Rx URB failed %d\n", status);
-               return STATUS_FAILURE;
+       ret = usb_submit_urb(urb, GFP_ATOMIC);
+       if (ret) {
+               dev_dbg(&priv->usb->dev, "Submit Rx URB failed %d\n", ret);
+               goto end;
        }
 
        rcb->in_use = true;
 
-       return status;
+end:
+       return ret;
 }
 
 static void vnt_tx_context_complete(struct urb *urb)
index 2910ca5..95147ec 100644 (file)
@@ -23,8 +23,8 @@ int vnt_control_out(struct vnt_private *priv, u8 request, u16 value,
 int vnt_control_in(struct vnt_private *priv, u8 request, u16 value,
                   u16 index, u16 length,  u8 *buffer);
 
-void vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 ref_off, u8 data);
-void vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data);
+int vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 ref_off, u8 data);
+int vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data);
 
 int vnt_start_interrupt_urb(struct vnt_private *priv);
 int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb);
index 2ad3fee..a5a8e80 100644 (file)
@@ -5,7 +5,7 @@ ccflags-y += -DFIRMWARE_1002=\"atmel/wilc1002_firmware.bin\" \
                -DFIRMWARE_1003=\"atmel/wilc1003_firmware.bin\"
 
 wilc1000-objs := wilc_wfi_cfgoperations.o wilc_netdev.o wilc_mon.o \
-                       host_interface.o wilc_wlan_cfg.o wilc_wlan.o
+                       wilc_hif.o wilc_wlan_cfg.o wilc_wlan.o
 
 obj-$(CONFIG_WILC1000_SDIO) += wilc1000-sdio.o
 wilc1000-sdio-objs += wilc_sdio.o
diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c
deleted file mode 100644 (file)
index ed15bd1..0000000
+++ /dev/null
@@ -1,2137 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
- * All rights reserved.
- */
-
-#include "wilc_wfi_netdevice.h"
-
-#define WILC_HIF_SCAN_TIMEOUT_MS                4000
-#define WILC_HIF_CONNECT_TIMEOUT_MS             9500
-
-#define WILC_FALSE_FRMWR_CHANNEL               100
-#define WILC_MAX_RATES_SUPPORTED               12
-
-struct wilc_rcvd_mac_info {
-       u8 status;
-};
-
-struct wilc_set_multicast {
-       u32 enabled;
-       u32 cnt;
-       u8 *mc_list;
-};
-
-struct wilc_del_all_sta {
-       u8 assoc_sta;
-       u8 mac[WILC_MAX_NUM_STA][ETH_ALEN];
-};
-
-struct wilc_op_mode {
-       __le32 mode;
-};
-
-struct wilc_reg_frame {
-       bool reg;
-       u8 reg_id;
-       __le16 frame_type;
-} __packed;
-
-struct wilc_drv_handler {
-       __le32 handler;
-       u8 mode;
-} __packed;
-
-struct wilc_wep_key {
-       u8 index;
-       u8 key_len;
-       u8 key[0];
-} __packed;
-
-struct wilc_sta_wpa_ptk {
-       u8 mac_addr[ETH_ALEN];
-       u8 key_len;
-       u8 key[0];
-} __packed;
-
-struct wilc_ap_wpa_ptk {
-       u8 mac_addr[ETH_ALEN];
-       u8 index;
-       u8 key_len;
-       u8 key[0];
-} __packed;
-
-struct wilc_gtk_key {
-       u8 mac_addr[ETH_ALEN];
-       u8 rsc[8];
-       u8 index;
-       u8 key_len;
-       u8 key[0];
-} __packed;
-
-union wilc_message_body {
-       struct wilc_rcvd_net_info net_info;
-       struct wilc_rcvd_mac_info mac_info;
-       struct wilc_set_multicast mc_info;
-       struct wilc_remain_ch remain_on_ch;
-       char *data;
-};
-
-struct host_if_msg {
-       union wilc_message_body body;
-       struct wilc_vif *vif;
-       struct work_struct work;
-       void (*fn)(struct work_struct *ws);
-       struct completion work_comp;
-       bool is_sync;
-};
-
-struct wilc_noa_opp_enable {
-       u8 ct_window;
-       u8 cnt;
-       __le32 duration;
-       __le32 interval;
-       __le32 start_time;
-} __packed;
-
-struct wilc_noa_opp_disable {
-       u8 cnt;
-       __le32 duration;
-       __le32 interval;
-       __le32 start_time;
-} __packed;
-
-struct wilc_join_bss_param {
-       char ssid[IEEE80211_MAX_SSID_LEN];
-       u8 ssid_terminator;
-       u8 bss_type;
-       u8 ch;
-       __le16 cap_info;
-       u8 sa[ETH_ALEN];
-       u8 bssid[ETH_ALEN];
-       __le16 beacon_period;
-       u8 dtim_period;
-       u8 supp_rates[WILC_MAX_RATES_SUPPORTED + 1];
-       u8 wmm_cap;
-       u8 uapsd_cap;
-       u8 ht_capable;
-       u8 rsn_found;
-       u8 rsn_grp_policy;
-       u8 mode_802_11i;
-       u8 p_suites[3];
-       u8 akm_suites[3];
-       u8 rsn_cap[2];
-       u8 noa_enabled;
-       __le32 tsf_lo;
-       u8 idx;
-       u8 opp_enabled;
-       union {
-               struct wilc_noa_opp_disable opp_dis;
-               struct wilc_noa_opp_enable opp_en;
-       };
-} __packed;
-
-/* 'msg' should be free by the caller for syc */
-static struct host_if_msg*
-wilc_alloc_work(struct wilc_vif *vif, void (*work_fun)(struct work_struct *),
-               bool is_sync)
-{
-       struct host_if_msg *msg;
-
-       if (!work_fun)
-               return ERR_PTR(-EINVAL);
-
-       msg = kzalloc(sizeof(*msg), GFP_ATOMIC);
-       if (!msg)
-               return ERR_PTR(-ENOMEM);
-       msg->fn = work_fun;
-       msg->vif = vif;
-       msg->is_sync = is_sync;
-       if (is_sync)
-               init_completion(&msg->work_comp);
-
-       return msg;
-}
-
-static int wilc_enqueue_work(struct host_if_msg *msg)
-{
-       INIT_WORK(&msg->work, msg->fn);
-
-       if (!msg->vif || !msg->vif->wilc || !msg->vif->wilc->hif_workqueue)
-               return -EINVAL;
-
-       if (!queue_work(msg->vif->wilc->hif_workqueue, &msg->work))
-               return -EINVAL;
-
-       return 0;
-}
-
-/* The idx starts from 0 to (NUM_CONCURRENT_IFC - 1), but 0 index used as
- * special purpose in wilc device, so we add 1 to the index to starts from 1.
- * As a result, the returned index will be 1 to NUM_CONCURRENT_IFC.
- */
-int wilc_get_vif_idx(struct wilc_vif *vif)
-{
-       return vif->idx + 1;
-}
-
-/* We need to minus 1 from idx which is from wilc device to get real index
- * of wilc->vif[], because we add 1 when pass to wilc device in the function
- * wilc_get_vif_idx.
- * As a result, the index should be between 0 and (NUM_CONCURRENT_IFC - 1).
- */
-static struct wilc_vif *wilc_get_vif_from_idx(struct wilc *wilc, int idx)
-{
-       int index = idx - 1;
-
-       if (index < 0 || index >= WILC_NUM_CONCURRENT_IFC)
-               return NULL;
-
-       return wilc->vif[index];
-}
-
-static int handle_scan_done(struct wilc_vif *vif, enum scan_event evt)
-{
-       int result = 0;
-       u8 abort_running_scan;
-       struct wid wid;
-       struct host_if_drv *hif_drv = vif->hif_drv;
-       struct wilc_user_scan_req *scan_req;
-
-       if (evt == SCAN_EVENT_ABORTED) {
-               abort_running_scan = 1;
-               wid.id = WID_ABORT_RUNNING_SCAN;
-               wid.type = WID_CHAR;
-               wid.val = (s8 *)&abort_running_scan;
-               wid.size = sizeof(char);
-
-               result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                             wilc_get_vif_idx(vif));
-
-               if (result) {
-                       netdev_err(vif->ndev, "Failed to set abort running\n");
-                       result = -EFAULT;
-               }
-       }
-
-       if (!hif_drv) {
-               netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);
-               return result;
-       }
-
-       scan_req = &hif_drv->usr_scan_req;
-       if (scan_req->scan_result) {
-               scan_req->scan_result(evt, NULL, scan_req->arg);
-               scan_req->scan_result = NULL;
-       }
-
-       return result;
-}
-
-int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
-             u8 *ch_freq_list, u8 ch_list_len,
-             void (*scan_result_fn)(enum scan_event,
-                                    struct wilc_rcvd_net_info *, void *),
-             void *user_arg, struct cfg80211_scan_request *request)
-{
-       int result = 0;
-       struct wid wid_list[5];
-       u32 index = 0;
-       u32 i;
-       u8 *buffer;
-       u8 valuesize = 0;
-       u8 *search_ssid_vals = NULL;
-       struct host_if_drv *hif_drv = vif->hif_drv;
-
-       if (hif_drv->hif_state >= HOST_IF_SCANNING &&
-           hif_drv->hif_state < HOST_IF_CONNECTED) {
-               netdev_err(vif->ndev, "Already scan\n");
-               result = -EBUSY;
-               goto error;
-       }
-
-       if (vif->obtaining_ip || vif->connecting) {
-               netdev_err(vif->ndev, "Don't do obss scan\n");
-               result = -EBUSY;
-               goto error;
-       }
-
-       hif_drv->usr_scan_req.ch_cnt = 0;
-
-       if (request->n_ssids) {
-               for (i = 0; i < request->n_ssids; i++)
-                       valuesize += ((request->ssids[i].ssid_len) + 1);
-               search_ssid_vals = kmalloc(valuesize + 1, GFP_KERNEL);
-               if (search_ssid_vals) {
-                       wid_list[index].id = WID_SSID_PROBE_REQ;
-                       wid_list[index].type = WID_STR;
-                       wid_list[index].val = search_ssid_vals;
-                       buffer = wid_list[index].val;
-
-                       *buffer++ = request->n_ssids;
-
-                       for (i = 0; i < request->n_ssids; i++) {
-                               *buffer++ = request->ssids[i].ssid_len;
-                               memcpy(buffer, request->ssids[i].ssid,
-                                      request->ssids[i].ssid_len);
-                               buffer += request->ssids[i].ssid_len;
-                       }
-                       wid_list[index].size = (s32)(valuesize + 1);
-                       index++;
-               }
-       }
-
-       wid_list[index].id = WID_INFO_ELEMENT_PROBE;
-       wid_list[index].type = WID_BIN_DATA;
-       wid_list[index].val = (s8 *)request->ie;
-       wid_list[index].size = request->ie_len;
-       index++;
-
-       wid_list[index].id = WID_SCAN_TYPE;
-       wid_list[index].type = WID_CHAR;
-       wid_list[index].size = sizeof(char);
-       wid_list[index].val = (s8 *)&scan_type;
-       index++;
-
-       wid_list[index].id = WID_SCAN_CHANNEL_LIST;
-       wid_list[index].type = WID_BIN_DATA;
-
-       if (ch_freq_list && ch_list_len > 0) {
-               for (i = 0; i < ch_list_len; i++) {
-                       if (ch_freq_list[i] > 0)
-                               ch_freq_list[i] -= 1;
-               }
-       }
-
-       wid_list[index].val = ch_freq_list;
-       wid_list[index].size = ch_list_len;
-       index++;
-
-       wid_list[index].id = WID_START_SCAN_REQ;
-       wid_list[index].type = WID_CHAR;
-       wid_list[index].size = sizeof(char);
-       wid_list[index].val = (s8 *)&scan_source;
-       index++;
-
-       hif_drv->usr_scan_req.scan_result = scan_result_fn;
-       hif_drv->usr_scan_req.arg = user_arg;
-
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
-                                     index,
-                                     wilc_get_vif_idx(vif));
-       if (result) {
-               netdev_err(vif->ndev, "Failed to send scan parameters\n");
-               goto error;
-       }
-
-       hif_drv->scan_timer_vif = vif;
-       mod_timer(&hif_drv->scan_timer,
-                 jiffies + msecs_to_jiffies(WILC_HIF_SCAN_TIMEOUT_MS));
-
-error:
-
-       kfree(search_ssid_vals);
-
-       return result;
-}
-
-static int wilc_send_connect_wid(struct wilc_vif *vif)
-{
-       int result = 0;
-       struct wid wid_list[4];
-       u32 wid_cnt = 0;
-       struct host_if_drv *hif_drv = vif->hif_drv;
-       struct wilc_conn_info *conn_attr = &hif_drv->conn_info;
-       struct wilc_join_bss_param *bss_param = conn_attr->param;
-
-       wid_list[wid_cnt].id = WID_INFO_ELEMENT_ASSOCIATE;
-       wid_list[wid_cnt].type = WID_BIN_DATA;
-       wid_list[wid_cnt].val = conn_attr->req_ies;
-       wid_list[wid_cnt].size = conn_attr->req_ies_len;
-       wid_cnt++;
-
-       wid_list[wid_cnt].id = WID_11I_MODE;
-       wid_list[wid_cnt].type = WID_CHAR;
-       wid_list[wid_cnt].size = sizeof(char);
-       wid_list[wid_cnt].val = (s8 *)&conn_attr->security;
-       wid_cnt++;
-
-       wid_list[wid_cnt].id = WID_AUTH_TYPE;
-       wid_list[wid_cnt].type = WID_CHAR;
-       wid_list[wid_cnt].size = sizeof(char);
-       wid_list[wid_cnt].val = (s8 *)&conn_attr->auth_type;
-       wid_cnt++;
-
-       wid_list[wid_cnt].id = WID_JOIN_REQ_EXTENDED;
-       wid_list[wid_cnt].type = WID_STR;
-       wid_list[wid_cnt].size = sizeof(*bss_param);
-       wid_list[wid_cnt].val = (u8 *)bss_param;
-       wid_cnt++;
-
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
-                                     wid_cnt,
-                                     wilc_get_vif_idx(vif));
-       if (result) {
-               netdev_err(vif->ndev, "failed to send config packet\n");
-               goto error;
-       } else {
-               hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP;
-       }
-
-       return 0;
-
-error:
-
-       kfree(conn_attr->req_ies);
-       conn_attr->req_ies = NULL;
-
-       return result;
-}
-
-static void handle_connect_timeout(struct work_struct *work)
-{
-       struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
-       struct wilc_vif *vif = msg->vif;
-       int result;
-       struct wid wid;
-       u16 dummy_reason_code = 0;
-       struct host_if_drv *hif_drv = vif->hif_drv;
-
-       if (!hif_drv) {
-               netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);
-               goto out;
-       }
-
-       hif_drv->hif_state = HOST_IF_IDLE;
-
-       if (hif_drv->conn_info.conn_result) {
-               hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_CONN_RESP,
-                                              WILC_MAC_STATUS_DISCONNECTED,
-                                              hif_drv->conn_info.arg);
-
-       } else {
-               netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
-       }
-
-       wid.id = WID_DISCONNECT;
-       wid.type = WID_CHAR;
-       wid.val = (s8 *)&dummy_reason_code;
-       wid.size = sizeof(char);
-
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       if (result)
-               netdev_err(vif->ndev, "Failed to send disconnect\n");
-
-       hif_drv->conn_info.req_ies_len = 0;
-       kfree(hif_drv->conn_info.req_ies);
-       hif_drv->conn_info.req_ies = NULL;
-
-out:
-       kfree(msg);
-}
-
-void *wilc_parse_join_bss_param(struct cfg80211_bss *bss,
-                               struct cfg80211_crypto_settings *crypto)
-{
-       struct wilc_join_bss_param *param;
-       struct ieee80211_p2p_noa_attr noa_attr;
-       u8 rates_len = 0;
-       const u8 *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie;
-       const u8 *ht_ie, *wpa_ie, *wmm_ie, *rsn_ie;
-       int ret;
-       const struct cfg80211_bss_ies *ies = rcu_dereference(bss->ies);
-
-       param = kzalloc(sizeof(*param), GFP_KERNEL);
-       if (!param)
-               return NULL;
-
-       param->beacon_period = cpu_to_le16(bss->beacon_interval);
-       param->cap_info = cpu_to_le16(bss->capability);
-       param->bss_type = WILC_FW_BSS_TYPE_INFRA;
-       param->ch = ieee80211_frequency_to_channel(bss->channel->center_freq);
-       ether_addr_copy(param->bssid, bss->bssid);
-
-       ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
-       if (ssid_elm) {
-               if (ssid_elm[1] <= IEEE80211_MAX_SSID_LEN)
-                       memcpy(param->ssid, ssid_elm + 2, ssid_elm[1]);
-       }
-
-       tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len);
-       if (tim_elm && tim_elm[1] >= 2)
-               param->dtim_period = tim_elm[3];
-
-       memset(param->p_suites, 0xFF, 3);
-       memset(param->akm_suites, 0xFF, 3);
-
-       rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies->data, ies->len);
-       if (rates_ie) {
-               rates_len = rates_ie[1];
-               param->supp_rates[0] = rates_len;
-               memcpy(&param->supp_rates[1], rates_ie + 2, rates_len);
-       }
-
-       supp_rates_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies->data,
-                                        ies->len);
-       if (supp_rates_ie) {
-               if (supp_rates_ie[1] > (WILC_MAX_RATES_SUPPORTED - rates_len))
-                       param->supp_rates[0] = WILC_MAX_RATES_SUPPORTED;
-               else
-                       param->supp_rates[0] += supp_rates_ie[1];
-
-               memcpy(&param->supp_rates[rates_len + 1], supp_rates_ie + 2,
-                      (param->supp_rates[0] - rates_len));
-       }
-
-       ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies->data, ies->len);
-       if (ht_ie)
-               param->ht_capable = true;
-
-       ret = cfg80211_get_p2p_attr(ies->data, ies->len,
-                                   IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
-                                   (u8 *)&noa_attr, sizeof(noa_attr));
-       if (ret > 0) {
-               param->tsf_lo = cpu_to_le32(ies->tsf);
-               param->noa_enabled = 1;
-               param->idx = noa_attr.index;
-               if (noa_attr.oppps_ctwindow & IEEE80211_P2P_OPPPS_ENABLE_BIT) {
-                       param->opp_enabled = 1;
-                       param->opp_en.ct_window = noa_attr.oppps_ctwindow;
-                       param->opp_en.cnt = noa_attr.desc[0].count;
-                       param->opp_en.duration = noa_attr.desc[0].duration;
-                       param->opp_en.interval = noa_attr.desc[0].interval;
-                       param->opp_en.start_time = noa_attr.desc[0].start_time;
-               } else {
-                       param->opp_enabled = 0;
-                       param->opp_dis.cnt = noa_attr.desc[0].count;
-                       param->opp_dis.duration = noa_attr.desc[0].duration;
-                       param->opp_dis.interval = noa_attr.desc[0].interval;
-                       param->opp_dis.start_time = noa_attr.desc[0].start_time;
-               }
-       }
-       wmm_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
-                                        WLAN_OUI_TYPE_MICROSOFT_WMM,
-                                        ies->data, ies->len);
-       if (wmm_ie) {
-               struct ieee80211_wmm_param_ie *ie;
-
-               ie = (struct ieee80211_wmm_param_ie *)wmm_ie;
-               if ((ie->oui_subtype == 0 || ie->oui_subtype == 1) &&
-                   ie->version == 1) {
-                       param->wmm_cap = true;
-                       if (ie->qos_info & BIT(7))
-                               param->uapsd_cap = true;
-               }
-       }
-
-       wpa_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
-                                        WLAN_OUI_TYPE_MICROSOFT_WPA,
-                                        ies->data, ies->len);
-       if (wpa_ie) {
-               param->mode_802_11i = 1;
-               param->rsn_found = true;
-       }
-
-       rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies->data, ies->len);
-       if (rsn_ie) {
-               int offset = 8;
-
-               param->mode_802_11i = 2;
-               param->rsn_found = true;
-               //extract RSN capabilities
-               offset += (rsn_ie[offset] * 4) + 2;
-               offset += (rsn_ie[offset] * 4) + 2;
-               memcpy(param->rsn_cap, &rsn_ie[offset], 2);
-       }
-
-       if (param->rsn_found) {
-               int i;
-
-               param->rsn_grp_policy = crypto->cipher_group & 0xFF;
-               for (i = 0; i < crypto->n_ciphers_pairwise && i < 3; i++)
-                       param->p_suites[i] = crypto->ciphers_pairwise[i] & 0xFF;
-
-               for (i = 0; i < crypto->n_akm_suites && i < 3; i++)
-                       param->akm_suites[i] = crypto->akm_suites[i] & 0xFF;
-       }
-
-       return (void *)param;
-}
-
-static void handle_rcvd_ntwrk_info(struct work_struct *work)
-{
-       struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
-       struct wilc_rcvd_net_info *rcvd_info = &msg->body.net_info;
-       struct wilc_user_scan_req *scan_req = &msg->vif->hif_drv->usr_scan_req;
-       const u8 *ch_elm;
-       u8 *ies;
-       int ies_len;
-       size_t offset;
-
-       if (ieee80211_is_probe_resp(rcvd_info->mgmt->frame_control))
-               offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
-       else if (ieee80211_is_beacon(rcvd_info->mgmt->frame_control))
-               offset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
-       else
-               goto done;
-
-       ies = rcvd_info->mgmt->u.beacon.variable;
-       ies_len = rcvd_info->frame_len - offset;
-       if (ies_len <= 0)
-               goto done;
-
-       ch_elm = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ies, ies_len);
-       if (ch_elm && ch_elm[1] > 0)
-               rcvd_info->ch = ch_elm[2];
-
-       if (scan_req->scan_result)
-               scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, rcvd_info,
-                                     scan_req->arg);
-
-done:
-       kfree(rcvd_info->mgmt);
-       kfree(msg);
-}
-
-static void host_int_get_assoc_res_info(struct wilc_vif *vif,
-                                       u8 *assoc_resp_info,
-                                       u32 max_assoc_resp_info_len,
-                                       u32 *rcvd_assoc_resp_info_len)
-{
-       int result;
-       struct wid wid;
-
-       wid.id = WID_ASSOC_RES_INFO;
-       wid.type = WID_STR;
-       wid.val = assoc_resp_info;
-       wid.size = max_assoc_resp_info_len;
-
-       result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       if (result) {
-               *rcvd_assoc_resp_info_len = 0;
-               netdev_err(vif->ndev, "Failed to send association response\n");
-               return;
-       }
-
-       *rcvd_assoc_resp_info_len = wid.size;
-}
-
-static s32 wilc_parse_assoc_resp_info(u8 *buffer, u32 buffer_len,
-                                     struct wilc_conn_info *ret_conn_info)
-{
-       u8 *ies;
-       u16 ies_len;
-       struct assoc_resp *res = (struct assoc_resp *)buffer;
-
-       ret_conn_info->status = le16_to_cpu(res->status_code);
-       if (ret_conn_info->status == WLAN_STATUS_SUCCESS) {
-               ies = &buffer[sizeof(*res)];
-               ies_len = buffer_len - sizeof(*res);
-
-               ret_conn_info->resp_ies = kmemdup(ies, ies_len, GFP_KERNEL);
-               if (!ret_conn_info->resp_ies)
-                       return -ENOMEM;
-
-               ret_conn_info->resp_ies_len = ies_len;
-       }
-
-       return 0;
-}
-
-static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif,
-                                                 u8 mac_status)
-{
-       struct host_if_drv *hif_drv = vif->hif_drv;
-       struct wilc_conn_info *conn_info = &hif_drv->conn_info;
-
-       if (mac_status == WILC_MAC_STATUS_CONNECTED) {
-               u32 assoc_resp_info_len;
-
-               memset(hif_drv->assoc_resp, 0, WILC_MAX_ASSOC_RESP_FRAME_SIZE);
-
-               host_int_get_assoc_res_info(vif, hif_drv->assoc_resp,
-                                           WILC_MAX_ASSOC_RESP_FRAME_SIZE,
-                                           &assoc_resp_info_len);
-
-               if (assoc_resp_info_len != 0) {
-                       s32 err = 0;
-
-                       err = wilc_parse_assoc_resp_info(hif_drv->assoc_resp,
-                                                        assoc_resp_info_len,
-                                                        conn_info);
-                       if (err)
-                               netdev_err(vif->ndev,
-                                          "wilc_parse_assoc_resp_info() returned error %d\n",
-                                          err);
-               }
-       }
-
-       del_timer(&hif_drv->connect_timer);
-       conn_info->conn_result(CONN_DISCONN_EVENT_CONN_RESP, mac_status,
-                              hif_drv->conn_info.arg);
-
-       if (mac_status == WILC_MAC_STATUS_CONNECTED &&
-           conn_info->status == WLAN_STATUS_SUCCESS) {
-               ether_addr_copy(hif_drv->assoc_bssid, conn_info->bssid);
-               wilc_set_power_mgmt(vif, 0, 0);
-
-               hif_drv->hif_state = HOST_IF_CONNECTED;
-
-               vif->obtaining_ip = true;
-               mod_timer(&vif->during_ip_timer,
-                         jiffies + msecs_to_jiffies(10000));
-       } else {
-               hif_drv->hif_state = HOST_IF_IDLE;
-       }
-
-       kfree(conn_info->resp_ies);
-       conn_info->resp_ies = NULL;
-       conn_info->resp_ies_len = 0;
-
-       kfree(conn_info->req_ies);
-       conn_info->req_ies = NULL;
-       conn_info->req_ies_len = 0;
-}
-
-static inline void host_int_handle_disconnect(struct wilc_vif *vif)
-{
-       struct host_if_drv *hif_drv = vif->hif_drv;
-
-       if (hif_drv->usr_scan_req.scan_result) {
-               del_timer(&hif_drv->scan_timer);
-               handle_scan_done(vif, SCAN_EVENT_ABORTED);
-       }
-
-       if (hif_drv->conn_info.conn_result) {
-               vif->obtaining_ip = false;
-               wilc_set_power_mgmt(vif, 0, 0);
-
-               hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF,
-                                              0, hif_drv->conn_info.arg);
-       } else {
-               netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
-       }
-
-       eth_zero_addr(hif_drv->assoc_bssid);
-
-       hif_drv->conn_info.req_ies_len = 0;
-       kfree(hif_drv->conn_info.req_ies);
-       hif_drv->conn_info.req_ies = NULL;
-       hif_drv->hif_state = HOST_IF_IDLE;
-}
-
-static void handle_rcvd_gnrl_async_info(struct work_struct *work)
-{
-       struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
-       struct wilc_vif *vif = msg->vif;
-       struct wilc_rcvd_mac_info *mac_info = &msg->body.mac_info;
-       struct host_if_drv *hif_drv = vif->hif_drv;
-
-       if (!hif_drv) {
-               netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);
-               goto free_msg;
-       }
-
-       if (!hif_drv->conn_info.conn_result) {
-               netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
-               goto free_msg;
-       }
-
-       if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) {
-               host_int_parse_assoc_resp_info(vif, mac_info->status);
-       } else if (mac_info->status == WILC_MAC_STATUS_DISCONNECTED) {
-               if (hif_drv->hif_state == HOST_IF_CONNECTED) {
-                       host_int_handle_disconnect(vif);
-               } else if (hif_drv->usr_scan_req.scan_result) {
-                       del_timer(&hif_drv->scan_timer);
-                       handle_scan_done(vif, SCAN_EVENT_ABORTED);
-               }
-       }
-
-free_msg:
-       kfree(msg);
-}
-
-int wilc_disconnect(struct wilc_vif *vif)
-{
-       struct wid wid;
-       struct host_if_drv *hif_drv = vif->hif_drv;
-       struct wilc_user_scan_req *scan_req;
-       struct wilc_conn_info *conn_info;
-       int result;
-       u16 dummy_reason_code = 0;
-
-       wid.id = WID_DISCONNECT;
-       wid.type = WID_CHAR;
-       wid.val = (s8 *)&dummy_reason_code;
-       wid.size = sizeof(char);
-
-       vif->obtaining_ip = false;
-       wilc_set_power_mgmt(vif, 0, 0);
-
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       if (result) {
-               netdev_err(vif->ndev, "Failed to send disconnect\n");
-               return result;
-       }
-
-       scan_req = &hif_drv->usr_scan_req;
-       conn_info = &hif_drv->conn_info;
-
-       if (scan_req->scan_result) {
-               del_timer(&hif_drv->scan_timer);
-               scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->arg);
-               scan_req->scan_result = NULL;
-       }
-
-       if (conn_info->conn_result) {
-               if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP)
-                       del_timer(&hif_drv->connect_timer);
-
-               conn_info->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, 0,
-                                      conn_info->arg);
-       } else {
-               netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
-       }
-
-       hif_drv->hif_state = HOST_IF_IDLE;
-
-       eth_zero_addr(hif_drv->assoc_bssid);
-
-       conn_info->req_ies_len = 0;
-       kfree(conn_info->req_ies);
-       conn_info->req_ies = NULL;
-
-       return 0;
-}
-
-void wilc_resolve_disconnect_aberration(struct wilc_vif *vif)
-{
-       if (!vif->hif_drv)
-               return;
-       if (vif->hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP ||
-           vif->hif_drv->hif_state == HOST_IF_CONNECTING)
-               wilc_disconnect(vif);
-}
-
-int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats)
-{
-       struct wid wid_list[5];
-       u32 wid_cnt = 0, result;
-
-       wid_list[wid_cnt].id = WID_LINKSPEED;
-       wid_list[wid_cnt].type = WID_CHAR;
-       wid_list[wid_cnt].size = sizeof(char);
-       wid_list[wid_cnt].val = (s8 *)&stats->link_speed;
-       wid_cnt++;
-
-       wid_list[wid_cnt].id = WID_RSSI;
-       wid_list[wid_cnt].type = WID_CHAR;
-       wid_list[wid_cnt].size = sizeof(char);
-       wid_list[wid_cnt].val = (s8 *)&stats->rssi;
-       wid_cnt++;
-
-       wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT;
-       wid_list[wid_cnt].type = WID_INT;
-       wid_list[wid_cnt].size = sizeof(u32);
-       wid_list[wid_cnt].val = (s8 *)&stats->tx_cnt;
-       wid_cnt++;
-
-       wid_list[wid_cnt].id = WID_RECEIVED_FRAGMENT_COUNT;
-       wid_list[wid_cnt].type = WID_INT;
-       wid_list[wid_cnt].size = sizeof(u32);
-       wid_list[wid_cnt].val = (s8 *)&stats->rx_cnt;
-       wid_cnt++;
-
-       wid_list[wid_cnt].id = WID_FAILED_COUNT;
-       wid_list[wid_cnt].type = WID_INT;
-       wid_list[wid_cnt].size = sizeof(u32);
-       wid_list[wid_cnt].val = (s8 *)&stats->tx_fail_cnt;
-       wid_cnt++;
-
-       result = wilc_send_config_pkt(vif, WILC_GET_CFG, wid_list,
-                                     wid_cnt,
-                                     wilc_get_vif_idx(vif));
-
-       if (result) {
-               netdev_err(vif->ndev, "Failed to send scan parameters\n");
-               return result;
-       }
-
-       if (stats->link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH &&
-           stats->link_speed != DEFAULT_LINK_SPEED)
-               wilc_enable_tcp_ack_filter(vif, true);
-       else if (stats->link_speed != DEFAULT_LINK_SPEED)
-               wilc_enable_tcp_ack_filter(vif, false);
-
-       return result;
-}
-
-static void handle_get_statistics(struct work_struct *work)
-{
-       struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
-       struct wilc_vif *vif = msg->vif;
-       struct rf_info *stats = (struct rf_info *)msg->body.data;
-
-       wilc_get_statistics(vif, stats);
-
-       kfree(msg);
-}
-
-static void wilc_hif_pack_sta_param(u8 *cur_byte, const u8 *mac,
-                                   struct station_parameters *params)
-{
-       ether_addr_copy(cur_byte, mac);
-       cur_byte += ETH_ALEN;
-
-       put_unaligned_le16(params->aid, cur_byte);
-       cur_byte += 2;
-
-       *cur_byte++ = params->supported_rates_len;
-       if (params->supported_rates_len > 0)
-               memcpy(cur_byte, params->supported_rates,
-                      params->supported_rates_len);
-       cur_byte += params->supported_rates_len;
-
-       if (params->ht_capa) {
-               *cur_byte++ = true;
-               memcpy(cur_byte, &params->ht_capa,
-                      sizeof(struct ieee80211_ht_cap));
-       } else {
-               *cur_byte++ = false;
-       }
-       cur_byte += sizeof(struct ieee80211_ht_cap);
-
-       put_unaligned_le16(params->sta_flags_mask, cur_byte);
-       cur_byte += 2;
-       put_unaligned_le16(params->sta_flags_set, cur_byte);
-}
-
-static int handle_remain_on_chan(struct wilc_vif *vif,
-                                struct wilc_remain_ch *hif_remain_ch)
-{
-       int result;
-       u8 remain_on_chan_flag;
-       struct wid wid;
-       struct host_if_drv *hif_drv = vif->hif_drv;
-
-       if (hif_drv->usr_scan_req.scan_result)
-               return -EBUSY;
-
-       if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP)
-               return -EBUSY;
-
-       if (vif->obtaining_ip || vif->connecting)
-               return -EBUSY;
-
-       remain_on_chan_flag = true;
-       wid.id = WID_REMAIN_ON_CHAN;
-       wid.type = WID_STR;
-       wid.size = 2;
-       wid.val = kmalloc(wid.size, GFP_KERNEL);
-       if (!wid.val)
-               return -ENOMEM;
-
-       wid.val[0] = remain_on_chan_flag;
-       wid.val[1] = (s8)hif_remain_ch->ch;
-
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       kfree(wid.val);
-       if (result)
-               return -EBUSY;
-
-       hif_drv->remain_on_ch.arg = hif_remain_ch->arg;
-       hif_drv->remain_on_ch.expired = hif_remain_ch->expired;
-       hif_drv->remain_on_ch.ch = hif_remain_ch->ch;
-       hif_drv->remain_on_ch.cookie = hif_remain_ch->cookie;
-       hif_drv->remain_on_ch_timer_vif = vif;
-
-       return 0;
-}
-
-static void handle_listen_state_expired(struct work_struct *work)
-{
-       struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
-       struct wilc_vif *vif = msg->vif;
-       struct wilc_remain_ch *hif_remain_ch = &msg->body.remain_on_ch;
-       u8 remain_on_chan_flag;
-       struct wid wid;
-       int result;
-       struct host_if_drv *hif_drv = vif->hif_drv;
-       struct wilc_priv *priv = wdev_priv(vif->ndev->ieee80211_ptr);
-
-       if (priv->p2p_listen_state) {
-               remain_on_chan_flag = false;
-               wid.id = WID_REMAIN_ON_CHAN;
-               wid.type = WID_STR;
-               wid.size = 2;
-               wid.val = kmalloc(wid.size, GFP_KERNEL);
-
-               if (!wid.val)
-                       goto free_msg;
-
-               wid.val[0] = remain_on_chan_flag;
-               wid.val[1] = WILC_FALSE_FRMWR_CHANNEL;
-
-               result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                             wilc_get_vif_idx(vif));
-               kfree(wid.val);
-               if (result != 0) {
-                       netdev_err(vif->ndev, "Failed to set remain channel\n");
-                       goto free_msg;
-               }
-
-               if (hif_drv->remain_on_ch.expired) {
-                       hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.arg,
-                                                     hif_remain_ch->cookie);
-               }
-       } else {
-               netdev_dbg(vif->ndev, "Not in listen state\n");
-       }
-
-free_msg:
-       kfree(msg);
-}
-
-static void listen_timer_cb(struct timer_list *t)
-{
-       struct host_if_drv *hif_drv = from_timer(hif_drv, t,
-                                                     remain_on_ch_timer);
-       struct wilc_vif *vif = hif_drv->remain_on_ch_timer_vif;
-       int result;
-       struct host_if_msg *msg;
-
-       del_timer(&vif->hif_drv->remain_on_ch_timer);
-
-       msg = wilc_alloc_work(vif, handle_listen_state_expired, false);
-       if (IS_ERR(msg))
-               return;
-
-       msg->body.remain_on_ch.cookie = vif->hif_drv->remain_on_ch.cookie;
-
-       result = wilc_enqueue_work(msg);
-       if (result) {
-               netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
-               kfree(msg);
-       }
-}
-
-static void handle_set_mcast_filter(struct work_struct *work)
-{
-       struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
-       struct wilc_vif *vif = msg->vif;
-       struct wilc_set_multicast *set_mc = &msg->body.mc_info;
-       int result;
-       struct wid wid;
-       u8 *cur_byte;
-
-       wid.id = WID_SETUP_MULTICAST_FILTER;
-       wid.type = WID_BIN;
-       wid.size = sizeof(struct wilc_set_multicast) + (set_mc->cnt * ETH_ALEN);
-       wid.val = kmalloc(wid.size, GFP_KERNEL);
-       if (!wid.val)
-               goto error;
-
-       cur_byte = wid.val;
-       put_unaligned_le32(set_mc->enabled, cur_byte);
-       cur_byte += 4;
-
-       put_unaligned_le32(set_mc->cnt, cur_byte);
-       cur_byte += 4;
-
-       if (set_mc->cnt > 0 && set_mc->mc_list)
-               memcpy(cur_byte, set_mc->mc_list, set_mc->cnt * ETH_ALEN);
-
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       if (result)
-               netdev_err(vif->ndev, "Failed to send setup multicast\n");
-
-error:
-       kfree(set_mc->mc_list);
-       kfree(wid.val);
-       kfree(msg);
-}
-
-static void handle_scan_timer(struct work_struct *work)
-{
-       struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
-
-       handle_scan_done(msg->vif, SCAN_EVENT_ABORTED);
-       kfree(msg);
-}
-
-static void handle_scan_complete(struct work_struct *work)
-{
-       struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
-       struct wilc *wilc = msg->vif->wilc;
-
-       del_timer(&msg->vif->hif_drv->scan_timer);
-
-       if (!wilc_wlan_get_num_conn_ifcs(wilc))
-               wilc_chip_sleep_manually(wilc);
-
-       handle_scan_done(msg->vif, SCAN_EVENT_DONE);
-
-       kfree(msg);
-}
-
-static void timer_scan_cb(struct timer_list *t)
-{
-       struct host_if_drv *hif_drv = from_timer(hif_drv, t, scan_timer);
-       struct wilc_vif *vif = hif_drv->scan_timer_vif;
-       struct host_if_msg *msg;
-       int result;
-
-       msg = wilc_alloc_work(vif, handle_scan_timer, false);
-       if (IS_ERR(msg))
-               return;
-
-       result = wilc_enqueue_work(msg);
-       if (result)
-               kfree(msg);
-}
-
-static void timer_connect_cb(struct timer_list *t)
-{
-       struct host_if_drv *hif_drv = from_timer(hif_drv, t,
-                                                     connect_timer);
-       struct wilc_vif *vif = hif_drv->connect_timer_vif;
-       struct host_if_msg *msg;
-       int result;
-
-       msg = wilc_alloc_work(vif, handle_connect_timeout, false);
-       if (IS_ERR(msg))
-               return;
-
-       result = wilc_enqueue_work(msg);
-       if (result)
-               kfree(msg);
-}
-
-int wilc_remove_wep_key(struct wilc_vif *vif, u8 index)
-{
-       struct wid wid;
-       int result;
-
-       wid.id = WID_REMOVE_WEP_KEY;
-       wid.type = WID_STR;
-       wid.size = sizeof(char);
-       wid.val = &index;
-
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       if (result)
-               netdev_err(vif->ndev,
-                          "Failed to send remove wep key config packet\n");
-       return result;
-}
-
-int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index)
-{
-       struct wid wid;
-       int result;
-
-       wid.id = WID_KEY_ID;
-       wid.type = WID_CHAR;
-       wid.size = sizeof(char);
-       wid.val = &index;
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       if (result)
-               netdev_err(vif->ndev,
-                          "Failed to send wep default key config packet\n");
-
-       return result;
-}
-
-int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
-                            u8 index)
-{
-       struct wid wid;
-       int result;
-       struct wilc_wep_key *wep_key;
-
-       wid.id = WID_ADD_WEP_KEY;
-       wid.type = WID_STR;
-       wid.size = sizeof(*wep_key) + len;
-       wep_key = kzalloc(wid.size, GFP_KERNEL);
-       if (!wep_key)
-               return -ENOMEM;
-
-       wid.val = (u8 *)wep_key;
-
-       wep_key->index = index;
-       wep_key->key_len = len;
-       memcpy(wep_key->key, key, len);
-
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       if (result)
-               netdev_err(vif->ndev,
-                          "Failed to add wep key config packet\n");
-
-       kfree(wep_key);
-       return result;
-}
-
-int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len,
-                           u8 index, u8 mode, enum authtype auth_type)
-{
-       struct wid wid_list[3];
-       int result;
-       struct wilc_wep_key *wep_key;
-
-       wid_list[0].id = WID_11I_MODE;
-       wid_list[0].type = WID_CHAR;
-       wid_list[0].size = sizeof(char);
-       wid_list[0].val = &mode;
-
-       wid_list[1].id = WID_AUTH_TYPE;
-       wid_list[1].type = WID_CHAR;
-       wid_list[1].size = sizeof(char);
-       wid_list[1].val = (s8 *)&auth_type;
-
-       wid_list[2].id = WID_WEP_KEY_VALUE;
-       wid_list[2].type = WID_STR;
-       wid_list[2].size = sizeof(*wep_key) + len;
-       wep_key = kzalloc(wid_list[2].size, GFP_KERNEL);
-       if (!wep_key)
-               return -ENOMEM;
-
-       wid_list[2].val = (u8 *)wep_key;
-
-       wep_key->index = index;
-       wep_key->key_len = len;
-       memcpy(wep_key->key, key, len);
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
-                                     ARRAY_SIZE(wid_list),
-                                     wilc_get_vif_idx(vif));
-       if (result)
-               netdev_err(vif->ndev,
-                          "Failed to add wep ap key config packet\n");
-
-       kfree(wep_key);
-       return result;
-}
-
-int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
-                const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic,
-                u8 mode, u8 cipher_mode, u8 index)
-{
-       int result = 0;
-       u8 t_key_len  = ptk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN;
-
-       if (mode == WILC_AP_MODE) {
-               struct wid wid_list[2];
-               struct wilc_ap_wpa_ptk *key_buf;
-
-               wid_list[0].id = WID_11I_MODE;
-               wid_list[0].type = WID_CHAR;
-               wid_list[0].size = sizeof(char);
-               wid_list[0].val = (s8 *)&cipher_mode;
-
-               key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);
-               if (!key_buf)
-                       return -ENOMEM;
-
-               ether_addr_copy(key_buf->mac_addr, mac_addr);
-               key_buf->index = index;
-               key_buf->key_len = t_key_len;
-               memcpy(&key_buf->key[0], ptk, ptk_key_len);
-
-               if (rx_mic)
-                       memcpy(&key_buf->key[ptk_key_len], rx_mic,
-                              WILC_RX_MIC_KEY_LEN);
-
-               if (tx_mic)
-                       memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN],
-                              tx_mic, WILC_TX_MIC_KEY_LEN);
-
-               wid_list[1].id = WID_ADD_PTK;
-               wid_list[1].type = WID_STR;
-               wid_list[1].size = sizeof(*key_buf) + t_key_len;
-               wid_list[1].val = (u8 *)key_buf;
-               result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
-                                             ARRAY_SIZE(wid_list),
-                                             wilc_get_vif_idx(vif));
-               kfree(key_buf);
-       } else if (mode == WILC_STATION_MODE) {
-               struct wid wid;
-               struct wilc_sta_wpa_ptk *key_buf;
-
-               key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);
-               if (!key_buf)
-                       return -ENOMEM;
-
-               ether_addr_copy(key_buf->mac_addr, mac_addr);
-               key_buf->key_len = t_key_len;
-               memcpy(&key_buf->key[0], ptk, ptk_key_len);
-
-               if (rx_mic)
-                       memcpy(&key_buf->key[ptk_key_len], rx_mic,
-                              WILC_RX_MIC_KEY_LEN);
-
-               if (tx_mic)
-                       memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN],
-                              tx_mic, WILC_TX_MIC_KEY_LEN);
-
-               wid.id = WID_ADD_PTK;
-               wid.type = WID_STR;
-               wid.size = sizeof(*key_buf) + t_key_len;
-               wid.val = (s8 *)key_buf;
-               result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                             wilc_get_vif_idx(vif));
-               kfree(key_buf);
-       }
-
-       return result;
-}
-
-int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
-                   u8 index, u32 key_rsc_len, const u8 *key_rsc,
-                   const u8 *rx_mic, const u8 *tx_mic, u8 mode,
-                   u8 cipher_mode)
-{
-       int result = 0;
-       struct wilc_gtk_key *gtk_key;
-       int t_key_len = gtk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN;
-
-       gtk_key = kzalloc(sizeof(*gtk_key) + t_key_len, GFP_KERNEL);
-       if (!gtk_key)
-               return -ENOMEM;
-
-       /* fill bssid value only in station mode */
-       if (mode == WILC_STATION_MODE &&
-           vif->hif_drv->hif_state == HOST_IF_CONNECTED)
-               memcpy(gtk_key->mac_addr, vif->hif_drv->assoc_bssid, ETH_ALEN);
-
-       if (key_rsc)
-               memcpy(gtk_key->rsc, key_rsc, 8);
-       gtk_key->index = index;
-       gtk_key->key_len = t_key_len;
-       memcpy(&gtk_key->key[0], rx_gtk, gtk_key_len);
-
-       if (rx_mic)
-               memcpy(&gtk_key->key[gtk_key_len], rx_mic, WILC_RX_MIC_KEY_LEN);
-
-       if (tx_mic)
-               memcpy(&gtk_key->key[gtk_key_len + WILC_RX_MIC_KEY_LEN],
-                      tx_mic, WILC_TX_MIC_KEY_LEN);
-
-       if (mode == WILC_AP_MODE) {
-               struct wid wid_list[2];
-
-               wid_list[0].id = WID_11I_MODE;
-               wid_list[0].type = WID_CHAR;
-               wid_list[0].size = sizeof(char);
-               wid_list[0].val = (s8 *)&cipher_mode;
-
-               wid_list[1].id = WID_ADD_RX_GTK;
-               wid_list[1].type = WID_STR;
-               wid_list[1].size = sizeof(*gtk_key) + t_key_len;
-               wid_list[1].val = (u8 *)gtk_key;
-
-               result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
-                                             ARRAY_SIZE(wid_list),
-                                             wilc_get_vif_idx(vif));
-       } else if (mode == WILC_STATION_MODE) {
-               struct wid wid;
-
-               wid.id = WID_ADD_RX_GTK;
-               wid.type = WID_STR;
-               wid.size = sizeof(*gtk_key) + t_key_len;
-               wid.val = (u8 *)gtk_key;
-               result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                             wilc_get_vif_idx(vif));
-       }
-
-       kfree(gtk_key);
-       return result;
-}
-
-int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid)
-{
-       struct wid wid;
-
-       wid.id = WID_PMKID_INFO;
-       wid.type = WID_STR;
-       wid.size = (pmkid->numpmkid * sizeof(struct wilc_pmkid)) + 1;
-       wid.val = (u8 *)pmkid;
-
-       return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                   wilc_get_vif_idx(vif));
-}
-
-int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr)
-{
-       int result;
-       struct wid wid;
-
-       wid.id = WID_MAC_ADDR;
-       wid.type = WID_STR;
-       wid.size = ETH_ALEN;
-       wid.val = mac_addr;
-
-       result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       if (result)
-               netdev_err(vif->ndev, "Failed to get mac address\n");
-
-       return result;
-}
-
-int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies,
-                     size_t ies_len)
-{
-       int result;
-       struct host_if_drv *hif_drv = vif->hif_drv;
-       struct wilc_conn_info *conn_info = &hif_drv->conn_info;
-
-       if (bssid)
-               ether_addr_copy(conn_info->bssid, bssid);
-
-       if (ies) {
-               conn_info->req_ies_len = ies_len;
-               conn_info->req_ies = kmemdup(ies, ies_len, GFP_KERNEL);
-               if (!conn_info->req_ies)
-                       return -ENOMEM;
-       }
-
-       result = wilc_send_connect_wid(vif);
-       if (result)
-               goto free_ies;
-
-       hif_drv->connect_timer_vif = vif;
-       mod_timer(&hif_drv->connect_timer,
-                 jiffies + msecs_to_jiffies(WILC_HIF_CONNECT_TIMEOUT_MS));
-
-       return 0;
-
-free_ies:
-       kfree(conn_info->req_ies);
-
-       return result;
-}
-
-int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel)
-{
-       struct wid wid;
-       int result;
-
-       wid.id = WID_CURRENT_CHANNEL;
-       wid.type = WID_CHAR;
-       wid.size = sizeof(char);
-       wid.val = &channel;
-
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       if (result)
-               netdev_err(vif->ndev, "Failed to set channel\n");
-
-       return result;
-}
-
-int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode,
-                            u8 ifc_id)
-{
-       struct wid wid;
-       struct host_if_drv *hif_drv = vif->hif_drv;
-       int result;
-       struct wilc_drv_handler drv;
-
-       if (!hif_drv)
-               return -EFAULT;
-
-       wid.id = WID_SET_DRV_HANDLER;
-       wid.type = WID_STR;
-       wid.size = sizeof(drv);
-       wid.val = (u8 *)&drv;
-
-       drv.handler = cpu_to_le32(index);
-       drv.mode = (ifc_id | (mode << 1));
-
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                     hif_drv->driver_handler_id);
-       if (result)
-               netdev_err(vif->ndev, "Failed to set driver handler\n");
-
-       return result;
-}
-
-int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode)
-{
-       struct wid wid;
-       struct wilc_op_mode op_mode;
-       int result;
-
-       wid.id = WID_SET_OPERATION_MODE;
-       wid.type = WID_INT;
-       wid.size = sizeof(op_mode);
-       wid.val = (u8 *)&op_mode;
-
-       op_mode.mode = cpu_to_le32(mode);
-
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       if (result)
-               netdev_err(vif->ndev, "Failed to set operation mode\n");
-
-       return result;
-}
-
-s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac, u32 *out_val)
-{
-       struct wid wid;
-       s32 result;
-
-       wid.id = WID_SET_STA_MAC_INACTIVE_TIME;
-       wid.type = WID_STR;
-       wid.size = ETH_ALEN;
-       wid.val = kzalloc(wid.size, GFP_KERNEL);
-       if (!wid.val)
-               return -ENOMEM;
-
-       ether_addr_copy(wid.val, mac);
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       kfree(wid.val);
-       if (result) {
-               netdev_err(vif->ndev, "Failed to set inactive mac\n");
-               return result;
-       }
-
-       wid.id = WID_GET_INACTIVE_TIME;
-       wid.type = WID_INT;
-       wid.val = (s8 *)out_val;
-       wid.size = sizeof(u32);
-       result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       if (result)
-               netdev_err(vif->ndev, "Failed to get inactive time\n");
-
-       return result;
-}
-
-int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level)
-{
-       struct wid wid;
-       int result;
-
-       if (!rssi_level) {
-               netdev_err(vif->ndev, "%s: RSSI level is NULL\n", __func__);
-               return -EFAULT;
-       }
-
-       wid.id = WID_RSSI;
-       wid.type = WID_CHAR;
-       wid.size = sizeof(char);
-       wid.val = rssi_level;
-       result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       if (result)
-               netdev_err(vif->ndev, "Failed to get RSSI value\n");
-
-       return result;
-}
-
-static int wilc_get_stats_async(struct wilc_vif *vif, struct rf_info *stats)
-{
-       int result;
-       struct host_if_msg *msg;
-
-       msg = wilc_alloc_work(vif, handle_get_statistics, false);
-       if (IS_ERR(msg))
-               return PTR_ERR(msg);
-
-       msg->body.data = (char *)stats;
-
-       result = wilc_enqueue_work(msg);
-       if (result) {
-               netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
-               kfree(msg);
-               return result;
-       }
-
-       return result;
-}
-
-int wilc_hif_set_cfg(struct wilc_vif *vif, struct cfg_param_attr *param)
-{
-       struct wid wid_list[4];
-       int i = 0;
-
-       if (param->flag & WILC_CFG_PARAM_RETRY_SHORT) {
-               wid_list[i].id = WID_SHORT_RETRY_LIMIT;
-               wid_list[i].val = (s8 *)&param->short_retry_limit;
-               wid_list[i].type = WID_SHORT;
-               wid_list[i].size = sizeof(u16);
-               i++;
-       }
-       if (param->flag & WILC_CFG_PARAM_RETRY_LONG) {
-               wid_list[i].id = WID_LONG_RETRY_LIMIT;
-               wid_list[i].val = (s8 *)&param->long_retry_limit;
-               wid_list[i].type = WID_SHORT;
-               wid_list[i].size = sizeof(u16);
-               i++;
-       }
-       if (param->flag & WILC_CFG_PARAM_FRAG_THRESHOLD) {
-               wid_list[i].id = WID_FRAG_THRESHOLD;
-               wid_list[i].val = (s8 *)&param->frag_threshold;
-               wid_list[i].type = WID_SHORT;
-               wid_list[i].size = sizeof(u16);
-               i++;
-       }
-       if (param->flag & WILC_CFG_PARAM_RTS_THRESHOLD) {
-               wid_list[i].id = WID_RTS_THRESHOLD;
-               wid_list[i].val = (s8 *)&param->rts_threshold;
-               wid_list[i].type = WID_SHORT;
-               wid_list[i].size = sizeof(u16);
-               i++;
-       }
-
-       return wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
-                                   i, wilc_get_vif_idx(vif));
-}
-
-static void get_periodic_rssi(struct timer_list *t)
-{
-       struct wilc_vif *vif = from_timer(vif, t, periodic_rssi);
-
-       if (!vif->hif_drv) {
-               netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
-               return;
-       }
-
-       if (vif->hif_drv->hif_state == HOST_IF_CONNECTED)
-               wilc_get_stats_async(vif, &vif->periodic_stat);
-
-       mod_timer(&vif->periodic_rssi, jiffies + msecs_to_jiffies(5000));
-}
-
-int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler)
-{
-       struct host_if_drv *hif_drv;
-       struct wilc_vif *vif = netdev_priv(dev);
-       struct wilc *wilc = vif->wilc;
-       int i;
-
-       hif_drv  = kzalloc(sizeof(*hif_drv), GFP_KERNEL);
-       if (!hif_drv)
-               return -ENOMEM;
-
-       *hif_drv_handler = hif_drv;
-       for (i = 0; i < wilc->vif_num; i++)
-               if (dev == wilc->vif[i]->ndev) {
-                       wilc->vif[i]->hif_drv = hif_drv;
-                       hif_drv->driver_handler_id = i + 1;
-                       break;
-               }
-
-       vif->obtaining_ip = false;
-
-       if (wilc->clients_count == 0)
-               mutex_init(&wilc->deinit_lock);
-
-       timer_setup(&vif->periodic_rssi, get_periodic_rssi, 0);
-       mod_timer(&vif->periodic_rssi, jiffies + msecs_to_jiffies(5000));
-
-       timer_setup(&hif_drv->scan_timer, timer_scan_cb, 0);
-       timer_setup(&hif_drv->connect_timer, timer_connect_cb, 0);
-       timer_setup(&hif_drv->remain_on_ch_timer, listen_timer_cb, 0);
-
-       hif_drv->hif_state = HOST_IF_IDLE;
-
-       hif_drv->p2p_timeout = 0;
-
-       wilc->clients_count++;
-
-       return 0;
-}
-
-int wilc_deinit(struct wilc_vif *vif)
-{
-       int result = 0;
-       struct host_if_drv *hif_drv = vif->hif_drv;
-
-       if (!hif_drv) {
-               netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
-               return -EFAULT;
-       }
-
-       mutex_lock(&vif->wilc->deinit_lock);
-
-       del_timer_sync(&hif_drv->scan_timer);
-       del_timer_sync(&hif_drv->connect_timer);
-       del_timer_sync(&vif->periodic_rssi);
-       del_timer_sync(&hif_drv->remain_on_ch_timer);
-
-       wilc_set_wfi_drv_handler(vif, 0, 0, 0);
-
-       if (hif_drv->usr_scan_req.scan_result) {
-               hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED, NULL,
-                                                 hif_drv->usr_scan_req.arg);
-               hif_drv->usr_scan_req.scan_result = NULL;
-       }
-
-       hif_drv->hif_state = HOST_IF_IDLE;
-
-       kfree(hif_drv);
-       vif->hif_drv = NULL;
-       vif->wilc->clients_count--;
-       mutex_unlock(&vif->wilc->deinit_lock);
-       return result;
-}
-
-void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length)
-{
-       int result;
-       struct host_if_msg *msg;
-       int id;
-       struct host_if_drv *hif_drv;
-       struct wilc_vif *vif;
-
-       id = get_unaligned_le32(&buffer[length - 4]);
-       vif = wilc_get_vif_from_idx(wilc, id);
-       if (!vif)
-               return;
-       hif_drv = vif->hif_drv;
-
-       if (!hif_drv) {
-               netdev_err(vif->ndev, "driver not init[%p]\n", hif_drv);
-               return;
-       }
-
-       msg = wilc_alloc_work(vif, handle_rcvd_ntwrk_info, false);
-       if (IS_ERR(msg))
-               return;
-
-       msg->body.net_info.frame_len = get_unaligned_le16(&buffer[6]) - 1;
-       msg->body.net_info.rssi = buffer[8];
-       msg->body.net_info.mgmt = kmemdup(&buffer[9],
-                                         msg->body.net_info.frame_len,
-                                         GFP_KERNEL);
-       if (!msg->body.net_info.mgmt) {
-               kfree(msg);
-               return;
-       }
-
-       result = wilc_enqueue_work(msg);
-       if (result) {
-               netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
-               kfree(msg->body.net_info.mgmt);
-               kfree(msg);
-       }
-}
-
-void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length)
-{
-       int result;
-       struct host_if_msg *msg;
-       int id;
-       struct host_if_drv *hif_drv;
-       struct wilc_vif *vif;
-
-       mutex_lock(&wilc->deinit_lock);
-
-       id = get_unaligned_le32(&buffer[length - 4]);
-       vif = wilc_get_vif_from_idx(wilc, id);
-       if (!vif) {
-               mutex_unlock(&wilc->deinit_lock);
-               return;
-       }
-
-       hif_drv = vif->hif_drv;
-
-       if (!hif_drv) {
-               mutex_unlock(&wilc->deinit_lock);
-               return;
-       }
-
-       if (!hif_drv->conn_info.conn_result) {
-               netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
-               mutex_unlock(&wilc->deinit_lock);
-               return;
-       }
-
-       msg = wilc_alloc_work(vif, handle_rcvd_gnrl_async_info, false);
-       if (IS_ERR(msg)) {
-               mutex_unlock(&wilc->deinit_lock);
-               return;
-       }
-
-       msg->body.mac_info.status = buffer[7];
-       result = wilc_enqueue_work(msg);
-       if (result) {
-               netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
-               kfree(msg);
-       }
-
-       mutex_unlock(&wilc->deinit_lock);
-}
-
-void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length)
-{
-       int result;
-       int id;
-       struct host_if_drv *hif_drv;
-       struct wilc_vif *vif;
-
-       id = get_unaligned_le32(&buffer[length - 4]);
-       vif = wilc_get_vif_from_idx(wilc, id);
-       if (!vif)
-               return;
-       hif_drv = vif->hif_drv;
-
-       if (!hif_drv)
-               return;
-
-       if (hif_drv->usr_scan_req.scan_result) {
-               struct host_if_msg *msg;
-
-               msg = wilc_alloc_work(vif, handle_scan_complete, false);
-               if (IS_ERR(msg))
-                       return;
-
-               result = wilc_enqueue_work(msg);
-               if (result) {
-                       netdev_err(vif->ndev, "%s: enqueue work failed\n",
-                                  __func__);
-                       kfree(msg);
-               }
-       }
-}
-
-int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie,
-                          u32 duration, u16 chan,
-                          void (*expired)(void *, u64),
-                          void *user_arg)
-{
-       struct wilc_remain_ch roc;
-       int result;
-
-       roc.ch = chan;
-       roc.expired = expired;
-       roc.arg = user_arg;
-       roc.duration = duration;
-       roc.cookie = cookie;
-       result = handle_remain_on_chan(vif, &roc);
-       if (result)
-               netdev_err(vif->ndev, "%s: failed to set remain on channel\n",
-                          __func__);
-
-       return result;
-}
-
-int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie)
-{
-       int result;
-       struct host_if_msg *msg;
-       struct host_if_drv *hif_drv = vif->hif_drv;
-
-       if (!hif_drv) {
-               netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
-               return -EFAULT;
-       }
-
-       del_timer(&hif_drv->remain_on_ch_timer);
-
-       msg = wilc_alloc_work(vif, handle_listen_state_expired, false);
-       if (IS_ERR(msg))
-               return PTR_ERR(msg);
-
-       msg->body.remain_on_ch.cookie = cookie;
-
-       result = wilc_enqueue_work(msg);
-       if (result) {
-               netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
-               kfree(msg);
-       }
-
-       return result;
-}
-
-void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg)
-{
-       struct wid wid;
-       int result;
-       struct wilc_reg_frame reg_frame;
-
-       wid.id = WID_REGISTER_FRAME;
-       wid.type = WID_STR;
-       wid.size = sizeof(reg_frame);
-       wid.val = (u8 *)&reg_frame;
-
-       memset(&reg_frame, 0x0, sizeof(reg_frame));
-       reg_frame.reg = reg;
-
-       switch (frame_type) {
-       case IEEE80211_STYPE_ACTION:
-               reg_frame.reg_id = WILC_FW_ACTION_FRM_IDX;
-               break;
-
-       case IEEE80211_STYPE_PROBE_REQ:
-               reg_frame.reg_id = WILC_FW_PROBE_REQ_IDX;
-               break;
-
-       default:
-               break;
-       }
-       reg_frame.frame_type = cpu_to_le16(frame_type);
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       if (result)
-               netdev_err(vif->ndev, "Failed to frame register\n");
-}
-
-int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period,
-                   struct cfg80211_beacon_data *params)
-{
-       struct wid wid;
-       int result;
-       u8 *cur_byte;
-
-       wid.id = WID_ADD_BEACON;
-       wid.type = WID_BIN;
-       wid.size = params->head_len + params->tail_len + 16;
-       wid.val = kzalloc(wid.size, GFP_KERNEL);
-       if (!wid.val)
-               return -ENOMEM;
-
-       cur_byte = wid.val;
-       put_unaligned_le32(interval, cur_byte);
-       cur_byte += 4;
-       put_unaligned_le32(dtim_period, cur_byte);
-       cur_byte += 4;
-       put_unaligned_le32(params->head_len, cur_byte);
-       cur_byte += 4;
-
-       if (params->head_len > 0)
-               memcpy(cur_byte, params->head, params->head_len);
-       cur_byte += params->head_len;
-
-       put_unaligned_le32(params->tail_len, cur_byte);
-       cur_byte += 4;
-
-       if (params->tail_len > 0)
-               memcpy(cur_byte, params->tail, params->tail_len);
-
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       if (result)
-               netdev_err(vif->ndev, "Failed to send add beacon\n");
-
-       kfree(wid.val);
-
-       return result;
-}
-
-int wilc_del_beacon(struct wilc_vif *vif)
-{
-       int result;
-       struct wid wid;
-       u8 del_beacon = 0;
-
-       wid.id = WID_DEL_BEACON;
-       wid.type = WID_CHAR;
-       wid.size = sizeof(char);
-       wid.val = &del_beacon;
-
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       if (result)
-               netdev_err(vif->ndev, "Failed to send delete beacon\n");
-
-       return result;
-}
-
-int wilc_add_station(struct wilc_vif *vif, const u8 *mac,
-                    struct station_parameters *params)
-{
-       struct wid wid;
-       int result;
-       u8 *cur_byte;
-
-       wid.id = WID_ADD_STA;
-       wid.type = WID_BIN;
-       wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len;
-       wid.val = kmalloc(wid.size, GFP_KERNEL);
-       if (!wid.val)
-               return -ENOMEM;
-
-       cur_byte = wid.val;
-       wilc_hif_pack_sta_param(cur_byte, mac, params);
-
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       if (result != 0)
-               netdev_err(vif->ndev, "Failed to send add station\n");
-
-       kfree(wid.val);
-
-       return result;
-}
-
-int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr)
-{
-       struct wid wid;
-       int result;
-
-       wid.id = WID_REMOVE_STA;
-       wid.type = WID_BIN;
-       wid.size = ETH_ALEN;
-       wid.val = kzalloc(wid.size, GFP_KERNEL);
-       if (!wid.val)
-               return -ENOMEM;
-
-       if (!mac_addr)
-               eth_broadcast_addr(wid.val);
-       else
-               ether_addr_copy(wid.val, mac_addr);
-
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       if (result)
-               netdev_err(vif->ndev, "Failed to del station\n");
-
-       kfree(wid.val);
-
-       return result;
-}
-
-int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN])
-{
-       struct wid wid;
-       int result;
-       int i;
-       u8 assoc_sta = 0;
-       struct wilc_del_all_sta del_sta;
-
-       memset(&del_sta, 0x0, sizeof(del_sta));
-       for (i = 0; i < WILC_MAX_NUM_STA; i++) {
-               if (!is_zero_ether_addr(mac_addr[i])) {
-                       assoc_sta++;
-                       ether_addr_copy(del_sta.mac[i], mac_addr[i]);
-               }
-       }
-
-       if (!assoc_sta)
-               return 0;
-
-       del_sta.assoc_sta = assoc_sta;
-
-       wid.id = WID_DEL_ALL_STA;
-       wid.type = WID_STR;
-       wid.size = (assoc_sta * ETH_ALEN) + 1;
-       wid.val = (u8 *)&del_sta;
-
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       if (result)
-               netdev_err(vif->ndev, "Failed to send delete all station\n");
-
-       return result;
-}
-
-int wilc_edit_station(struct wilc_vif *vif, const u8 *mac,
-                     struct station_parameters *params)
-{
-       struct wid wid;
-       int result;
-       u8 *cur_byte;
-
-       wid.id = WID_EDIT_STA;
-       wid.type = WID_BIN;
-       wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len;
-       wid.val = kmalloc(wid.size, GFP_KERNEL);
-       if (!wid.val)
-               return -ENOMEM;
-
-       cur_byte = wid.val;
-       wilc_hif_pack_sta_param(cur_byte, mac, params);
-
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       if (result)
-               netdev_err(vif->ndev, "Failed to send edit station\n");
-
-       kfree(wid.val);
-       return result;
-}
-
-int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout)
-{
-       struct wid wid;
-       int result;
-       s8 power_mode;
-
-       if (wilc_wlan_get_num_conn_ifcs(vif->wilc) == 2 && enabled)
-               return 0;
-
-       if (enabled)
-               power_mode = WILC_FW_MIN_FAST_PS;
-       else
-               power_mode = WILC_FW_NO_POWERSAVE;
-
-       wid.id = WID_POWER_MANAGEMENT;
-       wid.val = &power_mode;
-       wid.size = sizeof(char);
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                     wilc_get_vif_idx(vif));
-       if (result)
-               netdev_err(vif->ndev, "Failed to send power management\n");
-
-       return result;
-}
-
-int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count,
-                               u8 *mc_list)
-{
-       int result;
-       struct host_if_msg *msg;
-
-       msg = wilc_alloc_work(vif, handle_set_mcast_filter, false);
-       if (IS_ERR(msg))
-               return PTR_ERR(msg);
-
-       msg->body.mc_info.enabled = enabled;
-       msg->body.mc_info.cnt = count;
-       msg->body.mc_info.mc_list = mc_list;
-
-       result = wilc_enqueue_work(msg);
-       if (result) {
-               netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
-               kfree(msg);
-       }
-       return result;
-}
-
-int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power)
-{
-       struct wid wid;
-
-       wid.id = WID_TX_POWER;
-       wid.type = WID_CHAR;
-       wid.val = &tx_power;
-       wid.size = sizeof(char);
-
-       return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
-                                  wilc_get_vif_idx(vif));
-}
-
-int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power)
-{
-       struct wid wid;
-
-       wid.id = WID_TX_POWER;
-       wid.type = WID_CHAR;
-       wid.val = tx_power;
-       wid.size = sizeof(char);
-
-       return wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1,
-                                   wilc_get_vif_idx(vif));
-}
diff --git a/drivers/staging/wilc1000/host_interface.h b/drivers/staging/wilc1000/host_interface.h
deleted file mode 100644 (file)
index a907c6d..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries
- * All rights reserved.
- */
-
-#ifndef HOST_INT_H
-#define HOST_INT_H
-#include <linux/ieee80211.h>
-#include "wilc_wlan_if.h"
-
-enum {
-       WILC_IDLE_MODE = 0x0,
-       WILC_AP_MODE = 0x1,
-       WILC_STATION_MODE = 0x2,
-       WILC_GO_MODE = 0x3,
-       WILC_CLIENT_MODE = 0x4
-};
-
-#define WILC_MAX_NUM_STA                       9
-#define WILC_MAX_NUM_SCANNED_CH                        14
-#define WILC_MAX_NUM_PROBED_SSID               10
-
-#define WILC_TX_MIC_KEY_LEN                    8
-#define WILC_RX_MIC_KEY_LEN                    8
-
-#define WILC_MAX_NUM_PMKIDS                    16
-#define WILC_ADD_STA_LENGTH                    40
-#define WILC_NUM_CONCURRENT_IFC                        2
-
-enum {
-       WILC_SET_CFG = 0,
-       WILC_GET_CFG
-};
-
-#define WILC_MAX_ASSOC_RESP_FRAME_SIZE   256
-
-struct assoc_resp {
-       __le16 capab_info;
-       __le16 status_code;
-       __le16 aid;
-} __packed;
-
-struct rf_info {
-       u8 link_speed;
-       s8 rssi;
-       u32 tx_cnt;
-       u32 rx_cnt;
-       u32 tx_fail_cnt;
-};
-
-enum host_if_state {
-       HOST_IF_IDLE                    = 0,
-       HOST_IF_SCANNING                = 1,
-       HOST_IF_CONNECTING              = 2,
-       HOST_IF_WAITING_CONN_RESP       = 3,
-       HOST_IF_CONNECTED               = 4,
-       HOST_IF_P2P_LISTEN              = 5,
-       HOST_IF_FORCE_32BIT             = 0xFFFFFFFF
-};
-
-struct wilc_pmkid {
-       u8 bssid[ETH_ALEN];
-       u8 pmkid[WLAN_PMKID_LEN];
-} __packed;
-
-struct wilc_pmkid_attr {
-       u8 numpmkid;
-       struct wilc_pmkid pmkidlist[WILC_MAX_NUM_PMKIDS];
-} __packed;
-
-struct cfg_param_attr {
-       u32 flag;
-       u16 short_retry_limit;
-       u16 long_retry_limit;
-       u16 frag_threshold;
-       u16 rts_threshold;
-};
-
-enum cfg_param {
-       WILC_CFG_PARAM_RETRY_SHORT = BIT(0),
-       WILC_CFG_PARAM_RETRY_LONG = BIT(1),
-       WILC_CFG_PARAM_FRAG_THRESHOLD = BIT(2),
-       WILC_CFG_PARAM_RTS_THRESHOLD = BIT(3)
-};
-
-enum scan_event {
-       SCAN_EVENT_NETWORK_FOUND        = 0,
-       SCAN_EVENT_DONE                 = 1,
-       SCAN_EVENT_ABORTED              = 2,
-       SCAN_EVENT_FORCE_32BIT          = 0xFFFFFFFF
-};
-
-enum conn_event {
-       CONN_DISCONN_EVENT_CONN_RESP            = 0,
-       CONN_DISCONN_EVENT_DISCONN_NOTIF        = 1,
-       CONN_DISCONN_EVENT_FORCE_32BIT          = 0xFFFFFFFF
-};
-
-enum {
-       WILC_HIF_SDIO = 0,
-       WILC_HIF_SPI = BIT(0)
-};
-
-enum {
-       WILC_MAC_STATUS_INIT = -1,
-       WILC_MAC_STATUS_DISCONNECTED = 0,
-       WILC_MAC_STATUS_CONNECTED = 1
-};
-
-struct wilc_rcvd_net_info {
-       s8 rssi;
-       u8 ch;
-       u16 frame_len;
-       struct ieee80211_mgmt *mgmt;
-};
-
-
-struct wilc_user_scan_req {
-       void (*scan_result)(enum scan_event evt,
-                           struct wilc_rcvd_net_info *info, void *priv);
-       void *arg;
-       u32 ch_cnt;
-};
-
-struct wilc_conn_info {
-       u8 bssid[ETH_ALEN];
-       u8 security;
-       enum authtype auth_type;
-       u8 ch;
-       u8 *req_ies;
-       size_t req_ies_len;
-       u8 *resp_ies;
-       u16 resp_ies_len;
-       u16 status;
-       void (*conn_result)(enum conn_event evt, u8 status, void *priv_data);
-       void *arg;
-       void *param;
-};
-
-struct wilc_remain_ch {
-       u16 ch;
-       u32 duration;
-       void (*expired)(void *priv, u64 cookie);
-       void *arg;
-       u32 cookie;
-};
-
-struct wilc;
-struct host_if_drv {
-       struct wilc_user_scan_req usr_scan_req;
-       struct wilc_conn_info conn_info;
-       struct wilc_remain_ch remain_on_ch;
-       u64 p2p_timeout;
-
-       enum host_if_state hif_state;
-
-       u8 assoc_bssid[ETH_ALEN];
-
-       struct timer_list scan_timer;
-       struct wilc_vif *scan_timer_vif;
-
-       struct timer_list connect_timer;
-       struct wilc_vif *connect_timer_vif;
-
-       struct timer_list remain_on_ch_timer;
-       struct wilc_vif *remain_on_ch_timer_vif;
-
-       bool ifc_up;
-       int driver_handler_id;
-       u8 assoc_resp[WILC_MAX_ASSOC_RESP_FRAME_SIZE];
-};
-
-struct wilc_vif;
-int wilc_remove_wep_key(struct wilc_vif *vif, u8 index);
-int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index);
-int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
-                            u8 index);
-int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len,
-                           u8 index, u8 mode, enum authtype auth_type);
-int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
-                const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic,
-                u8 mode, u8 cipher_mode, u8 index);
-s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac,
-                          u32 *out_val);
-int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
-                   u8 index, u32 key_rsc_len, const u8 *key_rsc,
-                   const u8 *rx_mic, const u8 *tx_mic, u8 mode,
-                   u8 cipher_mode);
-int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid);
-int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr);
-int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies,
-                     size_t ies_len);
-int wilc_disconnect(struct wilc_vif *vif);
-int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel);
-int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level);
-int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
-             u8 *ch_freq_list, u8 ch_list_len,
-             void (*scan_result_fn)(enum scan_event,
-                                    struct wilc_rcvd_net_info *, void *),
-             void *user_arg, struct cfg80211_scan_request *request);
-int wilc_hif_set_cfg(struct wilc_vif *vif,
-                    struct cfg_param_attr *cfg_param);
-int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler);
-int wilc_deinit(struct wilc_vif *vif);
-int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period,
-                   struct cfg80211_beacon_data *params);
-int wilc_del_beacon(struct wilc_vif *vif);
-int wilc_add_station(struct wilc_vif *vif, const u8 *mac,
-                    struct station_parameters *params);
-int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN]);
-int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr);
-int wilc_edit_station(struct wilc_vif *vif, const u8 *mac,
-                     struct station_parameters *params);
-int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout);
-int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count,
-                               u8 *mc_list);
-int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie,
-                          u32 duration, u16 chan,
-                          void (*expired)(void *, u64),
-                          void *user_arg);
-int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie);
-void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg);
-int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode,
-                            u8 ifc_id);
-int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode);
-int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats);
-void wilc_resolve_disconnect_aberration(struct wilc_vif *vif);
-int wilc_get_vif_idx(struct wilc_vif *vif);
-int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power);
-int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power);
-void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length);
-void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length);
-void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length);
-void *wilc_parse_join_bss_param(struct cfg80211_bss *bss,
-                               struct cfg80211_crypto_settings *crypto);
-#endif
diff --git a/drivers/staging/wilc1000/wilc_hif.c b/drivers/staging/wilc1000/wilc_hif.c
new file mode 100644 (file)
index 0000000..9345cab
--- /dev/null
@@ -0,0 +1,2089 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include "wilc_wfi_netdevice.h"
+
+#define WILC_HIF_SCAN_TIMEOUT_MS                5000
+#define WILC_HIF_CONNECT_TIMEOUT_MS             9500
+
+#define WILC_FALSE_FRMWR_CHANNEL               100
+#define WILC_MAX_RATES_SUPPORTED               12
+
+struct wilc_rcvd_mac_info {
+       u8 status;
+};
+
+struct wilc_set_multicast {
+       u32 enabled;
+       u32 cnt;
+       u8 *mc_list;
+};
+
+struct wilc_del_all_sta {
+       u8 assoc_sta;
+       u8 mac[WILC_MAX_NUM_STA][ETH_ALEN];
+};
+
+struct wilc_op_mode {
+       __le32 mode;
+};
+
+struct wilc_reg_frame {
+       bool reg;
+       u8 reg_id;
+       __le16 frame_type;
+} __packed;
+
+struct wilc_drv_handler {
+       __le32 handler;
+       u8 mode;
+} __packed;
+
+struct wilc_wep_key {
+       u8 index;
+       u8 key_len;
+       u8 key[0];
+} __packed;
+
+struct wilc_sta_wpa_ptk {
+       u8 mac_addr[ETH_ALEN];
+       u8 key_len;
+       u8 key[0];
+} __packed;
+
+struct wilc_ap_wpa_ptk {
+       u8 mac_addr[ETH_ALEN];
+       u8 index;
+       u8 key_len;
+       u8 key[0];
+} __packed;
+
+struct wilc_gtk_key {
+       u8 mac_addr[ETH_ALEN];
+       u8 rsc[8];
+       u8 index;
+       u8 key_len;
+       u8 key[0];
+} __packed;
+
+union wilc_message_body {
+       struct wilc_rcvd_net_info net_info;
+       struct wilc_rcvd_mac_info mac_info;
+       struct wilc_set_multicast mc_info;
+       struct wilc_remain_ch remain_on_ch;
+       char *data;
+};
+
+struct host_if_msg {
+       union wilc_message_body body;
+       struct wilc_vif *vif;
+       struct work_struct work;
+       void (*fn)(struct work_struct *ws);
+       struct completion work_comp;
+       bool is_sync;
+};
+
+struct wilc_noa_opp_enable {
+       u8 ct_window;
+       u8 cnt;
+       __le32 duration;
+       __le32 interval;
+       __le32 start_time;
+} __packed;
+
+struct wilc_noa_opp_disable {
+       u8 cnt;
+       __le32 duration;
+       __le32 interval;
+       __le32 start_time;
+} __packed;
+
+struct wilc_join_bss_param {
+       char ssid[IEEE80211_MAX_SSID_LEN];
+       u8 ssid_terminator;
+       u8 bss_type;
+       u8 ch;
+       __le16 cap_info;
+       u8 sa[ETH_ALEN];
+       u8 bssid[ETH_ALEN];
+       __le16 beacon_period;
+       u8 dtim_period;
+       u8 supp_rates[WILC_MAX_RATES_SUPPORTED + 1];
+       u8 wmm_cap;
+       u8 uapsd_cap;
+       u8 ht_capable;
+       u8 rsn_found;
+       u8 rsn_grp_policy;
+       u8 mode_802_11i;
+       u8 p_suites[3];
+       u8 akm_suites[3];
+       u8 rsn_cap[2];
+       u8 noa_enabled;
+       __le32 tsf_lo;
+       u8 idx;
+       u8 opp_enabled;
+       union {
+               struct wilc_noa_opp_disable opp_dis;
+               struct wilc_noa_opp_enable opp_en;
+       };
+} __packed;
+
+/* 'msg' should be free by the caller for syc */
+static struct host_if_msg*
+wilc_alloc_work(struct wilc_vif *vif, void (*work_fun)(struct work_struct *),
+               bool is_sync)
+{
+       struct host_if_msg *msg;
+
+       if (!work_fun)
+               return ERR_PTR(-EINVAL);
+
+       msg = kzalloc(sizeof(*msg), GFP_ATOMIC);
+       if (!msg)
+               return ERR_PTR(-ENOMEM);
+       msg->fn = work_fun;
+       msg->vif = vif;
+       msg->is_sync = is_sync;
+       if (is_sync)
+               init_completion(&msg->work_comp);
+
+       return msg;
+}
+
+static int wilc_enqueue_work(struct host_if_msg *msg)
+{
+       INIT_WORK(&msg->work, msg->fn);
+
+       if (!msg->vif || !msg->vif->wilc || !msg->vif->wilc->hif_workqueue)
+               return -EINVAL;
+
+       if (!queue_work(msg->vif->wilc->hif_workqueue, &msg->work))
+               return -EINVAL;
+
+       return 0;
+}
+
+/* The idx starts from 0 to (NUM_CONCURRENT_IFC - 1), but 0 index used as
+ * special purpose in wilc device, so we add 1 to the index to starts from 1.
+ * As a result, the returned index will be 1 to NUM_CONCURRENT_IFC.
+ */
+int wilc_get_vif_idx(struct wilc_vif *vif)
+{
+       return vif->idx + 1;
+}
+
+/* We need to minus 1 from idx which is from wilc device to get real index
+ * of wilc->vif[], because we add 1 when pass to wilc device in the function
+ * wilc_get_vif_idx.
+ * As a result, the index should be between 0 and (NUM_CONCURRENT_IFC - 1).
+ */
+static struct wilc_vif *wilc_get_vif_from_idx(struct wilc *wilc, int idx)
+{
+       int index = idx - 1;
+
+       if (index < 0 || index >= WILC_NUM_CONCURRENT_IFC)
+               return NULL;
+
+       return wilc->vif[index];
+}
+
+static int handle_scan_done(struct wilc_vif *vif, enum scan_event evt)
+{
+       int result = 0;
+       u8 abort_running_scan;
+       struct wid wid;
+       struct host_if_drv *hif_drv = vif->hif_drv;
+       struct wilc_user_scan_req *scan_req;
+
+       if (evt == SCAN_EVENT_ABORTED) {
+               abort_running_scan = 1;
+               wid.id = WID_ABORT_RUNNING_SCAN;
+               wid.type = WID_CHAR;
+               wid.val = (s8 *)&abort_running_scan;
+               wid.size = sizeof(char);
+
+               result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+               if (result) {
+                       netdev_err(vif->ndev, "Failed to set abort running\n");
+                       result = -EFAULT;
+               }
+       }
+
+       if (!hif_drv) {
+               netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);
+               return result;
+       }
+
+       scan_req = &hif_drv->usr_scan_req;
+       if (scan_req->scan_result) {
+               scan_req->scan_result(evt, NULL, scan_req->arg);
+               scan_req->scan_result = NULL;
+       }
+
+       return result;
+}
+
+int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
+             u8 *ch_freq_list, u8 ch_list_len,
+             void (*scan_result_fn)(enum scan_event,
+                                    struct wilc_rcvd_net_info *, void *),
+             void *user_arg, struct cfg80211_scan_request *request)
+{
+       int result = 0;
+       struct wid wid_list[5];
+       u32 index = 0;
+       u32 i, scan_timeout;
+       u8 *buffer;
+       u8 valuesize = 0;
+       u8 *search_ssid_vals = NULL;
+       struct host_if_drv *hif_drv = vif->hif_drv;
+
+       if (hif_drv->hif_state >= HOST_IF_SCANNING &&
+           hif_drv->hif_state < HOST_IF_CONNECTED) {
+               netdev_err(vif->ndev, "Already scan\n");
+               result = -EBUSY;
+               goto error;
+       }
+
+       if (vif->obtaining_ip || vif->connecting) {
+               netdev_err(vif->ndev, "Don't do obss scan\n");
+               result = -EBUSY;
+               goto error;
+       }
+
+       hif_drv->usr_scan_req.ch_cnt = 0;
+
+       if (request->n_ssids) {
+               for (i = 0; i < request->n_ssids; i++)
+                       valuesize += ((request->ssids[i].ssid_len) + 1);
+               search_ssid_vals = kmalloc(valuesize + 1, GFP_KERNEL);
+               if (search_ssid_vals) {
+                       wid_list[index].id = WID_SSID_PROBE_REQ;
+                       wid_list[index].type = WID_STR;
+                       wid_list[index].val = search_ssid_vals;
+                       buffer = wid_list[index].val;
+
+                       *buffer++ = request->n_ssids;
+
+                       for (i = 0; i < request->n_ssids; i++) {
+                               *buffer++ = request->ssids[i].ssid_len;
+                               memcpy(buffer, request->ssids[i].ssid,
+                                      request->ssids[i].ssid_len);
+                               buffer += request->ssids[i].ssid_len;
+                       }
+                       wid_list[index].size = (s32)(valuesize + 1);
+                       index++;
+               }
+       }
+
+       wid_list[index].id = WID_INFO_ELEMENT_PROBE;
+       wid_list[index].type = WID_BIN_DATA;
+       wid_list[index].val = (s8 *)request->ie;
+       wid_list[index].size = request->ie_len;
+       index++;
+
+       wid_list[index].id = WID_SCAN_TYPE;
+       wid_list[index].type = WID_CHAR;
+       wid_list[index].size = sizeof(char);
+       wid_list[index].val = (s8 *)&scan_type;
+       index++;
+
+       if (scan_type == WILC_FW_PASSIVE_SCAN && request->duration) {
+               wid_list[index].id = WID_PASSIVE_SCAN_TIME;
+               wid_list[index].type = WID_SHORT;
+               wid_list[index].size = sizeof(u16);
+               wid_list[index].val = (s8 *)&request->duration;
+               index++;
+
+               scan_timeout = (request->duration * ch_list_len) + 500;
+       } else {
+               scan_timeout = WILC_HIF_SCAN_TIMEOUT_MS;
+       }
+
+       wid_list[index].id = WID_SCAN_CHANNEL_LIST;
+       wid_list[index].type = WID_BIN_DATA;
+
+       if (ch_freq_list && ch_list_len > 0) {
+               for (i = 0; i < ch_list_len; i++) {
+                       if (ch_freq_list[i] > 0)
+                               ch_freq_list[i] -= 1;
+               }
+       }
+
+       wid_list[index].val = ch_freq_list;
+       wid_list[index].size = ch_list_len;
+       index++;
+
+       wid_list[index].id = WID_START_SCAN_REQ;
+       wid_list[index].type = WID_CHAR;
+       wid_list[index].size = sizeof(char);
+       wid_list[index].val = (s8 *)&scan_source;
+       index++;
+
+       hif_drv->usr_scan_req.scan_result = scan_result_fn;
+       hif_drv->usr_scan_req.arg = user_arg;
+
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, index);
+       if (result) {
+               netdev_err(vif->ndev, "Failed to send scan parameters\n");
+               goto error;
+       }
+
+       hif_drv->scan_timer_vif = vif;
+       mod_timer(&hif_drv->scan_timer,
+                 jiffies + msecs_to_jiffies(scan_timeout));
+
+error:
+
+       kfree(search_ssid_vals);
+
+       return result;
+}
+
+static int wilc_send_connect_wid(struct wilc_vif *vif)
+{
+       int result = 0;
+       struct wid wid_list[4];
+       u32 wid_cnt = 0;
+       struct host_if_drv *hif_drv = vif->hif_drv;
+       struct wilc_conn_info *conn_attr = &hif_drv->conn_info;
+       struct wilc_join_bss_param *bss_param = conn_attr->param;
+
+       wid_list[wid_cnt].id = WID_INFO_ELEMENT_ASSOCIATE;
+       wid_list[wid_cnt].type = WID_BIN_DATA;
+       wid_list[wid_cnt].val = conn_attr->req_ies;
+       wid_list[wid_cnt].size = conn_attr->req_ies_len;
+       wid_cnt++;
+
+       wid_list[wid_cnt].id = WID_11I_MODE;
+       wid_list[wid_cnt].type = WID_CHAR;
+       wid_list[wid_cnt].size = sizeof(char);
+       wid_list[wid_cnt].val = (s8 *)&conn_attr->security;
+       wid_cnt++;
+
+       wid_list[wid_cnt].id = WID_AUTH_TYPE;
+       wid_list[wid_cnt].type = WID_CHAR;
+       wid_list[wid_cnt].size = sizeof(char);
+       wid_list[wid_cnt].val = (s8 *)&conn_attr->auth_type;
+       wid_cnt++;
+
+       wid_list[wid_cnt].id = WID_JOIN_REQ_EXTENDED;
+       wid_list[wid_cnt].type = WID_STR;
+       wid_list[wid_cnt].size = sizeof(*bss_param);
+       wid_list[wid_cnt].val = (u8 *)bss_param;
+       wid_cnt++;
+
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, wid_cnt);
+       if (result) {
+               netdev_err(vif->ndev, "failed to send config packet\n");
+               goto error;
+       } else {
+               hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP;
+       }
+
+       return 0;
+
+error:
+
+       kfree(conn_attr->req_ies);
+       conn_attr->req_ies = NULL;
+
+       return result;
+}
+
+static void handle_connect_timeout(struct work_struct *work)
+{
+       struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+       struct wilc_vif *vif = msg->vif;
+       int result;
+       struct wid wid;
+       u16 dummy_reason_code = 0;
+       struct host_if_drv *hif_drv = vif->hif_drv;
+
+       if (!hif_drv) {
+               netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);
+               goto out;
+       }
+
+       hif_drv->hif_state = HOST_IF_IDLE;
+
+       if (hif_drv->conn_info.conn_result) {
+               hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_CONN_RESP,
+                                              WILC_MAC_STATUS_DISCONNECTED,
+                                              hif_drv->conn_info.arg);
+
+       } else {
+               netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
+       }
+
+       wid.id = WID_DISCONNECT;
+       wid.type = WID_CHAR;
+       wid.val = (s8 *)&dummy_reason_code;
+       wid.size = sizeof(char);
+
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       if (result)
+               netdev_err(vif->ndev, "Failed to send disconnect\n");
+
+       hif_drv->conn_info.req_ies_len = 0;
+       kfree(hif_drv->conn_info.req_ies);
+       hif_drv->conn_info.req_ies = NULL;
+
+out:
+       kfree(msg);
+}
+
+void *wilc_parse_join_bss_param(struct cfg80211_bss *bss,
+                               struct cfg80211_crypto_settings *crypto)
+{
+       struct wilc_join_bss_param *param;
+       struct ieee80211_p2p_noa_attr noa_attr;
+       u8 rates_len = 0;
+       const u8 *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie;
+       const u8 *ht_ie, *wpa_ie, *wmm_ie, *rsn_ie;
+       int ret;
+       const struct cfg80211_bss_ies *ies = rcu_dereference(bss->ies);
+
+       param = kzalloc(sizeof(*param), GFP_KERNEL);
+       if (!param)
+               return NULL;
+
+       param->beacon_period = cpu_to_le16(bss->beacon_interval);
+       param->cap_info = cpu_to_le16(bss->capability);
+       param->bss_type = WILC_FW_BSS_TYPE_INFRA;
+       param->ch = ieee80211_frequency_to_channel(bss->channel->center_freq);
+       ether_addr_copy(param->bssid, bss->bssid);
+
+       ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
+       if (ssid_elm) {
+               if (ssid_elm[1] <= IEEE80211_MAX_SSID_LEN)
+                       memcpy(param->ssid, ssid_elm + 2, ssid_elm[1]);
+       }
+
+       tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len);
+       if (tim_elm && tim_elm[1] >= 2)
+               param->dtim_period = tim_elm[3];
+
+       memset(param->p_suites, 0xFF, 3);
+       memset(param->akm_suites, 0xFF, 3);
+
+       rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies->data, ies->len);
+       if (rates_ie) {
+               rates_len = rates_ie[1];
+               param->supp_rates[0] = rates_len;
+               memcpy(&param->supp_rates[1], rates_ie + 2, rates_len);
+       }
+
+       supp_rates_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies->data,
+                                        ies->len);
+       if (supp_rates_ie) {
+               if (supp_rates_ie[1] > (WILC_MAX_RATES_SUPPORTED - rates_len))
+                       param->supp_rates[0] = WILC_MAX_RATES_SUPPORTED;
+               else
+                       param->supp_rates[0] += supp_rates_ie[1];
+
+               memcpy(&param->supp_rates[rates_len + 1], supp_rates_ie + 2,
+                      (param->supp_rates[0] - rates_len));
+       }
+
+       ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies->data, ies->len);
+       if (ht_ie)
+               param->ht_capable = true;
+
+       ret = cfg80211_get_p2p_attr(ies->data, ies->len,
+                                   IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
+                                   (u8 *)&noa_attr, sizeof(noa_attr));
+       if (ret > 0) {
+               param->tsf_lo = cpu_to_le32(ies->tsf);
+               param->noa_enabled = 1;
+               param->idx = noa_attr.index;
+               if (noa_attr.oppps_ctwindow & IEEE80211_P2P_OPPPS_ENABLE_BIT) {
+                       param->opp_enabled = 1;
+                       param->opp_en.ct_window = noa_attr.oppps_ctwindow;
+                       param->opp_en.cnt = noa_attr.desc[0].count;
+                       param->opp_en.duration = noa_attr.desc[0].duration;
+                       param->opp_en.interval = noa_attr.desc[0].interval;
+                       param->opp_en.start_time = noa_attr.desc[0].start_time;
+               } else {
+                       param->opp_enabled = 0;
+                       param->opp_dis.cnt = noa_attr.desc[0].count;
+                       param->opp_dis.duration = noa_attr.desc[0].duration;
+                       param->opp_dis.interval = noa_attr.desc[0].interval;
+                       param->opp_dis.start_time = noa_attr.desc[0].start_time;
+               }
+       }
+       wmm_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
+                                        WLAN_OUI_TYPE_MICROSOFT_WMM,
+                                        ies->data, ies->len);
+       if (wmm_ie) {
+               struct ieee80211_wmm_param_ie *ie;
+
+               ie = (struct ieee80211_wmm_param_ie *)wmm_ie;
+               if ((ie->oui_subtype == 0 || ie->oui_subtype == 1) &&
+                   ie->version == 1) {
+                       param->wmm_cap = true;
+                       if (ie->qos_info & BIT(7))
+                               param->uapsd_cap = true;
+               }
+       }
+
+       wpa_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
+                                        WLAN_OUI_TYPE_MICROSOFT_WPA,
+                                        ies->data, ies->len);
+       if (wpa_ie) {
+               param->mode_802_11i = 1;
+               param->rsn_found = true;
+       }
+
+       rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies->data, ies->len);
+       if (rsn_ie) {
+               int offset = 8;
+
+               param->mode_802_11i = 2;
+               param->rsn_found = true;
+               //extract RSN capabilities
+               offset += (rsn_ie[offset] * 4) + 2;
+               offset += (rsn_ie[offset] * 4) + 2;
+               memcpy(param->rsn_cap, &rsn_ie[offset], 2);
+       }
+
+       if (param->rsn_found) {
+               int i;
+
+               param->rsn_grp_policy = crypto->cipher_group & 0xFF;
+               for (i = 0; i < crypto->n_ciphers_pairwise && i < 3; i++)
+                       param->p_suites[i] = crypto->ciphers_pairwise[i] & 0xFF;
+
+               for (i = 0; i < crypto->n_akm_suites && i < 3; i++)
+                       param->akm_suites[i] = crypto->akm_suites[i] & 0xFF;
+       }
+
+       return (void *)param;
+}
+
+static void handle_rcvd_ntwrk_info(struct work_struct *work)
+{
+       struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+       struct wilc_rcvd_net_info *rcvd_info = &msg->body.net_info;
+       struct wilc_user_scan_req *scan_req = &msg->vif->hif_drv->usr_scan_req;
+       const u8 *ch_elm;
+       u8 *ies;
+       int ies_len;
+       size_t offset;
+
+       if (ieee80211_is_probe_resp(rcvd_info->mgmt->frame_control))
+               offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+       else if (ieee80211_is_beacon(rcvd_info->mgmt->frame_control))
+               offset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
+       else
+               goto done;
+
+       ies = rcvd_info->mgmt->u.beacon.variable;
+       ies_len = rcvd_info->frame_len - offset;
+       if (ies_len <= 0)
+               goto done;
+
+       ch_elm = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ies, ies_len);
+       if (ch_elm && ch_elm[1] > 0)
+               rcvd_info->ch = ch_elm[2];
+
+       if (scan_req->scan_result)
+               scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, rcvd_info,
+                                     scan_req->arg);
+
+done:
+       kfree(rcvd_info->mgmt);
+       kfree(msg);
+}
+
+static void host_int_get_assoc_res_info(struct wilc_vif *vif,
+                                       u8 *assoc_resp_info,
+                                       u32 max_assoc_resp_info_len,
+                                       u32 *rcvd_assoc_resp_info_len)
+{
+       int result;
+       struct wid wid;
+
+       wid.id = WID_ASSOC_RES_INFO;
+       wid.type = WID_STR;
+       wid.val = assoc_resp_info;
+       wid.size = max_assoc_resp_info_len;
+
+       result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
+       if (result) {
+               *rcvd_assoc_resp_info_len = 0;
+               netdev_err(vif->ndev, "Failed to send association response\n");
+               return;
+       }
+
+       *rcvd_assoc_resp_info_len = wid.size;
+}
+
+static s32 wilc_parse_assoc_resp_info(u8 *buffer, u32 buffer_len,
+                                     struct wilc_conn_info *ret_conn_info)
+{
+       u8 *ies;
+       u16 ies_len;
+       struct assoc_resp *res = (struct assoc_resp *)buffer;
+
+       ret_conn_info->status = le16_to_cpu(res->status_code);
+       if (ret_conn_info->status == WLAN_STATUS_SUCCESS) {
+               ies = &buffer[sizeof(*res)];
+               ies_len = buffer_len - sizeof(*res);
+
+               ret_conn_info->resp_ies = kmemdup(ies, ies_len, GFP_KERNEL);
+               if (!ret_conn_info->resp_ies)
+                       return -ENOMEM;
+
+               ret_conn_info->resp_ies_len = ies_len;
+       }
+
+       return 0;
+}
+
+static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif,
+                                                 u8 mac_status)
+{
+       struct host_if_drv *hif_drv = vif->hif_drv;
+       struct wilc_conn_info *conn_info = &hif_drv->conn_info;
+
+       if (mac_status == WILC_MAC_STATUS_CONNECTED) {
+               u32 assoc_resp_info_len;
+
+               memset(hif_drv->assoc_resp, 0, WILC_MAX_ASSOC_RESP_FRAME_SIZE);
+
+               host_int_get_assoc_res_info(vif, hif_drv->assoc_resp,
+                                           WILC_MAX_ASSOC_RESP_FRAME_SIZE,
+                                           &assoc_resp_info_len);
+
+               if (assoc_resp_info_len != 0) {
+                       s32 err = 0;
+
+                       err = wilc_parse_assoc_resp_info(hif_drv->assoc_resp,
+                                                        assoc_resp_info_len,
+                                                        conn_info);
+                       if (err)
+                               netdev_err(vif->ndev,
+                                          "wilc_parse_assoc_resp_info() returned error %d\n",
+                                          err);
+               }
+       }
+
+       del_timer(&hif_drv->connect_timer);
+       conn_info->conn_result(CONN_DISCONN_EVENT_CONN_RESP, mac_status,
+                              hif_drv->conn_info.arg);
+
+       if (mac_status == WILC_MAC_STATUS_CONNECTED &&
+           conn_info->status == WLAN_STATUS_SUCCESS) {
+               ether_addr_copy(hif_drv->assoc_bssid, conn_info->bssid);
+               wilc_set_power_mgmt(vif, 0, 0);
+
+               hif_drv->hif_state = HOST_IF_CONNECTED;
+
+               vif->obtaining_ip = true;
+               mod_timer(&vif->during_ip_timer,
+                         jiffies + msecs_to_jiffies(10000));
+       } else {
+               hif_drv->hif_state = HOST_IF_IDLE;
+       }
+
+       kfree(conn_info->resp_ies);
+       conn_info->resp_ies = NULL;
+       conn_info->resp_ies_len = 0;
+
+       kfree(conn_info->req_ies);
+       conn_info->req_ies = NULL;
+       conn_info->req_ies_len = 0;
+}
+
+static inline void host_int_handle_disconnect(struct wilc_vif *vif)
+{
+       struct host_if_drv *hif_drv = vif->hif_drv;
+
+       if (hif_drv->usr_scan_req.scan_result) {
+               del_timer(&hif_drv->scan_timer);
+               handle_scan_done(vif, SCAN_EVENT_ABORTED);
+       }
+
+       if (hif_drv->conn_info.conn_result) {
+               vif->obtaining_ip = false;
+               wilc_set_power_mgmt(vif, 0, 0);
+
+               hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF,
+                                              0, hif_drv->conn_info.arg);
+       } else {
+               netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
+       }
+
+       eth_zero_addr(hif_drv->assoc_bssid);
+
+       hif_drv->conn_info.req_ies_len = 0;
+       kfree(hif_drv->conn_info.req_ies);
+       hif_drv->conn_info.req_ies = NULL;
+       hif_drv->hif_state = HOST_IF_IDLE;
+}
+
+static void handle_rcvd_gnrl_async_info(struct work_struct *work)
+{
+       struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+       struct wilc_vif *vif = msg->vif;
+       struct wilc_rcvd_mac_info *mac_info = &msg->body.mac_info;
+       struct host_if_drv *hif_drv = vif->hif_drv;
+
+       if (!hif_drv) {
+               netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);
+               goto free_msg;
+       }
+
+       if (!hif_drv->conn_info.conn_result) {
+               netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
+               goto free_msg;
+       }
+
+       if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) {
+               host_int_parse_assoc_resp_info(vif, mac_info->status);
+       } else if (mac_info->status == WILC_MAC_STATUS_DISCONNECTED) {
+               if (hif_drv->hif_state == HOST_IF_CONNECTED) {
+                       host_int_handle_disconnect(vif);
+               } else if (hif_drv->usr_scan_req.scan_result) {
+                       del_timer(&hif_drv->scan_timer);
+                       handle_scan_done(vif, SCAN_EVENT_ABORTED);
+               }
+       }
+
+free_msg:
+       kfree(msg);
+}
+
+int wilc_disconnect(struct wilc_vif *vif)
+{
+       struct wid wid;
+       struct host_if_drv *hif_drv = vif->hif_drv;
+       struct wilc_user_scan_req *scan_req;
+       struct wilc_conn_info *conn_info;
+       int result;
+       u16 dummy_reason_code = 0;
+
+       wid.id = WID_DISCONNECT;
+       wid.type = WID_CHAR;
+       wid.val = (s8 *)&dummy_reason_code;
+       wid.size = sizeof(char);
+
+       vif->obtaining_ip = false;
+       wilc_set_power_mgmt(vif, 0, 0);
+
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       if (result) {
+               netdev_err(vif->ndev, "Failed to send disconnect\n");
+               return result;
+       }
+
+       scan_req = &hif_drv->usr_scan_req;
+       conn_info = &hif_drv->conn_info;
+
+       if (scan_req->scan_result) {
+               del_timer(&hif_drv->scan_timer);
+               scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->arg);
+               scan_req->scan_result = NULL;
+       }
+
+       if (conn_info->conn_result) {
+               if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP)
+                       del_timer(&hif_drv->connect_timer);
+
+               conn_info->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, 0,
+                                      conn_info->arg);
+       } else {
+               netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
+       }
+
+       hif_drv->hif_state = HOST_IF_IDLE;
+
+       eth_zero_addr(hif_drv->assoc_bssid);
+
+       conn_info->req_ies_len = 0;
+       kfree(conn_info->req_ies);
+       conn_info->req_ies = NULL;
+
+       return 0;
+}
+
+void wilc_resolve_disconnect_aberration(struct wilc_vif *vif)
+{
+       if (!vif->hif_drv)
+               return;
+       if (vif->hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP ||
+           vif->hif_drv->hif_state == HOST_IF_CONNECTING)
+               wilc_disconnect(vif);
+}
+
+int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats)
+{
+       struct wid wid_list[5];
+       u32 wid_cnt = 0, result;
+
+       wid_list[wid_cnt].id = WID_LINKSPEED;
+       wid_list[wid_cnt].type = WID_CHAR;
+       wid_list[wid_cnt].size = sizeof(char);
+       wid_list[wid_cnt].val = (s8 *)&stats->link_speed;
+       wid_cnt++;
+
+       wid_list[wid_cnt].id = WID_RSSI;
+       wid_list[wid_cnt].type = WID_CHAR;
+       wid_list[wid_cnt].size = sizeof(char);
+       wid_list[wid_cnt].val = (s8 *)&stats->rssi;
+       wid_cnt++;
+
+       wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT;
+       wid_list[wid_cnt].type = WID_INT;
+       wid_list[wid_cnt].size = sizeof(u32);
+       wid_list[wid_cnt].val = (s8 *)&stats->tx_cnt;
+       wid_cnt++;
+
+       wid_list[wid_cnt].id = WID_RECEIVED_FRAGMENT_COUNT;
+       wid_list[wid_cnt].type = WID_INT;
+       wid_list[wid_cnt].size = sizeof(u32);
+       wid_list[wid_cnt].val = (s8 *)&stats->rx_cnt;
+       wid_cnt++;
+
+       wid_list[wid_cnt].id = WID_FAILED_COUNT;
+       wid_list[wid_cnt].type = WID_INT;
+       wid_list[wid_cnt].size = sizeof(u32);
+       wid_list[wid_cnt].val = (s8 *)&stats->tx_fail_cnt;
+       wid_cnt++;
+
+       result = wilc_send_config_pkt(vif, WILC_GET_CFG, wid_list, wid_cnt);
+       if (result) {
+               netdev_err(vif->ndev, "Failed to send scan parameters\n");
+               return result;
+       }
+
+       if (stats->link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH &&
+           stats->link_speed != DEFAULT_LINK_SPEED)
+               wilc_enable_tcp_ack_filter(vif, true);
+       else if (stats->link_speed != DEFAULT_LINK_SPEED)
+               wilc_enable_tcp_ack_filter(vif, false);
+
+       return result;
+}
+
+static void handle_get_statistics(struct work_struct *work)
+{
+       struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+       struct wilc_vif *vif = msg->vif;
+       struct rf_info *stats = (struct rf_info *)msg->body.data;
+
+       wilc_get_statistics(vif, stats);
+
+       kfree(msg);
+}
+
+static void wilc_hif_pack_sta_param(u8 *cur_byte, const u8 *mac,
+                                   struct station_parameters *params)
+{
+       ether_addr_copy(cur_byte, mac);
+       cur_byte += ETH_ALEN;
+
+       put_unaligned_le16(params->aid, cur_byte);
+       cur_byte += 2;
+
+       *cur_byte++ = params->supported_rates_len;
+       if (params->supported_rates_len > 0)
+               memcpy(cur_byte, params->supported_rates,
+                      params->supported_rates_len);
+       cur_byte += params->supported_rates_len;
+
+       if (params->ht_capa) {
+               *cur_byte++ = true;
+               memcpy(cur_byte, &params->ht_capa,
+                      sizeof(struct ieee80211_ht_cap));
+       } else {
+               *cur_byte++ = false;
+       }
+       cur_byte += sizeof(struct ieee80211_ht_cap);
+
+       put_unaligned_le16(params->sta_flags_mask, cur_byte);
+       cur_byte += 2;
+       put_unaligned_le16(params->sta_flags_set, cur_byte);
+}
+
+static int handle_remain_on_chan(struct wilc_vif *vif,
+                                struct wilc_remain_ch *hif_remain_ch)
+{
+       int result;
+       u8 remain_on_chan_flag;
+       struct wid wid;
+       struct host_if_drv *hif_drv = vif->hif_drv;
+
+       if (hif_drv->usr_scan_req.scan_result)
+               return -EBUSY;
+
+       if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP)
+               return -EBUSY;
+
+       if (vif->obtaining_ip || vif->connecting)
+               return -EBUSY;
+
+       remain_on_chan_flag = true;
+       wid.id = WID_REMAIN_ON_CHAN;
+       wid.type = WID_STR;
+       wid.size = 2;
+       wid.val = kmalloc(wid.size, GFP_KERNEL);
+       if (!wid.val)
+               return -ENOMEM;
+
+       wid.val[0] = remain_on_chan_flag;
+       wid.val[1] = (s8)hif_remain_ch->ch;
+
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       kfree(wid.val);
+       if (result)
+               return -EBUSY;
+
+       hif_drv->remain_on_ch.arg = hif_remain_ch->arg;
+       hif_drv->remain_on_ch.expired = hif_remain_ch->expired;
+       hif_drv->remain_on_ch.ch = hif_remain_ch->ch;
+       hif_drv->remain_on_ch.cookie = hif_remain_ch->cookie;
+       hif_drv->remain_on_ch_timer_vif = vif;
+
+       return 0;
+}
+
+static int wilc_handle_roc_expired(struct wilc_vif *vif, u64 cookie)
+{
+       u8 remain_on_chan_flag;
+       struct wid wid;
+       int result;
+       struct host_if_drv *hif_drv = vif->hif_drv;
+       struct wilc_priv *priv = wdev_priv(vif->ndev->ieee80211_ptr);
+
+       if (priv->p2p_listen_state) {
+               remain_on_chan_flag = false;
+               wid.id = WID_REMAIN_ON_CHAN;
+               wid.type = WID_STR;
+               wid.size = 2;
+
+               wid.val = kmalloc(wid.size, GFP_KERNEL);
+               if (!wid.val)
+                       return -ENOMEM;
+
+               wid.val[0] = remain_on_chan_flag;
+               wid.val[1] = WILC_FALSE_FRMWR_CHANNEL;
+
+               result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+               kfree(wid.val);
+               if (result != 0) {
+                       netdev_err(vif->ndev, "Failed to set remain channel\n");
+                       return -EINVAL;
+               }
+
+               if (hif_drv->remain_on_ch.expired) {
+                       hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.arg,
+                                                     cookie);
+               }
+       } else {
+               netdev_dbg(vif->ndev, "Not in listen state\n");
+       }
+
+       return 0;
+}
+
+static void wilc_handle_listen_state_expired(struct work_struct *work)
+{
+       struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+
+       wilc_handle_roc_expired(msg->vif, msg->body.remain_on_ch.cookie);
+       kfree(msg);
+}
+
+static void listen_timer_cb(struct timer_list *t)
+{
+       struct host_if_drv *hif_drv = from_timer(hif_drv, t,
+                                                     remain_on_ch_timer);
+       struct wilc_vif *vif = hif_drv->remain_on_ch_timer_vif;
+       int result;
+       struct host_if_msg *msg;
+
+       del_timer(&vif->hif_drv->remain_on_ch_timer);
+
+       msg = wilc_alloc_work(vif, wilc_handle_listen_state_expired, false);
+       if (IS_ERR(msg))
+               return;
+
+       msg->body.remain_on_ch.cookie = vif->hif_drv->remain_on_ch.cookie;
+
+       result = wilc_enqueue_work(msg);
+       if (result) {
+               netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+               kfree(msg);
+       }
+}
+
+static void handle_set_mcast_filter(struct work_struct *work)
+{
+       struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+       struct wilc_vif *vif = msg->vif;
+       struct wilc_set_multicast *set_mc = &msg->body.mc_info;
+       int result;
+       struct wid wid;
+       u8 *cur_byte;
+
+       wid.id = WID_SETUP_MULTICAST_FILTER;
+       wid.type = WID_BIN;
+       wid.size = sizeof(struct wilc_set_multicast) + (set_mc->cnt * ETH_ALEN);
+       wid.val = kmalloc(wid.size, GFP_KERNEL);
+       if (!wid.val)
+               goto error;
+
+       cur_byte = wid.val;
+       put_unaligned_le32(set_mc->enabled, cur_byte);
+       cur_byte += 4;
+
+       put_unaligned_le32(set_mc->cnt, cur_byte);
+       cur_byte += 4;
+
+       if (set_mc->cnt > 0 && set_mc->mc_list)
+               memcpy(cur_byte, set_mc->mc_list, set_mc->cnt * ETH_ALEN);
+
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       if (result)
+               netdev_err(vif->ndev, "Failed to send setup multicast\n");
+
+error:
+       kfree(set_mc->mc_list);
+       kfree(wid.val);
+       kfree(msg);
+}
+
+static void handle_scan_timer(struct work_struct *work)
+{
+       struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+
+       handle_scan_done(msg->vif, SCAN_EVENT_ABORTED);
+       kfree(msg);
+}
+
+static void handle_scan_complete(struct work_struct *work)
+{
+       struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+       struct wilc *wilc = msg->vif->wilc;
+
+       del_timer(&msg->vif->hif_drv->scan_timer);
+
+       if (!wilc_wlan_get_num_conn_ifcs(wilc))
+               wilc_chip_sleep_manually(wilc);
+
+       handle_scan_done(msg->vif, SCAN_EVENT_DONE);
+
+       kfree(msg);
+}
+
+static void timer_scan_cb(struct timer_list *t)
+{
+       struct host_if_drv *hif_drv = from_timer(hif_drv, t, scan_timer);
+       struct wilc_vif *vif = hif_drv->scan_timer_vif;
+       struct host_if_msg *msg;
+       int result;
+
+       msg = wilc_alloc_work(vif, handle_scan_timer, false);
+       if (IS_ERR(msg))
+               return;
+
+       result = wilc_enqueue_work(msg);
+       if (result)
+               kfree(msg);
+}
+
+static void timer_connect_cb(struct timer_list *t)
+{
+       struct host_if_drv *hif_drv = from_timer(hif_drv, t,
+                                                     connect_timer);
+       struct wilc_vif *vif = hif_drv->connect_timer_vif;
+       struct host_if_msg *msg;
+       int result;
+
+       msg = wilc_alloc_work(vif, handle_connect_timeout, false);
+       if (IS_ERR(msg))
+               return;
+
+       result = wilc_enqueue_work(msg);
+       if (result)
+               kfree(msg);
+}
+
+int wilc_remove_wep_key(struct wilc_vif *vif, u8 index)
+{
+       struct wid wid;
+       int result;
+
+       wid.id = WID_REMOVE_WEP_KEY;
+       wid.type = WID_STR;
+       wid.size = sizeof(char);
+       wid.val = &index;
+
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       if (result)
+               netdev_err(vif->ndev,
+                          "Failed to send remove wep key config packet\n");
+       return result;
+}
+
+int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index)
+{
+       struct wid wid;
+       int result;
+
+       wid.id = WID_KEY_ID;
+       wid.type = WID_CHAR;
+       wid.size = sizeof(char);
+       wid.val = &index;
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       if (result)
+               netdev_err(vif->ndev,
+                          "Failed to send wep default key config packet\n");
+
+       return result;
+}
+
+int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
+                            u8 index)
+{
+       struct wid wid;
+       int result;
+       struct wilc_wep_key *wep_key;
+
+       wid.id = WID_ADD_WEP_KEY;
+       wid.type = WID_STR;
+       wid.size = sizeof(*wep_key) + len;
+       wep_key = kzalloc(wid.size, GFP_KERNEL);
+       if (!wep_key)
+               return -ENOMEM;
+
+       wid.val = (u8 *)wep_key;
+
+       wep_key->index = index;
+       wep_key->key_len = len;
+       memcpy(wep_key->key, key, len);
+
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       if (result)
+               netdev_err(vif->ndev,
+                          "Failed to add wep key config packet\n");
+
+       kfree(wep_key);
+       return result;
+}
+
+int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len,
+                           u8 index, u8 mode, enum authtype auth_type)
+{
+       struct wid wid_list[3];
+       int result;
+       struct wilc_wep_key *wep_key;
+
+       wid_list[0].id = WID_11I_MODE;
+       wid_list[0].type = WID_CHAR;
+       wid_list[0].size = sizeof(char);
+       wid_list[0].val = &mode;
+
+       wid_list[1].id = WID_AUTH_TYPE;
+       wid_list[1].type = WID_CHAR;
+       wid_list[1].size = sizeof(char);
+       wid_list[1].val = (s8 *)&auth_type;
+
+       wid_list[2].id = WID_WEP_KEY_VALUE;
+       wid_list[2].type = WID_STR;
+       wid_list[2].size = sizeof(*wep_key) + len;
+       wep_key = kzalloc(wid_list[2].size, GFP_KERNEL);
+       if (!wep_key)
+               return -ENOMEM;
+
+       wid_list[2].val = (u8 *)wep_key;
+
+       wep_key->index = index;
+       wep_key->key_len = len;
+       memcpy(wep_key->key, key, len);
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
+                                     ARRAY_SIZE(wid_list));
+       if (result)
+               netdev_err(vif->ndev,
+                          "Failed to add wep ap key config packet\n");
+
+       kfree(wep_key);
+       return result;
+}
+
+int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
+                const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic,
+                u8 mode, u8 cipher_mode, u8 index)
+{
+       int result = 0;
+       u8 t_key_len  = ptk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN;
+
+       if (mode == WILC_AP_MODE) {
+               struct wid wid_list[2];
+               struct wilc_ap_wpa_ptk *key_buf;
+
+               wid_list[0].id = WID_11I_MODE;
+               wid_list[0].type = WID_CHAR;
+               wid_list[0].size = sizeof(char);
+               wid_list[0].val = (s8 *)&cipher_mode;
+
+               key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);
+               if (!key_buf)
+                       return -ENOMEM;
+
+               ether_addr_copy(key_buf->mac_addr, mac_addr);
+               key_buf->index = index;
+               key_buf->key_len = t_key_len;
+               memcpy(&key_buf->key[0], ptk, ptk_key_len);
+
+               if (rx_mic)
+                       memcpy(&key_buf->key[ptk_key_len], rx_mic,
+                              WILC_RX_MIC_KEY_LEN);
+
+               if (tx_mic)
+                       memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN],
+                              tx_mic, WILC_TX_MIC_KEY_LEN);
+
+               wid_list[1].id = WID_ADD_PTK;
+               wid_list[1].type = WID_STR;
+               wid_list[1].size = sizeof(*key_buf) + t_key_len;
+               wid_list[1].val = (u8 *)key_buf;
+               result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
+                                             ARRAY_SIZE(wid_list));
+               kfree(key_buf);
+       } else if (mode == WILC_STATION_MODE) {
+               struct wid wid;
+               struct wilc_sta_wpa_ptk *key_buf;
+
+               key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);
+               if (!key_buf)
+                       return -ENOMEM;
+
+               ether_addr_copy(key_buf->mac_addr, mac_addr);
+               key_buf->key_len = t_key_len;
+               memcpy(&key_buf->key[0], ptk, ptk_key_len);
+
+               if (rx_mic)
+                       memcpy(&key_buf->key[ptk_key_len], rx_mic,
+                              WILC_RX_MIC_KEY_LEN);
+
+               if (tx_mic)
+                       memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN],
+                              tx_mic, WILC_TX_MIC_KEY_LEN);
+
+               wid.id = WID_ADD_PTK;
+               wid.type = WID_STR;
+               wid.size = sizeof(*key_buf) + t_key_len;
+               wid.val = (s8 *)key_buf;
+               result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+               kfree(key_buf);
+       }
+
+       return result;
+}
+
+int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
+                   u8 index, u32 key_rsc_len, const u8 *key_rsc,
+                   const u8 *rx_mic, const u8 *tx_mic, u8 mode,
+                   u8 cipher_mode)
+{
+       int result = 0;
+       struct wilc_gtk_key *gtk_key;
+       int t_key_len = gtk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN;
+
+       gtk_key = kzalloc(sizeof(*gtk_key) + t_key_len, GFP_KERNEL);
+       if (!gtk_key)
+               return -ENOMEM;
+
+       /* fill bssid value only in station mode */
+       if (mode == WILC_STATION_MODE &&
+           vif->hif_drv->hif_state == HOST_IF_CONNECTED)
+               memcpy(gtk_key->mac_addr, vif->hif_drv->assoc_bssid, ETH_ALEN);
+
+       if (key_rsc)
+               memcpy(gtk_key->rsc, key_rsc, 8);
+       gtk_key->index = index;
+       gtk_key->key_len = t_key_len;
+       memcpy(&gtk_key->key[0], rx_gtk, gtk_key_len);
+
+       if (rx_mic)
+               memcpy(&gtk_key->key[gtk_key_len], rx_mic, WILC_RX_MIC_KEY_LEN);
+
+       if (tx_mic)
+               memcpy(&gtk_key->key[gtk_key_len + WILC_RX_MIC_KEY_LEN],
+                      tx_mic, WILC_TX_MIC_KEY_LEN);
+
+       if (mode == WILC_AP_MODE) {
+               struct wid wid_list[2];
+
+               wid_list[0].id = WID_11I_MODE;
+               wid_list[0].type = WID_CHAR;
+               wid_list[0].size = sizeof(char);
+               wid_list[0].val = (s8 *)&cipher_mode;
+
+               wid_list[1].id = WID_ADD_RX_GTK;
+               wid_list[1].type = WID_STR;
+               wid_list[1].size = sizeof(*gtk_key) + t_key_len;
+               wid_list[1].val = (u8 *)gtk_key;
+
+               result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
+                                             ARRAY_SIZE(wid_list));
+       } else if (mode == WILC_STATION_MODE) {
+               struct wid wid;
+
+               wid.id = WID_ADD_RX_GTK;
+               wid.type = WID_STR;
+               wid.size = sizeof(*gtk_key) + t_key_len;
+               wid.val = (u8 *)gtk_key;
+               result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       }
+
+       kfree(gtk_key);
+       return result;
+}
+
+int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid)
+{
+       struct wid wid;
+
+       wid.id = WID_PMKID_INFO;
+       wid.type = WID_STR;
+       wid.size = (pmkid->numpmkid * sizeof(struct wilc_pmkid)) + 1;
+       wid.val = (u8 *)pmkid;
+
+       return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+}
+
+int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr)
+{
+       int result;
+       struct wid wid;
+
+       wid.id = WID_MAC_ADDR;
+       wid.type = WID_STR;
+       wid.size = ETH_ALEN;
+       wid.val = mac_addr;
+
+       result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
+       if (result)
+               netdev_err(vif->ndev, "Failed to get mac address\n");
+
+       return result;
+}
+
+int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies,
+                     size_t ies_len)
+{
+       int result;
+       struct host_if_drv *hif_drv = vif->hif_drv;
+       struct wilc_conn_info *conn_info = &hif_drv->conn_info;
+
+       if (bssid)
+               ether_addr_copy(conn_info->bssid, bssid);
+
+       if (ies) {
+               conn_info->req_ies_len = ies_len;
+               conn_info->req_ies = kmemdup(ies, ies_len, GFP_KERNEL);
+               if (!conn_info->req_ies)
+                       return -ENOMEM;
+       }
+
+       result = wilc_send_connect_wid(vif);
+       if (result)
+               goto free_ies;
+
+       hif_drv->connect_timer_vif = vif;
+       mod_timer(&hif_drv->connect_timer,
+                 jiffies + msecs_to_jiffies(WILC_HIF_CONNECT_TIMEOUT_MS));
+
+       return 0;
+
+free_ies:
+       kfree(conn_info->req_ies);
+
+       return result;
+}
+
+int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel)
+{
+       struct wid wid;
+       int result;
+
+       wid.id = WID_CURRENT_CHANNEL;
+       wid.type = WID_CHAR;
+       wid.size = sizeof(char);
+       wid.val = &channel;
+
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       if (result)
+               netdev_err(vif->ndev, "Failed to set channel\n");
+
+       return result;
+}
+
+int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode,
+                            u8 ifc_id)
+{
+       struct wid wid;
+       struct host_if_drv *hif_drv = vif->hif_drv;
+       int result;
+       struct wilc_drv_handler drv;
+
+       if (!hif_drv)
+               return -EFAULT;
+
+       wid.id = WID_SET_DRV_HANDLER;
+       wid.type = WID_STR;
+       wid.size = sizeof(drv);
+       wid.val = (u8 *)&drv;
+
+       drv.handler = cpu_to_le32(index);
+       drv.mode = (ifc_id | (mode << 1));
+
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       if (result)
+               netdev_err(vif->ndev, "Failed to set driver handler\n");
+
+       return result;
+}
+
+int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode)
+{
+       struct wid wid;
+       struct wilc_op_mode op_mode;
+       int result;
+
+       wid.id = WID_SET_OPERATION_MODE;
+       wid.type = WID_INT;
+       wid.size = sizeof(op_mode);
+       wid.val = (u8 *)&op_mode;
+
+       op_mode.mode = cpu_to_le32(mode);
+
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       if (result)
+               netdev_err(vif->ndev, "Failed to set operation mode\n");
+
+       return result;
+}
+
+s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac, u32 *out_val)
+{
+       struct wid wid;
+       s32 result;
+
+       wid.id = WID_SET_STA_MAC_INACTIVE_TIME;
+       wid.type = WID_STR;
+       wid.size = ETH_ALEN;
+       wid.val = kzalloc(wid.size, GFP_KERNEL);
+       if (!wid.val)
+               return -ENOMEM;
+
+       ether_addr_copy(wid.val, mac);
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       kfree(wid.val);
+       if (result) {
+               netdev_err(vif->ndev, "Failed to set inactive mac\n");
+               return result;
+       }
+
+       wid.id = WID_GET_INACTIVE_TIME;
+       wid.type = WID_INT;
+       wid.val = (s8 *)out_val;
+       wid.size = sizeof(u32);
+       result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
+       if (result)
+               netdev_err(vif->ndev, "Failed to get inactive time\n");
+
+       return result;
+}
+
+int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level)
+{
+       struct wid wid;
+       int result;
+
+       if (!rssi_level) {
+               netdev_err(vif->ndev, "%s: RSSI level is NULL\n", __func__);
+               return -EFAULT;
+       }
+
+       wid.id = WID_RSSI;
+       wid.type = WID_CHAR;
+       wid.size = sizeof(char);
+       wid.val = rssi_level;
+       result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
+       if (result)
+               netdev_err(vif->ndev, "Failed to get RSSI value\n");
+
+       return result;
+}
+
+static int wilc_get_stats_async(struct wilc_vif *vif, struct rf_info *stats)
+{
+       int result;
+       struct host_if_msg *msg;
+
+       msg = wilc_alloc_work(vif, handle_get_statistics, false);
+       if (IS_ERR(msg))
+               return PTR_ERR(msg);
+
+       msg->body.data = (char *)stats;
+
+       result = wilc_enqueue_work(msg);
+       if (result) {
+               netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+               kfree(msg);
+               return result;
+       }
+
+       return result;
+}
+
+int wilc_hif_set_cfg(struct wilc_vif *vif, struct cfg_param_attr *param)
+{
+       struct wid wid_list[4];
+       int i = 0;
+
+       if (param->flag & WILC_CFG_PARAM_RETRY_SHORT) {
+               wid_list[i].id = WID_SHORT_RETRY_LIMIT;
+               wid_list[i].val = (s8 *)&param->short_retry_limit;
+               wid_list[i].type = WID_SHORT;
+               wid_list[i].size = sizeof(u16);
+               i++;
+       }
+       if (param->flag & WILC_CFG_PARAM_RETRY_LONG) {
+               wid_list[i].id = WID_LONG_RETRY_LIMIT;
+               wid_list[i].val = (s8 *)&param->long_retry_limit;
+               wid_list[i].type = WID_SHORT;
+               wid_list[i].size = sizeof(u16);
+               i++;
+       }
+       if (param->flag & WILC_CFG_PARAM_FRAG_THRESHOLD) {
+               wid_list[i].id = WID_FRAG_THRESHOLD;
+               wid_list[i].val = (s8 *)&param->frag_threshold;
+               wid_list[i].type = WID_SHORT;
+               wid_list[i].size = sizeof(u16);
+               i++;
+       }
+       if (param->flag & WILC_CFG_PARAM_RTS_THRESHOLD) {
+               wid_list[i].id = WID_RTS_THRESHOLD;
+               wid_list[i].val = (s8 *)&param->rts_threshold;
+               wid_list[i].type = WID_SHORT;
+               wid_list[i].size = sizeof(u16);
+               i++;
+       }
+
+       return wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, i);
+}
+
+static void get_periodic_rssi(struct timer_list *t)
+{
+       struct wilc_vif *vif = from_timer(vif, t, periodic_rssi);
+
+       if (!vif->hif_drv) {
+               netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
+               return;
+       }
+
+       if (vif->hif_drv->hif_state == HOST_IF_CONNECTED)
+               wilc_get_stats_async(vif, &vif->periodic_stat);
+
+       mod_timer(&vif->periodic_rssi, jiffies + msecs_to_jiffies(5000));
+}
+
+int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler)
+{
+       struct host_if_drv *hif_drv;
+       struct wilc_vif *vif = netdev_priv(dev);
+       struct wilc *wilc = vif->wilc;
+
+       hif_drv  = kzalloc(sizeof(*hif_drv), GFP_KERNEL);
+       if (!hif_drv)
+               return -ENOMEM;
+
+       *hif_drv_handler = hif_drv;
+
+       vif->hif_drv = hif_drv;
+       vif->obtaining_ip = false;
+
+       if (wilc->clients_count == 0)
+               mutex_init(&wilc->deinit_lock);
+
+       timer_setup(&vif->periodic_rssi, get_periodic_rssi, 0);
+       mod_timer(&vif->periodic_rssi, jiffies + msecs_to_jiffies(5000));
+
+       timer_setup(&hif_drv->scan_timer, timer_scan_cb, 0);
+       timer_setup(&hif_drv->connect_timer, timer_connect_cb, 0);
+       timer_setup(&hif_drv->remain_on_ch_timer, listen_timer_cb, 0);
+
+       hif_drv->hif_state = HOST_IF_IDLE;
+
+       hif_drv->p2p_timeout = 0;
+
+       wilc->clients_count++;
+
+       return 0;
+}
+
+int wilc_deinit(struct wilc_vif *vif)
+{
+       int result = 0;
+       struct host_if_drv *hif_drv = vif->hif_drv;
+
+       if (!hif_drv) {
+               netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
+               return -EFAULT;
+       }
+
+       mutex_lock(&vif->wilc->deinit_lock);
+
+       del_timer_sync(&hif_drv->scan_timer);
+       del_timer_sync(&hif_drv->connect_timer);
+       del_timer_sync(&vif->periodic_rssi);
+       del_timer_sync(&hif_drv->remain_on_ch_timer);
+
+       wilc_set_wfi_drv_handler(vif, 0, 0, 0);
+
+       if (hif_drv->usr_scan_req.scan_result) {
+               hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED, NULL,
+                                                 hif_drv->usr_scan_req.arg);
+               hif_drv->usr_scan_req.scan_result = NULL;
+       }
+
+       hif_drv->hif_state = HOST_IF_IDLE;
+
+       kfree(hif_drv);
+       vif->hif_drv = NULL;
+       vif->wilc->clients_count--;
+       mutex_unlock(&vif->wilc->deinit_lock);
+       return result;
+}
+
+void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length)
+{
+       int result;
+       struct host_if_msg *msg;
+       int id;
+       struct host_if_drv *hif_drv;
+       struct wilc_vif *vif;
+
+       id = get_unaligned_le32(&buffer[length - 4]);
+       vif = wilc_get_vif_from_idx(wilc, id);
+       if (!vif)
+               return;
+       hif_drv = vif->hif_drv;
+
+       if (!hif_drv) {
+               netdev_err(vif->ndev, "driver not init[%p]\n", hif_drv);
+               return;
+       }
+
+       msg = wilc_alloc_work(vif, handle_rcvd_ntwrk_info, false);
+       if (IS_ERR(msg))
+               return;
+
+       msg->body.net_info.frame_len = get_unaligned_le16(&buffer[6]) - 1;
+       msg->body.net_info.rssi = buffer[8];
+       msg->body.net_info.mgmt = kmemdup(&buffer[9],
+                                         msg->body.net_info.frame_len,
+                                         GFP_KERNEL);
+       if (!msg->body.net_info.mgmt) {
+               kfree(msg);
+               return;
+       }
+
+       result = wilc_enqueue_work(msg);
+       if (result) {
+               netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+               kfree(msg->body.net_info.mgmt);
+               kfree(msg);
+       }
+}
+
+void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length)
+{
+       int result;
+       struct host_if_msg *msg;
+       int id;
+       struct host_if_drv *hif_drv;
+       struct wilc_vif *vif;
+
+       mutex_lock(&wilc->deinit_lock);
+
+       id = get_unaligned_le32(&buffer[length - 4]);
+       vif = wilc_get_vif_from_idx(wilc, id);
+       if (!vif) {
+               mutex_unlock(&wilc->deinit_lock);
+               return;
+       }
+
+       hif_drv = vif->hif_drv;
+
+       if (!hif_drv) {
+               mutex_unlock(&wilc->deinit_lock);
+               return;
+       }
+
+       if (!hif_drv->conn_info.conn_result) {
+               netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
+               mutex_unlock(&wilc->deinit_lock);
+               return;
+       }
+
+       msg = wilc_alloc_work(vif, handle_rcvd_gnrl_async_info, false);
+       if (IS_ERR(msg)) {
+               mutex_unlock(&wilc->deinit_lock);
+               return;
+       }
+
+       msg->body.mac_info.status = buffer[7];
+       result = wilc_enqueue_work(msg);
+       if (result) {
+               netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+               kfree(msg);
+       }
+
+       mutex_unlock(&wilc->deinit_lock);
+}
+
+void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length)
+{
+       int result;
+       int id;
+       struct host_if_drv *hif_drv;
+       struct wilc_vif *vif;
+
+       id = get_unaligned_le32(&buffer[length - 4]);
+       vif = wilc_get_vif_from_idx(wilc, id);
+       if (!vif)
+               return;
+       hif_drv = vif->hif_drv;
+
+       if (!hif_drv)
+               return;
+
+       if (hif_drv->usr_scan_req.scan_result) {
+               struct host_if_msg *msg;
+
+               msg = wilc_alloc_work(vif, handle_scan_complete, false);
+               if (IS_ERR(msg))
+                       return;
+
+               result = wilc_enqueue_work(msg);
+               if (result) {
+                       netdev_err(vif->ndev, "%s: enqueue work failed\n",
+                                  __func__);
+                       kfree(msg);
+               }
+       }
+}
+
+int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie,
+                          u32 duration, u16 chan,
+                          void (*expired)(void *, u64),
+                          void *user_arg)
+{
+       struct wilc_remain_ch roc;
+       int result;
+
+       roc.ch = chan;
+       roc.expired = expired;
+       roc.arg = user_arg;
+       roc.duration = duration;
+       roc.cookie = cookie;
+       result = handle_remain_on_chan(vif, &roc);
+       if (result)
+               netdev_err(vif->ndev, "%s: failed to set remain on channel\n",
+                          __func__);
+
+       return result;
+}
+
+int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie)
+{
+       if (!vif->hif_drv) {
+               netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
+               return -EFAULT;
+       }
+
+       del_timer(&vif->hif_drv->remain_on_ch_timer);
+
+       return wilc_handle_roc_expired(vif, cookie);
+}
+
+void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg)
+{
+       struct wid wid;
+       int result;
+       struct wilc_reg_frame reg_frame;
+
+       wid.id = WID_REGISTER_FRAME;
+       wid.type = WID_STR;
+       wid.size = sizeof(reg_frame);
+       wid.val = (u8 *)&reg_frame;
+
+       memset(&reg_frame, 0x0, sizeof(reg_frame));
+       reg_frame.reg = reg;
+
+       switch (frame_type) {
+       case IEEE80211_STYPE_ACTION:
+               reg_frame.reg_id = WILC_FW_ACTION_FRM_IDX;
+               break;
+
+       case IEEE80211_STYPE_PROBE_REQ:
+               reg_frame.reg_id = WILC_FW_PROBE_REQ_IDX;
+               break;
+
+       default:
+               break;
+       }
+       reg_frame.frame_type = cpu_to_le16(frame_type);
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       if (result)
+               netdev_err(vif->ndev, "Failed to frame register\n");
+}
+
+int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period,
+                   struct cfg80211_beacon_data *params)
+{
+       struct wid wid;
+       int result;
+       u8 *cur_byte;
+
+       wid.id = WID_ADD_BEACON;
+       wid.type = WID_BIN;
+       wid.size = params->head_len + params->tail_len + 16;
+       wid.val = kzalloc(wid.size, GFP_KERNEL);
+       if (!wid.val)
+               return -ENOMEM;
+
+       cur_byte = wid.val;
+       put_unaligned_le32(interval, cur_byte);
+       cur_byte += 4;
+       put_unaligned_le32(dtim_period, cur_byte);
+       cur_byte += 4;
+       put_unaligned_le32(params->head_len, cur_byte);
+       cur_byte += 4;
+
+       if (params->head_len > 0)
+               memcpy(cur_byte, params->head, params->head_len);
+       cur_byte += params->head_len;
+
+       put_unaligned_le32(params->tail_len, cur_byte);
+       cur_byte += 4;
+
+       if (params->tail_len > 0)
+               memcpy(cur_byte, params->tail, params->tail_len);
+
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       if (result)
+               netdev_err(vif->ndev, "Failed to send add beacon\n");
+
+       kfree(wid.val);
+
+       return result;
+}
+
+int wilc_del_beacon(struct wilc_vif *vif)
+{
+       int result;
+       struct wid wid;
+       u8 del_beacon = 0;
+
+       wid.id = WID_DEL_BEACON;
+       wid.type = WID_CHAR;
+       wid.size = sizeof(char);
+       wid.val = &del_beacon;
+
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       if (result)
+               netdev_err(vif->ndev, "Failed to send delete beacon\n");
+
+       return result;
+}
+
+int wilc_add_station(struct wilc_vif *vif, const u8 *mac,
+                    struct station_parameters *params)
+{
+       struct wid wid;
+       int result;
+       u8 *cur_byte;
+
+       wid.id = WID_ADD_STA;
+       wid.type = WID_BIN;
+       wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len;
+       wid.val = kmalloc(wid.size, GFP_KERNEL);
+       if (!wid.val)
+               return -ENOMEM;
+
+       cur_byte = wid.val;
+       wilc_hif_pack_sta_param(cur_byte, mac, params);
+
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       if (result != 0)
+               netdev_err(vif->ndev, "Failed to send add station\n");
+
+       kfree(wid.val);
+
+       return result;
+}
+
+int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr)
+{
+       struct wid wid;
+       int result;
+
+       wid.id = WID_REMOVE_STA;
+       wid.type = WID_BIN;
+       wid.size = ETH_ALEN;
+       wid.val = kzalloc(wid.size, GFP_KERNEL);
+       if (!wid.val)
+               return -ENOMEM;
+
+       if (!mac_addr)
+               eth_broadcast_addr(wid.val);
+       else
+               ether_addr_copy(wid.val, mac_addr);
+
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       if (result)
+               netdev_err(vif->ndev, "Failed to del station\n");
+
+       kfree(wid.val);
+
+       return result;
+}
+
+int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN])
+{
+       struct wid wid;
+       int result;
+       int i;
+       u8 assoc_sta = 0;
+       struct wilc_del_all_sta del_sta;
+
+       memset(&del_sta, 0x0, sizeof(del_sta));
+       for (i = 0; i < WILC_MAX_NUM_STA; i++) {
+               if (!is_zero_ether_addr(mac_addr[i])) {
+                       assoc_sta++;
+                       ether_addr_copy(del_sta.mac[i], mac_addr[i]);
+               }
+       }
+
+       if (!assoc_sta)
+               return 0;
+
+       del_sta.assoc_sta = assoc_sta;
+
+       wid.id = WID_DEL_ALL_STA;
+       wid.type = WID_STR;
+       wid.size = (assoc_sta * ETH_ALEN) + 1;
+       wid.val = (u8 *)&del_sta;
+
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       if (result)
+               netdev_err(vif->ndev, "Failed to send delete all station\n");
+
+       return result;
+}
+
+int wilc_edit_station(struct wilc_vif *vif, const u8 *mac,
+                     struct station_parameters *params)
+{
+       struct wid wid;
+       int result;
+       u8 *cur_byte;
+
+       wid.id = WID_EDIT_STA;
+       wid.type = WID_BIN;
+       wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len;
+       wid.val = kmalloc(wid.size, GFP_KERNEL);
+       if (!wid.val)
+               return -ENOMEM;
+
+       cur_byte = wid.val;
+       wilc_hif_pack_sta_param(cur_byte, mac, params);
+
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       if (result)
+               netdev_err(vif->ndev, "Failed to send edit station\n");
+
+       kfree(wid.val);
+       return result;
+}
+
+int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout)
+{
+       struct wid wid;
+       int result;
+       s8 power_mode;
+
+       if (wilc_wlan_get_num_conn_ifcs(vif->wilc) == 2 && enabled)
+               return 0;
+
+       if (enabled)
+               power_mode = WILC_FW_MIN_FAST_PS;
+       else
+               power_mode = WILC_FW_NO_POWERSAVE;
+
+       wid.id = WID_POWER_MANAGEMENT;
+       wid.val = &power_mode;
+       wid.size = sizeof(char);
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       if (result)
+               netdev_err(vif->ndev, "Failed to send power management\n");
+
+       return result;
+}
+
+int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count,
+                               u8 *mc_list)
+{
+       int result;
+       struct host_if_msg *msg;
+
+       msg = wilc_alloc_work(vif, handle_set_mcast_filter, false);
+       if (IS_ERR(msg))
+               return PTR_ERR(msg);
+
+       msg->body.mc_info.enabled = enabled;
+       msg->body.mc_info.cnt = count;
+       msg->body.mc_info.mc_list = mc_list;
+
+       result = wilc_enqueue_work(msg);
+       if (result) {
+               netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+               kfree(msg);
+       }
+       return result;
+}
+
+int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power)
+{
+       struct wid wid;
+
+       wid.id = WID_TX_POWER;
+       wid.type = WID_CHAR;
+       wid.val = &tx_power;
+       wid.size = sizeof(char);
+
+       return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+}
+
+int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power)
+{
+       struct wid wid;
+
+       wid.id = WID_TX_POWER;
+       wid.type = WID_CHAR;
+       wid.val = tx_power;
+       wid.size = sizeof(char);
+
+       return wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
+}
diff --git a/drivers/staging/wilc1000/wilc_hif.h b/drivers/staging/wilc1000/wilc_hif.h
new file mode 100644 (file)
index 0000000..be1d249
--- /dev/null
@@ -0,0 +1,235 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries
+ * All rights reserved.
+ */
+
+#ifndef HOST_INT_H
+#define HOST_INT_H
+#include <linux/ieee80211.h>
+#include "wilc_wlan_if.h"
+
+enum {
+       WILC_IDLE_MODE = 0x0,
+       WILC_AP_MODE = 0x1,
+       WILC_STATION_MODE = 0x2,
+       WILC_GO_MODE = 0x3,
+       WILC_CLIENT_MODE = 0x4
+};
+
+#define WILC_MAX_NUM_STA                       9
+#define WILC_MAX_NUM_SCANNED_CH                        14
+#define WILC_MAX_NUM_PROBED_SSID               10
+
+#define WILC_TX_MIC_KEY_LEN                    8
+#define WILC_RX_MIC_KEY_LEN                    8
+
+#define WILC_MAX_NUM_PMKIDS                    16
+#define WILC_ADD_STA_LENGTH                    40
+#define WILC_NUM_CONCURRENT_IFC                        2
+
+enum {
+       WILC_SET_CFG = 0,
+       WILC_GET_CFG
+};
+
+#define WILC_MAX_ASSOC_RESP_FRAME_SIZE   256
+
+struct assoc_resp {
+       __le16 capab_info;
+       __le16 status_code;
+       __le16 aid;
+} __packed;
+
+struct rf_info {
+       u8 link_speed;
+       s8 rssi;
+       u32 tx_cnt;
+       u32 rx_cnt;
+       u32 tx_fail_cnt;
+};
+
+enum host_if_state {
+       HOST_IF_IDLE                    = 0,
+       HOST_IF_SCANNING                = 1,
+       HOST_IF_CONNECTING              = 2,
+       HOST_IF_WAITING_CONN_RESP       = 3,
+       HOST_IF_CONNECTED               = 4,
+       HOST_IF_P2P_LISTEN              = 5,
+       HOST_IF_FORCE_32BIT             = 0xFFFFFFFF
+};
+
+struct wilc_pmkid {
+       u8 bssid[ETH_ALEN];
+       u8 pmkid[WLAN_PMKID_LEN];
+} __packed;
+
+struct wilc_pmkid_attr {
+       u8 numpmkid;
+       struct wilc_pmkid pmkidlist[WILC_MAX_NUM_PMKIDS];
+} __packed;
+
+struct cfg_param_attr {
+       u32 flag;
+       u16 short_retry_limit;
+       u16 long_retry_limit;
+       u16 frag_threshold;
+       u16 rts_threshold;
+};
+
+enum cfg_param {
+       WILC_CFG_PARAM_RETRY_SHORT = BIT(0),
+       WILC_CFG_PARAM_RETRY_LONG = BIT(1),
+       WILC_CFG_PARAM_FRAG_THRESHOLD = BIT(2),
+       WILC_CFG_PARAM_RTS_THRESHOLD = BIT(3)
+};
+
+enum scan_event {
+       SCAN_EVENT_NETWORK_FOUND        = 0,
+       SCAN_EVENT_DONE                 = 1,
+       SCAN_EVENT_ABORTED              = 2,
+       SCAN_EVENT_FORCE_32BIT          = 0xFFFFFFFF
+};
+
+enum conn_event {
+       CONN_DISCONN_EVENT_CONN_RESP            = 0,
+       CONN_DISCONN_EVENT_DISCONN_NOTIF        = 1,
+       CONN_DISCONN_EVENT_FORCE_32BIT          = 0xFFFFFFFF
+};
+
+enum {
+       WILC_HIF_SDIO = 0,
+       WILC_HIF_SPI = BIT(0)
+};
+
+enum {
+       WILC_MAC_STATUS_INIT = -1,
+       WILC_MAC_STATUS_DISCONNECTED = 0,
+       WILC_MAC_STATUS_CONNECTED = 1
+};
+
+struct wilc_rcvd_net_info {
+       s8 rssi;
+       u8 ch;
+       u16 frame_len;
+       struct ieee80211_mgmt *mgmt;
+};
+
+struct wilc_user_scan_req {
+       void (*scan_result)(enum scan_event evt,
+                           struct wilc_rcvd_net_info *info, void *priv);
+       void *arg;
+       u32 ch_cnt;
+};
+
+struct wilc_conn_info {
+       u8 bssid[ETH_ALEN];
+       u8 security;
+       enum authtype auth_type;
+       u8 ch;
+       u8 *req_ies;
+       size_t req_ies_len;
+       u8 *resp_ies;
+       u16 resp_ies_len;
+       u16 status;
+       void (*conn_result)(enum conn_event evt, u8 status, void *priv_data);
+       void *arg;
+       void *param;
+};
+
+struct wilc_remain_ch {
+       u16 ch;
+       u32 duration;
+       void (*expired)(void *priv, u64 cookie);
+       void *arg;
+       u32 cookie;
+};
+
+struct wilc;
+struct host_if_drv {
+       struct wilc_user_scan_req usr_scan_req;
+       struct wilc_conn_info conn_info;
+       struct wilc_remain_ch remain_on_ch;
+       u64 p2p_timeout;
+
+       enum host_if_state hif_state;
+
+       u8 assoc_bssid[ETH_ALEN];
+
+       struct timer_list scan_timer;
+       struct wilc_vif *scan_timer_vif;
+
+       struct timer_list connect_timer;
+       struct wilc_vif *connect_timer_vif;
+
+       struct timer_list remain_on_ch_timer;
+       struct wilc_vif *remain_on_ch_timer_vif;
+
+       bool ifc_up;
+       u8 assoc_resp[WILC_MAX_ASSOC_RESP_FRAME_SIZE];
+};
+
+struct wilc_vif;
+int wilc_remove_wep_key(struct wilc_vif *vif, u8 index);
+int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index);
+int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
+                            u8 index);
+int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len,
+                           u8 index, u8 mode, enum authtype auth_type);
+int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
+                const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic,
+                u8 mode, u8 cipher_mode, u8 index);
+s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac,
+                          u32 *out_val);
+int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
+                   u8 index, u32 key_rsc_len, const u8 *key_rsc,
+                   const u8 *rx_mic, const u8 *tx_mic, u8 mode,
+                   u8 cipher_mode);
+int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid);
+int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr);
+int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies,
+                     size_t ies_len);
+int wilc_disconnect(struct wilc_vif *vif);
+int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel);
+int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level);
+int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
+             u8 *ch_freq_list, u8 ch_list_len,
+             void (*scan_result_fn)(enum scan_event,
+                                    struct wilc_rcvd_net_info *, void *),
+             void *user_arg, struct cfg80211_scan_request *request);
+int wilc_hif_set_cfg(struct wilc_vif *vif,
+                    struct cfg_param_attr *cfg_param);
+int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler);
+int wilc_deinit(struct wilc_vif *vif);
+int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period,
+                   struct cfg80211_beacon_data *params);
+int wilc_del_beacon(struct wilc_vif *vif);
+int wilc_add_station(struct wilc_vif *vif, const u8 *mac,
+                    struct station_parameters *params);
+int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN]);
+int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr);
+int wilc_edit_station(struct wilc_vif *vif, const u8 *mac,
+                     struct station_parameters *params);
+int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout);
+int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count,
+                               u8 *mc_list);
+int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie,
+                          u32 duration, u16 chan,
+                          void (*expired)(void *, u64),
+                          void *user_arg);
+int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie);
+void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg);
+int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode,
+                            u8 ifc_id);
+int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode);
+int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats);
+void wilc_resolve_disconnect_aberration(struct wilc_vif *vif);
+int wilc_get_vif_idx(struct wilc_vif *vif);
+int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power);
+int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power);
+void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length);
+void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length);
+void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length);
+void *wilc_parse_join_bss_param(struct cfg80211_bss *bss,
+                               struct cfg80211_crypto_settings *crypto);
+#endif
index 9fe19a3..7d7933d 100644 (file)
@@ -233,6 +233,7 @@ struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl,
        strncpy(wl->monitor_dev->name, name, IFNAMSIZ);
        wl->monitor_dev->name[IFNAMSIZ - 1] = 0;
        wl->monitor_dev->netdev_ops = &wilc_wfi_netdev_ops;
+       wl->monitor_dev->needs_free_netdev = true;
 
        if (register_netdevice(wl->monitor_dev)) {
                netdev_err(real_dev, "register_netdevice failed\n");
@@ -247,12 +248,14 @@ struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl,
        return wl->monitor_dev;
 }
 
-void wilc_wfi_deinit_mon_interface(struct wilc *wl)
+void wilc_wfi_deinit_mon_interface(struct wilc *wl, bool rtnl_locked)
 {
        if (!wl->monitor_dev)
                return;
 
-       unregister_netdev(wl->monitor_dev);
-       free_netdev(wl->monitor_dev);
+       if (rtnl_locked)
+               unregister_netdevice(wl->monitor_dev);
+       else
+               unregister_netdev(wl->monitor_dev);
        wl->monitor_dev = NULL;
 }
index ba78c08..565e2b5 100644 (file)
@@ -97,22 +97,29 @@ static struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header)
 {
        u8 *bssid, *bssid1;
        int i = 0;
+       struct net_device *ndev = NULL;
 
        bssid = mac_header + 10;
        bssid1 = mac_header + 4;
 
+       mutex_lock(&wilc->vif_mutex);
        for (i = 0; i < wilc->vif_num; i++) {
                if (wilc->vif[i]->mode == WILC_STATION_MODE)
                        if (ether_addr_equal_unaligned(bssid,
-                                                      wilc->vif[i]->bssid))
-                               return wilc->vif[i]->ndev;
+                                                      wilc->vif[i]->bssid)) {
+                               ndev = wilc->vif[i]->ndev;
+                               goto out;
+                       }
                if (wilc->vif[i]->mode == WILC_AP_MODE)
                        if (ether_addr_equal_unaligned(bssid1,
-                                                      wilc->vif[i]->bssid))
-                               return wilc->vif[i]->ndev;
+                                                      wilc->vif[i]->bssid)) {
+                               ndev = wilc->vif[i]->ndev;
+                               goto out;
+                       }
        }
-
-       return NULL;
+out:
+       mutex_unlock(&wilc->vif_mutex);
+       return ndev;
 }
 
 void wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode)
@@ -143,9 +150,7 @@ static int wilc_txq_task(void *vp)
 {
        int ret;
        u32 txq_count;
-       struct net_device *dev = vp;
-       struct wilc_vif *vif = netdev_priv(dev);
-       struct wilc *wl = vif->wilc;
+       struct wilc *wl = vp;
 
        complete(&wl->txq_thread_started);
        while (1) {
@@ -159,14 +164,18 @@ static int wilc_txq_task(void *vp)
                        break;
                }
                do {
-                       ret = wilc_wlan_handle_txq(dev, &txq_count);
+                       ret = wilc_wlan_handle_txq(wl, &txq_count);
                        if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD) {
-                               if (wl->vif[0]->mac_opened &&
-                                   netif_queue_stopped(wl->vif[0]->ndev))
-                                       netif_wake_queue(wl->vif[0]->ndev);
-                               if (wl->vif[1]->mac_opened &&
-                                   netif_queue_stopped(wl->vif[1]->ndev))
-                                       netif_wake_queue(wl->vif[1]->ndev);
+                               int i;
+                               struct wilc_vif *ifc;
+
+                               mutex_lock(&wl->vif_mutex);
+                               for (i = 0; i < wl->vif_num; i++) {
+                                       ifc = wl->vif[i];
+                                       if (ifc->mac_opened && ifc->ndev)
+                                               netif_wake_queue(ifc->ndev);
+                               }
+                               mutex_unlock(&wl->vif_mutex);
                        }
                } while (ret == -ENOBUFS && !wl->close);
        }
@@ -245,14 +254,13 @@ static int wilc1000_firmware_download(struct net_device *dev)
 
 static int wilc_init_fw_config(struct net_device *dev, struct wilc_vif *vif)
 {
-       struct wilc_priv *priv;
+       struct wilc_priv *priv = &vif->priv;
        struct host_if_drv *hif_drv;
        u8 b;
        u16 hw;
        u32 w;
 
        netdev_dbg(dev, "Start configuring Firmware\n");
-       priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
        hif_drv = (struct host_if_drv *)priv->hif_drv;
        netdev_dbg(dev, "Host = %p\n", hif_drv);
 
@@ -424,6 +432,7 @@ static void wlan_deinit_locks(struct net_device *dev)
        mutex_destroy(&wilc->rxq_cs);
        mutex_destroy(&wilc->cfg_cmd_lock);
        mutex_destroy(&wilc->txq_add_to_head_cs);
+       mutex_destroy(&wilc->vif_mutex);
 }
 
 static void wlan_deinitialize_threads(struct net_device *dev)
@@ -477,31 +486,12 @@ static void wilc_wlan_deinitialize(struct net_device *dev)
        }
 }
 
-static void wlan_init_locks(struct net_device *dev)
-{
-       struct wilc_vif *vif = netdev_priv(dev);
-       struct wilc *wl = vif->wilc;
-
-       mutex_init(&wl->hif_cs);
-       mutex_init(&wl->rxq_cs);
-       mutex_init(&wl->cfg_cmd_lock);
-
-       spin_lock_init(&wl->txq_spinlock);
-       mutex_init(&wl->txq_add_to_head_cs);
-
-       init_completion(&wl->txq_event);
-
-       init_completion(&wl->cfg_event);
-       init_completion(&wl->sync_event);
-       init_completion(&wl->txq_thread_started);
-}
-
 static int wlan_initialize_threads(struct net_device *dev)
 {
        struct wilc_vif *vif = netdev_priv(dev);
        struct wilc *wilc = vif->wilc;
 
-       wilc->txq_thread = kthread_run(wilc_txq_task, (void *)dev,
+       wilc->txq_thread = kthread_run(wilc_txq_task, (void *)wilc,
                                       "K_TXQ_TASK");
        if (IS_ERR(wilc->txq_thread)) {
                netdev_err(dev, "couldn't create TXQ thread\n");
@@ -513,6 +503,12 @@ static int wlan_initialize_threads(struct net_device *dev)
        return 0;
 }
 
+static int dev_state_ev_handler(struct notifier_block *this,
+                               unsigned long event, void *ptr);
+static struct notifier_block g_dev_notifier = {
+       .notifier_call = dev_state_ev_handler
+};
+
 static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif)
 {
        int ret = 0;
@@ -522,23 +518,19 @@ static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif)
                wl->mac_status = WILC_MAC_STATUS_INIT;
                wl->close = 0;
 
-               wlan_init_locks(dev);
-
                ret = wilc_wlan_init(dev);
+               if (ret < 0)
+                       return -EIO;
+
+               ret = wlan_initialize_threads(dev);
                if (ret < 0) {
                        ret = -EIO;
-                       goto fail_locks;
+                       goto fail_wilc_wlan;
                }
 
                if (wl->gpio_irq && init_irq(dev)) {
                        ret = -EIO;
-                       goto fail_locks;
-               }
-
-               ret = wlan_initialize_threads(dev);
-               if (ret < 0) {
-                       ret = -EIO;
-                       goto fail_wilc_wlan;
+                       goto fail_threads;
                }
 
                if (!wl->dev_irq_num &&
@@ -582,7 +574,7 @@ static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif)
                        ret = -EIO;
                        goto fail_fw_start;
                }
-
+               register_inetaddr_notifier(&g_dev_notifier);
                wl->initialized = true;
                return 0;
 
@@ -596,12 +588,10 @@ fail_irq_enable:
 fail_irq_init:
                if (wl->dev_irq_num)
                        deinit_irq(dev);
-
+fail_threads:
                wlan_deinitialize_threads(dev);
 fail_wilc_wlan:
                wilc_wlan_cleanup(dev);
-fail_locks:
-               wlan_deinit_locks(dev);
                netdev_err(dev, "WLAN initialization FAILED\n");
        } else {
                netdev_dbg(dev, "wilc1000 already initialized\n");
@@ -624,7 +614,6 @@ static int wilc_mac_open(struct net_device *ndev)
        struct wilc_priv *priv = wdev_priv(vif->ndev->ieee80211_ptr);
        unsigned char mac_add[ETH_ALEN] = {0};
        int ret = 0;
-       int i = 0;
 
        if (!wl || !wl->dev) {
                netdev_err(ndev, "device not ready\n");
@@ -643,19 +632,13 @@ static int wilc_mac_open(struct net_device *ndev)
                return ret;
        }
 
-       for (i = 0; i < wl->vif_num; i++) {
-               if (ndev == wl->vif[i]->ndev) {
-                       wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif),
-                                                vif->iftype, vif->ifc_id);
-                       wilc_set_operation_mode(vif, vif->iftype);
-                       break;
-               }
-       }
+       wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif), vif->iftype,
+                                vif->idx);
+       wilc_set_operation_mode(vif, vif->iftype);
 
        wilc_get_mac_address(vif, mac_add);
        netdev_dbg(ndev, "Mac address: %pM\n", mac_add);
-       memcpy(wl->vif[i]->src_addr, mac_add, ETH_ALEN);
-       memcpy(ndev->dev_addr, wl->vif[i]->src_addr, ETH_ALEN);
+       ether_addr_copy(ndev->dev_addr, mac_add);
 
        if (!is_valid_ether_addr(ndev->dev_addr)) {
                netdev_err(ndev, "Wrong MAC address\n");
@@ -758,16 +741,19 @@ netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev)
 
        vif->netstats.tx_packets++;
        vif->netstats.tx_bytes += tx_data->size;
-       tx_data->bssid = wilc->vif[vif->idx]->bssid;
        queue_count = wilc_wlan_txq_add_net_pkt(ndev, (void *)tx_data,
                                                tx_data->buff, tx_data->size,
                                                wilc_tx_complete);
 
        if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) {
-               if (wilc->vif[0]->mac_opened)
-                       netif_stop_queue(wilc->vif[0]->ndev);
-               if (wilc->vif[1]->mac_opened)
-                       netif_stop_queue(wilc->vif[1]->ndev);
+               int i;
+
+               mutex_lock(&wilc->vif_mutex);
+               for (i = 0; i < wilc->vif_num; i++) {
+                       if (wilc->vif[i]->mac_opened)
+                               netif_stop_queue(wilc->vif[i]->ndev);
+               }
+               mutex_unlock(&wilc->vif_mutex);
        }
 
        return 0;
@@ -794,6 +780,7 @@ static int wilc_mac_close(struct net_device *ndev)
        if (wl->open_ifcs == 0) {
                netdev_dbg(ndev, "Deinitializing wilc1000\n");
                wl->close = 1;
+               unregister_inetaddr_notifier(&g_dev_notifier);
                wilc_wlan_deinitialize(ndev);
        }
 
@@ -848,18 +835,23 @@ void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size)
        int i = 0;
        struct wilc_vif *vif;
 
+       mutex_lock(&wilc->vif_mutex);
        for (i = 0; i < wilc->vif_num; i++) {
+               u16 type = le16_to_cpup((__le16 *)buff);
+
                vif = netdev_priv(wilc->vif[i]->ndev);
+               if ((type == vif->frame_reg[0].type && vif->frame_reg[0].reg) ||
+                   (type == vif->frame_reg[1].type && vif->frame_reg[1].reg)) {
+                       wilc_wfi_p2p_rx(vif, buff, size);
+                       break;
+               }
+
                if (vif->monitor_flag) {
                        wilc_wfi_monitor_rx(wilc->monitor_dev, buff, size);
-                       return;
+                       break;
                }
        }
-
-       vif = netdev_priv(wilc->vif[1]->ndev);
-       if ((buff[0] == vif->frame_reg[0].type && vif->frame_reg[0].reg) ||
-           (buff[0] == vif->frame_reg[1].type && vif->frame_reg[1].reg))
-               wilc_wfi_p2p_rx(wilc->vif[1]->ndev, buff, size);
+       mutex_unlock(&wilc->vif_mutex);
 }
 
 static const struct net_device_ops wilc_netdev_ops = {
@@ -890,14 +882,10 @@ static int dev_state_ev_handler(struct notifier_block *this,
        if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
                return NOTIFY_DONE;
 
-       priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
-       if (!priv)
-               return NOTIFY_DONE;
+       vif = netdev_priv(dev);
+       priv = &vif->priv;
 
        hif_drv = (struct host_if_drv *)priv->hif_drv;
-       vif = netdev_priv(dev);
-       if (!vif || !hif_drv)
-               return NOTIFY_DONE;
 
        switch (event) {
        case NETDEV_UP:
@@ -932,10 +920,6 @@ static int dev_state_ev_handler(struct notifier_block *this,
        return NOTIFY_DONE;
 }
 
-static struct notifier_block g_dev_notifier = {
-       .notifier_call = dev_state_ev_handler
-};
-
 void wilc_netdev_cleanup(struct wilc *wilc)
 {
        int i;
@@ -943,137 +927,71 @@ void wilc_netdev_cleanup(struct wilc *wilc)
        if (!wilc)
                return;
 
-       if (wilc->vif[0]->ndev || wilc->vif[1]->ndev)
-               unregister_inetaddr_notifier(&g_dev_notifier);
-
        if (wilc->firmware) {
                release_firmware(wilc->firmware);
                wilc->firmware = NULL;
        }
 
-       for (i = 0; i < WILC_NUM_CONCURRENT_IFC; i++) {
-               if (wilc->vif[i] && wilc->vif[i]->ndev) {
+       for (i = 0; i < wilc->vif_num; i++) {
+               if (wilc->vif[i] && wilc->vif[i]->ndev)
                        unregister_netdev(wilc->vif[i]->ndev);
-                       wilc_free_wiphy(wilc->vif[i]->ndev);
-                       free_netdev(wilc->vif[i]->ndev);
-               }
        }
 
-       wilc_wfi_deinit_mon_interface(wilc);
+       wilc_wfi_deinit_mon_interface(wilc, false);
        flush_workqueue(wilc->hif_workqueue);
        destroy_workqueue(wilc->hif_workqueue);
        wilc_wlan_cfg_deinit(wilc);
        kfree(wilc->bus_data);
-       kfree(wilc);
+       wiphy_unregister(wilc->wiphy);
+       wiphy_free(wilc->wiphy);
 }
 EXPORT_SYMBOL_GPL(wilc_netdev_cleanup);
 
-int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type,
-                    const struct wilc_hif_func *ops)
+struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name,
+                                     int vif_type, enum nl80211_iftype type,
+                                     bool rtnl_locked)
 {
-       int i, ret;
-       struct wilc_vif *vif;
        struct net_device *ndev;
-       struct wilc *wl;
-
-       wl = kzalloc(sizeof(*wl), GFP_KERNEL);
-       if (!wl)
-               return -ENOMEM;
-
-       ret = wilc_wlan_cfg_init(wl);
-       if (ret)
-               goto free_wl;
-
-       *wilc = wl;
-       wl->io_type = io_type;
-       wl->hif_func = ops;
-       wl->enable_ps = true;
-       wl->chip_ps_state = WILC_CHIP_WAKEDUP;
-       INIT_LIST_HEAD(&wl->txq_head.list);
-       INIT_LIST_HEAD(&wl->rxq_head.list);
-
-       wl->hif_workqueue = create_singlethread_workqueue("WILC_wq");
-       if (!wl->hif_workqueue) {
-               ret = -ENOMEM;
-               goto free_cfg;
-       }
-
-       register_inetaddr_notifier(&g_dev_notifier);
-
-       for (i = 0; i < WILC_NUM_CONCURRENT_IFC; i++) {
-               struct wireless_dev *wdev;
+       struct wilc_vif *vif;
+       int ret;
 
-               ndev = alloc_etherdev(sizeof(struct wilc_vif));
-               if (!ndev) {
-                       ret = -ENOMEM;
-                       goto free_ndev;
-               }
+       ndev = alloc_etherdev(sizeof(*vif));
+       if (!ndev)
+               return ERR_PTR(-ENOMEM);
 
-               vif = netdev_priv(ndev);
-               memset(vif, 0, sizeof(struct wilc_vif));
+       vif = netdev_priv(ndev);
+       ndev->ieee80211_ptr = &vif->priv.wdev;
+       strcpy(ndev->name, name);
+       vif->wilc = wl;
+       vif->ndev = ndev;
+       ndev->ml_priv = vif;
 
-               if (i == 0) {
-                       strcpy(ndev->name, "wlan%d");
-                       vif->ifc_id = 1;
-               } else {
-                       strcpy(ndev->name, "p2p%d");
-                       vif->ifc_id = 0;
-               }
-               vif->wilc = *wilc;
-               vif->ndev = ndev;
-               wl->vif[i] = vif;
-               wl->vif_num = i + 1;
-               vif->idx = i;
-
-               ndev->netdev_ops = &wilc_netdev_ops;
-
-               wdev = wilc_create_wiphy(ndev, dev);
-               if (!wdev) {
-                       netdev_err(ndev, "Can't register WILC Wiphy\n");
-                       ret = -ENOMEM;
-                       goto free_ndev;
-               }
+       ndev->netdev_ops = &wilc_netdev_ops;
 
-               SET_NETDEV_DEV(ndev, dev);
+       SET_NETDEV_DEV(ndev, wiphy_dev(wl->wiphy));
 
-               vif->ndev->ieee80211_ptr = wdev;
-               vif->ndev->ml_priv = vif;
-               wdev->netdev = vif->ndev;
-               vif->netstats.rx_packets = 0;
-               vif->netstats.tx_packets = 0;
-               vif->netstats.rx_bytes = 0;
-               vif->netstats.tx_bytes = 0;
+       vif->priv.wdev.wiphy = wl->wiphy;
+       vif->priv.wdev.netdev = ndev;
+       vif->priv.wdev.iftype = type;
+       vif->priv.dev = ndev;
 
+       if (rtnl_locked)
+               ret = register_netdevice(ndev);
+       else
                ret = register_netdev(ndev);
-               if (ret)
-                       goto free_ndev;
 
-               vif->iftype = WILC_STATION_MODE;
-               vif->mac_opened = 0;
+       if (ret) {
+               free_netdev(ndev);
+               return ERR_PTR(-EFAULT);
        }
 
-       return 0;
-
-free_ndev:
-       for (; i >= 0; i--) {
-               if (wl->vif[i]) {
-                       if (wl->vif[i]->iftype == WILC_STATION_MODE)
-                               unregister_netdev(wl->vif[i]->ndev);
-
-                       if (wl->vif[i]->ndev) {
-                               wilc_free_wiphy(wl->vif[i]->ndev);
-                               free_netdev(wl->vif[i]->ndev);
-                       }
-               }
-       }
-       unregister_inetaddr_notifier(&g_dev_notifier);
-       destroy_workqueue(wl->hif_workqueue);
-free_cfg:
-       wilc_wlan_cfg_deinit(wl);
-free_wl:
-       kfree(wl);
-       return ret;
+       ndev->needs_free_netdev = true;
+       vif->iftype = vif_type;
+       vif->wilc->vif[wl->vif_num] = vif;
+       vif->idx = wl->vif_num;
+       wl->vif_num += 1;
+       vif->mac_opened = 0;
+       return vif;
 }
-EXPORT_SYMBOL_GPL(wilc_netdev_init);
 
 MODULE_LICENSE("GPL");
index b789c57..4c1c81f 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/mmc/host.h>
 
 #include "wilc_wfi_netdevice.h"
+#include "wilc_wfi_cfgoperations.h"
 
 #define SDIO_MODALIAS "wilc1000_sdio"
 
@@ -139,11 +140,9 @@ static int wilc_sdio_probe(struct sdio_func *func,
                }
        }
 
-       dev_dbg(&func->dev, "Initializing netdev\n");
-       ret = wilc_netdev_init(&wilc, &func->dev, WILC_HIF_SDIO,
-                              &wilc_hif_sdio);
+       ret = wilc_cfg80211_init(&wilc, &func->dev, WILC_HIF_SDIO,
+                                &wilc_hif_sdio);
        if (ret) {
-               dev_err(&func->dev, "Couldn't initialize netdev\n");
                kfree(sdio_priv);
                return ret;
        }
index d8910bf..3c1ae9e 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/spi/spi.h>
 
 #include "wilc_wfi_netdevice.h"
+#include "wilc_wfi_cfgoperations.h"
 
 struct wilc_spi {
        int crc_off;
@@ -120,7 +121,7 @@ static int wilc_bus_probe(struct spi_device *spi)
                        dev_err(&spi->dev, "failed to get the irq gpio\n");
        }
 
-       ret = wilc_netdev_init(&wilc, NULL, WILC_HIF_SPI, &wilc_hif_spi);
+       ret = wilc_cfg80211_init(&wilc, &spi->dev, WILC_HIF_SPI, &wilc_hif_spi);
        if (ret) {
                kfree(spi_priv);
                return ret;
index f682572..d72fdd3 100644 (file)
@@ -183,47 +183,67 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status,
                eth_zero_addr(priv->associated_bss);
                wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE);
 
-               if (vif->iftype != WILC_CLIENT_MODE)
+               if (vif->iftype != WILC_CLIENT_MODE) {
                        wl->sta_ch = WILC_INVALID_CHANNEL;
-
-               if (wfi_drv->ifc_up && dev == wl->vif[1]->ndev)
-                       reason = 3;
-               else if (!wfi_drv->ifc_up && dev == wl->vif[1]->ndev)
-                       reason = 1;
+               } else {
+                       if (wfi_drv->ifc_up)
+                               reason = 3;
+                       else
+                               reason = 1;
+               }
 
                cfg80211_disconnected(dev, reason, NULL, 0, false, GFP_KERNEL);
        }
 }
 
+static struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl)
+{
+       int i;
+
+       for (i = 0; i < wl->vif_num; i++)
+               if (wl->vif[i])
+                       return wl->vif[i];
+
+       return ERR_PTR(-EINVAL);
+}
+
 static int set_channel(struct wiphy *wiphy,
                       struct cfg80211_chan_def *chandef)
 {
-       u32 channelnum = 0;
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct wilc_vif *vif = netdev_priv(priv->dev);
-       int result = 0;
+       struct wilc *wl = wiphy_priv(wiphy);
+       struct wilc_vif *vif;
+       u32 channelnum;
+       int result;
+
+       mutex_lock(&wl->vif_mutex);
+       vif = wilc_get_wl_to_vif(wl);
+       if (IS_ERR(vif)) {
+               mutex_unlock(&wl->vif_mutex);
+               return PTR_ERR(vif);
+       }
 
        channelnum = ieee80211_frequency_to_channel(chandef->chan->center_freq);
 
-       vif->wilc->op_ch = channelnum;
+       wl->op_ch = channelnum;
        result = wilc_set_mac_chnl_num(vif, channelnum);
+       if (result)
+               netdev_err(vif->ndev, "Error in setting channel\n");
 
-       if (result != 0)
-               netdev_err(priv->dev, "Error in setting channel\n");
-
+       mutex_unlock(&wl->vif_mutex);
        return result;
 }
 
 static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
 {
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct wilc_vif *vif = netdev_priv(priv->dev);
+       struct wilc_vif *vif = netdev_priv(request->wdev->netdev);
+       struct wilc_priv *priv = &vif->priv;
        u32 i;
        int ret = 0;
        u8 scan_ch_list[WILC_MAX_NUM_SCANNED_CH];
+       u8 scan_type;
 
        if (request->n_channels > WILC_MAX_NUM_SCANNED_CH) {
-               netdev_err(priv->dev, "Requested scanned channels over\n");
+               netdev_err(vif->ndev, "Requested scanned channels over\n");
                return -EINVAL;
        }
 
@@ -235,9 +255,14 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
                scan_ch_list[i] = ieee80211_frequency_to_channel(freq);
        }
 
-       ret = wilc_scan(vif, WILC_FW_USER_SCAN, WILC_FW_ACTIVE_SCAN,
-                       scan_ch_list, request->n_channels, cfg_scan_result,
-                       (void *)priv, request);
+       if (request->n_ssids)
+               scan_type = WILC_FW_ACTIVE_SCAN;
+       else
+               scan_type = WILC_FW_PASSIVE_SCAN;
+
+       ret = wilc_scan(vif, WILC_FW_USER_SCAN, scan_type, scan_ch_list,
+                       request->n_channels, cfg_scan_result, (void *)priv,
+                       request);
 
        if (ret) {
                priv->scan_req = NULL;
@@ -250,8 +275,8 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
 static int connect(struct wiphy *wiphy, struct net_device *dev,
                   struct cfg80211_connect_params *sme)
 {
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct wilc_vif *vif = netdev_priv(priv->dev);
+       struct wilc_vif *vif = netdev_priv(dev);
+       struct wilc_priv *priv = &vif->priv;
        struct host_if_drv *wfi_drv = priv->hif_drv;
        int ret;
        u32 i;
@@ -404,8 +429,8 @@ out_error:
 static int disconnect(struct wiphy *wiphy, struct net_device *dev,
                      u16 reason_code)
 {
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct wilc_vif *vif = netdev_priv(priv->dev);
+       struct wilc_vif *vif = netdev_priv(dev);
+       struct wilc_priv *priv = &vif->priv;
        struct wilc *wilc = vif->wilc;
        int ret;
 
@@ -495,17 +520,17 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
 
 {
        int ret = 0, keylen = params->key_len;
-       struct wilc_priv *priv = wiphy_priv(wiphy);
        const u8 *rx_mic = NULL;
        const u8 *tx_mic = NULL;
        u8 mode = WILC_FW_SEC_NO;
        u8 op_mode;
        struct wilc_vif *vif = netdev_priv(netdev);
+       struct wilc_priv *priv = &vif->priv;
 
        switch (params->cipher) {
        case WLAN_CIPHER_SUITE_WEP40:
        case WLAN_CIPHER_SUITE_WEP104:
-               if (priv->wdev->iftype == NL80211_IFTYPE_AP) {
+               if (priv->wdev.iftype == NL80211_IFTYPE_AP) {
                        wilc_wfi_cfg_copy_wep_info(priv, key_index, params);
 
                        if (params->cipher == WLAN_CIPHER_SUITE_WEP40)
@@ -532,8 +557,8 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
 
        case WLAN_CIPHER_SUITE_TKIP:
        case WLAN_CIPHER_SUITE_CCMP:
-               if (priv->wdev->iftype == NL80211_IFTYPE_AP ||
-                   priv->wdev->iftype == NL80211_IFTYPE_P2P_GO) {
+               if (priv->wdev.iftype == NL80211_IFTYPE_AP ||
+                   priv->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
                        struct wilc_wfi_key *key;
 
                        ret = wilc_wfi_cfg_allocate_wpa_entry(priv, key_index);
@@ -605,9 +630,9 @@ static int del_key(struct wiphy *wiphy, struct net_device *netdev,
                   bool pairwise,
                   const u8 *mac_addr)
 {
-       struct wilc_priv *priv = wiphy_priv(wiphy);
+       struct wilc *wl = wiphy_priv(wiphy);
        struct wilc_vif *vif = netdev_priv(netdev);
-       struct wilc *wl = vif->wilc;
+       struct wilc_priv *priv = &vif->priv;
 
        if (netdev == wl->vif[0]->ndev) {
                if (priv->wilc_gtk[key_index]) {
@@ -644,7 +669,8 @@ static int get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
                   bool pairwise, const u8 *mac_addr, void *cookie,
                   void (*callback)(void *cookie, struct key_params *))
 {
-       struct wilc_priv *priv = wiphy_priv(wiphy);
+       struct wilc_vif *vif = netdev_priv(netdev);
+       struct wilc_priv *priv = &vif->priv;
        struct  key_params key_params;
 
        if (!pairwise) {
@@ -669,8 +695,7 @@ static int get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
 static int set_default_key(struct wiphy *wiphy, struct net_device *netdev,
                           u8 key_index, bool unicast, bool multicast)
 {
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct wilc_vif *vif = netdev_priv(priv->dev);
+       struct wilc_vif *vif = netdev_priv(netdev);
 
        wilc_set_wep_default_keyid(vif, key_index);
 
@@ -680,8 +705,8 @@ static int set_default_key(struct wiphy *wiphy, struct net_device *netdev,
 static int get_station(struct wiphy *wiphy, struct net_device *dev,
                       const u8 *mac, struct station_info *sinfo)
 {
-       struct wilc_priv *priv = wiphy_priv(wiphy);
        struct wilc_vif *vif = netdev_priv(dev);
+       struct wilc_priv *priv = &vif->priv;
        u32 i = 0;
        u32 associatedsta = ~0;
        u32 inactive_time = 0;
@@ -737,13 +762,35 @@ static int change_bss(struct wiphy *wiphy, struct net_device *dev,
        return 0;
 }
 
+struct wilc_vif *wilc_get_interface(struct wilc *wl)
+{
+       int i;
+       struct wilc_vif *vif = NULL;
+
+       mutex_lock(&wl->vif_mutex);
+       for (i = 0; i < wl->vif_num; i++) {
+               if (wl->vif[i]) {
+                       vif = wl->vif[i];
+                       break;
+               }
+       }
+       mutex_unlock(&wl->vif_mutex);
+       return vif;
+}
+
 static int set_wiphy_params(struct wiphy *wiphy, u32 changed)
 {
        int ret;
        struct cfg_param_attr cfg_param_val;
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct wilc_vif *vif = netdev_priv(priv->dev);
+       struct wilc *wl = wiphy_priv(wiphy);
+       struct wilc_vif *vif;
+       struct wilc_priv *priv;
+
+       vif = wilc_get_interface(wl);
+       if (!vif)
+               return -EINVAL;
 
+       priv = &vif->priv;
        cfg_param_val.flag = 0;
 
        if (changed & WIPHY_PARAM_RETRY_SHORT) {
@@ -798,8 +845,8 @@ static int set_wiphy_params(struct wiphy *wiphy, u32 changed)
 static int set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
                     struct cfg80211_pmksa *pmksa)
 {
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct wilc_vif *vif = netdev_priv(priv->dev);
+       struct wilc_vif *vif = netdev_priv(netdev);
+       struct wilc_priv *priv = &vif->priv;
        u32 i;
        int ret = 0;
        u8 flag = 0;
@@ -834,7 +881,8 @@ static int del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
 {
        u32 i;
        int ret = 0;
-       struct wilc_priv *priv = wiphy_priv(wiphy);
+       struct wilc_vif *vif = netdev_priv(netdev);
+       struct wilc_priv *priv = &vif->priv;
 
        for (i = 0; i < priv->pmkid_list.numpmkid; i++) {
                if (!memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid,
@@ -864,9 +912,9 @@ static int del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
 
 static int flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
 {
-       struct wilc_priv *priv = wiphy_priv(wiphy);
+       struct wilc_vif *vif = netdev_priv(netdev);
 
-       memset(&priv->pmkid_list, 0, sizeof(struct wilc_pmkid_attr));
+       memset(&vif->priv.pmkid_list, 0, sizeof(struct wilc_pmkid_attr));
 
        return 0;
 }
@@ -981,12 +1029,11 @@ static void wilc_wfi_cfg_parse_rx_vendor_spec(struct wilc_priv *priv, u8 *buff,
        }
 }
 
-void wilc_wfi_p2p_rx(struct net_device *dev, u8 *buff, u32 size)
+void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size)
 {
-       struct wilc_priv *priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
-       struct host_if_drv *wfi_drv = priv->hif_drv;
-       struct wilc_vif *vif = netdev_priv(dev);
        struct wilc *wl = vif->wilc;
+       struct wilc_priv *priv = &vif->priv;
+       struct host_if_drv *wfi_drv = priv->hif_drv;
        u32 header, pkt_offset;
        s32 freq;
        __le16 fc;
@@ -1002,8 +1049,8 @@ void wilc_wfi_p2p_rx(struct net_device *dev, u8 *buff, u32 size)
                    pkt_offset & IS_MGMT_STATUS_SUCCES)
                        ack = true;
 
-               cfg80211_mgmt_tx_status(priv->wdev, priv->tx_cookie, buff, size,
-                                       ack, GFP_KERNEL);
+               cfg80211_mgmt_tx_status(&priv->wdev, priv->tx_cookie, buff,
+                                       size, ack, GFP_KERNEL);
                return;
        }
 
@@ -1011,13 +1058,13 @@ void wilc_wfi_p2p_rx(struct net_device *dev, u8 *buff, u32 size)
 
        fc = ((struct ieee80211_hdr *)buff)->frame_control;
        if (!ieee80211_is_action(fc)) {
-               cfg80211_rx_mgmt(priv->wdev, freq, 0, buff, size, 0);
+               cfg80211_rx_mgmt(&priv->wdev, freq, 0, buff, size, 0);
                return;
        }
 
        if (priv->cfg_scanning &&
            time_after_eq(jiffies, (unsigned long)wfi_drv->p2p_timeout)) {
-               netdev_dbg(dev, "Receiving action wrong ch\n");
+               netdev_dbg(vif->ndev, "Receiving action wrong ch\n");
                return;
        }
        if (buff[ACTION_CAT_ID] == PUB_ACTION_ATTR_ID) {
@@ -1040,14 +1087,14 @@ void wilc_wfi_p2p_rx(struct net_device *dev, u8 *buff, u32 size)
                        break;
 
                default:
-                       netdev_dbg(dev,
+                       netdev_dbg(vif->ndev,
                                   "%s: Not handled action frame type:%x\n",
                                   __func__, buff[ACTION_SUBTYPE_ID]);
                        break;
                }
        }
 
-       cfg80211_rx_mgmt(priv->wdev, freq, 0, buff, size, 0);
+       cfg80211_rx_mgmt(&priv->wdev, freq, 0, buff, size, 0);
 }
 
 static void wilc_wfi_mgmt_tx_complete(void *priv, int status)
@@ -1060,7 +1107,8 @@ static void wilc_wfi_mgmt_tx_complete(void *priv, int status)
 
 static void wilc_wfi_remain_on_channel_expired(void *data, u64 cookie)
 {
-       struct wilc_priv *priv = data;
+       struct wilc_vif *vif = data;
+       struct wilc_priv *priv = &vif->priv;
        struct wilc_wfi_p2p_listen_params *params = &priv->remain_on_ch_params;
 
        if (cookie != params->listen_cookie)
@@ -1068,7 +1116,7 @@ static void wilc_wfi_remain_on_channel_expired(void *data, u64 cookie)
 
        priv->p2p_listen_state = false;
 
-       cfg80211_remain_on_channel_expired(priv->wdev, params->listen_cookie,
+       cfg80211_remain_on_channel_expired(&priv->wdev, params->listen_cookie,
                                           params->listen_ch, GFP_KERNEL);
 }
 
@@ -1078,8 +1126,8 @@ static int remain_on_channel(struct wiphy *wiphy,
                             unsigned int duration, u64 *cookie)
 {
        int ret = 0;
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct wilc_vif *vif = netdev_priv(priv->dev);
+       struct wilc_vif *vif = netdev_priv(wdev->netdev);
+       struct wilc_priv *priv = &vif->priv;
        u64 id;
 
        if (wdev->iftype == NL80211_IFTYPE_AP) {
@@ -1093,7 +1141,7 @@ static int remain_on_channel(struct wiphy *wiphy,
 
        ret = wilc_remain_on_channel(vif, id, duration, chan->hw_value,
                                     wilc_wfi_remain_on_channel_expired,
-                                    (void *)priv);
+                                    (void *)vif);
        if (ret)
                return ret;
 
@@ -1116,8 +1164,8 @@ static int cancel_remain_on_channel(struct wiphy *wiphy,
                                    struct wireless_dev *wdev,
                                    u64 cookie)
 {
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct wilc_vif *vif = netdev_priv(priv->dev);
+       struct wilc_vif *vif = netdev_priv(wdev->netdev);
+       struct wilc_priv *priv = &vif->priv;
 
        if (cookie != priv->remain_on_ch_params.listen_cookie)
                return -ENOENT;
@@ -1187,9 +1235,9 @@ static int mgmt_tx(struct wiphy *wiphy,
        size_t len = params->len;
        const struct ieee80211_mgmt *mgmt;
        struct wilc_p2p_mgmt_data *mgmt_tx;
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct host_if_drv *wfi_drv = priv->hif_drv;
        struct wilc_vif *vif = netdev_priv(wdev->netdev);
+       struct wilc_priv *priv = &vif->priv;
+       struct host_if_drv *wfi_drv = priv->hif_drv;
        u32 buf_len = len + sizeof(p2p_vendor_spec) +
                        sizeof(priv->p2p.local_random);
        int ret = 0;
@@ -1273,7 +1321,8 @@ static int mgmt_tx_cancel_wait(struct wiphy *wiphy,
                               struct wireless_dev *wdev,
                               u64 cookie)
 {
-       struct wilc_priv *priv = wiphy_priv(wiphy);
+       struct wilc_vif *vif = netdev_priv(wdev->netdev);
+       struct wilc_priv *priv = &vif->priv;
        struct host_if_drv *wfi_drv = priv->hif_drv;
 
        wfi_drv->p2p_timeout = jiffies;
@@ -1283,7 +1332,7 @@ static int mgmt_tx_cancel_wait(struct wiphy *wiphy,
 
                params = &priv->remain_on_ch_params;
 
-               cfg80211_remain_on_channel_expired(priv->wdev,
+               cfg80211_remain_on_channel_expired(wdev,
                                                   params->listen_cookie,
                                                   params->listen_ch,
                                                   GFP_KERNEL);
@@ -1295,9 +1344,8 @@ static int mgmt_tx_cancel_wait(struct wiphy *wiphy,
 void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
                              u16 frame_type, bool reg)
 {
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct wilc_vif *vif = netdev_priv(priv->wdev->netdev);
-       struct wilc *wl = vif->wilc;
+       struct wilc *wl = wiphy_priv(wiphy);
+       struct wilc_vif *vif = netdev_priv(wdev->netdev);
 
        if (!frame_type)
                return;
@@ -1331,8 +1379,7 @@ static int set_cqm_rssi_config(struct wiphy *wiphy, struct net_device *dev,
 static int dump_station(struct wiphy *wiphy, struct net_device *dev,
                        int idx, u8 *mac, struct station_info *sinfo)
 {
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct wilc_vif *vif = netdev_priv(priv->dev);
+       struct wilc_vif *vif = netdev_priv(dev);
        int ret;
 
        if (idx != 0)
@@ -1344,15 +1391,15 @@ static int dump_station(struct wiphy *wiphy, struct net_device *dev,
        if (ret)
                return ret;
 
-       memcpy(mac, priv->associated_bss, ETH_ALEN);
+       memcpy(mac, vif->priv.associated_bss, ETH_ALEN);
        return 0;
 }
 
 static int set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
                          bool enabled, int timeout)
 {
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct wilc_vif *vif = netdev_priv(priv->dev);
+       struct wilc_vif *vif = netdev_priv(dev);
+       struct wilc_priv *priv = &vif->priv;
 
        if (!priv->hif_drv)
                return -EIO;
@@ -1367,9 +1414,9 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
                               enum nl80211_iftype type,
                               struct vif_params *params)
 {
-       struct wilc_priv *priv = wiphy_priv(wiphy);
+       struct wilc *wl = wiphy_priv(wiphy);
        struct wilc_vif *vif = netdev_priv(dev);
-       struct wilc *wl = vif->wilc;
+       struct wilc_priv *priv = &vif->priv;
 
        priv->p2p.local_random = 0x01;
        priv->p2p.recv_random = 0x00;
@@ -1381,8 +1428,10 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
        case NL80211_IFTYPE_STATION:
                vif->connecting = false;
                dev->ieee80211_ptr->iftype = type;
-               priv->wdev->iftype = type;
+               priv->wdev.iftype = type;
                vif->monitor_flag = 0;
+               if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE)
+                       wilc_wfi_deinit_mon_interface(wl, true);
                vif->iftype = WILC_STATION_MODE;
                wilc_set_operation_mode(vif, WILC_STATION_MODE);
 
@@ -1396,7 +1445,7 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
        case NL80211_IFTYPE_P2P_CLIENT:
                vif->connecting = false;
                dev->ieee80211_ptr->iftype = type;
-               priv->wdev->iftype = type;
+               priv->wdev.iftype = type;
                vif->monitor_flag = 0;
                vif->iftype = WILC_CLIENT_MODE;
                wilc_set_operation_mode(vif, WILC_STATION_MODE);
@@ -1408,12 +1457,12 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
        case NL80211_IFTYPE_AP:
                wl->enable_ps = false;
                dev->ieee80211_ptr->iftype = type;
-               priv->wdev->iftype = type;
+               priv->wdev.iftype = type;
                vif->iftype = WILC_AP_MODE;
 
                if (wl->initialized) {
                        wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif),
-                                                0, vif->ifc_id);
+                                                0, vif->idx);
                        wilc_set_operation_mode(vif, WILC_AP_MODE);
                        wilc_set_power_mgmt(vif, 0, 0);
                }
@@ -1425,7 +1474,7 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
                          jiffies + msecs_to_jiffies(WILC_IP_TIMEOUT_MS));
                wilc_set_operation_mode(vif, WILC_AP_MODE);
                dev->ieee80211_ptr->iftype = type;
-               priv->wdev->iftype = type;
+               priv->wdev.iftype = type;
                vif->iftype = WILC_GO_MODE;
 
                wl->enable_ps = false;
@@ -1444,14 +1493,13 @@ static int start_ap(struct wiphy *wiphy, struct net_device *dev,
                    struct cfg80211_ap_settings *settings)
 {
        struct wilc_vif *vif = netdev_priv(dev);
-       struct wilc *wl = vif->wilc;
        int ret;
 
        ret = set_channel(wiphy, &settings->chandef);
        if (ret != 0)
                netdev_err(dev, "Error in setting channel\n");
 
-       wilc_wlan_set_bssid(dev, wl->vif[vif->idx]->src_addr, WILC_AP_MODE);
+       wilc_wlan_set_bssid(dev, dev->dev_addr, WILC_AP_MODE);
        wilc_set_power_mgmt(vif, 0, 0);
 
        return wilc_add_beacon(vif, settings->beacon_interval,
@@ -1461,8 +1509,7 @@ static int start_ap(struct wiphy *wiphy, struct net_device *dev,
 static int change_beacon(struct wiphy *wiphy, struct net_device *dev,
                         struct cfg80211_beacon_data *beacon)
 {
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct wilc_vif *vif = netdev_priv(priv->dev);
+       struct wilc_vif *vif = netdev_priv(dev);
 
        return wilc_add_beacon(vif, 0, 0, beacon);
 }
@@ -1470,8 +1517,7 @@ static int change_beacon(struct wiphy *wiphy, struct net_device *dev,
 static int stop_ap(struct wiphy *wiphy, struct net_device *dev)
 {
        int ret;
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct wilc_vif *vif = netdev_priv(priv->dev);
+       struct wilc_vif *vif = netdev_priv(dev);
 
        wilc_wlan_set_bssid(dev, NULL, WILC_AP_MODE);
 
@@ -1487,8 +1533,8 @@ static int add_station(struct wiphy *wiphy, struct net_device *dev,
                       const u8 *mac, struct station_parameters *params)
 {
        int ret = 0;
-       struct wilc_priv *priv = wiphy_priv(wiphy);
        struct wilc_vif *vif = netdev_priv(dev);
+       struct wilc_priv *priv = &vif->priv;
 
        if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) {
                memcpy(priv->assoc_stainfo.sta_associated_bss[params->aid], mac,
@@ -1507,8 +1553,8 @@ static int del_station(struct wiphy *wiphy, struct net_device *dev,
 {
        const u8 *mac = params->mac;
        int ret = 0;
-       struct wilc_priv *priv = wiphy_priv(wiphy);
        struct wilc_vif *vif = netdev_priv(dev);
+       struct wilc_priv *priv = &vif->priv;
        struct sta_info *info;
 
        if (!(vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE))
@@ -1539,60 +1585,157 @@ static int change_station(struct wiphy *wiphy, struct net_device *dev,
        return ret;
 }
 
+static int wilc_get_vif_from_type(struct wilc *wl, int type)
+{
+       int i;
+
+       mutex_lock(&wl->vif_mutex);
+       for (i = 0; i < wl->vif_num; i++) {
+               if (wl->vif[i]->iftype == type) {
+                       mutex_unlock(&wl->vif_mutex);
+                       return i;
+               }
+       }
+       mutex_unlock(&wl->vif_mutex);
+
+       return -EINVAL;
+}
+
 static struct wireless_dev *add_virtual_intf(struct wiphy *wiphy,
                                             const char *name,
                                             unsigned char name_assign_type,
                                             enum nl80211_iftype type,
                                             struct vif_params *params)
 {
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct wilc_vif *vif = netdev_priv(priv->wdev->netdev);
-       struct net_device *new_ifc;
+       struct wilc *wl = wiphy_priv(wiphy);
+       struct wilc_vif *vif;
+       struct wireless_dev *wdev;
+       int iftype;
+       int ret;
 
        if (type == NL80211_IFTYPE_MONITOR) {
-               new_ifc = wilc_wfi_init_mon_interface(vif->wilc, name,
-                                                     vif->ndev);
-               if (new_ifc) {
-                       vif = netdev_priv(priv->wdev->netdev);
-                       vif->monitor_flag = 1;
+               struct net_device *ndev;
+               int ap_index = wilc_get_vif_from_type(wl, WILC_AP_MODE);
+
+               if (ap_index < 0) {
+                       ap_index = wilc_get_vif_from_type(wl, WILC_GO_MODE);
+                       if (ap_index < 0)
+                               goto validate_interface;
                }
+
+               vif  = wl->vif[ap_index];
+               if (vif->monitor_flag)
+                       goto validate_interface;
+
+               ndev = wilc_wfi_init_mon_interface(wl, name, vif->ndev);
+               if (ndev)
+                       vif->monitor_flag = 1;
+               else
+                       return ERR_PTR(-EINVAL);
+
+               wdev = &vif->priv.wdev;
+               return wdev;
+       }
+
+validate_interface:
+       mutex_lock(&wl->vif_mutex);
+       if (wl->vif_num == WILC_NUM_CONCURRENT_IFC) {
+               pr_err("Reached maximum number of interface\n");
+               ret = -EINVAL;
+               goto out_err;
        }
-       return priv->wdev;
+
+       switch (type) {
+       case NL80211_IFTYPE_STATION:
+               iftype = WILC_STATION_MODE;
+               break;
+       case NL80211_IFTYPE_AP:
+               iftype = WILC_AP_MODE;
+               break;
+       default:
+               ret = -EOPNOTSUPP;
+               goto out_err;
+       }
+
+       vif = wilc_netdev_ifc_init(wl, name, iftype, type, true);
+       if (IS_ERR(vif)) {
+               ret = PTR_ERR(vif);
+               goto out_err;
+       }
+
+       mutex_unlock(&wl->vif_mutex);
+
+       return &vif->priv.wdev;
+
+out_err:
+       mutex_unlock(&wl->vif_mutex);
+       return ERR_PTR(ret);
 }
 
 static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
 {
+       struct wilc *wl = wiphy_priv(wiphy);
+       struct wilc_vif *vif;
+       int i;
+
+       if (wdev->iftype == NL80211_IFTYPE_AP ||
+           wdev->iftype == NL80211_IFTYPE_P2P_GO)
+               wilc_wfi_deinit_mon_interface(wl, true);
+       vif = netdev_priv(wdev->netdev);
+       cfg80211_stop_iface(wiphy, wdev, GFP_KERNEL);
+       unregister_netdevice(vif->ndev);
+       vif->monitor_flag = 0;
+
+       mutex_lock(&wl->vif_mutex);
+       wilc_set_wfi_drv_handler(vif, 0, 0, 0);
+       for (i = vif->idx; i < wl->vif_num ; i++) {
+               if ((i + 1) >= wl->vif_num) {
+                       wl->vif[i] = NULL;
+               } else {
+                       vif = wl->vif[i + 1];
+                       vif->idx = i;
+                       wl->vif[i] = vif;
+                       wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif),
+                                                vif->iftype, vif->idx);
+               }
+       }
+       wl->vif_num--;
+       mutex_unlock(&wl->vif_mutex);
+
        return 0;
 }
 
 static int wilc_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
 {
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct wilc_vif *vif = netdev_priv(priv->dev);
+       struct wilc *wl = wiphy_priv(wiphy);
 
-       if (!wow && wilc_wlan_get_num_conn_ifcs(vif->wilc))
-               vif->wilc->suspend_event = true;
+       if (!wow && wilc_wlan_get_num_conn_ifcs(wl))
+               wl->suspend_event = true;
        else
-               vif->wilc->suspend_event = false;
+               wl->suspend_event = false;
 
        return 0;
 }
 
 static int wilc_resume(struct wiphy *wiphy)
 {
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct wilc_vif *vif = netdev_priv(priv->dev);
-
-       netdev_info(vif->ndev, "cfg resume\n");
        return 0;
 }
 
 static void wilc_set_wakeup(struct wiphy *wiphy, bool enabled)
 {
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct wilc_vif *vif = netdev_priv(priv->dev);
+       struct wilc *wl = wiphy_priv(wiphy);
+       struct wilc_vif *vif;
+
+       mutex_lock(&wl->vif_mutex);
+       vif = wilc_get_wl_to_vif(wl);
+       if (IS_ERR(vif)) {
+               mutex_unlock(&wl->vif_mutex);
+               return;
+       }
 
        netdev_info(vif->ndev, "cfg set wake up = %d\n", enabled);
+       mutex_unlock(&wl->vif_mutex);
 }
 
 static int set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
@@ -1600,8 +1743,7 @@ static int set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
 {
        int ret;
        s32 tx_power = MBM_TO_DBM(mbm);
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct wilc_vif *vif = netdev_priv(priv->dev);
+       struct wilc_vif *vif = netdev_priv(wdev->netdev);
 
        if (tx_power < 0)
                tx_power = 0;
@@ -1618,8 +1760,7 @@ static int get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
                        int *dbm)
 {
        int ret;
-       struct wilc_priv *priv = wiphy_priv(wiphy);
-       struct wilc_vif *vif = netdev_priv(priv->dev);
+       struct wilc_vif *vif = netdev_priv(wdev->netdev);
        struct wilc *wl = vif->wilc;
 
        /* If firmware is not started, return. */
@@ -1676,98 +1817,137 @@ static const struct cfg80211_ops wilc_cfg80211_ops = {
 
 };
 
-static struct wireless_dev *wilc_wfi_cfg_alloc(void)
+static void wlan_init_locks(struct wilc *wl)
 {
-       struct wireless_dev *wdev;
+       mutex_init(&wl->hif_cs);
+       mutex_init(&wl->rxq_cs);
+       mutex_init(&wl->cfg_cmd_lock);
+       mutex_init(&wl->vif_mutex);
+
+       spin_lock_init(&wl->txq_spinlock);
+       mutex_init(&wl->txq_add_to_head_cs);
+
+       init_completion(&wl->txq_event);
+       init_completion(&wl->cfg_event);
+       init_completion(&wl->sync_event);
+       init_completion(&wl->txq_thread_started);
+}
 
-       wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
-       if (!wdev)
-               goto out;
+int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type,
+                      const struct wilc_hif_func *ops)
+{
+       struct wilc *wl;
+       struct wilc_vif *vif;
+       int ret;
 
-       wdev->wiphy = wiphy_new(&wilc_cfg80211_ops, sizeof(struct wilc_priv));
-       if (!wdev->wiphy)
-               goto free_mem;
+       wl = wilc_create_wiphy(dev);
+       if (!wl)
+               return -EINVAL;
 
-       return wdev;
+       ret = wilc_wlan_cfg_init(wl);
+       if (ret)
+               goto free_wl;
+
+       *wilc = wl;
+       wl->io_type = io_type;
+       wl->hif_func = ops;
+       wl->enable_ps = false;
+       wl->chip_ps_state = WILC_CHIP_WAKEDUP;
+       INIT_LIST_HEAD(&wl->txq_head.list);
+       INIT_LIST_HEAD(&wl->rxq_head.list);
+
+       wl->hif_workqueue = create_singlethread_workqueue("WILC_wq");
+       if (!wl->hif_workqueue) {
+               ret = -ENOMEM;
+               goto free_cfg;
+       }
+       vif = wilc_netdev_ifc_init(wl, "wlan%d", WILC_STATION_MODE,
+                                  NL80211_IFTYPE_STATION, false);
+       if (IS_ERR(vif)) {
+               ret = PTR_ERR(vif);
+               goto free_hq;
+       }
 
-free_mem:
-       kfree(wdev);
-out:
-       return NULL;
+       wlan_init_locks(wl);
+
+       return 0;
+
+free_hq:
+       destroy_workqueue(wl->hif_workqueue);
+
+free_cfg:
+       wilc_wlan_cfg_deinit(wl);
+
+free_wl:
+       wiphy_unregister(wl->wiphy);
+       wiphy_free(wl->wiphy);
+       return ret;
 }
+EXPORT_SYMBOL_GPL(wilc_cfg80211_init);
 
-struct wireless_dev *wilc_create_wiphy(struct net_device *net,
-                                      struct device *dev)
+struct wilc *wilc_create_wiphy(struct device *dev)
 {
-       struct wilc_priv *priv;
-       struct wireless_dev *wdev;
+       struct wiphy *wiphy;
+       struct wilc *wl;
        int ret;
 
-       wdev = wilc_wfi_cfg_alloc();
-       if (!wdev) {
-               netdev_err(net, "wiphy new allocate failed\n");
+       wiphy = wiphy_new(&wilc_cfg80211_ops, sizeof(*wl));
+       if (!wiphy)
                return NULL;
-       }
 
-       priv = wdev_priv(wdev);
-       priv->wdev = wdev;
+       wl = wiphy_priv(wiphy);
 
-       memcpy(priv->bitrates, wilc_bitrates, sizeof(wilc_bitrates));
-       memcpy(priv->channels, wilc_2ghz_channels, sizeof(wilc_2ghz_channels));
-       priv->band.bitrates = priv->bitrates;
-       priv->band.n_bitrates = ARRAY_SIZE(priv->bitrates);
-       priv->band.channels = priv->channels;
-       priv->band.n_channels = ARRAY_SIZE(wilc_2ghz_channels);
+       memcpy(wl->bitrates, wilc_bitrates, sizeof(wilc_bitrates));
+       memcpy(wl->channels, wilc_2ghz_channels, sizeof(wilc_2ghz_channels));
+       wl->band.bitrates = wl->bitrates;
+       wl->band.n_bitrates = ARRAY_SIZE(wl->bitrates);
+       wl->band.channels = wl->channels;
+       wl->band.n_channels = ARRAY_SIZE(wilc_2ghz_channels);
 
-       priv->band.ht_cap.ht_supported = 1;
-       priv->band.ht_cap.cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
-       priv->band.ht_cap.mcs.rx_mask[0] = 0xff;
-       priv->band.ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K;
-       priv->band.ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
+       wl->band.ht_cap.ht_supported = 1;
+       wl->band.ht_cap.cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+       wl->band.ht_cap.mcs.rx_mask[0] = 0xff;
+       wl->band.ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K;
+       wl->band.ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
 
-       wdev->wiphy->bands[NL80211_BAND_2GHZ] = &priv->band;
+       wiphy->bands[NL80211_BAND_2GHZ] = &wl->band;
 
-       wdev->wiphy->max_scan_ssids = WILC_MAX_NUM_PROBED_SSID;
+       wiphy->max_scan_ssids = WILC_MAX_NUM_PROBED_SSID;
 #ifdef CONFIG_PM
-       wdev->wiphy->wowlan = &wowlan_support;
+       wiphy->wowlan = &wowlan_support;
 #endif
-       wdev->wiphy->max_num_pmkids = WILC_MAX_NUM_PMKIDS;
-       wdev->wiphy->max_scan_ie_len = 1000;
-       wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
-       memcpy(priv->cipher_suites, wilc_cipher_suites,
+       wiphy->max_num_pmkids = WILC_MAX_NUM_PMKIDS;
+       wiphy->max_scan_ie_len = 1000;
+       wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+       memcpy(wl->cipher_suites, wilc_cipher_suites,
               sizeof(wilc_cipher_suites));
-       wdev->wiphy->cipher_suites = priv->cipher_suites;
-       wdev->wiphy->n_cipher_suites = ARRAY_SIZE(wilc_cipher_suites);
-       wdev->wiphy->mgmt_stypes = wilc_wfi_cfg80211_mgmt_types;
-
-       wdev->wiphy->max_remain_on_channel_duration = 500;
-       wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
-                                       BIT(NL80211_IFTYPE_AP) |
-                                       BIT(NL80211_IFTYPE_MONITOR) |
-                                       BIT(NL80211_IFTYPE_P2P_GO) |
-                                       BIT(NL80211_IFTYPE_P2P_CLIENT);
-       wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
-       wdev->iftype = NL80211_IFTYPE_STATION;
-
-       set_wiphy_dev(wdev->wiphy, dev);
-
-       ret = wiphy_register(wdev->wiphy);
+       wiphy->cipher_suites = wl->cipher_suites;
+       wiphy->n_cipher_suites = ARRAY_SIZE(wilc_cipher_suites);
+       wiphy->mgmt_stypes = wilc_wfi_cfg80211_mgmt_types;
+
+       wiphy->max_remain_on_channel_duration = 500;
+       wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+                               BIT(NL80211_IFTYPE_AP) |
+                               BIT(NL80211_IFTYPE_MONITOR) |
+                               BIT(NL80211_IFTYPE_P2P_GO) |
+                               BIT(NL80211_IFTYPE_P2P_CLIENT);
+       wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+
+       set_wiphy_dev(wiphy, dev);
+       wl->wiphy = wiphy;
+       ret = wiphy_register(wiphy);
        if (ret) {
-               netdev_err(net, "Cannot register wiphy device\n");
-               wiphy_free(wdev->wiphy);
-               kfree(wdev);
+               wiphy_free(wiphy);
                return NULL;
        }
-
-       priv->dev = net;
-       return wdev;
+       return wl;
 }
 
 int wilc_init_host_int(struct net_device *net)
 {
        int ret;
-       struct wilc_priv *priv = wdev_priv(net->ieee80211_ptr);
-       struct wilc_vif *vif = netdev_priv(priv->dev);
+       struct wilc_vif *vif = netdev_priv(net);
+       struct wilc_priv *priv = &vif->priv;
 
        timer_setup(&vif->during_ip_timer, clear_during_ip, 0);
 
@@ -1784,8 +1964,8 @@ int wilc_init_host_int(struct net_device *net)
 void wilc_deinit_host_int(struct net_device *net)
 {
        int ret;
-       struct wilc_priv *priv = wdev_priv(net->ieee80211_ptr);
-       struct wilc_vif *vif = netdev_priv(priv->dev);
+       struct wilc_vif *vif = netdev_priv(net);
+       struct wilc_priv *priv = &vif->priv;
 
        priv->p2p_listen_state = false;
 
@@ -1798,19 +1978,3 @@ void wilc_deinit_host_int(struct net_device *net)
                netdev_err(net, "Error while deinitializing host interface\n");
 }
 
-void wilc_free_wiphy(struct net_device *net)
-{
-       if (!net)
-               return;
-
-       if (!net->ieee80211_ptr)
-               return;
-
-       if (!net->ieee80211_ptr->wiphy)
-               return;
-
-       wiphy_unregister(net->ieee80211_ptr->wiphy);
-
-       wiphy_free(net->ieee80211_ptr->wiphy);
-       kfree(net->ieee80211_ptr);
-}
index 31dfa1f..234faaa 100644 (file)
@@ -8,17 +8,20 @@
 #define NM_WFI_CFGOPERATIONS
 #include "wilc_wfi_netdevice.h"
 
-struct wireless_dev *wilc_create_wiphy(struct net_device *net,
-                                      struct device *dev);
-void wilc_free_wiphy(struct net_device *net);
+struct wiphy *wilc_cfg_alloc(void);
+int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type,
+                      const struct wilc_hif_func *ops);
+struct wilc *wilc_create_wiphy(struct device *dev);
 void wilc_deinit_host_int(struct net_device *net);
 int wilc_init_host_int(struct net_device *net);
 void wilc_wfi_monitor_rx(struct net_device *mon_dev, u8 *buff, u32 size);
-void wilc_wfi_deinit_mon_interface(struct wilc *wl);
+struct wilc_vif *wilc_netdev_interface(struct wilc *wl, const char *name,
+                                      enum nl80211_iftype type);
+void wilc_wfi_deinit_mon_interface(struct wilc *wl, bool rtnl_locked);
 struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl,
                                               const char *name,
                                               struct net_device *real_dev);
 void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
                              u16 frame_type, bool reg);
-
+struct wilc_vif *wilc_get_interface(struct wilc *wl);
 #endif
index df00762..1e74a08 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/if_arp.h>
 #include <linux/gpio/consumer.h>
 
-#include "host_interface.h"
+#include "wilc_hif.h"
 #include "wilc_wlan.h"
 #include "wilc_wlan_cfg.h"
 
@@ -129,7 +129,7 @@ static struct ieee80211_rate wilc_bitrates[] = {
 };
 
 struct wilc_priv {
-       struct wireless_dev *wdev;
+       struct wireless_dev wdev;
        struct cfg80211_scan_request *scan_req;
 
        struct wilc_wfi_p2p_listen_params remain_on_ch_params;
@@ -156,10 +156,6 @@ struct wilc_priv {
        int scanned_cnt;
        struct wilc_p2p_var p2p;
 
-       struct ieee80211_channel channels[ARRAY_SIZE(wilc_2ghz_channels)];
-       struct ieee80211_rate bitrates[ARRAY_SIZE(wilc_bitrates)];
-       struct ieee80211_supported_band band;
-       u32 cipher_suites[ARRAY_SIZE(wilc_cipher_suites)];
        u64 inc_roc_cookie;
 };
 
@@ -202,21 +198,21 @@ struct wilc_vif {
        struct frame_reg frame_reg[NUM_REG_FRAME];
        struct net_device_stats netstats;
        struct wilc *wilc;
-       u8 src_addr[ETH_ALEN];
        u8 bssid[ETH_ALEN];
        struct host_if_drv *hif_drv;
        struct net_device *ndev;
        u8 mode;
-       u8 ifc_id;
        struct timer_list during_ip_timer;
        bool obtaining_ip;
        struct timer_list periodic_rssi;
        struct rf_info periodic_stat;
        struct tcp_ack_filter ack_filter;
        bool connecting;
+       struct wilc_priv priv;
 };
 
 struct wilc {
+       struct wiphy *wiphy;
        const struct wilc_hif_func *hif_func;
        int io_type;
        s8 mac_status;
@@ -226,6 +222,8 @@ struct wilc {
        int close;
        u8 vif_num;
        struct wilc_vif *vif[WILC_NUM_CONCURRENT_IFC];
+       /*protect vif list*/
+       struct mutex vif_mutex;
        u8 open_ifcs;
        /*protect head of transmit queue*/
        struct mutex txq_add_to_head_cs;
@@ -275,6 +273,10 @@ struct wilc {
        struct mutex deinit_lock;
        u8 sta_ch;
        u8 op_ch;
+       struct ieee80211_channel channels[ARRAY_SIZE(wilc_2ghz_channels)];
+       struct ieee80211_rate bitrates[ARRAY_SIZE(wilc_bitrates)];
+       struct ieee80211_supported_band band;
+       u32 cipher_suites[ARRAY_SIZE(wilc_cipher_suites)];
 };
 
 struct wilc_wfi_mon_priv {
@@ -284,9 +286,9 @@ struct wilc_wfi_mon_priv {
 void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset);
 void wilc_mac_indicate(struct wilc *wilc);
 void wilc_netdev_cleanup(struct wilc *wilc);
-int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type,
-                    const struct wilc_hif_func *ops);
 void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size);
 void wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode);
-
+struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name,
+                                     int vif_type, enum nl80211_iftype type,
+                                     bool rtnl_locked);
 #endif
index 95eaf8f..d46876e 100644 (file)
@@ -6,7 +6,7 @@
 
 #include <linux/if_ether.h>
 #include <linux/ip.h>
-#include "wilc_wfi_netdevice.h"
+#include "wilc_wfi_cfgoperations.h"
 #include "wilc_wlan_cfg.h"
 
 static inline bool is_wilc1000(u32 id)
@@ -267,6 +267,7 @@ static int wilc_wlan_txq_add_cfg_pkt(struct wilc_vif *vif, u8 *buffer,
        tqe->tx_complete_func = NULL;
        tqe->priv = NULL;
        tqe->ack_idx = NOT_TCP_ACK;
+       tqe->vif = vif;
 
        wilc_wlan_txq_add_to_head(vif, tqe);
 
@@ -295,6 +296,7 @@ int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer,
        tqe->buffer_size = buffer_size;
        tqe->tx_complete_func = tx_complete_fn;
        tqe->priv = priv;
+       tqe->vif = vif;
 
        tqe->ack_idx = NOT_TCP_ACK;
        if (vif->ack_filter.enabled)
@@ -326,6 +328,7 @@ int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,
        tqe->tx_complete_func = tx_complete_fn;
        tqe->priv = priv;
        tqe->ack_idx = NOT_TCP_ACK;
+       tqe->vif = vif;
        wilc_wlan_txq_add_to_tail(dev, tqe);
        return 1;
 }
@@ -482,7 +485,7 @@ void host_sleep_notify(struct wilc *wilc)
 }
 EXPORT_SYMBOL_GPL(host_sleep_notify);
 
-int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
+int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
 {
        int i, entries = 0;
        u32 sum;
@@ -494,17 +497,20 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
        int counter;
        int timeout;
        u32 vmm_table[WILC_VMM_TBL_SIZE];
-       struct wilc_vif *vif = netdev_priv(dev);
-       struct wilc *wilc = vif->wilc;
        const struct wilc_hif_func *func;
        u8 *txb = wilc->tx_buffer;
+       struct net_device *dev;
+       struct wilc_vif *vif;
 
        if (wilc->quit)
                goto out;
 
        mutex_lock(&wilc->txq_add_to_head_cs);
-       wilc_wlan_txq_filter_dup_tcp_ack(dev);
        tqe = wilc_wlan_txq_get_first(wilc);
+       if (!tqe)
+               goto out;
+       dev = tqe->vif->ndev;
+       wilc_wlan_txq_filter_dup_tcp_ack(dev);
        i = 0;
        sum = 0;
        do {
@@ -629,6 +635,7 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
                if (!tqe)
                        break;
 
+               vif = tqe->vif;
                if (vmm_table[i] == 0)
                        break;
 
@@ -648,8 +655,7 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
                if (tqe->type == WILC_CFG_PKT) {
                        buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET;
                } else if (tqe->type == WILC_NET_PKT) {
-                       bssid = ((struct tx_complete_data *)(tqe->priv))->bssid;
-
+                       bssid = tqe->vif->bssid;
                        buffer_offset = ETH_ETHERNET_HDR_OFFSET;
                        memcpy(&txb[offset + 8], bssid, 6);
                } else {
@@ -709,9 +715,6 @@ static void wilc_wlan_handle_rx_buff(struct wilc *wilc, u8 *buffer, int size)
                        break;
 
                if (pkt_offset & IS_MANAGMEMENT) {
-                       pkt_offset &= ~(IS_MANAGMEMENT |
-                                       IS_MANAGMEMENT_CALLBACK |
-                                       IS_MGMT_STATUS_SUCCES);
                        buff_ptr += HOST_HDR_OFFSET;
                        wilc_wfi_mgmt_rx(wilc, buff_ptr, pkt_len);
                } else {
@@ -1199,10 +1202,11 @@ int wilc_wlan_cfg_get_val(struct wilc *wl, u16 wid, u8 *buffer, u32 buffer_size)
 }
 
 int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids,
-                        u32 count, u32 drv)
+                        u32 count)
 {
        int i;
        int ret = 0;
+       u32 drv = wilc_get_vif_idx(vif);
 
        if (mode == WILC_GET_CFG) {
                for (i = 0; i < count; i++) {
index 1a27f62..d2eef7b 100644 (file)
@@ -216,6 +216,7 @@ struct txq_entry_t {
        int buffer_size;
        void *priv;
        int status;
+       struct wilc_vif *vif;
        void (*tx_complete_func)(void *priv, int status);
 };
 
@@ -253,7 +254,6 @@ struct wilc_hif_func {
 struct tx_complete_data {
        int size;
        void *buff;
-       u8 *bssid;
        struct sk_buff *skb;
 };
 
@@ -284,7 +284,7 @@ int wilc_wlan_stop(struct wilc *wilc);
 int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer,
                              u32 buffer_size,
                              void (*tx_complete_fn)(void *, int));
-int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count);
+int wilc_wlan_handle_txq(struct wilc *wl, u32 *txq_count);
 void wilc_handle_isr(struct wilc *wilc);
 void wilc_wlan_cleanup(struct net_device *dev);
 int wilc_wlan_cfg_set(struct wilc_vif *vif, int start, u16 wid, u8 *buffer,
@@ -301,13 +301,13 @@ void wilc_enable_tcp_ack_filter(struct wilc_vif *vif, bool value);
 int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc);
 netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *dev);
 
-void wilc_wfi_p2p_rx(struct net_device *dev, u8 *buff, u32 size);
+void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size);
 void host_wakeup_notify(struct wilc *wilc);
 void host_sleep_notify(struct wilc *wilc);
 void chip_allow_sleep(struct wilc *wilc);
 void chip_wakeup(struct wilc *wilc);
 int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids,
-                        u32 count, u32 drv);
+                        u32 count);
 int wilc_wlan_init(struct net_device *dev);
 u32 wilc_get_chipid(struct wilc *wilc, bool update);
 #endif
index b15de36..b89d0e0 100644 (file)
@@ -684,7 +684,7 @@ enum {
        WID_LONG_RETRY_LIMIT            = 0x1003,
        WID_BEACON_INTERVAL             = 0x1006,
        WID_MEMORY_ACCESS_16BIT         = 0x1008,
-
+       WID_PASSIVE_SCAN_TIME           = 0x100D,
        WID_JOIN_START_TIMEOUT          = 0x100F,
        WID_ASOC_TIMEOUT                = 0x1011,
        WID_11I_PROTOCOL_TIMEOUT        = 0x1012,
index 8a862f7..eee1998 100644 (file)
@@ -231,17 +231,9 @@ static int prism2_set_default_key(struct wiphy *wiphy, struct net_device *dev,
 {
        struct wlandevice *wlandev = dev->ml_priv;
 
-       int err = 0;
-       int result = 0;
-
-       result = prism2_domibset_uint32(wlandev,
-               DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID,
-               key_index);
-
-       if (result)
-               err = -EFAULT;
-
-       return err;
+       return  prism2_domibset_uint32(wlandev,
+                                      DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID,
+                                      key_index);
 }
 
 static int prism2_get_station(struct wiphy *wiphy, struct net_device *dev,
index 181a32a..685d771 100644 (file)
@@ -152,22 +152,11 @@ static u32 iscsi_handle_authentication(
 
        if (strstr("None", authtype))
                return 1;
-#ifdef CANSRP
-       else if (strstr("SRP", authtype))
-               return srp_main_loop(conn, auth, in_buf, out_buf,
-                               &in_length, out_length);
-#endif
        else if (strstr("CHAP", authtype))
                return chap_main_loop(conn, auth, in_buf, out_buf,
                                &in_length, out_length);
-       else if (strstr("SPKM1", authtype))
-               return 2;
-       else if (strstr("SPKM2", authtype))
-               return 2;
-       else if (strstr("KRB5", authtype))
-               return 2;
-       else
-               return 2;
+       /* SRP, SPKM1, SPKM2 and KRB5 are unsupported */
+       return 2;
 }
 
 static void iscsi_remove_failed_auth_entry(struct iscsi_conn *conn)
index b43d638..04eda11 100644 (file)
@@ -1824,20 +1824,18 @@ static int tcmu_update_uio_info(struct tcmu_dev *udev)
 {
        struct tcmu_hba *hba = udev->hba->hba_ptr;
        struct uio_info *info;
-       size_t size, used;
        char *str;
 
        info = &udev->uio_info;
-       size = snprintf(NULL, 0, "tcm-user/%u/%s/%s", hba->host_id, udev->name,
-                       udev->dev_config);
-       size += 1; /* for \0 */
-       str = kmalloc(size, GFP_KERNEL);
-       if (!str)
-               return -ENOMEM;
 
-       used = snprintf(str, size, "tcm-user/%u/%s", hba->host_id, udev->name);
        if (udev->dev_config[0])
-               snprintf(str + used, size - used, "/%s", udev->dev_config);
+               str = kasprintf(GFP_KERNEL, "tcm-user/%u/%s/%s", hba->host_id,
+                               udev->name, udev->dev_config);
+       else
+               str = kasprintf(GFP_KERNEL, "tcm-user/%u/%s", hba->host_id,
+                               udev->name);
+       if (!str)
+               return -ENOMEM;
 
        /* If the old string exists, free it */
        kfree(info->name);
index ba39647..3199977 100644 (file)
@@ -123,8 +123,6 @@ static void bcm2835_thermal_debugfs(struct platform_device *pdev)
        struct debugfs_regset32 *regset;
 
        data->debugfsdir = debugfs_create_dir("bcm2835_thermal", NULL);
-       if (!data->debugfsdir)
-               return;
 
        regset = devm_kzalloc(&pdev->dev, sizeof(*regset), GFP_KERNEL);
        if (!regset)
index 79d214b..5149a81 100644 (file)
@@ -698,17 +698,9 @@ DEFINE_SHOW_ATTRIBUTE(powerclamp_debug);
 static inline void powerclamp_create_debug_files(void)
 {
        debug_dir = debugfs_create_dir("intel_powerclamp", NULL);
-       if (!debug_dir)
-               return;
-
-       if (!debugfs_create_file("powerclamp_calib", S_IRUGO, debug_dir,
-                                       cal_data, &powerclamp_debug_fops))
-               goto file_error;
 
-       return;
-
-file_error:
-       debugfs_remove_recursive(debug_dir);
+       debugfs_create_file("powerclamp_calib", S_IRUGO, debug_dir, cal_data,
+                           &powerclamp_debug_fops);
 }
 
 static enum cpuhp_state hp_state;
index e85d54d..ddb4a97 100644 (file)
@@ -75,29 +75,14 @@ static struct dentry *debugfs;
 static unsigned int pkg_interrupt_cnt;
 static unsigned int pkg_work_cnt;
 
-static int pkg_temp_debugfs_init(void)
+static void pkg_temp_debugfs_init(void)
 {
-       struct dentry *d;
-
        debugfs = debugfs_create_dir("pkg_temp_thermal", NULL);
-       if (!debugfs)
-               return -ENOENT;
-
-       d = debugfs_create_u32("pkg_thres_interrupt", S_IRUGO, debugfs,
-                              &pkg_interrupt_cnt);
-       if (!d)
-               goto err_out;
-
-       d = debugfs_create_u32("pkg_thres_work", S_IRUGO, debugfs,
-                              &pkg_work_cnt);
-       if (!d)
-               goto err_out;
 
-       return 0;
-
-err_out:
-       debugfs_remove_recursive(debugfs);
-       return -ENOENT;
+       debugfs_create_u32("pkg_thres_interrupt", S_IRUGO, debugfs,
+                          &pkg_interrupt_cnt);
+       debugfs_create_u32("pkg_thres_work", S_IRUGO, debugfs,
+                          &pkg_work_cnt);
 }
 
 /*
index fcf70a3..43941eb 100644 (file)
@@ -1485,23 +1485,13 @@ DEFINE_SHOW_ATTRIBUTE(regs);
 static void soctherm_debug_init(struct platform_device *pdev)
 {
        struct tegra_soctherm *tegra = platform_get_drvdata(pdev);
-       struct dentry *root, *file;
+       struct dentry *root;
 
        root = debugfs_create_dir("soctherm", NULL);
-       if (!root) {
-               dev_err(&pdev->dev, "failed to create debugfs directory\n");
-               return;
-       }
 
        tegra->debugfs_dir = root;
 
-       file = debugfs_create_file("reg_contents", 0644, root,
-                                  pdev, &regs_fops);
-       if (!file) {
-               dev_err(&pdev->dev, "failed to create debugfs file\n");
-               debugfs_remove_recursive(tegra->debugfs_dir);
-               tegra->debugfs_dir = NULL;
-       }
+       debugfs_create_file("reg_contents", 0644, root, pdev, &regs_fops);
 }
 #else
 static inline void soctherm_debug_init(struct platform_device *pdev) {}
index 10b56c6..5668a44 100644 (file)
@@ -1967,10 +1967,10 @@ struct tb_sw_lookup {
        u64 route;
 };
 
-static int tb_switch_match(struct device *dev, void *data)
+static int tb_switch_match(struct device *dev, const void *data)
 {
        struct tb_switch *sw = tb_to_switch(dev);
-       struct tb_sw_lookup *lookup = data;
+       const struct tb_sw_lookup *lookup = data;
 
        if (!sw)
                return 0;
index ebfb0bd..33ad9d6 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/serial_reg.h>
 #include <linux/dmaengine.h>
 
+#include "../serial_mctrl_gpio.h"
+
 struct uart_8250_dma {
        int (*tx_dma)(struct uart_8250_port *p);
        int (*rx_dma)(struct uart_8250_port *p);
@@ -128,6 +130,24 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value)
        up->dl_write(up, value);
 }
 
+static inline bool serial8250_set_THRI(struct uart_8250_port *up)
+{
+       if (up->ier & UART_IER_THRI)
+               return false;
+       up->ier |= UART_IER_THRI;
+       serial_out(up, UART_IER, up->ier);
+       return true;
+}
+
+static inline bool serial8250_clear_THRI(struct uart_8250_port *up)
+{
+       if (!(up->ier & UART_IER_THRI))
+               return false;
+       up->ier &= ~UART_IER_THRI;
+       serial_out(up, UART_IER, up->ier);
+       return true;
+}
+
 struct uart_8250_port *serial8250_get_port(int line);
 
 void serial8250_rpm_get(struct uart_8250_port *p);
@@ -139,14 +159,82 @@ void serial8250_rpm_put_tx(struct uart_8250_port *p);
 int serial8250_em485_init(struct uart_8250_port *p);
 void serial8250_em485_destroy(struct uart_8250_port *p);
 
+/* MCR <-> TIOCM conversion */
+static inline int serial8250_TIOCM_to_MCR(int tiocm)
+{
+       int mcr = 0;
+
+       if (tiocm & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (tiocm & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (tiocm & TIOCM_OUT1)
+               mcr |= UART_MCR_OUT1;
+       if (tiocm & TIOCM_OUT2)
+               mcr |= UART_MCR_OUT2;
+       if (tiocm & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       return mcr;
+}
+
+static inline int serial8250_MCR_to_TIOCM(int mcr)
+{
+       int tiocm = 0;
+
+       if (mcr & UART_MCR_RTS)
+               tiocm |= TIOCM_RTS;
+       if (mcr & UART_MCR_DTR)
+               tiocm |= TIOCM_DTR;
+       if (mcr & UART_MCR_OUT1)
+               tiocm |= TIOCM_OUT1;
+       if (mcr & UART_MCR_OUT2)
+               tiocm |= TIOCM_OUT2;
+       if (mcr & UART_MCR_LOOP)
+               tiocm |= TIOCM_LOOP;
+
+       return tiocm;
+}
+
+/* MSR <-> TIOCM conversion */
+static inline int serial8250_MSR_to_TIOCM(int msr)
+{
+       int tiocm = 0;
+
+       if (msr & UART_MSR_DCD)
+               tiocm |= TIOCM_CAR;
+       if (msr & UART_MSR_RI)
+               tiocm |= TIOCM_RNG;
+       if (msr & UART_MSR_DSR)
+               tiocm |= TIOCM_DSR;
+       if (msr & UART_MSR_CTS)
+               tiocm |= TIOCM_CTS;
+
+       return tiocm;
+}
+
 static inline void serial8250_out_MCR(struct uart_8250_port *up, int value)
 {
        serial_out(up, UART_MCR, value);
+
+       if (up->gpios)
+               mctrl_gpio_set(up->gpios, serial8250_MCR_to_TIOCM(value));
 }
 
 static inline int serial8250_in_MCR(struct uart_8250_port *up)
 {
-       return serial_in(up, UART_MCR);
+       int mctrl;
+
+       mctrl = serial_in(up, UART_MCR);
+
+       if (up->gpios) {
+               unsigned int mctrl_gpio = 0;
+
+               mctrl_gpio = mctrl_gpio_get_outputs(up->gpios, &mctrl_gpio);
+               mctrl |= serial8250_TIOCM_to_MCR(mctrl_gpio);
+       }
+
+       return mctrl;
 }
 
 #if defined(__alpha__) && !defined(CONFIG_PCI)
index e441221..df3bcc0 100644 (file)
@@ -14,6 +14,7 @@
  *           serial8250_register_8250_port() ports
  */
 
+#include <linux/acpi.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/ioport.h>
@@ -982,6 +983,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
 
        uart = serial8250_find_match_or_unused(&up->port);
        if (uart && uart->port.type != PORT_8250_CIR) {
+               struct mctrl_gpios *gpios;
+
                if (uart->port.dev)
                        uart_remove_one_port(&serial8250_reg, &uart->port);
 
@@ -1016,6 +1019,22 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
                if (up->port.flags & UPF_FIXED_TYPE)
                        uart->port.type = up->port.type;
 
+               /*
+                * Only call mctrl_gpio_init(), if the device has no ACPI
+                * companion device
+                */
+               if (!has_acpi_companion(uart->port.dev)) {
+                       gpios = mctrl_gpio_init(&uart->port, 0);
+                       if (IS_ERR(gpios)) {
+                               if (PTR_ERR(gpios) != -ENOSYS) {
+                                       ret = PTR_ERR(gpios);
+                                       goto out_unlock;
+                               }
+                       } else {
+                               uart->gpios = gpios;
+                       }
+               }
+
                serial8250_set_defaults(uart);
 
                /* Possibly override default I/O functions.  */
@@ -1082,6 +1101,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
                }
        }
 
+out_unlock:
        mutex_unlock(&serial_mutex);
 
        return ret;
index bfa1a85..890fa7d 100644 (file)
@@ -34,10 +34,8 @@ static void __dma_tx_complete(void *param)
                uart_write_wakeup(&p->port);
 
        ret = serial8250_tx_dma(p);
-       if (ret) {
-               p->ier |= UART_IER_THRI;
-               serial_port_out(&p->port, UART_IER, p->ier);
-       }
+       if (ret)
+               serial8250_set_THRI(p);
 
        spin_unlock_irqrestore(&p->port.lock, flags);
 }
@@ -100,10 +98,7 @@ int serial8250_tx_dma(struct uart_8250_port *p)
        dma_async_issue_pending(dma->txchan);
        if (dma->tx_err) {
                dma->tx_err = 0;
-               if (p->ier & UART_IER_THRI) {
-                       p->ier &= ~UART_IER_THRI;
-                       serial_out(p, UART_IER, p->ier);
-               }
+               serial8250_clear_THRI(p);
        }
        return 0;
 err:
index 417c7c8..b411ba4 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/serial_8250.h>
@@ -47,7 +48,6 @@
 #define MTK_UART_DMA_EN_RX     0x5
 
 #define MTK_UART_ESCAPE_CHAR   0x77    /* Escape char added under sw fc */
-#define MTK_UART_TX_SIZE       UART_XMIT_SIZE
 #define MTK_UART_RX_SIZE       0x8000
 #define MTK_UART_TX_TRIGGER    1
 #define MTK_UART_RX_TRIGGER    MTK_UART_RX_SIZE
@@ -70,6 +70,7 @@ struct mtk8250_data {
 #ifdef CONFIG_SERIAL_8250_DMA
        enum dma_rx_status      rx_status;
 #endif
+       int                     rx_wakeup_irq;
 };
 
 /* flow control mode */
@@ -89,28 +90,30 @@ static void mtk8250_dma_rx_complete(void *param)
        struct mtk8250_data *data = up->port.private_data;
        struct tty_port *tty_port = &up->port.state->port;
        struct dma_tx_state state;
+       int copied, total, cnt;
        unsigned char *ptr;
-       int copied;
 
-       dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
-                               dma->rx_size, DMA_FROM_DEVICE);
+       if (data->rx_status == DMA_RX_SHUTDOWN)
+               return;
 
        dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
+       total = dma->rx_size - state.residue;
+       cnt = total;
 
-       if (data->rx_status == DMA_RX_SHUTDOWN)
-               return;
+       if ((data->rx_pos + cnt) > dma->rx_size)
+               cnt = dma->rx_size - data->rx_pos;
 
-       if ((data->rx_pos + state.residue) <= dma->rx_size) {
-               ptr = (unsigned char *)(data->rx_pos + dma->rx_buf);
-               copied = tty_insert_flip_string(tty_port, ptr, state.residue);
-       } else {
-               ptr = (unsigned char *)(data->rx_pos + dma->rx_buf);
-               copied = tty_insert_flip_string(tty_port, ptr,
-                                               dma->rx_size - data->rx_pos);
+       ptr = (unsigned char *)(data->rx_pos + dma->rx_buf);
+       copied = tty_insert_flip_string(tty_port, ptr, cnt);
+       data->rx_pos += cnt;
+
+       if (total > cnt) {
                ptr = (unsigned char *)(dma->rx_buf);
-               copied += tty_insert_flip_string(tty_port, ptr,
-                               data->rx_pos + state.residue - dma->rx_size);
+               cnt = total - cnt;
+               copied += tty_insert_flip_string(tty_port, ptr, cnt);
+               data->rx_pos = cnt;
        }
+
        up->port.icount.rx += copied;
 
        tty_flip_buffer_push(tty_port);
@@ -121,9 +124,7 @@ static void mtk8250_dma_rx_complete(void *param)
 static void mtk8250_rx_dma(struct uart_8250_port *up)
 {
        struct uart_8250_dma *dma = up->dma;
-       struct mtk8250_data *data = up->port.private_data;
        struct dma_async_tx_descriptor  *desc;
-       struct dma_tx_state      state;
 
        desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
                                           dma->rx_size, DMA_DEV_TO_MEM,
@@ -138,12 +139,6 @@ static void mtk8250_rx_dma(struct uart_8250_port *up)
 
        dma->rx_cookie = dmaengine_submit(desc);
 
-       dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
-       data->rx_pos = state.residue;
-
-       dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr,
-                                  dma->rx_size, DMA_FROM_DEVICE);
-
        dma_async_issue_pending(dma->rxchan);
 }
 
@@ -156,13 +151,11 @@ static void mtk8250_dma_enable(struct uart_8250_port *up)
        if (data->rx_status != DMA_RX_START)
                return;
 
-       dma->rxconf.direction           = DMA_DEV_TO_MEM;
-       dma->rxconf.src_addr_width      = dma->rx_size / 1024;
-       dma->rxconf.src_addr            = dma->rx_addr;
+       dma->rxconf.src_port_window_size        = dma->rx_size;
+       dma->rxconf.src_addr                            = dma->rx_addr;
 
-       dma->txconf.direction           = DMA_MEM_TO_DEV;
-       dma->txconf.dst_addr_width      = MTK_UART_TX_SIZE / 1024;
-       dma->txconf.dst_addr            = dma->tx_addr;
+       dma->txconf.dst_port_window_size        = UART_XMIT_SIZE;
+       dma->txconf.dst_addr                            = dma->tx_addr;
 
        serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
                UART_FCR_CLEAR_XMIT);
@@ -551,6 +544,8 @@ static int mtk8250_probe(struct platform_device *pdev)
        pm_runtime_set_active(&pdev->dev);
        pm_runtime_enable(&pdev->dev);
 
+       data->rx_wakeup_irq = platform_get_irq(pdev, 1);
+
        return 0;
 }
 
@@ -572,15 +567,35 @@ static int mtk8250_remove(struct platform_device *pdev)
 static int __maybe_unused mtk8250_suspend(struct device *dev)
 {
        struct mtk8250_data *data = dev_get_drvdata(dev);
+       int irq = data->rx_wakeup_irq;
+       int err;
 
        serial8250_suspend_port(data->line);
 
+       pinctrl_pm_select_sleep_state(dev);
+       if (irq >= 0) {
+               err = enable_irq_wake(irq);
+               if (err) {
+                       dev_err(dev,
+                               "failed to enable irq wake on IRQ %d: %d\n",
+                               irq, err);
+                       pinctrl_pm_select_default_state(dev);
+                       serial8250_resume_port(data->line);
+                       return err;
+               }
+       }
+
        return 0;
 }
 
 static int __maybe_unused mtk8250_resume(struct device *dev)
 {
        struct mtk8250_data *data = dev_get_drvdata(dev);
+       int irq = data->rx_wakeup_irq;
+
+       if (irq >= 0)
+               disable_irq_wake(irq);
+       pinctrl_pm_select_default_state(dev);
 
        serial8250_resume_port(data->line);
 
index 0277479..0826cfd 100644 (file)
@@ -70,9 +70,10 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
                /* Get clk rate through clk driver if present */
                info->clk = devm_clk_get(&ofdev->dev, NULL);
                if (IS_ERR(info->clk)) {
-                       dev_warn(&ofdev->dev,
-                               "clk or clock-frequency not defined\n");
                        ret = PTR_ERR(info->clk);
+                       if (ret != -EPROBE_DEFER)
+                               dev_warn(&ofdev->dev,
+                                        "failed to get clock: %d\n", ret);
                        goto err_pmruntime;
                }
 
@@ -205,18 +206,16 @@ err_pmruntime:
 /*
  * Try to register a serial port
  */
-static const struct of_device_id of_platform_serial_table[];
 static int of_platform_serial_probe(struct platform_device *ofdev)
 {
-       const struct of_device_id *match;
        struct of_serial_info *info;
        struct uart_8250_port port8250;
+       unsigned int port_type;
        u32 tx_threshold;
-       int port_type;
        int ret;
 
-       match = of_match_device(of_platform_serial_table, &ofdev->dev);
-       if (!match)
+       port_type = (unsigned long)of_device_get_match_data(&ofdev->dev);
+       if (port_type == PORT_UNKNOWN)
                return -EINVAL;
 
        if (of_property_read_bool(ofdev->dev.of_node, "used-by-rtas"))
@@ -226,7 +225,6 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
        if (info == NULL)
                return -ENOMEM;
 
-       port_type = (unsigned long)match->data;
        memset(&port8250, 0, sizeof(port8250));
        ret = of_platform_serial_setup(ofdev, port_type, &port8250.port, info);
        if (ret)
index 0a83166..3ef65cb 100644 (file)
@@ -141,18 +141,20 @@ static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
 
        serial8250_do_set_mctrl(port, mctrl);
 
-       /*
-        * Turn off autoRTS if RTS is lowered and restore autoRTS setting
-        * if RTS is raised
-        */
-       lcr = serial_in(up, UART_LCR);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-       if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
-               priv->efr |= UART_EFR_RTS;
-       else
-               priv->efr &= ~UART_EFR_RTS;
-       serial_out(up, UART_EFR, priv->efr);
-       serial_out(up, UART_LCR, lcr);
+       if (!up->gpios) {
+               /*
+                * Turn off autoRTS if RTS is lowered and restore autoRTS
+                * setting if RTS is raised
+                */
+               lcr = serial_in(up, UART_LCR);
+               serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+               if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
+                       priv->efr |= UART_EFR_RTS;
+               else
+                       priv->efr &= ~UART_EFR_RTS;
+               serial_out(up, UART_EFR, priv->efr);
+               serial_out(up, UART_LCR, lcr);
+       }
 }
 
 /*
@@ -453,7 +455,8 @@ static void omap_8250_set_termios(struct uart_port *port,
        priv->efr = 0;
        up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
 
-       if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
+       if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW &&
+           !up->gpios) {
                /* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */
                up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
                priv->efr |= UART_EFR_CTS;
@@ -923,15 +926,13 @@ static void omap_8250_dma_tx_complete(void *param)
                ret = omap_8250_tx_dma(p);
                if (ret)
                        en_thri = true;
-
        } else if (p->capabilities & UART_CAP_RPM) {
                en_thri = true;
        }
 
        if (en_thri) {
                dma->tx_err = 1;
-               p->ier |= UART_IER_THRI;
-               serial_port_out(&p->port, UART_IER, p->ier);
+               serial8250_set_THRI(p);
        }
 
        spin_unlock_irqrestore(&p->port.lock, flags);
@@ -959,10 +960,7 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
                        ret = -EBUSY;
                        goto err;
                }
-               if (p->ier & UART_IER_THRI) {
-                       p->ier &= ~UART_IER_THRI;
-                       serial_out(p, UART_IER, p->ier);
-               }
+               serial8250_clear_THRI(p);
                return 0;
        }
 
@@ -1020,10 +1018,7 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
        if (dma->tx_err)
                dma->tx_err = 0;
 
-       if (p->ier & UART_IER_THRI) {
-               p->ier &= ~UART_IER_THRI;
-               serial_out(p, UART_IER, p->ier);
-       }
+       serial8250_clear_THRI(p);
        if (skip_byte)
                serial_out(p, UART_TX, xmit->buf[xmit->tail]);
        return 0;
index df41397..7f740b3 100644 (file)
@@ -1326,13 +1326,66 @@ static int pci_default_setup(struct serial_private *priv,
 
        return setup_port(priv, port, bar, offset, board->reg_shift);
 }
-
+static void
+pericom_do_set_divisor(struct uart_port *port, unsigned int baud,
+                              unsigned int quot, unsigned int quot_frac)
+{
+       int scr;
+       int lcr;
+       int actual_baud;
+       int tolerance;
+
+       for (scr = 5 ; scr <= 15 ; scr++) {
+               actual_baud = 921600 * 16 / scr;
+               tolerance = actual_baud / 50;
+
+               if ((baud < actual_baud + tolerance) &&
+                       (baud > actual_baud - tolerance)) {
+
+                       lcr = serial_port_in(port, UART_LCR);
+                       serial_port_out(port, UART_LCR, lcr | 0x80);
+
+                       serial_port_out(port, UART_DLL, 1);
+                       serial_port_out(port, UART_DLM, 0);
+                       serial_port_out(port, 2, 16 - scr);
+                       serial_port_out(port, UART_LCR, lcr);
+                       return;
+               } else if (baud > actual_baud) {
+                       break;
+               }
+       }
+       serial8250_do_set_divisor(port, baud, quot, quot_frac);
+}
 static int pci_pericom_setup(struct serial_private *priv,
                  const struct pciserial_board *board,
                  struct uart_8250_port *port, int idx)
 {
        unsigned int bar, offset = board->first_offset, maxnr;
 
+       bar = FL_GET_BASE(board->flags);
+       if (board->flags & FL_BASE_BARS)
+               bar += idx;
+       else
+               offset += idx * board->uart_offset;
+
+
+       maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >>
+               (board->reg_shift + 3);
+
+       if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
+               return 1;
+
+       port->port.set_divisor = pericom_do_set_divisor;
+
+       return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+static int pci_pericom_setup_four_at_eight(struct serial_private *priv,
+                 const struct pciserial_board *board,
+                 struct uart_8250_port *port, int idx)
+{
+       unsigned int bar, offset = board->first_offset, maxnr;
+
        bar = FL_GET_BASE(board->flags);
        if (board->flags & FL_BASE_BARS)
                bar += idx;
@@ -1348,6 +1401,8 @@ static int pci_pericom_setup(struct serial_private *priv,
        if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
                return 1;
 
+       port->port.set_divisor = pericom_do_set_divisor;
+
        return setup_port(priv, port, bar, offset, board->reg_shift);
 }
 
@@ -1995,7 +2050,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .device         = PCI_DEVICE_ID_PERICOM_PI7C9X7954,
                .subvendor      = PCI_ANY_ID,
                .subdevice      = PCI_ANY_ID,
-               .setup          = pci_pericom_setup,
+               .setup          = pci_pericom_setup_four_at_eight,
        },
        /*
         * PLX
@@ -2032,107 +2087,113 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S,
                .device     = PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
-       /*
+       {
+               .vendor     = PCI_VENDOR_ID_ACCESIO,
+               .device     = PCI_ANY_ID,
+               .subvendor  = PCI_ANY_ID,
+               .subdevice  = PCI_ANY_ID,
+               .setup      = pci_pericom_setup,
+       },      /*
         * SBS Technologies, Inc., PMC-OCTALPRO 232
         */
        {
index 431e69a..dfca331 100644 (file)
@@ -462,8 +462,8 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
                return -ENODEV;
 
        dev_dbg(&dev->dev,
-                "Setup PNP port: port %lx, mem %pa, irq %d, type %d\n",
-                uart.port.iobase, &uart.port.mapbase,
+                "Setup PNP port: port %#lx, mem %#llx, irq %u, type %u\n",
+                uart.port.iobase, (unsigned long long)uart.port.mapbase,
                 uart.port.irq, uart.port.iotype);
 
        if (flags & CIR_PORT) {
index d2f3310..c1cec80 100644 (file)
@@ -1502,11 +1502,8 @@ static void __stop_tx_rs485(struct uart_8250_port *p)
 
 static inline void __do_stop_tx(struct uart_8250_port *p)
 {
-       if (p->ier & UART_IER_THRI) {
-               p->ier &= ~UART_IER_THRI;
-               serial_out(p, UART_IER, p->ier);
+       if (serial8250_clear_THRI(p))
                serial8250_rpm_put_tx(p);
-       }
 }
 
 static inline void __stop_tx(struct uart_8250_port *p)
@@ -1555,10 +1552,7 @@ static inline void __start_tx(struct uart_port *port)
        if (up->dma && !up->dma->tx_dma(up))
                return;
 
-       if (!(up->ier & UART_IER_THRI)) {
-               up->ier |= UART_IER_THRI;
-               serial_port_out(port, UART_IER, up->ier);
-
+       if (serial8250_set_THRI(up)) {
                if (up->bugs & UART_BUG_TXEN) {
                        unsigned char lsr;
 
@@ -1662,6 +1656,8 @@ static void serial8250_disable_ms(struct uart_port *port)
        if (up->bugs & UART_BUG_NOMSR)
                return;
 
+       mctrl_gpio_disable_ms(up->gpios);
+
        up->ier &= ~UART_IER_MSI;
        serial_port_out(port, UART_IER, up->ier);
 }
@@ -1674,6 +1670,8 @@ static void serial8250_enable_ms(struct uart_port *port)
        if (up->bugs & UART_BUG_NOMSR)
                return;
 
+       mctrl_gpio_enable_ms(up->gpios);
+
        up->ier |= UART_IER_MSI;
 
        serial8250_rpm_get(up);
@@ -1869,13 +1867,13 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
 
        status = serial_port_in(port, UART_LSR);
 
-       if (status & (UART_LSR_DR | UART_LSR_BI) &&
-           iir & UART_IIR_RDI) {
+       if (status & (UART_LSR_DR | UART_LSR_BI)) {
                if (!up->dma || handle_rx_dma(up, iir))
                        status = serial8250_rx_chars(up, status);
        }
        serial8250_modem_status(up);
-       if ((!up->dma || up->dma->tx_err) && (status & UART_LSR_THRE))
+       if ((!up->dma || up->dma->tx_err) && (status & UART_LSR_THRE) &&
+               (up->ier & UART_IER_THRI))
                serial8250_tx_chars(up);
 
        uart_unlock_and_check_sysrq(port, flags);
@@ -1944,22 +1942,17 @@ unsigned int serial8250_do_get_mctrl(struct uart_port *port)
 {
        struct uart_8250_port *up = up_to_u8250p(port);
        unsigned int status;
-       unsigned int ret;
+       unsigned int val;
 
        serial8250_rpm_get(up);
        status = serial8250_modem_status(up);
        serial8250_rpm_put(up);
 
-       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;
+       val = serial8250_MSR_to_TIOCM(status);
+       if (up->gpios)
+               return mctrl_gpio_get(up->gpios, &val);
+
+       return val;
 }
 EXPORT_SYMBOL_GPL(serial8250_do_get_mctrl);
 
@@ -1973,18 +1966,9 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port)
 void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
        struct uart_8250_port *up = up_to_u8250p(port);
-       unsigned char mcr = 0;
+       unsigned char mcr;
 
-       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;
+       mcr = serial8250_TIOCM_to_MCR(mctrl);
 
        mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr;
 
index 296115f..509f6a3 100644 (file)
@@ -8,6 +8,7 @@ config SERIAL_8250
        tristate "8250/16550 and compatible serial support"
        depends on !S390
        select SERIAL_CORE
+       select SERIAL_MCTRL_GPIO if GPIOLIB
        ---help---
          This selects whether you want to include the driver for the standard
          serial ports.  The standard answer is Y.  People who might say N
index 0d31251..b416c7b 100644 (file)
@@ -457,20 +457,6 @@ config SERIAL_21285_CONSOLE
          your boot loader (lilo or loadlin) about how to pass options to the
          kernel at boot time.)
 
-config SERIAL_MPSC
-       bool "Marvell MPSC serial port support"
-       depends on MV64X60
-       select SERIAL_CORE
-       help
-         Say Y here if you want to use the Marvell MPSC serial controller.
-
-config SERIAL_MPSC_CONSOLE
-       bool "Support for console on Marvell MPSC serial port"
-       depends on SERIAL_MPSC
-       select SERIAL_CORE_CONSOLE
-       help
-         Say Y here if you want to support a serial console on a Marvell MPSC.
-
 config SERIAL_PXA
        bool "PXA serial port support (DEPRECATED)"
        depends on ARCH_PXA || ARCH_MMP
index 79c3d51..7cd7cab 100644 (file)
@@ -46,7 +46,6 @@ obj-$(CONFIG_SERIAL_CPM) += cpm_uart/
 obj-$(CONFIG_SERIAL_IMX) += imx.o
 obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o
 obj-$(CONFIG_SERIAL_ICOM) += icom.o
-obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
 obj-$(CONFIG_SERIAL_MESON) += meson_uart.o
 obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
 obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
index 89ade21..5921a33 100644 (file)
@@ -1717,7 +1717,7 @@ static int pl011_allocate_irq(struct uart_amba_port *uap)
 {
        pl011_write(uap->im, uap, REG_IMSC);
 
-       return request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
+       return request_irq(uap->port.irq, pl011_int, IRQF_SHARED, "uart-pl011", uap);
 }
 
 /*
index b929c7a..de6d02f 100644 (file)
@@ -407,7 +407,16 @@ static int cpm_uart_startup(struct uart_port *port)
                        clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX);
                }
                cpm_uart_initbd(pinfo);
-               cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
+               if (IS_SMC(pinfo)) {
+                       out_be32(&pinfo->smcup->smc_rstate, 0);
+                       out_be32(&pinfo->smcup->smc_tstate, 0);
+                       out_be16(&pinfo->smcup->smc_rbptr,
+                                in_be16(&pinfo->smcup->smc_rbase));
+                       out_be16(&pinfo->smcup->smc_tbptr,
+                                in_be16(&pinfo->smcup->smc_tbase));
+               } else {
+                       cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
+               }
        }
        /* Install interrupt handler. */
        retval = request_irq(port->irq, cpm_uart_int, 0, "cpm_uart", port);
@@ -567,8 +576,6 @@ static void cpm_uart_set_termios(struct uart_port *port,
        /*
         * Set up parity check flag
         */
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
        port->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
        if (termios->c_iflag & INPCK)
                port->read_status_mask |= BD_SC_FR | BD_SC_PR;
@@ -861,16 +868,14 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
                 (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE);
 
 /*
- *  In case SMC1 is being relocated...
+ *  In case SMC is being relocated...
  */
-#if defined (CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
        out_be16(&up->smc_rbptr, in_be16(&pinfo->smcup->smc_rbase));
        out_be16(&up->smc_tbptr, in_be16(&pinfo->smcup->smc_tbase));
        out_be32(&up->smc_rstate, 0);
        out_be32(&up->smc_tstate, 0);
        out_be16(&up->smc_brkcr, 1);              /* number of break chars */
        out_be16(&up->smc_brkec, 0);
-#endif
 
        /* Set up the uart parameters in the
         * parameter ram.
@@ -884,8 +889,6 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
        out_be16(&up->smc_brkec, 0);
        out_be16(&up->smc_brkcr, 1);
 
-       cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
-
        /* Set UART mode, 8 bit, no parity, one stop.
         * Enable receive and transmit.
         */
index f460cca..13ac36e 100644 (file)
@@ -541,7 +541,11 @@ static int __init digicolor_uart_init(void)
        if (ret)
                return ret;
 
-       return platform_driver_register(&digicolor_uart_platform);
+       ret = platform_driver_register(&digicolor_uart_platform);
+       if (ret)
+               uart_unregister_driver(&digicolor_uart);
+
+       return ret;
 }
 module_init(digicolor_uart_init);
 
index ea1c85e..92dad2b 100644 (file)
 
 static DEFINE_IDA(fsl_lpuart_ida);
 
+enum lpuart_type {
+       VF610_LPUART,
+       LS1021A_LPUART,
+       IMX7ULP_LPUART,
+       IMX8QXP_LPUART,
+};
+
 struct lpuart_port {
        struct uart_port        port;
-       struct clk              *clk;
+       enum lpuart_type        devtype;
+       struct clk              *ipg_clk;
+       struct clk              *baud_clk;
        unsigned int            txfifo_size;
        unsigned int            rxfifo_size;
 
@@ -261,19 +270,29 @@ struct lpuart_port {
 };
 
 struct lpuart_soc_data {
-       char    iotype;
-       u8      reg_off;
+       enum lpuart_type devtype;
+       char iotype;
+       u8 reg_off;
 };
 
 static const struct lpuart_soc_data vf_data = {
+       .devtype = VF610_LPUART,
        .iotype = UPIO_MEM,
 };
 
 static const struct lpuart_soc_data ls_data = {
+       .devtype = LS1021A_LPUART,
        .iotype = UPIO_MEM32BE,
 };
 
-static struct lpuart_soc_data imx_data = {
+static struct lpuart_soc_data imx7ulp_data = {
+       .devtype = IMX7ULP_LPUART,
+       .iotype = UPIO_MEM32,
+       .reg_off = IMX_REG_OFF,
+};
+
+static struct lpuart_soc_data imx8qxp_data = {
+       .devtype = IMX8QXP_LPUART,
        .iotype = UPIO_MEM32,
        .reg_off = IMX_REG_OFF,
 };
@@ -281,7 +300,8 @@ static struct lpuart_soc_data imx_data = {
 static const struct of_device_id lpuart_dt_ids[] = {
        { .compatible = "fsl,vf610-lpuart",     .data = &vf_data, },
        { .compatible = "fsl,ls1021a-lpuart",   .data = &ls_data, },
-       { .compatible = "fsl,imx7ulp-lpuart",   .data = &imx_data, },
+       { .compatible = "fsl,imx7ulp-lpuart",   .data = &imx7ulp_data, },
+       { .compatible = "fsl,imx8qxp-lpuart",   .data = &imx8qxp_data, },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
@@ -289,6 +309,11 @@ MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
 /* Forward declare this for the dma callbacks*/
 static void lpuart_dma_tx_complete(void *arg);
 
+static inline bool is_imx8qxp_lpuart(struct lpuart_port *sport)
+{
+       return sport->devtype == IMX8QXP_LPUART;
+}
+
 static inline u32 lpuart32_read(struct uart_port *port, u32 off)
 {
        switch (port->iotype) {
@@ -314,6 +339,39 @@ static inline void lpuart32_write(struct uart_port *port, u32 val,
        }
 }
 
+static int __lpuart_enable_clks(struct lpuart_port *sport, bool is_en)
+{
+       int ret = 0;
+
+       if (is_en) {
+               ret = clk_prepare_enable(sport->ipg_clk);
+               if (ret)
+                       return ret;
+
+               ret = clk_prepare_enable(sport->baud_clk);
+               if (ret) {
+                       clk_disable_unprepare(sport->ipg_clk);
+                       return ret;
+               }
+       } else {
+               clk_disable_unprepare(sport->baud_clk);
+               clk_disable_unprepare(sport->ipg_clk);
+       }
+
+       return 0;
+}
+
+static unsigned int lpuart_get_baud_clk_rate(struct lpuart_port *sport)
+{
+       if (is_imx8qxp_lpuart(sport))
+               return clk_get_rate(sport->baud_clk);
+
+       return clk_get_rate(sport->ipg_clk);
+}
+
+#define lpuart_enable_clks(x)  __lpuart_enable_clks(x, true)
+#define lpuart_disable_clks(x) __lpuart_enable_clks(x, false)
+
 static void lpuart_stop_tx(struct uart_port *port)
 {
        unsigned char temp;
@@ -1040,10 +1098,8 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
                sport->rx_dma_rng_buf_len = 16;
 
        ring->buf = kmalloc(sport->rx_dma_rng_buf_len, GFP_ATOMIC);
-       if (!ring->buf) {
-               dev_err(sport->port.dev, "Ring buf alloc failed\n");
+       if (!ring->buf)
                return -ENOMEM;
-       }
 
        sg_init_one(&sport->rx_sgl, ring->buf, sport->rx_dma_rng_buf_len);
        sg_set_buf(&sport->rx_sgl, ring->buf, sport->rx_dma_rng_buf_len);
@@ -2071,14 +2127,14 @@ lpuart_console_get_options(struct lpuart_port *sport, int *baud,
        brfa = readb(sport->port.membase + UARTCR4);
        brfa &= UARTCR4_BRFA_MASK;
 
-       uartclk = clk_get_rate(sport->clk);
+       uartclk = lpuart_get_baud_clk_rate(sport);
        /*
         * baud = mod_clk/(16*(sbr[13]+(brfa)/32)
         */
        baud_raw = uartclk / (16 * (sbr + brfa / 32));
 
        if (*baud != baud_raw)
-               printk(KERN_INFO "Serial: Console lpuart rounded baud rate"
+               dev_info(sport->port.dev, "Serial: Console lpuart rounded baud rate"
                                "from %d to %d\n", baud_raw, *baud);
 }
 
@@ -2114,14 +2170,14 @@ lpuart32_console_get_options(struct lpuart_port *sport, int *baud,
        bd = lpuart32_read(&sport->port, UARTBAUD);
        bd &= UARTBAUD_SBR_MASK;
        sbr = bd;
-       uartclk = clk_get_rate(sport->clk);
+       uartclk = lpuart_get_baud_clk_rate(sport);
        /*
         * baud = mod_clk/(16*(sbr[13]+(brfa)/32)
         */
        baud_raw = uartclk / (16 * sbr);
 
        if (*baud != baud_raw)
-               printk(KERN_INFO "Serial: Console lpuart rounded baud rate"
+               dev_info(sport->port.dev, "Serial: Console lpuart rounded baud rate"
                                "from %d to %d\n", baud_raw, *baud);
 }
 
@@ -2288,6 +2344,7 @@ static int lpuart_probe(struct platform_device *pdev)
        sport->port.mapbase = res->start;
        sport->port.dev = &pdev->dev;
        sport->port.type = PORT_LPUART;
+       sport->devtype = sdata->devtype;
        ret = platform_get_irq(pdev, 0);
        if (ret < 0) {
                dev_err(&pdev->dev, "cannot obtain irq\n");
@@ -2303,20 +2360,27 @@ static int lpuart_probe(struct platform_device *pdev)
 
        sport->port.rs485_config = lpuart_config_rs485;
 
-       sport->clk = devm_clk_get(&pdev->dev, "ipg");
-       if (IS_ERR(sport->clk)) {
-               ret = PTR_ERR(sport->clk);
-               dev_err(&pdev->dev, "failed to get uart clk: %d\n", ret);
+       sport->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
+       if (IS_ERR(sport->ipg_clk)) {
+               ret = PTR_ERR(sport->ipg_clk);
+               dev_err(&pdev->dev, "failed to get uart ipg clk: %d\n", ret);
                return ret;
        }
 
-       ret = clk_prepare_enable(sport->clk);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to enable uart clk: %d\n", ret);
-               return ret;
+       sport->baud_clk = NULL;
+       if (is_imx8qxp_lpuart(sport)) {
+               sport->baud_clk = devm_clk_get(&pdev->dev, "baud");
+               if (IS_ERR(sport->baud_clk)) {
+                       ret = PTR_ERR(sport->baud_clk);
+                       dev_err(&pdev->dev, "failed to get uart baud clk: %d\n", ret);
+                       return ret;
+               }
        }
 
-       sport->port.uartclk = clk_get_rate(sport->clk);
+       ret = lpuart_enable_clks(sport);
+       if (ret)
+               return ret;
+       sport->port.uartclk = lpuart_get_baud_clk_rate(sport);
 
        lpuart_ports[sport->port.line] = sport;
 
@@ -2364,7 +2428,7 @@ static int lpuart_probe(struct platform_device *pdev)
 
 failed_attach_port:
 failed_irq_request:
-       clk_disable_unprepare(sport->clk);
+       lpuart_disable_clks(sport);
        return ret;
 }
 
@@ -2376,7 +2440,7 @@ static int lpuart_remove(struct platform_device *pdev)
 
        ida_simple_remove(&fsl_lpuart_ida, sport->port.line);
 
-       clk_disable_unprepare(sport->clk);
+       lpuart_disable_clks(sport);
 
        if (sport->dma_tx_chan)
                dma_release_channel(sport->dma_tx_chan);
@@ -2441,7 +2505,7 @@ static int lpuart_suspend(struct device *dev)
        }
 
        if (sport->port.suspended && !irq_wake)
-               clk_disable_unprepare(sport->clk);
+               lpuart_disable_clks(sport);
 
        return 0;
 }
@@ -2453,7 +2517,7 @@ static int lpuart_resume(struct device *dev)
        unsigned long temp;
 
        if (sport->port.suspended && !irq_wake)
-               clk_prepare_enable(sport->clk);
+               lpuart_enable_clks(sport);
 
        if (lpuart_is_32(sport)) {
                lpuart32_setup_watermark(sport);
index 8b752e8..57d6e6b 100644 (file)
@@ -383,6 +383,7 @@ static void imx_uart_ucrs_restore(struct imx_port *sport,
 }
 #endif
 
+/* called with port.lock taken and irqs caller dependent */
 static void imx_uart_rts_active(struct imx_port *sport, u32 *ucr2)
 {
        *ucr2 &= ~(UCR2_CTSC | UCR2_CTS);
@@ -391,6 +392,7 @@ static void imx_uart_rts_active(struct imx_port *sport, u32 *ucr2)
        mctrl_gpio_set(sport->gpios, sport->port.mctrl);
 }
 
+/* called with port.lock taken and irqs caller dependent */
 static void imx_uart_rts_inactive(struct imx_port *sport, u32 *ucr2)
 {
        *ucr2 &= ~UCR2_CTSC;
@@ -400,6 +402,7 @@ static void imx_uart_rts_inactive(struct imx_port *sport, u32 *ucr2)
        mctrl_gpio_set(sport->gpios, sport->port.mctrl);
 }
 
+/* called with port.lock taken and irqs caller dependent */
 static void imx_uart_rts_auto(struct imx_port *sport, u32 *ucr2)
 {
        *ucr2 |= UCR2_CTSC;
@@ -1549,40 +1552,46 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
                old_csize = CS8;
        }
 
+       del_timer_sync(&sport->timer);
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
+       quot = uart_get_divisor(port, baud);
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+
+       /*
+        * Read current UCR2 and save it for future use, then clear all the bits
+        * except those we will or may need to preserve.
+        */
+       old_ucr2 = imx_uart_readl(sport, UCR2);
+       ucr2 = old_ucr2 & (UCR2_TXEN | UCR2_RXEN | UCR2_ATEN | UCR2_CTS);
+
+       ucr2 |= UCR2_SRST | UCR2_IRTS;
        if ((termios->c_cflag & CSIZE) == CS8)
-               ucr2 = UCR2_WS | UCR2_SRST | UCR2_IRTS;
-       else
-               ucr2 = UCR2_SRST | UCR2_IRTS;
-
-       if (termios->c_cflag & CRTSCTS) {
-               if (sport->have_rtscts) {
-                       ucr2 &= ~UCR2_IRTS;
-
-                       if (port->rs485.flags & SER_RS485_ENABLED) {
-                               /*
-                                * RTS is mandatory for rs485 operation, so keep
-                                * it under manual control and keep transmitter
-                                * disabled.
-                                */
-                               if (port->rs485.flags &
-                                   SER_RS485_RTS_AFTER_SEND)
-                                       imx_uart_rts_active(sport, &ucr2);
-                               else
-                                       imx_uart_rts_inactive(sport, &ucr2);
-                       } else {
-                               imx_uart_rts_auto(sport, &ucr2);
-                       }
-               } else {
-                       termios->c_cflag &= ~CRTSCTS;
-               }
-       } else if (port->rs485.flags & SER_RS485_ENABLED) {
-               /* disable transmitter */
+               ucr2 |= UCR2_WS;
+
+       if (!sport->have_rtscts)
+               termios->c_cflag &= ~CRTSCTS;
+
+       if (port->rs485.flags & SER_RS485_ENABLED) {
+               /*
+                * RTS is mandatory for rs485 operation, so keep
+                * it under manual control and keep transmitter
+                * disabled.
+                */
                if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
                        imx_uart_rts_active(sport, &ucr2);
                else
                        imx_uart_rts_inactive(sport, &ucr2);
-       }
 
+       } else if (termios->c_cflag & CRTSCTS)
+               imx_uart_rts_auto(sport, &ucr2);
+
+       if (termios->c_cflag & CRTSCTS)
+               ucr2 &= ~UCR2_IRTS;
 
        if (termios->c_cflag & CSTOPB)
                ucr2 |= UCR2_STPB;
@@ -1592,16 +1601,6 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
                        ucr2 |= UCR2_PROE;
        }
 
-       del_timer_sync(&sport->timer);
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
-       quot = uart_get_divisor(port, baud);
-
-       spin_lock_irqsave(&sport->port.lock, flags);
-
        sport->port.read_status_mask = 0;
        if (termios->c_iflag & INPCK)
                sport->port.read_status_mask |= (URXD_FRMERR | URXD_PRERR);
@@ -1639,7 +1638,6 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
        imx_uart_writel(sport,
                        old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN),
                        UCR1);
-       old_ucr2 = imx_uart_readl(sport, UCR2);
        imx_uart_writel(sport, old_ucr2 & ~UCR2_ATEN, UCR2);
 
        while (!(imx_uart_readl(sport, USR2) & USR2_TXDC))
@@ -1647,7 +1645,6 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
 
        /* then, disable everything */
        imx_uart_writel(sport, old_ucr2 & ~(UCR2_TXEN | UCR2_RXEN | UCR2_ATEN), UCR2);
-       old_ucr2 &= (UCR2_TXEN | UCR2_RXEN | UCR2_ATEN);
 
        /* custom-baudrate handling */
        div = sport->port.uartclk / (baud * 16);
@@ -1685,8 +1682,7 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
 
        imx_uart_writel(sport, old_ucr1, UCR1);
 
-       /* set the parity, stop bits and data size */
-       imx_uart_writel(sport, ucr2 | old_ucr2, UCR2);
+       imx_uart_writel(sport, ucr2, UCR2);
 
        if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
                imx_uart_enable_ms(&sport->port);
@@ -2015,7 +2011,7 @@ imx_uart_console_get_options(struct imx_port *sport, int *baud,
                }
 
                if (*baud != baud_raw)
-                       pr_info("Console IMX rounded baud rate from %d to %d\n",
+                       dev_info(sport->port.dev, "Console IMX rounded baud rate from %d to %d\n",
                                baud_raw, *baud);
        }
 }
index e5aebbf..e6c48a9 100644 (file)
@@ -258,12 +258,17 @@ struct max310x_one {
        struct work_struct      tx_work;
        struct work_struct      md_work;
        struct work_struct      rs_work;
+
+       u8 wr_header;
+       u8 rd_header;
+       u8 rx_buf[MAX310X_FIFO_SIZE];
 };
+#define to_max310x_port(_port) \
+       container_of(_port, struct max310x_one, port)
 
 struct max310x_port {
        struct max310x_devtype  *devtype;
        struct regmap           *regmap;
-       struct mutex            mutex;
        struct clk              *clk;
 #ifdef CONFIG_GPIOLIB
        struct gpio_chip        gpio;
@@ -496,37 +501,48 @@ static bool max310x_reg_precious(struct device *dev, unsigned int reg)
 
 static int max310x_set_baud(struct uart_port *port, int baud)
 {
-       unsigned int mode = 0, clk = port->uartclk, div = clk / baud;
-
-       /* Check for minimal value for divider */
-       if (div < 16)
-               div = 16;
+       unsigned int mode = 0, div = 0, frac = 0, c = 0, F = 0;
 
-       if (clk % baud && (div / 16) < 0x8000) {
+       /*
+        * Calculate the integer divisor first. Select a proper mode
+        * in case if the requested baud is too high for the pre-defined
+        * clocks frequency.
+        */
+       div = port->uartclk / baud;
+       if (div < 8) {
+               /* Mode x4 */
+               c = 4;
+               mode = MAX310X_BRGCFG_4XMODE_BIT;
+       } else if (div < 16) {
                /* Mode x2 */
+               c = 8;
                mode = MAX310X_BRGCFG_2XMODE_BIT;
-               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;
-               }
+       } else {
+               c = 16;
        }
 
-       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);
+       /* Calculate the divisor in accordance with the fraction coefficient */
+       div /= c;
+       F = c*baud;
 
-       return DIV_ROUND_CLOSEST(clk, div);
+       /* Calculate the baud rate fraction */
+       if (div > 0)
+               frac = (16*(port->uartclk % F)) / F;
+       else
+               div = 1;
+
+       max310x_port_write(port, MAX310X_BRGDIVMSB_REG, div >> 8);
+       max310x_port_write(port, MAX310X_BRGDIVLSB_REG, div);
+       max310x_port_write(port, MAX310X_BRGCFG_REG, frac | mode);
+
+       /* Return the actual baud rate we just programmed */
+       return (16*port->uartclk) / (c*(16*div + frac));
 }
 
 static int max310x_update_best_err(unsigned long f, long *besterr)
 {
        /* Use baudrate 115200 for calculate error */
-       long err = f % (115200 * 16);
+       long err = f % (460800 * 16);
 
        if ((*besterr < 0) || (*besterr > err)) {
                *besterr = err;
@@ -607,11 +623,11 @@ static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
 
 static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len)
 {
-       u8 header[] = { (port->iobase + MAX310X_THR_REG) | MAX310X_WRITE_BIT };
+       struct max310x_one *one = to_max310x_port(port);
        struct spi_transfer xfer[] = {
                {
-                       .tx_buf = &header,
-                       .len = sizeof(header),
+                       .tx_buf = &one->wr_header,
+                       .len = sizeof(one->wr_header),
                }, {
                        .tx_buf = txbuf,
                        .len = len,
@@ -622,11 +638,11 @@ static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int
 
 static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int len)
 {
-       u8 header[] = { port->iobase + MAX310X_RHR_REG };
+       struct max310x_one *one = to_max310x_port(port);
        struct spi_transfer xfer[] = {
                {
-                       .tx_buf = &header,
-                       .len = sizeof(header),
+                       .tx_buf = &one->rd_header,
+                       .len = sizeof(one->rd_header),
                }, {
                        .rx_buf = rxbuf,
                        .len = len,
@@ -637,8 +653,8 @@ static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int l
 
 static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
 {
+       struct max310x_one *one = to_max310x_port(port);
        unsigned int sts, ch, flag, i;
-       u8 buf[MAX310X_FIFO_SIZE];
 
        if (port->read_status_mask == MAX310X_LSR_RXOVR_BIT) {
                /* We are just reading, happily ignoring any error conditions.
@@ -653,7 +669,7 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
                 * */
 
                sts = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG);
-               max310x_batch_read(port, buf, rxlen);
+               max310x_batch_read(port, one->rx_buf, rxlen);
 
                port->icount.rx += rxlen;
                flag = TTY_NORMAL;
@@ -664,9 +680,16 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
                        port->icount.overrun++;
                }
 
-               for (i = 0; i < rxlen; ++i) {
-                       uart_insert_char(port, sts, MAX310X_LSR_RXOVR_BIT, buf[i], flag);
-               }
+               for (i = 0; i < (rxlen - 1); ++i)
+                       uart_insert_char(port, sts, 0, one->rx_buf[i], flag);
+
+               /*
+                * Handle the overrun case for the last character only, since
+                * the RxFIFO overflow happens after it is pushed to the FIFO
+                * tail.
+                */
+               uart_insert_char(port, sts, MAX310X_LSR_RXOVR_BIT,
+                                one->rx_buf[rxlen], flag);
 
        } else {
                if (unlikely(rxlen >= port->fifosize)) {
@@ -766,10 +789,9 @@ static void max310x_handle_tx(struct uart_port *port)
 
 static void max310x_start_tx(struct uart_port *port)
 {
-       struct max310x_one *one = container_of(port, struct max310x_one, port);
+       struct max310x_one *one = to_max310x_port(port);
 
-       if (!work_pending(&one->tx_work))
-               schedule_work(&one->tx_work);
+       schedule_work(&one->tx_work);
 }
 
 static irqreturn_t max310x_port_irq(struct max310x_port *s, int portno)
@@ -826,14 +848,11 @@ static irqreturn_t max310x_ist(int irq, void *dev_id)
        return IRQ_RETVAL(handled);
 }
 
-static void max310x_wq_proc(struct work_struct *ws)
+static void max310x_tx_proc(struct work_struct *ws)
 {
        struct max310x_one *one = container_of(ws, struct max310x_one, tx_work);
-       struct max310x_port *s = dev_get_drvdata(one->port.dev);
 
-       mutex_lock(&s->mutex);
        max310x_handle_tx(&one->port);
-       mutex_unlock(&s->mutex);
 }
 
 static unsigned int max310x_tx_empty(struct uart_port *port)
@@ -863,7 +882,7 @@ static void max310x_md_proc(struct work_struct *ws)
 
 static void max310x_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
-       struct max310x_one *one = container_of(port, struct max310x_one, port);
+       struct max310x_one *one = to_max310x_port(port);
 
        schedule_work(&one->md_work);
 }
@@ -962,37 +981,36 @@ static void max310x_set_termios(struct uart_port *port,
 static void max310x_rs_proc(struct work_struct *ws)
 {
        struct max310x_one *one = container_of(ws, struct max310x_one, rs_work);
-       unsigned int val;
+       unsigned int delay, mode1 = 0, mode2 = 0;
 
-       val = (one->port.rs485.delay_rts_before_send << 4) |
+       delay = (one->port.rs485.delay_rts_before_send << 4) |
                one->port.rs485.delay_rts_after_send;
-       max310x_port_write(&one->port, MAX310X_HDPIXDELAY_REG, val);
+       max310x_port_write(&one->port, MAX310X_HDPIXDELAY_REG, delay);
 
        if (one->port.rs485.flags & SER_RS485_ENABLED) {
-               max310x_port_update(&one->port, MAX310X_MODE1_REG,
-                               MAX310X_MODE1_TRNSCVCTRL_BIT,
-                               MAX310X_MODE1_TRNSCVCTRL_BIT);
-               max310x_port_update(&one->port, MAX310X_MODE2_REG,
-                               MAX310X_MODE2_ECHOSUPR_BIT,
-                               MAX310X_MODE2_ECHOSUPR_BIT);
-       } else {
-               max310x_port_update(&one->port, MAX310X_MODE1_REG,
-                               MAX310X_MODE1_TRNSCVCTRL_BIT, 0);
-               max310x_port_update(&one->port, MAX310X_MODE2_REG,
-                               MAX310X_MODE2_ECHOSUPR_BIT, 0);
+               mode1 = MAX310X_MODE1_TRNSCVCTRL_BIT;
+
+               if (!(one->port.rs485.flags & SER_RS485_RX_DURING_TX))
+                       mode2 = MAX310X_MODE2_ECHOSUPR_BIT;
        }
+
+       max310x_port_update(&one->port, MAX310X_MODE1_REG,
+                       MAX310X_MODE1_TRNSCVCTRL_BIT, mode1);
+       max310x_port_update(&one->port, MAX310X_MODE2_REG,
+                       MAX310X_MODE2_ECHOSUPR_BIT, mode2);
 }
 
 static int max310x_rs485_config(struct uart_port *port,
                                struct serial_rs485 *rs485)
 {
-       struct max310x_one *one = container_of(port, struct max310x_one, port);
+       struct max310x_one *one = to_max310x_port(port);
 
        if ((rs485->delay_rts_before_send > 0x0f) ||
            (rs485->delay_rts_after_send > 0x0f))
                return -ERANGE;
 
-       rs485->flags &= SER_RS485_RTS_ON_SEND | SER_RS485_ENABLED;
+       rs485->flags &= SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX |
+                       SER_RS485_ENABLED;
        memset(rs485->padding, 0, sizeof(rs485->padding));
        port->rs485 = *rs485;
 
@@ -1018,6 +1036,22 @@ static int max310x_startup(struct uart_port *port)
        max310x_port_update(port, MAX310X_MODE2_REG,
                            MAX310X_MODE2_FIFORST_BIT, 0);
 
+       /* Configure mode1/mode2 to have rs485/rs232 enabled at startup */
+       val = (clamp(port->rs485.delay_rts_before_send, 0U, 15U) << 4) |
+               clamp(port->rs485.delay_rts_after_send, 0U, 15U);
+       max310x_port_write(port, MAX310X_HDPIXDELAY_REG, val);
+
+       if (port->rs485.flags & SER_RS485_ENABLED) {
+               max310x_port_update(port, MAX310X_MODE1_REG,
+                                   MAX310X_MODE1_TRNSCVCTRL_BIT,
+                                   MAX310X_MODE1_TRNSCVCTRL_BIT);
+
+               if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
+                       max310x_port_update(port, MAX310X_MODE2_REG,
+                                           MAX310X_MODE2_ECHOSUPR_BIT,
+                                           MAX310X_MODE2_ECHOSUPR_BIT);
+       }
+
        /* Configure flow control levels */
        /* Flow control halt level 96, resume level 48 */
        max310x_port_write(port, MAX310X_FLOWLVL_REG,
@@ -1269,8 +1303,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
        uartclk = max310x_set_ref_clk(dev, s, freq, xtal);
        dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk);
 
-       mutex_init(&s->mutex);
-
        for (i = 0; i < devtype->nr; i++) {
                unsigned int line;
 
@@ -1298,11 +1330,15 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
                /* Clear IRQ status register */
                max310x_port_read(&s->p[i].port, MAX310X_IRQSTS_REG);
                /* Initialize queue for start TX */
-               INIT_WORK(&s->p[i].tx_work, max310x_wq_proc);
+               INIT_WORK(&s->p[i].tx_work, max310x_tx_proc);
                /* Initialize queue for changing LOOPBACK mode */
                INIT_WORK(&s->p[i].md_work, max310x_md_proc);
                /* Initialize queue for changing RS485 mode */
                INIT_WORK(&s->p[i].rs_work, max310x_rs_proc);
+               /* Initialize SPI-transfer buffers */
+               s->p[i].wr_header = (s->p[i].port.iobase + MAX310X_THR_REG) |
+                                   MAX310X_WRITE_BIT;
+               s->p[i].rd_header = (s->p[i].port.iobase + MAX310X_RHR_REG);
 
                /* Register port */
                ret = uart_add_one_port(&max310x_uart, &s->p[i].port);
@@ -1350,8 +1386,6 @@ out_uart:
                }
        }
 
-       mutex_destroy(&s->mutex);
-
 out_clk:
        clk_disable_unprepare(s->clk);
 
@@ -1372,7 +1406,6 @@ static int max310x_remove(struct device *dev)
                s->devtype->power(&s->p[i].port, 0);
        }
 
-       mutex_destroy(&s->mutex);
        clk_disable_unprepare(s->clk);
 
        return 0;
diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c
deleted file mode 100644 (file)
index 1f60d6f..0000000
+++ /dev/null
@@ -1,2138 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Generic driver for the MPSC (UART mode) on Marvell parts (e.g., GT64240,
- * GT64260, MV64340, MV64360, GT96100, ... ).
- *
- * Author: Mark A. Greer <mgreer@mvista.com>
- *
- * Based on an old MPSC driver that was in the linuxppc tree.  It appears to
- * have been created by Chris Zankel (formerly of MontaVista) but there
- * is no proper Copyright so I'm not sure.  Apparently, parts were also
- * taken from PPCBoot (now U-Boot).  Also based on drivers/serial/8250.c
- * by Russell King.
- *
- * 2004 (c) MontaVista, Software, Inc.
- */
-/*
- * The MPSC interface is much like a typical network controller's interface.
- * That is, you set up separate rings of descriptors for transmitting and
- * receiving data.  There is also a pool of buffers with (one buffer per
- * descriptor) that incoming data are dma'd into or outgoing data are dma'd
- * out of.
- *
- * The MPSC requires two other controllers to be able to work.  The Baud Rate
- * Generator (BRG) provides a clock at programmable frequencies which determines
- * the baud rate.  The Serial DMA Controller (SDMA) takes incoming data from the
- * MPSC and DMA's it into memory or DMA's outgoing data and passes it to the
- * MPSC.  It is actually the SDMA interrupt that the driver uses to keep the
- * transmit and receive "engines" going (i.e., indicate data has been
- * transmitted or received).
- *
- * NOTES:
- *
- * 1) Some chips have an erratum where several regs cannot be
- * read.  To work around that, we keep a local copy of those regs in
- * 'mpsc_port_info'.
- *
- * 2) Some chips have an erratum where the ctlr will hang when the SDMA ctlr
- * accesses system mem with coherency enabled.  For that reason, the driver
- * assumes that coherency for that ctlr has been disabled.  This means
- * that when in a cache coherent system, the driver has to manually manage
- * the data cache on the areas that it touches because the dma_* macro are
- * basically no-ops.
- *
- * 3) There is an erratum (on PPC) where you can't use the instruction to do
- * a DMA_TO_DEVICE/cache clean so DMA_BIDIRECTIONAL/flushes are used in places
- * where a DMA_TO_DEVICE/clean would have [otherwise] sufficed.
- *
- * 4) AFAICT, hardware flow control isn't supported by the controller --MAG.
- */
-
-
-#if defined(CONFIG_SERIAL_MPSC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/mv643xx.h>
-#include <linux/platform_device.h>
-#include <linux/gfp.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#define        MPSC_NUM_CTLRS          2
-
-/*
- * Descriptors and buffers must be cache line aligned.
- * Buffers lengths must be multiple of cache line size.
- * Number of Tx & Rx descriptors must be powers of 2.
- */
-#define        MPSC_RXR_ENTRIES        32
-#define        MPSC_RXRE_SIZE          dma_get_cache_alignment()
-#define        MPSC_RXR_SIZE           (MPSC_RXR_ENTRIES * MPSC_RXRE_SIZE)
-#define        MPSC_RXBE_SIZE          dma_get_cache_alignment()
-#define        MPSC_RXB_SIZE           (MPSC_RXR_ENTRIES * MPSC_RXBE_SIZE)
-
-#define        MPSC_TXR_ENTRIES        32
-#define        MPSC_TXRE_SIZE          dma_get_cache_alignment()
-#define        MPSC_TXR_SIZE           (MPSC_TXR_ENTRIES * MPSC_TXRE_SIZE)
-#define        MPSC_TXBE_SIZE          dma_get_cache_alignment()
-#define        MPSC_TXB_SIZE           (MPSC_TXR_ENTRIES * MPSC_TXBE_SIZE)
-
-#define        MPSC_DMA_ALLOC_SIZE     (MPSC_RXR_SIZE + MPSC_RXB_SIZE + MPSC_TXR_SIZE \
-               + MPSC_TXB_SIZE + dma_get_cache_alignment() /* for alignment */)
-
-/* Rx and Tx Ring entry descriptors -- assume entry size is <= cacheline size */
-struct mpsc_rx_desc {
-       u16 bufsize;
-       u16 bytecnt;
-       u32 cmdstat;
-       u32 link;
-       u32 buf_ptr;
-} __attribute((packed));
-
-struct mpsc_tx_desc {
-       u16 bytecnt;
-       u16 shadow;
-       u32 cmdstat;
-       u32 link;
-       u32 buf_ptr;
-} __attribute((packed));
-
-/*
- * Some regs that have the erratum that you can't read them are are shared
- * between the two MPSC controllers.  This struct contains those shared regs.
- */
-struct mpsc_shared_regs {
-       phys_addr_t mpsc_routing_base_p;
-       phys_addr_t sdma_intr_base_p;
-
-       void __iomem *mpsc_routing_base;
-       void __iomem *sdma_intr_base;
-
-       u32 MPSC_MRR_m;
-       u32 MPSC_RCRR_m;
-       u32 MPSC_TCRR_m;
-       u32 SDMA_INTR_CAUSE_m;
-       u32 SDMA_INTR_MASK_m;
-};
-
-/* The main driver data structure */
-struct mpsc_port_info {
-       struct uart_port port;  /* Overlay uart_port structure */
-
-       /* Internal driver state for this ctlr */
-       u8 ready;
-       u8 rcv_data;
-
-       /* Info passed in from platform */
-       u8 mirror_regs;         /* Need to mirror regs? */
-       u8 cache_mgmt;          /* Need manual cache mgmt? */
-       u8 brg_can_tune;        /* BRG has baud tuning? */
-       u32 brg_clk_src;
-       u16 mpsc_max_idle;
-       int default_baud;
-       int default_bits;
-       int default_parity;
-       int default_flow;
-
-       /* Physical addresses of various blocks of registers (from platform) */
-       phys_addr_t mpsc_base_p;
-       phys_addr_t sdma_base_p;
-       phys_addr_t brg_base_p;
-
-       /* Virtual addresses of various blocks of registers (from platform) */
-       void __iomem *mpsc_base;
-       void __iomem *sdma_base;
-       void __iomem *brg_base;
-
-       /* Descriptor ring and buffer allocations */
-       void *dma_region;
-       dma_addr_t dma_region_p;
-
-       dma_addr_t rxr;         /* Rx descriptor ring */
-       dma_addr_t rxr_p;       /* Phys addr of rxr */
-       u8 *rxb;                /* Rx Ring I/O buf */
-       u8 *rxb_p;              /* Phys addr of rxb */
-       u32 rxr_posn;           /* First desc w/ Rx data */
-
-       dma_addr_t txr;         /* Tx descriptor ring */
-       dma_addr_t txr_p;       /* Phys addr of txr */
-       u8 *txb;                /* Tx Ring I/O buf */
-       u8 *txb_p;              /* Phys addr of txb */
-       int txr_head;           /* Where new data goes */
-       int txr_tail;           /* Where sent data comes off */
-       spinlock_t tx_lock;     /* transmit lock */
-
-       /* Mirrored values of regs we can't read (if 'mirror_regs' set) */
-       u32 MPSC_MPCR_m;
-       u32 MPSC_CHR_1_m;
-       u32 MPSC_CHR_2_m;
-       u32 MPSC_CHR_10_m;
-       u32 BRG_BCR_m;
-       struct mpsc_shared_regs *shared_regs;
-};
-
-/* Hooks to platform-specific code */
-int mpsc_platform_register_driver(void);
-void mpsc_platform_unregister_driver(void);
-
-/* Hooks back in to mpsc common to be called by platform-specific code */
-struct mpsc_port_info *mpsc_device_probe(int index);
-struct mpsc_port_info *mpsc_device_remove(int index);
-
-/* Main MPSC Configuration Register Offsets */
-#define        MPSC_MMCRL                      0x0000
-#define        MPSC_MMCRH                      0x0004
-#define        MPSC_MPCR                       0x0008
-#define        MPSC_CHR_1                      0x000c
-#define        MPSC_CHR_2                      0x0010
-#define        MPSC_CHR_3                      0x0014
-#define        MPSC_CHR_4                      0x0018
-#define        MPSC_CHR_5                      0x001c
-#define        MPSC_CHR_6                      0x0020
-#define        MPSC_CHR_7                      0x0024
-#define        MPSC_CHR_8                      0x0028
-#define        MPSC_CHR_9                      0x002c
-#define        MPSC_CHR_10                     0x0030
-#define        MPSC_CHR_11                     0x0034
-
-#define        MPSC_MPCR_FRZ                   (1 << 9)
-#define        MPSC_MPCR_CL_5                  0
-#define        MPSC_MPCR_CL_6                  1
-#define        MPSC_MPCR_CL_7                  2
-#define        MPSC_MPCR_CL_8                  3
-#define        MPSC_MPCR_SBL_1                 0
-#define        MPSC_MPCR_SBL_2                 1
-
-#define        MPSC_CHR_2_TEV                  (1<<1)
-#define        MPSC_CHR_2_TA                   (1<<7)
-#define        MPSC_CHR_2_TTCS                 (1<<9)
-#define        MPSC_CHR_2_REV                  (1<<17)
-#define        MPSC_CHR_2_RA                   (1<<23)
-#define        MPSC_CHR_2_CRD                  (1<<25)
-#define        MPSC_CHR_2_EH                   (1<<31)
-#define        MPSC_CHR_2_PAR_ODD              0
-#define        MPSC_CHR_2_PAR_SPACE            1
-#define        MPSC_CHR_2_PAR_EVEN             2
-#define        MPSC_CHR_2_PAR_MARK             3
-
-/* MPSC Signal Routing */
-#define        MPSC_MRR                        0x0000
-#define        MPSC_RCRR                       0x0004
-#define        MPSC_TCRR                       0x0008
-
-/* Serial DMA Controller Interface Registers */
-#define        SDMA_SDC                        0x0000
-#define        SDMA_SDCM                       0x0008
-#define        SDMA_RX_DESC                    0x0800
-#define        SDMA_RX_BUF_PTR                 0x0808
-#define        SDMA_SCRDP                      0x0810
-#define        SDMA_TX_DESC                    0x0c00
-#define        SDMA_SCTDP                      0x0c10
-#define        SDMA_SFTDP                      0x0c14
-
-#define        SDMA_DESC_CMDSTAT_PE            (1<<0)
-#define        SDMA_DESC_CMDSTAT_CDL           (1<<1)
-#define        SDMA_DESC_CMDSTAT_FR            (1<<3)
-#define        SDMA_DESC_CMDSTAT_OR            (1<<6)
-#define        SDMA_DESC_CMDSTAT_BR            (1<<9)
-#define        SDMA_DESC_CMDSTAT_MI            (1<<10)
-#define        SDMA_DESC_CMDSTAT_A             (1<<11)
-#define        SDMA_DESC_CMDSTAT_AM            (1<<12)
-#define        SDMA_DESC_CMDSTAT_CT            (1<<13)
-#define        SDMA_DESC_CMDSTAT_C             (1<<14)
-#define        SDMA_DESC_CMDSTAT_ES            (1<<15)
-#define        SDMA_DESC_CMDSTAT_L             (1<<16)
-#define        SDMA_DESC_CMDSTAT_F             (1<<17)
-#define        SDMA_DESC_CMDSTAT_P             (1<<18)
-#define        SDMA_DESC_CMDSTAT_EI            (1<<23)
-#define        SDMA_DESC_CMDSTAT_O             (1<<31)
-
-#define SDMA_DESC_DFLT                 (SDMA_DESC_CMDSTAT_O \
-               | SDMA_DESC_CMDSTAT_EI)
-
-#define        SDMA_SDC_RFT                    (1<<0)
-#define        SDMA_SDC_SFM                    (1<<1)
-#define        SDMA_SDC_BLMR                   (1<<6)
-#define        SDMA_SDC_BLMT                   (1<<7)
-#define        SDMA_SDC_POVR                   (1<<8)
-#define        SDMA_SDC_RIFB                   (1<<9)
-
-#define        SDMA_SDCM_ERD                   (1<<7)
-#define        SDMA_SDCM_AR                    (1<<15)
-#define        SDMA_SDCM_STD                   (1<<16)
-#define        SDMA_SDCM_TXD                   (1<<23)
-#define        SDMA_SDCM_AT                    (1<<31)
-
-#define        SDMA_0_CAUSE_RXBUF              (1<<0)
-#define        SDMA_0_CAUSE_RXERR              (1<<1)
-#define        SDMA_0_CAUSE_TXBUF              (1<<2)
-#define        SDMA_0_CAUSE_TXEND              (1<<3)
-#define        SDMA_1_CAUSE_RXBUF              (1<<8)
-#define        SDMA_1_CAUSE_RXERR              (1<<9)
-#define        SDMA_1_CAUSE_TXBUF              (1<<10)
-#define        SDMA_1_CAUSE_TXEND              (1<<11)
-
-#define        SDMA_CAUSE_RX_MASK      (SDMA_0_CAUSE_RXBUF | SDMA_0_CAUSE_RXERR \
-               | SDMA_1_CAUSE_RXBUF | SDMA_1_CAUSE_RXERR)
-#define        SDMA_CAUSE_TX_MASK      (SDMA_0_CAUSE_TXBUF | SDMA_0_CAUSE_TXEND \
-               | SDMA_1_CAUSE_TXBUF | SDMA_1_CAUSE_TXEND)
-
-/* SDMA Interrupt registers */
-#define        SDMA_INTR_CAUSE                 0x0000
-#define        SDMA_INTR_MASK                  0x0080
-
-/* Baud Rate Generator Interface Registers */
-#define        BRG_BCR                         0x0000
-#define        BRG_BTR                         0x0004
-
-/*
- * Define how this driver is known to the outside (we've been assigned a
- * range on the "Low-density serial ports" major).
- */
-#define MPSC_MAJOR                     204
-#define MPSC_MINOR_START               44
-#define        MPSC_DRIVER_NAME                "MPSC"
-#define        MPSC_DEV_NAME                   "ttyMM"
-#define        MPSC_VERSION                    "1.00"
-
-static struct mpsc_port_info mpsc_ports[MPSC_NUM_CTLRS];
-static struct mpsc_shared_regs mpsc_shared_regs;
-static struct uart_driver mpsc_reg;
-
-static void mpsc_start_rx(struct mpsc_port_info *pi);
-static void mpsc_free_ring_mem(struct mpsc_port_info *pi);
-static void mpsc_release_port(struct uart_port *port);
-/*
- ******************************************************************************
- *
- * Baud Rate Generator Routines (BRG)
- *
- ******************************************************************************
- */
-static void mpsc_brg_init(struct mpsc_port_info *pi, u32 clk_src)
-{
-       u32     v;
-
-       v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
-       v = (v & ~(0xf << 18)) | ((clk_src & 0xf) << 18);
-
-       if (pi->brg_can_tune)
-               v &= ~(1 << 25);
-
-       if (pi->mirror_regs)
-               pi->BRG_BCR_m = v;
-       writel(v, pi->brg_base + BRG_BCR);
-
-       writel(readl(pi->brg_base + BRG_BTR) & 0xffff0000,
-               pi->brg_base + BRG_BTR);
-}
-
-static void mpsc_brg_enable(struct mpsc_port_info *pi)
-{
-       u32     v;
-
-       v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
-       v |= (1 << 16);
-
-       if (pi->mirror_regs)
-               pi->BRG_BCR_m = v;
-       writel(v, pi->brg_base + BRG_BCR);
-}
-
-static void mpsc_brg_disable(struct mpsc_port_info *pi)
-{
-       u32     v;
-
-       v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
-       v &= ~(1 << 16);
-
-       if (pi->mirror_regs)
-               pi->BRG_BCR_m = v;
-       writel(v, pi->brg_base + BRG_BCR);
-}
-
-/*
- * To set the baud, we adjust the CDV field in the BRG_BCR reg.
- * From manual: Baud = clk / ((CDV+1)*2) ==> CDV = (clk / (baud*2)) - 1.
- * However, the input clock is divided by 16 in the MPSC b/c of how
- * 'MPSC_MMCRH' was set up so we have to divide the 'clk' used in our
- * calculation by 16 to account for that.  So the real calculation
- * that accounts for the way the mpsc is set up is:
- * CDV = (clk / (baud*2*16)) - 1 ==> CDV = (clk / (baud << 5)) - 1.
- */
-static void mpsc_set_baudrate(struct mpsc_port_info *pi, u32 baud)
-{
-       u32     cdv = (pi->port.uartclk / (baud << 5)) - 1;
-       u32     v;
-
-       mpsc_brg_disable(pi);
-       v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
-       v = (v & 0xffff0000) | (cdv & 0xffff);
-
-       if (pi->mirror_regs)
-               pi->BRG_BCR_m = v;
-       writel(v, pi->brg_base + BRG_BCR);
-       mpsc_brg_enable(pi);
-}
-
-/*
- ******************************************************************************
- *
- * Serial DMA Routines (SDMA)
- *
- ******************************************************************************
- */
-
-static void mpsc_sdma_burstsize(struct mpsc_port_info *pi, u32 burst_size)
-{
-       u32     v;
-
-       pr_debug("mpsc_sdma_burstsize[%d]: burst_size: %d\n",
-                       pi->port.line, burst_size);
-
-       burst_size >>= 3; /* Divide by 8 b/c reg values are 8-byte chunks */
-
-       if (burst_size < 2)
-               v = 0x0;        /* 1 64-bit word */
-       else if (burst_size < 4)
-               v = 0x1;        /* 2 64-bit words */
-       else if (burst_size < 8)
-               v = 0x2;        /* 4 64-bit words */
-       else
-               v = 0x3;        /* 8 64-bit words */
-
-       writel((readl(pi->sdma_base + SDMA_SDC) & (0x3 << 12)) | (v << 12),
-               pi->sdma_base + SDMA_SDC);
-}
-
-static void mpsc_sdma_init(struct mpsc_port_info *pi, u32 burst_size)
-{
-       pr_debug("mpsc_sdma_init[%d]: burst_size: %d\n", pi->port.line,
-               burst_size);
-
-       writel((readl(pi->sdma_base + SDMA_SDC) & 0x3ff) | 0x03f,
-               pi->sdma_base + SDMA_SDC);
-       mpsc_sdma_burstsize(pi, burst_size);
-}
-
-static u32 mpsc_sdma_intr_mask(struct mpsc_port_info *pi, u32 mask)
-{
-       u32     old, v;
-
-       pr_debug("mpsc_sdma_intr_mask[%d]: mask: 0x%x\n", pi->port.line, mask);
-
-       old = v = (pi->mirror_regs) ? pi->shared_regs->SDMA_INTR_MASK_m :
-               readl(pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
-
-       mask &= 0xf;
-       if (pi->port.line)
-               mask <<= 8;
-       v &= ~mask;
-
-       if (pi->mirror_regs)
-               pi->shared_regs->SDMA_INTR_MASK_m = v;
-       writel(v, pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
-
-       if (pi->port.line)
-               old >>= 8;
-       return old & 0xf;
-}
-
-static void mpsc_sdma_intr_unmask(struct mpsc_port_info *pi, u32 mask)
-{
-       u32     v;
-
-       pr_debug("mpsc_sdma_intr_unmask[%d]: mask: 0x%x\n", pi->port.line,mask);
-
-       v = (pi->mirror_regs) ? pi->shared_regs->SDMA_INTR_MASK_m
-               : readl(pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
-
-       mask &= 0xf;
-       if (pi->port.line)
-               mask <<= 8;
-       v |= mask;
-
-       if (pi->mirror_regs)
-               pi->shared_regs->SDMA_INTR_MASK_m = v;
-       writel(v, pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
-}
-
-static void mpsc_sdma_intr_ack(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_sdma_intr_ack[%d]: Acknowledging IRQ\n", pi->port.line);
-
-       if (pi->mirror_regs)
-               pi->shared_regs->SDMA_INTR_CAUSE_m = 0;
-       writeb(0x00, pi->shared_regs->sdma_intr_base + SDMA_INTR_CAUSE
-                       + pi->port.line);
-}
-
-static void mpsc_sdma_set_rx_ring(struct mpsc_port_info *pi,
-               struct mpsc_rx_desc *rxre_p)
-{
-       pr_debug("mpsc_sdma_set_rx_ring[%d]: rxre_p: 0x%x\n",
-               pi->port.line, (u32)rxre_p);
-
-       writel((u32)rxre_p, pi->sdma_base + SDMA_SCRDP);
-}
-
-static void mpsc_sdma_set_tx_ring(struct mpsc_port_info *pi,
-               struct mpsc_tx_desc *txre_p)
-{
-       writel((u32)txre_p, pi->sdma_base + SDMA_SFTDP);
-       writel((u32)txre_p, pi->sdma_base + SDMA_SCTDP);
-}
-
-static void mpsc_sdma_cmd(struct mpsc_port_info *pi, u32 val)
-{
-       u32     v;
-
-       v = readl(pi->sdma_base + SDMA_SDCM);
-       if (val)
-               v |= val;
-       else
-               v = 0;
-       wmb();
-       writel(v, pi->sdma_base + SDMA_SDCM);
-       wmb();
-}
-
-static uint mpsc_sdma_tx_active(struct mpsc_port_info *pi)
-{
-       return readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_TXD;
-}
-
-static void mpsc_sdma_start_tx(struct mpsc_port_info *pi)
-{
-       struct mpsc_tx_desc *txre, *txre_p;
-
-       /* If tx isn't running & there's a desc ready to go, start it */
-       if (!mpsc_sdma_tx_active(pi)) {
-               txre = (struct mpsc_tx_desc *)(pi->txr
-                               + (pi->txr_tail * MPSC_TXRE_SIZE));
-               dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
-                               DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       invalidate_dcache_range((ulong)txre,
-                                       (ulong)txre + MPSC_TXRE_SIZE);
-#endif
-
-               if (be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O) {
-                       txre_p = (struct mpsc_tx_desc *)
-                               (pi->txr_p + (pi->txr_tail * MPSC_TXRE_SIZE));
-
-                       mpsc_sdma_set_tx_ring(pi, txre_p);
-                       mpsc_sdma_cmd(pi, SDMA_SDCM_STD | SDMA_SDCM_TXD);
-               }
-       }
-}
-
-static void mpsc_sdma_stop(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_sdma_stop[%d]: Stopping SDMA\n", pi->port.line);
-
-       /* Abort any SDMA transfers */
-       mpsc_sdma_cmd(pi, 0);
-       mpsc_sdma_cmd(pi, SDMA_SDCM_AR | SDMA_SDCM_AT);
-
-       /* Clear the SDMA current and first TX and RX pointers */
-       mpsc_sdma_set_tx_ring(pi, NULL);
-       mpsc_sdma_set_rx_ring(pi, NULL);
-
-       /* Disable interrupts */
-       mpsc_sdma_intr_mask(pi, 0xf);
-       mpsc_sdma_intr_ack(pi);
-}
-
-/*
- ******************************************************************************
- *
- * Multi-Protocol Serial Controller Routines (MPSC)
- *
- ******************************************************************************
- */
-
-static void mpsc_hw_init(struct mpsc_port_info *pi)
-{
-       u32     v;
-
-       pr_debug("mpsc_hw_init[%d]: Initializing hardware\n", pi->port.line);
-
-       /* Set up clock routing */
-       if (pi->mirror_regs) {
-               v = pi->shared_regs->MPSC_MRR_m;
-               v &= ~0x1c7;
-               pi->shared_regs->MPSC_MRR_m = v;
-               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_MRR);
-
-               v = pi->shared_regs->MPSC_RCRR_m;
-               v = (v & ~0xf0f) | 0x100;
-               pi->shared_regs->MPSC_RCRR_m = v;
-               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_RCRR);
-
-               v = pi->shared_regs->MPSC_TCRR_m;
-               v = (v & ~0xf0f) | 0x100;
-               pi->shared_regs->MPSC_TCRR_m = v;
-               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_TCRR);
-       } else {
-               v = readl(pi->shared_regs->mpsc_routing_base + MPSC_MRR);
-               v &= ~0x1c7;
-               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_MRR);
-
-               v = readl(pi->shared_regs->mpsc_routing_base + MPSC_RCRR);
-               v = (v & ~0xf0f) | 0x100;
-               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_RCRR);
-
-               v = readl(pi->shared_regs->mpsc_routing_base + MPSC_TCRR);
-               v = (v & ~0xf0f) | 0x100;
-               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_TCRR);
-       }
-
-       /* Put MPSC in UART mode & enabel Tx/Rx egines */
-       writel(0x000004c4, pi->mpsc_base + MPSC_MMCRL);
-
-       /* No preamble, 16x divider, low-latency, */
-       writel(0x04400400, pi->mpsc_base + MPSC_MMCRH);
-       mpsc_set_baudrate(pi, pi->default_baud);
-
-       if (pi->mirror_regs) {
-               pi->MPSC_CHR_1_m = 0;
-               pi->MPSC_CHR_2_m = 0;
-       }
-       writel(0, pi->mpsc_base + MPSC_CHR_1);
-       writel(0, pi->mpsc_base + MPSC_CHR_2);
-       writel(pi->mpsc_max_idle, pi->mpsc_base + MPSC_CHR_3);
-       writel(0, pi->mpsc_base + MPSC_CHR_4);
-       writel(0, pi->mpsc_base + MPSC_CHR_5);
-       writel(0, pi->mpsc_base + MPSC_CHR_6);
-       writel(0, pi->mpsc_base + MPSC_CHR_7);
-       writel(0, pi->mpsc_base + MPSC_CHR_8);
-       writel(0, pi->mpsc_base + MPSC_CHR_9);
-       writel(0, pi->mpsc_base + MPSC_CHR_10);
-}
-
-static void mpsc_enter_hunt(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_enter_hunt[%d]: Hunting...\n", pi->port.line);
-
-       if (pi->mirror_regs) {
-               writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_EH,
-                       pi->mpsc_base + MPSC_CHR_2);
-               /* Erratum prevents reading CHR_2 so just delay for a while */
-               udelay(100);
-       } else {
-               writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_EH,
-                               pi->mpsc_base + MPSC_CHR_2);
-
-               while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_EH)
-                       udelay(10);
-       }
-}
-
-static void mpsc_freeze(struct mpsc_port_info *pi)
-{
-       u32     v;
-
-       pr_debug("mpsc_freeze[%d]: Freezing\n", pi->port.line);
-
-       v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
-               readl(pi->mpsc_base + MPSC_MPCR);
-       v |= MPSC_MPCR_FRZ;
-
-       if (pi->mirror_regs)
-               pi->MPSC_MPCR_m = v;
-       writel(v, pi->mpsc_base + MPSC_MPCR);
-}
-
-static void mpsc_unfreeze(struct mpsc_port_info *pi)
-{
-       u32     v;
-
-       v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
-               readl(pi->mpsc_base + MPSC_MPCR);
-       v &= ~MPSC_MPCR_FRZ;
-
-       if (pi->mirror_regs)
-               pi->MPSC_MPCR_m = v;
-       writel(v, pi->mpsc_base + MPSC_MPCR);
-
-       pr_debug("mpsc_unfreeze[%d]: Unfrozen\n", pi->port.line);
-}
-
-static void mpsc_set_char_length(struct mpsc_port_info *pi, u32 len)
-{
-       u32     v;
-
-       pr_debug("mpsc_set_char_length[%d]: char len: %d\n", pi->port.line,len);
-
-       v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
-               readl(pi->mpsc_base + MPSC_MPCR);
-       v = (v & ~(0x3 << 12)) | ((len & 0x3) << 12);
-
-       if (pi->mirror_regs)
-               pi->MPSC_MPCR_m = v;
-       writel(v, pi->mpsc_base + MPSC_MPCR);
-}
-
-static void mpsc_set_stop_bit_length(struct mpsc_port_info *pi, u32 len)
-{
-       u32     v;
-
-       pr_debug("mpsc_set_stop_bit_length[%d]: stop bits: %d\n",
-               pi->port.line, len);
-
-       v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
-               readl(pi->mpsc_base + MPSC_MPCR);
-
-       v = (v & ~(1 << 14)) | ((len & 0x1) << 14);
-
-       if (pi->mirror_regs)
-               pi->MPSC_MPCR_m = v;
-       writel(v, pi->mpsc_base + MPSC_MPCR);
-}
-
-static void mpsc_set_parity(struct mpsc_port_info *pi, u32 p)
-{
-       u32     v;
-
-       pr_debug("mpsc_set_parity[%d]: parity bits: 0x%x\n", pi->port.line, p);
-
-       v = (pi->mirror_regs) ? pi->MPSC_CHR_2_m :
-               readl(pi->mpsc_base + MPSC_CHR_2);
-
-       p &= 0x3;
-       v = (v & ~0xc000c) | (p << 18) | (p << 2);
-
-       if (pi->mirror_regs)
-               pi->MPSC_CHR_2_m = v;
-       writel(v, pi->mpsc_base + MPSC_CHR_2);
-}
-
-/*
- ******************************************************************************
- *
- * Driver Init Routines
- *
- ******************************************************************************
- */
-
-static void mpsc_init_hw(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_init_hw[%d]: Initializing\n", pi->port.line);
-
-       mpsc_brg_init(pi, pi->brg_clk_src);
-       mpsc_brg_enable(pi);
-       mpsc_sdma_init(pi, dma_get_cache_alignment());  /* burst a cacheline */
-       mpsc_sdma_stop(pi);
-       mpsc_hw_init(pi);
-}
-
-static int mpsc_alloc_ring_mem(struct mpsc_port_info *pi)
-{
-       int rc = 0;
-
-       pr_debug("mpsc_alloc_ring_mem[%d]: Allocating ring mem\n",
-               pi->port.line);
-
-       if (!pi->dma_region) {
-               if (!dma_set_mask(pi->port.dev, 0xffffffff)) {
-                       printk(KERN_ERR "MPSC: Inadequate DMA support\n");
-                       rc = -ENXIO;
-               } else if ((pi->dma_region = dma_alloc_attrs(pi->port.dev,
-                                               MPSC_DMA_ALLOC_SIZE,
-                                               &pi->dma_region_p, GFP_KERNEL,
-                                               DMA_ATTR_NON_CONSISTENT))
-                               == NULL) {
-                       printk(KERN_ERR "MPSC: Can't alloc Desc region\n");
-                       rc = -ENOMEM;
-               }
-       }
-
-       return rc;
-}
-
-static void mpsc_free_ring_mem(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_free_ring_mem[%d]: Freeing ring mem\n", pi->port.line);
-
-       if (pi->dma_region) {
-               dma_free_attrs(pi->port.dev, MPSC_DMA_ALLOC_SIZE,
-                               pi->dma_region, pi->dma_region_p,
-                               DMA_ATTR_NON_CONSISTENT);
-               pi->dma_region = NULL;
-               pi->dma_region_p = (dma_addr_t)NULL;
-       }
-}
-
-static void mpsc_init_rings(struct mpsc_port_info *pi)
-{
-       struct mpsc_rx_desc *rxre;
-       struct mpsc_tx_desc *txre;
-       dma_addr_t dp, dp_p;
-       u8 *bp, *bp_p;
-       int i;
-
-       pr_debug("mpsc_init_rings[%d]: Initializing rings\n", pi->port.line);
-
-       BUG_ON(pi->dma_region == NULL);
-
-       memset(pi->dma_region, 0, MPSC_DMA_ALLOC_SIZE);
-
-       /*
-        * Descriptors & buffers are multiples of cacheline size and must be
-        * cacheline aligned.
-        */
-       dp = ALIGN((u32)pi->dma_region, dma_get_cache_alignment());
-       dp_p = ALIGN((u32)pi->dma_region_p, dma_get_cache_alignment());
-
-       /*
-        * Partition dma region into rx ring descriptor, rx buffers,
-        * tx ring descriptors, and tx buffers.
-        */
-       pi->rxr = dp;
-       pi->rxr_p = dp_p;
-       dp += MPSC_RXR_SIZE;
-       dp_p += MPSC_RXR_SIZE;
-
-       pi->rxb = (u8 *)dp;
-       pi->rxb_p = (u8 *)dp_p;
-       dp += MPSC_RXB_SIZE;
-       dp_p += MPSC_RXB_SIZE;
-
-       pi->rxr_posn = 0;
-
-       pi->txr = dp;
-       pi->txr_p = dp_p;
-       dp += MPSC_TXR_SIZE;
-       dp_p += MPSC_TXR_SIZE;
-
-       pi->txb = (u8 *)dp;
-       pi->txb_p = (u8 *)dp_p;
-
-       pi->txr_head = 0;
-       pi->txr_tail = 0;
-
-       /* Init rx ring descriptors */
-       dp = pi->rxr;
-       dp_p = pi->rxr_p;
-       bp = pi->rxb;
-       bp_p = pi->rxb_p;
-
-       for (i = 0; i < MPSC_RXR_ENTRIES; i++) {
-               rxre = (struct mpsc_rx_desc *)dp;
-
-               rxre->bufsize = cpu_to_be16(MPSC_RXBE_SIZE);
-               rxre->bytecnt = cpu_to_be16(0);
-               rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O
-                               | SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F
-                               | SDMA_DESC_CMDSTAT_L);
-               rxre->link = cpu_to_be32(dp_p + MPSC_RXRE_SIZE);
-               rxre->buf_ptr = cpu_to_be32(bp_p);
-
-               dp += MPSC_RXRE_SIZE;
-               dp_p += MPSC_RXRE_SIZE;
-               bp += MPSC_RXBE_SIZE;
-               bp_p += MPSC_RXBE_SIZE;
-       }
-       rxre->link = cpu_to_be32(pi->rxr_p);    /* Wrap last back to first */
-
-       /* Init tx ring descriptors */
-       dp = pi->txr;
-       dp_p = pi->txr_p;
-       bp = pi->txb;
-       bp_p = pi->txb_p;
-
-       for (i = 0; i < MPSC_TXR_ENTRIES; i++) {
-               txre = (struct mpsc_tx_desc *)dp;
-
-               txre->link = cpu_to_be32(dp_p + MPSC_TXRE_SIZE);
-               txre->buf_ptr = cpu_to_be32(bp_p);
-
-               dp += MPSC_TXRE_SIZE;
-               dp_p += MPSC_TXRE_SIZE;
-               bp += MPSC_TXBE_SIZE;
-               bp_p += MPSC_TXBE_SIZE;
-       }
-       txre->link = cpu_to_be32(pi->txr_p);    /* Wrap last back to first */
-
-       dma_cache_sync(pi->port.dev, (void *)pi->dma_region,
-                       MPSC_DMA_ALLOC_SIZE, DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       flush_dcache_range((ulong)pi->dma_region,
-                                       (ulong)pi->dma_region
-                                       + MPSC_DMA_ALLOC_SIZE);
-#endif
-
-       return;
-}
-
-static void mpsc_uninit_rings(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_uninit_rings[%d]: Uninitializing rings\n",pi->port.line);
-
-       BUG_ON(pi->dma_region == NULL);
-
-       pi->rxr = 0;
-       pi->rxr_p = 0;
-       pi->rxb = NULL;
-       pi->rxb_p = NULL;
-       pi->rxr_posn = 0;
-
-       pi->txr = 0;
-       pi->txr_p = 0;
-       pi->txb = NULL;
-       pi->txb_p = NULL;
-       pi->txr_head = 0;
-       pi->txr_tail = 0;
-}
-
-static int mpsc_make_ready(struct mpsc_port_info *pi)
-{
-       int rc;
-
-       pr_debug("mpsc_make_ready[%d]: Making cltr ready\n", pi->port.line);
-
-       if (!pi->ready) {
-               mpsc_init_hw(pi);
-               rc = mpsc_alloc_ring_mem(pi);
-               if (rc)
-                       return rc;
-               mpsc_init_rings(pi);
-               pi->ready = 1;
-       }
-
-       return 0;
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-static int serial_polled;
-#endif
-
-/*
- ******************************************************************************
- *
- * Interrupt Handling Routines
- *
- ******************************************************************************
- */
-
-static int mpsc_rx_intr(struct mpsc_port_info *pi, unsigned long *flags)
-{
-       struct mpsc_rx_desc *rxre;
-       struct tty_port *port = &pi->port.state->port;
-       u32     cmdstat, bytes_in, i;
-       int     rc = 0;
-       u8      *bp;
-       char    flag = TTY_NORMAL;
-
-       pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line);
-
-       rxre = (struct mpsc_rx_desc *)(pi->rxr + (pi->rxr_posn*MPSC_RXRE_SIZE));
-
-       dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
-                       DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-               invalidate_dcache_range((ulong)rxre,
-                               (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-
-       /*
-        * Loop through Rx descriptors handling ones that have been completed.
-        */
-       while (!((cmdstat = be32_to_cpu(rxre->cmdstat))
-                               & SDMA_DESC_CMDSTAT_O)) {
-               bytes_in = be16_to_cpu(rxre->bytecnt);
-#ifdef CONFIG_CONSOLE_POLL
-               if (unlikely(serial_polled)) {
-                       serial_polled = 0;
-                       return 0;
-               }
-#endif
-               /* Following use of tty struct directly is deprecated */
-               if (tty_buffer_request_room(port, bytes_in) < bytes_in) {
-                       if (port->low_latency) {
-                               spin_unlock_irqrestore(&pi->port.lock, *flags);
-                               tty_flip_buffer_push(port);
-                               spin_lock_irqsave(&pi->port.lock, *flags);
-                       }
-                       /*
-                        * If this failed then we will throw away the bytes
-                        * but must do so to clear interrupts.
-                        */
-               }
-
-               bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE);
-               dma_cache_sync(pi->port.dev, (void *)bp, MPSC_RXBE_SIZE,
-                               DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       invalidate_dcache_range((ulong)bp,
-                                       (ulong)bp + MPSC_RXBE_SIZE);
-#endif
-
-               /*
-                * Other than for parity error, the manual provides little
-                * info on what data will be in a frame flagged by any of
-                * these errors.  For parity error, it is the last byte in
-                * the buffer that had the error.  As for the rest, I guess
-                * we'll assume there is no data in the buffer.
-                * If there is...it gets lost.
-                */
-               if (unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR
-                                               | SDMA_DESC_CMDSTAT_FR
-                                               | SDMA_DESC_CMDSTAT_OR))) {
-
-                       pi->port.icount.rx++;
-
-                       if (cmdstat & SDMA_DESC_CMDSTAT_BR) {   /* Break */
-                               pi->port.icount.brk++;
-
-                               if (uart_handle_break(&pi->port))
-                                       goto next_frame;
-                       } else if (cmdstat & SDMA_DESC_CMDSTAT_FR) {
-                               pi->port.icount.frame++;
-                       } else if (cmdstat & SDMA_DESC_CMDSTAT_OR) {
-                               pi->port.icount.overrun++;
-                       }
-
-                       cmdstat &= pi->port.read_status_mask;
-
-                       if (cmdstat & SDMA_DESC_CMDSTAT_BR)
-                               flag = TTY_BREAK;
-                       else if (cmdstat & SDMA_DESC_CMDSTAT_FR)
-                               flag = TTY_FRAME;
-                       else if (cmdstat & SDMA_DESC_CMDSTAT_OR)
-                               flag = TTY_OVERRUN;
-                       else if (cmdstat & SDMA_DESC_CMDSTAT_PE)
-                               flag = TTY_PARITY;
-               }
-
-               if (uart_handle_sysrq_char(&pi->port, *bp)) {
-                       bp++;
-                       bytes_in--;
-#ifdef CONFIG_CONSOLE_POLL
-                       if (unlikely(serial_polled)) {
-                               serial_polled = 0;
-                               return 0;
-                       }
-#endif
-                       goto next_frame;
-               }
-
-               if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR
-                                               | SDMA_DESC_CMDSTAT_FR
-                                               | SDMA_DESC_CMDSTAT_OR)))
-                               && !(cmdstat & pi->port.ignore_status_mask)) {
-                       tty_insert_flip_char(port, *bp, flag);
-               } else {
-                       for (i=0; i<bytes_in; i++)
-                               tty_insert_flip_char(port, *bp++, TTY_NORMAL);
-
-                       pi->port.icount.rx += bytes_in;
-               }
-
-next_frame:
-               rxre->bytecnt = cpu_to_be16(0);
-               wmb();
-               rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O
-                               | SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F
-                               | SDMA_DESC_CMDSTAT_L);
-               wmb();
-               dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
-                               DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       flush_dcache_range((ulong)rxre,
-                                       (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-
-               /* Advance to next descriptor */
-               pi->rxr_posn = (pi->rxr_posn + 1) & (MPSC_RXR_ENTRIES - 1);
-               rxre = (struct mpsc_rx_desc *)
-                       (pi->rxr + (pi->rxr_posn * MPSC_RXRE_SIZE));
-               dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
-                               DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       invalidate_dcache_range((ulong)rxre,
-                                       (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-               rc = 1;
-       }
-
-       /* Restart rx engine, if its stopped */
-       if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0)
-               mpsc_start_rx(pi);
-
-       spin_unlock_irqrestore(&pi->port.lock, *flags);
-       tty_flip_buffer_push(port);
-       spin_lock_irqsave(&pi->port.lock, *flags);
-       return rc;
-}
-
-static void mpsc_setup_tx_desc(struct mpsc_port_info *pi, u32 count, u32 intr)
-{
-       struct mpsc_tx_desc *txre;
-
-       txre = (struct mpsc_tx_desc *)(pi->txr
-                       + (pi->txr_head * MPSC_TXRE_SIZE));
-
-       txre->bytecnt = cpu_to_be16(count);
-       txre->shadow = txre->bytecnt;
-       wmb();                  /* ensure cmdstat is last field updated */
-       txre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O | SDMA_DESC_CMDSTAT_F
-                       | SDMA_DESC_CMDSTAT_L
-                       | ((intr) ? SDMA_DESC_CMDSTAT_EI : 0));
-       wmb();
-       dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
-                       DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-               flush_dcache_range((ulong)txre,
-                               (ulong)txre + MPSC_TXRE_SIZE);
-#endif
-}
-
-static void mpsc_copy_tx_data(struct mpsc_port_info *pi)
-{
-       struct circ_buf *xmit = &pi->port.state->xmit;
-       u8 *bp;
-       u32 i;
-
-       /* Make sure the desc ring isn't full */
-       while (CIRC_CNT(pi->txr_head, pi->txr_tail, MPSC_TXR_ENTRIES)
-                       < (MPSC_TXR_ENTRIES - 1)) {
-               if (pi->port.x_char) {
-                       /*
-                        * Ideally, we should use the TCS field in
-                        * CHR_1 to put the x_char out immediately but
-                        * errata prevents us from being able to read
-                        * CHR_2 to know that its safe to write to
-                        * CHR_1.  Instead, just put it in-band with
-                        * all the other Tx data.
-                        */
-                       bp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);
-                       *bp = pi->port.x_char;
-                       pi->port.x_char = 0;
-                       i = 1;
-               } else if (!uart_circ_empty(xmit)
-                               && !uart_tx_stopped(&pi->port)) {
-                       i = min((u32)MPSC_TXBE_SIZE,
-                               (u32)uart_circ_chars_pending(xmit));
-                       i = min(i, (u32)CIRC_CNT_TO_END(xmit->head, xmit->tail,
-                               UART_XMIT_SIZE));
-                       bp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);
-                       memcpy(bp, &xmit->buf[xmit->tail], i);
-                       xmit->tail = (xmit->tail + i) & (UART_XMIT_SIZE - 1);
-
-                       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-                               uart_write_wakeup(&pi->port);
-               } else { /* All tx data copied into ring bufs */
-                       return;
-               }
-
-               dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE,
-                               DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       flush_dcache_range((ulong)bp,
-                                       (ulong)bp + MPSC_TXBE_SIZE);
-#endif
-               mpsc_setup_tx_desc(pi, i, 1);
-
-               /* Advance to next descriptor */
-               pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1);
-       }
-}
-
-static int mpsc_tx_intr(struct mpsc_port_info *pi)
-{
-       struct mpsc_tx_desc *txre;
-       int rc = 0;
-       unsigned long iflags;
-
-       spin_lock_irqsave(&pi->tx_lock, iflags);
-
-       if (!mpsc_sdma_tx_active(pi)) {
-               txre = (struct mpsc_tx_desc *)(pi->txr
-                               + (pi->txr_tail * MPSC_TXRE_SIZE));
-
-               dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
-                               DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       invalidate_dcache_range((ulong)txre,
-                                       (ulong)txre + MPSC_TXRE_SIZE);
-#endif
-
-               while (!(be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O)) {
-                       rc = 1;
-                       pi->port.icount.tx += be16_to_cpu(txre->bytecnt);
-                       pi->txr_tail = (pi->txr_tail+1) & (MPSC_TXR_ENTRIES-1);
-
-                       /* If no more data to tx, fall out of loop */
-                       if (pi->txr_head == pi->txr_tail)
-                               break;
-
-                       txre = (struct mpsc_tx_desc *)(pi->txr
-                                       + (pi->txr_tail * MPSC_TXRE_SIZE));
-                       dma_cache_sync(pi->port.dev, (void *)txre,
-                                       MPSC_TXRE_SIZE, DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-                       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                               invalidate_dcache_range((ulong)txre,
-                                               (ulong)txre + MPSC_TXRE_SIZE);
-#endif
-               }
-
-               mpsc_copy_tx_data(pi);
-               mpsc_sdma_start_tx(pi); /* start next desc if ready */
-       }
-
-       spin_unlock_irqrestore(&pi->tx_lock, iflags);
-       return rc;
-}
-
-/*
- * This is the driver's interrupt handler.  To avoid a race, we first clear
- * the interrupt, then handle any completed Rx/Tx descriptors.  When done
- * handling those descriptors, we restart the Rx/Tx engines if they're stopped.
- */
-static irqreturn_t mpsc_sdma_intr(int irq, void *dev_id)
-{
-       struct mpsc_port_info *pi = dev_id;
-       ulong iflags;
-       int rc = IRQ_NONE;
-
-       pr_debug("mpsc_sdma_intr[%d]: SDMA Interrupt Received\n",pi->port.line);
-
-       spin_lock_irqsave(&pi->port.lock, iflags);
-       mpsc_sdma_intr_ack(pi);
-       if (mpsc_rx_intr(pi, &iflags))
-               rc = IRQ_HANDLED;
-       if (mpsc_tx_intr(pi))
-               rc = IRQ_HANDLED;
-       spin_unlock_irqrestore(&pi->port.lock, iflags);
-
-       pr_debug("mpsc_sdma_intr[%d]: SDMA Interrupt Handled\n", pi->port.line);
-       return rc;
-}
-
-/*
- ******************************************************************************
- *
- * serial_core.c Interface routines
- *
- ******************************************************************************
- */
-static uint mpsc_tx_empty(struct uart_port *port)
-{
-       struct mpsc_port_info *pi =
-               container_of(port, struct mpsc_port_info, port);
-       ulong iflags;
-       uint rc;
-
-       spin_lock_irqsave(&pi->port.lock, iflags);
-       rc = mpsc_sdma_tx_active(pi) ? 0 : TIOCSER_TEMT;
-       spin_unlock_irqrestore(&pi->port.lock, iflags);
-
-       return rc;
-}
-
-static void mpsc_set_mctrl(struct uart_port *port, uint mctrl)
-{
-       /* Have no way to set modem control lines AFAICT */
-}
-
-static uint mpsc_get_mctrl(struct uart_port *port)
-{
-       struct mpsc_port_info *pi =
-               container_of(port, struct mpsc_port_info, port);
-       u32 mflags, status;
-
-       status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m
-               : readl(pi->mpsc_base + MPSC_CHR_10);
-
-       mflags = 0;
-       if (status & 0x1)
-               mflags |= TIOCM_CTS;
-       if (status & 0x2)
-               mflags |= TIOCM_CAR;
-
-       return mflags | TIOCM_DSR;      /* No way to tell if DSR asserted */
-}
-
-static void mpsc_stop_tx(struct uart_port *port)
-{
-       struct mpsc_port_info *pi =
-               container_of(port, struct mpsc_port_info, port);
-
-       pr_debug("mpsc_stop_tx[%d]\n", port->line);
-
-       mpsc_freeze(pi);
-}
-
-static void mpsc_start_tx(struct uart_port *port)
-{
-       struct mpsc_port_info *pi =
-               container_of(port, struct mpsc_port_info, port);
-       unsigned long iflags;
-
-       spin_lock_irqsave(&pi->tx_lock, iflags);
-
-       mpsc_unfreeze(pi);
-       mpsc_copy_tx_data(pi);
-       mpsc_sdma_start_tx(pi);
-
-       spin_unlock_irqrestore(&pi->tx_lock, iflags);
-
-       pr_debug("mpsc_start_tx[%d]\n", port->line);
-}
-
-static void mpsc_start_rx(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_start_rx[%d]: Starting...\n", pi->port.line);
-
-       if (pi->rcv_data) {
-               mpsc_enter_hunt(pi);
-               mpsc_sdma_cmd(pi, SDMA_SDCM_ERD);
-       }
-}
-
-static void mpsc_stop_rx(struct uart_port *port)
-{
-       struct mpsc_port_info *pi =
-               container_of(port, struct mpsc_port_info, port);
-
-       pr_debug("mpsc_stop_rx[%d]: Stopping...\n", port->line);
-
-       if (pi->mirror_regs) {
-               writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_RA,
-                               pi->mpsc_base + MPSC_CHR_2);
-               /* Erratum prevents reading CHR_2 so just delay for a while */
-               udelay(100);
-       } else {
-               writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_RA,
-                               pi->mpsc_base + MPSC_CHR_2);
-
-               while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_RA)
-                       udelay(10);
-       }
-
-       mpsc_sdma_cmd(pi, SDMA_SDCM_AR);
-}
-
-static void mpsc_break_ctl(struct uart_port *port, int ctl)
-{
-       struct mpsc_port_info *pi =
-               container_of(port, struct mpsc_port_info, port);
-       ulong   flags;
-       u32     v;
-
-       v = ctl ? 0x00ff0000 : 0;
-
-       spin_lock_irqsave(&pi->port.lock, flags);
-       if (pi->mirror_regs)
-               pi->MPSC_CHR_1_m = v;
-       writel(v, pi->mpsc_base + MPSC_CHR_1);
-       spin_unlock_irqrestore(&pi->port.lock, flags);
-}
-
-static int mpsc_startup(struct uart_port *port)
-{
-       struct mpsc_port_info *pi =
-               container_of(port, struct mpsc_port_info, port);
-       u32 flag = 0;
-       int rc;
-
-       pr_debug("mpsc_startup[%d]: Starting up MPSC, irq: %d\n",
-               port->line, pi->port.irq);
-
-       if ((rc = mpsc_make_ready(pi)) == 0) {
-               /* Setup IRQ handler */
-               mpsc_sdma_intr_ack(pi);
-
-               /* If irq's are shared, need to set flag */
-               if (mpsc_ports[0].port.irq == mpsc_ports[1].port.irq)
-                       flag = IRQF_SHARED;
-
-               if (request_irq(pi->port.irq, mpsc_sdma_intr, flag,
-                                       "mpsc-sdma", pi))
-                       printk(KERN_ERR "MPSC: Can't get SDMA IRQ %d\n",
-                                       pi->port.irq);
-
-               mpsc_sdma_intr_unmask(pi, 0xf);
-               mpsc_sdma_set_rx_ring(pi, (struct mpsc_rx_desc *)(pi->rxr_p
-                                       + (pi->rxr_posn * MPSC_RXRE_SIZE)));
-       }
-
-       return rc;
-}
-
-static void mpsc_shutdown(struct uart_port *port)
-{
-       struct mpsc_port_info *pi =
-               container_of(port, struct mpsc_port_info, port);
-
-       pr_debug("mpsc_shutdown[%d]: Shutting down MPSC\n", port->line);
-
-       mpsc_sdma_stop(pi);
-       free_irq(pi->port.irq, pi);
-}
-
-static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
-                struct ktermios *old)
-{
-       struct mpsc_port_info *pi =
-               container_of(port, struct mpsc_port_info, port);
-       u32 baud;
-       ulong flags;
-       u32 chr_bits, stop_bits, par;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               chr_bits = MPSC_MPCR_CL_5;
-               break;
-       case CS6:
-               chr_bits = MPSC_MPCR_CL_6;
-               break;
-       case CS7:
-               chr_bits = MPSC_MPCR_CL_7;
-               break;
-       case CS8:
-       default:
-               chr_bits = MPSC_MPCR_CL_8;
-               break;
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               stop_bits = MPSC_MPCR_SBL_2;
-       else
-               stop_bits = MPSC_MPCR_SBL_1;
-
-       par = MPSC_CHR_2_PAR_EVEN;
-       if (termios->c_cflag & PARENB)
-               if (termios->c_cflag & PARODD)
-                       par = MPSC_CHR_2_PAR_ODD;
-#ifdef CMSPAR
-               if (termios->c_cflag & CMSPAR) {
-                       if (termios->c_cflag & PARODD)
-                               par = MPSC_CHR_2_PAR_MARK;
-                       else
-                               par = MPSC_CHR_2_PAR_SPACE;
-               }
-#endif
-
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk);
-
-       spin_lock_irqsave(&pi->port.lock, flags);
-
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       mpsc_set_char_length(pi, chr_bits);
-       mpsc_set_stop_bit_length(pi, stop_bits);
-       mpsc_set_parity(pi, par);
-       mpsc_set_baudrate(pi, baud);
-
-       /* Characters/events to read */
-       pi->port.read_status_mask = SDMA_DESC_CMDSTAT_OR;
-
-       if (termios->c_iflag & INPCK)
-               pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_PE
-                       | SDMA_DESC_CMDSTAT_FR;
-
-       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
-               pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_BR;
-
-       /* Characters/events to ignore */
-       pi->port.ignore_status_mask = 0;
-
-       if (termios->c_iflag & IGNPAR)
-               pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_PE
-                       | SDMA_DESC_CMDSTAT_FR;
-
-       if (termios->c_iflag & IGNBRK) {
-               pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_BR;
-
-               if (termios->c_iflag & IGNPAR)
-                       pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_OR;
-       }
-
-       if ((termios->c_cflag & CREAD)) {
-               if (!pi->rcv_data) {
-                       pi->rcv_data = 1;
-                       mpsc_start_rx(pi);
-               }
-       } else if (pi->rcv_data) {
-               mpsc_stop_rx(port);
-               pi->rcv_data = 0;
-       }
-
-       spin_unlock_irqrestore(&pi->port.lock, flags);
-}
-
-static const char *mpsc_type(struct uart_port *port)
-{
-       pr_debug("mpsc_type[%d]: port type: %s\n", port->line,MPSC_DRIVER_NAME);
-       return MPSC_DRIVER_NAME;
-}
-
-static int mpsc_request_port(struct uart_port *port)
-{
-       /* Should make chip/platform specific call */
-       return 0;
-}
-
-static void mpsc_release_port(struct uart_port *port)
-{
-       struct mpsc_port_info *pi =
-               container_of(port, struct mpsc_port_info, port);
-
-       if (pi->ready) {
-               mpsc_uninit_rings(pi);
-               mpsc_free_ring_mem(pi);
-               pi->ready = 0;
-       }
-}
-
-static void mpsc_config_port(struct uart_port *port, int flags)
-{
-}
-
-static int mpsc_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       struct mpsc_port_info *pi =
-               container_of(port, struct mpsc_port_info, port);
-       int rc = 0;
-
-       pr_debug("mpsc_verify_port[%d]: Verifying port data\n", pi->port.line);
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPSC)
-               rc = -EINVAL;
-       else if (pi->port.irq != ser->irq)
-               rc = -EINVAL;
-       else if (ser->io_type != SERIAL_IO_MEM)
-               rc = -EINVAL;
-       else if (pi->port.uartclk / 16 != ser->baud_base) /* Not sure */
-               rc = -EINVAL;
-       else if ((void *)pi->port.mapbase != ser->iomem_base)
-               rc = -EINVAL;
-       else if (pi->port.iobase != ser->port)
-               rc = -EINVAL;
-       else if (ser->hub6 != 0)
-               rc = -EINVAL;
-
-       return rc;
-}
-#ifdef CONFIG_CONSOLE_POLL
-/* Serial polling routines for writing and reading from the uart while
- * in an interrupt or debug context.
- */
-
-static char poll_buf[2048];
-static int poll_ptr;
-static int poll_cnt;
-static void mpsc_put_poll_char(struct uart_port *port,
-                                                          unsigned char c);
-
-static int mpsc_get_poll_char(struct uart_port *port)
-{
-       struct mpsc_port_info *pi =
-               container_of(port, struct mpsc_port_info, port);
-       struct mpsc_rx_desc *rxre;
-       u32     cmdstat, bytes_in, i;
-       u8      *bp;
-
-       if (!serial_polled)
-               serial_polled = 1;
-
-       pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line);
-
-       if (poll_cnt) {
-               poll_cnt--;
-               return poll_buf[poll_ptr++];
-       }
-       poll_ptr = 0;
-       poll_cnt = 0;
-
-       while (poll_cnt == 0) {
-               rxre = (struct mpsc_rx_desc *)(pi->rxr +
-                      (pi->rxr_posn*MPSC_RXRE_SIZE));
-               dma_cache_sync(pi->port.dev, (void *)rxre,
-                              MPSC_RXRE_SIZE, DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       invalidate_dcache_range((ulong)rxre,
-                       (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-               /*
-                * Loop through Rx descriptors handling ones that have
-                * been completed.
-                */
-               while (poll_cnt == 0 &&
-                      !((cmdstat = be32_to_cpu(rxre->cmdstat)) &
-                        SDMA_DESC_CMDSTAT_O)){
-                       bytes_in = be16_to_cpu(rxre->bytecnt);
-                       bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE);
-                       dma_cache_sync(pi->port.dev, (void *) bp,
-                                      MPSC_RXBE_SIZE, DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-                       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                               invalidate_dcache_range((ulong)bp,
-                                       (ulong)bp + MPSC_RXBE_SIZE);
-#endif
-                       if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR |
-                        SDMA_DESC_CMDSTAT_FR | SDMA_DESC_CMDSTAT_OR))) &&
-                               !(cmdstat & pi->port.ignore_status_mask)) {
-                               poll_buf[poll_cnt] = *bp;
-                               poll_cnt++;
-                       } else {
-                               for (i = 0; i < bytes_in; i++) {
-                                       poll_buf[poll_cnt] = *bp++;
-                                       poll_cnt++;
-                               }
-                               pi->port.icount.rx += bytes_in;
-                       }
-                       rxre->bytecnt = cpu_to_be16(0);
-                       wmb();
-                       rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O |
-                                                   SDMA_DESC_CMDSTAT_EI |
-                                                   SDMA_DESC_CMDSTAT_F |
-                                                   SDMA_DESC_CMDSTAT_L);
-                       wmb();
-                       dma_cache_sync(pi->port.dev, (void *)rxre,
-                                      MPSC_RXRE_SIZE, DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-                       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                               flush_dcache_range((ulong)rxre,
-                                          (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-
-                       /* Advance to next descriptor */
-                       pi->rxr_posn = (pi->rxr_posn + 1) &
-                               (MPSC_RXR_ENTRIES - 1);
-                       rxre = (struct mpsc_rx_desc *)(pi->rxr +
-                                      (pi->rxr_posn * MPSC_RXRE_SIZE));
-                       dma_cache_sync(pi->port.dev, (void *)rxre,
-                                      MPSC_RXRE_SIZE, DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-                       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                               invalidate_dcache_range((ulong)rxre,
-                                               (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-               }
-
-               /* Restart rx engine, if its stopped */
-               if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0)
-                       mpsc_start_rx(pi);
-       }
-       if (poll_cnt) {
-               poll_cnt--;
-               return poll_buf[poll_ptr++];
-       }
-
-       return 0;
-}
-
-
-static void mpsc_put_poll_char(struct uart_port *port,
-                        unsigned char c)
-{
-       struct mpsc_port_info *pi =
-               container_of(port, struct mpsc_port_info, port);
-       u32 data;
-
-       data = readl(pi->mpsc_base + MPSC_MPCR);
-       writeb(c, pi->mpsc_base + MPSC_CHR_1);
-       mb();
-       data = readl(pi->mpsc_base + MPSC_CHR_2);
-       data |= MPSC_CHR_2_TTCS;
-       writel(data, pi->mpsc_base + MPSC_CHR_2);
-       mb();
-
-       while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_TTCS);
-}
-#endif
-
-static const struct uart_ops mpsc_pops = {
-       .tx_empty       = mpsc_tx_empty,
-       .set_mctrl      = mpsc_set_mctrl,
-       .get_mctrl      = mpsc_get_mctrl,
-       .stop_tx        = mpsc_stop_tx,
-       .start_tx       = mpsc_start_tx,
-       .stop_rx        = mpsc_stop_rx,
-       .break_ctl      = mpsc_break_ctl,
-       .startup        = mpsc_startup,
-       .shutdown       = mpsc_shutdown,
-       .set_termios    = mpsc_set_termios,
-       .type           = mpsc_type,
-       .release_port   = mpsc_release_port,
-       .request_port   = mpsc_request_port,
-       .config_port    = mpsc_config_port,
-       .verify_port    = mpsc_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char = mpsc_get_poll_char,
-       .poll_put_char = mpsc_put_poll_char,
-#endif
-};
-
-/*
- ******************************************************************************
- *
- * Console Interface Routines
- *
- ******************************************************************************
- */
-
-#ifdef CONFIG_SERIAL_MPSC_CONSOLE
-static void mpsc_console_write(struct console *co, const char *s, uint count)
-{
-       struct mpsc_port_info *pi = &mpsc_ports[co->index];
-       u8 *bp, *dp, add_cr = 0;
-       int i;
-       unsigned long iflags;
-
-       spin_lock_irqsave(&pi->tx_lock, iflags);
-
-       while (pi->txr_head != pi->txr_tail) {
-               while (mpsc_sdma_tx_active(pi))
-                       udelay(100);
-               mpsc_sdma_intr_ack(pi);
-               mpsc_tx_intr(pi);
-       }
-
-       while (mpsc_sdma_tx_active(pi))
-               udelay(100);
-
-       while (count > 0) {
-               bp = dp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);
-
-               for (i = 0; i < MPSC_TXBE_SIZE; i++) {
-                       if (count == 0)
-                               break;
-
-                       if (add_cr) {
-                               *(dp++) = '\r';
-                               add_cr = 0;
-                       } else {
-                               *(dp++) = *s;
-
-                               if (*(s++) == '\n') { /* add '\r' after '\n' */
-                                       add_cr = 1;
-                                       count++;
-                               }
-                       }
-
-                       count--;
-               }
-
-               dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE,
-                               DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       flush_dcache_range((ulong)bp,
-                                       (ulong)bp + MPSC_TXBE_SIZE);
-#endif
-               mpsc_setup_tx_desc(pi, i, 0);
-               pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1);
-               mpsc_sdma_start_tx(pi);
-
-               while (mpsc_sdma_tx_active(pi))
-                       udelay(100);
-
-               pi->txr_tail = (pi->txr_tail + 1) & (MPSC_TXR_ENTRIES - 1);
-       }
-
-       spin_unlock_irqrestore(&pi->tx_lock, iflags);
-}
-
-static int __init mpsc_console_setup(struct console *co, char *options)
-{
-       struct mpsc_port_info *pi;
-       int baud, bits, parity, flow;
-
-       pr_debug("mpsc_console_setup[%d]: options: %s\n", co->index, options);
-
-       if (co->index >= MPSC_NUM_CTLRS)
-               co->index = 0;
-
-       pi = &mpsc_ports[co->index];
-
-       baud = pi->default_baud;
-       bits = pi->default_bits;
-       parity = pi->default_parity;
-       flow = pi->default_flow;
-
-       if (!pi->port.ops)
-               return -ENODEV;
-
-       spin_lock_init(&pi->port.lock); /* Temporary fix--copied from 8250.c */
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(&pi->port, co, baud, parity, bits, flow);
-}
-
-static struct console mpsc_console = {
-       .name   = MPSC_DEV_NAME,
-       .write  = mpsc_console_write,
-       .device = uart_console_device,
-       .setup  = mpsc_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1,
-       .data   = &mpsc_reg,
-};
-
-static int __init mpsc_late_console_init(void)
-{
-       pr_debug("mpsc_late_console_init: Enter\n");
-
-       if (!(mpsc_console.flags & CON_ENABLED))
-               register_console(&mpsc_console);
-       return 0;
-}
-
-late_initcall(mpsc_late_console_init);
-
-#define MPSC_CONSOLE   &mpsc_console
-#else
-#define MPSC_CONSOLE   NULL
-#endif
-/*
- ******************************************************************************
- *
- * Dummy Platform Driver to extract & map shared register regions
- *
- ******************************************************************************
- */
-static void mpsc_resource_err(char *s)
-{
-       printk(KERN_WARNING "MPSC: Platform device resource error in %s\n", s);
-}
-
-static int mpsc_shared_map_regs(struct platform_device *pd)
-{
-       struct resource *r;
-
-       if ((r = platform_get_resource(pd, IORESOURCE_MEM,
-                                       MPSC_ROUTING_BASE_ORDER))
-                       && request_mem_region(r->start,
-                               MPSC_ROUTING_REG_BLOCK_SIZE,
-                               "mpsc_routing_regs")) {
-               mpsc_shared_regs.mpsc_routing_base = ioremap(r->start,
-                               MPSC_ROUTING_REG_BLOCK_SIZE);
-               mpsc_shared_regs.mpsc_routing_base_p = r->start;
-       } else {
-               mpsc_resource_err("MPSC routing base");
-               return -ENOMEM;
-       }
-
-       if ((r = platform_get_resource(pd, IORESOURCE_MEM,
-                                       MPSC_SDMA_INTR_BASE_ORDER))
-                       && request_mem_region(r->start,
-                               MPSC_SDMA_INTR_REG_BLOCK_SIZE,
-                               "sdma_intr_regs")) {
-               mpsc_shared_regs.sdma_intr_base = ioremap(r->start,
-                       MPSC_SDMA_INTR_REG_BLOCK_SIZE);
-               mpsc_shared_regs.sdma_intr_base_p = r->start;
-       } else {
-               iounmap(mpsc_shared_regs.mpsc_routing_base);
-               release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,
-                               MPSC_ROUTING_REG_BLOCK_SIZE);
-               mpsc_resource_err("SDMA intr base");
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-static void mpsc_shared_unmap_regs(void)
-{
-       if (mpsc_shared_regs.mpsc_routing_base) {
-               iounmap(mpsc_shared_regs.mpsc_routing_base);
-               release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,
-                               MPSC_ROUTING_REG_BLOCK_SIZE);
-       }
-       if (mpsc_shared_regs.sdma_intr_base) {
-               iounmap(mpsc_shared_regs.sdma_intr_base);
-               release_mem_region(mpsc_shared_regs.sdma_intr_base_p,
-                               MPSC_SDMA_INTR_REG_BLOCK_SIZE);
-       }
-
-       mpsc_shared_regs.mpsc_routing_base = NULL;
-       mpsc_shared_regs.sdma_intr_base = NULL;
-
-       mpsc_shared_regs.mpsc_routing_base_p = 0;
-       mpsc_shared_regs.sdma_intr_base_p = 0;
-}
-
-static int mpsc_shared_drv_probe(struct platform_device *dev)
-{
-       struct mpsc_shared_pdata        *pdata;
-       int rc;
-
-       if (dev->id != 0)
-               return -ENODEV;
-
-       rc = mpsc_shared_map_regs(dev);
-       if (rc)
-               return rc;
-
-       pdata = dev_get_platdata(&dev->dev);
-
-       mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val;
-       mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val;
-       mpsc_shared_regs.MPSC_TCRR_m= pdata->tcrr_val;
-       mpsc_shared_regs.SDMA_INTR_CAUSE_m = pdata->intr_cause_val;
-       mpsc_shared_regs.SDMA_INTR_MASK_m = pdata->intr_mask_val;
-
-       return 0;
-}
-
-static int mpsc_shared_drv_remove(struct platform_device *dev)
-{
-       if (dev->id != 0)
-               return -ENODEV;
-
-       mpsc_shared_unmap_regs();
-       mpsc_shared_regs.MPSC_MRR_m = 0;
-       mpsc_shared_regs.MPSC_RCRR_m = 0;
-       mpsc_shared_regs.MPSC_TCRR_m = 0;
-       mpsc_shared_regs.SDMA_INTR_CAUSE_m = 0;
-       mpsc_shared_regs.SDMA_INTR_MASK_m = 0;
-
-       return 0;
-}
-
-static struct platform_driver mpsc_shared_driver = {
-       .probe  = mpsc_shared_drv_probe,
-       .remove = mpsc_shared_drv_remove,
-       .driver = {
-               .name   = MPSC_SHARED_NAME,
-       },
-};
-
-/*
- ******************************************************************************
- *
- * Driver Interface Routines
- *
- ******************************************************************************
- */
-static struct uart_driver mpsc_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = MPSC_DRIVER_NAME,
-       .dev_name       = MPSC_DEV_NAME,
-       .major          = MPSC_MAJOR,
-       .minor          = MPSC_MINOR_START,
-       .nr             = MPSC_NUM_CTLRS,
-       .cons           = MPSC_CONSOLE,
-};
-
-static int mpsc_drv_map_regs(struct mpsc_port_info *pi,
-               struct platform_device *pd)
-{
-       struct resource *r;
-
-       if ((r = platform_get_resource(pd, IORESOURCE_MEM, MPSC_BASE_ORDER))
-                       && request_mem_region(r->start, MPSC_REG_BLOCK_SIZE,
-                       "mpsc_regs")) {
-               pi->mpsc_base = ioremap(r->start, MPSC_REG_BLOCK_SIZE);
-               pi->mpsc_base_p = r->start;
-       } else {
-               mpsc_resource_err("MPSC base");
-               goto err;
-       }
-
-       if ((r = platform_get_resource(pd, IORESOURCE_MEM,
-                                       MPSC_SDMA_BASE_ORDER))
-                       && request_mem_region(r->start,
-                               MPSC_SDMA_REG_BLOCK_SIZE, "sdma_regs")) {
-               pi->sdma_base = ioremap(r->start,MPSC_SDMA_REG_BLOCK_SIZE);
-               pi->sdma_base_p = r->start;
-       } else {
-               mpsc_resource_err("SDMA base");
-               goto err;
-       }
-
-       if ((r = platform_get_resource(pd,IORESOURCE_MEM,MPSC_BRG_BASE_ORDER))
-                       && request_mem_region(r->start,
-                               MPSC_BRG_REG_BLOCK_SIZE, "brg_regs")) {
-               pi->brg_base = ioremap(r->start, MPSC_BRG_REG_BLOCK_SIZE);
-               pi->brg_base_p = r->start;
-       } else {
-               mpsc_resource_err("BRG base");
-               goto err;
-       }
-       return 0;
-
-err:
-       if (pi->sdma_base) {
-               iounmap(pi->sdma_base);
-               pi->sdma_base = NULL;
-       }
-       if (pi->mpsc_base) {
-               iounmap(pi->mpsc_base);
-               pi->mpsc_base = NULL;
-       }
-       return -ENOMEM;
-}
-
-static void mpsc_drv_unmap_regs(struct mpsc_port_info *pi)
-{
-       if (pi->mpsc_base) {
-               iounmap(pi->mpsc_base);
-               release_mem_region(pi->mpsc_base_p, MPSC_REG_BLOCK_SIZE);
-       }
-       if (pi->sdma_base) {
-               iounmap(pi->sdma_base);
-               release_mem_region(pi->sdma_base_p, MPSC_SDMA_REG_BLOCK_SIZE);
-       }
-       if (pi->brg_base) {
-               iounmap(pi->brg_base);
-               release_mem_region(pi->brg_base_p, MPSC_BRG_REG_BLOCK_SIZE);
-       }
-
-       pi->mpsc_base = NULL;
-       pi->sdma_base = NULL;
-       pi->brg_base = NULL;
-
-       pi->mpsc_base_p = 0;
-       pi->sdma_base_p = 0;
-       pi->brg_base_p = 0;
-}
-
-static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi,
-               struct platform_device *pd, int num)
-{
-       struct mpsc_pdata       *pdata;
-
-       pdata = dev_get_platdata(&pd->dev);
-
-       pi->port.uartclk = pdata->brg_clk_freq;
-       pi->port.iotype = UPIO_MEM;
-       pi->port.line = num;
-       pi->port.type = PORT_MPSC;
-       pi->port.fifosize = MPSC_TXBE_SIZE;
-       pi->port.membase = pi->mpsc_base;
-       pi->port.mapbase = (ulong)pi->mpsc_base;
-       pi->port.ops = &mpsc_pops;
-
-       pi->mirror_regs = pdata->mirror_regs;
-       pi->cache_mgmt = pdata->cache_mgmt;
-       pi->brg_can_tune = pdata->brg_can_tune;
-       pi->brg_clk_src = pdata->brg_clk_src;
-       pi->mpsc_max_idle = pdata->max_idle;
-       pi->default_baud = pdata->default_baud;
-       pi->default_bits = pdata->default_bits;
-       pi->default_parity = pdata->default_parity;
-       pi->default_flow = pdata->default_flow;
-
-       /* Initial values of mirrored regs */
-       pi->MPSC_CHR_1_m = pdata->chr_1_val;
-       pi->MPSC_CHR_2_m = pdata->chr_2_val;
-       pi->MPSC_CHR_10_m = pdata->chr_10_val;
-       pi->MPSC_MPCR_m = pdata->mpcr_val;
-       pi->BRG_BCR_m = pdata->bcr_val;
-
-       pi->shared_regs = &mpsc_shared_regs;
-
-       pi->port.irq = platform_get_irq(pd, 0);
-}
-
-static int mpsc_drv_probe(struct platform_device *dev)
-{
-       struct mpsc_port_info *pi;
-       int rc;
-
-       dev_dbg(&dev->dev, "mpsc_drv_probe: Adding MPSC %d\n", dev->id);
-
-       if (dev->id >= MPSC_NUM_CTLRS)
-               return -ENODEV;
-
-       pi = &mpsc_ports[dev->id];
-
-       rc = mpsc_drv_map_regs(pi, dev);
-       if (rc)
-               return rc;
-
-       mpsc_drv_get_platform_data(pi, dev, dev->id);
-       pi->port.dev = &dev->dev;
-
-       rc = mpsc_make_ready(pi);
-       if (rc)
-               goto err_unmap;
-
-       spin_lock_init(&pi->tx_lock);
-       rc = uart_add_one_port(&mpsc_reg, &pi->port);
-       if (rc)
-               goto err_relport;
-
-       return 0;
-err_relport:
-       mpsc_release_port(&pi->port);
-err_unmap:
-       mpsc_drv_unmap_regs(pi);
-       return rc;
-}
-
-static struct platform_driver mpsc_driver = {
-       .probe  = mpsc_drv_probe,
-       .driver = {
-               .name                   = MPSC_CTLR_NAME,
-               .suppress_bind_attrs    = true,
-       },
-};
-
-static int __init mpsc_drv_init(void)
-{
-       int     rc;
-
-       printk(KERN_INFO "Serial: MPSC driver\n");
-
-       memset(mpsc_ports, 0, sizeof(mpsc_ports));
-       memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
-
-       rc = uart_register_driver(&mpsc_reg);
-       if (rc)
-               return rc;
-
-       rc = platform_driver_register(&mpsc_shared_driver);
-       if (rc)
-               goto err_unreg_uart;
-
-       rc = platform_driver_register(&mpsc_driver);
-       if (rc)
-               goto err_unreg_plat;
-
-       return 0;
-err_unreg_plat:
-       platform_driver_unregister(&mpsc_shared_driver);
-err_unreg_uart:
-       uart_unregister_driver(&mpsc_reg);
-       return rc;
-}
-device_initcall(mpsc_drv_init);
-
-/*
-MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
-MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver");
-MODULE_LICENSE("GPL");
-*/
index 23833ad..3657a24 100644 (file)
@@ -383,10 +383,14 @@ no_rx:
 
 static inline void msm_wait_for_xmitr(struct uart_port *port)
 {
+       unsigned int timeout = 500000;
+
        while (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY)) {
                if (msm_read(port, UART_ISR) & UART_ISR_TX_READY)
                        break;
                udelay(1);
+               if (!timeout--)
+                       break;
        }
        msm_write(port, UART_CR_CMD_RESET_TX_READY, UART_CR);
 }
index 83f4dd0..4223cb4 100644 (file)
@@ -1777,6 +1777,7 @@ static int uart_port_activate(struct tty_port *port, struct tty_struct *tty)
 {
        struct uart_state *state = container_of(port, struct uart_state, port);
        struct uart_port *uport;
+       int ret;
 
        uport = uart_port_check(state);
        if (!uport || uport->flags & UPF_DEAD)
@@ -1787,7 +1788,11 @@ static int uart_port_activate(struct tty_port *port, struct tty_struct *tty)
        /*
         * Start up the serial port.
         */
-       return uart_startup(tty, state, 0);
+       ret = uart_startup(tty, state, 0);
+       if (ret > 0)
+               tty_port_set_active(port, 1);
+
+       return ret;
 }
 
 static const char *uart_type(struct uart_port *port)
index 39ed562..2b40018 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/termios.h>
 #include <linux/serial_core.h>
 #include <linux/module.h>
+#include <linux/property.h>
 
 #include "serial_mctrl_gpio.h"
 
@@ -116,6 +117,19 @@ struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
 
        for (i = 0; i < UART_GPIO_MAX; i++) {
                enum gpiod_flags flags;
+               char *gpio_str;
+               bool present;
+
+               /* Check if GPIO property exists and continue if not */
+               gpio_str = kasprintf(GFP_KERNEL, "%s-gpios",
+                                    mctrl_gpios_desc[i].name);
+               if (!gpio_str)
+                       continue;
+
+               present = device_property_present(dev, gpio_str);
+               kfree(gpio_str);
+               if (!present)
+                       continue;
 
                if (mctrl_gpios_desc[i].dir_out)
                        flags = GPIOD_OUT_LOW;
index abc7057..d18c680 100644 (file)
@@ -1398,6 +1398,7 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
        struct circ_buf *xmit = &port->state->xmit;
        unsigned long flags;
        dma_addr_t buf;
+       int head, tail;
 
        /*
         * DMA is idle now.
@@ -1407,16 +1408,23 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
         * consistent xmit buffer state.
         */
        spin_lock_irq(&port->lock);
-       buf = s->tx_dma_addr + (xmit->tail & (UART_XMIT_SIZE - 1));
+       head = xmit->head;
+       tail = xmit->tail;
+       buf = s->tx_dma_addr + (tail & (UART_XMIT_SIZE - 1));
        s->tx_dma_len = min_t(unsigned int,
-               CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
-               CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE));
-       spin_unlock_irq(&port->lock);
+               CIRC_CNT(head, tail, UART_XMIT_SIZE),
+               CIRC_CNT_TO_END(head, tail, UART_XMIT_SIZE));
+       if (!s->tx_dma_len) {
+               /* Transmit buffer has been flushed */
+               spin_unlock_irq(&port->lock);
+               return;
+       }
 
        desc = dmaengine_prep_slave_single(chan, buf, s->tx_dma_len,
                                           DMA_MEM_TO_DEV,
                                           DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!desc) {
+               spin_unlock_irq(&port->lock);
                dev_warn(port->dev, "Failed preparing Tx DMA descriptor\n");
                goto switch_to_pio;
        }
@@ -1424,18 +1432,18 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
        dma_sync_single_for_device(chan->device->dev, buf, s->tx_dma_len,
                                   DMA_TO_DEVICE);
 
-       spin_lock_irq(&port->lock);
        desc->callback = sci_dma_tx_complete;
        desc->callback_param = s;
-       spin_unlock_irq(&port->lock);
        s->cookie_tx = dmaengine_submit(desc);
        if (dma_submit_error(s->cookie_tx)) {
+               spin_unlock_irq(&port->lock);
                dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n");
                goto switch_to_pio;
        }
 
+       spin_unlock_irq(&port->lock);
        dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n",
-               __func__, xmit->buf, xmit->tail, xmit->head, s->cookie_tx);
+               __func__, xmit->buf, tail, head, s->cookie_tx);
 
        dma_async_issue_pending(chan);
        return;
@@ -1648,11 +1656,18 @@ static void sci_free_dma(struct uart_port *port)
 
 static void sci_flush_buffer(struct uart_port *port)
 {
+       struct sci_port *s = to_sci_port(port);
+
        /*
         * In uart_flush_buffer(), the xmit circular buffer has just been
-        * cleared, so we have to reset tx_dma_len accordingly.
+        * cleared, so we have to reset tx_dma_len accordingly, and stop any
+        * pending transfers
         */
-       to_sci_port(port)->tx_dma_len = 0;
+       s->tx_dma_len = 0;
+       if (s->chan_tx) {
+               dmaengine_terminate_async(s->chan_tx);
+               s->cookie_tx = -EINVAL;
+       }
 }
 #else /* !CONFIG_SERIAL_SH_SCI_DMA */
 static inline void sci_request_dma(struct uart_port *port)
index e8d7a7b..24a2261 100644 (file)
@@ -105,9 +105,7 @@ static int stm32_config_rs485(struct uart_port *port,
        struct stm32_usart_config *cfg = &stm32_port->info->cfg;
        u32 usartdiv, baud, cr1, cr3;
        bool over8;
-       unsigned long flags;
 
-       spin_lock_irqsave(&port->lock, flags);
        stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
 
        port->rs485 = *rs485conf;
@@ -147,7 +145,6 @@ static int stm32_config_rs485(struct uart_port *port,
        }
 
        stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
-       spin_unlock_irqrestore(&port->lock, flags);
 
        return 0;
 }
@@ -194,8 +191,8 @@ static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res,
        return 0;
 }
 
-static unsigned long
-stm32_get_char(struct uart_port *port, u32 *sr, int *last_res)
+static unsigned long stm32_get_char(struct uart_port *port, u32 *sr,
+                                   int *last_res)
 {
        struct stm32_port *stm32_port = to_stm32_port(port);
        struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
@@ -205,10 +202,13 @@ stm32_get_char(struct uart_port *port, u32 *sr, int *last_res)
                c = stm32_port->rx_buf[RX_BUF_L - (*last_res)--];
                if ((*last_res) == 0)
                        *last_res = RX_BUF_L;
-               return c;
        } else {
-               return readl_relaxed(port->membase + ofs->rdr);
+               c = readl_relaxed(port->membase + ofs->rdr);
+               /* apply RDR data mask */
+               c &= stm32_port->rdr_mask;
        }
+
+       return c;
 }
 
 static void stm32_receive_chars(struct uart_port *port, bool threaded)
@@ -225,35 +225,51 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded)
 
        while (stm32_pending_rx(port, &sr, &stm32_port->last_res, threaded)) {
                sr |= USART_SR_DUMMY_RX;
-               c = stm32_get_char(port, &sr, &stm32_port->last_res);
                flag = TTY_NORMAL;
-               port->icount.rx++;
 
+               /*
+                * Status bits has to be cleared before reading the RDR:
+                * In FIFO mode, reading the RDR will pop the next data
+                * (if any) along with its status bits into the SR.
+                * Not doing so leads to misalignement between RDR and SR,
+                * and clear status bits of the next rx data.
+                *
+                * Clear errors flags for stm32f7 and stm32h7 compatible
+                * devices. On stm32f4 compatible devices, the error bit is
+                * cleared by the sequence [read SR - read DR].
+                */
+               if ((sr & USART_SR_ERR_MASK) && ofs->icr != UNDEF_REG)
+                       stm32_clr_bits(port, ofs->icr, USART_ICR_ORECF |
+                                      USART_ICR_PECF | USART_ICR_FECF);
+
+               c = stm32_get_char(port, &sr, &stm32_port->last_res);
+               port->icount.rx++;
                if (sr & USART_SR_ERR_MASK) {
-                       if (sr & USART_SR_LBD) {
-                               port->icount.brk++;
-                               if (uart_handle_break(port))
-                                       continue;
-                       } else if (sr & USART_SR_ORE) {
-                               if (ofs->icr != UNDEF_REG)
-                                       writel_relaxed(USART_ICR_ORECF,
-                                                      port->membase +
-                                                      ofs->icr);
+                       if (sr & USART_SR_ORE) {
                                port->icount.overrun++;
                        } else if (sr & USART_SR_PE) {
                                port->icount.parity++;
                        } else if (sr & USART_SR_FE) {
-                               port->icount.frame++;
+                               /* Break detection if character is null */
+                               if (!c) {
+                                       port->icount.brk++;
+                                       if (uart_handle_break(port))
+                                               continue;
+                               } else {
+                                       port->icount.frame++;
+                               }
                        }
 
                        sr &= port->read_status_mask;
 
-                       if (sr & USART_SR_LBD)
-                               flag = TTY_BREAK;
-                       else if (sr & USART_SR_PE)
+                       if (sr & USART_SR_PE) {
                                flag = TTY_PARITY;
-                       else if (sr & USART_SR_FE)
-                               flag = TTY_FRAME;
+                       } else if (sr & USART_SR_FE) {
+                               if (!c)
+                                       flag = TTY_BREAK;
+                               else
+                                       flag = TTY_FRAME;
+                       }
                }
 
                if (uart_handle_sysrq_char(port, c))
@@ -271,21 +287,6 @@ static void stm32_tx_dma_complete(void *arg)
        struct uart_port *port = arg;
        struct stm32_port *stm32port = to_stm32_port(port);
        struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
-       unsigned int isr;
-       int ret;
-
-       ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr,
-                                               isr,
-                                               (isr & USART_SR_TC),
-                                               10, 100000);
-
-       if (ret)
-               dev_err(port->dev, "terminal count not set\n");
-
-       if (ofs->icr == UNDEF_REG)
-               stm32_clr_bits(port, ofs->isr, USART_SR_TC);
-       else
-               stm32_set_bits(port, ofs->icr, USART_CR_TC);
 
        stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
        stm32port->tx_dma_busy = false;
@@ -294,32 +295,57 @@ static void stm32_tx_dma_complete(void *arg)
        stm32_transmit_chars(port);
 }
 
+static void stm32_tx_interrupt_enable(struct uart_port *port)
+{
+       struct stm32_port *stm32_port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+
+       /*
+        * Enables TX FIFO threashold irq when FIFO is enabled,
+        * or TX empty irq when FIFO is disabled
+        */
+       if (stm32_port->fifoen)
+               stm32_set_bits(port, ofs->cr3, USART_CR3_TXFTIE);
+       else
+               stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE);
+}
+
+static void stm32_tx_interrupt_disable(struct uart_port *port)
+{
+       struct stm32_port *stm32_port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+
+       if (stm32_port->fifoen)
+               stm32_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE);
+       else
+               stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE);
+}
+
 static void stm32_transmit_chars_pio(struct uart_port *port)
 {
        struct stm32_port *stm32_port = to_stm32_port(port);
        struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
        struct circ_buf *xmit = &port->state->xmit;
-       unsigned int isr;
-       int ret;
 
        if (stm32_port->tx_dma_busy) {
                stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
                stm32_port->tx_dma_busy = false;
        }
 
-       ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr,
-                                               isr,
-                                               (isr & USART_SR_TXE),
-                                               10, 100000);
-
-       if (ret)
-               dev_err(port->dev, "tx empty not set\n");
-
-       stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE);
+       while (!uart_circ_empty(xmit)) {
+               /* Check that TDR is empty before filling FIFO */
+               if (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE))
+                       break;
+               writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
 
-       writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr);
-       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-       port->icount.tx++;
+       /* rely on TXE irq (mask or unmask) for sending remaining data */
+       if (uart_circ_empty(xmit))
+               stm32_tx_interrupt_disable(port);
+       else
+               stm32_tx_interrupt_enable(port);
 }
 
 static void stm32_transmit_chars_dma(struct uart_port *port)
@@ -377,7 +403,6 @@ static void stm32_transmit_chars_dma(struct uart_port *port)
        /* Issue pending DMA TX requests */
        dma_async_issue_pending(stm32port->tx_ch);
 
-       stm32_clr_bits(port, ofs->isr, USART_SR_TC);
        stm32_set_bits(port, ofs->cr3, USART_CR3_DMAT);
 
        xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
@@ -401,15 +426,15 @@ static void stm32_transmit_chars(struct uart_port *port)
                return;
        }
 
-       if (uart_tx_stopped(port)) {
-               stm32_stop_tx(port);
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               stm32_tx_interrupt_disable(port);
                return;
        }
 
-       if (uart_circ_empty(xmit)) {
-               stm32_stop_tx(port);
-               return;
-       }
+       if (ofs->icr == UNDEF_REG)
+               stm32_clr_bits(port, ofs->isr, USART_SR_TC);
+       else
+               stm32_set_bits(port, ofs->icr, USART_ICR_TCCF);
 
        if (stm32_port->tx_ch)
                stm32_transmit_chars_dma(port);
@@ -420,7 +445,7 @@ static void stm32_transmit_chars(struct uart_port *port)
                uart_write_wakeup(port);
 
        if (uart_circ_empty(xmit))
-               stm32_stop_tx(port);
+               stm32_tx_interrupt_disable(port);
 }
 
 static irqreturn_t stm32_interrupt(int irq, void *ptr)
@@ -434,6 +459,10 @@ static irqreturn_t stm32_interrupt(int irq, void *ptr)
 
        sr = readl_relaxed(port->membase + ofs->isr);
 
+       if ((sr & USART_SR_RTOF) && ofs->icr != UNDEF_REG)
+               writel_relaxed(USART_ICR_RTOCF,
+                              port->membase + ofs->icr);
+
        if ((sr & USART_SR_WUF) && (ofs->icr != UNDEF_REG))
                writel_relaxed(USART_ICR_WUCF,
                               port->membase + ofs->icr);
@@ -495,10 +524,7 @@ static unsigned int stm32_get_mctrl(struct uart_port *port)
 /* Transmit stop */
 static void stm32_stop_tx(struct uart_port *port)
 {
-       struct stm32_port *stm32_port = to_stm32_port(port);
-       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
-
-       stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE);
+       stm32_tx_interrupt_disable(port);
 }
 
 /* There are probably characters waiting to be transmitted. */
@@ -520,7 +546,10 @@ static void stm32_throttle(struct uart_port *port)
        unsigned long flags;
 
        spin_lock_irqsave(&port->lock, flags);
-       stm32_clr_bits(port, ofs->cr1, USART_CR1_RXNEIE);
+       stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq);
+       if (stm32_port->cr3_irq)
+               stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq);
+
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
@@ -532,7 +561,10 @@ static void stm32_unthrottle(struct uart_port *port)
        unsigned long flags;
 
        spin_lock_irqsave(&port->lock, flags);
-       stm32_set_bits(port, ofs->cr1, USART_CR1_RXNEIE);
+       stm32_set_bits(port, ofs->cr1, stm32_port->cr1_irq);
+       if (stm32_port->cr3_irq)
+               stm32_set_bits(port, ofs->cr3, stm32_port->cr3_irq);
+
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
@@ -542,7 +574,10 @@ static void stm32_stop_rx(struct uart_port *port)
        struct stm32_port *stm32_port = to_stm32_port(port);
        struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
 
-       stm32_clr_bits(port, ofs->cr1, USART_CR1_RXNEIE);
+       stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq);
+       if (stm32_port->cr3_irq)
+               stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq);
+
 }
 
 /* Handle breaks - ignored by us */
@@ -554,7 +589,6 @@ static int stm32_startup(struct uart_port *port)
 {
        struct stm32_port *stm32_port = to_stm32_port(port);
        struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
-       struct stm32_usart_config *cfg = &stm32_port->info->cfg;
        const char *name = to_platform_device(port->dev)->name;
        u32 val;
        int ret;
@@ -565,16 +599,21 @@ static int stm32_startup(struct uart_port *port)
        if (ret)
                return ret;
 
-       if (cfg->has_wakeup && stm32_port->wakeirq >= 0) {
-               ret = dev_pm_set_dedicated_wake_irq(port->dev,
-                                                   stm32_port->wakeirq);
-               if (ret) {
-                       free_irq(port->irq, port);
-                       return ret;
-               }
+       /* RX FIFO Flush */
+       if (ofs->rqr != UNDEF_REG)
+               stm32_set_bits(port, ofs->rqr, USART_RQR_RXFRQ);
+
+       /* Tx and RX FIFO configuration */
+       if (stm32_port->fifoen) {
+               val = readl_relaxed(port->membase + ofs->cr3);
+               val &= ~(USART_CR3_TXFTCFG_MASK | USART_CR3_RXFTCFG_MASK);
+               val |= USART_CR3_TXFTCFG_HALF << USART_CR3_TXFTCFG_SHIFT;
+               val |= USART_CR3_RXFTCFG_HALF << USART_CR3_RXFTCFG_SHIFT;
+               writel_relaxed(val, port->membase + ofs->cr3);
        }
 
-       val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+       /* RX FIFO enabling */
+       val = stm32_port->cr1_irq | USART_CR1_RE;
        if (stm32_port->fifoen)
                val |= USART_CR1_FIFOEN;
        stm32_set_bits(port, ofs->cr1, val);
@@ -587,18 +626,57 @@ static void stm32_shutdown(struct uart_port *port)
        struct stm32_port *stm32_port = to_stm32_port(port);
        struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
        struct stm32_usart_config *cfg = &stm32_port->info->cfg;
-       u32 val;
+       u32 val, isr;
+       int ret;
 
-       val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+       val = USART_CR1_TXEIE | USART_CR1_TE;
+       val |= stm32_port->cr1_irq | USART_CR1_RE;
        val |= BIT(cfg->uart_enable_bit);
        if (stm32_port->fifoen)
                val |= USART_CR1_FIFOEN;
+
+       ret = readl_relaxed_poll_timeout(port->membase + ofs->isr,
+                                        isr, (isr & USART_SR_TC),
+                                        10, 100000);
+
+       if (ret)
+               dev_err(port->dev, "transmission complete not set\n");
+
        stm32_clr_bits(port, ofs->cr1, val);
 
-       dev_pm_clear_wake_irq(port->dev);
        free_irq(port->irq, port);
 }
 
+static unsigned int stm32_get_databits(struct ktermios *termios)
+{
+       unsigned int bits;
+
+       tcflag_t cflag = termios->c_cflag;
+
+       switch (cflag & CSIZE) {
+       /*
+        * CSIZE settings are not necessarily supported in hardware.
+        * CSIZE unsupported configurations are handled here to set word length
+        * to 8 bits word as default configuration and to print debug message.
+        */
+       case CS5:
+               bits = 5;
+               break;
+       case CS6:
+               bits = 6;
+               break;
+       case CS7:
+               bits = 7;
+               break;
+       /* default including CS8 */
+       default:
+               bits = 8;
+               break;
+       }
+
+       return bits;
+}
+
 static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
                            struct ktermios *old)
 {
@@ -606,7 +684,7 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
        struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
        struct stm32_usart_config *cfg = &stm32_port->info->cfg;
        struct serial_rs485 *rs485conf = &port->rs485;
-       unsigned int baud;
+       unsigned int baud, bits;
        u32 usartdiv, mantissa, fraction, oversampling;
        tcflag_t cflag = termios->c_cflag;
        u32 cr1, cr2, cr3;
@@ -622,26 +700,64 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
        /* Stop serial port and reset value */
        writel_relaxed(0, port->membase + ofs->cr1);
 
-       cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE;
+       /* flush RX & TX FIFO */
+       if (ofs->rqr != UNDEF_REG)
+               stm32_set_bits(port, ofs->rqr,
+                              USART_RQR_TXFRQ | USART_RQR_RXFRQ);
 
+       cr1 = USART_CR1_TE | USART_CR1_RE;
        if (stm32_port->fifoen)
                cr1 |= USART_CR1_FIFOEN;
        cr2 = 0;
-       cr3 = 0;
+       cr3 = readl_relaxed(port->membase + ofs->cr3);
+       cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTCFG_MASK | USART_CR3_RXFTIE
+               | USART_CR3_TXFTCFG_MASK;
 
        if (cflag & CSTOPB)
                cr2 |= USART_CR2_STOP_2B;
 
+       bits = stm32_get_databits(termios);
+       stm32_port->rdr_mask = (BIT(bits) - 1);
+
        if (cflag & PARENB) {
+               bits++;
                cr1 |= USART_CR1_PCE;
-               if ((cflag & CSIZE) == CS8) {
-                       if (cfg->has_7bits_data)
-                               cr1 |= USART_CR1_M0;
-                       else
-                               cr1 |= USART_CR1_M;
-               }
        }
 
+       /*
+        * Word length configuration:
+        * CS8 + parity, 9 bits word aka [M1:M0] = 0b01
+        * CS7 or (CS6 + parity), 7 bits word aka [M1:M0] = 0b10
+        * CS8 or (CS7 + parity), 8 bits word aka [M1:M0] = 0b00
+        * M0 and M1 already cleared by cr1 initialization.
+        */
+       if (bits == 9)
+               cr1 |= USART_CR1_M0;
+       else if ((bits == 7) && cfg->has_7bits_data)
+               cr1 |= USART_CR1_M1;
+       else if (bits != 8)
+               dev_dbg(port->dev, "Unsupported data bits config: %u bits\n"
+                       , bits);
+
+       if (ofs->rtor != UNDEF_REG && (stm32_port->rx_ch ||
+                                      stm32_port->fifoen)) {
+               if (cflag & CSTOPB)
+                       bits = bits + 3; /* 1 start bit + 2 stop bits */
+               else
+                       bits = bits + 2; /* 1 start bit + 1 stop bit */
+
+               /* RX timeout irq to occur after last stop bit + bits */
+               stm32_port->cr1_irq = USART_CR1_RTOIE;
+               writel_relaxed(bits, port->membase + ofs->rtor);
+               cr2 |= USART_CR2_RTOEN;
+               /* Not using dma, enable fifo threshold irq */
+               if (!stm32_port->rx_ch)
+                       stm32_port->cr3_irq =  USART_CR3_RXFTIE;
+       }
+
+       cr1 |= stm32_port->cr1_irq;
+       cr3 |= stm32_port->cr3_irq;
+
        if (cflag & PARODD)
                cr1 |= USART_CR1_PS;
 
@@ -679,14 +795,14 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
        if (termios->c_iflag & INPCK)
                port->read_status_mask |= USART_SR_PE | USART_SR_FE;
        if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
-               port->read_status_mask |= USART_SR_LBD;
+               port->read_status_mask |= USART_SR_FE;
 
        /* Characters to ignore */
        port->ignore_status_mask = 0;
        if (termios->c_iflag & IGNPAR)
                port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
        if (termios->c_iflag & IGNBRK) {
-               port->ignore_status_mask |= USART_SR_LBD;
+               port->ignore_status_mask |= USART_SR_FE;
                /*
                 * If we're ignoring parity and break indicators,
                 * ignore overruns too (for real raw support).
@@ -808,12 +924,32 @@ static int stm32_init_port(struct stm32_port *stm32port,
        port->flags     = UPF_BOOT_AUTOCONF;
        port->ops       = &stm32_uart_ops;
        port->dev       = &pdev->dev;
-       port->irq       = platform_get_irq(pdev, 0);
+       port->fifosize  = stm32port->info->cfg.fifosize;
+
+       ret = platform_get_irq(pdev, 0);
+       if (ret <= 0) {
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "Can't get event IRQ: %d\n", ret);
+               return ret ? ret : -ENODEV;
+       }
+       port->irq = ret;
+
        port->rs485_config = stm32_config_rs485;
 
        stm32_init_rs485(port, pdev);
 
-       stm32port->wakeirq = platform_get_irq(pdev, 1);
+       if (stm32port->info->cfg.has_wakeup) {
+               stm32port->wakeirq = platform_get_irq(pdev, 1);
+               if (stm32port->wakeirq <= 0 && stm32port->wakeirq != -ENXIO) {
+                       if (stm32port->wakeirq != -EPROBE_DEFER)
+                               dev_err(&pdev->dev,
+                                       "Can't get event wake IRQ: %d\n",
+                                       stm32port->wakeirq);
+                       return stm32port->wakeirq ? stm32port->wakeirq :
+                               -ENODEV;
+               }
+       }
+
        stm32port->fifoen = stm32port->info->cfg.has_fifo;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -862,6 +998,8 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
        stm32_ports[id].hw_flow_control = of_property_read_bool(np,
                                                        "st,hw-flow-ctrl");
        stm32_ports[id].port.line = id;
+       stm32_ports[id].cr1_irq = USART_CR1_RXNEIE;
+       stm32_ports[id].cr3_irq = 0;
        stm32_ports[id].last_res = RX_BUF_L;
        return &stm32_ports[id];
 }
@@ -1020,15 +1158,22 @@ static int stm32_serial_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       if (stm32port->info->cfg.has_wakeup && stm32port->wakeirq >= 0) {
+       if (stm32port->wakeirq > 0) {
                ret = device_init_wakeup(&pdev->dev, true);
                if (ret)
                        goto err_uninit;
+
+               ret = dev_pm_set_dedicated_wake_irq(&pdev->dev,
+                                                   stm32port->wakeirq);
+               if (ret)
+                       goto err_nowup;
+
+               device_set_wakeup_enable(&pdev->dev, false);
        }
 
        ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
        if (ret)
-               goto err_nowup;
+               goto err_wirq;
 
        ret = stm32_of_dma_rx_probe(stm32port, pdev);
        if (ret)
@@ -1042,8 +1187,12 @@ static int stm32_serial_probe(struct platform_device *pdev)
 
        return 0;
 
+err_wirq:
+       if (stm32port->wakeirq > 0)
+               dev_pm_clear_wake_irq(&pdev->dev);
+
 err_nowup:
-       if (stm32port->info->cfg.has_wakeup && stm32port->wakeirq >= 0)
+       if (stm32port->wakeirq > 0)
                device_init_wakeup(&pdev->dev, false);
 
 err_uninit:
@@ -1057,7 +1206,6 @@ static int stm32_serial_remove(struct platform_device *pdev)
        struct uart_port *port = platform_get_drvdata(pdev);
        struct stm32_port *stm32_port = to_stm32_port(port);
        struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
-       struct stm32_usart_config *cfg = &stm32_port->info->cfg;
 
        stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR);
 
@@ -1079,8 +1227,10 @@ static int stm32_serial_remove(struct platform_device *pdev)
                                  TX_BUF_L, stm32_port->tx_buf,
                                  stm32_port->tx_dma_buf);
 
-       if (cfg->has_wakeup && stm32_port->wakeirq >= 0)
+       if (stm32_port->wakeirq > 0) {
+               dev_pm_clear_wake_irq(&pdev->dev);
                device_init_wakeup(&pdev->dev, false);
+       }
 
        clk_disable_unprepare(stm32_port->clk);
 
@@ -1195,7 +1345,7 @@ static void stm32_serial_enable_wakeup(struct uart_port *port, bool enable)
        struct stm32_usart_config *cfg = &stm32_port->info->cfg;
        u32 val;
 
-       if (!cfg->has_wakeup || stm32_port->wakeirq < 0)
+       if (stm32_port->wakeirq <= 0)
                return;
 
        if (enable) {
index 6f294e2..a175c10 100644 (file)
@@ -27,6 +27,7 @@ struct stm32_usart_config {
        bool has_7bits_data;
        bool has_wakeup;
        bool has_fifo;
+       int fifosize;
 };
 
 struct stm32_usart_info {
@@ -54,6 +55,7 @@ struct stm32_usart_info stm32f4_info = {
        .cfg = {
                .uart_enable_bit = 13,
                .has_7bits_data = false,
+               .fifosize = 1,
        }
 };
 
@@ -74,6 +76,7 @@ struct stm32_usart_info stm32f7_info = {
        .cfg = {
                .uart_enable_bit = 0,
                .has_7bits_data = true,
+               .fifosize = 1,
        }
 };
 
@@ -96,6 +99,7 @@ struct stm32_usart_info stm32h7_info = {
                .has_7bits_data = true,
                .has_wakeup = true,
                .has_fifo = true,
+               .fifosize = 16,
        }
 };
 
@@ -108,7 +112,6 @@ struct stm32_usart_info stm32h7_info = {
 #define USART_SR_RXNE          BIT(5)
 #define USART_SR_TC            BIT(6)
 #define USART_SR_TXE           BIT(7)
-#define USART_SR_LBD           BIT(8)
 #define USART_SR_CTSIF         BIT(9)
 #define USART_SR_CTS           BIT(10)         /* F7 */
 #define USART_SR_RTOF          BIT(11)         /* F7 */
@@ -120,8 +123,7 @@ struct stm32_usart_info stm32h7_info = {
 #define USART_SR_SBKF          BIT(18)         /* F7 */
 #define USART_SR_WUF           BIT(20)         /* H7 */
 #define USART_SR_TEACK         BIT(21)         /* F7 */
-#define USART_SR_ERR_MASK      (USART_SR_LBD | USART_SR_ORE | \
-                                USART_SR_FE | USART_SR_PE)
+#define USART_SR_ERR_MASK      (USART_SR_ORE | USART_SR_FE | USART_SR_PE)
 /* Dummy bits */
 #define USART_SR_DUMMY_RX      BIT(16)
 
@@ -151,8 +153,7 @@ struct stm32_usart_info stm32h7_info = {
 #define USART_CR1_PS           BIT(9)
 #define USART_CR1_PCE          BIT(10)
 #define USART_CR1_WAKE         BIT(11)
-#define USART_CR1_M            BIT(12)
-#define USART_CR1_M0           BIT(12)         /* F7 */
+#define USART_CR1_M0           BIT(12)         /* F7 (CR1_M for F4) */
 #define USART_CR1_MME          BIT(13)         /* F7 */
 #define USART_CR1_CMIE         BIT(14)         /* F7 */
 #define USART_CR1_OVER8                BIT(15)
@@ -169,8 +170,6 @@ struct stm32_usart_info stm32h7_info = {
 /* USART_CR2 */
 #define USART_CR2_ADD_MASK     GENMASK(3, 0)   /* F4 */
 #define USART_CR2_ADDM7                BIT(4)          /* F7 */
-#define USART_CR2_LBDL         BIT(5)
-#define USART_CR2_LBDIE                BIT(6)
 #define USART_CR2_LBCL         BIT(8)
 #define USART_CR2_CPHA         BIT(9)
 #define USART_CR2_CPOL         BIT(10)
@@ -209,6 +208,19 @@ struct stm32_usart_info stm32h7_info = {
 #define USART_CR3_WUS_MASK     GENMASK(21, 20) /* H7 */
 #define USART_CR3_WUS_START_BIT        BIT(21)         /* H7 */
 #define USART_CR3_WUFIE                BIT(22)         /* H7 */
+#define USART_CR3_TXFTIE       BIT(23)         /* H7 */
+#define USART_CR3_TCBGTIE      BIT(24)         /* H7 */
+#define USART_CR3_RXFTCFG_MASK GENMASK(27, 25) /* H7 */
+#define USART_CR3_RXFTCFG_SHIFT        25              /* H7 */
+#define USART_CR3_RXFTIE       BIT(28)         /* H7 */
+#define USART_CR3_TXFTCFG_MASK GENMASK(31, 29) /* H7 */
+#define USART_CR3_TXFTCFG_SHIFT        29              /* H7 */
+
+/* TX FIFO threashold set to half of its depth */
+#define USART_CR3_TXFTCFG_HALF 0x2
+
+/* RX FIFO threashold set to half of its depth */
+#define USART_CR3_RXFTCFG_HALF 0x2
 
 /* USART_GTPR */
 #define USART_GTPR_PSC_MASK    GENMASK(7, 0)
@@ -227,12 +239,10 @@ struct stm32_usart_info stm32h7_info = {
 
 /* USART_ICR */
 #define USART_ICR_PECF         BIT(0)          /* F7 */
-#define USART_ICR_FFECF                BIT(1)          /* F7 */
-#define USART_ICR_NCF          BIT(2)          /* F7 */
+#define USART_ICR_FECF         BIT(1)          /* F7 */
 #define USART_ICR_ORECF                BIT(3)          /* F7 */
 #define USART_ICR_IDLECF       BIT(4)          /* F7 */
 #define USART_ICR_TCCF         BIT(6)          /* F7 */
-#define USART_ICR_LBDCF                BIT(8)          /* F7 */
 #define USART_ICR_CTSCF                BIT(9)          /* F7 */
 #define USART_ICR_RTOCF                BIT(11)         /* F7 */
 #define USART_ICR_EOBCF                BIT(12)         /* F7 */
@@ -256,11 +266,14 @@ struct stm32_port {
        struct dma_chan *tx_ch;  /* dma tx channel            */
        dma_addr_t tx_dma_buf;   /* dma tx buffer bus address */
        unsigned char *tx_buf;   /* dma tx buffer cpu address */
+       u32 cr1_irq;             /* USART_CR1_RXNEIE or RTOIE */
+       u32 cr3_irq;             /* USART_CR3_RXFTIE */
        int last_res;
        bool tx_dma_busy;        /* dma tx busy               */
        bool hw_flow_control;
        bool fifoen;
        int wakeirq;
+       int rdr_mask;           /* receive data register mask */
 };
 
 static struct stm32_port stm32_ports[STM32_MAX_PORTS];
index 605354f..f145946 100644 (file)
 #include <linux/of.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
+#include <linux/iopoll.h>
 
 #define CDNS_UART_TTY_NAME     "ttyPS"
 #define CDNS_UART_NAME         "xuartps"
-#define CDNS_UART_MAJOR                0       /* use dynamic node allocation */
 #define CDNS_UART_FIFO_SIZE    64      /* FIFO size */
 #define CDNS_UART_REGISTER_SPACE       0x1000
+#define TX_TIMEOUT             500000
 
 /* Rx Trigger level */
 static int rx_trigger_level = 56;
-module_param(rx_trigger_level, uint, S_IRUGO);
+static int uartps_major;
+module_param(rx_trigger_level, uint, 0444);
 MODULE_PARM_DESC(rx_trigger_level, "Rx trigger level, 1-63 bytes");
 
 /* Rx Timeout */
 static int rx_timeout = 10;
-module_param(rx_timeout, uint, S_IRUGO);
+module_param(rx_timeout, uint, 0444);
 MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
 
 /* Register offsets for the UART. */
@@ -199,7 +201,7 @@ struct cdns_platform_data {
        u32 quirks;
 };
 #define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
-               clk_rate_change_nb);
+               clk_rate_change_nb)
 
 /**
  * cdns_uart_handle_rx - Handle the received bytes along with Rx errors.
@@ -312,15 +314,16 @@ static void cdns_uart_handle_tx(void *dev_id)
        } else {
                numbytes = port->fifosize;
                while (numbytes && !uart_circ_empty(&port->state->xmit) &&
-                      !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)) {
+                      !(readl(port->membase + CDNS_UART_SR) &
+                                               CDNS_UART_SR_TXFULL)) {
                        /*
                         * Get the data from the UART circular buffer
                         * and write it to the cdns_uart's TX_FIFO
                         * register.
                         */
                        writel(
-                               port->state->xmit.buf[port->state->xmit.
-                               tail], port->membase + CDNS_UART_FIFO);
+                               port->state->xmit.buf[port->state->xmit.tail],
+                                       port->membase + CDNS_UART_FIFO);
 
                        port->icount.tx++;
 
@@ -684,18 +687,21 @@ static void cdns_uart_set_termios(struct uart_port *port,
        unsigned int cval = 0;
        unsigned int baud, minbaud, maxbaud;
        unsigned long flags;
-       unsigned int ctrl_reg, mode_reg;
-
-       spin_lock_irqsave(&port->lock, flags);
+       unsigned int ctrl_reg, mode_reg, val;
+       int err;
 
        /* Wait for the transmit FIFO to empty before making changes */
        if (!(readl(port->membase + CDNS_UART_CR) &
                                CDNS_UART_CR_TX_DIS)) {
-               while (!(readl(port->membase + CDNS_UART_SR) &
-                               CDNS_UART_SR_TXEMPTY)) {
-                       cpu_relax();
+               err = readl_poll_timeout(port->membase + CDNS_UART_SR,
+                                        val, (val & CDNS_UART_SR_TXEMPTY),
+                                        1000, TX_TIMEOUT);
+               if (err) {
+                       dev_err(port->dev, "timed out waiting for tx empty");
+                       return;
                }
        }
+       spin_lock_irqsave(&port->lock, flags);
 
        /* Disable the TX and RX to set baud rate */
        ctrl_reg = readl(port->membase + CDNS_UART_CR);
@@ -1073,8 +1079,6 @@ static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c)
                cpu_relax();
 
        spin_unlock_irqrestore(&port->lock, flags);
-
-       return;
 }
 #endif
 
@@ -1517,7 +1521,7 @@ static int cdns_uart_probe(struct platform_device *pdev)
        cdns_uart_uart_driver->owner = THIS_MODULE;
        cdns_uart_uart_driver->driver_name = driver_name;
        cdns_uart_uart_driver->dev_name = CDNS_UART_TTY_NAME;
-       cdns_uart_uart_driver->major = CDNS_UART_MAJOR;
+       cdns_uart_uart_driver->major = uartps_major;
        cdns_uart_uart_driver->minor = cdns_uart_data->id;
        cdns_uart_uart_driver->nr = 1;
 
@@ -1546,6 +1550,7 @@ static int cdns_uart_probe(struct platform_device *pdev)
                goto err_out_id;
        }
 
+       uartps_major = cdns_uart_uart_driver->tty_driver->major;
        cdns_uart_data->cdns_uart_driver = cdns_uart_uart_driver;
 
        /*
index 033ac7e..566728f 100644 (file)
@@ -1837,7 +1837,7 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
 static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
                int *index)
 {
-       struct tty_driver *driver;
+       struct tty_driver *driver = NULL;
 
        switch (device) {
 #ifdef CONFIG_VT
@@ -1858,6 +1858,8 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
                                break;
                        }
                }
+               if (driver)
+                       tty_driver_kref_put(driver);
                return ERR_PTR(-ENODEV);
        }
        default:
index e4b2741..6e59d37 100644 (file)
@@ -45,6 +45,7 @@ config USB_ARCH_HAS_HCD
 config USB
        tristate "Support for Host-side USB"
        depends on USB_ARCH_HAS_HCD
+       select GENERIC_ALLOCATOR
        select USB_COMMON
        select NLS  # for UTF-8 strings
        ---help---
@@ -74,7 +75,7 @@ config USB
          After choosing your HCD, then select drivers for the USB peripherals
          you'll be using.  You may want to check out the information provided
          in <file:Documentation/usb/> and especially the links given in
-         <file:Documentation/usb/usb-help.txt>.
+         <file:Documentation/usb/usb-help.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called usbcore.
index 7d1b8c8..ecc2de1 100644 (file)
@@ -5,6 +5,7 @@
 
 # Object files in subdirectories
 
+obj-$(CONFIG_USB_COMMON)       += common/
 obj-$(CONFIG_USB)              += core/
 obj-$(CONFIG_USB_SUPPORT)      += phy/
 
@@ -60,8 +61,6 @@ obj-$(CONFIG_USB_CHIPIDEA)    += chipidea/
 obj-$(CONFIG_USB_RENESAS_USBHS)        += renesas_usbhs/
 obj-$(CONFIG_USB_GADGET)       += gadget/
 
-obj-$(CONFIG_USB_COMMON)       += common/
-
 obj-$(CONFIG_USBIP_CORE)       += usbip/
 
 obj-$(CONFIG_TYPEC)            += typec/
index 989aaa3..3d958a1 100644 (file)
@@ -7,7 +7,6 @@ menuconfig USB_ATM
        tristate "USB DSL modem support"
        depends on ATM
        select CRC32
-       default n
        help
          Say Y here if you want to connect a USB Digital Subscriber Line (DSL)
          modem to your computer's USB port.  You will then need to choose your
index 2754b4c..8faa51b 100644 (file)
@@ -1,55 +1,11 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
-/*-
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-2-Clause)
+/*
  * Copyright (c) 2003, 2004
  *     Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
  *
  * Copyright (c) 2005-2007 Matthieu Castet <castet.matthieu@free.fr>
  * Copyright (c) 2005-2007 Stanislaw Gruszka <stf_xl@wp.pl>
  *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * BSD license below:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice unmodified, this list of conditions, and the following
- *    disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- *
- * GPL license :
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the 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.
- *
- *
  * HISTORY : some part of the code was base on ueagle 1.3 BSD driver,
  * Damien Bergamini agree to put his code under a DUAL GPL/BSD license.
  *
index ceec8d5..b5abfe8 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/usb/of.h>
 #include <linux/clk.h>
 #include <linux/pinctrl/consumer.h>
+#include <linux/pm_qos.h>
 
 #include "ci.h"
 #include "ci_hdrc_imx.h"
@@ -63,6 +64,11 @@ static const struct ci_hdrc_imx_platform_flag imx7d_usb_data = {
        .flags = CI_HDRC_SUPPORTS_RUNTIME_PM,
 };
 
+static const struct ci_hdrc_imx_platform_flag imx7ulp_usb_data = {
+       .flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
+               CI_HDRC_PMQOS,
+};
+
 static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
        { .compatible = "fsl,imx23-usb", .data = &imx23_usb_data},
        { .compatible = "fsl,imx28-usb", .data = &imx28_usb_data},
@@ -72,6 +78,7 @@ static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
        { .compatible = "fsl,imx6sx-usb", .data = &imx6sx_usb_data},
        { .compatible = "fsl,imx6ul-usb", .data = &imx6ul_usb_data},
        { .compatible = "fsl,imx7d-usb", .data = &imx7d_usb_data},
+       { .compatible = "fsl,imx7ulp-usb", .data = &imx7ulp_usb_data},
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids);
@@ -93,6 +100,8 @@ struct ci_hdrc_imx_data {
        struct clk *clk_ahb;
        struct clk *clk_per;
        /* --------------------------------- */
+       struct pm_qos_request pm_qos_req;
+       const struct ci_hdrc_imx_platform_flag *plat_data;
 };
 
 /* Common functions shared by usbmisc drivers */
@@ -309,6 +318,8 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
        if (!data)
                return -ENOMEM;
 
+       data->plat_data = imx_platform_flag;
+       pdata.flags |= imx_platform_flag->flags;
        platform_set_drvdata(pdev, data);
        data->usbmisc_data = usbmisc_get_init_data(dev);
        if (IS_ERR(data->usbmisc_data))
@@ -369,6 +380,11 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
                        }
                }
        }
+
+       if (pdata.flags & CI_HDRC_PMQOS)
+               pm_qos_add_request(&data->pm_qos_req,
+                       PM_QOS_CPU_DMA_LATENCY, 0);
+
        ret = imx_get_clks(dev);
        if (ret)
                goto disable_hsic_regulator;
@@ -382,8 +398,9 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
                ret = PTR_ERR(data->phy);
                /* Return -EINVAL if no usbphy is available */
                if (ret == -ENODEV)
-                       ret = -EINVAL;
-               goto err_clk;
+                       data->phy = NULL;
+               else
+                       goto err_clk;
        }
 
        pdata.usb_phy = data->phy;
@@ -396,7 +413,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
                usb_phy_init(pdata.usb_phy);
        }
 
-       pdata.flags |= imx_platform_flag->flags;
        if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM)
                data->supports_runtime_pm = true;
 
@@ -439,6 +455,8 @@ err_clk:
 disable_hsic_regulator:
        if (data->hsic_pad_regulator)
                ret = regulator_disable(data->hsic_pad_regulator);
+       if (pdata.flags & CI_HDRC_PMQOS)
+               pm_qos_remove_request(&data->pm_qos_req);
        return ret;
 }
 
@@ -455,6 +473,8 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev)
        if (data->override_phy_control)
                usb_phy_shutdown(data->phy);
        imx_disable_unprepare_clks(&pdev->dev);
+       if (data->plat_data->flags & CI_HDRC_PMQOS)
+               pm_qos_remove_request(&data->pm_qos_req);
        if (data->hsic_pad_regulator)
                regulator_disable(data->hsic_pad_regulator);
 
@@ -480,6 +500,9 @@ static int __maybe_unused imx_controller_suspend(struct device *dev)
        }
 
        imx_disable_unprepare_clks(dev);
+       if (data->plat_data->flags & CI_HDRC_PMQOS)
+               pm_qos_remove_request(&data->pm_qos_req);
+
        data->in_lpm = true;
 
        return 0;
@@ -497,6 +520,10 @@ static int __maybe_unused imx_controller_resume(struct device *dev)
                return 0;
        }
 
+       if (data->plat_data->flags & CI_HDRC_PMQOS)
+               pm_qos_add_request(&data->pm_qos_req,
+                       PM_QOS_CPU_DMA_LATENCY, 0);
+
        ret = imx_prepare_enable_clks(dev);
        if (ret)
                return ret;
index b8b3caa..bb4645a 100644 (file)
@@ -175,7 +175,6 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev)
        struct platform_device *plat_ci;
        struct clk *clk;
        struct reset_control *reset;
-       struct resource *res;
        int ret;
        struct device_node *ulpi_node, *phy_node;
 
@@ -209,8 +208,7 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev)
        if (IS_ERR(clk))
                return PTR_ERR(clk);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       ci->base = devm_ioremap_resource(&pdev->dev, res);
+       ci->base = devm_platform_ioremap_resource(pdev, 1);
        if (IS_ERR(ci->base))
                return PTR_ERR(ci->base);
 
index 27749ac..26062d6 100644 (file)
@@ -523,8 +523,9 @@ int hw_device_reset(struct ci_hdrc *ci)
        hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM);
 
        if (hw_read(ci, OP_USBMODE, USBMODE_CM) != USBMODE_CM_DC) {
-               pr_err("cannot enter in %s device mode", ci_role(ci)->name);
-               pr_err("lpm = %i", ci->hw_bank.lpm);
+               dev_err(ci->dev, "cannot enter in %s device mode\n",
+                       ci_role(ci)->name);
+               dev_err(ci->dev, "lpm = %i\n", ci->hw_bank.lpm);
                return -ENODEV;
        }
 
index d8b67e1..078c1fd 100644 (file)
@@ -763,13 +763,16 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = {
                .compatible = "fsl,imx7d-usbmisc",
                .data = &imx7d_usbmisc_ops,
        },
+       {
+               .compatible = "fsl,imx7ulp-usbmisc",
+               .data = &imx7d_usbmisc_ops,
+       },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
 
 static int usbmisc_imx_probe(struct platform_device *pdev)
 {
-       struct resource *res;
        struct imx_usbmisc *data;
        const struct of_device_id *of_id;
 
@@ -783,8 +786,7 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
 
        spin_lock_init(&data->lock);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       data->base = devm_ioremap_resource(&pdev->dev, res);
+       data->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(data->base))
                return PTR_ERR(data->base);
 
index 52f3a53..f8a7989 100644 (file)
@@ -10,7 +10,7 @@ config USB_ACM
        ---help---
          This driver supports USB modems and ISDN adapters which support the
          Communication Device Class Abstract Control Model interface.
-         Please read <file:Documentation/usb/acm.txt> for details.
+         Please read <file:Documentation/usb/acm.rst> for details.
 
          If your modem only reports "Cls=ff(vend.)" in the descriptors in
          /sys/kernel/debug/usb/devices, then your modem will not work with this
index 9e9caff..a7824a5 100644 (file)
@@ -949,7 +949,7 @@ struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf,
                                        int bufsize,
                                        int (*manage_power)(struct usb_interface *, int))
 {
-       int rv = -EINVAL;
+       int rv;
 
        rv = wdm_create(intf, ep, bufsize, manage_power);
        if (rv < 0)
index 18f5dcf..1433260 100644 (file)
@@ -15,6 +15,8 @@
 #include <linux/usb/of.h>
 #include <linux/usb/otg.h>
 #include <linux/of_platform.h>
+#include <linux/debugfs.h>
+#include "common.h"
 
 static const char *const ep_type_names[] = {
        [USB_ENDPOINT_XFER_CONTROL] = "ctrl",
@@ -291,4 +293,23 @@ struct device *usb_of_get_companion_dev(struct device *dev)
 EXPORT_SYMBOL_GPL(usb_of_get_companion_dev);
 #endif
 
+struct dentry *usb_debug_root;
+EXPORT_SYMBOL_GPL(usb_debug_root);
+
+static int __init usb_common_init(void)
+{
+       usb_debug_root = debugfs_create_dir("usb", NULL);
+       ledtrig_usb_init();
+       return 0;
+}
+
+static void __exit usb_common_exit(void)
+{
+       ledtrig_usb_exit();
+       debugfs_remove_recursive(usb_debug_root);
+}
+
+subsys_initcall(usb_common_init);
+module_exit(usb_common_exit);
+
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/common/common.h b/drivers/usb/common/common.h
new file mode 100644 (file)
index 0000000..424a913
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __LINUX_USB_COMMON_H
+#define __LINUX_USB_COMMON_H
+
+#if defined(CONFIG_USB_LED_TRIG)
+void ledtrig_usb_init(void);
+void ledtrig_usb_exit(void);
+#else
+static inline void ledtrig_usb_init(void) { }
+static inline void ledtrig_usb_exit(void) { }
+#endif
+
+#endif /* __LINUX_USB_COMMON_H */
index 7bd8116..0865dd4 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/init.h>
 #include <linux/leds.h>
 #include <linux/usb.h>
+#include "common.h"
 
 #define BLINK_DELAY 30
 
@@ -36,18 +37,14 @@ void usb_led_activity(enum usb_led_event ev)
 EXPORT_SYMBOL_GPL(usb_led_activity);
 
 
-static int __init ledtrig_usb_init(void)
+void __init ledtrig_usb_init(void)
 {
        led_trigger_register_simple("usb-gadget", &ledtrig_usb_gadget);
        led_trigger_register_simple("usb-host", &ledtrig_usb_host);
-       return 0;
 }
 
-static void __exit ledtrig_usb_exit(void)
+void __exit ledtrig_usb_exit(void)
 {
        led_trigger_unregister_simple(ledtrig_usb_gadget);
        led_trigger_unregister_simple(ledtrig_usb_host);
 }
-
-module_init(ledtrig_usb_init);
-module_exit(ledtrig_usb_exit);
index bdb6bd0..ecaacc8 100644 (file)
@@ -45,7 +45,6 @@ config USB_DYNAMIC_MINORS
 config USB_OTG
        bool "OTG support"
        depends on PM
-       default n
        help
          The most notable feature of USB OTG is support for a
          "Dual-Role" device, which can act as either a device
index f641342..1359b78 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
+#include <linux/genalloc.h>
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
 
@@ -67,7 +68,7 @@ int hcd_buffer_create(struct usb_hcd *hcd)
 
        if (!IS_ENABLED(CONFIG_HAS_DMA) ||
            (!is_device_dma_capable(hcd->self.sysdev) &&
-            !(hcd->driver->flags & HCD_LOCAL_MEM)))
+            !hcd->localmem_pool))
                return 0;
 
        for (i = 0; i < HCD_BUFFER_POOLS; i++) {
@@ -124,10 +125,12 @@ void *hcd_buffer_alloc(
        if (size == 0)
                return NULL;
 
+       if (hcd->localmem_pool)
+               return gen_pool_dma_alloc(hcd->localmem_pool, size, dma);
+
        /* some USB hosts just use PIO */
        if (!IS_ENABLED(CONFIG_HAS_DMA) ||
-           (!is_device_dma_capable(bus->sysdev) &&
-            !(hcd->driver->flags & HCD_LOCAL_MEM))) {
+           !is_device_dma_capable(bus->sysdev)) {
                *dma = ~(dma_addr_t) 0;
                return kmalloc(size, mem_flags);
        }
@@ -152,9 +155,13 @@ void hcd_buffer_free(
        if (!addr)
                return;
 
+       if (hcd->localmem_pool) {
+               gen_pool_free(hcd->localmem_pool, (unsigned long)addr, size);
+               return;
+       }
+
        if (!IS_ENABLED(CONFIG_HAS_DMA) ||
-           (!is_device_dma_capable(bus->sysdev) &&
-            !(hcd->driver->flags & HCD_LOCAL_MEM))) {
+           !is_device_dma_capable(bus->sysdev)) {
                kfree(addr);
                return;
        }
index a024481..b265ab5 100644 (file)
@@ -48,9 +48,6 @@
 #define USB_DEVICE_MAX                 (USB_MAXBUS * 128)
 #define USB_SG_SIZE                    16384 /* split-size for large txs */
 
-/* Mutual exclusion for removal, open, and release */
-DEFINE_MUTEX(usbfs_mutex);
-
 struct usb_dev_state {
        struct list_head list;      /* state list */
        struct usb_device *dev;
@@ -945,9 +942,9 @@ error:
        return ret;
 }
 
-static int match_devt(struct device *dev, void *data)
+static int match_devt(struct device *dev, const void *data)
 {
-       return dev->devt == (dev_t) (unsigned long) data;
+       return dev->devt == (dev_t)(unsigned long)(void *)data;
 }
 
 static struct usb_device *usbdev_lookup_by_devt(dev_t devt)
@@ -977,15 +974,9 @@ static int usbdev_open(struct inode *inode, struct file *file)
 
        ret = -ENODEV;
 
-       /* Protect against simultaneous removal or release */
-       mutex_lock(&usbfs_mutex);
-
        /* usbdev device-node */
        if (imajor(inode) == USB_DEVICE_MAJOR)
                dev = usbdev_lookup_by_devt(inode->i_rdev);
-
-       mutex_unlock(&usbfs_mutex);
-
        if (!dev)
                goto out_free_ps;
 
@@ -1306,6 +1297,39 @@ static int proc_connectinfo(struct usb_dev_state *ps, void __user *arg)
        return 0;
 }
 
+static int proc_conninfo_ex(struct usb_dev_state *ps,
+                           void __user *arg, size_t size)
+{
+       struct usbdevfs_conninfo_ex ci;
+       struct usb_device *udev = ps->dev;
+
+       if (size < sizeof(ci.size))
+               return -EINVAL;
+
+       memset(&ci, 0, sizeof(ci));
+       ci.size = sizeof(ci);
+       ci.busnum = udev->bus->busnum;
+       ci.devnum = udev->devnum;
+       ci.speed = udev->speed;
+
+       while (udev && udev->portnum != 0) {
+               if (++ci.num_ports <= ARRAY_SIZE(ci.ports))
+                       ci.ports[ARRAY_SIZE(ci.ports) - ci.num_ports] =
+                                       udev->portnum;
+               udev = udev->parent;
+       }
+
+       if (ci.num_ports < ARRAY_SIZE(ci.ports))
+               memmove(&ci.ports[0],
+                       &ci.ports[ARRAY_SIZE(ci.ports) - ci.num_ports],
+                       ci.num_ports);
+
+       if (copy_to_user(arg, &ci, min(sizeof(ci), size)))
+               return -EFAULT;
+
+       return 0;
+}
+
 static int proc_resetdevice(struct usb_dev_state *ps)
 {
        struct usb_host_config *actconfig = ps->dev->actconfig;
@@ -1484,15 +1508,15 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
                        ret = -EFAULT;
                        goto error;
                }
-               if (uurb->buffer_length < (le16_to_cpup(&dr->wLength) + 8)) {
+               if (uurb->buffer_length < (le16_to_cpu(dr->wLength) + 8)) {
                        ret = -EINVAL;
                        goto error;
                }
                ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest,
-                                     le16_to_cpup(&dr->wIndex));
+                                     le16_to_cpu(dr->wIndex));
                if (ret)
                        goto error;
-               uurb->buffer_length = le16_to_cpup(&dr->wLength);
+               uurb->buffer_length = le16_to_cpu(dr->wLength);
                uurb->buffer += 8;
                if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
                        is_in = 1;
@@ -1507,9 +1531,9 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
                        "bRequest=%02x wValue=%04x "
                        "wIndex=%04x wLength=%04x\n",
                        dr->bRequestType, dr->bRequest,
-                       __le16_to_cpup(&dr->wValue),
-                       __le16_to_cpup(&dr->wIndex),
-                       __le16_to_cpup(&dr->wLength));
+                       __le16_to_cpu(dr->wValue),
+                       __le16_to_cpu(dr->wIndex),
+                       __le16_to_cpu(dr->wLength));
                u = sizeof(struct usb_ctrlrequest);
                break;
 
@@ -2137,6 +2161,9 @@ static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl)
        if (ps->privileges_dropped)
                return -EACCES;
 
+       if (!connected(ps))
+               return -ENODEV;
+
        /* alloc buffer */
        size = _IOC_SIZE(ctl->ioctl_code);
        if (size > 0) {
@@ -2153,11 +2180,6 @@ static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl)
                }
        }
 
-       if (!connected(ps)) {
-               kfree(buf);
-               return -ENODEV;
-       }
-
        if (ps->dev->state != USB_STATE_CONFIGURED)
                retval = -EHOSTUNREACH;
        else if (!(intf = usb_ifnum_to_if(ps->dev, ctl->ifno)))
@@ -2259,7 +2281,7 @@ static int proc_get_capabilities(struct usb_dev_state *ps, void __user *arg)
 
        caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM |
                        USBDEVFS_CAP_REAP_AFTER_DISCONNECT | USBDEVFS_CAP_MMAP |
-                       USBDEVFS_CAP_DROP_PRIVILEGES;
+                       USBDEVFS_CAP_DROP_PRIVILEGES | USBDEVFS_CAP_CONNINFO_EX;
        if (!ps->dev->bus->no_stop_on_short)
                caps |= USBDEVFS_CAP_BULK_CONTINUATION;
        if (ps->dev->bus->sg_tablesize)
@@ -2558,6 +2580,13 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
                break;
        }
 
+       /* Handle variable-length commands */
+       switch (cmd & ~IOCSIZE_MASK) {
+       case USBDEVFS_CONNINFO_EX(0):
+               ret = proc_conninfo_ex(ps, p, _IOC_SIZE(cmd));
+               break;
+       }
+
  done:
        usb_unlock_device(dev);
        if (ret >= 0)
index 94d2255..8853393 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/workqueue.h>
 #include <linux/pm_runtime.h>
 #include <linux/types.h>
+#include <linux/genalloc.h>
+#include <linux/io.h>
 
 #include <linux/phy/phy.h>
 #include <linux/usb.h>
@@ -1345,14 +1347,14 @@ EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
  * using regular system memory - like pci devices doing bus mastering.
  *
  * To support host controllers with limited dma capabilities we provide dma
- * bounce buffers. This feature can be enabled using the HCD_LOCAL_MEM flag.
+ * bounce buffers. This feature can be enabled by initializing
+ * hcd->localmem_pool using usb_hcd_setup_local_mem().
  * For this to work properly the host controller code must first use the
  * function dma_declare_coherent_memory() to point out which memory area
  * that should be used for dma allocations.
  *
- * The HCD_LOCAL_MEM flag then tells the usb code to allocate all data for
- * dma using dma_alloc_coherent() which in turn allocates from the memory
- * area pointed out with dma_declare_coherent_memory().
+ * The initialized hcd->localmem_pool then tells the usb code to allocate all
+ * data for dma using the genalloc API.
  *
  * So, to summarize...
  *
@@ -1362,9 +1364,6 @@ EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
  *   (a) "normal" kernel memory is no good, and
  *   (b) there's not enough to share
  *
- * - The only *portable* hook for such stuff in the
- *   DMA framework is dma_declare_coherent_memory()
- *
  * - So we use that, even though the primary requirement
  *   is that the memory be "local" (hence addressable
  *   by that device), not "coherent".
@@ -1531,7 +1530,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
                                                urb->setup_dma))
                                return -EAGAIN;
                        urb->transfer_flags |= URB_SETUP_MAP_SINGLE;
-               } else if (hcd->driver->flags & HCD_LOCAL_MEM) {
+               } else if (hcd->localmem_pool) {
                        ret = hcd_alloc_coherent(
                                        urb->dev->bus, mem_flags,
                                        &urb->setup_dma,
@@ -1601,7 +1600,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
                                else
                                        urb->transfer_flags |= URB_DMA_MAP_SINGLE;
                        }
-               } else if (hcd->driver->flags & HCD_LOCAL_MEM) {
+               } else if (hcd->localmem_pool) {
                        ret = hcd_alloc_coherent(
                                        urb->dev->bus, mem_flags,
                                        &urb->transfer_dma,
@@ -3039,6 +3038,40 @@ usb_hcd_platform_shutdown(struct platform_device *dev)
 }
 EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown);
 
+int usb_hcd_setup_local_mem(struct usb_hcd *hcd, phys_addr_t phys_addr,
+                           dma_addr_t dma, size_t size)
+{
+       int err;
+       void *local_mem;
+
+       hcd->localmem_pool = devm_gen_pool_create(hcd->self.sysdev, 4,
+                                                 dev_to_node(hcd->self.sysdev),
+                                                 dev_name(hcd->self.sysdev));
+       if (IS_ERR(hcd->localmem_pool))
+               return PTR_ERR(hcd->localmem_pool);
+
+       local_mem = devm_memremap(hcd->self.sysdev, phys_addr,
+                                 size, MEMREMAP_WC);
+       if (!local_mem)
+               return -ENOMEM;
+
+       /*
+        * Here we pass a dma_addr_t but the arg type is a phys_addr_t.
+        * It's not backed by system memory and thus there's no kernel mapping
+        * for it.
+        */
+       err = gen_pool_add_virt(hcd->localmem_pool, (unsigned long)local_mem,
+                               dma, size, dev_to_node(hcd->self.sysdev));
+       if (err < 0) {
+               dev_err(hcd->self.sysdev, "gen_pool_add_virt failed with %d\n",
+                       err);
+               return err;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_setup_local_mem);
+
 /*-------------------------------------------------------------------------*/
 
 #if IS_ENABLED(CONFIG_USB_MON)
index 2f94568..236313f 100644 (file)
@@ -873,7 +873,7 @@ int usb_hub_clear_tt_buffer(struct urb *urb)
        /* info that CLEAR_TT_BUFFER needs */
        clear->tt = tt->multi ? udev->ttport : 1;
        clear->devinfo = usb_pipeendpoint (pipe);
-       clear->devinfo |= udev->devnum << 4;
+       clear->devinfo |= ((u16)udev->devaddr) << 4;
        clear->devinfo |= usb_pipecontrol(pipe)
                        ? (USB_ENDPOINT_XFER_CONTROL << 11)
                        : (USB_ENDPOINT_XFER_BULK << 11);
@@ -2125,6 +2125,8 @@ static void update_devnum(struct usb_device *udev, int devnum)
        /* The address for a WUSB device is managed by wusbcore. */
        if (!udev->wusb)
                udev->devnum = devnum;
+       if (!udev->devaddr)
+               udev->devaddr = (u8)devnum;
 }
 
 static void hub_free_dev(struct usb_device *udev)
@@ -2719,7 +2721,7 @@ static bool use_new_scheme(struct usb_device *udev, int retry,
 }
 
 /* Is a USB 3.0 port in the Inactive or Compliance Mode state?
- * Port worm reset is required to recover
+ * Port warm reset is required to recover
  */
 static bool hub_port_warm_reset_required(struct usb_hub *hub, int port1,
                u16 portstatus)
@@ -3617,6 +3619,7 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
        struct usb_device *hdev;
        struct usb_device *udev;
        int connect_change = 0;
+       u16 link_state;
        int ret;
 
        hdev = hub->hdev;
@@ -3626,9 +3629,11 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
                        return 0;
                usb_clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND);
        } else {
+               link_state = portstatus & USB_PORT_STAT_LINK_STATE;
                if (!udev || udev->state != USB_STATE_SUSPENDED ||
-                                (portstatus & USB_PORT_STAT_LINK_STATE) !=
-                                USB_SS_PORT_LS_U0)
+                               (link_state != USB_SS_PORT_LS_U0 &&
+                                link_state != USB_SS_PORT_LS_U1 &&
+                                link_state != USB_SS_PORT_LS_U2))
                        return 0;
        }
 
@@ -3999,6 +4004,9 @@ static int usb_set_lpm_timeout(struct usb_device *udev,
  * control transfers to set the hub timeout or enable device-initiated U1/U2
  * will be successful.
  *
+ * If the control transfer to enable device-initiated U1/U2 entry fails, then
+ * hub-initiated U1/U2 will be disabled.
+ *
  * If we cannot set the parent hub U1/U2 timeout, we attempt to let the xHCI
  * driver know about it.  If that call fails, it should be harmless, and just
  * take up more slightly more bus bandwidth for unnecessary U1/U2 exit latency.
@@ -4053,23 +4061,24 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
                 * host know that this link state won't be enabled.
                 */
                hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
-       } else {
-               /* Only a configured device will accept the Set Feature
-                * U1/U2_ENABLE
-                */
-               if (udev->actconfig)
-                       usb_set_device_initiated_lpm(udev, state, true);
+               return;
+       }
 
-               /* As soon as usb_set_lpm_timeout(timeout) returns 0, the
-                * hub-initiated LPM is enabled. Thus, LPM is enabled no
-                * matter the result of usb_set_device_initiated_lpm().
-                * The only difference is whether device is able to initiate
-                * LPM.
-                */
+       /* Only a configured device will accept the Set Feature
+        * U1/U2_ENABLE
+        */
+       if (udev->actconfig &&
+           usb_set_device_initiated_lpm(udev, state, true) == 0) {
                if (state == USB3_LPM_U1)
                        udev->usb3_lpm_u1_enabled = 1;
                else if (state == USB3_LPM_U2)
                        udev->usb3_lpm_u2_enabled = 1;
+       } else {
+               /* Don't request U1/U2 entry if the device
+                * cannot transition to U1/U2.
+                */
+               usb_set_lpm_timeout(udev, state, 0);
+               hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
        }
 }
 
@@ -4139,7 +4148,7 @@ int usb_disable_lpm(struct usb_device *udev)
        if (!udev || !udev->parent ||
                        udev->speed < USB_SPEED_SUPER ||
                        !udev->lpm_capable ||
-                       udev->state < USB_STATE_DEFAULT)
+                       udev->state < USB_STATE_CONFIGURED)
                return 0;
 
        hcd = bus_to_hcd(udev->bus);
@@ -4198,7 +4207,7 @@ void usb_enable_lpm(struct usb_device *udev)
        if (!udev || !udev->parent ||
                        udev->speed < USB_SPEED_SUPER ||
                        !udev->lpm_capable ||
-                       udev->state < USB_STATE_DEFAULT)
+                       udev->state < USB_STATE_CONFIGURED)
                return;
 
        udev->lpm_disable_count--;
index ab474b1..e614366 100644 (file)
@@ -53,11 +53,8 @@ void usb_notify_add_device(struct usb_device *udev)
 
 void usb_notify_remove_device(struct usb_device *udev)
 {
-       /* Protect against simultaneous usbfs open */
-       mutex_lock(&usbfs_mutex);
        blocking_notifier_call_chain(&usb_notifier_list,
                        USB_DEVICE_REMOVE, udev);
-       mutex_unlock(&usbfs_mutex);
 }
 
 void usb_notify_add_bus(struct usb_bus *ubus)
index 7fcb9f7..0ab8738 100644 (file)
@@ -325,9 +325,9 @@ struct find_interface_arg {
        struct device_driver *drv;
 };
 
-static int __find_interface(struct device *dev, void *data)
+static int __find_interface(struct device *dev, const void *data)
 {
-       struct find_interface_arg *arg = data;
+       const struct find_interface_arg *arg = data;
        struct usb_interface *intf;
 
        if (!is_usb_interface(dev))
@@ -1185,19 +1185,17 @@ static struct notifier_block usb_bus_nb = {
        .notifier_call = usb_bus_notify,
 };
 
-struct dentry *usb_debug_root;
-EXPORT_SYMBOL_GPL(usb_debug_root);
+static struct dentry *usb_devices_root;
 
 static void usb_debugfs_init(void)
 {
-       usb_debug_root = debugfs_create_dir("usb", NULL);
-       debugfs_create_file("devices", 0444, usb_debug_root, NULL,
-                           &usbfs_devices_fops);
+       usb_devices_root = debugfs_create_file("devices", 0444, usb_debug_root,
+                                              NULL, &usbfs_devices_fops);
 }
 
 static void usb_debugfs_cleanup(void)
 {
-       debugfs_remove_recursive(usb_debug_root);
+       debugfs_remove(usb_devices_root);
 }
 
 /*
index d95a535..bd8d01f 100644 (file)
@@ -169,7 +169,6 @@ extern const struct attribute_group *usb_device_groups[];
 extern const struct attribute_group *usb_interface_groups[];
 
 /* usbfs stuff */
-extern struct mutex usbfs_mutex;
 extern struct usb_driver usbfs_driver;
 extern const struct file_operations usbfs_devices_fops;
 extern const struct file_operations usbdev_file_operations;
index 68d095a..16e1aa3 100644 (file)
@@ -58,7 +58,6 @@ config USB_DWC2_PCI
        tristate "DWC2 PCI"
        depends on USB_PCI
        depends on USB_GADGET || !USB_GADGET
-       default n
        select NOP_USB_XCEIV
        help
          The Designware USB2.0 PCI interface module for controllers
index 8b499d6..8e41d70 100644 (file)
@@ -531,7 +531,7 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
        }
 
        /* Wait for AHB master IDLE state */
-       if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 50)) {
+       if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000)) {
                dev_warn(hsotg->dev, "%s: HANG! AHB Idle timeout GRSTCTL GRSTCTL_AHBIDLE\n",
                         __func__);
                return -EBUSY;
index 152ac41..d08d070 100644 (file)
@@ -861,6 +861,9 @@ struct dwc2_hregs_backup {
  * @hibernated:                True if core is hibernated
  * @reset_phy_on_wake: Quirk saying that we should assert PHY reset on a
  *                     remote wakeup.
+ * @phy_off_for_suspend: Status of whether we turned the PHY off at suspend.
+ * @need_phy_for_wake: Quirk saying that we should keep the PHY on at
+ *                     suspend if we need USB to wake us up.
  * @frame_number:       Frame number read from the core. For both device
  *                     and host modes. The value ranges are from 0
  *                     to HFNUM_MAX_FRNUM.
@@ -1049,6 +1052,8 @@ struct dwc2_hsotg {
        unsigned int ll_hw_enabled:1;
        unsigned int hibernated:1;
        unsigned int reset_phy_on_wake:1;
+       unsigned int need_phy_for_wake:1;
+       unsigned int phy_off_for_suspend:1;
        u16 frame_number;
 
        struct phy *phy;
@@ -1438,6 +1443,7 @@ int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg);
 int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg);
 int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg,
                               int rem_wakeup, int reset);
+bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2);
 static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg)
 { schedule_work(&hsotg->phy_reset_work); }
 #else
@@ -1463,6 +1469,8 @@ static inline int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg)
 static inline int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg,
                                             int rem_wakeup, int reset)
 { return 0; }
+static inline bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2)
+{ return false; }
 static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg) {}
 
 #endif
index 2192a28..ee144ff 100644 (file)
@@ -4685,7 +4685,6 @@ fail2:
        spin_unlock_irqrestore(&hsotg->lock, flags);
        urb->hcpriv = NULL;
        kfree(qtd);
-       qtd = NULL;
 fail1:
        if (qh_allocated) {
                struct dwc2_qtd *qtd2, *qtd2_tmp;
@@ -5587,3 +5586,22 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
        dev_dbg(hsotg->dev, "Host hibernation restore complete\n");
        return ret;
 }
+
+bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2)
+{
+       struct usb_device *root_hub = dwc2_hsotg_to_hcd(dwc2)->self.root_hub;
+
+       /* If the controller isn't allowed to wakeup then we can power off. */
+       if (!device_may_wakeup(dwc2->dev))
+               return true;
+
+       /*
+        * We don't want to power off the PHY if something under the
+        * root hub has wakeup enabled.
+        */
+       if (usb_wakeup_enabled_descendants(root_hub))
+               return false;
+
+       /* No reason to keep the PHY powered, so allow poweroff */
+       return true;
+}
index ce6445a..8ca6d12 100644 (file)
@@ -582,7 +582,6 @@ static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg,
 {
        list_del(&qtd->qtd_list_entry);
        kfree(qtd);
-       qtd = NULL;
 }
 
 /* Descriptor DMA support functions */
index 5949262..55f841a 100644 (file)
@@ -76,6 +76,7 @@ static void dwc2_set_s3c6400_params(struct dwc2_hsotg *hsotg)
        struct dwc2_core_params *p = &hsotg->params;
 
        p->power_down = 0;
+       p->phy_utmi_width = 8;
 }
 
 static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg)
index e98d781..80fd3c6 100644 (file)
@@ -438,6 +438,10 @@ static int dwc2_driver_probe(struct platform_device *dev)
        if (retval)
                goto error;
 
+       hsotg->need_phy_for_wake =
+               of_property_read_bool(dev->dev.of_node,
+                                     "snps,need-phy-for-wake");
+
        /*
         * Reset before dwc2_get_hwparams() then it could get power-on real
         * reset value form registers.
@@ -469,6 +473,14 @@ static int dwc2_driver_probe(struct platform_device *dev)
                hsotg->gadget_enabled = 1;
        }
 
+       /*
+        * If we need PHY for wakeup we must be wakeup capable.
+        * When we have a device that can wake without the PHY we
+        * can adjust this condition.
+        */
+       if (hsotg->need_phy_for_wake)
+               device_set_wakeup_capable(&dev->dev, true);
+
        hsotg->reset_phy_on_wake =
                of_property_read_bool(dev->dev.of_node,
                                      "snps,reset-phy-on-wake");
@@ -507,13 +519,17 @@ error:
 static int __maybe_unused dwc2_suspend(struct device *dev)
 {
        struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
+       bool is_device_mode = dwc2_is_device_mode(dwc2);
        int ret = 0;
 
-       if (dwc2_is_device_mode(dwc2))
+       if (is_device_mode)
                dwc2_hsotg_suspend(dwc2);
 
-       if (dwc2->ll_hw_enabled)
+       if (dwc2->ll_hw_enabled &&
+           (is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) {
                ret = __dwc2_lowlevel_hw_disable(dwc2);
+               dwc2->phy_off_for_suspend = true;
+       }
 
        return ret;
 }
@@ -523,11 +539,12 @@ static int __maybe_unused dwc2_resume(struct device *dev)
        struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
        int ret = 0;
 
-       if (dwc2->ll_hw_enabled) {
+       if (dwc2->phy_off_for_suspend && dwc2->ll_hw_enabled) {
                ret = __dwc2_lowlevel_hw_enable(dwc2);
                if (ret)
                        return ret;
        }
+       dwc2->phy_off_for_suspend = false;
 
        if (dwc2_is_device_mode(dwc2))
                ret = dwc2_hsotg_resume(dwc2);
index 4a62045..89abc60 100644 (file)
@@ -128,7 +128,7 @@ config USB_DWC3_QCOM
        tristate "Qualcomm Platform"
        depends on ARCH_QCOM || COMPILE_TEST
        depends on EXTCON || !EXTCON
-       depends on OF
+       depends on (OF || ACPI)
        default USB_DWC3
        help
          Some Qualcomm SoCs use DesignWare Core IP for USB2/3
index 4aff1d8..c9bb93a 100644 (file)
@@ -1282,6 +1282,10 @@ static void dwc3_get_properties(struct dwc3 *dwc)
                                "snps,dis_u2_susphy_quirk");
        dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
                                "snps,dis_enblslpm_quirk");
+       dwc->dis_u1_entry_quirk = device_property_read_bool(dev,
+                               "snps,dis-u1-entry-quirk");
+       dwc->dis_u2_entry_quirk = device_property_read_bool(dev,
+                               "snps,dis-u2-entry-quirk");
        dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
                                "snps,dis_rxdet_inp3_quirk");
        dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
@@ -1423,11 +1427,6 @@ static int dwc3_probe(struct platform_device *pdev)
        dwc->regs       = regs;
        dwc->regs_size  = resource_size(&dwc_res);
 
-       if (!dwc3_core_is_valid(dwc)) {
-               dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
-               return -ENODEV;
-       }
-
        dwc3_get_properties(dwc);
 
        dwc->reset = devm_reset_control_get_optional_shared(dev, NULL);
@@ -1460,6 +1459,12 @@ static int dwc3_probe(struct platform_device *pdev)
        if (ret)
                goto unprepare_clks;
 
+       if (!dwc3_core_is_valid(dwc)) {
+               dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
+               ret = -ENODEV;
+               goto disable_clks;
+       }
+
        platform_set_drvdata(pdev, dwc);
        dwc3_cache_hwparams(dwc);
 
@@ -1525,6 +1530,7 @@ err1:
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
+disable_clks:
        clk_bulk_disable(dwc->num_clks, dwc->clks);
 unprepare_clks:
        clk_bulk_unprepare(dwc->num_clks, dwc->clks);
index f19cbeb..3dd783b 100644 (file)
@@ -649,7 +649,6 @@ struct dwc3_event_buffer {
  * @cancelled_list: list of cancelled requests for this endpoint
  * @pending_list: list of pending requests for this endpoint
  * @started_list: list of started requests on this endpoint
- * @lock: spinlock for endpoint request queue traversal
  * @regs: pointer to first endpoint register
  * @trb_pool: array of transaction buffers
  * @trb_pool_dma: dma address of @trb_pool
@@ -677,7 +676,6 @@ struct dwc3_ep {
        struct list_head        pending_list;
        struct list_head        started_list;
 
-       spinlock_t              lock;
        void __iomem            *regs;
 
        struct dwc3_trb         *trb_pool;
@@ -1014,6 +1012,8 @@ struct dwc3_scratchpad_array {
  * @dis_u2_susphy_quirk: set if we disable usb2 suspend phy
  * @dis_enblslpm_quirk: set if we clear enblslpm in GUSB2PHYCFG,
  *                      disabling the suspend signal to the PHY.
+ * @dis_u1_entry_quirk: set if link entering into U1 state needs to be disabled.
+ * @dis_u2_entry_quirk: set if link entering into U2 state needs to be disabled.
  * @dis_rxdet_inp3_quirk: set if we disable Rx.Detect in P3
  * @dis_u2_freeclk_exists_quirk : set if we clear u2_freeclk_exists
  *                     in GUSB2PHYCFG, specify that USB2 PHY doesn't
@@ -1205,6 +1205,8 @@ struct dwc3 {
        unsigned                dis_u3_susphy_quirk:1;
        unsigned                dis_u2_susphy_quirk:1;
        unsigned                dis_enblslpm_quirk:1;
+       unsigned                dis_u1_entry_quirk:1;
+       unsigned                dis_u2_entry_quirk:1;
        unsigned                dis_rxdet_inp3_quirk:1;
        unsigned                dis_u2_freeclk_exists_quirk:1;
        unsigned                dis_del_phy_power_chg_quirk:1;
index 2aec31a..bca7e92 100644 (file)
@@ -11,9 +11,7 @@
  * - Control registers for each USB2 Ports
  * - Control registers for the USB PHY layer
  * - SuperSpeed PHY can be enabled only if port is used
- *
- * TOFIX:
- * - Add dynamic OTG switching with ID change interrupt
+ * - Dynamic OTG switching with ID change interrupt
  */
 
 #include <linux/module.h>
@@ -348,6 +346,22 @@ static enum usb_role dwc3_meson_g12a_role_get(struct device *dev)
                USB_ROLE_HOST : USB_ROLE_DEVICE;
 }
 
+static irqreturn_t dwc3_meson_g12a_irq_thread(int irq, void *data)
+{
+       struct dwc3_meson_g12a *priv = data;
+       enum phy_mode otg_id;
+
+       otg_id = dwc3_meson_g12a_get_id(priv);
+       if (otg_id != priv->otg_phy_mode) {
+               if (dwc3_meson_g12a_otg_mode_set(priv, otg_id))
+                       dev_warn(priv->dev, "Failed to switch OTG mode\n");
+       }
+
+       regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_IRQ, 0);
+
+       return IRQ_HANDLED;
+}
+
 static struct device *dwc3_meson_g12_find_child(struct device *dev,
                                                const char *compatible)
 {
@@ -374,7 +388,7 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
        void __iomem *base;
        struct resource *res;
        enum phy_mode otg_id;
-       int ret, i;
+       int ret, i, irq;
 
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
@@ -436,6 +450,19 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
        /* Get dr_mode */
        priv->otg_mode = usb_get_dr_mode(dev);
 
+       if (priv->otg_mode == USB_DR_MODE_OTG) {
+               /* Ack irq before registering */
+               regmap_update_bits(priv->regmap, USB_R5,
+                                  USB_R5_ID_DIG_IRQ, 0);
+
+               irq = platform_get_irq(pdev, 0);
+               ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+                                               dwc3_meson_g12a_irq_thread,
+                                               IRQF_ONESHOT, pdev->name, priv);
+               if (ret)
+                       return ret;
+       }
+
        dwc3_meson_g12a_usb_init(priv);
 
        /* Init PHYs */
@@ -460,7 +487,6 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
 
        /* Setup OTG mode corresponding to the ID pin */
        if (priv->otg_mode == USB_DR_MODE_OTG) {
-               /* TOFIX Handle ID mode toggling via IRQ */
                otg_id = dwc3_meson_g12a_get_id(priv);
                if (otg_id != priv->otg_phy_mode) {
                        if (dwc3_meson_g12a_otg_mode_set(priv, otg_id))
index 8cced36..5e8e182 100644 (file)
@@ -34,6 +34,8 @@
 #define PCI_DEVICE_ID_INTEL_CNPLP              0x9dee
 #define PCI_DEVICE_ID_INTEL_CNPH               0xa36e
 #define PCI_DEVICE_ID_INTEL_ICLLP              0x34ee
+#define PCI_DEVICE_ID_INTEL_EHLLP              0x4b7e
+#define PCI_DEVICE_ID_INTEL_TGPLP              0xa0ee
 
 #define PCI_INTEL_BXT_DSM_GUID         "732b85d5-b7a7-4a1b-9ba0-4bbd00ffd511"
 #define PCI_INTEL_BXT_FUNC_PMU_PWR     4
@@ -339,6 +341,12 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICLLP),
          (kernel_ulong_t) &dwc3_pci_intel_properties, },
 
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHLLP),
+         (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPLP),
+         (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_NL_USB),
          (kernel_ulong_t) &dwc3_pci_amd_properties, },
        {  }    /* Terminating Entry */
index 184df4d..261af9e 100644 (file)
@@ -4,6 +4,7 @@
  * Inspired by dwc3-of-simple.c
  */
 
+#include <linux/acpi.h>
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/clk.h>
 #define PWR_EVNT_LPM_IN_L2_MASK                        BIT(4)
 #define PWR_EVNT_LPM_OUT_L2_MASK               BIT(5)
 
+#define SDM845_QSCRATCH_BASE_OFFSET            0xf8800
+#define SDM845_QSCRATCH_SIZE                   0x400
+#define SDM845_DWC3_CORE_SIZE                  0xcd00
+
+struct dwc3_acpi_pdata {
+       u32                     qscratch_base_offset;
+       u32                     qscratch_base_size;
+       u32                     dwc3_core_base_size;
+       int                     hs_phy_irq_index;
+       int                     dp_hs_phy_irq_index;
+       int                     dm_hs_phy_irq_index;
+       int                     ss_phy_irq_index;
+};
+
 struct dwc3_qcom {
        struct device           *dev;
        void __iomem            *qscratch_base;
@@ -56,6 +71,8 @@ struct dwc3_qcom {
        struct notifier_block   vbus_nb;
        struct notifier_block   host_nb;
 
+       const struct dwc3_acpi_pdata *acpi_pdata;
+
        enum usb_dr_mode        mode;
        bool                    is_suspended;
        bool                    pm_suspended;
@@ -300,12 +317,27 @@ static void dwc3_qcom_select_utmi_clk(struct dwc3_qcom *qcom)
                          PIPE_UTMI_CLK_DIS);
 }
 
+static int dwc3_qcom_get_irq(struct platform_device *pdev,
+                            const char *name, int num)
+{
+       struct device_node *np = pdev->dev.of_node;
+       int ret;
+
+       if (np)
+               ret = platform_get_irq_byname(pdev, name);
+       else
+               ret = platform_get_irq(pdev, num);
+
+       return ret;
+}
+
 static int dwc3_qcom_setup_irq(struct platform_device *pdev)
 {
        struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
+       const struct dwc3_acpi_pdata *pdata = qcom->acpi_pdata;
        int irq, ret;
-
-       irq = platform_get_irq_byname(pdev, "hs_phy_irq");
+       irq = dwc3_qcom_get_irq(pdev, "hs_phy_irq",
+                               pdata ? pdata->hs_phy_irq_index : -1);
        if (irq > 0) {
                /* Keep wakeup interrupts disabled until suspend */
                irq_set_status_flags(irq, IRQ_NOAUTOEN);
@@ -320,7 +352,8 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
                qcom->hs_phy_irq = irq;
        }
 
-       irq = platform_get_irq_byname(pdev, "dp_hs_phy_irq");
+       irq = dwc3_qcom_get_irq(pdev, "dp_hs_phy_irq",
+                               pdata ? pdata->dp_hs_phy_irq_index : -1);
        if (irq > 0) {
                irq_set_status_flags(irq, IRQ_NOAUTOEN);
                ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
@@ -334,7 +367,8 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
                qcom->dp_hs_phy_irq = irq;
        }
 
-       irq = platform_get_irq_byname(pdev, "dm_hs_phy_irq");
+       irq = dwc3_qcom_get_irq(pdev, "dm_hs_phy_irq",
+                               pdata ? pdata->dm_hs_phy_irq_index : -1);
        if (irq > 0) {
                irq_set_status_flags(irq, IRQ_NOAUTOEN);
                ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
@@ -348,7 +382,8 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
                qcom->dm_hs_phy_irq = irq;
        }
 
-       irq = platform_get_irq_byname(pdev, "ss_phy_irq");
+       irq = dwc3_qcom_get_irq(pdev, "ss_phy_irq",
+                               pdata ? pdata->ss_phy_irq_index : -1);
        if (irq > 0) {
                irq_set_status_flags(irq, IRQ_NOAUTOEN);
                ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
@@ -371,11 +406,14 @@ static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
        struct device_node      *np = dev->of_node;
        int                     i;
 
-       qcom->num_clocks = count;
-
-       if (!count)
+       if (!np || !count)
                return 0;
 
+       if (count < 0)
+               return count;
+
+       qcom->num_clocks = count;
+
        qcom->clks = devm_kcalloc(dev, qcom->num_clocks,
                                  sizeof(struct clk *), GFP_KERNEL);
        if (!qcom->clks)
@@ -409,12 +447,115 @@ static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
        return 0;
 }
 
-static int dwc3_qcom_probe(struct platform_device *pdev)
+static const struct property_entry dwc3_qcom_acpi_properties[] = {
+       PROPERTY_ENTRY_STRING("dr_mode", "host"),
+       {}
+};
+
+static int dwc3_qcom_acpi_register_core(struct platform_device *pdev)
+{
+       struct dwc3_qcom        *qcom = platform_get_drvdata(pdev);
+       struct device           *dev = &pdev->dev;
+       struct resource         *res, *child_res = NULL;
+       int                     irq;
+       int                     ret;
+
+       qcom->dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
+       if (!qcom->dwc3)
+               return -ENOMEM;
+
+       qcom->dwc3->dev.parent = dev;
+       qcom->dwc3->dev.type = dev->type;
+       qcom->dwc3->dev.dma_mask = dev->dma_mask;
+       qcom->dwc3->dev.dma_parms = dev->dma_parms;
+       qcom->dwc3->dev.coherent_dma_mask = dev->coherent_dma_mask;
+
+       child_res = kcalloc(2, sizeof(*child_res), GFP_KERNEL);
+       if (!child_res)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "failed to get memory resource\n");
+               ret = -ENODEV;
+               goto out;
+       }
+
+       child_res[0].flags = res->flags;
+       child_res[0].start = res->start;
+       child_res[0].end = child_res[0].start +
+               qcom->acpi_pdata->dwc3_core_base_size;
+
+       irq = platform_get_irq(pdev, 0);
+       child_res[1].flags = IORESOURCE_IRQ;
+       child_res[1].start = child_res[1].end = irq;
+
+       ret = platform_device_add_resources(qcom->dwc3, child_res, 2);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to add resources\n");
+               goto out;
+       }
+
+       ret = platform_device_add_properties(qcom->dwc3,
+                                            dwc3_qcom_acpi_properties);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to add properties\n");
+               goto out;
+       }
+
+       ret = platform_device_add(qcom->dwc3);
+       if (ret)
+               dev_err(&pdev->dev, "failed to add device\n");
+
+out:
+       kfree(child_res);
+       return ret;
+}
+
+static int dwc3_qcom_of_register_core(struct platform_device *pdev)
 {
+       struct dwc3_qcom        *qcom = platform_get_drvdata(pdev);
        struct device_node      *np = pdev->dev.of_node, *dwc3_np;
        struct device           *dev = &pdev->dev;
+       int                     ret;
+
+       dwc3_np = of_get_child_by_name(np, "dwc3");
+       if (!dwc3_np) {
+               dev_err(dev, "failed to find dwc3 core child\n");
+               return -ENODEV;
+       }
+
+       ret = of_platform_populate(np, NULL, NULL, dev);
+       if (ret) {
+               dev_err(dev, "failed to register dwc3 core - %d\n", ret);
+               return ret;
+       }
+
+       qcom->dwc3 = of_find_device_by_node(dwc3_np);
+       if (!qcom->dwc3) {
+               dev_err(dev, "failed to get dwc3 platform device\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static const struct dwc3_acpi_pdata sdm845_acpi_pdata = {
+       .qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET,
+       .qscratch_base_size = SDM845_QSCRATCH_SIZE,
+       .dwc3_core_base_size = SDM845_DWC3_CORE_SIZE,
+       .hs_phy_irq_index = 1,
+       .dp_hs_phy_irq_index = 4,
+       .dm_hs_phy_irq_index = 3,
+       .ss_phy_irq_index = 2
+};
+
+static int dwc3_qcom_probe(struct platform_device *pdev)
+{
+       struct device_node      *np = pdev->dev.of_node;
+       struct device           *dev = &pdev->dev;
        struct dwc3_qcom        *qcom;
-       struct resource         *res;
+       struct resource         *res, *parent_res = NULL;
        int                     ret, i;
        bool                    ignore_pipe_clk;
 
@@ -425,6 +566,14 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, qcom);
        qcom->dev = &pdev->dev;
 
+       if (has_acpi_companion(dev)) {
+               qcom->acpi_pdata = acpi_device_get_match_data(dev);
+               if (!qcom->acpi_pdata) {
+                       dev_err(&pdev->dev, "no supporting ACPI device data\n");
+                       return -EINVAL;
+               }
+       }
+
        qcom->resets = devm_reset_control_array_get_optional_exclusive(dev);
        if (IS_ERR(qcom->resets)) {
                ret = PTR_ERR(qcom->resets);
@@ -446,15 +595,28 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
                goto reset_assert;
        }
 
-       ret = dwc3_qcom_clk_init(qcom, of_count_phandle_with_args(np,
-                                               "clocks", "#clock-cells"));
+       ret = dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np));
        if (ret) {
                dev_err(dev, "failed to get clocks\n");
                goto reset_assert;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       qcom->qscratch_base = devm_ioremap_resource(dev, res);
+
+       if (np) {
+               parent_res = res;
+       } else {
+               parent_res = kmemdup(res, sizeof(struct resource), GFP_KERNEL);
+               if (!parent_res)
+                       return -ENOMEM;
+
+               parent_res->start = res->start +
+                       qcom->acpi_pdata->qscratch_base_offset;
+               parent_res->end = parent_res->start +
+                       qcom->acpi_pdata->qscratch_base_size;
+       }
+
+       qcom->qscratch_base = devm_ioremap_resource(dev, parent_res);
        if (IS_ERR(qcom->qscratch_base)) {
                dev_err(dev, "failed to map qscratch, err=%d\n", ret);
                ret = PTR_ERR(qcom->qscratch_base);
@@ -462,13 +624,8 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
        }
 
        ret = dwc3_qcom_setup_irq(pdev);
-       if (ret)
-               goto clk_disable;
-
-       dwc3_np = of_get_child_by_name(np, "dwc3");
-       if (!dwc3_np) {
-               dev_err(dev, "failed to find dwc3 core child\n");
-               ret = -ENODEV;
+       if (ret) {
+               dev_err(dev, "failed to setup IRQs, err=%d\n", ret);
                goto clk_disable;
        }
 
@@ -481,16 +638,13 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
        if (ignore_pipe_clk)
                dwc3_qcom_select_utmi_clk(qcom);
 
-       ret = of_platform_populate(np, NULL, NULL, dev);
-       if (ret) {
-               dev_err(dev, "failed to register dwc3 core - %d\n", ret);
-               goto clk_disable;
-       }
+       if (np)
+               ret = dwc3_qcom_of_register_core(pdev);
+       else
+               ret = dwc3_qcom_acpi_register_core(pdev);
 
-       qcom->dwc3 = of_find_device_by_node(dwc3_np);
-       if (!qcom->dwc3) {
-               dev_err(&pdev->dev, "failed to get dwc3 platform device\n");
-               ret = -ENODEV;
+       if (ret) {
+               dev_err(dev, "failed to register DWC3 Core, err=%d\n", ret);
                goto depopulate;
        }
 
@@ -514,7 +668,10 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
        return 0;
 
 depopulate:
-       of_platform_depopulate(&pdev->dev);
+       if (np)
+               of_platform_depopulate(&pdev->dev);
+       else
+               platform_device_put(pdev);
 clk_disable:
        for (i = qcom->num_clocks - 1; i >= 0; i--) {
                clk_disable_unprepare(qcom->clks[i]);
@@ -601,6 +758,12 @@ static const struct of_device_id dwc3_qcom_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match);
 
+static const struct acpi_device_id dwc3_qcom_acpi_match[] = {
+       { "QCOM2430", (unsigned long)&sdm845_acpi_pdata },
+       { },
+};
+MODULE_DEVICE_TABLE(acpi, dwc3_qcom_acpi_match);
+
 static struct platform_driver dwc3_qcom_driver = {
        .probe          = dwc3_qcom_probe,
        .remove         = dwc3_qcom_remove,
@@ -608,6 +771,7 @@ static struct platform_driver dwc3_qcom_driver = {
                .name   = "dwc3-qcom",
                .pm     = &dwc3_qcom_dev_pm_ops,
                .of_match_table = dwc3_qcom_of_match,
+               .acpi_match_table = ACPI_PTR(dwc3_qcom_acpi_match),
        },
 };
 
index 8efde17..3996b9c 100644 (file)
@@ -379,6 +379,8 @@ static int dwc3_ep0_handle_u1(struct dwc3 *dwc, enum usb_device_state state,
        if ((dwc->speed != DWC3_DSTS_SUPERSPEED) &&
                        (dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS))
                return -EINVAL;
+       if (set && dwc->dis_u1_entry_quirk)
+               return -EINVAL;
 
        reg = dwc3_readl(dwc->regs, DWC3_DCTL);
        if (set)
@@ -401,6 +403,8 @@ static int dwc3_ep0_handle_u2(struct dwc3 *dwc, enum usb_device_state state,
        if ((dwc->speed != DWC3_DSTS_SUPERSPEED) &&
                        (dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS))
                return -EINVAL;
+       if (set && dwc->dis_u2_entry_quirk)
+               return -EINVAL;
 
        reg = dwc3_readl(dwc->regs, DWC3_DCTL);
        if (set)
@@ -626,7 +630,10 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
                         * nothing is pending from application.
                         */
                        reg = dwc3_readl(dwc->regs, DWC3_DCTL);
-                       reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA);
+                       if (!dwc->dis_u1_entry_quirk)
+                               reg |= DWC3_DCTL_ACCEPTU1ENA;
+                       if (!dwc->dis_u2_entry_quirk)
+                               reg |= DWC3_DCTL_ACCEPTU2ENA;
                        dwc3_writel(dwc->regs, DWC3_DCTL, reg);
                }
                break;
index d676553..173f532 100644 (file)
@@ -2073,6 +2073,25 @@ out:
        return 0;
 }
 
+static void dwc3_gadget_config_params(struct usb_gadget *g,
+                                     struct usb_dcd_config_params *params)
+{
+       struct dwc3             *dwc = gadget_to_dwc(g);
+
+       /* U1 Device exit Latency */
+       if (dwc->dis_u1_entry_quirk)
+               params->bU1devExitLat = 0;
+       else
+               params->bU1devExitLat = DWC3_DEFAULT_U1_DEV_EXIT_LAT;
+
+       /* U2 Device exit Latency */
+       if (dwc->dis_u2_entry_quirk)
+               params->bU2DevExitLat = 0;
+       else
+               params->bU2DevExitLat =
+                               cpu_to_le16(DWC3_DEFAULT_U2_DEV_EXIT_LAT);
+}
+
 static void dwc3_gadget_set_speed(struct usb_gadget *g,
                                  enum usb_device_speed speed)
 {
@@ -2142,6 +2161,7 @@ static const struct usb_gadget_ops dwc3_gadget_ops = {
        .udc_start              = dwc3_gadget_start,
        .udc_stop               = dwc3_gadget_stop,
        .udc_set_speed          = dwc3_gadget_set_speed,
+       .get_config_params      = dwc3_gadget_config_params,
 };
 
 /* -------------------------------------------------------------------------- */
@@ -2251,8 +2271,6 @@ static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum)
                dep->endpoint.comp_desc = NULL;
        }
 
-       spin_lock_init(&dep->lock);
-
        if (num == 0)
                ret = dwc3_gadget_init_control_endpoint(dep);
        else if (direction)
index 3ed738e..5faf4d1 100644 (file)
@@ -48,6 +48,12 @@ struct dwc3;
 /* DEPXFERCFG parameter 0 */
 #define DWC3_DEPXFERCFG_NUM_XFER_RES(n)        ((n) & 0xffff)
 
+/* U1 Device exit Latency */
+#define DWC3_DEFAULT_U1_DEV_EXIT_LAT   0x0A    /* Less then 10 microsec */
+
+/* U2 Device exit Latency */
+#define DWC3_DEFAULT_U2_DEV_EXIT_LAT   0x1FF   /* Less then 511 microsec */
+
 /* -------------------------------------------------------------------------- */
 
 #define to_dwc3_request(r)     (container_of(r, struct dwc3_request, request))
index ec189d7..02ff850 100644 (file)
@@ -228,7 +228,7 @@ config USB_CONFIGFS
          specified simply by creating appropriate directories in configfs.
          Associating functions with configurations is done by creating
          appropriate symbolic links.
-         For more information see Documentation/usb/gadget_configfs.txt.
+         For more information see Documentation/usb/gadget_configfs.rst.
 
 config USB_CONFIGFS_SERIAL
        bool "Generic serial bulk in/out"
@@ -441,7 +441,7 @@ config USB_CONFIGFS_F_HID
          The HID function driver provides generic emulation of USB
          Human Interface Devices (HID).
 
-         For more information, see Documentation/usb/gadget_hid.txt.
+         For more information, see Documentation/usb/gadget_hid.rst.
 
 config USB_CONFIGFS_F_UVC
        bool "USB Webcam function"
@@ -466,7 +466,7 @@ config USB_CONFIGFS_F_PRINTER
          receive or send printer data. It can use ioctl calls to
          the device file to get or set printer status.
 
-         For more information, see Documentation/usb/gadget_printer.txt
+         For more information, see Documentation/usb/gadget_printer.rst
          which includes sample code for accessing the device file.
 
 config USB_CONFIGFS_F_TCM
index b8a1584..9118b42 100644 (file)
@@ -653,7 +653,7 @@ static int bos_desc(struct usb_composite_dev *cdev)
 
                /* Get Controller configuration */
                if (cdev->gadget->ops->get_config_params) {
-                       cdev->gadget->ops->get_config_params(
+                       cdev->gadget->ops->get_config_params(cdev->gadget,
                                &dcd_config_params);
                } else {
                        dcd_config_params.bU1devExitLat =
index c13befa..b81a91d 100644 (file)
@@ -166,7 +166,6 @@ static struct usb_gadget_strings *eem_strings[] = {
 static int eem_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
 {
        struct usb_composite_dev *cdev = f->config->cdev;
-       int                     value = -EOPNOTSUPP;
        u16                     w_index = le16_to_cpu(ctrl->wIndex);
        u16                     w_value = le16_to_cpu(ctrl->wValue);
        u16                     w_length = le16_to_cpu(ctrl->wLength);
@@ -176,7 +175,7 @@ static int eem_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
                w_value, w_index, w_length);
 
        /* device either stalls (value < 0) or reports success */
-       return value;
+       return -EOPNOTSUPP;
 }
 
 
index 47be961..213ff03 100644 (file)
@@ -997,7 +997,6 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
                 * earlier
                 */
                gadget = epfile->ffs->gadget;
-               io_data->use_sg = gadget->sg_supported && data_len > PAGE_SIZE;
 
                spin_lock_irq(&epfile->ffs->eps_lock);
                /* In the meantime, endpoint got disabled or changed. */
@@ -1012,6 +1011,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
                 */
                if (io_data->read)
                        data_len = usb_ep_align_maybe(gadget, ep->ep, data_len);
+
+               io_data->use_sg = gadget->sg_supported && data_len > PAGE_SIZE;
                spin_unlock_irq(&epfile->ffs->eps_lock);
 
                data = ffs_alloc_buffer(io_data, data_len);
@@ -1182,11 +1183,12 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
        ENTER();
 
        if (!is_sync_kiocb(kiocb)) {
-               p = kmalloc(sizeof(io_data), GFP_KERNEL);
+               p = kzalloc(sizeof(io_data), GFP_KERNEL);
                if (unlikely(!p))
                        return -ENOMEM;
                p->aio = true;
        } else {
+               memset(p, 0, sizeof(*p));
                p->aio = false;
        }
 
@@ -1218,11 +1220,12 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
        ENTER();
 
        if (!is_sync_kiocb(kiocb)) {
-               p = kmalloc(sizeof(io_data), GFP_KERNEL);
+               p = kzalloc(sizeof(io_data), GFP_KERNEL);
                if (unlikely(!p))
                        return -ENOMEM;
                p->aio = true;
        } else {
+               memset(p, 0, sizeof(*p));
                p->aio = false;
        }
 
index 043f97a..29cc569 100644 (file)
@@ -47,7 +47,7 @@
  *
  * For more information about MSF and in particular its module
  * parameters and sysfs interface read the
- * <Documentation/usb/mass-storage.txt> file.
+ * <Documentation/usb/mass-storage.rst> file.
  */
 
 /*
index fb5ed97..56906d1 100644 (file)
@@ -40,7 +40,7 @@ struct uac_rtd_params {
 
        void *rbuf;
 
-       unsigned max_psize;     /* MaxPacketSize of endpoint */
+       unsigned int max_psize; /* MaxPacketSize of endpoint */
        struct uac_req *ureq;
 
        spinlock_t lock;
@@ -78,7 +78,7 @@ static const struct snd_pcm_hardware uac_pcm_hardware = {
 
 static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req)
 {
-       unsigned pending;
+       unsigned int pending;
        unsigned long flags, flags2;
        unsigned int hw_ptr;
        int status = req->status;
index 737bd77..fbe96ef 100644 (file)
@@ -186,11 +186,12 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
                out = dev->port_usb->out_ep;
        else
                out = NULL;
-       spin_unlock_irqrestore(&dev->lock, flags);
 
        if (!out)
+       {
+               spin_unlock_irqrestore(&dev->lock, flags);
                return -ENOTCONN;
-
+       }
 
        /* Padding up to RX_EXTRA handles minor disagreements with host.
         * Normally we use the USB "terminate on short read" convention;
@@ -214,6 +215,7 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
 
        if (dev->port_usb->is_fixed)
                size = max_t(size_t, size, dev->port_usb->fixed_out_len);
+       spin_unlock_irqrestore(&dev->lock, flags);
 
        skb = __netdev_alloc_skb(dev->net, size + NET_IP_ALIGN, gfp_flags);
        if (skb == NULL) {
@@ -1004,9 +1006,9 @@ int gether_get_ifname(struct net_device *net, char *name, int len)
        int ret;
 
        rtnl_lock();
-       ret = snprintf(name, len, "%s\n", netdev_name(net));
+       ret = scnprintf(name, len, "%s\n", netdev_name(net));
        rtnl_unlock();
-       return ret < len ? ret : len;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(gether_get_ifname);
 
index d7c9e4f..69ff7f8 100644 (file)
@@ -153,7 +153,6 @@ config USB_ETH_EEM
        depends on USB_ETH
        select USB_LIBCOMPOSITE
        select USB_F_EEM
-       default n
        help
          CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM
          and therefore can be supported by more hardware.  Technically ECM and
@@ -288,7 +287,7 @@ config USB_G_SERIAL
          Say "y" to link the driver statically, or "m" to build a
          dynamically linked module called "g_serial".
 
-         For more information, see Documentation/usb/gadget_serial.txt
+         For more information, see Documentation/usb/gadget_serial.rst
          which includes instructions and a "driver info file" needed to
          make MS-Windows work with CDC ACM.
 
@@ -322,7 +321,7 @@ config USB_G_PRINTER
          Say "y" to link the driver statically, or "m" to build a
          dynamically linked module called "g_printer".
 
-         For more information, see Documentation/usb/gadget_printer.txt
+         For more information, see Documentation/usb/gadget_printer.rst
          which includes sample code for accessing the device file.
 
 if TTY
@@ -419,7 +418,6 @@ config USB_G_MULTI_RNDIS
 config USB_G_MULTI_CDC
        bool "CDC Ethernet + CDC Serial + Storage configuration"
        depends on USB_G_MULTI
-       default n
        select USB_F_ECM
        help
          This option enables a configuration with CDC Ethernet (ECM), CDC
@@ -438,7 +436,7 @@ config USB_G_HID
          The HID gadget driver provides generic emulation of USB
          Human Interface Devices (HID).
 
-         For more information, see Documentation/usb/gadget_hid.txt which
+         For more information, see Documentation/usb/gadget_hid.rst which
          includes sample code for accessing the device files.
 
          Say "y" to link the driver statically, or "m" to build a
index 03959dc..194ffb1 100644 (file)
@@ -799,7 +799,6 @@ static int at91_wakeup(struct usb_gadget *gadget)
 {
        struct at91_udc *udc = to_udc(gadget);
        u32             glbstate;
-       int             status = -EINVAL;
        unsigned long   flags;
 
        DBG("%s\n", __func__ );
@@ -818,7 +817,7 @@ static int at91_wakeup(struct usb_gadget *gadget)
 
 done:
        spin_unlock_irqrestore(&udc->lock, flags);
-       return status;
+       return 0;
 }
 
 /* reinit == restore initial software state */
index cec4929..21f3e6c 100644 (file)
@@ -481,7 +481,6 @@ static int fotg210_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedge)
        struct fotg210_ep *ep;
        struct fotg210_udc *fotg210;
        unsigned long flags;
-       int ret = 0;
 
        ep = container_of(_ep, struct fotg210_ep, ep);
 
@@ -504,7 +503,7 @@ static int fotg210_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedge)
        }
 
        spin_unlock_irqrestore(&ep->fotg210->lock, flags);
-       return ret;
+       return 0;
 }
 
 static int fotg210_ep_set_halt(struct usb_ep *_ep, int value)
index 564aeee..247de0f 100644 (file)
@@ -1178,11 +1178,6 @@ registers_show(struct device *_dev, struct device_attribute *attr, char *buf)
        size = PAGE_SIZE;
        spin_lock_irqsave(&dev->lock, flags);
 
-       if (dev->driver)
-               s = dev->driver->driver.name;
-       else
-               s = "(none)";
-
        /* Main Control Registers */
        t = scnprintf(next, size, "%s version %s,"
                "chiprev %02x, locctl %02x\n"
index fcf13ef..f36f073 100644 (file)
@@ -2103,7 +2103,6 @@ done:
 static int omap_udc_stop(struct usb_gadget *g)
 {
        unsigned long   flags;
-       int             status = -ENODEV;
 
        if (udc->dc_clk != NULL)
                omap_udc_enable_clock(1);
@@ -2125,7 +2124,7 @@ static int omap_udc_stop(struct usb_gadget *g)
        if (udc->dc_clk != NULL)
                omap_udc_enable_clock(0);
 
-       return status;
+       return 0;
 }
 
 /*-------------------------------------------------------------------------*/
index 7dc2485..87062d2 100644 (file)
@@ -351,6 +351,8 @@ struct renesas_usb3 {
        int disabled_count;
 
        struct usb_request *ep0_req;
+
+       enum usb_role connection_state;
        u16 test_mode;
        u8 ep0_buf[USB3_EP0_BUF_SIZE];
        bool softconnect;
@@ -359,6 +361,7 @@ struct renesas_usb3 {
        bool extcon_usb;                /* check vbus and set EXTCON_USB */
        bool forced_b_device;
        bool start_to_connect;
+       bool role_sw_by_connector;
 };
 
 #define gadget_to_renesas_usb3(_gadget)        \
@@ -699,8 +702,11 @@ static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
        unsigned long flags;
 
        spin_lock_irqsave(&usb3->lock, flags);
-       usb3_set_mode_by_role_sw(usb3, host);
-       usb3_vbus_out(usb3, a_dev);
+       if (!usb3->role_sw_by_connector ||
+           usb3->connection_state != USB_ROLE_NONE) {
+               usb3_set_mode_by_role_sw(usb3, host);
+               usb3_vbus_out(usb3, a_dev);
+       }
        /* for A-Peripheral or forced B-device mode */
        if ((!host && a_dev) || usb3->start_to_connect)
                usb3_connect(usb3);
@@ -716,7 +722,8 @@ static void usb3_check_id(struct renesas_usb3 *usb3)
 {
        usb3->extcon_host = usb3_is_a_device(usb3);
 
-       if (usb3->extcon_host && !usb3->forced_b_device)
+       if ((!usb3->role_sw_by_connector && usb3->extcon_host &&
+            !usb3->forced_b_device) || usb3->connection_state == USB_ROLE_HOST)
                usb3_mode_config(usb3, true, true);
        else
                usb3_mode_config(usb3, false, false);
@@ -1161,7 +1168,7 @@ static void usb3_set_status_stage(struct renesas_usb3_ep *usb3_ep,
 static void usb3_p0_xfer(struct renesas_usb3_ep *usb3_ep,
                         struct renesas_usb3_request *usb3_req)
 {
-       int ret = -EAGAIN;
+       int ret;
 
        if (usb3_ep->dir_in)
                ret = usb3_write_pipe(usb3_ep, usb3_req, USB3_P0_WRITE);
@@ -2343,14 +2350,65 @@ static enum usb_role renesas_usb3_role_switch_get(struct device *dev)
        return cur_role;
 }
 
-static int renesas_usb3_role_switch_set(struct device *dev,
-                                       enum usb_role role)
+static void handle_ext_role_switch_states(struct device *dev,
+                                           enum usb_role role)
+{
+       struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
+       struct device *host = usb3->host_dev;
+       enum usb_role cur_role = renesas_usb3_role_switch_get(dev);
+
+       switch (role) {
+       case USB_ROLE_NONE:
+               usb3->connection_state = USB_ROLE_NONE;
+               if (usb3->driver)
+                       usb3_disconnect(usb3);
+               usb3_vbus_out(usb3, false);
+               break;
+       case USB_ROLE_DEVICE:
+               if (usb3->connection_state == USB_ROLE_NONE) {
+                       usb3->connection_state = USB_ROLE_DEVICE;
+                       usb3_set_mode(usb3, false);
+                       if (usb3->driver)
+                               usb3_connect(usb3);
+               } else if (cur_role == USB_ROLE_HOST)  {
+                       device_release_driver(host);
+                       usb3_set_mode(usb3, false);
+                       if (usb3->driver)
+                               usb3_connect(usb3);
+               }
+               usb3_vbus_out(usb3, false);
+               break;
+       case USB_ROLE_HOST:
+               if (usb3->connection_state == USB_ROLE_NONE) {
+                       if (usb3->driver)
+                               usb3_disconnect(usb3);
+
+                       usb3->connection_state = USB_ROLE_HOST;
+                       usb3_set_mode(usb3, true);
+                       usb3_vbus_out(usb3, true);
+                       if (device_attach(host) < 0)
+                               dev_err(dev, "device_attach(host) failed\n");
+               } else if (cur_role == USB_ROLE_DEVICE) {
+                       usb3_disconnect(usb3);
+                       /* Must set the mode before device_attach of the host */
+                       usb3_set_mode(usb3, true);
+                       /* This device_attach() might sleep */
+                       if (device_attach(host) < 0)
+                               dev_err(dev, "device_attach(host) failed\n");
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static void handle_role_switch_states(struct device *dev,
+                                           enum usb_role role)
 {
        struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
        struct device *host = usb3->host_dev;
        enum usb_role cur_role = renesas_usb3_role_switch_get(dev);
 
-       pm_runtime_get_sync(dev);
        if (cur_role == USB_ROLE_HOST && role == USB_ROLE_DEVICE) {
                device_release_driver(host);
                usb3_set_mode(usb3, false);
@@ -2361,6 +2419,20 @@ static int renesas_usb3_role_switch_set(struct device *dev,
                if (device_attach(host) < 0)
                        dev_err(dev, "device_attach(host) failed\n");
        }
+}
+
+static int renesas_usb3_role_switch_set(struct device *dev,
+                                       enum usb_role role)
+{
+       struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
+
+       pm_runtime_get_sync(dev);
+
+       if (usb3->role_sw_by_connector)
+               handle_ext_role_switch_states(dev, role);
+       else
+               handle_role_switch_states(dev, role);
+
        pm_runtime_put(dev);
 
        return 0;
@@ -2650,7 +2722,7 @@ static const unsigned int renesas_usb3_cable[] = {
        EXTCON_NONE,
 };
 
-static const struct usb_role_switch_desc renesas_usb3_role_switch_desc = {
+static struct usb_role_switch_desc renesas_usb3_role_switch_desc = {
        .set = renesas_usb3_role_switch_set,
        .get = renesas_usb3_role_switch_get,
        .allow_userspace_control = true,
@@ -2741,6 +2813,11 @@ static int renesas_usb3_probe(struct platform_device *pdev)
        if (ret < 0)
                goto err_dev_create;
 
+       if (device_property_read_bool(&pdev->dev, "usb-role-switch")) {
+               usb3->role_sw_by_connector = true;
+               renesas_usb3_role_switch_desc.fwnode = dev_fwnode(&pdev->dev);
+       }
+
        INIT_WORK(&usb3->role_work, renesas_usb3_role_work);
        usb3->role_sw = usb_role_switch_register(&pdev->dev,
                                        &renesas_usb3_role_switch_desc);
index d809671..40b5de5 100644 (file)
@@ -114,7 +114,7 @@ config USB_EHCI_HCD
          Controller Driver or UHCI (for Via motherboards) Host Controller
          Driver too.
 
-         You may want to read <file:Documentation/usb/ehci.txt>.
+         You may want to read <file:Documentation/usb/ehci.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called ehci-hcd.
@@ -161,7 +161,6 @@ config USB_EHCI_PCI
 config USB_EHCI_HCD_PMC_MSP
        tristate "EHCI support for on-chip PMC MSP71xx USB controller"
        depends on MSP_HAS_USB
-       default n
        select USB_EHCI_BIG_ENDIAN_DESC
        select USB_EHCI_BIG_ENDIAN_MMIO
        ---help---
@@ -308,7 +307,6 @@ config USB_CNS3XXX_EHCI
 
 config USB_EHCI_HCD_PLATFORM
        tristate "Generic EHCI driver for a platform device"
-       default n
        ---help---
          Adds an EHCI host driver for a generic platform device, which
          provides a memory space and an irq.
@@ -318,7 +316,6 @@ config USB_EHCI_HCD_PLATFORM
 config USB_OCTEON_EHCI
        bool "Octeon on-chip EHCI support (DEPRECATED)"
        depends on CAVIUM_OCTEON_SOC
-       default n
        select USB_EHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
        select USB_EHCI_HCD_PLATFORM
        help
@@ -526,7 +523,6 @@ config USB_OHCI_HCD_SSB
        depends on (SSB = y || SSB = USB_OHCI_HCD)
        select USB_HCD_SSB
        select USB_OHCI_HCD_PLATFORM
-       default n
        ---help---
          This option is deprecated now and the driver was removed, use
          USB_HCD_SSB and USB_OHCI_HCD_PLATFORM instead.
@@ -569,7 +565,6 @@ config USB_CNS3XXX_OHCI
 
 config USB_OHCI_HCD_PLATFORM
        tristate "Generic OHCI driver for a platform device"
-       default n
        ---help---
          Adds an OHCI host driver for a generic platform device, which
          provides a memory space and an irq.
index 8e3bab1..3a29a1a 100644 (file)
@@ -39,6 +39,7 @@ static struct hc_driver __read_mostly exynos_ehci_hc_driver;
 
 struct exynos_ehci_hcd {
        struct clk *clk;
+       struct device_node *of_node;
        struct phy *phy[PHY_NUMBER];
 };
 
@@ -203,6 +204,13 @@ static int exynos_ehci_probe(struct platform_device *pdev)
        ehci = hcd_to_ehci(hcd);
        ehci->caps = hcd->regs;
 
+       /*
+        * Workaround: reset of_node pointer to avoid conflict between Exynos
+        * EHCI port subnodes and generic USB device bindings
+        */
+       exynos_ehci->of_node = pdev->dev.of_node;
+       pdev->dev.of_node = NULL;
+
        /* DMA burst Enable */
        writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
 
@@ -219,6 +227,7 @@ static int exynos_ehci_probe(struct platform_device *pdev)
 
 fail_add_hcd:
        exynos_ehci_phy_disable(&pdev->dev);
+       pdev->dev.of_node = exynos_ehci->of_node;
 fail_io:
        clk_disable_unprepare(exynos_ehci->clk);
 fail_clk:
@@ -231,6 +240,8 @@ static int exynos_ehci_remove(struct platform_device *pdev)
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
        struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd);
 
+       pdev->dev.of_node = exynos_ehci->of_node;
+
        usb_remove_hcd(hcd);
 
        exynos_ehci_phy_disable(&pdev->dev);
index e3d0c1c..9e9c232 100644 (file)
@@ -122,6 +122,12 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev)
                tmp |= 0x4;
                iowrite32be(tmp, hcd->regs + FSL_SOC_USB_CTRL);
        }
+
+       /* Set USB_EN bit to select ULPI phy for USB controller version 2.5 */
+       if (pdata->controller_ver == FSL_USB_VER_2_5 &&
+           pdata->phy_mode == FSL_USB2_PHY_ULPI)
+               iowrite32be(USB_CTRL_USB_EN, hcd->regs + FSL_SOC_USB_CTRL);
+
        /*
         * Enable UTMI phy and program PTS field in UTMI mode before asserting
         * controller reset for USB Controller version 2.5
@@ -177,6 +183,17 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev)
        return retval;
 }
 
+static bool usb_phy_clk_valid(struct usb_hcd *hcd)
+{
+       void __iomem *non_ehci = hcd->regs;
+       bool ret = true;
+
+       if (!(ioread32be(non_ehci + FSL_SOC_USB_CTRL) & PHY_CLK_VALID))
+               ret = false;
+
+       return ret;
+}
+
 static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
                               enum fsl_usb2_phy_modes phy_mode,
                               unsigned int port_offset)
@@ -219,7 +236,26 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
                portsc |= PORT_PTS_PTW;
                /* fall through */
        case FSL_USB2_PHY_UTMI:
+               /* Presence of this node "has_fsl_erratum_a006918"
+                * in device-tree is used to stop USB controller
+                * initialization in Linux
+                */
+               if (pdata->has_fsl_erratum_a006918) {
+                       dev_warn(dev, "USB PHY clock invalid\n");
+                       return -EINVAL;
+               }
+               /* fall through */
        case FSL_USB2_PHY_UTMI_DUAL:
+               /* PHY_CLK_VALID bit is de-featured from all controller
+                * versions below 2.4 and is to be checked only for
+                * internal UTMI phy
+                */
+               if (pdata->controller_ver > FSL_USB_VER_2_4 &&
+                   pdata->have_sysif_regs && !usb_phy_clk_valid(hcd)) {
+                       dev_err(dev, "USB PHY clock invalid\n");
+                       return -EINVAL;
+               }
+
                if (pdata->have_sysif_regs && pdata->controller_ver) {
                        /* controller version 1.6 or above */
                        tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL);
@@ -243,17 +279,11 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
                break;
        }
 
-       /*
-        * check PHY_CLK_VALID to determine phy clock presence before writing
-        * to portsc
-        */
-       if (pdata->check_phy_clk_valid) {
-               if (!(ioread32be(non_ehci + FSL_SOC_USB_CTRL) &
-                   PHY_CLK_VALID)) {
-                       dev_warn(hcd->self.controller,
-                                "USB PHY clock invalid\n");
-                       return -EINVAL;
-               }
+       if (pdata->have_sysif_regs &&
+           pdata->controller_ver > FSL_USB_VER_1_6 &&
+           !usb_phy_clk_valid(hcd)) {
+               dev_warn(hcd->self.controller, "USB PHY clock invalid\n");
+               return -EINVAL;
        }
 
        ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
index cbc4220..9d18c6e 100644 (file)
@@ -50,4 +50,7 @@
 #define UTMI_PHY_EN             (1<<9)
 #define ULPI_PHY_CLK_SEL        (1<<10)
 #define PHY_CLK_VALID          (1<<17)
+
+/* Retry count for checking UTMI PHY CLK validity */
+#define UTMI_PHY_CLK_VALID_CHK_RETRY 5
 #endif                         /* _EHCI_FSL_H */
index cdafa97..9da7e22 100644 (file)
@@ -559,7 +559,7 @@ static int ehci_init(struct usb_hcd *hcd)
        ehci->command = temp;
 
        /* Accept arbitrarily long scatter-gather lists */
-       if (!(hcd->driver->flags & HCD_LOCAL_MEM))
+       if (!hcd->localmem_pool)
                hcd->self.sg_tablesize = ~0;
 
        /* Prepare for unlinking active QHs */
index dc42981..ccb4e61 100644 (file)
@@ -152,7 +152,6 @@ static int st_ehci_platform_probe(struct platform_device *dev)
        struct resource *res_mem;
        struct usb_ehci_pdata *pdata = &ehci_platform_defaults;
        struct st_ehci_platform_priv *priv;
-       struct ehci_hcd *ehci;
        int err, irq, clk = 0;
 
        if (usb_disabled())
@@ -177,7 +176,6 @@ static int st_ehci_platform_probe(struct platform_device *dev)
        platform_set_drvdata(dev, hcd);
        dev->dev.platform_data = pdata;
        priv = hcd_to_ehci_priv(hcd);
-       ehci = hcd_to_ehci(hcd);
 
        priv->phy = devm_phy_get(&dev->dev, "usb");
        if (IS_ERR(priv->phy)) {
index 0da68df..77cc36e 100644 (file)
@@ -10,6 +10,7 @@
  * Most of code borrowed from the Linux-3.7 EHCI driver
  */
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/device.h>
 #include <linux/dmapool.h>
 #include <linux/kernel.h>
@@ -4995,7 +4996,7 @@ static int hcd_fotg210_init(struct usb_hcd *hcd)
        fotg210->command = temp;
 
        /* Accept arbitrarily long scatter-gather lists */
-       if (!(hcd->driver->flags & HCD_LOCAL_MEM))
+       if (!hcd->localmem_pool)
                hcd->self.sg_tablesize = ~0;
        return 0;
 }
@@ -5669,9 +5670,18 @@ static int fotg210_hcd_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id fotg210_of_match[] = {
+       { .compatible = "faraday,fotg210" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, fotg210_of_match);
+#endif
+
 static struct platform_driver fotg210_hcd_driver = {
        .driver = {
                .name   = "fotg210-hcd",
+               .of_match_table = of_match_ptr(fotg210_of_match),
        },
        .probe  = fotg210_hcd_probe,
        .remove = fotg210_hcd_remove,
index 4f8b8a0..ae8f60f 100644 (file)
@@ -224,12 +224,10 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev)
                of_property_read_bool(np, "fsl,usb-erratum-a005275");
        pdata->has_fsl_erratum_a005697 =
                of_property_read_bool(np, "fsl,usb_erratum-a005697");
-
-       if (of_get_property(np, "fsl,usb_erratum_14", NULL))
-               pdata->has_fsl_erratum_14 = 1;
-       else
-               pdata->has_fsl_erratum_14 = 0;
-
+       pdata->has_fsl_erratum_a006918 =
+               of_property_read_bool(np, "fsl,usb_erratum-a006918");
+       pdata->has_fsl_erratum_14 =
+               of_property_read_bool(np, "fsl,usb_erratum-14");
 
        /*
         * Determine whether phy_clk_valid needs to be checked
index 6502408..4c49688 100644 (file)
@@ -11,7 +11,7 @@
 
 #define USE_32BIT              0
 
-/* These options are mutually eclusive */
+/* These options are mutually exclusive */
 #define USE_PLATFORM_DELAY     0
 #define USE_NDELAY             0
 
index c0c4dcc..905c631 100644 (file)
@@ -30,6 +30,7 @@ static struct hc_driver __read_mostly exynos_ohci_hc_driver;
 
 struct exynos_ohci_hcd {
        struct clk *clk;
+       struct device_node *of_node;
        struct phy *phy[PHY_NUMBER];
 };
 
@@ -170,6 +171,13 @@ static int exynos_ohci_probe(struct platform_device *pdev)
                goto fail_io;
        }
 
+       /*
+        * Workaround: reset of_node pointer to avoid conflict between Exynos
+        * OHCI port subnodes and generic USB device bindings
+        */
+       exynos_ohci->of_node = pdev->dev.of_node;
+       pdev->dev.of_node = NULL;
+
        err = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (err) {
                dev_err(&pdev->dev, "Failed to add USB HCD\n");
@@ -180,6 +188,7 @@ static int exynos_ohci_probe(struct platform_device *pdev)
 
 fail_add_hcd:
        exynos_ohci_phy_disable(&pdev->dev);
+       pdev->dev.of_node = exynos_ohci->of_node;
 fail_io:
        clk_disable_unprepare(exynos_ohci->clk);
 fail_clk:
@@ -192,6 +201,8 @@ static int exynos_ohci_remove(struct platform_device *pdev)
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
        struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd);
 
+       pdev->dev.of_node = exynos_ohci->of_node;
+
        usb_remove_hcd(hcd);
 
        exynos_ohci_phy_disable(&pdev->dev);
index 210181f..b457fda 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/dmapool.h>
 #include <linux/workqueue.h>
 #include <linux/debugfs.h>
+#include <linux/genalloc.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -447,7 +448,7 @@ static int ohci_init (struct ohci_hcd *ohci)
        struct usb_hcd *hcd = ohci_to_hcd(ohci);
 
        /* Accept arbitrarily long scatter-gather lists */
-       if (!(hcd->driver->flags & HCD_LOCAL_MEM))
+       if (!hcd->localmem_pool)
                hcd->self.sg_tablesize = ~0;
 
        if (distrust_firmware)
@@ -505,8 +506,15 @@ static int ohci_init (struct ohci_hcd *ohci)
        timer_setup(&ohci->io_watchdog, io_watchdog_func, 0);
        ohci->prev_frame_no = IO_WATCHDOG_OFF;
 
-       ohci->hcca = dma_alloc_coherent (hcd->self.controller,
-                       sizeof(*ohci->hcca), &ohci->hcca_dma, GFP_KERNEL);
+       if (hcd->localmem_pool)
+               ohci->hcca = gen_pool_dma_alloc_align(hcd->localmem_pool,
+                                               sizeof(*ohci->hcca),
+                                               &ohci->hcca_dma, 256);
+       else
+               ohci->hcca = dma_alloc_coherent(hcd->self.controller,
+                                               sizeof(*ohci->hcca),
+                                               &ohci->hcca_dma,
+                                               GFP_KERNEL);
        if (!ohci->hcca)
                return -ENOMEM;
 
@@ -990,9 +998,14 @@ static void ohci_stop (struct usb_hcd *hcd)
        remove_debug_files (ohci);
        ohci_mem_cleanup (ohci);
        if (ohci->hcca) {
-               dma_free_coherent (hcd->self.controller,
-                               sizeof *ohci->hcca,
-                               ohci->hcca, ohci->hcca_dma);
+               if (hcd->localmem_pool)
+                       gen_pool_free(hcd->localmem_pool,
+                                     (unsigned long)ohci->hcca,
+                                     sizeof(*ohci->hcca));
+               else
+                       dma_free_coherent(hcd->self.controller,
+                                         sizeof(*ohci->hcca),
+                                         ohci->hcca, ohci->hcca_dma);
                ohci->hcca = NULL;
                ohci->hcca_dma = 0;
        }
index 3965ac0..1425335 100644 (file)
@@ -36,6 +36,13 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
 
 static int ohci_mem_init (struct ohci_hcd *ohci)
 {
+       /*
+        * HCs with local memory allocate from localmem_pool so there's
+        * no need to create the below dma pools.
+        */
+       if (ohci_to_hcd(ohci)->localmem_pool)
+               return 0;
+
        ohci->td_cache = dma_pool_create ("ohci_td",
                ohci_to_hcd(ohci)->self.controller,
                sizeof (struct td),
@@ -84,8 +91,13 @@ td_alloc (struct ohci_hcd *hc, gfp_t mem_flags)
 {
        dma_addr_t      dma;
        struct td       *td;
+       struct usb_hcd  *hcd = ohci_to_hcd(hc);
 
-       td = dma_pool_zalloc (hc->td_cache, mem_flags, &dma);
+       if (hcd->localmem_pool)
+               td = gen_pool_dma_zalloc_align(hcd->localmem_pool,
+                               sizeof(*td), &dma, 32);
+       else
+               td = dma_pool_zalloc(hc->td_cache, mem_flags, &dma);
        if (td) {
                /* in case hc fetches it, make it look dead */
                td->hwNextTD = cpu_to_hc32 (hc, dma);
@@ -99,6 +111,7 @@ static void
 td_free (struct ohci_hcd *hc, struct td *td)
 {
        struct td       **prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)];
+       struct usb_hcd  *hcd = ohci_to_hcd(hc);
 
        while (*prev && *prev != td)
                prev = &(*prev)->td_hash;
@@ -106,7 +119,12 @@ td_free (struct ohci_hcd *hc, struct td *td)
                *prev = td->td_hash;
        else if ((td->hwINFO & cpu_to_hc32(hc, TD_DONE)) != 0)
                ohci_dbg (hc, "no hash for td %p\n", td);
-       dma_pool_free (hc->td_cache, td, td->td_dma);
+
+       if (hcd->localmem_pool)
+               gen_pool_free(hcd->localmem_pool, (unsigned long)td,
+                             sizeof(*td));
+       else
+               dma_pool_free(hc->td_cache, td, td->td_dma);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -117,8 +135,13 @@ ed_alloc (struct ohci_hcd *hc, gfp_t mem_flags)
 {
        dma_addr_t      dma;
        struct ed       *ed;
+       struct usb_hcd  *hcd = ohci_to_hcd(hc);
 
-       ed = dma_pool_zalloc (hc->ed_cache, mem_flags, &dma);
+       if (hcd->localmem_pool)
+               ed = gen_pool_dma_zalloc_align(hcd->localmem_pool,
+                               sizeof(*ed), &dma, 16);
+       else
+               ed = dma_pool_zalloc(hc->ed_cache, mem_flags, &dma);
        if (ed) {
                INIT_LIST_HEAD (&ed->td_list);
                ed->dma = dma;
@@ -129,6 +152,12 @@ ed_alloc (struct ohci_hcd *hc, gfp_t mem_flags)
 static void
 ed_free (struct ohci_hcd *hc, struct ed *ed)
 {
-       dma_pool_free (hc->ed_cache, ed, ed->dma);
+       struct usb_hcd  *hcd = ohci_to_hcd(hc);
+
+       if (hcd->localmem_pool)
+               gen_pool_free(hcd->localmem_pool, (unsigned long)ed,
+                             sizeof(*ed));
+       else
+               dma_pool_free(hc->ed_cache, ed, ed->dma);
 }
 
index fbcd349..a033f7d 100644 (file)
@@ -274,7 +274,7 @@ static const struct ohci_driver_overrides pci_overrides __initconst = {
        .reset =                ohci_pci_reset,
 };
 
-static const struct pci_device_id pci_ids [] = { {
+static const struct pci_device_id pci_ids[] = { {
        /* handle any USB OHCI controller */
        PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_OHCI, ~0),
        .driver_data =  (unsigned long) &ohci_pci_hc_driver,
index 4511e27..d961097 100644 (file)
@@ -293,7 +293,6 @@ static int ohci_s3c2410_hub_control(
 static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc)
 {
        struct s3c2410_hcd_port *port;
-       struct usb_hcd *hcd;
        unsigned long flags;
        int portno;
 
@@ -301,7 +300,6 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc)
                return;
 
        port = &info->port[0];
-       hcd = info->hcd;
 
        local_irq_save(flags);
 
index c26228c..c158cda 100644 (file)
@@ -49,7 +49,7 @@ static const struct hc_driver ohci_sm501_hc_driver = {
         * generic hardware linkage
         */
        .irq =                  ohci_irq,
-       .flags =                HCD_USB11 | HCD_MEMORY | HCD_LOCAL_MEM,
+       .flags =                HCD_USB11 | HCD_MEMORY,
 
        /*
         * basic lifecycle operations
@@ -110,40 +110,18 @@ static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev)
                goto err0;
        }
 
-       /* The sm501 chip is equipped with local memory that may be used
-        * by on-chip devices such as the video controller and the usb host.
-        * This driver uses dma_declare_coherent_memory() to make sure
-        * usb allocations with dma_alloc_coherent() allocate from
-        * this local memory. The dma_handle returned by dma_alloc_coherent()
-        * will be an offset starting from 0 for the first local memory byte.
-        *
-        * So as long as data is allocated using dma_alloc_coherent() all is
-        * fine. This is however not always the case - buffers may be allocated
-        * using kmalloc() - so the usb core needs to be told that it must copy
-        * data into our local memory if the buffers happen to be placed in
-        * regular memory. The HCD_LOCAL_MEM flag does just that.
-        */
-
-       retval = dma_declare_coherent_memory(dev, mem->start,
-                                        mem->start - mem->parent->start,
-                                        resource_size(mem));
-       if (retval) {
-               dev_err(dev, "cannot declare coherent memory\n");
-               goto err1;
-       }
-
        /* allocate, reserve and remap resources for registers */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL) {
                dev_err(dev, "no resource definition for registers\n");
                retval = -ENOENT;
-               goto err2;
+               goto err1;
        }
 
        hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
        if (!hcd) {
                retval = -ENOMEM;
-               goto err2;
+               goto err1;
        }
 
        hcd->rsrc_start = res->start;
@@ -164,6 +142,25 @@ static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev)
 
        ohci_hcd_init(hcd_to_ohci(hcd));
 
+       /* The sm501 chip is equipped with local memory that may be used
+        * by on-chip devices such as the video controller and the usb host.
+        * This driver uses genalloc so that usb allocations with
+        * gen_pool_dma_alloc() allocate from this local memory. The dma_handle
+        * returned by gen_pool_dma_alloc() will be an offset starting from 0
+        * for the first local memory byte.
+        *
+        * So as long as data is allocated using gen_pool_dma_alloc() all is
+        * fine. This is however not always the case - buffers may be allocated
+        * using kmalloc() - so the usb core needs to be told that it must copy
+        * data into our local memory if the buffers happen to be placed in
+        * regular memory. A non-null hcd->localmem_pool initialized by the
+        * the call to usb_hcd_setup_local_mem() below does just that.
+        */
+
+       if (usb_hcd_setup_local_mem(hcd, mem->start,
+                                   mem->start - mem->parent->start,
+                                   resource_size(mem)) < 0)
+               goto err5;
        retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (retval)
                goto err5;
@@ -181,8 +178,6 @@ err4:
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err3:
        usb_put_hcd(hcd);
-err2:
-       dma_release_declared_memory(dev);
 err1:
        release_mem_region(mem->start, resource_size(mem));
 err0:
@@ -197,7 +192,6 @@ static int ohci_hcd_sm501_drv_remove(struct platform_device *pdev)
        usb_remove_hcd(hcd);
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
-       dma_release_declared_memory(&pdev->dev);
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        if (mem)
                release_mem_region(mem->start, resource_size(mem));
index 69fa046..5cc0544 100644 (file)
@@ -35,7 +35,6 @@ static struct hc_driver __read_mostly ohci_spear_hc_driver;
 static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)
 {
        const struct hc_driver *driver = &ohci_spear_hc_driver;
-       struct ohci_hcd *ohci;
        struct usb_hcd *hcd = NULL;
        struct clk *usbh_clk;
        struct spear_ohci *sohci_p;
@@ -85,8 +84,6 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)
 
        clk_prepare_enable(sohci_p->clk);
 
-       ohci = hcd_to_ohci(hcd);
-
        retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), 0);
        if (retval == 0) {
                device_wakeup_enable(hcd->self.controller);
index 992807c..638a92b 100644 (file)
@@ -132,7 +132,6 @@ static int st_ohci_platform_probe(struct platform_device *dev)
        struct resource *res_mem;
        struct usb_ohci_pdata *pdata = &ohci_platform_defaults;
        struct st_ohci_platform_priv *priv;
-       struct ohci_hcd *ohci;
        int err, irq, clk = 0;
 
        if (usb_disabled())
@@ -158,7 +157,6 @@ static int st_ohci_platform_probe(struct platform_device *dev)
        platform_set_drvdata(dev, hcd);
        dev->dev.platform_data = pdata;
        priv = hcd_to_ohci_priv(hcd);
-       ohci = hcd_to_ohci(hcd);
 
        priv->phy = devm_phy_get(&dev->dev, "usb");
        if (IS_ERR(priv->phy)) {
index f88a037..d5a293a 100644 (file)
@@ -153,7 +153,7 @@ static const struct hc_driver ohci_tmio_hc_driver = {
 
        /* generic hardware linkage */
        .irq =                  ohci_irq,
-       .flags =                HCD_USB11 | HCD_MEMORY | HCD_LOCAL_MEM,
+       .flags =                HCD_USB11 | HCD_MEMORY,
 
        /* basic lifecycle operations */
        .start =                ohci_tmio_start,
@@ -224,11 +224,6 @@ static int ohci_hcd_tmio_drv_probe(struct platform_device *dev)
                goto err_ioremap_regs;
        }
 
-       ret = dma_declare_coherent_memory(&dev->dev, sram->start, sram->start,
-                               resource_size(sram));
-       if (ret)
-               goto err_dma_declare;
-
        if (cell->enable) {
                ret = cell->enable(dev);
                if (ret)
@@ -239,6 +234,11 @@ static int ohci_hcd_tmio_drv_probe(struct platform_device *dev)
        ohci = hcd_to_ohci(hcd);
        ohci_hcd_init(ohci);
 
+       ret = usb_hcd_setup_local_mem(hcd, sram->start, sram->start,
+                                     resource_size(sram));
+       if (ret < 0)
+               goto err_enable;
+
        ret = usb_add_hcd(hcd, irq, 0);
        if (ret)
                goto err_add_hcd;
@@ -254,8 +254,6 @@ err_add_hcd:
        if (cell->disable)
                cell->disable(dev);
 err_enable:
-       dma_release_declared_memory(&dev->dev);
-err_dma_declare:
        iounmap(hcd->regs);
 err_ioremap_regs:
        iounmap(tmio->ccr);
@@ -276,7 +274,6 @@ static int ohci_hcd_tmio_drv_remove(struct platform_device *dev)
        tmio_stop_hc(dev);
        if (cell->disable)
                cell->disable(dev);
-       dma_release_declared_memory(&dev->dev);
        iounmap(hcd->regs);
        iounmap(tmio->ccr);
        usb_put_hcd(hcd);
index ef4813b..b015b00 100644 (file)
@@ -385,6 +385,8 @@ struct ohci_hcd {
 
        /*
         * memory management for queue data structures
+        *
+        * @td_cache and @ed_cache are %NULL if &usb_hcd.localmem_pool is used.
         */
        struct dma_pool         *td_cache;
        struct dma_pool         *ed_cache;
index 4a5c9b5..400c40b 100644 (file)
@@ -2554,10 +2554,9 @@ static int u132_get_frame(struct usb_hcd *hcd)
                dev_err(&u132->platform_dev->dev, "device is being removed\n");
                return -ESHUTDOWN;
        } else {
-               int frame = 0;
                dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n");
                mdelay(100);
-               return frame;
+               return 0;
        }
 }
 
index 98deb5f..03bc597 100644 (file)
@@ -581,7 +581,7 @@ static int uhci_start(struct usb_hcd *hcd)
 
        hcd->uses_new_polling = 1;
        /* Accept arbitrarily long scatter-gather lists */
-       if (!(hcd->driver->flags & HCD_LOCAL_MEM))
+       if (!hcd->localmem_pool)
                hcd->self.sg_tablesize = ~0;
 
        spin_lock_init(&uhci->lock);
index 121782e..9741cde 100644 (file)
@@ -399,7 +399,7 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
         * stream once the endpoint is on the HW schedule.
         */
        if ((ep_state & EP_STOP_CMD_PENDING) || (ep_state & SET_DEQ_PENDING) ||
-           (ep_state & EP_HALTED))
+           (ep_state & EP_HALTED) || (ep_state & EP_CLEARING_TT))
                return;
        writel(DB_VALUE(ep_index, stream_id), db_addr);
        /* The CPU has better things to do at this point than wait for a
@@ -433,6 +433,13 @@ static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
        }
 }
 
+void xhci_ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
+               unsigned int slot_id,
+               unsigned int ep_index)
+{
+       ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
+}
+
 /* Get the right ring for the given slot_id, ep_index and stream_id.
  * If the endpoint supports streams, boundary check the URB's stream ID.
  * If the endpoint doesn't support streams, return the singular endpoint ring.
@@ -1799,6 +1806,23 @@ struct xhci_segment *trb_in_td(struct xhci_hcd *xhci,
        return NULL;
 }
 
+static void xhci_clear_hub_tt_buffer(struct xhci_hcd *xhci, struct xhci_td *td,
+               struct xhci_virt_ep *ep)
+{
+       /*
+        * As part of low/full-speed endpoint-halt processing
+        * we must clear the TT buffer (USB 2.0 specification 11.17.5).
+        */
+       if (td->urb->dev->tt && !usb_pipeint(td->urb->pipe) &&
+           (td->urb->dev->tt->hub != xhci_to_hcd(xhci)->self.root_hub) &&
+           !(ep->ep_state & EP_CLEARING_TT)) {
+               ep->ep_state |= EP_CLEARING_TT;
+               td->urb->ep->hcpriv = td->urb->dev;
+               if (usb_hub_clear_tt_buffer(td->urb))
+                       ep->ep_state &= ~EP_CLEARING_TT;
+       }
+}
+
 static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci,
                unsigned int slot_id, unsigned int ep_index,
                unsigned int stream_id, struct xhci_td *td,
@@ -1825,6 +1849,7 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci,
        if (reset_type == EP_HARD_RESET) {
                ep->ep_state |= EP_HARD_CLEAR_TOGGLE;
                xhci_cleanup_stalled_ring(xhci, ep_index, stream_id, td);
+               xhci_clear_hub_tt_buffer(xhci, td, ep);
        }
        xhci_ring_cmd_db(xhci);
 }
index 2941581..dafc659 100644 (file)
@@ -354,29 +354,6 @@ enum tegra_xusb_mbox_cmd {
        MBOX_CMD_NAK
 };
 
-static const char * const mbox_cmd_name[] = {
-       [  1] = "MSG_ENABLE",
-       [  2] = "INC_FALCON_CLOCK",
-       [  3] = "DEC_FALCON_CLOCK",
-       [  4] = "INC_SSPI_CLOCK",
-       [  5] = "DEC_SSPI_CLOCK",
-       [  6] = "SET_BW",
-       [  7] = "SET_SS_PWR_GATING",
-       [  8] = "SET_SS_PWR_UNGATING",
-       [  9] = "SAVE_DFE_CTLE_CTX",
-       [ 10] = "AIRPLANE_MODE_ENABLED",
-       [ 11] = "AIRPLANE_MODE_DISABLED",
-       [ 12] = "START_HSIC_IDLE",
-       [ 13] = "STOP_HSIC_IDLE",
-       [ 14] = "DBC_WAKE_STACK",
-       [ 15] = "HSIC_PRETEND_CONNECT",
-       [ 16] = "RESET_SSPI",
-       [ 17] = "DISABLE_SS_LFPS_DETECTION",
-       [ 18] = "ENABLE_SS_LFPS_DETECTION",
-       [128] = "ACK",
-       [129] = "NAK",
-};
-
 struct tegra_xusb_mbox_msg {
        u32 cmd;
        u32 data;
index 3f79f35..248cd7a 100644 (file)
@@ -4130,6 +4130,8 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
        /* Zero the input context control for later use */
        ctrl_ctx->add_flags = 0;
        ctrl_ctx->drop_flags = 0;
+       slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
+       udev->devaddr = (u8)(le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK);
 
        xhci_dbg_trace(xhci, trace_xhci_dbg_address,
                       "Internal device address = %d",
@@ -5176,6 +5178,26 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
 }
 EXPORT_SYMBOL_GPL(xhci_gen_setup);
 
+static void xhci_clear_tt_buffer_complete(struct usb_hcd *hcd,
+               struct usb_host_endpoint *ep)
+{
+       struct xhci_hcd *xhci;
+       struct usb_device *udev;
+       unsigned int slot_id;
+       unsigned int ep_index;
+       unsigned long flags;
+
+       xhci = hcd_to_xhci(hcd);
+       udev = (struct usb_device *)ep->hcpriv;
+       slot_id = udev->slot_id;
+       ep_index = xhci_get_endpoint_index(&ep->desc);
+
+       spin_lock_irqsave(&xhci->lock, flags);
+       xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_CLEARING_TT;
+       xhci_ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
+       spin_unlock_irqrestore(&xhci->lock, flags);
+}
+
 static const struct hc_driver xhci_hc_driver = {
        .description =          "xhci-hcd",
        .product_desc =         "xHCI Host Controller",
@@ -5237,6 +5259,7 @@ static const struct hc_driver xhci_hc_driver = {
        .enable_usb3_lpm_timeout =      xhci_enable_usb3_lpm_timeout,
        .disable_usb3_lpm_timeout =     xhci_disable_usb3_lpm_timeout,
        .find_raw_port_number = xhci_find_raw_port_number,
+       .clear_tt_buffer_complete = xhci_clear_tt_buffer_complete,
 };
 
 void xhci_init_driver(struct hc_driver *drv,
index 92e764c..7a26496 100644 (file)
@@ -936,6 +936,8 @@ struct xhci_virt_ep {
 #define EP_GETTING_NO_STREAMS  (1 << 5)
 #define EP_HARD_CLEAR_TOGGLE   (1 << 6)
 #define EP_SOFT_CLEAR_TOGGLE   (1 << 7)
+/* usb_hub_clear_tt_buffer is in progress */
+#define EP_CLEARING_TT         (1 << 8)
        /* ----  Related to URB cancellation ---- */
        struct list_head        cancelled_td_list;
        /* Watchdog timer for stop endpoint command to cancel URBs */
@@ -2111,6 +2113,9 @@ void xhci_handle_command_timeout(struct work_struct *work);
 
 void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
                unsigned int ep_index, unsigned int stream_id);
+void xhci_ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
+               unsigned int slot_id,
+               unsigned int ep_index);
 void xhci_cleanup_command_queue(struct xhci_hcd *xhci);
 void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring);
 unsigned int count_trbs(u64 addr, u64 len);
index 607be1f..0a57c2c 100644 (file)
@@ -488,7 +488,6 @@ static void mts_command_done( struct urb *transfer )
 
 static void mts_do_sg (struct urb* transfer)
 {
-       struct scatterlist * sg;
        int status = transfer->status;
        MTS_INT_INIT();
 
@@ -500,13 +499,12 @@ static void mts_do_sg (struct urb* transfer)
                mts_transfer_cleanup(transfer);
         }
 
-       sg = scsi_sglist(context->srb);
-       context->fragment++;
+       context->curr_sg = sg_next(context->curr_sg);
        mts_int_submit_urb(transfer,
                           context->data_pipe,
-                          sg_virt(&sg[context->fragment]),
-                          sg[context->fragment].length,
-                          context->fragment + 1 == scsi_sg_count(context->srb) ?
+                          sg_virt(context->curr_sg),
+                          context->curr_sg->length,
+                          sg_is_last(context->curr_sg) ?
                           mts_data_done : mts_do_sg);
 }
 
@@ -526,22 +524,20 @@ static void
 mts_build_transfer_context(struct scsi_cmnd *srb, struct mts_desc* desc)
 {
        int pipe;
-       struct scatterlist * sg;
-       
+
        MTS_DEBUG_GOT_HERE();
 
        desc->context.instance = desc;
        desc->context.srb = srb;
-       desc->context.fragment = 0;
 
        if (!scsi_bufflen(srb)) {
                desc->context.data = NULL;
                desc->context.data_length = 0;
                return;
        } else {
-               sg = scsi_sglist(srb);
-               desc->context.data = sg_virt(&sg[0]);
-               desc->context.data_length = sg[0].length;
+               desc->context.curr_sg = scsi_sglist(srb);
+               desc->context.data = sg_virt(desc->context.curr_sg);
+               desc->context.data_length = desc->context.curr_sg->length;
        }
 
 
index 66685e5..7bd5f46 100644 (file)
@@ -21,7 +21,7 @@ struct mts_transfer_context
        void *data;
        unsigned data_length;
        int data_pipe;
-       int fragment;
+       struct scatterlist *curr_sg;
 
        u8 *scsi_status; /* status returned from ep_response after command completion */
 };
index 4a88e1c..bdae62b 100644 (file)
@@ -51,7 +51,7 @@ config USB_RIO500
        tristate "USB Diamond Rio500 support"
        help
          Say Y here if you want to connect a USB Rio500 mp3 player to your
-         computer's USB port. Please read <file:Documentation/usb/rio.txt>
+         computer's USB port. Please read <file:Documentation/usb/rio.rst>
          for more information.
 
          To compile this driver as a module, choose M here: the
index 9465fb9..344d523 100644 (file)
@@ -343,7 +343,6 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
        struct adu_device *dev;
        size_t bytes_read = 0;
        size_t bytes_to_read = count;
-       int i;
        int retval = 0;
        int timeout = 0;
        int should_submit = 0;
@@ -371,23 +370,22 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
        timeout = COMMAND_TIMEOUT;
        dev_dbg(&dev->udev->dev, "%s : about to start looping\n", __func__);
        while (bytes_to_read) {
-               int data_in_secondary = dev->secondary_tail - dev->secondary_head;
+               size_t data_in_secondary = dev->secondary_tail - dev->secondary_head;
                dev_dbg(&dev->udev->dev,
-                       "%s : while, data_in_secondary=%d, status=%d\n",
+                       "%s : while, data_in_secondary=%zu, status=%d\n",
                        __func__, data_in_secondary,
                        dev->interrupt_in_urb->status);
 
                if (data_in_secondary) {
                        /* drain secondary buffer */
-                       int amount = bytes_to_read < data_in_secondary ? bytes_to_read : data_in_secondary;
-                       i = copy_to_user(buffer, dev->read_buffer_secondary+dev->secondary_head, amount);
-                       if (i) {
+                       size_t amount = min(bytes_to_read, data_in_secondary);
+                       if (copy_to_user(buffer, dev->read_buffer_secondary+dev->secondary_head, amount)) {
                                retval = -EFAULT;
                                goto exit;
                        }
-                       dev->secondary_head += (amount - i);
-                       bytes_read += (amount - i);
-                       bytes_to_read -= (amount - i);
+                       dev->secondary_head += amount;
+                       bytes_read += amount;
+                       bytes_to_read -= amount;
                } else {
                        /* we check the primary buffer */
                        spin_lock_irqsave (&dev->buflock, flags);
index 257efac..cdee3af 100644 (file)
@@ -2023,13 +2023,6 @@ static int ftdi_elan_synchronize(struct usb_ftdi *ftdi)
                                                goto read;
                                        } else
                                                goto reset;
-                               } else if (s1 == 0x31 && s2 == 0x60) {
-                                       if (read_stop-- > 0) {
-                                               goto read;
-                                       } else {
-                                               dev_err(&ftdi->udev->dev, "retry limit reached\n");
-                                               continue;
-                                       }
                                } else {
                                        if (read_stop-- > 0) {
                                                goto read;
index ea06f1f..2ab9600 100644 (file)
@@ -1747,10 +1747,10 @@ static int sisusb_setup_screen(struct sisusb_usb_data *sisusb,
        return ret;
 }
 
-static int sisusb_set_default_mode(struct sisusb_usb_data *sisusb,
+static void sisusb_set_default_mode(struct sisusb_usb_data *sisusb,
                int touchengines)
 {
-       int ret = 0, i, j, modex, bpp, du;
+       int i, j, modex, bpp, du;
        u8 sr31, cr63, tmp8;
        static const char attrdata[] = {
                0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
@@ -1873,8 +1873,6 @@ static int sisusb_set_default_mode(struct sisusb_usb_data *sisusb,
        }
 
        SETIREG(SISCR, 0x34, 0x44);     /* we just set std mode #44 */
-
-       return ret;
 }
 
 static int sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
@@ -2019,7 +2017,7 @@ static int sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
 
                ret |= SETIREG(SISCR, 0x83, 0x00);
 
-               ret |= sisusb_set_default_mode(sisusb, 0);
+               sisusb_set_default_mode(sisusb, 0);
 
                ret |= SETIREGAND(SISSR, 0x21, 0xdf);
                ret |= SETIREGOR(SISSR, 0x01, 0x20);
@@ -2246,7 +2244,7 @@ static int sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
                if (sisusb_init_gfxcore(sisusb) == 0) {
                        sisusb->gfxinit = 1;
                        sisusb_get_ramconfig(sisusb);
-                       ret |= sisusb_set_default_mode(sisusb, 1);
+                       sisusb_set_default_mode(sisusb, 1);
                        ret |= sisusb_setup_screen(sisusb, 1, initscreen);
                }
        }
index 48f1b2d..ffc7cd4 100644 (file)
@@ -8,6 +8,6 @@ config USB_MON
        help
          If you select this option, a component which captures the USB traffic
          between peripheral-specific drivers and HC drivers will be built.
-         For more information, see <file:Documentation/usb/usbmon.txt>.
+         For more information, see <file:Documentation/usb/usbmon.rst>.
 
          If unsure, say Y, if allowed, otherwise M.
index b7c86cc..62c57dd 100644 (file)
@@ -528,7 +528,8 @@ void ssusb_dr_debugfs_init(struct ssusb_mtk *ssusb)
 
 void ssusb_debugfs_create_root(struct ssusb_mtk *ssusb)
 {
-       ssusb->dbgfs_root = debugfs_create_dir(dev_name(ssusb->dev), NULL);
+       ssusb->dbgfs_root =
+               debugfs_create_dir(dev_name(ssusb->dev), usb_debug_root);
 }
 
 void ssusb_debugfs_remove_root(struct ssusb_mtk *ssusb)
index a3cb25c..d16dfc3 100644 (file)
@@ -118,9 +118,9 @@ static const struct of_device_id omap_control_usb_id_table[] = {
 MODULE_DEVICE_TABLE(of, omap_control_usb_id_table);
 
 static struct platform_driver am335x_control_driver;
-static int match(struct device *dev, void *data)
+static int match(struct device *dev, const void *data)
 {
-       struct device_node *node = (struct device_node *)data;
+       const struct device_node *node = (const struct device_node *)data;
        return dev->of_node == node &&
                dev->driver == &am335x_control_driver.driver;
 }
index 93b7d6a..6cf6fbd 100644 (file)
@@ -142,9 +142,9 @@ static struct i2c_driver isp1301_driver = {
 
 module_i2c_driver(isp1301_driver);
 
-static int match(struct device *dev, void *data)
+static int match(struct device *dev, const void *data)
 {
-       struct device_node *node = (struct device_node *)data;
+       const struct device_node *node = (const struct device_node *)data;
        return (dev->of_node == node) &&
                (dev->driver == &isp1301_driver.driver);
 }
index cfd9add..cf7ecdc 100644 (file)
@@ -401,7 +401,6 @@ static void mv_otg_update_state(struct mv_otg *mvotg)
 static void mv_otg_work(struct work_struct *work)
 {
        struct mv_otg *mvotg;
-       struct usb_phy *phy;
        struct usb_otg *otg;
        int old_state;
 
@@ -409,7 +408,6 @@ static void mv_otg_work(struct work_struct *work)
 
 run:
        /* work queue is single thread, or we need spin_lock to protect */
-       phy = &mvotg->phy;
        otg = mvotg->phy.otg;
        old_state = otg->state;
 
index 6fa16ab..70b8c82 100644 (file)
 #include <linux/of_device.h>
 #include <linux/regmap.h>
 #include <linux/mfd/syscon.h>
+#include <linux/iopoll.h>
 
 #define DRIVER_NAME "mxs_phy"
 
+/* Register Macro */
 #define HW_USBPHY_PWD                          0x00
 #define HW_USBPHY_TX                           0x10
 #define HW_USBPHY_CTRL                         0x30
 #define GM_USBPHY_TX_TXCAL45DN(x)            (((x) & 0xf) << 8)
 #define GM_USBPHY_TX_D_CAL(x)                (((x) & 0xf) << 0)
 
+/* imx7ulp */
+#define HW_USBPHY_PLL_SIC                      0xa0
+#define HW_USBPHY_PLL_SIC_SET                  0xa4
+#define HW_USBPHY_PLL_SIC_CLR                  0xa8
+
 #define BM_USBPHY_CTRL_SFTRST                  BIT(31)
 #define BM_USBPHY_CTRL_CLKGATE                 BIT(30)
 #define BM_USBPHY_CTRL_OTG_ID_VALUE            BIT(27)
 #define BM_USBPHY_IP_FIX                       (BIT(17) | BIT(18))
 
 #define BM_USBPHY_DEBUG_CLKGATE                        BIT(30)
+/* imx7ulp */
+#define BM_USBPHY_PLL_LOCK                     BIT(31)
+#define BM_USBPHY_PLL_REG_ENABLE               BIT(21)
+#define BM_USBPHY_PLL_BYPASS                   BIT(16)
+#define BM_USBPHY_PLL_POWER                    BIT(12)
+#define BM_USBPHY_PLL_EN_USB_CLKS              BIT(6)
 
 /* Anatop Registers */
 #define ANADIG_ANA_MISC0                       0x150
@@ -168,6 +181,9 @@ static const struct mxs_phy_data imx6ul_phy_data = {
        .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
 };
 
+static const struct mxs_phy_data imx7ulp_phy_data = {
+};
+
 static const struct of_device_id mxs_phy_dt_ids[] = {
        { .compatible = "fsl,imx6sx-usbphy", .data = &imx6sx_phy_data, },
        { .compatible = "fsl,imx6sl-usbphy", .data = &imx6sl_phy_data, },
@@ -175,6 +191,7 @@ static const struct of_device_id mxs_phy_dt_ids[] = {
        { .compatible = "fsl,imx23-usbphy", .data = &imx23_phy_data, },
        { .compatible = "fsl,vf610-usbphy", .data = &vf610_phy_data, },
        { .compatible = "fsl,imx6ul-usbphy", .data = &imx6ul_phy_data, },
+       { .compatible = "fsl,imx7ulp-usbphy", .data = &imx7ulp_phy_data, },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids);
@@ -199,6 +216,11 @@ static inline bool is_imx6sl_phy(struct mxs_phy *mxs_phy)
        return mxs_phy->data == &imx6sl_phy_data;
 }
 
+static inline bool is_imx7ulp_phy(struct mxs_phy *mxs_phy)
+{
+       return mxs_phy->data == &imx7ulp_phy_data;
+}
+
 /*
  * PHY needs some 32K cycles to switch from 32K clock to
  * bus (such as AHB/AXI, etc) clock.
@@ -222,14 +244,49 @@ static void mxs_phy_tx_init(struct mxs_phy *mxs_phy)
        }
 }
 
+static int mxs_phy_pll_enable(void __iomem *base, bool enable)
+{
+       int ret = 0;
+
+       if (enable) {
+               u32 value;
+
+               writel(BM_USBPHY_PLL_REG_ENABLE, base + HW_USBPHY_PLL_SIC_SET);
+               writel(BM_USBPHY_PLL_BYPASS, base + HW_USBPHY_PLL_SIC_CLR);
+               writel(BM_USBPHY_PLL_POWER, base + HW_USBPHY_PLL_SIC_SET);
+               ret = readl_poll_timeout(base + HW_USBPHY_PLL_SIC,
+                       value, (value & BM_USBPHY_PLL_LOCK) != 0,
+                       100, 10000);
+               if (ret)
+                       return ret;
+
+               writel(BM_USBPHY_PLL_EN_USB_CLKS, base +
+                               HW_USBPHY_PLL_SIC_SET);
+       } else {
+               writel(BM_USBPHY_PLL_EN_USB_CLKS, base +
+                               HW_USBPHY_PLL_SIC_CLR);
+               writel(BM_USBPHY_PLL_POWER, base + HW_USBPHY_PLL_SIC_CLR);
+               writel(BM_USBPHY_PLL_BYPASS, base + HW_USBPHY_PLL_SIC_SET);
+               writel(BM_USBPHY_PLL_REG_ENABLE, base + HW_USBPHY_PLL_SIC_CLR);
+       }
+
+       return ret;
+}
+
 static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
 {
        int ret;
        void __iomem *base = mxs_phy->phy.io_priv;
 
+       if (is_imx7ulp_phy(mxs_phy)) {
+               ret = mxs_phy_pll_enable(base, true);
+               if (ret)
+                       return ret;
+       }
+
        ret = stmp_reset_block(base + HW_USBPHY_CTRL);
        if (ret)
-               return ret;
+               goto disable_pll;
 
        /* Power up the PHY */
        writel(0, base + HW_USBPHY_PWD);
@@ -267,6 +324,11 @@ static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
        mxs_phy_tx_init(mxs_phy);
 
        return 0;
+
+disable_pll:
+       if (is_imx7ulp_phy(mxs_phy))
+               mxs_phy_pll_enable(base, false);
+       return ret;
 }
 
 /* Return true if the vbus is there */
@@ -388,6 +450,9 @@ static void mxs_phy_shutdown(struct usb_phy *phy)
        writel(BM_USBPHY_CTRL_CLKGATE,
               phy->io_priv + HW_USBPHY_CTRL_SET);
 
+       if (is_imx7ulp_phy(mxs_phy))
+               mxs_phy_pll_enable(phy->io_priv, false);
+
        clk_disable_unprepare(mxs_phy->clk);
 }
 
index 7fdbff2..d6b3fef 100644 (file)
@@ -8,7 +8,6 @@ config USB_RENESAS_USBHS
        depends on USB_GADGET
        depends on ARCH_RENESAS || SUPERH || COMPILE_TEST
        depends on EXTCON || !EXTCON # if EXTCON=m, USBHS cannot be built-in
-       default n
        help
          Renesas USBHS is a discrete USB host and peripheral controller chip
          that supports both full and high speed USB 2.0 data transfers.
index 5c5b51b..a1fed56 100644 (file)
@@ -5,7 +5,7 @@
 
 obj-$(CONFIG_USB_RENESAS_USBHS)        += renesas_usbhs.o
 
-renesas_usbhs-y                        := common.o mod.o pipe.o fifo.o rcar2.o rcar3.o rza.o
+renesas_usbhs-y                        := common.o mod.o pipe.o fifo.o rcar2.o rcar3.o rza.o rza2.o
 
 ifneq ($(CONFIG_USB_RENESAS_USBHS_HCD),)
        renesas_usbhs-y         += mod_host.o
index 249fbee..4c3de77 100644 (file)
@@ -3,6 +3,7 @@
  * Renesas USB driver
  *
  * Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2019 Renesas Electronics Corporation
  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
  */
 #include <linux/clk.h>
  *                     | ....  |       +-----------+
  */
 
-
-#define USBHSF_RUNTIME_PWCTRL  (1 << 0)
-
-/* status */
-#define usbhsc_flags_init(p)   do {(p)->flags = 0; } while (0)
-#define usbhsc_flags_set(p, b) ((p)->flags |=  (b))
-#define usbhsc_flags_clr(p, b) ((p)->flags &= ~(b))
-#define usbhsc_flags_has(p, b) ((p)->flags &   (b))
-
 /*
  * platform call back
  *
@@ -61,8 +53,8 @@
  */
 #define usbhs_platform_call(priv, func, args...)\
        (!(priv) ? -ENODEV :                    \
-        !((priv)->pfunc.func) ? 0 :            \
-        (priv)->pfunc.func(args))
+        !((priv)->pfunc->func) ? 0 :           \
+        (priv)->pfunc->func(args))
 
 /*
  *             common functions
@@ -92,6 +84,11 @@ struct usbhs_priv *usbhs_pdev_to_priv(struct platform_device *pdev)
        return dev_get_drvdata(&pdev->dev);
 }
 
+int usbhs_get_id_as_gadget(struct platform_device *pdev)
+{
+       return USBHS_GADGET;
+}
+
 /*
  *             syscfg functions
  */
@@ -104,10 +101,6 @@ void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable)
 {
        u16 mask = DCFM | DRPD | DPRPU | HSE | USBE;
        u16 val  = DCFM | DRPD | HSE | USBE;
-       int has_otg = usbhs_get_dparam(priv, has_otg);
-
-       if (has_otg)
-               usbhs_bset(priv, DVSTCTR, (EXTLP | PWEN), (EXTLP | PWEN));
 
        /*
         * if enable
@@ -123,6 +116,12 @@ void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable)
        u16 mask = DCFM | DRPD | DPRPU | HSE | USBE;
        u16 val  = HSE | USBE;
 
+       /* CNEN bit is required for function operation */
+       if (usbhs_get_dparam(priv, has_cnen)) {
+               mask |= CNEN;
+               val  |= CNEN;
+       }
+
        /*
         * if enable
         *
@@ -294,11 +293,7 @@ static void usbhsc_set_buswait(struct usbhs_priv *priv)
 
 static bool usbhsc_is_multi_clks(struct usbhs_priv *priv)
 {
-       if (priv->dparam.type == USBHS_TYPE_RCAR_GEN3 ||
-           priv->dparam.type == USBHS_TYPE_RCAR_GEN3_WITH_PLL)
-               return true;
-
-       return false;
+       return priv->dparam.multi_clks;
 }
 
 static int usbhsc_clk_get(struct device *dev, struct usbhs_priv *priv)
@@ -307,7 +302,7 @@ static int usbhsc_clk_get(struct device *dev, struct usbhs_priv *priv)
                return 0;
 
        /* The first clock should exist */
-       priv->clks[0] = of_clk_get(dev->of_node, 0);
+       priv->clks[0] = of_clk_get(dev_of_node(dev), 0);
        if (IS_ERR(priv->clks[0]))
                return PTR_ERR(priv->clks[0]);
 
@@ -315,7 +310,7 @@ static int usbhsc_clk_get(struct device *dev, struct usbhs_priv *priv)
         * To backward compatibility with old DT, this driver checks the return
         * value if it's -ENOENT or not.
         */
-       priv->clks[1] = of_clk_get(dev->of_node, 1);
+       priv->clks[1] = of_clk_get(dev_of_node(dev), 1);
        if (PTR_ERR(priv->clks[1]) == -ENOENT)
                priv->clks[1] = NULL;
        else if (IS_ERR(priv->clks[1]))
@@ -454,7 +449,7 @@ static void usbhsc_hotplug(struct usbhs_priv *priv)
        /*
         * get vbus status from platform
         */
-       enable = usbhs_platform_call(priv, get_vbus, pdev);
+       enable = usbhs_mod_info_call(priv, get_vbus, pdev);
 
        /*
         * get id from platform
@@ -479,7 +474,7 @@ static void usbhsc_hotplug(struct usbhs_priv *priv)
                dev_dbg(&pdev->dev, "%s enable\n", __func__);
 
                /* power on */
-               if (usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
+               if (usbhs_get_dparam(priv, runtime_pwctrl))
                        usbhsc_power_ctrl(priv, enable);
 
                /* bus init */
@@ -499,7 +494,7 @@ static void usbhsc_hotplug(struct usbhs_priv *priv)
                usbhsc_bus_init(priv);
 
                /* power off */
-               if (usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
+               if (usbhs_get_dparam(priv, runtime_pwctrl))
                        usbhsc_power_ctrl(priv, enable);
 
                usbhs_mod_change(priv, -1);
@@ -520,7 +515,7 @@ static void usbhsc_notify_hotplug(struct work_struct *work)
        usbhsc_hotplug(priv);
 }
 
-static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev)
+int usbhsc_schedule_notify_hotplug(struct platform_device *pdev)
 {
        struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
        int delay = usbhs_get_dparam(priv, detection_delay);
@@ -541,115 +536,86 @@ static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev)
 static const struct of_device_id usbhs_of_match[] = {
        {
                .compatible = "renesas,usbhs-r8a774c0",
-               .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL,
+               .data = &usbhs_rcar_gen3_with_pll_plat_info,
        },
        {
                .compatible = "renesas,usbhs-r8a7790",
-               .data = (void *)USBHS_TYPE_RCAR_GEN2,
+               .data = &usbhs_rcar_gen2_plat_info,
        },
        {
                .compatible = "renesas,usbhs-r8a7791",
-               .data = (void *)USBHS_TYPE_RCAR_GEN2,
+               .data = &usbhs_rcar_gen2_plat_info,
        },
        {
                .compatible = "renesas,usbhs-r8a7794",
-               .data = (void *)USBHS_TYPE_RCAR_GEN2,
+               .data = &usbhs_rcar_gen2_plat_info,
        },
        {
                .compatible = "renesas,usbhs-r8a7795",
-               .data = (void *)USBHS_TYPE_RCAR_GEN3,
+               .data = &usbhs_rcar_gen3_plat_info,
        },
        {
                .compatible = "renesas,usbhs-r8a7796",
-               .data = (void *)USBHS_TYPE_RCAR_GEN3,
+               .data = &usbhs_rcar_gen3_plat_info,
        },
        {
                .compatible = "renesas,usbhs-r8a77990",
-               .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL,
+               .data = &usbhs_rcar_gen3_with_pll_plat_info,
        },
        {
                .compatible = "renesas,usbhs-r8a77995",
-               .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL,
+               .data = &usbhs_rcar_gen3_with_pll_plat_info,
        },
        {
                .compatible = "renesas,rcar-gen2-usbhs",
-               .data = (void *)USBHS_TYPE_RCAR_GEN2,
+               .data = &usbhs_rcar_gen2_plat_info,
        },
        {
                .compatible = "renesas,rcar-gen3-usbhs",
-               .data = (void *)USBHS_TYPE_RCAR_GEN3,
+               .data = &usbhs_rcar_gen3_plat_info,
        },
        {
                .compatible = "renesas,rza1-usbhs",
-               .data = (void *)USBHS_TYPE_RZA1,
+               .data = &usbhs_rza1_plat_info,
+       },
+       {
+               .compatible = "renesas,rza2-usbhs",
+               .data = &usbhs_rza2_plat_info,
        },
        { },
 };
 MODULE_DEVICE_TABLE(of, usbhs_of_match);
 
-static struct renesas_usbhs_platform_info *usbhs_parse_dt(struct device *dev)
-{
-       struct renesas_usbhs_platform_info *info;
-       struct renesas_usbhs_driver_param *dparam;
-       u32 tmp;
-       int gpio;
-
-       info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
-       if (!info)
-               return NULL;
-
-       dparam = &info->driver_param;
-       dparam->type = (uintptr_t)of_device_get_match_data(dev);
-       if (!of_property_read_u32(dev->of_node, "renesas,buswait", &tmp))
-               dparam->buswait_bwait = tmp;
-       gpio = of_get_named_gpio_flags(dev->of_node, "renesas,enable-gpio", 0,
-                                      NULL);
-       if (gpio > 0)
-               dparam->enable_gpio = gpio;
-
-       if (dparam->type == USBHS_TYPE_RCAR_GEN2 ||
-           dparam->type == USBHS_TYPE_RCAR_GEN3 ||
-           dparam->type == USBHS_TYPE_RCAR_GEN3_WITH_PLL) {
-               dparam->has_usb_dmac = 1;
-               dparam->pipe_configs = usbhsc_new_pipe;
-               dparam->pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
-       }
-
-       if (dparam->type == USBHS_TYPE_RZA1) {
-               dparam->pipe_configs = usbhsc_new_pipe;
-               dparam->pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
-       }
-
-       return info;
-}
-
 static int usbhs_probe(struct platform_device *pdev)
 {
-       struct renesas_usbhs_platform_info *info = renesas_usbhs_get_info(pdev);
-       struct renesas_usbhs_driver_callback *dfunc;
+       const struct renesas_usbhs_platform_info *info;
        struct usbhs_priv *priv;
        struct resource *res, *irq_res;
-       int ret;
+       struct device *dev = &pdev->dev;
+       int ret, gpio;
+       u32 tmp;
 
        /* check device node */
-       if (pdev->dev.of_node)
-               info = pdev->dev.platform_data = usbhs_parse_dt(&pdev->dev);
+       if (dev_of_node(dev))
+               info = of_device_get_match_data(dev);
+       else
+               info = renesas_usbhs_get_info(pdev);
 
        /* check platform information */
        if (!info) {
-               dev_err(&pdev->dev, "no platform information\n");
+               dev_err(dev, "no platform information\n");
                return -EINVAL;
        }
 
        /* platform data */
        irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!irq_res) {
-               dev_err(&pdev->dev, "Not enough Renesas USB platform resources.\n");
+               dev_err(dev, "Not enough Renesas USB platform resources.\n");
                return -ENODEV;
        }
 
        /* usb private data */
-       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
@@ -658,13 +624,13 @@ static int usbhs_probe(struct platform_device *pdev)
        if (IS_ERR(priv->base))
                return PTR_ERR(priv->base);
 
-       if (of_property_read_bool(pdev->dev.of_node, "extcon")) {
-               priv->edev = extcon_get_edev_by_phandle(&pdev->dev, 0);
+       if (of_property_read_bool(dev_of_node(dev), "extcon")) {
+               priv->edev = extcon_get_edev_by_phandle(dev, 0);
                if (IS_ERR(priv->edev))
                        return PTR_ERR(priv->edev);
        }
 
-       priv->rsts = devm_reset_control_array_get_optional_shared(&pdev->dev);
+       priv->rsts = devm_reset_control_array_get_optional_shared(dev);
        if (IS_ERR(priv->rsts))
                return PTR_ERR(priv->rsts);
 
@@ -672,50 +638,35 @@ static int usbhs_probe(struct platform_device *pdev)
         * care platform info
         */
 
-       memcpy(&priv->dparam,
-              &info->driver_param,
-              sizeof(struct renesas_usbhs_driver_param));
+       priv->dparam = info->driver_param;
 
-       switch (priv->dparam.type) {
-       case USBHS_TYPE_RCAR_GEN2:
-               priv->pfunc = usbhs_rcar2_ops;
-               break;
-       case USBHS_TYPE_RCAR_GEN3:
-               priv->pfunc = usbhs_rcar3_ops;
-               break;
-       case USBHS_TYPE_RCAR_GEN3_WITH_PLL:
-               priv->pfunc = usbhs_rcar3_with_pll_ops;
-               break;
-       case USBHS_TYPE_RZA1:
-               priv->pfunc = usbhs_rza1_ops;
-               break;
-       default:
-               if (!info->platform_callback.get_id) {
-                       dev_err(&pdev->dev, "no platform callbacks");
-                       return -EINVAL;
-               }
-               memcpy(&priv->pfunc,
-                      &info->platform_callback,
-                      sizeof(struct renesas_usbhs_platform_callback));
-               break;
+       if (!info->platform_callback.get_id) {
+               dev_err(dev, "no platform callbacks\n");
+               return -EINVAL;
        }
-
-       /* set driver callback functions for platform */
-       dfunc                   = &info->driver_callback;
-       dfunc->notify_hotplug   = usbhsc_drvcllbck_notify_hotplug;
+       priv->pfunc = &info->platform_callback;
 
        /* set default param if platform doesn't have */
-       if (!priv->dparam.pipe_configs) {
+       if (usbhs_get_dparam(priv, has_new_pipe_configs)) {
+               priv->dparam.pipe_configs = usbhsc_new_pipe;
+               priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
+       } else if (!priv->dparam.pipe_configs) {
                priv->dparam.pipe_configs = usbhsc_default_pipe;
                priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_default_pipe);
        }
        if (!priv->dparam.pio_dma_border)
                priv->dparam.pio_dma_border = 64; /* 64byte */
+       if (!of_property_read_u32(dev_of_node(dev), "renesas,buswait", &tmp))
+               priv->dparam.buswait_bwait = tmp;
+       gpio = of_get_named_gpio_flags(dev_of_node(dev), "renesas,enable-gpio",
+                                      0, NULL);
+       if (gpio > 0)
+               priv->dparam.enable_gpio = gpio;
 
        /* FIXME */
        /* runtime power control ? */
-       if (priv->pfunc.get_vbus)
-               usbhsc_flags_set(priv, USBHSF_RUNTIME_PWCTRL);
+       if (priv->pfunc->get_vbus)
+               usbhs_get_dparam(priv, runtime_pwctrl) = 1;
 
        /*
         * priv settings
@@ -747,7 +698,7 @@ static int usbhs_probe(struct platform_device *pdev)
        if (ret)
                goto probe_fail_rst;
 
-       ret = usbhsc_clk_get(&pdev->dev, priv);
+       ret = usbhsc_clk_get(dev, priv);
        if (ret)
                goto probe_fail_clks;
 
@@ -763,8 +714,7 @@ static int usbhs_probe(struct platform_device *pdev)
                ret = !gpio_get_value(priv->dparam.enable_gpio);
                gpio_free(priv->dparam.enable_gpio);
                if (ret) {
-                       dev_warn(&pdev->dev,
-                                "USB function not selected (GPIO %d)\n",
+                       dev_warn(dev, "USB function not selected (GPIO %d)\n",
                                 priv->dparam.enable_gpio);
                        ret = -ENOTSUPP;
                        goto probe_end_mod_exit;
@@ -780,7 +730,7 @@ static int usbhs_probe(struct platform_device *pdev)
         */
        ret = usbhs_platform_call(priv, hardware_init, pdev);
        if (ret < 0) {
-               dev_err(&pdev->dev, "platform init failed.\n");
+               dev_err(dev, "platform init failed.\n");
                goto probe_end_mod_exit;
        }
 
@@ -788,18 +738,20 @@ static int usbhs_probe(struct platform_device *pdev)
        usbhs_platform_call(priv, phy_reset, pdev);
 
        /* power control */
-       pm_runtime_enable(&pdev->dev);
-       if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) {
+       pm_runtime_enable(dev);
+       if (!usbhs_get_dparam(priv, runtime_pwctrl)) {
                usbhsc_power_ctrl(priv, 1);
                usbhs_mod_autonomy_mode(priv);
+       } else {
+               usbhs_mod_non_autonomy_mode(priv);
        }
 
        /*
         * manual call notify_hotplug for cold plug
         */
-       usbhsc_drvcllbck_notify_hotplug(pdev);
+       usbhsc_schedule_notify_hotplug(pdev);
 
-       dev_info(&pdev->dev, "probed\n");
+       dev_info(dev, "probed\n");
 
        return ret;
 
@@ -814,7 +766,7 @@ probe_end_fifo_exit:
 probe_end_pipe_exit:
        usbhs_pipe_remove(priv);
 
-       dev_info(&pdev->dev, "probe failed (%d)\n", ret);
+       dev_info(dev, "probe failed (%d)\n", ret);
 
        return ret;
 }
@@ -822,15 +774,11 @@ probe_end_pipe_exit:
 static int usbhs_remove(struct platform_device *pdev)
 {
        struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
-       struct renesas_usbhs_platform_info *info = renesas_usbhs_get_info(pdev);
-       struct renesas_usbhs_driver_callback *dfunc = &info->driver_callback;
 
        dev_dbg(&pdev->dev, "usb remove\n");
 
-       dfunc->notify_hotplug = NULL;
-
        /* power off */
-       if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
+       if (!usbhs_get_dparam(priv, runtime_pwctrl))
                usbhsc_power_ctrl(priv, 0);
 
        pm_runtime_disable(&pdev->dev);
@@ -855,7 +803,7 @@ static __maybe_unused int usbhsc_suspend(struct device *dev)
                usbhs_mod_change(priv, -1);
        }
 
-       if (mod || !usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
+       if (mod || !usbhs_get_dparam(priv, runtime_pwctrl))
                usbhsc_power_ctrl(priv, 0);
 
        return 0;
@@ -866,14 +814,14 @@ static __maybe_unused int usbhsc_resume(struct device *dev)
        struct usbhs_priv *priv = dev_get_drvdata(dev);
        struct platform_device *pdev = usbhs_priv_to_pdev(priv);
 
-       if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) {
+       if (!usbhs_get_dparam(priv, runtime_pwctrl)) {
                usbhsc_power_ctrl(priv, 1);
                usbhs_mod_autonomy_mode(priv);
        }
 
        usbhs_platform_call(priv, phy_reset, pdev);
 
-       usbhsc_drvcllbck_notify_hotplug(pdev);
+       usbhsc_schedule_notify_hotplug(pdev);
 
        return 0;
 }
index 3777af8..d1a0a35 100644 (file)
@@ -3,6 +3,7 @@
  * Renesas USB driver
  *
  * Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2019 Renesas Electronics Corporation
  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
  */
 #ifndef RENESAS_USB_DRIVER_H
@@ -104,6 +105,7 @@ struct usbhs_priv;
 
 /* SYSCFG */
 #define SCKE   (1 << 10)       /* USB Module Clock Enable */
+#define CNEN   (1 << 8)        /* Single-ended receiver operation Enable */
 #define HSE    (1 << 7)        /* High-Speed Operation Enable */
 #define DCFM   (1 << 6)        /* Controller Function Select */
 #define DRPD   (1 << 5)        /* D+ Line/D- Line Resistance Control */
@@ -250,7 +252,7 @@ struct usbhs_priv {
        unsigned int irq;
        unsigned long irqflags;
 
-       struct renesas_usbhs_platform_callback  pfunc;
+       const struct renesas_usbhs_platform_callback *pfunc;
        struct renesas_usbhs_driver_param       dparam;
 
        struct delayed_work notify_hotplug_work;
@@ -260,8 +262,6 @@ struct usbhs_priv {
 
        spinlock_t              lock;
 
-       u32 flags;
-
        /*
         * module control
         */
@@ -292,6 +292,8 @@ void usbhs_bset(struct usbhs_priv *priv, u32 reg, u16 mask, u16 data);
 #define usbhs_lock(p, f) spin_lock_irqsave(usbhs_priv_to_lock(p), f)
 #define usbhs_unlock(p, f) spin_unlock_irqrestore(usbhs_priv_to_lock(p), f)
 
+int usbhs_get_id_as_gadget(struct platform_device *pdev);
+
 /*
  * sysconfig
  */
@@ -313,6 +315,7 @@ void usbhs_bus_send_sof_enable(struct usbhs_priv *priv);
 void usbhs_bus_send_reset(struct usbhs_priv *priv);
 int usbhs_bus_get_speed(struct usbhs_priv *priv);
 int usbhs_vbus_ctrl(struct usbhs_priv *priv, int enable);
+int usbhsc_schedule_notify_hotplug(struct platform_device *pdev);
 
 /*
  * frame
index 39fa2fc..2a01ceb 100644 (file)
@@ -3,6 +3,7 @@
  * Renesas USB driver
  *
  * Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2019 Renesas Electronics Corporation
  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
  */
 #include <linux/delay.h>
@@ -12,7 +13,6 @@
 #include "pipe.h"
 
 #define usbhsf_get_cfifo(p)    (&((p)->fifo_info.cfifo))
-#define usbhsf_is_cfifo(p, f)  (usbhsf_get_cfifo(p) == f)
 
 #define usbhsf_fifo_is_busy(f) ((f)->pipe) /* see usbhs_pipe_select_fifo */
 
@@ -325,10 +325,7 @@ static int usbhsf_fifo_select(struct usbhs_pipe *pipe,
        }
 
        /* "base" will be used below  */
-       if (usbhs_get_dparam(priv, has_sudmac) && !usbhsf_is_cfifo(priv, fifo))
-               usbhs_write(priv, fifo->sel, base);
-       else
-               usbhs_write(priv, fifo->sel, base | MBW_32);
+       usbhs_write(priv, fifo->sel, base | MBW_32);
 
        /* check ISEL and CURPIPE value */
        while (timeout--) {
@@ -543,8 +540,13 @@ static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done)
        }
 
        /* the rest operation */
-       for (i = 0; i < len; i++)
-               iowrite8(buf[i], addr + (0x03 - (i & 0x03)));
+       if (usbhs_get_dparam(priv, cfifo_byte_addr)) {
+               for (i = 0; i < len; i++)
+                       iowrite8(buf[i], addr + (i & 0x03));
+       } else {
+               for (i = 0; i < len; i++)
+                       iowrite8(buf[i], addr + (0x03 - (i & 0x03)));
+       }
 
        /*
         * variable update
@@ -802,9 +804,8 @@ static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
 }
 
 static void usbhsf_dma_complete(void *arg);
-static void xfer_work(struct work_struct *work)
+static void usbhsf_dma_xfer_preparing(struct usbhs_pkt *pkt)
 {
-       struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work);
        struct usbhs_pipe *pipe = pkt->pipe;
        struct usbhs_fifo *fifo;
        struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
@@ -812,12 +813,10 @@ static void xfer_work(struct work_struct *work)
        struct dma_chan *chan;
        struct device *dev = usbhs_priv_to_dev(priv);
        enum dma_transfer_direction dir;
-       unsigned long flags;
 
-       usbhs_lock(priv, flags);
        fifo = usbhs_pipe_to_fifo(pipe);
        if (!fifo)
-               goto xfer_work_end;
+               return;
 
        chan = usbhsf_dma_chan_get(fifo, pkt);
        dir = usbhs_pipe_is_dir_in(pipe) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
@@ -826,7 +825,7 @@ static void xfer_work(struct work_struct *work)
                                        pkt->trans, dir,
                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!desc)
-               goto xfer_work_end;
+               return;
 
        desc->callback          = usbhsf_dma_complete;
        desc->callback_param    = pipe;
@@ -834,7 +833,7 @@ static void xfer_work(struct work_struct *work)
        pkt->cookie = dmaengine_submit(desc);
        if (pkt->cookie < 0) {
                dev_err(dev, "Failed to submit dma descriptor\n");
-               goto xfer_work_end;
+               return;
        }
 
        dev_dbg(dev, "  %s %d (%d/ %d)\n",
@@ -845,8 +844,17 @@ static void xfer_work(struct work_struct *work)
        dma_async_issue_pending(chan);
        usbhsf_dma_start(pipe, fifo);
        usbhs_pipe_enable(pipe);
+}
 
-xfer_work_end:
+static void xfer_work(struct work_struct *work)
+{
+       struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work);
+       struct usbhs_pipe *pipe = pkt->pipe;
+       struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
+       unsigned long flags;
+
+       usbhs_lock(priv, flags);
+       usbhsf_dma_xfer_preparing(pkt);
        usbhs_unlock(priv, flags);
 }
 
@@ -899,8 +907,13 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
        pkt->trans = len;
 
        usbhsf_tx_irq_ctrl(pipe, 0);
-       INIT_WORK(&pkt->work, xfer_work);
-       schedule_work(&pkt->work);
+       /* FIXME: Workaound for usb dmac that driver can be used in atomic */
+       if (usbhs_get_dparam(priv, has_usb_dmac)) {
+               usbhsf_dma_xfer_preparing(pkt);
+       } else {
+               INIT_WORK(&pkt->work, xfer_work);
+               schedule_work(&pkt->work);
+       }
 
        return 0;
 
@@ -1006,8 +1019,7 @@ static int usbhsf_dma_prepare_pop_with_usb_dmac(struct usbhs_pkt *pkt,
 
        pkt->trans = pkt->length;
 
-       INIT_WORK(&pkt->work, xfer_work);
-       schedule_work(&pkt->work);
+       usbhsf_dma_xfer_preparing(pkt);
 
        return 0;
 
@@ -1276,7 +1288,7 @@ static void usbhsf_dma_init(struct usbhs_priv *priv, struct usbhs_fifo *fifo,
 {
        struct device *dev = usbhs_priv_to_dev(priv);
 
-       if (dev->of_node)
+       if (dev_of_node(dev))
                usbhsf_dma_init_dt(dev, fifo, channel);
        else
                usbhsf_dma_init_pdev(fifo);
index 7475c4f..10fc655 100644 (file)
@@ -3,6 +3,7 @@
  * Renesas USB driver
  *
  * Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2019 Renesas Electronics Corporation
  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
  */
 #include <linux/interrupt.h>
 #include "common.h"
 #include "mod.h"
 
-#define usbhs_priv_to_modinfo(priv) (&priv->mod_info)
-#define usbhs_mod_info_call(priv, func, param...)      \
-({                                             \
-       struct usbhs_mod_info *info;            \
-       info = usbhs_priv_to_modinfo(priv);     \
-       !info->func ? 0 :                       \
-        info->func(param);                     \
-})
-
 /*
  *             autonomy
  *
@@ -41,7 +33,7 @@ static int usbhsm_autonomy_irq_vbus(struct usbhs_priv *priv,
 {
        struct platform_device *pdev = usbhs_priv_to_pdev(priv);
 
-       renesas_usbhs_call_notify_hotplug(pdev);
+       usbhsc_schedule_notify_hotplug(pdev);
 
        return 0;
 }
@@ -50,12 +42,19 @@ void usbhs_mod_autonomy_mode(struct usbhs_priv *priv)
 {
        struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
 
-       info->irq_vbus          = usbhsm_autonomy_irq_vbus;
-       priv->pfunc.get_vbus    = usbhsm_autonomy_get_vbus;
+       info->irq_vbus = usbhsm_autonomy_irq_vbus;
+       info->get_vbus = usbhsm_autonomy_get_vbus;
 
        usbhs_irq_callback_update(priv, NULL);
 }
 
+void usbhs_mod_non_autonomy_mode(struct usbhs_priv *priv)
+{
+       struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
+
+       info->get_vbus = priv->pfunc->get_vbus;
+}
+
 /*
  *             host / gadget functions
  *
index a4a61d6..65dc19c 100644 (file)
@@ -3,6 +3,7 @@
  * Renesas USB driver
  *
  * Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2019 Renesas Electronics Corporation
  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
  */
 #ifndef RENESAS_USB_MOD_H
@@ -84,15 +85,20 @@ struct usbhs_mod_info {
        /*
         * INTSTS0 :: VBINT
         *
-        * This function will be used as autonomy mode
-        * when platform cannot call notify_hotplug.
+        * This function will be used as autonomy mode (runtime_pwctrl == 0)
+        * when the platform doesn't have own get_vbus function.
         *
-        * This callback cannot be member of "struct usbhs_mod"
-        * because it will be used even though
-        * host/gadget has not been selected.
+        * This callback cannot be member of "struct usbhs_mod" because it
+        * will be used even though host/gadget has not been selected.
         */
        int (*irq_vbus)(struct usbhs_priv *priv,
                        struct usbhs_irq_state *irq_state);
+
+       /*
+        * This function will be used on any gadget mode. To simplify the code,
+        * this member is in here.
+        */
+       int (*get_vbus)(struct platform_device *pdev);
 };
 
 /*
@@ -107,6 +113,7 @@ int usbhs_mod_probe(struct usbhs_priv *priv);
 void usbhs_mod_remove(struct usbhs_priv *priv);
 
 void usbhs_mod_autonomy_mode(struct usbhs_priv *priv);
+void usbhs_mod_non_autonomy_mode(struct usbhs_priv *priv);
 
 /*
  *             status functions
@@ -129,6 +136,15 @@ void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod);
                 mod->func(param);                      \
        })
 
+#define usbhs_priv_to_modinfo(priv) (&priv->mod_info)
+#define usbhs_mod_info_call(priv, func, param...)      \
+({                                                     \
+       struct usbhs_mod_info *info;                    \
+       info = usbhs_priv_to_modinfo(priv);             \
+       !info->func ? 0 :                               \
+        info->func(param);                             \
+})
+
 /*
  * host / gadget control
  */
index 59cac40..4d571a5 100644 (file)
@@ -3,6 +3,7 @@
  * Renesas USB driver
  *
  * Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2019 Renesas Electronics Corporation
  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
  */
 #include <linux/delay.h>
@@ -914,8 +915,8 @@ static void usbhs_mod_phy_mode(struct usbhs_priv *priv)
 {
        struct usbhs_mod_info *info = &priv->mod_info;
 
-       info->irq_vbus          = NULL;
-       priv->pfunc.get_vbus    = usbhsm_phy_get_vbus;
+       info->irq_vbus = NULL;
+       info->get_vbus = usbhsm_phy_get_vbus;
 
        usbhs_irq_callback_update(priv, NULL);
 }
@@ -1023,7 +1024,7 @@ static int usbhsg_vbus_session(struct usb_gadget *gadget, int is_active)
 
        gpriv->vbus_active = !!is_active;
 
-       renesas_usbhs_call_notify_hotplug(pdev);
+       usbhsc_schedule_notify_hotplug(pdev);
 
        return 0;
 }
index 0027092..440d213 100644 (file)
@@ -3,6 +3,7 @@
  * Renesas USB driver R-Car Gen. 2 initialization and power control
  *
  * Copyright (C) 2014 Ulrich Hecht
+ * Copyright (C) 2019 Renesas Electronics Corporation
  */
 
 #include <linux/gpio.h>
@@ -62,14 +63,15 @@ static int usbhs_rcar2_power_ctrl(struct platform_device *pdev,
        return retval;
 }
 
-static int usbhs_rcar2_get_id(struct platform_device *pdev)
-{
-       return USBHS_GADGET;
-}
-
-const struct renesas_usbhs_platform_callback usbhs_rcar2_ops = {
-       .hardware_init = usbhs_rcar2_hardware_init,
-       .hardware_exit = usbhs_rcar2_hardware_exit,
-       .power_ctrl = usbhs_rcar2_power_ctrl,
-       .get_id = usbhs_rcar2_get_id,
+const struct renesas_usbhs_platform_info usbhs_rcar_gen2_plat_info = {
+       .platform_callback = {
+               .hardware_init = usbhs_rcar2_hardware_init,
+               .hardware_exit = usbhs_rcar2_hardware_exit,
+               .power_ctrl = usbhs_rcar2_power_ctrl,
+               .get_id = usbhs_get_id_as_gadget,
+       },
+       .driver_param = {
+               .has_usb_dmac = 1,
+               .has_new_pipe_configs = 1,
+       },
 };
index 45e3526..7d88732 100644 (file)
@@ -1,5 +1,4 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "common.h"
 
-extern const struct renesas_usbhs_platform_callback
-       usbhs_rcar2_ops;
+extern const struct renesas_usbhs_platform_info usbhs_rcar_gen2_plat_info;
index 5e730e9..c181b2a 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Renesas USB driver R-Car Gen. 3 initialization and power control
  *
- * Copyright (C) 2016 Renesas Electronics Corporation
+ * Copyright (C) 2016-2019 Renesas Electronics Corporation
  */
 
 #include <linux/delay.h>
@@ -95,17 +95,26 @@ static int usbhs_rcar3_power_and_pll_ctrl(struct platform_device *pdev,
        return 0;
 }
 
-static int usbhs_rcar3_get_id(struct platform_device *pdev)
-{
-       return USBHS_GADGET;
-}
-
-const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = {
-       .power_ctrl = usbhs_rcar3_power_ctrl,
-       .get_id = usbhs_rcar3_get_id,
+const struct renesas_usbhs_platform_info usbhs_rcar_gen3_plat_info = {
+       .platform_callback = {
+               .power_ctrl = usbhs_rcar3_power_ctrl,
+               .get_id = usbhs_get_id_as_gadget,
+       },
+       .driver_param = {
+               .has_usb_dmac = 1,
+               .multi_clks = 1,
+               .has_new_pipe_configs = 1,
+       },
 };
 
-const struct renesas_usbhs_platform_callback usbhs_rcar3_with_pll_ops = {
-       .power_ctrl = usbhs_rcar3_power_and_pll_ctrl,
-       .get_id = usbhs_rcar3_get_id,
+const struct renesas_usbhs_platform_info usbhs_rcar_gen3_with_pll_plat_info = {
+       .platform_callback = {
+               .power_ctrl = usbhs_rcar3_power_and_pll_ctrl,
+               .get_id = usbhs_get_id_as_gadget,
+       },
+       .driver_param = {
+               .has_usb_dmac = 1,
+               .multi_clks = 1,
+               .has_new_pipe_configs = 1,
+       },
 };
index 49e535a..c7c5ec1 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "common.h"
 
-extern const struct renesas_usbhs_platform_callback usbhs_rcar3_ops;
-extern const struct renesas_usbhs_platform_callback usbhs_rcar3_with_pll_ops;
+extern const struct renesas_usbhs_platform_info usbhs_rcar_gen3_plat_info;
+extern const struct renesas_usbhs_platform_info
+                                       usbhs_rcar_gen3_with_pll_plat_info;
index 8c739bd..24de64e 100644 (file)
@@ -3,7 +3,7 @@
  * Renesas USB driver RZ/A initialization and power control
  *
  * Copyright (C) 2018 Chris Brandt
- * Copyright (C) 2018 Renesas Electronics Corporation
+ * Copyright (C) 2018-2019 Renesas Electronics Corporation
  */
 
 #include <linux/delay.h>
@@ -41,12 +41,12 @@ static int usbhs_rza1_hardware_init(struct platform_device *pdev)
        return 0;
 }
 
-static int usbhs_rza_get_id(struct platform_device *pdev)
-{
-       return USBHS_GADGET;
-}
-
-const struct renesas_usbhs_platform_callback usbhs_rza1_ops = {
-       .hardware_init = usbhs_rza1_hardware_init,
-       .get_id = usbhs_rza_get_id,
+const struct renesas_usbhs_platform_info usbhs_rza1_plat_info = {
+       .platform_callback = {
+               .hardware_init = usbhs_rza1_hardware_init,
+               .get_id = usbhs_get_id_as_gadget,
+       },
+       .driver_param = {
+               .has_new_pipe_configs = 1,
+       },
 };
index ca917ca..1ca42a6 100644 (file)
@@ -1,4 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "common.h"
 
-extern const struct renesas_usbhs_platform_callback usbhs_rza1_ops;
+extern const struct renesas_usbhs_platform_info usbhs_rza1_plat_info;
+extern const struct renesas_usbhs_platform_info usbhs_rza2_plat_info;
diff --git a/drivers/usb/renesas_usbhs/rza2.c b/drivers/usb/renesas_usbhs/rza2.c
new file mode 100644 (file)
index 0000000..0217495
--- /dev/null
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas USB driver RZ/A2 initialization and power control
+ *
+ * Copyright (C) 2019 Chris Brandt
+ * Copyright (C) 2019 Renesas Electronics Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include "common.h"
+#include "rza.h"
+
+static int usbhs_rza2_hardware_init(struct platform_device *pdev)
+{
+       struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
+       struct phy *phy = phy_get(&pdev->dev, "usb");
+
+       if (IS_ERR(phy))
+               return PTR_ERR(phy);
+
+       priv->phy = phy;
+       return 0;
+}
+
+static int usbhs_rza2_hardware_exit(struct platform_device *pdev)
+{
+       struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
+
+       phy_put(priv->phy);
+       priv->phy = NULL;
+
+       return 0;
+}
+
+static int usbhs_rza2_power_ctrl(struct platform_device *pdev,
+                               void __iomem *base, int enable)
+{
+       struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
+       int retval = 0;
+
+       if (!priv->phy)
+               return -ENODEV;
+
+       if (enable) {
+               retval = phy_init(priv->phy);
+               usbhs_bset(priv, SUSPMODE, SUSPM, SUSPM);
+               udelay(100);    /* Wait for PLL to become stable */
+               if (!retval)
+                       retval = phy_power_on(priv->phy);
+       } else {
+               usbhs_bset(priv, SUSPMODE, SUSPM, 0);
+               phy_power_off(priv->phy);
+               phy_exit(priv->phy);
+       }
+
+       return retval;
+}
+
+const struct renesas_usbhs_platform_info usbhs_rza2_plat_info = {
+       .platform_callback = {
+               .hardware_init = usbhs_rza2_hardware_init,
+               .hardware_exit = usbhs_rza2_hardware_exit,
+               .power_ctrl = usbhs_rza2_power_ctrl,
+               .get_id = usbhs_get_id_as_gadget,
+       },
+       .driver_param = {
+               .has_cnen = 1,
+               .cfifo_byte_addr = 1,
+               .has_new_pipe_configs = 1,
+       },
+};
index 7d03191..67279c6 100644 (file)
@@ -11,7 +11,7 @@ menuconfig USB_SERIAL
          ports, or acts like a serial device, and you want to connect it to
          your USB bus.
 
-         Please read <file:Documentation/usb/usb-serial.txt> for more
+         Please read <file:Documentation/usb/usb-serial.rst> for more
          information on the specifics of the different devices that are
          supported, and on how to use them.
 
@@ -47,7 +47,7 @@ config USB_SERIAL_GENERIC
        bool "USB Generic Serial Driver"
        help
          Say Y here if you want to use the generic USB serial driver.  Please
-         read <file:Documentation/usb/usb-serial.txt> for more information on
+         read <file:Documentation/usb/usb-serial.rst> for more information on
          using this driver.  It is recommended that the "USB Serial converter
          support" be compiled as a module for this driver to be used
          properly.
@@ -163,7 +163,7 @@ config USB_SERIAL_EMPEG
        help
          Say Y here if you want to connect to your Empeg empeg-car Mark I/II
          mp3 player via USB.  The driver uses a single ttyUSB{0,1,2,...}
-         device node.  See <file:Documentation/usb/usb-serial.txt> for more
+         device node.  See <file:Documentation/usb/usb-serial.rst> for more
          tidbits of information.
 
          To compile this driver as a module, choose M here: the
@@ -199,7 +199,7 @@ config USB_SERIAL_IPAQ
          Say Y here if you want to connect to your Compaq iPAQ, HP Jornada
          or any other PDA running Windows CE 3.0 or PocketPC 2002
          using a USB cradle/cable. For information on using the driver,
-         read <file:Documentation/usb/usb-serial.txt>.
+         read <file:Documentation/usb/usb-serial.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called ipaq.
@@ -334,7 +334,7 @@ config USB_SERIAL_KLSI
          adapter sold by Palm Inc. for use with their Palm III and Palm V
          series PDAs.
 
-         Please read <file:Documentation/usb/usb-serial.txt> for more
+         Please read <file:Documentation/usb/usb-serial.rst> for more
          information.
 
          To compile this driver as a module, choose M here: the
index c1235d5..9bb123a 100644 (file)
@@ -10,7 +10,7 @@
  *  and associated source files.  Please see the usb/serial files for
  *  individual credits and copyrights.
  *
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
  * driver
  *
  * TODO:
index 51bc062..a13a98d 100644 (file)
@@ -9,7 +9,7 @@
  *  and associated source files.  Please see the usb/serial files for
  *  individual credits and copyrights.
  *
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
  * driver
  *
  * 12-Mar-2001 gkh
index 72d3ae1..216edd5 100644 (file)
@@ -7,7 +7,7 @@
  *     Copyright (C) 2003,2004
  *         Neil Whelchel (koyama@firstlight.net)
  *
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
  * driver
  *
  * See http://geocities.com/i0xox0i for information on this driver and the
index d680bec..405e835 100644 (file)
@@ -8,7 +8,7 @@
  *     Copyright (C) 1999 - 2001
  *         Greg Kroah-Hartman (greg@kroah.com)
  *
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
  * driver
  */
 
index 1d8461a..4b3a049 100644 (file)
@@ -10,7 +10,7 @@
  *     Copyright (C) 2002
  *         Kuba Ober (kuba@mareimbrium.org)
  *
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
  * driver
  *
  * See http://ftdi-usb-sio.sourceforge.net for up to date testing info
@@ -1029,6 +1029,7 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(AIRBUS_DS_VID, AIRBUS_DS_P8GR) },
        /* EZPrototypes devices */
        { USB_DEVICE(EZPROTOTYPES_VID, HJELMSLUND_USB485_ISO_PID) },
+       { USB_DEVICE_INTERFACE_NUMBER(UNJO_VID, UNJO_ISODEBUG_V1_PID, 1) },
        { }                                     /* Terminating entry */
 };
 
index 5755f0d..f12d806 100644 (file)
 #define CHETCO_SEASMART_DISPLAY_PID    0xA5AD /* SeaSmart NMEA2000 Display */
 #define CHETCO_SEASMART_LITE_PID       0xA5AE /* SeaSmart Lite USB Adapter */
 #define CHETCO_SEASMART_ANALOG_PID     0xA5AF /* SeaSmart Analog Adapter */
+
+/*
+ * Unjo AB
+ */
+#define UNJO_VID                       0x22B7
+#define UNJO_ISODEBUG_V1_PID           0x150D
index 7643716..302eb95 100644 (file)
@@ -16,7 +16,7 @@
  * was written by Roman Weissgaerber <weissg@vienna.at>, Dag Brattli
  * <dag@brattli.net>, and Jean Tourrilhes <jt@hpl.hp.com>
  *
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
  * driver
  */
 
index 38d43c4..bf988f7 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright (C) 1999, 2000 Brian Warner       <warner@lothar.com>
  * Copyright (C) 2000 Al Borchers              <borchers@steinerpoint.com>
  *
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
  * driver
  */
 
index e51c946..5b6e982 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright (C) 2013,2017 Johan Hovold <johan@kernel.org>
  *
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
  * driver
  *
  * Please report both successes and troubles to the author at omninet@kroah.com
index a0aaf06..c1582fb 100644 (file)
@@ -1343,6 +1343,7 @@ static const struct usb_device_id option_ids[] = {
          .driver_info = RSVD(4) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0414, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0417, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_INTERFACE_CLASS(ZTE_VENDOR_ID, 0x0601, 0xff) },    /* GosunCn ZTE WeLink ME3630 (RNDIS mode) */
        { USB_DEVICE_INTERFACE_CLASS(ZTE_VENDOR_ID, 0x0602, 0xff) },    /* GosunCn ZTE WeLink ME3630 (MBIM mode) */
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff),
          .driver_info = RSVD(4) },
index 38ae0fc..8151dd7 100644 (file)
@@ -22,7 +22,7 @@
  * So, THIS CODE CAN DESTROY OTi-6858 AND ANY OTHER DEVICES, THAT ARE
  * CONNECTED TO IT!
  *
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
  * driver
  *
  * TODO:
index d7abde1..9d27b76 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Original driver for 2.2.x by anonymous
  *
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
  * driver
  */
 
index 676c296..a3179fe 100644 (file)
@@ -10,7 +10,7 @@
  * This driver was originally based on the ACM driver by Armin Fuerst (which was
  * based on a driver by Brad Keryan)
  *
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
  * driver
  */
 
index 8ddbecc..4412834 100644 (file)
@@ -6,7 +6,7 @@
  *     Copyright (C) 1999 - 2004
  *         Greg Kroah-Hartman (greg@kroah.com)
  *
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
  * driver
  *
  */
index fe29024..4bd69d0 100644 (file)
@@ -5,7 +5,7 @@
  *     Copyright (C) 1999 - 2003
  *         Greg Kroah-Hartman (greg@kroah.com)
  *
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
  * driver.
  *
  */
index aefd84f..79314d8 100644 (file)
@@ -8,7 +8,7 @@
  *     Copyright (C) 1999 - 2001
  *         Greg Kroah-Hartman (greg@kroah.com)
  *
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
  * driver
  */
 
index 72c1b0c..0039814 100644 (file)
@@ -8,7 +8,7 @@
  *      Copyright (C) 1999, 2000
  *          Greg Kroah-Hartman (greg@kroah.com)
  *
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
  * driver
  *
  */
index 59190d8..3079024 100644 (file)
@@ -195,8 +195,11 @@ static int slave_configure(struct scsi_device *sdev)
                 */
                sdev->skip_ms_page_8 = 1;
 
-               /* Some devices don't handle VPD pages correctly */
-               sdev->skip_vpd_pages = 1;
+               /*
+                * Some devices don't handle VPD pages correctly, so skip vpd
+                * pages if not forced by SCSI layer.
+                */
+               sdev->skip_vpd_pages = !sdev->try_vpd_pages;
 
                /* Do not attempt to use REPORT SUPPORTED OPERATION CODES */
                sdev->no_report_opcodes = 1;
index 7302f75..c524088 100644 (file)
@@ -1697,13 +1697,12 @@ static int fusb302_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
        struct fusb302_chip *chip;
-       struct i2c_adapter *adapter;
+       struct i2c_adapter *adapter = client->adapter;
        struct device *dev = &client->dev;
        const char *name;
        int ret = 0;
        u32 v;
 
-       adapter = to_i2c_adapter(client->dev.parent);
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
                dev_err(&client->dev,
                        "I2C/SMBus block functionality not supported!\n");
index c674abe..a38d140 100644 (file)
@@ -41,7 +41,7 @@
 #define TPS_STATUS_VCONN(s)            (!!((s) & BIT(7)))
 
 /* TPS_REG_SYSTEM_CONF bits */
-#define TPS_SYSCONF_PORTINFO(c)                ((c) & 3)
+#define TPS_SYSCONF_PORTINFO(c)                ((c) & 7)
 
 enum {
        TPS_PORTINFO_SINK,
@@ -127,7 +127,7 @@ tps6598x_block_read(struct tps6598x *tps, u8 reg, void *val, size_t len)
 }
 
 static int tps6598x_block_write(struct tps6598x *tps, u8 reg,
-                               void *val, size_t len)
+                               const void *val, size_t len)
 {
        u8 data[TPS_MAX_LEN + 1];
 
@@ -173,7 +173,7 @@ static inline int tps6598x_write64(struct tps6598x *tps, u8 reg, u64 val)
 static inline int
 tps6598x_write_4cc(struct tps6598x *tps, u8 reg, const char *val)
 {
-       return tps6598x_block_write(tps, reg, &val, sizeof(u32));
+       return tps6598x_block_write(tps, reg, val, 4);
 }
 
 static int tps6598x_read_partner_identity(struct tps6598x *tps)
index bf8a5fe..2e4bfcc 100644 (file)
@@ -201,7 +201,7 @@ static DRIVER_ATTR_RW(match_busid);
 
 static int do_rebind(char *busid, struct bus_id_priv *busid_priv)
 {
-       int ret;
+       int ret = 0;
 
        /* device_attach() callers should hold parent lock for USB */
        if (busid_priv->udev->dev.parent)
@@ -209,11 +209,9 @@ static int do_rebind(char *busid, struct bus_id_priv *busid_priv)
        ret = device_attach(&busid_priv->udev->dev);
        if (busid_priv->udev->dev.parent)
                device_unlock(busid_priv->udev->dev.parent);
-       if (ret < 0) {
+       if (ret < 0)
                dev_err(&busid_priv->udev->dev, "rebind failed\n");
-               return ret;
-       }
-       return 0;
+       return ret;
 }
 
 static void stub_device_rebind(void)
index 9aed15a..2fa26d0 100644 (file)
@@ -144,16 +144,14 @@ static int vhci_send_cmd_unlink(struct vhci_device *vdev)
        struct vhci_unlink *unlink = NULL;
 
        struct msghdr msg;
-       struct kvec iov[3];
+       struct kvec iov;
        size_t txsize;
-
        size_t total_size = 0;
 
        while ((unlink = dequeue_from_unlink_tx(vdev)) != NULL) {
                int ret;
                struct usbip_header pdu_header;
 
-               txsize = 0;
                memset(&pdu_header, 0, sizeof(pdu_header));
                memset(&msg, 0, sizeof(msg));
                memset(&iov, 0, sizeof(iov));
@@ -169,11 +167,11 @@ static int vhci_send_cmd_unlink(struct vhci_device *vdev)
 
                usbip_header_correct_endian(&pdu_header, 1);
 
-               iov[0].iov_base = &pdu_header;
-               iov[0].iov_len  = sizeof(pdu_header);
-               txsize += sizeof(pdu_header);
+               iov.iov_base = &pdu_header;
+               iov.iov_len  = sizeof(pdu_header);
+               txsize = sizeof(pdu_header);
 
-               ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, 1, txsize);
+               ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, &iov, 1, txsize);
                if (ret != txsize) {
                        pr_err("sendmsg failed!, ret=%d for %zd\n", ret,
                               txsize);
index 12e8918..abc0f36 100644 (file)
@@ -5,11 +5,9 @@
 config USB_WUSB
        tristate "Enable Wireless USB extensions"
        depends on UWB
-        select CRYPTO
-        select CRYPTO_BLKCIPHER
-        select CRYPTO_CBC
-        select CRYPTO_MANAGER
-        select CRYPTO_AES
+       select CRYPTO
+       select CRYPTO_AES
+       select CRYPTO_CCM
        help
          Enable the host-side support for Wireless USB.
 
index edb7263..9ee6648 100644 (file)
@@ -31,6 +31,9 @@
  *             funneled through AES are...16 bytes in size!
  */
 
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <crypto/hash.h>
 #include <crypto/skcipher.h>
 #include <linux/crypto.h>
 #include <linux/module.h>
@@ -109,16 +112,6 @@ struct aes_ccm_a {
        __be16 counter; /* Value of x */
 } __attribute__((packed));
 
-static void bytewise_xor(void *_bo, const void *_bi1, const void *_bi2,
-                        size_t size)
-{
-       u8 *bo = _bo;
-       const u8 *bi1 = _bi1, *bi2 = _bi2;
-       size_t itr;
-       for (itr = 0; itr < size; itr++)
-               bo[itr] = bi1[itr] ^ bi2[itr];
-}
-
 /* Scratch space for MAC calculations. */
 struct wusb_mac_scratch {
        struct aes_ccm_b0 b0;
@@ -150,8 +143,7 @@ struct wusb_mac_scratch {
  * @a: ASCII string, 14 bytes long (I guess zero padded if needed;
  *     we use exactly 14 bytes).
  *
- * @b: data stream to be processed; cannot be a global or const local
- *     (will confuse the scatterlists)
+ * @b: data stream to be processed
  *
  * @blen: size of b...
  *
@@ -160,16 +152,10 @@ struct wusb_mac_scratch {
  * @key. We bytewise xor B0 with B1 (1) and AES-crypt that. Then we
  * take the payload and divide it in blocks (16 bytes), xor them with
  * the previous crypto result (16 bytes) and crypt it, repeat the next
- * block with the output of the previous one, rinse wash (I guess this
- * is what AES CBC mode means...but I truly have no idea). So we use
- * the CBC(AES) blkcipher, that does precisely that. The IV (Initial
+ * block with the output of the previous one, rinse wash. So we use
+ * the CBC-MAC(AES) shash, that does precisely that. The IV (Initial
  * Vector) is 16 bytes and is set to zero, so
  *
- * See rfc3610. Linux crypto has a CBC implementation, but the
- * documentation is scarce, to say the least, and the example code is
- * so intricated that is difficult to understand how things work. Most
- * of this is guess work -- bite me.
- *
  * (1) Created as 6.5 says, again, using as l(a) 'Blen + 14', and
  *     using the 14 bytes of @a to fill up
  *     b1.{mac_header,e0,security_reserved,padding}.
@@ -189,44 +175,24 @@ struct wusb_mac_scratch {
  * NOTE: blen is not aligned to a block size, we'll pad zeros, that's
  *       what sg[4] is for. Maybe there is a smarter way to do this.
  */
-static int wusb_ccm_mac(struct crypto_sync_skcipher *tfm_cbc,
-                       struct crypto_cipher *tfm_aes,
+static int wusb_ccm_mac(struct crypto_shash *tfm_cbcmac,
                        struct wusb_mac_scratch *scratch,
                        void *mic,
                        const struct aes_ccm_nonce *n,
                        const struct aes_ccm_label *a, const void *b,
                        size_t blen)
 {
-       int result = 0;
-       SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm_cbc);
-       struct scatterlist sg[4], sg_dst;
-       void *dst_buf;
-       size_t dst_size;
-       u8 *iv;
-       size_t zero_padding;
+       SHASH_DESC_ON_STACK(desc, tfm_cbcmac);
+       u8 iv[AES_BLOCK_SIZE];
 
        /*
         * These checks should be compile time optimized out
         * ensure @a fills b1's mac_header and following fields
         */
-       WARN_ON(sizeof(*a) != sizeof(scratch->b1) - sizeof(scratch->b1.la));
-       WARN_ON(sizeof(scratch->b0) != sizeof(struct aes_ccm_block));
-       WARN_ON(sizeof(scratch->b1) != sizeof(struct aes_ccm_block));
-       WARN_ON(sizeof(scratch->ax) != sizeof(struct aes_ccm_block));
-
-       result = -ENOMEM;
-       zero_padding = blen % sizeof(struct aes_ccm_block);
-       if (zero_padding)
-               zero_padding = sizeof(struct aes_ccm_block) - zero_padding;
-       dst_size = blen + sizeof(scratch->b0) + sizeof(scratch->b1) +
-               zero_padding;
-       dst_buf = kzalloc(dst_size, GFP_KERNEL);
-       if (!dst_buf)
-               goto error_dst_buf;
-
-       iv = kzalloc(crypto_sync_skcipher_ivsize(tfm_cbc), GFP_KERNEL);
-       if (!iv)
-               goto error_iv;
+       BUILD_BUG_ON(sizeof(*a) != sizeof(scratch->b1) - sizeof(scratch->b1.la));
+       BUILD_BUG_ON(sizeof(scratch->b0) != sizeof(struct aes_ccm_block));
+       BUILD_BUG_ON(sizeof(scratch->b1) != sizeof(struct aes_ccm_block));
+       BUILD_BUG_ON(sizeof(scratch->ax) != sizeof(struct aes_ccm_block));
 
        /* Setup B0 */
        scratch->b0.flags = 0x59;       /* Format B0 */
@@ -243,46 +209,28 @@ static int wusb_ccm_mac(struct crypto_sync_skcipher *tfm_cbc,
        scratch->b1.la = cpu_to_be16(blen + 14);
        memcpy(&scratch->b1.mac_header, a, sizeof(*a));
 
-       sg_init_table(sg, ARRAY_SIZE(sg));
-       sg_set_buf(&sg[0], &scratch->b0, sizeof(scratch->b0));
-       sg_set_buf(&sg[1], &scratch->b1, sizeof(scratch->b1));
-       sg_set_buf(&sg[2], b, blen);
-       /* 0 if well behaved :) */
-       sg_set_page(&sg[3], ZERO_PAGE(0), zero_padding, 0);
-       sg_init_one(&sg_dst, dst_buf, dst_size);
-
-       skcipher_request_set_sync_tfm(req, tfm_cbc);
-       skcipher_request_set_callback(req, 0, NULL, NULL);
-       skcipher_request_set_crypt(req, sg, &sg_dst, dst_size, iv);
-       result = crypto_skcipher_encrypt(req);
-       skcipher_request_zero(req);
-       if (result < 0) {
-               printk(KERN_ERR "E: can't compute CBC-MAC tag (MIC): %d\n",
-                      result);
-               goto error_cbc_crypt;
-       }
+       desc->tfm = tfm_cbcmac;
+       crypto_shash_init(desc);
+       crypto_shash_update(desc, (u8 *)&scratch->b0, sizeof(scratch->b0) +
+                                                     sizeof(scratch->b1));
+       crypto_shash_finup(desc, b, blen, iv);
 
        /* Now we crypt the MIC Tag (*iv) with Ax -- values per WUSB1.0[6.5]
         * The procedure is to AES crypt the A0 block and XOR the MIC
         * Tag against it; we only do the first 8 bytes and place it
         * directly in the destination buffer.
-        *
-        * POS Crypto API: size is assumed to be AES's block size.
-        * Thanks for documenting it -- tip taken from airo.c
         */
        scratch->ax.flags = 0x01;               /* as per WUSB 1.0 spec */
        scratch->ax.ccm_nonce = *n;
        scratch->ax.counter = 0;
-       crypto_cipher_encrypt_one(tfm_aes, (void *)&scratch->ax,
-                                 (void *)&scratch->ax);
-       bytewise_xor(mic, &scratch->ax, iv, 8);
-       result = 8;
-error_cbc_crypt:
-       kfree(iv);
-error_iv:
-       kfree(dst_buf);
-error_dst_buf:
-       return result;
+
+       /* reuse the CBC-MAC transform to perform the single block encryption */
+       crypto_shash_digest(desc, (u8 *)&scratch->ax, sizeof(scratch->ax),
+                           (u8 *)&scratch->ax);
+
+       crypto_xor_cpy(mic, (u8 *)&scratch->ax, iv, 8);
+
+       return 8;
 }
 
 /*
@@ -298,45 +246,28 @@ ssize_t wusb_prf(void *out, size_t out_size,
 {
        ssize_t result, bytes = 0, bitr;
        struct aes_ccm_nonce n = *_n;
-       struct crypto_sync_skcipher *tfm_cbc;
-       struct crypto_cipher *tfm_aes;
-       struct wusb_mac_scratch *scratch;
+       struct crypto_shash *tfm_cbcmac;
+       struct wusb_mac_scratch scratch;
        u64 sfn = 0;
        __le64 sfn_le;
 
-       tfm_cbc = crypto_alloc_sync_skcipher("cbc(aes)", 0, 0);
-       if (IS_ERR(tfm_cbc)) {
-               result = PTR_ERR(tfm_cbc);
-               printk(KERN_ERR "E: can't load CBC(AES): %d\n", (int)result);
-               goto error_alloc_cbc;
-       }
-       result = crypto_sync_skcipher_setkey(tfm_cbc, key, 16);
-       if (result < 0) {
-               printk(KERN_ERR "E: can't set CBC key: %d\n", (int)result);
-               goto error_setkey_cbc;
+       tfm_cbcmac = crypto_alloc_shash("cbcmac(aes)", 0, 0);
+       if (IS_ERR(tfm_cbcmac)) {
+               result = PTR_ERR(tfm_cbcmac);
+               printk(KERN_ERR "E: can't load CBCMAC-AES: %d\n", (int)result);
+               goto error_alloc_cbcmac;
        }
 
-       tfm_aes = crypto_alloc_cipher("aes", 0, 0);
-       if (IS_ERR(tfm_aes)) {
-               result = PTR_ERR(tfm_aes);
-               printk(KERN_ERR "E: can't load AES: %d\n", (int)result);
-               goto error_alloc_aes;
-       }
-       result = crypto_cipher_setkey(tfm_aes, key, 16);
+       result = crypto_shash_setkey(tfm_cbcmac, key, AES_BLOCK_SIZE);
        if (result < 0) {
-               printk(KERN_ERR "E: can't set AES key: %d\n", (int)result);
-               goto error_setkey_aes;
-       }
-       scratch = kmalloc(sizeof(*scratch), GFP_KERNEL);
-       if (!scratch) {
-               result = -ENOMEM;
-               goto error_alloc_scratch;
+               printk(KERN_ERR "E: can't set CBCMAC-AES key: %d\n", (int)result);
+               goto error_setkey_cbcmac;
        }
 
        for (bitr = 0; bitr < (len + 63) / 64; bitr++) {
                sfn_le = cpu_to_le64(sfn++);
                memcpy(&n.sfn, &sfn_le, sizeof(n.sfn)); /* n.sfn++... */
-               result = wusb_ccm_mac(tfm_cbc, tfm_aes, scratch, out + bytes,
+               result = wusb_ccm_mac(tfm_cbcmac, &scratch, out + bytes,
                                      &n, a, b, blen);
                if (result < 0)
                        goto error_ccm_mac;
@@ -344,15 +275,10 @@ ssize_t wusb_prf(void *out, size_t out_size,
        }
        result = bytes;
 
-       kfree(scratch);
-error_alloc_scratch:
 error_ccm_mac:
-error_setkey_aes:
-       crypto_free_cipher(tfm_aes);
-error_alloc_aes:
-error_setkey_cbc:
-       crypto_free_sync_skcipher(tfm_cbc);
-error_alloc_cbc:
+error_setkey_cbcmac:
+       crypto_free_shash(tfm_cbcmac);
+error_alloc_cbcmac:
        return result;
 }
 
@@ -377,12 +303,8 @@ static int wusb_oob_mic_verify(void)
 {
        int result;
        u8 mic[8];
-       /* WUSB1.0[A.2] test vectors
-        *
-        * Need to keep it in the local stack as GCC 4.1.3something
-        * messes up and generates noise.
-        */
-       struct usb_handshake stv_hsmic_hs = {
+       /* WUSB1.0[A.2] test vectors */
+       static const struct usb_handshake stv_hsmic_hs = {
                .bMessageNumber = 2,
                .bStatus        = 00,
                .tTKID          = { 0x76, 0x98, 0x01 },
@@ -457,11 +379,8 @@ static int wusb_key_derive_verify(void)
 {
        int result = 0;
        struct wusb_keydvt_out keydvt_out;
-       /* These come from WUSB1.0[A.1] + 2006/12 errata
-        * NOTE: can't make this const or global -- somehow it seems
-        *       the scatterlists for crypto get confused and we get
-        *       bad data. There is no doc on this... */
-       struct wusb_keydvt_in stv_keydvt_in_a1 = {
+       /* These come from WUSB1.0[A.1] + 2006/12 errata */
+       static const struct wusb_keydvt_in stv_keydvt_in_a1 = {
                .hnonce = {
                        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
                        0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
index 0adf068..99941ae 100644 (file)
@@ -340,14 +340,12 @@ int au1100fb_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi)
  */
 int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
 {
-       struct au1100fb_device *fbdev;
-
-       fbdev = to_au1100fb_device(fbi);
+       struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
 
-       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
        pgprot_val(vma->vm_page_prot) |= (6 << 9); //CCA=6
 
-       return vm_iomap_memory(vma, fbdev->fb_phys, fbdev->fb_len);
+       return dma_mmap_coherent(fbdev->dev, vma, fbdev->fb_mem, fbdev->fb_phys,
+                       fbdev->fb_len);
 }
 
 static struct fb_ops au1100fb_ops =
@@ -412,7 +410,6 @@ static int au1100fb_drv_probe(struct platform_device *dev)
 {
        struct au1100fb_device *fbdev;
        struct resource *regs_res;
-       unsigned long page;
        struct clk *c;
 
        /* Allocate new device private */
@@ -424,6 +421,7 @@ static int au1100fb_drv_probe(struct platform_device *dev)
                goto failed;
 
        platform_set_drvdata(dev, (void *)fbdev);
+       fbdev->dev = &dev->dev;
 
        /* Allocate region for our registers and map them */
        regs_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
@@ -472,20 +470,6 @@ static int au1100fb_drv_probe(struct platform_device *dev)
        au1100fb_fix.smem_start = fbdev->fb_phys;
        au1100fb_fix.smem_len = fbdev->fb_len;
 
-       /*
-        * Set page reserved so that mmap will work. This is necessary
-        * since we'll be remapping normal memory.
-        */
-       for (page = (unsigned long)fbdev->fb_mem;
-            page < PAGE_ALIGN((unsigned long)fbdev->fb_mem + fbdev->fb_len);
-            page += PAGE_SIZE) {
-#ifdef CONFIG_DMA_NONCOHERENT
-               SetPageReserved(virt_to_page(CAC_ADDR((void *)page)));
-#else
-               SetPageReserved(virt_to_page(page));
-#endif
-       }
-
        print_dbg("Framebuffer memory map at %p", fbdev->fb_mem);
        print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024);
 
index 9af1993..e7239bc 100644 (file)
@@ -110,6 +110,7 @@ struct au1100fb_device {
        dma_addr_t              fb_phys;
        int                     panel_idx;
        struct clk              *lcdclk;
+       struct device           *dev;
 };
 
 /********************************************************************/
index 0b2434c..152fd29 100644 (file)
@@ -171,10 +171,10 @@ struct visor_busdev {
        u32 dev_no;
 };
 
-static int match_visorbus_dev_by_id(struct device *dev, void *data)
+static int match_visorbus_dev_by_id(struct device *dev, const void *data)
 {
        struct visor_device *vdev = to_visor_device(dev);
-       struct visor_busdev *id = data;
+       const struct visor_busdev *id = data;
 
        if (vdev->chipset_bus_no == id->bus_no &&
            vdev->chipset_dev_no == id->dev_no)
index 5ae74d5..f1fb18a 100644 (file)
 #define W1_F3A_FUNC_PIO_ACCESS_READ        0xF5
 #define W1_F3A_FUNC_PIO_ACCESS_WRITE       0x5A
 #define W1_F3A_SUCCESS_CONFIRM_BYTE        0xAA
+#define W1_F3A_INVALID_PIO_STATE           0xFF
 
 static ssize_t state_read(struct file *filp, struct kobject *kobj,
                          struct bin_attribute *bin_attr, char *buf, loff_t off,
                          size_t count)
 {
        struct w1_slave *sl = kobj_to_w1_slave(kobj);
+       unsigned int retries = W1_F3A_RETRIES;
+       ssize_t bytes_read = -EIO;
+       u8 state;
+
        dev_dbg(&sl->dev,
                "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
                bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
@@ -40,22 +45,37 @@ static ssize_t state_read(struct file *filp, struct kobject *kobj,
        mutex_lock(&sl->master->bus_mutex);
        dev_dbg(&sl->dev, "mutex locked");
 
-       if (w1_reset_select_slave(sl)) {
-               mutex_unlock(&sl->master->bus_mutex);
-               return -EIO;
-       }
+next:
+       if (w1_reset_select_slave(sl))
+               goto out;
+
+       while (retries--) {
+               w1_write_8(sl->master, W1_F3A_FUNC_PIO_ACCESS_READ);
+
+               state = w1_read_8(sl->master);
+               if ((state & 0x0F) == ((~state >> 4) & 0x0F)) {
+                       /* complement is correct */
+                       *buf = state;
+                       bytes_read = 1;
+                       goto out;
+               } else if (state == W1_F3A_INVALID_PIO_STATE) {
+                       /* slave didn't respond, try to select it again */
+                       dev_warn(&sl->dev, "slave device did not respond to PIO_ACCESS_READ, " \
+                                           "reselecting, retries left: %d\n", retries);
+                       goto next;
+               }
 
-       w1_write_8(sl->master, W1_F3A_FUNC_PIO_ACCESS_READ);
-       *buf = w1_read_8(sl->master);
+               if (w1_reset_resume_command(sl->master))
+                       goto out; /* unrecoverable error */
 
-       mutex_unlock(&sl->master->bus_mutex);
-       dev_dbg(&sl->dev, "mutex unlocked");
+               dev_warn(&sl->dev, "PIO_ACCESS_READ error, retries left: %d\n", retries);
+       }
 
-       /* check for correct complement */
-       if ((*buf & 0x0F) != ((~*buf >> 4) & 0x0F))
-               return -EIO;
-       else
-               return 1;
+out:
+       mutex_unlock(&sl->master->bus_mutex);
+       dev_dbg(&sl->dev, "%s, mutex unlocked, retries: %d\n",
+               (bytes_read > 0) ? "succeeded" : "error", retries);
+       return bytes_read;
 }
 
 static BIN_ATTR_RO(state, 1);
@@ -67,6 +87,7 @@ static ssize_t output_write(struct file *filp, struct kobject *kobj,
        struct w1_slave *sl = kobj_to_w1_slave(kobj);
        u8 w1_buf[3];
        unsigned int retries = W1_F3A_RETRIES;
+       ssize_t bytes_written = -EIO;
 
        if (count != 1 || off != 0)
                return -EFAULT;
@@ -76,7 +97,7 @@ static ssize_t output_write(struct file *filp, struct kobject *kobj,
        dev_dbg(&sl->dev, "mutex locked");
 
        if (w1_reset_select_slave(sl))
-               goto error;
+               goto out;
 
        /* according to the DS2413 datasheet the most significant 6 bits
           should be set to "1"s, so do it now */
@@ -89,18 +110,20 @@ static ssize_t output_write(struct file *filp, struct kobject *kobj,
                w1_write_block(sl->master, w1_buf, 3);
 
                if (w1_read_8(sl->master) == W1_F3A_SUCCESS_CONFIRM_BYTE) {
-                       mutex_unlock(&sl->master->bus_mutex);
-                       dev_dbg(&sl->dev, "mutex unlocked, retries:%d", retries);
-                       return 1;
+                       bytes_written = 1;
+                       goto out;
                }
                if (w1_reset_resume_command(sl->master))
-                       goto error;
+                       goto out; /* unrecoverable error */
+
+               dev_warn(&sl->dev, "PIO_ACCESS_WRITE error, retries left: %d\n", retries);
        }
 
-error:
+out:
        mutex_unlock(&sl->master->bus_mutex);
-       dev_dbg(&sl->dev, "mutex unlocked in error, retries:%d", retries);
-       return -EIO;
+       dev_dbg(&sl->dev, "%s, mutex unlocked, retries: %d\n",
+               (bytes_written > 0) ? "succeeded" : "error", retries);
+       return bytes_written;
 }
 
 static BIN_ATTR(output, S_IRUGO | S_IWUSR | S_IWGRP, NULL, output_write, 1);
index ee1ec98..ccb753a 100644 (file)
@@ -286,7 +286,7 @@ static struct w1_family_ops w1_f0d_fops = {
        .remove_slave   = w1_f0d_remove_slave,
 };
 
-static struct w1_family w1_family_2d = {
+static struct w1_family w1_family_0d = {
        .fid = W1_EEPROM_DS2805,
        .fops = &w1_f0d_fops,
 };
@@ -294,13 +294,13 @@ static struct w1_family w1_family_2d = {
 static int __init w1_f0d_init(void)
 {
        pr_info("%s()\n", __func__);
-       return w1_register_family(&w1_family_2d);
+       return w1_register_family(&w1_family_0d);
 }
 
 static void __exit w1_f0d_fini(void)
 {
        pr_info("%s()\n", __func__);
-       w1_unregister_family(&w1_family_2d);
+       w1_unregister_family(&w1_family_0d);
 }
 
 module_init(w1_f0d_init);
index e2ad448..9212910 100644 (file)
@@ -143,24 +143,18 @@ static void bcm_kona_wdt_debug_init(struct platform_device *pdev)
        wdt->debugfs = NULL;
 
        dir = debugfs_create_dir(BCM_KONA_WDT_NAME, NULL);
-       if (IS_ERR_OR_NULL(dir))
-               return;
 
-       if (debugfs_create_file("info", S_IFREG | S_IRUGO, dir, wdt,
-                               &bcm_kona_fops))
-               wdt->debugfs = dir;
-       else
-               debugfs_remove_recursive(dir);
+       debugfs_create_file("info", S_IFREG | S_IRUGO, dir, wdt,
+                           &bcm_kona_fops);
+       wdt->debugfs = dir;
 }
 
 static void bcm_kona_wdt_debug_exit(struct platform_device *pdev)
 {
        struct bcm_kona_wdt *wdt = platform_get_drvdata(pdev);
 
-       if (wdt && wdt->debugfs) {
+       if (wdt)
                debugfs_remove_recursive(wdt->debugfs);
-               wdt->debugfs = NULL;
-       }
 }
 
 #else
index 8023cf2..96a7709 100644 (file)
@@ -539,38 +539,23 @@ static void dbgfs_unregister(struct mei_wdt *wdt)
        wdt->dbgfs_dir = NULL;
 }
 
-static int dbgfs_register(struct mei_wdt *wdt)
+static void dbgfs_register(struct mei_wdt *wdt)
 {
-       struct dentry *dir, *f;
+       struct dentry *dir;
 
        dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
-       if (!dir)
-               return -ENOMEM;
-
        wdt->dbgfs_dir = dir;
-       f = debugfs_create_file("state", S_IRUSR, dir, wdt, &dbgfs_fops_state);
-       if (!f)
-               goto err;
 
-       f = debugfs_create_file("activation",  S_IRUSR,
-                               dir, wdt, &dbgfs_fops_activation);
-       if (!f)
-               goto err;
+       debugfs_create_file("state", S_IRUSR, dir, wdt, &dbgfs_fops_state);
 
-       return 0;
-err:
-       dbgfs_unregister(wdt);
-       return -ENODEV;
+       debugfs_create_file("activation", S_IRUSR, dir, wdt,
+                           &dbgfs_fops_activation);
 }
 
 #else
 
 static inline void dbgfs_unregister(struct mei_wdt *wdt) {}
-
-static inline int dbgfs_register(struct mei_wdt *wdt)
-{
-       return 0;
-}
+static inline void dbgfs_register(struct mei_wdt *wdt) {}
 #endif /* CONFIG_DEBUG_FS */
 
 static int mei_wdt_probe(struct mei_cl_device *cldev,
@@ -623,8 +608,7 @@ static int mei_wdt_probe(struct mei_cl_device *cldev,
        if (ret)
                goto err_disable;
 
-       if (dbgfs_register(wdt))
-               dev_warn(&cldev->dev, "cannot register debugfs\n");
+       dbgfs_register(wdt);
 
        return 0;
 
index 469dfbd..4c339c7 100644 (file)
@@ -264,8 +264,7 @@ void gntdev_put_map(struct gntdev_priv *priv, struct gntdev_grant_map *map)
 
 /* ------------------------------------------------------------------ */
 
-static int find_grant_ptes(pte_t *pte, pgtable_t token,
-               unsigned long addr, void *data)
+static int find_grant_ptes(pte_t *pte, unsigned long addr, void *data)
 {
        struct gntdev_grant_map *map = data;
        unsigned int pgnr = (addr - map->vma->vm_start) >> PAGE_SHIFT;
@@ -292,8 +291,7 @@ static int find_grant_ptes(pte_t *pte, pgtable_t token,
 }
 
 #ifdef CONFIG_X86
-static int set_grant_ptes_as_special(pte_t *pte, pgtable_t token,
-                                    unsigned long addr, void *data)
+static int set_grant_ptes_as_special(pte_t *pte, unsigned long addr, void *data)
 {
        set_pte_at(current->mm, addr, pte, pte_mkspecial(*pte));
        return 0;
index 1ff38d8..2f5ce72 100644 (file)
@@ -731,8 +731,7 @@ struct remap_pfn {
        unsigned long i;
 };
 
-static int remap_pfn_fn(pte_t *ptep, pgtable_t token, unsigned long addr,
-                       void *data)
+static int remap_pfn_fn(pte_t *ptep, unsigned long addr, void *data)
 {
        struct remap_pfn *r = data;
        struct page *page = r->pages[r->i];
@@ -966,8 +965,7 @@ static int privcmd_mmap(struct file *file, struct vm_area_struct *vma)
  * on a per pfn/pte basis. Mapping calls that fail with ENOENT
  * can be then retried until success.
  */
-static int is_mapped_fn(pte_t *pte, struct page *pmd_page,
-                       unsigned long addr, void *data)
+static int is_mapped_fn(pte_t *pte, unsigned long addr, void *data)
 {
        return pte_none(*pte) ? 0 : -EBUSY;
 }
index e7df65d..ba883a8 100644 (file)
@@ -93,8 +93,7 @@ static void setup_hparams(unsigned long gfn, void *data)
        info->fgfn++;
 }
 
-static int remap_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr,
-                       void *data)
+static int remap_pte_fn(pte_t *ptep, unsigned long addr, void *data)
 {
        struct remap_data *info = data;
        struct page *page = info->pages[info->index++];
index bc57ae9..cce9ace 100644 (file)
@@ -35,8 +35,9 @@
  * @page: structure to page
  *
  */
-static int v9fs_fid_readpage(struct p9_fid *fid, struct page *page)
+static int v9fs_fid_readpage(void *data, struct page *page)
 {
+       struct p9_fid *fid = data;
        struct inode *inode = page->mapping->host;
        struct bio_vec bvec = {.bv_page = page, .bv_len = PAGE_SIZE};
        struct iov_iter to;
@@ -107,7 +108,8 @@ static int v9fs_vfs_readpages(struct file *filp, struct address_space *mapping,
        if (ret == 0)
                return ret;
 
-       ret = read_cache_pages(mapping, pages, (void *)v9fs_vfs_readpage, filp);
+       ret = read_cache_pages(mapping, pages, v9fs_fid_readpage,
+                       filp->private_data);
        p9_debug(P9_DEBUG_VFS, "  = %d\n", ret);
        return ret;
 }
index c1e581d..2d40573 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1479,8 +1479,9 @@ static int aio_prep_rw(struct kiocb *req, const struct iocb *iocb)
        return 0;
 }
 
-static int aio_setup_rw(int rw, const struct iocb *iocb, struct iovec **iovec,
-               bool vectored, bool compat, struct iov_iter *iter)
+static ssize_t aio_setup_rw(int rw, const struct iocb *iocb,
+               struct iovec **iovec, bool vectored, bool compat,
+               struct iov_iter *iter)
 {
        void __user *buf = (void __user *)(uintptr_t)iocb->aio_buf;
        size_t len = iocb->aio_nbytes;
@@ -1537,7 +1538,7 @@ static int aio_read(struct kiocb *req, const struct iocb *iocb,
                return -EINVAL;
 
        ret = aio_setup_rw(READ, iocb, &iovec, vectored, compat, &iter);
-       if (ret)
+       if (ret < 0)
                return ret;
        ret = rw_verify_area(READ, file, &req->ki_pos, iov_iter_count(&iter));
        if (!ret)
@@ -1565,7 +1566,7 @@ static int aio_write(struct kiocb *req, const struct iocb *iocb,
                return -EINVAL;
 
        ret = aio_setup_rw(WRITE, iocb, &iovec, vectored, compat, &iter);
-       if (ret)
+       if (ret < 0)
                return ret;
        ret = rw_verify_area(WRITE, file, &req->ki_pos, iov_iter_count(&iter));
        if (!ret) {
index 56ae2f6..cfeff1b 100644 (file)
@@ -187,7 +187,7 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
        struct btrfs_inode *binode = BTRFS_I(inode);
        struct btrfs_root *root = binode->root;
        struct btrfs_trans_handle *trans;
-       unsigned int fsflags;
+       unsigned int fsflags, old_fsflags;
        int ret;
        const char *comp = NULL;
        u32 binode_flags = binode->flags;
@@ -212,13 +212,10 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
        inode_lock(inode);
 
        fsflags = btrfs_mask_fsflags_for_type(inode, fsflags);
-       if ((fsflags ^ btrfs_inode_flags_to_fsflags(binode->flags)) &
-           (FS_APPEND_FL | FS_IMMUTABLE_FL)) {
-               if (!capable(CAP_LINUX_IMMUTABLE)) {
-                       ret = -EPERM;
-                       goto out_unlock;
-               }
-       }
+       old_fsflags = btrfs_inode_flags_to_fsflags(binode->flags);
+       ret = vfs_ioc_setflags_prepare(inode, old_fsflags, fsflags);
+       if (ret)
+               goto out_unlock;
 
        if (fsflags & FS_SYNC_FL)
                binode_flags |= BTRFS_INODE_SYNC;
@@ -376,9 +373,7 @@ static int btrfs_ioctl_fsgetxattr(struct file *file, void __user *arg)
        struct btrfs_inode *binode = BTRFS_I(file_inode(file));
        struct fsxattr fa;
 
-       memset(&fa, 0, sizeof(fa));
-       fa.fsx_xflags = btrfs_inode_flags_to_xflags(binode->flags);
-
+       simple_fill_fsxattr(&fa, btrfs_inode_flags_to_xflags(binode->flags));
        if (copy_to_user(arg, &fa, sizeof(fa)))
                return -EFAULT;
 
@@ -391,7 +386,7 @@ static int btrfs_ioctl_fssetxattr(struct file *file, void __user *arg)
        struct btrfs_inode *binode = BTRFS_I(inode);
        struct btrfs_root *root = binode->root;
        struct btrfs_trans_handle *trans;
-       struct fsxattr fa;
+       struct fsxattr fa, old_fa;
        unsigned old_flags;
        unsigned old_i_flags;
        int ret = 0;
@@ -402,7 +397,6 @@ static int btrfs_ioctl_fssetxattr(struct file *file, void __user *arg)
        if (btrfs_root_readonly(root))
                return -EROFS;
 
-       memset(&fa, 0, sizeof(fa));
        if (copy_from_user(&fa, arg, sizeof(fa)))
                return -EFAULT;
 
@@ -422,13 +416,11 @@ static int btrfs_ioctl_fssetxattr(struct file *file, void __user *arg)
        old_flags = binode->flags;
        old_i_flags = inode->i_flags;
 
-       /* We need the capabilities to change append-only or immutable inode */
-       if (((old_flags & (BTRFS_INODE_APPEND | BTRFS_INODE_IMMUTABLE)) ||
-            (fa.fsx_xflags & (FS_XFLAG_APPEND | FS_XFLAG_IMMUTABLE))) &&
-           !capable(CAP_LINUX_IMMUTABLE)) {
-               ret = -EPERM;
+       simple_fill_fsxattr(&old_fa,
+                           btrfs_inode_flags_to_xflags(binode->flags));
+       ret = vfs_ioc_fssetxattr_check(inode, &old_fa, &fa);
+       if (ret)
                goto out_unlock;
-       }
 
        if (fa.fsx_xflags & FS_XFLAG_SYNC)
                binode->flags |= BTRFS_INODE_SYNC;
index 2f078b7..c1dfc97 100644 (file)
@@ -303,11 +303,12 @@ static ssize_t raid_bytes_show(struct kobject *kobj,
        return snprintf(buf, PAGE_SIZE, "%llu\n", val);
 }
 
-static struct attribute *raid_attributes[] = {
+static struct attribute *raid_attrs[] = {
        BTRFS_ATTR_PTR(raid, total_bytes),
        BTRFS_ATTR_PTR(raid, used_bytes),
        NULL
 };
+ATTRIBUTE_GROUPS(raid);
 
 static void release_raid_kobj(struct kobject *kobj)
 {
@@ -317,7 +318,7 @@ static void release_raid_kobj(struct kobject *kobj)
 struct kobj_type btrfs_raid_ktype = {
        .sysfs_ops = &kobj_sysfs_ops,
        .release = release_raid_kobj,
-       .default_attrs = raid_attributes,
+       .default_groups = raid_groups,
 };
 
 #define SPACE_INFO_ATTR(field)                                         \
@@ -364,6 +365,7 @@ static struct attribute *space_info_attrs[] = {
        BTRFS_ATTR_PTR(space_info, total_bytes_pinned),
        NULL,
 };
+ATTRIBUTE_GROUPS(space_info);
 
 static void space_info_release(struct kobject *kobj)
 {
@@ -375,7 +377,7 @@ static void space_info_release(struct kobject *kobj)
 struct kobj_type space_info_ktype = {
        .sysfs_ops = &kobj_sysfs_ops,
        .release = space_info_release,
-       .default_attrs = space_info_attrs,
+       .default_groups = space_info_groups,
 };
 
 static const struct attribute *allocation_attrs[] = {
@@ -910,12 +912,10 @@ void btrfs_sysfs_feature_update(struct btrfs_fs_info *fs_info,
        ret = sysfs_create_group(fsid_kobj, &btrfs_feature_attr_group);
 }
 
-static int btrfs_init_debugfs(void)
+static void btrfs_init_debugfs(void)
 {
 #ifdef CONFIG_DEBUG_FS
        btrfs_debugfs_root_dentry = debugfs_create_dir("btrfs", NULL);
-       if (!btrfs_debugfs_root_dentry)
-               return -ENOMEM;
 
        /*
         * Example code, how to export data through debugfs.
@@ -929,7 +929,6 @@ static int btrfs_init_debugfs(void)
 #endif
 
 #endif
-       return 0;
 }
 
 int __init btrfs_init_sysfs(void)
@@ -940,9 +939,7 @@ int __init btrfs_init_sysfs(void)
        if (!btrfs_kset)
                return -ENOMEM;
 
-       ret = btrfs_init_debugfs();
-       if (ret)
-               goto out1;
+       btrfs_init_debugfs();
 
        init_feature_attrs();
        ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
@@ -959,7 +956,6 @@ out_remove_group:
        sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
 out2:
        debugfs_remove_recursive(btrfs_debugfs_root_dentry);
-out1:
        kset_unregister(btrfs_kset);
 
        return ret;
index b3fc5fe..83cd41f 100644 (file)
@@ -245,21 +245,17 @@ void ceph_fs_debugfs_cleanup(struct ceph_fs_client *fsc)
        debugfs_remove(fsc->debugfs_mdsc);
 }
 
-int ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
+void ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
 {
        char name[100];
-       int err = -ENOMEM;
 
        dout("ceph_fs_debugfs_init\n");
-       BUG_ON(!fsc->client->debugfs_dir);
        fsc->debugfs_congestion_kb =
                debugfs_create_file("writeback_congestion_kb",
                                    0600,
                                    fsc->client->debugfs_dir,
                                    fsc,
                                    &congestion_kb_fops);
-       if (!fsc->debugfs_congestion_kb)
-               goto out;
 
        snprintf(name, sizeof(name), "../../bdi/%s",
                 dev_name(fsc->sb->s_bdi->dev));
@@ -267,52 +263,36 @@ int ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
                debugfs_create_symlink("bdi",
                                       fsc->client->debugfs_dir,
                                       name);
-       if (!fsc->debugfs_bdi)
-               goto out;
 
        fsc->debugfs_mdsmap = debugfs_create_file("mdsmap",
                                        0400,
                                        fsc->client->debugfs_dir,
                                        fsc,
                                        &mdsmap_show_fops);
-       if (!fsc->debugfs_mdsmap)
-               goto out;
 
        fsc->debugfs_mds_sessions = debugfs_create_file("mds_sessions",
                                        0400,
                                        fsc->client->debugfs_dir,
                                        fsc,
                                        &mds_sessions_show_fops);
-       if (!fsc->debugfs_mds_sessions)
-               goto out;
 
        fsc->debugfs_mdsc = debugfs_create_file("mdsc",
                                                0400,
                                                fsc->client->debugfs_dir,
                                                fsc,
                                                &mdsc_show_fops);
-       if (!fsc->debugfs_mdsc)
-               goto out;
 
        fsc->debugfs_caps = debugfs_create_file("caps",
                                                   0400,
                                                   fsc->client->debugfs_dir,
                                                   fsc,
                                                   &caps_show_fops);
-       if (!fsc->debugfs_caps)
-               goto out;
-
-       return 0;
-
-out:
-       ceph_fs_debugfs_cleanup(fsc);
-       return err;
 }
 
 
 #else  /* CONFIG_DEBUG_FS */
 
-int ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
+void ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
 {
        return 0;
 }
index d57fa60..ed1b65a 100644 (file)
@@ -937,9 +937,7 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
                        dout("mount opening path %s\n", path);
                }
 
-               err = ceph_fs_debugfs_init(fsc);
-               if (err < 0)
-                       goto out;
+               ceph_fs_debugfs_init(fsc);
 
                root = open_root_dentry(fsc, path, started);
                if (IS_ERR(root)) {
index 5f27e1f..fbe6869 100644 (file)
@@ -1102,7 +1102,7 @@ extern int ceph_locks_to_pagelist(struct ceph_filelock *flocks,
                                  int num_fcntl_locks, int num_flock_locks);
 
 /* debugfs.c */
-extern int ceph_fs_debugfs_init(struct ceph_fs_client *client);
+extern void ceph_fs_debugfs_init(struct ceph_fs_client *client);
 extern void ceph_fs_debugfs_cleanup(struct ceph_fs_client *client);
 
 /* quota.c */
index d18cad2..00dfe17 100644 (file)
@@ -98,7 +98,7 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
                           int minorct, const char *name)
 {
        struct char_device_struct *cd, *curr, *prev = NULL;
-       int ret = -EBUSY;
+       int ret;
        int i;
 
        if (major >= CHRDEV_MAJOR_MAX) {
@@ -129,6 +129,7 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
                major = ret;
        }
 
+       ret = -EBUSY;
        i = major_to_index(major);
        for (curr = chrdevs[i]; curr; prev = curr, curr = curr->next) {
                if (curr->major < major)
index ddd708b..93e4ca6 100644 (file)
@@ -997,25 +997,19 @@ static const struct file_operations u32_array_fops = {
  * @array as data. If the @mode variable is so set it can be read from.
  * Writing is not supported. Seek within the file is also not supported.
  * Once array is created its size can not be changed.
- *
- * The function returns a pointer to dentry on success. If an error occurs,
- * %ERR_PTR(-ERROR) or NULL will be returned. If debugfs is not enabled in
- * the kernel, the value %ERR_PTR(-ENODEV) will be returned.
  */
-struct dentry *debugfs_create_u32_array(const char *name, umode_t mode,
-                                           struct dentry *parent,
-                                           u32 *array, u32 elements)
+void debugfs_create_u32_array(const char *name, umode_t mode,
+                             struct dentry *parent, u32 *array, u32 elements)
 {
        struct array_data *data = kmalloc(sizeof(*data), GFP_KERNEL);
 
        if (data == NULL)
-               return NULL;
+               return;
 
        data->array = array;
        data->elements = elements;
 
-       return debugfs_create_file_unsafe(name, mode, parent, data,
-                                       &u32_array_fops);
+       debugfs_create_file_unsafe(name, mode, parent, data, &u32_array_fops);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u32_array);
 
index 1e444fe..042b688 100644 (file)
@@ -2,13 +2,16 @@
 /*
  *  inode.c - part of debugfs, a tiny little debug file system
  *
- *  Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>
+ *  Copyright (C) 2004,2019 Greg Kroah-Hartman <greg@kroah.com>
  *  Copyright (C) 2004 IBM Inc.
+ *  Copyright (C) 2019 Linux Foundation <gregkh@linuxfoundation.org>
  *
  *  debugfs is for people to use instead of /proc or /sys.
  *  See ./Documentation/core-api/kernel-api.rst for more details.
  */
 
+#define pr_fmt(fmt)    "debugfs: " fmt
+
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/mount.h>
@@ -285,15 +288,17 @@ static struct dentry *start_creating(const char *name, struct dentry *parent)
        struct dentry *dentry;
        int error;
 
-       pr_debug("debugfs: creating file '%s'\n",name);
+       pr_debug("creating file '%s'\n", name);
 
        if (IS_ERR(parent))
                return parent;
 
        error = simple_pin_fs(&debug_fs_type, &debugfs_mount,
                              &debugfs_mount_count);
-       if (error)
+       if (error) {
+               pr_err("Unable to pin filesystem for file '%s'\n", name);
                return ERR_PTR(error);
+       }
 
        /* If the parent is not specified, we create it in the root.
         * We need the root dentry to do this, which is in the super
@@ -306,6 +311,12 @@ static struct dentry *start_creating(const char *name, struct dentry *parent)
        inode_lock(d_inode(parent));
        dentry = lookup_one_len(name, parent, strlen(name));
        if (!IS_ERR(dentry) && d_really_is_positive(dentry)) {
+               if (d_is_dir(dentry))
+                       pr_err("Directory '%s' with parent '%s' already present!\n",
+                              name, parent->d_name.name);
+               else
+                       pr_err("File '%s' in directory '%s' already present!\n",
+                              name, parent->d_name.name);
                dput(dentry);
                dentry = ERR_PTR(-EEXIST);
        }
@@ -349,8 +360,11 @@ static struct dentry *__debugfs_create_file(const char *name, umode_t mode,
                return dentry;
 
        inode = debugfs_get_inode(dentry->d_sb);
-       if (unlikely(!inode))
+       if (unlikely(!inode)) {
+               pr_err("out of free dentries, can not create file '%s'\n",
+                      name);
                return failed_creating(dentry);
+       }
 
        inode->i_mode = mode;
        inode->i_private = data;
@@ -511,8 +525,11 @@ struct dentry *debugfs_create_dir(const char *name, struct dentry *parent)
                return dentry;
 
        inode = debugfs_get_inode(dentry->d_sb);
-       if (unlikely(!inode))
+       if (unlikely(!inode)) {
+               pr_err("out of free dentries, can not create directory '%s'\n",
+                      name);
                return failed_creating(dentry);
+       }
 
        inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
        inode->i_op = &simple_dir_inode_operations;
@@ -550,8 +567,11 @@ struct dentry *debugfs_create_automount(const char *name,
                return dentry;
 
        inode = debugfs_get_inode(dentry->d_sb);
-       if (unlikely(!inode))
+       if (unlikely(!inode)) {
+               pr_err("out of free dentries, can not create automount '%s'\n",
+                      name);
                return failed_creating(dentry);
+       }
 
        make_empty_dir_inode(inode);
        inode->i_flags |= S_AUTOMOUNT;
@@ -606,6 +626,8 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
 
        inode = debugfs_get_inode(dentry->d_sb);
        if (unlikely(!inode)) {
+               pr_err("out of free dentries, can not create symlink '%s'\n",
+                      name);
                kfree(link);
                return failed_creating(dentry);
        }
index 0e941d4..d6bbccb 100644 (file)
@@ -737,7 +737,7 @@ void dlm_delete_debug_file(struct dlm_ls *ls)
        debugfs_remove(ls->ls_debug_toss_dentry);
 }
 
-int dlm_create_debug_file(struct dlm_ls *ls)
+void dlm_create_debug_file(struct dlm_ls *ls)
 {
        char name[DLM_LOCKSPACE_LEN + 8];
 
@@ -748,8 +748,6 @@ int dlm_create_debug_file(struct dlm_ls *ls)
                                                      dlm_root,
                                                      ls,
                                                      &format1_fops);
-       if (!ls->ls_debug_rsb_dentry)
-               goto fail;
 
        /* format 2 */
 
@@ -761,8 +759,6 @@ int dlm_create_debug_file(struct dlm_ls *ls)
                                                        dlm_root,
                                                        ls,
                                                        &format2_fops);
-       if (!ls->ls_debug_locks_dentry)
-               goto fail;
 
        /* format 3 */
 
@@ -774,8 +770,6 @@ int dlm_create_debug_file(struct dlm_ls *ls)
                                                      dlm_root,
                                                      ls,
                                                      &format3_fops);
-       if (!ls->ls_debug_all_dentry)
-               goto fail;
 
        /* format 4 */
 
@@ -787,8 +781,6 @@ int dlm_create_debug_file(struct dlm_ls *ls)
                                                       dlm_root,
                                                       ls,
                                                       &format4_fops);
-       if (!ls->ls_debug_toss_dentry)
-               goto fail;
 
        memset(name, 0, sizeof(name));
        snprintf(name, DLM_LOCKSPACE_LEN + 8, "%s_waiters", ls->ls_name);
@@ -798,21 +790,12 @@ int dlm_create_debug_file(struct dlm_ls *ls)
                                                          dlm_root,
                                                          ls,
                                                          &waiters_fops);
-       if (!ls->ls_debug_waiters_dentry)
-               goto fail;
-
-       return 0;
-
- fail:
-       dlm_delete_debug_file(ls);
-       return -ENOMEM;
 }
 
-int __init dlm_register_debugfs(void)
+void __init dlm_register_debugfs(void)
 {
        mutex_init(&debug_buf_lock);
        dlm_root = debugfs_create_dir("dlm", NULL);
-       return dlm_root ? 0 : -ENOMEM;
 }
 
 void dlm_unregister_debugfs(void)
index da1173a..416d9de 100644 (file)
@@ -719,14 +719,14 @@ int dlm_plock_init(void);
 void dlm_plock_exit(void);
 
 #ifdef CONFIG_DLM_DEBUG
-int dlm_register_debugfs(void);
+void dlm_register_debugfs(void);
 void dlm_unregister_debugfs(void);
-int dlm_create_debug_file(struct dlm_ls *ls);
+void dlm_create_debug_file(struct dlm_ls *ls);
 void dlm_delete_debug_file(struct dlm_ls *ls);
 #else
-static inline int dlm_register_debugfs(void) { return 0; }
+static inline void dlm_register_debugfs(void) { }
 static inline void dlm_unregister_debugfs(void) { }
-static inline int dlm_create_debug_file(struct dlm_ls *ls) { return 0; }
+static inline void dlm_create_debug_file(struct dlm_ls *ls) { }
 static inline void dlm_delete_debug_file(struct dlm_ls *ls) { }
 #endif
 
index 4c2c85a..afb8340 100644 (file)
@@ -158,6 +158,7 @@ static struct attribute *dlm_attrs[] = {
        &dlm_attr_recover_nodeid.attr,
        NULL,
 };
+ATTRIBUTE_GROUPS(dlm);
 
 static ssize_t dlm_attr_show(struct kobject *kobj, struct attribute *attr,
                             char *buf)
@@ -187,7 +188,7 @@ static const struct sysfs_ops dlm_attr_ops = {
 };
 
 static struct kobj_type dlm_ktype = {
-       .default_attrs = dlm_attrs,
+       .default_groups = dlm_groups,
        .sysfs_ops     = &dlm_attr_ops,
        .release       = lockspace_kobj_release,
 };
index 114ebfe..3951d39 100644 (file)
@@ -1628,8 +1628,10 @@ static void clean_writequeues(void)
 
 static void work_stop(void)
 {
-       destroy_workqueue(recv_workqueue);
-       destroy_workqueue(send_workqueue);
+       if (recv_workqueue)
+               destroy_workqueue(recv_workqueue);
+       if (send_workqueue)
+               destroy_workqueue(send_workqueue);
 }
 
 static int work_start(void)
@@ -1689,13 +1691,17 @@ static void work_flush(void)
        struct hlist_node *n;
        struct connection *con;
 
-       flush_workqueue(recv_workqueue);
-       flush_workqueue(send_workqueue);
+       if (recv_workqueue)
+               flush_workqueue(recv_workqueue);
+       if (send_workqueue)
+               flush_workqueue(send_workqueue);
        do {
                ok = 1;
                foreach_conn(stop_conn);
-               flush_workqueue(recv_workqueue);
-               flush_workqueue(send_workqueue);
+               if (recv_workqueue)
+                       flush_workqueue(recv_workqueue);
+               if (send_workqueue)
+                       flush_workqueue(send_workqueue);
                for (i = 0; i < CONN_HASH_SIZE && ok; i++) {
                        hlist_for_each_entry_safe(con, n,
                                                  &connection_hash[i], list) {
index 3957992..afc66a1 100644 (file)
@@ -35,9 +35,7 @@ static int __init init_dlm(void)
        if (error)
                goto out_lockspace;
 
-       error = dlm_register_debugfs();
-       if (error)
-               goto out_config;
+       dlm_register_debugfs();
 
        error = dlm_user_init();
        if (error)
@@ -61,7 +59,6 @@ static int __init init_dlm(void)
        dlm_user_exit();
  out_debug:
        dlm_unregister_debugfs();
- out_config:
        dlm_config_exit();
  out_lockspace:
        dlm_lockspace_exit();
index ee3bc0c..e9e27a2 100644 (file)
@@ -107,16 +107,22 @@ out_free:
        return size;
 }
 
-static int
-efivarfs_ioc_getxflags(struct file *file, void __user *arg)
+static inline unsigned int efivarfs_getflags(struct inode *inode)
 {
-       struct inode *inode = file->f_mapping->host;
        unsigned int i_flags;
        unsigned int flags = 0;
 
        i_flags = inode->i_flags;
        if (i_flags & S_IMMUTABLE)
                flags |= FS_IMMUTABLE_FL;
+       return flags;
+}
+
+static int
+efivarfs_ioc_getxflags(struct file *file, void __user *arg)
+{
+       struct inode *inode = file->f_mapping->host;
+       unsigned int flags = efivarfs_getflags(inode);
 
        if (copy_to_user(arg, &flags, sizeof(flags)))
                return -EFAULT;
@@ -129,6 +135,7 @@ efivarfs_ioc_setxflags(struct file *file, void __user *arg)
        struct inode *inode = file->f_mapping->host;
        unsigned int flags;
        unsigned int i_flags = 0;
+       unsigned int oldflags = efivarfs_getflags(inode);
        int error;
 
        if (!inode_owner_or_capable(inode))
@@ -140,9 +147,6 @@ efivarfs_ioc_setxflags(struct file *file, void __user *arg)
        if (flags & ~FS_IMMUTABLE_FL)
                return -EOPNOTSUPP;
 
-       if (!capable(CAP_LINUX_IMMUTABLE))
-               return -EPERM;
-
        if (flags & FS_IMMUTABLE_FL)
                i_flags |= S_IMMUTABLE;
 
@@ -152,12 +156,16 @@ efivarfs_ioc_setxflags(struct file *file, void __user *arg)
                return error;
 
        inode_lock(inode);
+
+       error = vfs_ioc_setflags_prepare(inode, oldflags, flags);
+       if (error)
+               goto out;
+
        inode_set_flags(inode, i_flags, S_IMMUTABLE);
+out:
        inode_unlock(inode);
-
        mnt_drop_write_file(file);
-
-       return 0;
+       return error;
 }
 
 static long
index 0367c00..1b853fb 100644 (file)
@@ -60,18 +60,10 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                }
                oldflags = ei->i_flags;
 
-               /*
-                * The IMMUTABLE and APPEND_ONLY flags can only be changed by
-                * the relevant capability.
-                *
-                * This test looks nicer. Thanks to Pauline Middelink
-                */
-               if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) {
-                       if (!capable(CAP_LINUX_IMMUTABLE)) {
-                               inode_unlock(inode);
-                               ret = -EPERM;
-                               goto setflags_out;
-                       }
+               ret = vfs_ioc_setflags_prepare(inode, oldflags, flags);
+               if (ret) {
+                       inode_unlock(inode);
+                       goto setflags_out;
                }
 
                flags = flags & EXT2_FL_USER_MODIFIABLE;
index 74648d4..442f7ef 100644 (file)
@@ -312,16 +312,9 @@ static int ext4_ioctl_setflags(struct inode *inode,
        /* The JOURNAL_DATA flag is modifiable only by root */
        jflag = flags & EXT4_JOURNAL_DATA_FL;
 
-       /*
-        * The IMMUTABLE and APPEND_ONLY flags can only be changed by
-        * the relevant capability.
-        *
-        * This test looks nicer. Thanks to Pauline Middelink
-        */
-       if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
-               if (!capable(CAP_LINUX_IMMUTABLE))
-                       goto flags_out;
-       }
+       err = vfs_ioc_setflags_prepare(inode, oldflags, flags);
+       if (err)
+               goto flags_out;
 
        /*
         * The JOURNAL_DATA flag can only be changed by
@@ -741,28 +734,15 @@ group_add_out:
        return err;
 }
 
-static int ext4_ioctl_check_project(struct inode *inode, struct fsxattr *fa)
+static void ext4_fill_fsxattr(struct inode *inode, struct fsxattr *fa)
 {
-       /*
-        * Project Quota ID state is only allowed to change from within the init
-        * namespace. Enforce that restriction only if we are trying to change
-        * the quota ID state. Everything else is allowed in user namespaces.
-        */
-       if (current_user_ns() == &init_user_ns)
-               return 0;
-
-       if (__kprojid_val(EXT4_I(inode)->i_projid) != fa->fsx_projid)
-               return -EINVAL;
+       struct ext4_inode_info *ei = EXT4_I(inode);
 
-       if (ext4_test_inode_flag(inode, EXT4_INODE_PROJINHERIT)) {
-               if (!(fa->fsx_xflags & FS_XFLAG_PROJINHERIT))
-                       return -EINVAL;
-       } else {
-               if (fa->fsx_xflags & FS_XFLAG_PROJINHERIT)
-                       return -EINVAL;
-       }
+       simple_fill_fsxattr(fa, ext4_iflags_to_xflags(ei->i_flags &
+                                                     EXT4_FL_USER_VISIBLE));
 
-       return 0;
+       if (ext4_has_feature_project(inode->i_sb))
+               fa->fsx_projid = from_kprojid(&init_user_ns, ei->i_projid);
 }
 
 long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
@@ -1139,13 +1119,7 @@ resizefs_out:
        {
                struct fsxattr fa;
 
-               memset(&fa, 0, sizeof(struct fsxattr));
-               fa.fsx_xflags = ext4_iflags_to_xflags(ei->i_flags & EXT4_FL_USER_VISIBLE);
-
-               if (ext4_has_feature_project(inode->i_sb)) {
-                       fa.fsx_projid = (__u32)from_kprojid(&init_user_ns,
-                               EXT4_I(inode)->i_projid);
-               }
+               ext4_fill_fsxattr(inode, &fa);
 
                if (copy_to_user((struct fsxattr __user *)arg,
                                 &fa, sizeof(fa)))
@@ -1154,7 +1128,7 @@ resizefs_out:
        }
        case EXT4_IOC_FSSETXATTR:
        {
-               struct fsxattr fa;
+               struct fsxattr fa, old_fa;
                int err;
 
                if (copy_from_user(&fa, (struct fsxattr __user *)arg,
@@ -1177,7 +1151,8 @@ resizefs_out:
                        return err;
 
                inode_lock(inode);
-               err = ext4_ioctl_check_project(inode, &fa);
+               ext4_fill_fsxattr(inode, &old_fa);
+               err = vfs_ioc_fssetxattr_check(inode, &old_fa, &fa);
                if (err)
                        goto out;
                flags = (ei->i_flags & ~EXT4_FL_XFLAG_VISIBLE) |
index ed70b68..a0eef95 100644 (file)
@@ -146,8 +146,8 @@ static bool __is_bitmap_valid(struct f2fs_sb_info *sbi, block_t blkaddr,
 
        exist = f2fs_test_bit(offset, se->cur_valid_map);
        if (!exist && type == DATA_GENERIC_ENHANCE) {
-               f2fs_msg(sbi->sb, KERN_ERR, "Inconsistent error "
-                       "blkaddr:%u, sit bitmap:%d", blkaddr, exist);
+               f2fs_err(sbi, "Inconsistent error blkaddr:%u, sit bitmap:%d",
+                        blkaddr, exist);
                set_sbi_flag(sbi, SBI_NEED_FSCK);
                WARN_ON(1);
        }
@@ -184,8 +184,8 @@ bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
        case DATA_GENERIC_ENHANCE_READ:
                if (unlikely(blkaddr >= MAX_BLKADDR(sbi) ||
                                blkaddr < MAIN_BLKADDR(sbi))) {
-                       f2fs_msg(sbi->sb, KERN_WARNING,
-                               "access invalid blkaddr:%u", blkaddr);
+                       f2fs_warn(sbi, "access invalid blkaddr:%u",
+                                 blkaddr);
                        set_sbi_flag(sbi, SBI_NEED_FSCK);
                        WARN_ON(1);
                        return false;
@@ -657,9 +657,8 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
 
 err_out:
        set_sbi_flag(sbi, SBI_NEED_FSCK);
-       f2fs_msg(sbi->sb, KERN_WARNING,
-                       "%s: orphan failed (ino=%x), run fsck to fix.",
-                       __func__, ino);
+       f2fs_warn(sbi, "%s: orphan failed (ino=%x), run fsck to fix.",
+                 __func__, ino);
        return err;
 }
 
@@ -676,13 +675,12 @@ int f2fs_recover_orphan_inodes(struct f2fs_sb_info *sbi)
                return 0;
 
        if (bdev_read_only(sbi->sb->s_bdev)) {
-               f2fs_msg(sbi->sb, KERN_INFO, "write access "
-                       "unavailable, skipping orphan cleanup");
+               f2fs_info(sbi, "write access unavailable, skipping orphan cleanup");
                return 0;
        }
 
        if (s_flags & SB_RDONLY) {
-               f2fs_msg(sbi->sb, KERN_INFO, "orphan cleanup on readonly fs");
+               f2fs_info(sbi, "orphan cleanup on readonly fs");
                sbi->sb->s_flags &= ~SB_RDONLY;
        }
 
@@ -827,26 +825,14 @@ static int get_checkpoint_version(struct f2fs_sb_info *sbi, block_t cp_addr,
        if (crc_offset < CP_MIN_CHKSUM_OFFSET ||
                        crc_offset > CP_CHKSUM_OFFSET) {
                f2fs_put_page(*cp_page, 1);
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                       "invalid crc_offset: %zu", crc_offset);
+               f2fs_warn(sbi, "invalid crc_offset: %zu", crc_offset);
                return -EINVAL;
        }
 
-       if (__is_set_ckpt_flags(*cp_block, CP_LARGE_NAT_BITMAP_FLAG)) {
-               if (crc_offset != CP_MIN_CHKSUM_OFFSET) {
-                       f2fs_put_page(*cp_page, 1);
-                       f2fs_msg(sbi->sb, KERN_WARNING,
-                               "layout of large_nat_bitmap is deprecated, "
-                               "run fsck to repair, chksum_offset: %zu",
-                               crc_offset);
-                       return -EINVAL;
-               }
-       }
-
        crc = f2fs_checkpoint_chksum(sbi, *cp_block);
        if (crc != cur_cp_crc(*cp_block)) {
                f2fs_put_page(*cp_page, 1);
-               f2fs_msg(sbi->sb, KERN_WARNING, "invalid crc value");
+               f2fs_warn(sbi, "invalid crc value");
                return -EINVAL;
        }
 
@@ -869,9 +855,8 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
 
        if (le32_to_cpu(cp_block->cp_pack_total_block_count) >
                                        sbi->blocks_per_seg) {
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                       "invalid cp_pack_total_block_count:%u",
-                       le32_to_cpu(cp_block->cp_pack_total_block_count));
+               f2fs_warn(sbi, "invalid cp_pack_total_block_count:%u",
+                         le32_to_cpu(cp_block->cp_pack_total_block_count));
                goto invalid_cp;
        }
        pre_version = *version;
@@ -905,6 +890,7 @@ int f2fs_get_valid_checkpoint(struct f2fs_sb_info *sbi)
        unsigned int cp_blks = 1 + __cp_payload(sbi);
        block_t cp_blk_no;
        int i;
+       int err;
 
        sbi->ckpt = f2fs_kzalloc(sbi, array_size(blk_size, cp_blks),
                                 GFP_KERNEL);
@@ -932,6 +918,7 @@ int f2fs_get_valid_checkpoint(struct f2fs_sb_info *sbi)
        } else if (cp2) {
                cur_page = cp2;
        } else {
+               err = -EFSCORRUPTED;
                goto fail_no_cp;
        }
 
@@ -944,8 +931,10 @@ int f2fs_get_valid_checkpoint(struct f2fs_sb_info *sbi)
                sbi->cur_cp_pack = 2;
 
        /* Sanity checking of checkpoint */
-       if (f2fs_sanity_check_ckpt(sbi))
+       if (f2fs_sanity_check_ckpt(sbi)) {
+               err = -EFSCORRUPTED;
                goto free_fail_no_cp;
+       }
 
        if (cp_blks <= 1)
                goto done;
@@ -959,8 +948,10 @@ int f2fs_get_valid_checkpoint(struct f2fs_sb_info *sbi)
                unsigned char *ckpt = (unsigned char *)sbi->ckpt;
 
                cur_page = f2fs_get_meta_page(sbi, cp_blk_no + i);
-               if (IS_ERR(cur_page))
+               if (IS_ERR(cur_page)) {
+                       err = PTR_ERR(cur_page);
                        goto free_fail_no_cp;
+               }
                sit_bitmap_ptr = page_address(cur_page);
                memcpy(ckpt + i * blk_size, sit_bitmap_ptr, blk_size);
                f2fs_put_page(cur_page, 1);
@@ -975,7 +966,7 @@ free_fail_no_cp:
        f2fs_put_page(cp2, 1);
 fail_no_cp:
        kvfree(sbi->ckpt);
-       return -EINVAL;
+       return err;
 }
 
 static void __add_dirty_inode(struct inode *inode, enum inode_type type)
@@ -1142,17 +1133,24 @@ static void __prepare_cp_block(struct f2fs_sb_info *sbi)
 
 static bool __need_flush_quota(struct f2fs_sb_info *sbi)
 {
+       bool ret = false;
+
        if (!is_journalled_quota(sbi))
                return false;
-       if (is_sbi_flag_set(sbi, SBI_QUOTA_SKIP_FLUSH))
-               return false;
-       if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_REPAIR))
-               return false;
-       if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_FLUSH))
-               return true;
-       if (get_pages(sbi, F2FS_DIRTY_QDATA))
-               return true;
-       return false;
+
+       down_write(&sbi->quota_sem);
+       if (is_sbi_flag_set(sbi, SBI_QUOTA_SKIP_FLUSH)) {
+               ret = false;
+       } else if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_REPAIR)) {
+               ret = false;
+       } else if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_FLUSH)) {
+               clear_sbi_flag(sbi, SBI_QUOTA_NEED_FLUSH);
+               ret = true;
+       } else if (get_pages(sbi, F2FS_DIRTY_QDATA)) {
+               ret = true;
+       }
+       up_write(&sbi->quota_sem);
+       return ret;
 }
 
 /*
@@ -1171,26 +1169,22 @@ static int block_operations(struct f2fs_sb_info *sbi)
        blk_start_plug(&plug);
 
 retry_flush_quotas:
+       f2fs_lock_all(sbi);
        if (__need_flush_quota(sbi)) {
                int locked;
 
                if (++cnt > DEFAULT_RETRY_QUOTA_FLUSH_COUNT) {
                        set_sbi_flag(sbi, SBI_QUOTA_SKIP_FLUSH);
-                       f2fs_lock_all(sbi);
+                       set_sbi_flag(sbi, SBI_QUOTA_NEED_FLUSH);
                        goto retry_flush_dents;
                }
-               clear_sbi_flag(sbi, SBI_QUOTA_NEED_FLUSH);
+               f2fs_unlock_all(sbi);
 
                /* only failed during mount/umount/freeze/quotactl */
                locked = down_read_trylock(&sbi->sb->s_umount);
                f2fs_quota_sync(sbi->sb, -1);
                if (locked)
                        up_read(&sbi->sb->s_umount);
-       }
-
-       f2fs_lock_all(sbi);
-       if (__need_flush_quota(sbi)) {
-               f2fs_unlock_all(sbi);
                cond_resched();
                goto retry_flush_quotas;
        }
@@ -1212,12 +1206,6 @@ retry_flush_dents:
         */
        down_write(&sbi->node_change);
 
-       if (__need_flush_quota(sbi)) {
-               up_write(&sbi->node_change);
-               f2fs_unlock_all(sbi);
-               goto retry_flush_quotas;
-       }
-
        if (get_pages(sbi, F2FS_DIRTY_IMETA)) {
                up_write(&sbi->node_change);
                f2fs_unlock_all(sbi);
@@ -1313,7 +1301,8 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        else
                __clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
 
-       if (is_sbi_flag_set(sbi, SBI_NEED_FSCK))
+       if (is_sbi_flag_set(sbi, SBI_NEED_FSCK) ||
+               is_sbi_flag_set(sbi, SBI_IS_RESIZEFS))
                __set_ckpt_flags(ckpt, CP_FSCK_FLAG);
 
        if (is_sbi_flag_set(sbi, SBI_CP_DISABLED))
@@ -1328,10 +1317,8 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc)
 
        if (is_sbi_flag_set(sbi, SBI_QUOTA_SKIP_FLUSH))
                __set_ckpt_flags(ckpt, CP_QUOTA_NEED_FSCK_FLAG);
-       /*
-        * TODO: we count on fsck.f2fs to clear this flag until we figure out
-        * missing cases which clear it incorrectly.
-        */
+       else
+               __clear_ckpt_flags(ckpt, CP_QUOTA_NEED_FSCK_FLAG);
 
        if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_REPAIR))
                __set_ckpt_flags(ckpt, CP_QUOTA_NEED_FSCK_FLAG);
@@ -1571,8 +1558,7 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
                if (cpc->reason != CP_PAUSE)
                        return 0;
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                               "Start checkpoint disabled!");
+               f2fs_warn(sbi, "Start checkpoint disabled!");
        }
        mutex_lock(&sbi->cp_mutex);
 
@@ -1638,8 +1624,7 @@ stop:
        stat_inc_cp_count(sbi->stat_info);
 
        if (cpc->reason & CP_RECOVERY)
-               f2fs_msg(sbi->sb, KERN_NOTICE,
-                       "checkpoint: version = %llx", ckpt_ver);
+               f2fs_notice(sbi, "checkpoint: version = %llx", ckpt_ver);
 
        /* do checkpoint periodically */
        f2fs_update_time(sbi, CP_TIME);
index a546ac8..0ca530a 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/pagevec.h>
 #include <linux/blkdev.h>
 #include <linux/bio.h>
+#include <linux/swap.h>
 #include <linux/prefetch.h>
 #include <linux/uio.h>
 #include <linux/cleancache.h>
@@ -54,7 +55,7 @@ static bool __is_cp_guaranteed(struct page *page)
 
 static enum count_type __read_io_type(struct page *page)
 {
-       struct address_space *mapping = page->mapping;
+       struct address_space *mapping = page_file_mapping(page);
 
        if (mapping) {
                struct inode *inode = mapping->host;
@@ -347,20 +348,20 @@ static void __submit_merged_bio(struct f2fs_bio_info *io)
        io->bio = NULL;
 }
 
-static bool __has_merged_page(struct f2fs_bio_info *io, struct inode *inode,
+static bool __has_merged_page(struct bio *bio, struct inode *inode,
                                                struct page *page, nid_t ino)
 {
        struct bio_vec *bvec;
        struct page *target;
        struct bvec_iter_all iter_all;
 
-       if (!io->bio)
+       if (!bio)
                return false;
 
        if (!inode && !page && !ino)
                return true;
 
-       bio_for_each_segment_all(bvec, io->bio, iter_all) {
+       bio_for_each_segment_all(bvec, bio, iter_all) {
 
                target = bvec->bv_page;
                if (fscrypt_is_bounce_page(target))
@@ -410,7 +411,7 @@ static void __submit_merged_write_cond(struct f2fs_sb_info *sbi,
                        struct f2fs_bio_info *io = sbi->write_io[btype] + temp;
 
                        down_read(&io->io_rwsem);
-                       ret = __has_merged_page(io, inode, page, ino);
+                       ret = __has_merged_page(io->bio, inode, page, ino);
                        up_read(&io->io_rwsem);
                }
                if (ret)
@@ -454,7 +455,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
        if (!f2fs_is_valid_blkaddr(fio->sbi, fio->new_blkaddr,
                        fio->is_por ? META_POR : (__is_meta_io(fio) ?
                        META_GENERIC : DATA_GENERIC_ENHANCE)))
-               return -EFAULT;
+               return -EFSCORRUPTED;
 
        trace_f2fs_submit_page_bio(page, fio);
        f2fs_trace_ios(fio, 0);
@@ -480,6 +481,61 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
        return 0;
 }
 
+int f2fs_merge_page_bio(struct f2fs_io_info *fio)
+{
+       struct bio *bio = *fio->bio;
+       struct page *page = fio->encrypted_page ?
+                       fio->encrypted_page : fio->page;
+
+       if (!f2fs_is_valid_blkaddr(fio->sbi, fio->new_blkaddr,
+                       __is_meta_io(fio) ? META_GENERIC : DATA_GENERIC))
+               return -EFSCORRUPTED;
+
+       trace_f2fs_submit_page_bio(page, fio);
+       f2fs_trace_ios(fio, 0);
+
+       if (bio && (*fio->last_block + 1 != fio->new_blkaddr ||
+                       !__same_bdev(fio->sbi, fio->new_blkaddr, bio))) {
+               __submit_bio(fio->sbi, bio, fio->type);
+               bio = NULL;
+       }
+alloc_new:
+       if (!bio) {
+               bio = __bio_alloc(fio->sbi, fio->new_blkaddr, fio->io_wbc,
+                               BIO_MAX_PAGES, false, fio->type, fio->temp);
+               bio_set_op_attrs(bio, fio->op, fio->op_flags);
+       }
+
+       if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
+               __submit_bio(fio->sbi, bio, fio->type);
+               bio = NULL;
+               goto alloc_new;
+       }
+
+       if (fio->io_wbc)
+               wbc_account_io(fio->io_wbc, page, PAGE_SIZE);
+
+       inc_page_count(fio->sbi, WB_DATA_TYPE(page));
+
+       *fio->last_block = fio->new_blkaddr;
+       *fio->bio = bio;
+
+       return 0;
+}
+
+static void f2fs_submit_ipu_bio(struct f2fs_sb_info *sbi, struct bio **bio,
+                                                       struct page *page)
+{
+       if (!bio)
+               return;
+
+       if (!__has_merged_page(*bio, NULL, page, 0))
+               return;
+
+       __submit_bio(sbi, *bio, DATA);
+       *bio = NULL;
+}
+
 void f2fs_submit_page_write(struct f2fs_io_info *fio)
 {
        struct f2fs_sb_info *sbi = fio->sbi;
@@ -733,7 +789,7 @@ struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
                dn.data_blkaddr = ei.blk + index - ei.fofs;
                if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), dn.data_blkaddr,
                                                DATA_GENERIC_ENHANCE_READ)) {
-                       err = -EFAULT;
+                       err = -EFSCORRUPTED;
                        goto put_err;
                }
                goto got_it;
@@ -753,7 +809,7 @@ struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
                        !f2fs_is_valid_blkaddr(F2FS_I_SB(inode),
                                                dn.data_blkaddr,
                                                DATA_GENERIC_ENHANCE)) {
-               err = -EFAULT;
+               err = -EFSCORRUPTED;
                goto put_err;
        }
 got_it:
@@ -1099,7 +1155,7 @@ next_block:
 
        if (__is_valid_data_blkaddr(blkaddr) &&
                !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE)) {
-               err = -EFAULT;
+               err = -EFSCORRUPTED;
                goto sync_out;
        }
 
@@ -1529,7 +1585,7 @@ static int f2fs_read_single_page(struct inode *inode, struct page *page,
        sector_t block_nr;
        int ret = 0;
 
-       block_in_file = (sector_t)page->index;
+       block_in_file = (sector_t)page_index(page);
        last_block = block_in_file + nr_pages;
        last_block_in_file = (i_size_read(inode) + blocksize - 1) >>
                                                        blkbits;
@@ -1562,14 +1618,15 @@ got_it:
                block_nr = map->m_pblk + block_in_file - map->m_lblk;
                SetPageMappedToDisk(page);
 
-               if (!PageUptodate(page) && !cleancache_get_page(page)) {
+               if (!PageUptodate(page) && (!PageSwapCache(page) &&
+                                       !cleancache_get_page(page))) {
                        SetPageUptodate(page);
                        goto confused;
                }
 
                if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), block_nr,
                                                DATA_GENERIC_ENHANCE_READ)) {
-                       ret = -EFAULT;
+                       ret = -EFSCORRUPTED;
                        goto out;
                }
        } else {
@@ -1660,7 +1717,7 @@ static int f2fs_mpage_readpages(struct address_space *mapping,
                        prefetchw(&page->flags);
                        list_del(&page->lru);
                        if (add_to_page_cache_lru(page, mapping,
-                                                 page->index,
+                                                 page_index(page),
                                                  readahead_gfp_mask(mapping)))
                                goto next_page;
                }
@@ -1684,7 +1741,7 @@ next_page:
 
 static int f2fs_read_data_page(struct file *file, struct page *page)
 {
-       struct inode *inode = page->mapping->host;
+       struct inode *inode = page_file_mapping(page)->host;
        int ret = -EAGAIN;
 
        trace_f2fs_readpage(page, DATA);
@@ -1693,7 +1750,8 @@ static int f2fs_read_data_page(struct file *file, struct page *page)
        if (f2fs_has_inline_data(inode))
                ret = f2fs_read_inline_data(inode, page);
        if (ret == -EAGAIN)
-               ret = f2fs_mpage_readpages(page->mapping, NULL, page, 1, false);
+               ret = f2fs_mpage_readpages(page_file_mapping(page),
+                                               NULL, page, 1, false);
        return ret;
 }
 
@@ -1851,7 +1909,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
 
                if (!f2fs_is_valid_blkaddr(fio->sbi, fio->old_blkaddr,
                                                DATA_GENERIC_ENHANCE))
-                       return -EFAULT;
+                       return -EFSCORRUPTED;
 
                ipu_force = true;
                fio->need_lock = LOCK_DONE;
@@ -1878,7 +1936,7 @@ got_it:
        if (__is_valid_data_blkaddr(fio->old_blkaddr) &&
                !f2fs_is_valid_blkaddr(fio->sbi, fio->old_blkaddr,
                                                DATA_GENERIC_ENHANCE)) {
-               err = -EFAULT;
+               err = -EFSCORRUPTED;
                goto out_writepage;
        }
        /*
@@ -1946,6 +2004,8 @@ out:
 }
 
 static int __write_data_page(struct page *page, bool *submitted,
+                               struct bio **bio,
+                               sector_t *last_block,
                                struct writeback_control *wbc,
                                enum iostat_type io_type)
 {
@@ -1971,6 +2031,8 @@ static int __write_data_page(struct page *page, bool *submitted,
                .need_lock = LOCK_RETRY,
                .io_type = io_type,
                .io_wbc = wbc,
+               .bio = bio,
+               .last_block = last_block,
        };
 
        trace_f2fs_writepage(page, DATA);
@@ -2069,10 +2131,13 @@ out:
 
        unlock_page(page);
        if (!S_ISDIR(inode->i_mode) && !IS_NOQUOTA(inode) &&
-                                       !F2FS_I(inode)->cp_task)
+                                       !F2FS_I(inode)->cp_task) {
+               f2fs_submit_ipu_bio(sbi, bio, page);
                f2fs_balance_fs(sbi, need_balance_fs);
+       }
 
        if (unlikely(f2fs_cp_error(sbi))) {
+               f2fs_submit_ipu_bio(sbi, bio, page);
                f2fs_submit_merged_write(sbi, DATA);
                submitted = NULL;
        }
@@ -2099,7 +2164,7 @@ redirty_out:
 static int f2fs_write_data_page(struct page *page,
                                        struct writeback_control *wbc)
 {
-       return __write_data_page(page, NULL, wbc, FS_DATA_IO);
+       return __write_data_page(page, NULL, NULL, NULL, wbc, FS_DATA_IO);
 }
 
 /*
@@ -2115,6 +2180,8 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
        int done = 0;
        struct pagevec pvec;
        struct f2fs_sb_info *sbi = F2FS_M_SB(mapping);
+       struct bio *bio = NULL;
+       sector_t last_block;
        int nr_pages;
        pgoff_t uninitialized_var(writeback_index);
        pgoff_t index;
@@ -2191,17 +2258,20 @@ continue_unlock:
                        }
 
                        if (PageWriteback(page)) {
-                               if (wbc->sync_mode != WB_SYNC_NONE)
+                               if (wbc->sync_mode != WB_SYNC_NONE) {
                                        f2fs_wait_on_page_writeback(page,
                                                        DATA, true, true);
-                               else
+                                       f2fs_submit_ipu_bio(sbi, &bio, page);
+                               } else {
                                        goto continue_unlock;
+                               }
                        }
 
                        if (!clear_page_dirty_for_io(page))
                                goto continue_unlock;
 
-                       ret = __write_data_page(page, &submitted, wbc, io_type);
+                       ret = __write_data_page(page, &submitted, &bio,
+                                       &last_block, wbc, io_type);
                        if (unlikely(ret)) {
                                /*
                                 * keep nr_to_write, since vfs uses this to
@@ -2250,6 +2320,9 @@ continue_unlock:
        if (nwritten)
                f2fs_submit_merged_write_cond(F2FS_M_SB(mapping), mapping->host,
                                                                NULL, 0, DATA);
+       /* submit cached bio of IPU write */
+       if (bio)
+               __submit_bio(sbi, bio, DATA);
 
        return ret;
 }
@@ -2261,6 +2334,9 @@ static inline bool __should_serialize_io(struct inode *inode,
                return false;
        if (IS_NOQUOTA(inode))
                return false;
+       /* to avoid deadlock in path of data flush */
+       if (F2FS_I(inode)->cp_task)
+               return false;
        if (wbc->sync_mode != WB_SYNC_ALL)
                return true;
        if (get_dirty_pages(inode) >= SM_I(F2FS_I_SB(inode))->min_seq_blocks)
@@ -2532,7 +2608,7 @@ repeat:
        } else {
                if (!f2fs_is_valid_blkaddr(sbi, blkaddr,
                                DATA_GENERIC_ENHANCE_READ)) {
-                       err = -EFAULT;
+                       err = -EFSCORRUPTED;
                        goto fail;
                }
                err = f2fs_submit_page_read(inode, page, blkaddr);
@@ -2777,13 +2853,14 @@ int f2fs_release_page(struct page *page, gfp_t wait)
 
 static int f2fs_set_data_page_dirty(struct page *page)
 {
-       struct address_space *mapping = page->mapping;
-       struct inode *inode = mapping->host;
+       struct inode *inode = page_file_mapping(page)->host;
 
        trace_f2fs_set_page_dirty(page, DATA);
 
        if (!PageUptodate(page))
                SetPageUptodate(page);
+       if (PageSwapCache(page))
+               return __set_page_dirty_nobuffers(page);
 
        if (f2fs_is_atomic_file(inode) && !f2fs_is_commit_atomic_write(inode)) {
                if (!IS_ATOMIC_WRITTEN_PAGE(page)) {
@@ -2875,6 +2952,126 @@ int f2fs_migrate_page(struct address_space *mapping,
 }
 #endif
 
+#ifdef CONFIG_SWAP
+/* Copied from generic_swapfile_activate() to check any holes */
+static int check_swap_activate(struct file *swap_file, unsigned int max)
+{
+       struct address_space *mapping = swap_file->f_mapping;
+       struct inode *inode = mapping->host;
+       unsigned blocks_per_page;
+       unsigned long page_no;
+       unsigned blkbits;
+       sector_t probe_block;
+       sector_t last_block;
+       sector_t lowest_block = -1;
+       sector_t highest_block = 0;
+
+       blkbits = inode->i_blkbits;
+       blocks_per_page = PAGE_SIZE >> blkbits;
+
+       /*
+        * Map all the blocks into the extent list.  This code doesn't try
+        * to be very smart.
+        */
+       probe_block = 0;
+       page_no = 0;
+       last_block = i_size_read(inode) >> blkbits;
+       while ((probe_block + blocks_per_page) <= last_block && page_no < max) {
+               unsigned block_in_page;
+               sector_t first_block;
+
+               cond_resched();
+
+               first_block = bmap(inode, probe_block);
+               if (first_block == 0)
+                       goto bad_bmap;
+
+               /*
+                * It must be PAGE_SIZE aligned on-disk
+                */
+               if (first_block & (blocks_per_page - 1)) {
+                       probe_block++;
+                       goto reprobe;
+               }
+
+               for (block_in_page = 1; block_in_page < blocks_per_page;
+                                       block_in_page++) {
+                       sector_t block;
+
+                       block = bmap(inode, probe_block + block_in_page);
+                       if (block == 0)
+                               goto bad_bmap;
+                       if (block != first_block + block_in_page) {
+                               /* Discontiguity */
+                               probe_block++;
+                               goto reprobe;
+                       }
+               }
+
+               first_block >>= (PAGE_SHIFT - blkbits);
+               if (page_no) {  /* exclude the header page */
+                       if (first_block < lowest_block)
+                               lowest_block = first_block;
+                       if (first_block > highest_block)
+                               highest_block = first_block;
+               }
+
+               page_no++;
+               probe_block += blocks_per_page;
+reprobe:
+               continue;
+       }
+       return 0;
+
+bad_bmap:
+       pr_err("swapon: swapfile has holes\n");
+       return -EINVAL;
+}
+
+static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file,
+                               sector_t *span)
+{
+       struct inode *inode = file_inode(file);
+       int ret;
+
+       if (!S_ISREG(inode->i_mode))
+               return -EINVAL;
+
+       if (f2fs_readonly(F2FS_I_SB(inode)->sb))
+               return -EROFS;
+
+       ret = f2fs_convert_inline_inode(inode);
+       if (ret)
+               return ret;
+
+       ret = check_swap_activate(file, sis->max);
+       if (ret)
+               return ret;
+
+       set_inode_flag(inode, FI_PIN_FILE);
+       f2fs_precache_extents(inode);
+       f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
+       return 0;
+}
+
+static void f2fs_swap_deactivate(struct file *file)
+{
+       struct inode *inode = file_inode(file);
+
+       clear_inode_flag(inode, FI_PIN_FILE);
+}
+#else
+static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file,
+                               sector_t *span)
+{
+       return -EOPNOTSUPP;
+}
+
+static void f2fs_swap_deactivate(struct file *file)
+{
+}
+#endif
+
 const struct address_space_operations f2fs_dblock_aops = {
        .readpage       = f2fs_read_data_page,
        .readpages      = f2fs_read_data_pages,
@@ -2887,6 +3084,8 @@ const struct address_space_operations f2fs_dblock_aops = {
        .releasepage    = f2fs_release_page,
        .direct_IO      = f2fs_direct_IO,
        .bmap           = f2fs_bmap,
+       .swap_activate  = f2fs_swap_activate,
+       .swap_deactivate = f2fs_swap_deactivate,
 #ifdef CONFIG_MIGRATION
        .migratepage    = f2fs_migrate_page,
 #endif
index 99e9a5c..7706049 100644 (file)
@@ -27,8 +27,15 @@ static DEFINE_MUTEX(f2fs_stat_mutex);
 static void update_general_status(struct f2fs_sb_info *sbi)
 {
        struct f2fs_stat_info *si = F2FS_STAT(sbi);
+       struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
        int i;
 
+       /* these will be changed if online resize is done */
+       si->main_area_segs = le32_to_cpu(raw_super->segment_count_main);
+       si->main_area_sections = le32_to_cpu(raw_super->section_count);
+       si->main_area_zones = si->main_area_sections /
+                               le32_to_cpu(raw_super->secs_per_zone);
+
        /* validation check of the segment numbers */
        si->hit_largest = atomic64_read(&sbi->read_hit_largest);
        si->hit_cached = atomic64_read(&sbi->read_hit_cached);
index 59bc460..85a1528 100644 (file)
@@ -218,9 +218,8 @@ struct f2fs_dir_entry *__f2fs_find_entry(struct inode *dir,
 
        max_depth = F2FS_I(dir)->i_current_depth;
        if (unlikely(max_depth > MAX_DIR_HASH_DEPTH)) {
-               f2fs_msg(F2FS_I_SB(dir)->sb, KERN_WARNING,
-                               "Corrupted max_depth of %lu: %u",
-                               dir->i_ino, max_depth);
+               f2fs_warn(F2FS_I_SB(dir), "Corrupted max_depth of %lu: %u",
+                         dir->i_ino, max_depth);
                max_depth = MAX_DIR_HASH_DEPTH;
                f2fs_i_depth_write(dir, max_depth);
        }
@@ -816,11 +815,10 @@ int f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
                bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
                if (unlikely(bit_pos > d->max ||
                                le16_to_cpu(de->name_len) > F2FS_NAME_LEN)) {
-                       f2fs_msg(sbi->sb, KERN_WARNING,
-                               "%s: corrupted namelen=%d, run fsck to fix.",
-                               __func__, le16_to_cpu(de->name_len));
+                       f2fs_warn(sbi, "%s: corrupted namelen=%d, run fsck to fix.",
+                                 __func__, le16_to_cpu(de->name_len));
                        set_sbi_flag(sbi, SBI_NEED_FSCK);
-                       err = -EINVAL;
+                       err = -EFSCORRUPTED;
                        goto out;
                }
 
@@ -828,8 +826,8 @@ int f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
                        int save_len = fstr->len;
 
                        err = fscrypt_fname_disk_to_usr(d->inode,
-                                               (u32)de->hash_code, 0,
-                                               &de_name, fstr);
+                                               (u32)le32_to_cpu(de->hash_code),
+                                               0, &de_name, fstr);
                        if (err)
                                goto out;
 
index caf77fe..e600784 100644 (file)
@@ -184,10 +184,9 @@ bool f2fs_check_rb_tree_consistence(struct f2fs_sb_info *sbi,
                next_re = rb_entry(next, struct rb_entry, rb_node);
 
                if (cur_re->ofs + cur_re->len > next_re->ofs) {
-                       f2fs_msg(sbi->sb, KERN_INFO, "inconsistent rbtree, "
-                               "cur(%u, %u) next(%u, %u)",
-                               cur_re->ofs, cur_re->len,
-                               next_re->ofs, next_re->len);
+                       f2fs_info(sbi, "inconsistent rbtree, cur(%u, %u) next(%u, %u)",
+                                 cur_re->ofs, cur_re->len,
+                                 next_re->ofs, next_re->len);
                        return false;
                }
 
index 06b89a9..17382da 100644 (file)
@@ -136,6 +136,9 @@ struct f2fs_mount_info {
        int alloc_mode;                 /* segment allocation policy */
        int fsync_mode;                 /* fsync policy */
        bool test_dummy_encryption;     /* test dummy encryption */
+       block_t unusable_cap;           /* Amount of space allowed to be
+                                        * unusable when disabling checkpoint
+                                        */
 };
 
 #define F2FS_FEATURE_ENCRYPT           0x0001
@@ -412,6 +415,7 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,
 #define F2FS_IOC_SET_PIN_FILE          _IOW(F2FS_IOCTL_MAGIC, 13, __u32)
 #define F2FS_IOC_GET_PIN_FILE          _IOR(F2FS_IOCTL_MAGIC, 14, __u32)
 #define F2FS_IOC_PRECACHE_EXTENTS      _IO(F2FS_IOCTL_MAGIC, 15)
+#define F2FS_IOC_RESIZE_FS             _IOW(F2FS_IOCTL_MAGIC, 16, __u64)
 
 #define F2FS_IOC_SET_ENCRYPTION_POLICY FS_IOC_SET_ENCRYPTION_POLICY
 #define F2FS_IOC_GET_ENCRYPTION_POLICY FS_IOC_GET_ENCRYPTION_POLICY
@@ -476,8 +480,8 @@ static inline int get_inline_xattr_addrs(struct inode *inode);
 #define NR_INLINE_DENTRY(inode)        (MAX_INLINE_DATA(inode) * BITS_PER_BYTE / \
                                ((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \
                                BITS_PER_BYTE + 1))
-#define INLINE_DENTRY_BITMAP_SIZE(inode)       ((NR_INLINE_DENTRY(inode) + \
-                                       BITS_PER_BYTE - 1) / BITS_PER_BYTE)
+#define INLINE_DENTRY_BITMAP_SIZE(inode) \
+       DIV_ROUND_UP(NR_INLINE_DENTRY(inode), BITS_PER_BYTE)
 #define INLINE_RESERVED_SIZE(inode)    (MAX_INLINE_DATA(inode) - \
                                ((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \
                                NR_INLINE_DENTRY(inode) + \
@@ -1052,6 +1056,8 @@ struct f2fs_io_info {
        bool retry;             /* need to reallocate block address */
        enum iostat_type io_type;       /* io type */
        struct writeback_control *io_wbc; /* writeback control */
+       struct bio **bio;               /* bio for ipu */
+       sector_t *last_block;           /* last block number in bio */
        unsigned char version;          /* version of the node */
 };
 
@@ -1111,6 +1117,7 @@ enum {
        SBI_QUOTA_NEED_FLUSH,                   /* need to flush quota info in CP */
        SBI_QUOTA_SKIP_FLUSH,                   /* skip flushing quota in current CP */
        SBI_QUOTA_NEED_REPAIR,                  /* quota file may be corrupted */
+       SBI_IS_RESIZEFS,                        /* resizefs is in process */
 };
 
 enum {
@@ -1207,6 +1214,7 @@ struct f2fs_sb_info {
        /* for inode management */
        struct list_head inode_list[NR_INODE_TYPE];     /* dirty inode list */
        spinlock_t inode_lock[NR_INODE_TYPE];   /* for dirty inode list lock */
+       struct mutex flush_lock;                /* for flush exclusion */
 
        /* for extent tree cache */
        struct radix_tree_root extent_tree_root;/* cache extent cache entries */
@@ -1230,6 +1238,7 @@ struct f2fs_sb_info {
        unsigned int segs_per_sec;              /* segments per section */
        unsigned int secs_per_zone;             /* sections per zone */
        unsigned int total_sections;            /* total section count */
+       struct mutex resize_mutex;              /* for resize exclusion */
        unsigned int total_node_count;          /* total node block count */
        unsigned int total_valid_node_count;    /* valid node block count */
        loff_t max_file_blocks;                 /* max block index of file */
@@ -1247,6 +1256,7 @@ struct f2fs_sb_info {
        block_t unusable_block_count;           /* # of blocks saved by last cp */
 
        unsigned int nquota_files;              /* # of quota sysfile */
+       struct rw_semaphore quota_sem;          /* blocking cp for flags */
 
        /* # of pages, see count_type */
        atomic_t nr_pages[NR_COUNT_TYPE];
@@ -1488,7 +1498,7 @@ static inline struct f2fs_sb_info *F2FS_M_SB(struct address_space *mapping)
 
 static inline struct f2fs_sb_info *F2FS_P_SB(struct page *page)
 {
-       return F2FS_M_SB(page->mapping);
+       return F2FS_M_SB(page_file_mapping(page));
 }
 
 static inline struct f2fs_super_block *F2FS_RAW_SUPER(struct f2fs_sb_info *sbi)
@@ -1766,8 +1776,12 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
 
        if (!__allow_reserved_blocks(sbi, inode, true))
                avail_user_block_count -= F2FS_OPTION(sbi).root_reserved_blocks;
-       if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
-               avail_user_block_count -= sbi->unusable_block_count;
+       if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
+               if (avail_user_block_count > sbi->unusable_block_count)
+                       avail_user_block_count -= sbi->unusable_block_count;
+               else
+                       avail_user_block_count = 0;
+       }
        if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
                diff = sbi->total_valid_block_count - avail_user_block_count;
                if (diff > *count)
@@ -1795,7 +1809,20 @@ enospc:
        return -ENOSPC;
 }
 
-void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...);
+__printf(2, 3)
+void f2fs_printk(struct f2fs_sb_info *sbi, const char *fmt, ...);
+
+#define f2fs_err(sbi, fmt, ...)                                                \
+       f2fs_printk(sbi, KERN_ERR fmt, ##__VA_ARGS__)
+#define f2fs_warn(sbi, fmt, ...)                                       \
+       f2fs_printk(sbi, KERN_WARNING fmt, ##__VA_ARGS__)
+#define f2fs_notice(sbi, fmt, ...)                                     \
+       f2fs_printk(sbi, KERN_NOTICE fmt, ##__VA_ARGS__)
+#define f2fs_info(sbi, fmt, ...)                                       \
+       f2fs_printk(sbi, KERN_INFO fmt, ##__VA_ARGS__)
+#define f2fs_debug(sbi, fmt, ...)                                      \
+       f2fs_printk(sbi, KERN_DEBUG fmt, ##__VA_ARGS__)
+
 static inline void dec_valid_block_count(struct f2fs_sb_info *sbi,
                                                struct inode *inode,
                                                block_t count)
@@ -1811,11 +1838,10 @@ static inline void dec_valid_block_count(struct f2fs_sb_info *sbi,
                                        sbi->current_reserved_blocks + count);
        spin_unlock(&sbi->stat_lock);
        if (unlikely(inode->i_blocks < sectors)) {
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                       "Inconsistent i_blocks, ino:%lu, iblocks:%llu, sectors:%llu",
-                       inode->i_ino,
-                       (unsigned long long)inode->i_blocks,
-                       (unsigned long long)sectors);
+               f2fs_warn(sbi, "Inconsistent i_blocks, ino:%lu, iblocks:%llu, sectors:%llu",
+                         inode->i_ino,
+                         (unsigned long long)inode->i_blocks,
+                         (unsigned long long)sectors);
                set_sbi_flag(sbi, SBI_NEED_FSCK);
                return;
        }
@@ -1967,7 +1993,7 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi,
                                        struct inode *inode, bool is_inode)
 {
        block_t valid_block_count;
-       unsigned int valid_node_count;
+       unsigned int valid_node_count, user_block_count;
        int err;
 
        if (is_inode) {
@@ -1994,10 +2020,11 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi,
 
        if (!__allow_reserved_blocks(sbi, inode, false))
                valid_block_count += F2FS_OPTION(sbi).root_reserved_blocks;
+       user_block_count = sbi->user_block_count;
        if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
-               valid_block_count += sbi->unusable_block_count;
+               user_block_count -= sbi->unusable_block_count;
 
-       if (unlikely(valid_block_count > sbi->user_block_count)) {
+       if (unlikely(valid_block_count > user_block_count)) {
                spin_unlock(&sbi->stat_lock);
                goto enospc;
        }
@@ -2052,10 +2079,9 @@ static inline void dec_valid_node_count(struct f2fs_sb_info *sbi,
                dquot_free_inode(inode);
        } else {
                if (unlikely(inode->i_blocks == 0)) {
-                       f2fs_msg(sbi->sb, KERN_WARNING,
-                               "Inconsistent i_blocks, ino:%lu, iblocks:%llu",
-                               inode->i_ino,
-                               (unsigned long long)inode->i_blocks);
+                       f2fs_warn(sbi, "Inconsistent i_blocks, ino:%lu, iblocks:%llu",
+                                 inode->i_ino,
+                                 (unsigned long long)inode->i_blocks);
                        set_sbi_flag(sbi, SBI_NEED_FSCK);
                        return;
                }
@@ -2191,6 +2217,9 @@ static inline struct bio *f2fs_bio_alloc(struct f2fs_sb_info *sbi,
 
 static inline bool is_idle(struct f2fs_sb_info *sbi, int type)
 {
+       if (sbi->gc_mode == GC_URGENT)
+               return true;
+
        if (get_pages(sbi, F2FS_RD_DATA) || get_pages(sbi, F2FS_RD_NODE) ||
                get_pages(sbi, F2FS_RD_META) || get_pages(sbi, F2FS_WB_DATA) ||
                get_pages(sbi, F2FS_WB_CP_DATA) ||
@@ -2198,7 +2227,7 @@ static inline bool is_idle(struct f2fs_sb_info *sbi, int type)
                get_pages(sbi, F2FS_DIO_WRITE))
                return false;
 
-       if (SM_I(sbi) && SM_I(sbi)->dcc_info &&
+       if (type != DISCARD_TIME && SM_I(sbi) && SM_I(sbi)->dcc_info &&
                        atomic_read(&SM_I(sbi)->dcc_info->queued_discard))
                return false;
 
@@ -2320,57 +2349,23 @@ static inline void f2fs_change_bit(unsigned int nr, char *addr)
 }
 
 /*
- * Inode flags
+ * On-disk inode flags (f2fs_inode::i_flags)
  */
-#define F2FS_SECRM_FL                  0x00000001 /* Secure deletion */
-#define F2FS_UNRM_FL                   0x00000002 /* Undelete */
-#define F2FS_COMPR_FL                  0x00000004 /* Compress file */
 #define F2FS_SYNC_FL                   0x00000008 /* Synchronous updates */
 #define F2FS_IMMUTABLE_FL              0x00000010 /* Immutable file */
 #define F2FS_APPEND_FL                 0x00000020 /* writes to file may only append */
 #define F2FS_NODUMP_FL                 0x00000040 /* do not dump file */
 #define F2FS_NOATIME_FL                        0x00000080 /* do not update atime */
-/* Reserved for compression usage... */
-#define F2FS_DIRTY_FL                  0x00000100
-#define F2FS_COMPRBLK_FL               0x00000200 /* One or more compressed clusters */
-#define F2FS_NOCOMPR_FL                        0x00000400 /* Don't compress */
-#define F2FS_ENCRYPT_FL                        0x00000800 /* encrypted file */
-/* End compression flags --- maybe not all used */
 #define F2FS_INDEX_FL                  0x00001000 /* hash-indexed directory */
-#define F2FS_IMAGIC_FL                 0x00002000 /* AFS directory */
-#define F2FS_JOURNAL_DATA_FL           0x00004000 /* file data should be journaled */
-#define F2FS_NOTAIL_FL                 0x00008000 /* file tail should not be merged */
 #define F2FS_DIRSYNC_FL                        0x00010000 /* dirsync behaviour (directories only) */
-#define F2FS_TOPDIR_FL                 0x00020000 /* Top of directory hierarchies*/
-#define F2FS_HUGE_FILE_FL               0x00040000 /* Set to each huge file */
-#define F2FS_EXTENTS_FL                        0x00080000 /* Inode uses extents */
-#define F2FS_EA_INODE_FL               0x00200000 /* Inode used for large EA */
-#define F2FS_EOFBLOCKS_FL              0x00400000 /* Blocks allocated beyond EOF */
-#define F2FS_NOCOW_FL                  0x00800000 /* Do not cow file */
-#define F2FS_INLINE_DATA_FL            0x10000000 /* Inode has inline data. */
 #define F2FS_PROJINHERIT_FL            0x20000000 /* Create with parents projid */
-#define F2FS_RESERVED_FL               0x80000000 /* reserved for ext4 lib */
-
-#define F2FS_FL_USER_VISIBLE           0x30CBDFFF /* User visible flags */
-#define F2FS_FL_USER_MODIFIABLE                0x204BC0FF /* User modifiable flags */
-
-/* Flags we can manipulate with through F2FS_IOC_FSSETXATTR */
-#define F2FS_FL_XFLAG_VISIBLE          (F2FS_SYNC_FL | \
-                                        F2FS_IMMUTABLE_FL | \
-                                        F2FS_APPEND_FL | \
-                                        F2FS_NODUMP_FL | \
-                                        F2FS_NOATIME_FL | \
-                                        F2FS_PROJINHERIT_FL)
 
 /* Flags that should be inherited by new inodes from their parent. */
-#define F2FS_FL_INHERITED (F2FS_SECRM_FL | F2FS_UNRM_FL | F2FS_COMPR_FL |\
-                          F2FS_SYNC_FL | F2FS_NODUMP_FL | F2FS_NOATIME_FL |\
-                          F2FS_NOCOMPR_FL | F2FS_JOURNAL_DATA_FL |\
-                          F2FS_NOTAIL_FL | F2FS_DIRSYNC_FL |\
-                          F2FS_PROJINHERIT_FL)
+#define F2FS_FL_INHERITED (F2FS_SYNC_FL | F2FS_NODUMP_FL | F2FS_NOATIME_FL | \
+                          F2FS_DIRSYNC_FL | F2FS_PROJINHERIT_FL)
 
 /* Flags that are appropriate for regular files (all but dir-specific ones). */
-#define F2FS_REG_FLMASK                (~(F2FS_DIRSYNC_FL | F2FS_TOPDIR_FL))
+#define F2FS_REG_FLMASK                (~(F2FS_DIRSYNC_FL | F2FS_PROJINHERIT_FL))
 
 /* Flags that are appropriate for non-directories/regular files. */
 #define F2FS_OTHER_FLMASK      (F2FS_NODUMP_FL | F2FS_NOATIME_FL)
@@ -2856,9 +2851,8 @@ static inline void verify_blkaddr(struct f2fs_sb_info *sbi,
                                        block_t blkaddr, int type)
 {
        if (!f2fs_is_valid_blkaddr(sbi, blkaddr, type)) {
-               f2fs_msg(sbi->sb, KERN_ERR,
-                       "invalid blkaddr: %u, type: %d, run fsck to fix.",
-                       blkaddr, type);
+               f2fs_err(sbi, "invalid blkaddr: %u, type: %d, run fsck to fix.",
+                        blkaddr, type);
                f2fs_bug_on(sbi, 1);
        }
 }
@@ -2989,8 +2983,6 @@ int f2fs_quota_sync(struct super_block *sb, int type);
 void f2fs_quota_off_umount(struct super_block *sb);
 int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover);
 int f2fs_sync_fs(struct super_block *sb, int sync);
-extern __printf(3, 4)
-void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...);
 int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi);
 
 /*
@@ -3074,9 +3066,12 @@ bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi);
 void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi,
                                        struct cp_control *cpc);
 void f2fs_dirty_to_prefree(struct f2fs_sb_info *sbi);
-int f2fs_disable_cp_again(struct f2fs_sb_info *sbi);
+block_t f2fs_get_unusable_blocks(struct f2fs_sb_info *sbi);
+int f2fs_disable_cp_again(struct f2fs_sb_info *sbi, block_t unusable);
 void f2fs_release_discard_addrs(struct f2fs_sb_info *sbi);
 int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra);
+void allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type,
+                                       unsigned int start, unsigned int end);
 void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi);
 int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range);
 bool f2fs_exist_trim_candidates(struct f2fs_sb_info *sbi,
@@ -3169,6 +3164,7 @@ void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi,
                                nid_t ino, enum page_type type);
 void f2fs_flush_merged_writes(struct f2fs_sb_info *sbi);
 int f2fs_submit_page_bio(struct f2fs_io_info *fio);
+int f2fs_merge_page_bio(struct f2fs_io_info *fio);
 void f2fs_submit_page_write(struct f2fs_io_info *fio);
 struct block_device *f2fs_target_device(struct f2fs_sb_info *sbi,
                        block_t blk_addr, struct bio *bio);
@@ -3214,6 +3210,7 @@ block_t f2fs_start_bidx_of_node(unsigned int node_ofs, struct inode *inode);
 int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, bool background,
                        unsigned int segno);
 void f2fs_build_gc_manager(struct f2fs_sb_info *sbi);
+int f2fs_resize_fs(struct f2fs_sb_info *sbi, __u64 block_count);
 
 /*
  * recovery.c
@@ -3686,7 +3683,8 @@ static inline bool f2fs_force_buffered_io(struct inode *inode,
        if (test_opt(sbi, LFS) && (rw == WRITE) &&
                                block_unaligned_IO(inode, iocb, iter))
                return true;
-       if (is_sbi_flag_set(F2FS_I_SB(inode), SBI_CP_DISABLED))
+       if (is_sbi_flag_set(F2FS_I_SB(inode), SBI_CP_DISABLED) &&
+                                       !(inode->i_flags & S_SWAPFILE))
                return true;
 
        return false;
@@ -3712,4 +3710,7 @@ static inline bool is_journalled_quota(struct f2fs_sb_info *sbi)
        return false;
 }
 
+#define EFSBADCRC      EBADMSG         /* Bad CRC detected */
+#define EFSCORRUPTED   EUCLEAN         /* Filesystem is corrupted */
+
 #endif /* _LINUX_F2FS_H */
index 45b45f3..f8d46df 100644 (file)
@@ -707,11 +707,9 @@ int f2fs_getattr(const struct path *path, struct kstat *stat,
                stat->btime.tv_nsec = fi->i_crtime.tv_nsec;
        }
 
-       flags = fi->i_flags & F2FS_FL_USER_VISIBLE;
+       flags = fi->i_flags;
        if (flags & F2FS_APPEND_FL)
                stat->attributes |= STATX_ATTR_APPEND;
-       if (flags & F2FS_COMPR_FL)
-               stat->attributes |= STATX_ATTR_COMPRESSED;
        if (IS_ENCRYPTED(inode))
                stat->attributes |= STATX_ATTR_ENCRYPTED;
        if (flags & F2FS_IMMUTABLE_FL)
@@ -720,7 +718,6 @@ int f2fs_getattr(const struct path *path, struct kstat *stat,
                stat->attributes |= STATX_ATTR_NODUMP;
 
        stat->attributes_mask |= (STATX_ATTR_APPEND |
-                                 STATX_ATTR_COMPRESSED |
                                  STATX_ATTR_ENCRYPTED |
                                  STATX_ATTR_IMMUTABLE |
                                  STATX_ATTR_NODUMP);
@@ -1026,7 +1023,7 @@ next_dnode:
                        !f2fs_is_valid_blkaddr(sbi, *blkaddr,
                                        DATA_GENERIC_ENHANCE)) {
                        f2fs_put_dnode(&dn);
-                       return -EFAULT;
+                       return -EFSCORRUPTED;
                }
 
                if (!f2fs_is_checkpointed_data(sbi, *blkaddr)) {
@@ -1214,7 +1211,7 @@ roll_back:
 static int f2fs_do_collapse(struct inode *inode, loff_t offset, loff_t len)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
-       pgoff_t nrpages = (i_size_read(inode) + PAGE_SIZE - 1) / PAGE_SIZE;
+       pgoff_t nrpages = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
        pgoff_t start = offset >> PAGE_SHIFT;
        pgoff_t end = (offset + len) >> PAGE_SHIFT;
        int ret;
@@ -1467,7 +1464,7 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
        pg_start = offset >> PAGE_SHIFT;
        pg_end = (offset + len) >> PAGE_SHIFT;
        delta = pg_end - pg_start;
-       idx = (i_size_read(inode) + PAGE_SIZE - 1) / PAGE_SIZE;
+       idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
 
        /* avoid gc operation during block exchange */
        down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
@@ -1531,7 +1528,12 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
        if (off_end)
                map.m_len++;
 
-       err = f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_AIO);
+       if (f2fs_is_pinned_file(inode))
+               map.m_seg_type = CURSEG_COLD_DATA;
+
+       err = f2fs_map_blocks(inode, &map, 1, (f2fs_is_pinned_file(inode) ?
+                                               F2FS_GET_BLOCK_PRE_DIO :
+                                               F2FS_GET_BLOCK_PRE_AIO));
        if (err) {
                pgoff_t last_off;
 
@@ -1648,44 +1650,22 @@ static int f2fs_file_flush(struct file *file, fl_owner_t id)
        return 0;
 }
 
-static int f2fs_ioc_getflags(struct file *filp, unsigned long arg)
+static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask)
 {
-       struct inode *inode = file_inode(filp);
        struct f2fs_inode_info *fi = F2FS_I(inode);
-       unsigned int flags = fi->i_flags;
-
-       if (IS_ENCRYPTED(inode))
-               flags |= F2FS_ENCRYPT_FL;
-       if (f2fs_has_inline_data(inode) || f2fs_has_inline_dentry(inode))
-               flags |= F2FS_INLINE_DATA_FL;
-       if (is_inode_flag_set(inode, FI_PIN_FILE))
-               flags |= F2FS_NOCOW_FL;
-
-       flags &= F2FS_FL_USER_VISIBLE;
-
-       return put_user(flags, (int __user *)arg);
-}
-
-static int __f2fs_ioc_setflags(struct inode *inode, unsigned int flags)
-{
-       struct f2fs_inode_info *fi = F2FS_I(inode);
-       unsigned int oldflags;
+       u32 oldflags;
 
        /* Is it quota file? Do not allow user to mess with it */
        if (IS_NOQUOTA(inode))
                return -EPERM;
 
-       flags = f2fs_mask_flags(inode->i_mode, flags);
-
        oldflags = fi->i_flags;
 
-       if ((flags ^ oldflags) & (F2FS_APPEND_FL | F2FS_IMMUTABLE_FL))
+       if ((iflags ^ oldflags) & (F2FS_APPEND_FL | F2FS_IMMUTABLE_FL))
                if (!capable(CAP_LINUX_IMMUTABLE))
                        return -EPERM;
 
-       flags = flags & F2FS_FL_USER_MODIFIABLE;
-       flags |= oldflags & ~F2FS_FL_USER_MODIFIABLE;
-       fi->i_flags = flags;
+       fi->i_flags = iflags | (oldflags & ~mask);
 
        if (fi->i_flags & F2FS_PROJINHERIT_FL)
                set_inode_flag(inode, FI_PROJ_INHERIT);
@@ -1698,26 +1678,124 @@ static int __f2fs_ioc_setflags(struct inode *inode, unsigned int flags)
        return 0;
 }
 
+/* FS_IOC_GETFLAGS and FS_IOC_SETFLAGS support */
+
+/*
+ * To make a new on-disk f2fs i_flag gettable via FS_IOC_GETFLAGS, add an entry
+ * for it to f2fs_fsflags_map[], and add its FS_*_FL equivalent to
+ * F2FS_GETTABLE_FS_FL.  To also make it settable via FS_IOC_SETFLAGS, also add
+ * its FS_*_FL equivalent to F2FS_SETTABLE_FS_FL.
+ */
+
+static const struct {
+       u32 iflag;
+       u32 fsflag;
+} f2fs_fsflags_map[] = {
+       { F2FS_SYNC_FL,         FS_SYNC_FL },
+       { F2FS_IMMUTABLE_FL,    FS_IMMUTABLE_FL },
+       { F2FS_APPEND_FL,       FS_APPEND_FL },
+       { F2FS_NODUMP_FL,       FS_NODUMP_FL },
+       { F2FS_NOATIME_FL,      FS_NOATIME_FL },
+       { F2FS_INDEX_FL,        FS_INDEX_FL },
+       { F2FS_DIRSYNC_FL,      FS_DIRSYNC_FL },
+       { F2FS_PROJINHERIT_FL,  FS_PROJINHERIT_FL },
+};
+
+#define F2FS_GETTABLE_FS_FL (          \
+               FS_SYNC_FL |            \
+               FS_IMMUTABLE_FL |       \
+               FS_APPEND_FL |          \
+               FS_NODUMP_FL |          \
+               FS_NOATIME_FL |         \
+               FS_INDEX_FL |           \
+               FS_DIRSYNC_FL |         \
+               FS_PROJINHERIT_FL |     \
+               FS_ENCRYPT_FL |         \
+               FS_INLINE_DATA_FL |     \
+               FS_NOCOW_FL)
+
+#define F2FS_SETTABLE_FS_FL (          \
+               FS_SYNC_FL |            \
+               FS_IMMUTABLE_FL |       \
+               FS_APPEND_FL |          \
+               FS_NODUMP_FL |          \
+               FS_NOATIME_FL |         \
+               FS_DIRSYNC_FL |         \
+               FS_PROJINHERIT_FL)
+
+/* Convert f2fs on-disk i_flags to FS_IOC_{GET,SET}FLAGS flags */
+static inline u32 f2fs_iflags_to_fsflags(u32 iflags)
+{
+       u32 fsflags = 0;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(f2fs_fsflags_map); i++)
+               if (iflags & f2fs_fsflags_map[i].iflag)
+                       fsflags |= f2fs_fsflags_map[i].fsflag;
+
+       return fsflags;
+}
+
+/* Convert FS_IOC_{GET,SET}FLAGS flags to f2fs on-disk i_flags */
+static inline u32 f2fs_fsflags_to_iflags(u32 fsflags)
+{
+       u32 iflags = 0;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(f2fs_fsflags_map); i++)
+               if (fsflags & f2fs_fsflags_map[i].fsflag)
+                       iflags |= f2fs_fsflags_map[i].iflag;
+
+       return iflags;
+}
+
+static int f2fs_ioc_getflags(struct file *filp, unsigned long arg)
+{
+       struct inode *inode = file_inode(filp);
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+       u32 fsflags = f2fs_iflags_to_fsflags(fi->i_flags);
+
+       if (IS_ENCRYPTED(inode))
+               fsflags |= FS_ENCRYPT_FL;
+       if (f2fs_has_inline_data(inode) || f2fs_has_inline_dentry(inode))
+               fsflags |= FS_INLINE_DATA_FL;
+       if (is_inode_flag_set(inode, FI_PIN_FILE))
+               fsflags |= FS_NOCOW_FL;
+
+       fsflags &= F2FS_GETTABLE_FS_FL;
+
+       return put_user(fsflags, (int __user *)arg);
+}
+
 static int f2fs_ioc_setflags(struct file *filp, unsigned long arg)
 {
        struct inode *inode = file_inode(filp);
-       unsigned int flags;
+       u32 fsflags;
+       u32 iflags;
        int ret;
 
        if (!inode_owner_or_capable(inode))
                return -EACCES;
 
-       if (get_user(flags, (int __user *)arg))
+       if (get_user(fsflags, (int __user *)arg))
                return -EFAULT;
 
+       if (fsflags & ~F2FS_GETTABLE_FS_FL)
+               return -EOPNOTSUPP;
+       fsflags &= F2FS_SETTABLE_FS_FL;
+
+       iflags = f2fs_fsflags_to_iflags(fsflags);
+       if (f2fs_mask_flags(inode->i_mode, iflags) != iflags)
+               return -EOPNOTSUPP;
+
        ret = mnt_want_write_file(filp);
        if (ret)
                return ret;
 
        inode_lock(inode);
 
-       ret = __f2fs_ioc_setflags(inode, flags);
-
+       ret = f2fs_setflags_common(inode, iflags,
+                       f2fs_fsflags_to_iflags(F2FS_SETTABLE_FS_FL));
        inode_unlock(inode);
        mnt_drop_write_file(filp);
        return ret;
@@ -1764,9 +1842,8 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)
         * f2fs_is_atomic_file.
         */
        if (get_dirty_pages(inode))
-               f2fs_msg(F2FS_I_SB(inode)->sb, KERN_WARNING,
-               "Unexpected flush for atomic writes: ino=%lu, npages=%u",
-                                       inode->i_ino, get_dirty_pages(inode));
+               f2fs_warn(F2FS_I_SB(inode), "Unexpected flush for atomic writes: ino=%lu, npages=%u",
+                         inode->i_ino, get_dirty_pages(inode));
        ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
        if (ret) {
                up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
@@ -2201,8 +2278,7 @@ static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg)
                return -EROFS;
 
        if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
-               f2fs_msg(sbi->sb, KERN_INFO,
-                       "Skipping Checkpoint. Checkpoints currently disabled.");
+               f2fs_info(sbi, "Skipping Checkpoint. Checkpoints currently disabled.");
                return -EINVAL;
        }
 
@@ -2291,7 +2367,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
        if (!fragmented)
                goto out;
 
-       sec_num = (total + BLKS_PER_SEC(sbi) - 1) / BLKS_PER_SEC(sbi);
+       sec_num = DIV_ROUND_UP(total, BLKS_PER_SEC(sbi));
 
        /*
         * make sure there are enough free section for LFS allocation, this can
@@ -2587,10 +2663,8 @@ static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg)
 
        if (!f2fs_is_multi_device(sbi) || sbi->s_ndevs - 1 <= range.dev_num ||
                        __is_large_section(sbi)) {
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                       "Can't flush %u in %d for segs_per_sec %u != 1",
-                               range.dev_num, sbi->s_ndevs,
-                               sbi->segs_per_sec);
+               f2fs_warn(sbi, "Can't flush %u in %d for segs_per_sec %u != 1",
+                         range.dev_num, sbi->s_ndevs, sbi->segs_per_sec);
                return -EINVAL;
        }
 
@@ -2727,47 +2801,56 @@ static int f2fs_ioc_setproject(struct file *filp, __u32 projid)
 }
 #endif
 
-/* Transfer internal flags to xflags */
-static inline __u32 f2fs_iflags_to_xflags(unsigned long iflags)
-{
-       __u32 xflags = 0;
-
-       if (iflags & F2FS_SYNC_FL)
-               xflags |= FS_XFLAG_SYNC;
-       if (iflags & F2FS_IMMUTABLE_FL)
-               xflags |= FS_XFLAG_IMMUTABLE;
-       if (iflags & F2FS_APPEND_FL)
-               xflags |= FS_XFLAG_APPEND;
-       if (iflags & F2FS_NODUMP_FL)
-               xflags |= FS_XFLAG_NODUMP;
-       if (iflags & F2FS_NOATIME_FL)
-               xflags |= FS_XFLAG_NOATIME;
-       if (iflags & F2FS_PROJINHERIT_FL)
-               xflags |= FS_XFLAG_PROJINHERIT;
+/* FS_IOC_FSGETXATTR and FS_IOC_FSSETXATTR support */
+
+/*
+ * To make a new on-disk f2fs i_flag gettable via FS_IOC_FSGETXATTR and settable
+ * via FS_IOC_FSSETXATTR, add an entry for it to f2fs_xflags_map[], and add its
+ * FS_XFLAG_* equivalent to F2FS_SUPPORTED_XFLAGS.
+ */
+
+static const struct {
+       u32 iflag;
+       u32 xflag;
+} f2fs_xflags_map[] = {
+       { F2FS_SYNC_FL,         FS_XFLAG_SYNC },
+       { F2FS_IMMUTABLE_FL,    FS_XFLAG_IMMUTABLE },
+       { F2FS_APPEND_FL,       FS_XFLAG_APPEND },
+       { F2FS_NODUMP_FL,       FS_XFLAG_NODUMP },
+       { F2FS_NOATIME_FL,      FS_XFLAG_NOATIME },
+       { F2FS_PROJINHERIT_FL,  FS_XFLAG_PROJINHERIT },
+};
+
+#define F2FS_SUPPORTED_XFLAGS (                \
+               FS_XFLAG_SYNC |         \
+               FS_XFLAG_IMMUTABLE |    \
+               FS_XFLAG_APPEND |       \
+               FS_XFLAG_NODUMP |       \
+               FS_XFLAG_NOATIME |      \
+               FS_XFLAG_PROJINHERIT)
+
+/* Convert f2fs on-disk i_flags to FS_IOC_FS{GET,SET}XATTR flags */
+static inline u32 f2fs_iflags_to_xflags(u32 iflags)
+{
+       u32 xflags = 0;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(f2fs_xflags_map); i++)
+               if (iflags & f2fs_xflags_map[i].iflag)
+                       xflags |= f2fs_xflags_map[i].xflag;
+
        return xflags;
 }
 
-#define F2FS_SUPPORTED_FS_XFLAGS (FS_XFLAG_SYNC | FS_XFLAG_IMMUTABLE | \
-                                 FS_XFLAG_APPEND | FS_XFLAG_NODUMP | \
-                                 FS_XFLAG_NOATIME | FS_XFLAG_PROJINHERIT)
-
-/* Transfer xflags flags to internal */
-static inline unsigned long f2fs_xflags_to_iflags(__u32 xflags)
+/* Convert FS_IOC_FS{GET,SET}XATTR flags to f2fs on-disk i_flags */
+static inline u32 f2fs_xflags_to_iflags(u32 xflags)
 {
-       unsigned long iflags = 0;
+       u32 iflags = 0;
+       int i;
 
-       if (xflags & FS_XFLAG_SYNC)
-               iflags |= F2FS_SYNC_FL;
-       if (xflags & FS_XFLAG_IMMUTABLE)
-               iflags |= F2FS_IMMUTABLE_FL;
-       if (xflags & FS_XFLAG_APPEND)
-               iflags |= F2FS_APPEND_FL;
-       if (xflags & FS_XFLAG_NODUMP)
-               iflags |= F2FS_NODUMP_FL;
-       if (xflags & FS_XFLAG_NOATIME)
-               iflags |= F2FS_NOATIME_FL;
-       if (xflags & FS_XFLAG_PROJINHERIT)
-               iflags |= F2FS_PROJINHERIT_FL;
+       for (i = 0; i < ARRAY_SIZE(f2fs_xflags_map); i++)
+               if (xflags & f2fs_xflags_map[i].xflag)
+                       iflags |= f2fs_xflags_map[i].iflag;
 
        return iflags;
 }
@@ -2779,8 +2862,7 @@ static int f2fs_ioc_fsgetxattr(struct file *filp, unsigned long arg)
        struct fsxattr fa;
 
        memset(&fa, 0, sizeof(struct fsxattr));
-       fa.fsx_xflags = f2fs_iflags_to_xflags(fi->i_flags &
-                               F2FS_FL_USER_VISIBLE);
+       fa.fsx_xflags = f2fs_iflags_to_xflags(fi->i_flags);
 
        if (f2fs_sb_has_project_quota(F2FS_I_SB(inode)))
                fa.fsx_projid = (__u32)from_kprojid(&init_user_ns,
@@ -2818,9 +2900,8 @@ static int f2fs_ioctl_check_project(struct inode *inode, struct fsxattr *fa)
 static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg)
 {
        struct inode *inode = file_inode(filp);
-       struct f2fs_inode_info *fi = F2FS_I(inode);
        struct fsxattr fa;
-       unsigned int flags;
+       u32 iflags;
        int err;
 
        if (copy_from_user(&fa, (struct fsxattr __user *)arg, sizeof(fa)))
@@ -2830,11 +2911,11 @@ static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg)
        if (!inode_owner_or_capable(inode))
                return -EACCES;
 
-       if (fa.fsx_xflags & ~F2FS_SUPPORTED_FS_XFLAGS)
+       if (fa.fsx_xflags & ~F2FS_SUPPORTED_XFLAGS)
                return -EOPNOTSUPP;
 
-       flags = f2fs_xflags_to_iflags(fa.fsx_xflags);
-       if (f2fs_mask_flags(inode->i_mode, flags) != flags)
+       iflags = f2fs_xflags_to_iflags(fa.fsx_xflags);
+       if (f2fs_mask_flags(inode->i_mode, iflags) != iflags)
                return -EOPNOTSUPP;
 
        err = mnt_want_write_file(filp);
@@ -2845,9 +2926,8 @@ static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg)
        err = f2fs_ioctl_check_project(inode, &fa);
        if (err)
                goto out;
-       flags = (fi->i_flags & ~F2FS_FL_XFLAG_VISIBLE) |
-                               (flags & F2FS_FL_XFLAG_VISIBLE);
-       err = __f2fs_ioc_setflags(inode, flags);
+       err = f2fs_setflags_common(inode, iflags,
+                       f2fs_xflags_to_iflags(F2FS_SUPPORTED_XFLAGS));
        if (err)
                goto out;
 
@@ -2869,10 +2949,9 @@ int f2fs_pin_file_control(struct inode *inode, bool inc)
                                fi->i_gc_failures[GC_FAILURE_PIN] + 1);
 
        if (fi->i_gc_failures[GC_FAILURE_PIN] > sbi->gc_pin_file_threshold) {
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                       "%s: Enable GC = ino %lx after %x GC trials",
-                       __func__, inode->i_ino,
-                       fi->i_gc_failures[GC_FAILURE_PIN]);
+               f2fs_warn(sbi, "%s: Enable GC = ino %lx after %x GC trials",
+                         __func__, inode->i_ino,
+                         fi->i_gc_failures[GC_FAILURE_PIN]);
                clear_inode_flag(inode, FI_PIN_FILE);
                return -EAGAIN;
        }
@@ -2885,9 +2964,6 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
        __u32 pin;
        int ret = 0;
 
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
        if (get_user(pin, (__u32 __user *)arg))
                return -EFAULT;
 
@@ -2980,6 +3056,27 @@ static int f2fs_ioc_precache_extents(struct file *filp, unsigned long arg)
        return f2fs_precache_extents(file_inode(filp));
 }
 
+static int f2fs_ioc_resize_fs(struct file *filp, unsigned long arg)
+{
+       struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(filp));
+       __u64 block_count;
+       int ret;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (f2fs_readonly(sbi->sb))
+               return -EROFS;
+
+       if (copy_from_user(&block_count, (void __user *)arg,
+                          sizeof(block_count)))
+               return -EFAULT;
+
+       ret = f2fs_resize_fs(sbi, block_count);
+
+       return ret;
+}
+
 long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(filp)))))
@@ -3036,6 +3133,8 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                return f2fs_ioc_set_pin_file(filp, arg);
        case F2FS_IOC_PRECACHE_EXTENTS:
                return f2fs_ioc_precache_extents(filp, arg);
+       case F2FS_IOC_RESIZE_FS:
+               return f2fs_ioc_resize_fs(filp, arg);
        default:
                return -ENOTTY;
        }
@@ -3149,6 +3248,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case F2FS_IOC_GET_PIN_FILE:
        case F2FS_IOC_SET_PIN_FILE:
        case F2FS_IOC_PRECACHE_EXTENTS:
+       case F2FS_IOC_RESIZE_FS:
                break;
        default:
                return -ENOIOCTLCMD;
index 963fb45..6691f52 100644 (file)
@@ -311,10 +311,11 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
        struct sit_info *sm = SIT_I(sbi);
        struct victim_sel_policy p;
        unsigned int secno, last_victim;
-       unsigned int last_segment = MAIN_SEGS(sbi);
+       unsigned int last_segment;
        unsigned int nsearched = 0;
 
        mutex_lock(&dirty_i->seglist_lock);
+       last_segment = MAIN_SECS(sbi) * sbi->segs_per_sec;
 
        p.alloc_mode = alloc_mode;
        select_policy(sbi, gc_type, type, &p);
@@ -387,7 +388,8 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
                        goto next;
                /* Don't touch checkpointed data */
                if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED) &&
-                                       get_ckpt_valid_blocks(sbi, segno)))
+                                       get_ckpt_valid_blocks(sbi, segno) &&
+                                       p.alloc_mode != SSR))
                        goto next;
                if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap))
                        goto next;
@@ -404,7 +406,8 @@ next:
                                sm->last_victim[p.gc_mode] = last_victim + 1;
                        else
                                sm->last_victim[p.gc_mode] = segno + 1;
-                       sm->last_victim[p.gc_mode] %= MAIN_SEGS(sbi);
+                       sm->last_victim[p.gc_mode] %=
+                               (MAIN_SECS(sbi) * sbi->segs_per_sec);
                        break;
                }
        }
@@ -615,9 +618,8 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
        }
 
        if (sum->version != dni->version) {
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                               "%s: valid data with mismatched node version.",
-                               __func__);
+               f2fs_warn(sbi, "%s: valid data with mismatched node version.",
+                         __func__);
                set_sbi_flag(sbi, SBI_NEED_FSCK);
        }
 
@@ -658,7 +660,7 @@ static int ra_data_block(struct inode *inode, pgoff_t index)
                dn.data_blkaddr = ei.blk + index - ei.fofs;
                if (unlikely(!f2fs_is_valid_blkaddr(sbi, dn.data_blkaddr,
                                                DATA_GENERIC_ENHANCE_READ))) {
-                       err = -EFAULT;
+                       err = -EFSCORRUPTED;
                        goto put_page;
                }
                goto got_it;
@@ -676,7 +678,7 @@ static int ra_data_block(struct inode *inode, pgoff_t index)
        }
        if (unlikely(!f2fs_is_valid_blkaddr(sbi, dn.data_blkaddr,
                                                DATA_GENERIC_ENHANCE))) {
-               err = -EFAULT;
+               err = -EFSCORRUPTED;
                goto put_page;
        }
 got_it:
@@ -1180,9 +1182,8 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
 
                sum = page_address(sum_page);
                if (type != GET_SUM_TYPE((&sum->footer))) {
-                       f2fs_msg(sbi->sb, KERN_ERR, "Inconsistent segment (%u) "
-                               "type [%d, %d] in SSA and SIT",
-                               segno, type, GET_SUM_TYPE((&sum->footer)));
+                       f2fs_err(sbi, "Inconsistent segment (%u) type [%d, %d] in SSA and SIT",
+                                segno, type, GET_SUM_TYPE((&sum->footer)));
                        set_sbi_flag(sbi, SBI_NEED_FSCK);
                        f2fs_stop_checkpoint(sbi, false);
                        goto skip;
@@ -1360,3 +1361,176 @@ void f2fs_build_gc_manager(struct f2fs_sb_info *sbi)
                SIT_I(sbi)->last_victim[ALLOC_NEXT] =
                                GET_SEGNO(sbi, FDEV(0).end_blk) + 1;
 }
+
+static int free_segment_range(struct f2fs_sb_info *sbi, unsigned int start,
+                                                       unsigned int end)
+{
+       int type;
+       unsigned int segno, next_inuse;
+       int err = 0;
+
+       /* Move out cursegs from the target range */
+       for (type = CURSEG_HOT_DATA; type < NR_CURSEG_TYPE; type++)
+               allocate_segment_for_resize(sbi, type, start, end);
+
+       /* do GC to move out valid blocks in the range */
+       for (segno = start; segno <= end; segno += sbi->segs_per_sec) {
+               struct gc_inode_list gc_list = {
+                       .ilist = LIST_HEAD_INIT(gc_list.ilist),
+                       .iroot = RADIX_TREE_INIT(gc_list.iroot, GFP_NOFS),
+               };
+
+               mutex_lock(&sbi->gc_mutex);
+               do_garbage_collect(sbi, segno, &gc_list, FG_GC);
+               mutex_unlock(&sbi->gc_mutex);
+               put_gc_inode(&gc_list);
+
+               if (get_valid_blocks(sbi, segno, true))
+                       return -EAGAIN;
+       }
+
+       err = f2fs_sync_fs(sbi->sb, 1);
+       if (err)
+               return err;
+
+       next_inuse = find_next_inuse(FREE_I(sbi), end + 1, start);
+       if (next_inuse <= end) {
+               f2fs_err(sbi, "segno %u should be free but still inuse!",
+                        next_inuse);
+               f2fs_bug_on(sbi, 1);
+       }
+       return err;
+}
+
+static void update_sb_metadata(struct f2fs_sb_info *sbi, int secs)
+{
+       struct f2fs_super_block *raw_sb = F2FS_RAW_SUPER(sbi);
+       int section_count = le32_to_cpu(raw_sb->section_count);
+       int segment_count = le32_to_cpu(raw_sb->segment_count);
+       int segment_count_main = le32_to_cpu(raw_sb->segment_count_main);
+       long long block_count = le64_to_cpu(raw_sb->block_count);
+       int segs = secs * sbi->segs_per_sec;
+
+       raw_sb->section_count = cpu_to_le32(section_count + secs);
+       raw_sb->segment_count = cpu_to_le32(segment_count + segs);
+       raw_sb->segment_count_main = cpu_to_le32(segment_count_main + segs);
+       raw_sb->block_count = cpu_to_le64(block_count +
+                                       (long long)segs * sbi->blocks_per_seg);
+}
+
+static void update_fs_metadata(struct f2fs_sb_info *sbi, int secs)
+{
+       int segs = secs * sbi->segs_per_sec;
+       long long user_block_count =
+                               le64_to_cpu(F2FS_CKPT(sbi)->user_block_count);
+
+       SM_I(sbi)->segment_count = (int)SM_I(sbi)->segment_count + segs;
+       MAIN_SEGS(sbi) = (int)MAIN_SEGS(sbi) + segs;
+       FREE_I(sbi)->free_sections = (int)FREE_I(sbi)->free_sections + secs;
+       FREE_I(sbi)->free_segments = (int)FREE_I(sbi)->free_segments + segs;
+       F2FS_CKPT(sbi)->user_block_count = cpu_to_le64(user_block_count +
+                                       (long long)segs * sbi->blocks_per_seg);
+}
+
+int f2fs_resize_fs(struct f2fs_sb_info *sbi, __u64 block_count)
+{
+       __u64 old_block_count, shrunk_blocks;
+       unsigned int secs;
+       int gc_mode, gc_type;
+       int err = 0;
+       __u32 rem;
+
+       old_block_count = le64_to_cpu(F2FS_RAW_SUPER(sbi)->block_count);
+       if (block_count > old_block_count)
+               return -EINVAL;
+
+       /* new fs size should align to section size */
+       div_u64_rem(block_count, BLKS_PER_SEC(sbi), &rem);
+       if (rem)
+               return -EINVAL;
+
+       if (block_count == old_block_count)
+               return 0;
+
+       if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) {
+               f2fs_err(sbi, "Should run fsck to repair first.");
+               return -EFSCORRUPTED;
+       }
+
+       if (test_opt(sbi, DISABLE_CHECKPOINT)) {
+               f2fs_err(sbi, "Checkpoint should be enabled.");
+               return -EINVAL;
+       }
+
+       freeze_bdev(sbi->sb->s_bdev);
+
+       shrunk_blocks = old_block_count - block_count;
+       secs = div_u64(shrunk_blocks, BLKS_PER_SEC(sbi));
+       spin_lock(&sbi->stat_lock);
+       if (shrunk_blocks + valid_user_blocks(sbi) +
+               sbi->current_reserved_blocks + sbi->unusable_block_count +
+               F2FS_OPTION(sbi).root_reserved_blocks > sbi->user_block_count)
+               err = -ENOSPC;
+       else
+               sbi->user_block_count -= shrunk_blocks;
+       spin_unlock(&sbi->stat_lock);
+       if (err) {
+               thaw_bdev(sbi->sb->s_bdev, sbi->sb);
+               return err;
+       }
+
+       mutex_lock(&sbi->resize_mutex);
+       set_sbi_flag(sbi, SBI_IS_RESIZEFS);
+
+       mutex_lock(&DIRTY_I(sbi)->seglist_lock);
+
+       MAIN_SECS(sbi) -= secs;
+
+       for (gc_mode = 0; gc_mode < MAX_GC_POLICY; gc_mode++)
+               if (SIT_I(sbi)->last_victim[gc_mode] >=
+                                       MAIN_SECS(sbi) * sbi->segs_per_sec)
+                       SIT_I(sbi)->last_victim[gc_mode] = 0;
+
+       for (gc_type = BG_GC; gc_type <= FG_GC; gc_type++)
+               if (sbi->next_victim_seg[gc_type] >=
+                                       MAIN_SECS(sbi) * sbi->segs_per_sec)
+                       sbi->next_victim_seg[gc_type] = NULL_SEGNO;
+
+       mutex_unlock(&DIRTY_I(sbi)->seglist_lock);
+
+       err = free_segment_range(sbi, MAIN_SECS(sbi) * sbi->segs_per_sec,
+                       MAIN_SEGS(sbi) - 1);
+       if (err)
+               goto out;
+
+       update_sb_metadata(sbi, -secs);
+
+       err = f2fs_commit_super(sbi, false);
+       if (err) {
+               update_sb_metadata(sbi, secs);
+               goto out;
+       }
+
+       update_fs_metadata(sbi, -secs);
+       clear_sbi_flag(sbi, SBI_IS_RESIZEFS);
+       err = f2fs_sync_fs(sbi->sb, 1);
+       if (err) {
+               update_fs_metadata(sbi, secs);
+               update_sb_metadata(sbi, secs);
+               f2fs_commit_super(sbi, false);
+       }
+out:
+       if (err) {
+               set_sbi_flag(sbi, SBI_NEED_FSCK);
+               f2fs_err(sbi, "resize_fs failed, should run fsck to repair!");
+
+               MAIN_SECS(sbi) += secs;
+               spin_lock(&sbi->stat_lock);
+               sbi->user_block_count += shrunk_blocks;
+               spin_unlock(&sbi->stat_lock);
+       }
+       clear_sbi_flag(sbi, SBI_IS_RESIZEFS);
+       mutex_unlock(&sbi->resize_mutex);
+       thaw_bdev(sbi->sb->s_bdev, sbi->sb);
+       return err;
+}
index 404d246..3613efc 100644 (file)
@@ -140,11 +140,9 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
        if (unlikely(dn->data_blkaddr != NEW_ADDR)) {
                f2fs_put_dnode(dn);
                set_sbi_flag(fio.sbi, SBI_NEED_FSCK);
-               f2fs_msg(fio.sbi->sb, KERN_WARNING,
-                       "%s: corrupted inline inode ino=%lx, i_addr[0]:0x%x, "
-                       "run fsck to fix.",
-                       __func__, dn->inode->i_ino, dn->data_blkaddr);
-               return -EINVAL;
+               f2fs_warn(fio.sbi, "%s: corrupted inline inode ino=%lx, i_addr[0]:0x%x, run fsck to fix.",
+                         __func__, dn->inode->i_ino, dn->data_blkaddr);
+               return -EFSCORRUPTED;
        }
 
        f2fs_bug_on(F2FS_P_SB(page), PageWriteback(page));
@@ -383,11 +381,9 @@ static int f2fs_move_inline_dirents(struct inode *dir, struct page *ipage,
        if (unlikely(dn.data_blkaddr != NEW_ADDR)) {
                f2fs_put_dnode(&dn);
                set_sbi_flag(F2FS_P_SB(page), SBI_NEED_FSCK);
-               f2fs_msg(F2FS_P_SB(page)->sb, KERN_WARNING,
-                       "%s: corrupted inline inode ino=%lx, i_addr[0]:0x%x, "
-                       "run fsck to fix.",
-                       __func__, dir->i_ino, dn.data_blkaddr);
-               err = -EINVAL;
+               f2fs_warn(F2FS_P_SB(page), "%s: corrupted inline inode ino=%lx, i_addr[0]:0x%x, run fsck to fix.",
+                         __func__, dir->i_ino, dn.data_blkaddr);
+               err = -EFSCORRUPTED;
                goto out;
        }
 
index ccb0222..a33d7a8 100644 (file)
@@ -74,7 +74,7 @@ static int __written_first_block(struct f2fs_sb_info *sbi,
        if (!__is_valid_data_blkaddr(addr))
                return 1;
        if (!f2fs_is_valid_blkaddr(sbi, addr, DATA_GENERIC_ENHANCE))
-               return -EFAULT;
+               return -EFSCORRUPTED;
        return 0;
 }
 
@@ -176,9 +176,8 @@ bool f2fs_inode_chksum_verify(struct f2fs_sb_info *sbi, struct page *page)
        calculated = f2fs_inode_chksum(sbi, page);
 
        if (provided != calculated)
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                       "checksum invalid, nid = %lu, ino_of_node = %x, %x vs. %x",
-                       page->index, ino_of_node(page), provided, calculated);
+               f2fs_warn(sbi, "checksum invalid, nid = %lu, ino_of_node = %x, %x vs. %x",
+                         page->index, ino_of_node(page), provided, calculated);
 
        return provided == calculated;
 }
@@ -202,50 +201,41 @@ static bool sanity_check_inode(struct inode *inode, struct page *node_page)
        iblocks = le64_to_cpu(F2FS_INODE(node_page)->i_blocks);
        if (!iblocks) {
                set_sbi_flag(sbi, SBI_NEED_FSCK);
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                       "%s: corrupted inode i_blocks i_ino=%lx iblocks=%llu, "
-                       "run fsck to fix.",
-                       __func__, inode->i_ino, iblocks);
+               f2fs_warn(sbi, "%s: corrupted inode i_blocks i_ino=%lx iblocks=%llu, run fsck to fix.",
+                         __func__, inode->i_ino, iblocks);
                return false;
        }
 
        if (ino_of_node(node_page) != nid_of_node(node_page)) {
                set_sbi_flag(sbi, SBI_NEED_FSCK);
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                       "%s: corrupted inode footer i_ino=%lx, ino,nid: "
-                       "[%u, %u] run fsck to fix.",
-                       __func__, inode->i_ino,
-                       ino_of_node(node_page), nid_of_node(node_page));
+               f2fs_warn(sbi, "%s: corrupted inode footer i_ino=%lx, ino,nid: [%u, %u] run fsck to fix.",
+                         __func__, inode->i_ino,
+                         ino_of_node(node_page), nid_of_node(node_page));
                return false;
        }
 
        if (f2fs_sb_has_flexible_inline_xattr(sbi)
                        && !f2fs_has_extra_attr(inode)) {
                set_sbi_flag(sbi, SBI_NEED_FSCK);
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                       "%s: corrupted inode ino=%lx, run fsck to fix.",
-                       __func__, inode->i_ino);
+               f2fs_warn(sbi, "%s: corrupted inode ino=%lx, run fsck to fix.",
+                         __func__, inode->i_ino);
                return false;
        }
 
        if (f2fs_has_extra_attr(inode) &&
                        !f2fs_sb_has_extra_attr(sbi)) {
                set_sbi_flag(sbi, SBI_NEED_FSCK);
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                       "%s: inode (ino=%lx) is with extra_attr, "
-                       "but extra_attr feature is off",
-                       __func__, inode->i_ino);
+               f2fs_warn(sbi, "%s: inode (ino=%lx) is with extra_attr, but extra_attr feature is off",
+                         __func__, inode->i_ino);
                return false;
        }
 
        if (fi->i_extra_isize > F2FS_TOTAL_EXTRA_ATTR_SIZE ||
                        fi->i_extra_isize % sizeof(__le32)) {
                set_sbi_flag(sbi, SBI_NEED_FSCK);
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                       "%s: inode (ino=%lx) has corrupted i_extra_isize: %d, "
-                       "max: %zu",
-                       __func__, inode->i_ino, fi->i_extra_isize,
-                       F2FS_TOTAL_EXTRA_ATTR_SIZE);
+               f2fs_warn(sbi, "%s: inode (ino=%lx) has corrupted i_extra_isize: %d, max: %zu",
+                         __func__, inode->i_ino, fi->i_extra_isize,
+                         F2FS_TOTAL_EXTRA_ATTR_SIZE);
                return false;
        }
 
@@ -255,11 +245,9 @@ static bool sanity_check_inode(struct inode *inode, struct page *node_page)
                (!fi->i_inline_xattr_size ||
                fi->i_inline_xattr_size > MAX_INLINE_XATTR_SIZE)) {
                set_sbi_flag(sbi, SBI_NEED_FSCK);
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                       "%s: inode (ino=%lx) has corrupted "
-                       "i_inline_xattr_size: %d, max: %zu",
-                       __func__, inode->i_ino, fi->i_inline_xattr_size,
-                       MAX_INLINE_XATTR_SIZE);
+               f2fs_warn(sbi, "%s: inode (ino=%lx) has corrupted i_inline_xattr_size: %d, max: %zu",
+                         __func__, inode->i_ino, fi->i_inline_xattr_size,
+                         MAX_INLINE_XATTR_SIZE);
                return false;
        }
 
@@ -272,11 +260,9 @@ static bool sanity_check_inode(struct inode *inode, struct page *node_page)
                        !f2fs_is_valid_blkaddr(sbi, ei->blk + ei->len - 1,
                                                DATA_GENERIC_ENHANCE))) {
                        set_sbi_flag(sbi, SBI_NEED_FSCK);
-                       f2fs_msg(sbi->sb, KERN_WARNING,
-                               "%s: inode (ino=%lx) extent info [%u, %u, %u] "
-                               "is incorrect, run fsck to fix",
-                               __func__, inode->i_ino,
-                               ei->blk, ei->fofs, ei->len);
+                       f2fs_warn(sbi, "%s: inode (ino=%lx) extent info [%u, %u, %u] is incorrect, run fsck to fix",
+                                 __func__, inode->i_ino,
+                                 ei->blk, ei->fofs, ei->len);
                        return false;
                }
        }
@@ -284,19 +270,15 @@ static bool sanity_check_inode(struct inode *inode, struct page *node_page)
        if (f2fs_has_inline_data(inode) &&
                        (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode))) {
                set_sbi_flag(sbi, SBI_NEED_FSCK);
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                       "%s: inode (ino=%lx, mode=%u) should not have "
-                       "inline_data, run fsck to fix",
-                       __func__, inode->i_ino, inode->i_mode);
+               f2fs_warn(sbi, "%s: inode (ino=%lx, mode=%u) should not have inline_data, run fsck to fix",
+                         __func__, inode->i_ino, inode->i_mode);
                return false;
        }
 
        if (f2fs_has_inline_dentry(inode) && !S_ISDIR(inode->i_mode)) {
                set_sbi_flag(sbi, SBI_NEED_FSCK);
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                       "%s: inode (ino=%lx, mode=%u) should not have "
-                       "inline_dentry, run fsck to fix",
-                       __func__, inode->i_ino, inode->i_mode);
+               f2fs_warn(sbi, "%s: inode (ino=%lx, mode=%u) should not have inline_dentry, run fsck to fix",
+                         __func__, inode->i_ino, inode->i_mode);
                return false;
        }
 
@@ -343,6 +325,8 @@ static int do_read_inode(struct inode *inode)
                                        le16_to_cpu(ri->i_gc_failures);
        fi->i_xattr_nid = le32_to_cpu(ri->i_xattr_nid);
        fi->i_flags = le32_to_cpu(ri->i_flags);
+       if (S_ISREG(inode->i_mode))
+               fi->i_flags &= ~F2FS_PROJINHERIT_FL;
        fi->flags = 0;
        fi->i_advise = ri->i_advise;
        fi->i_pino = le32_to_cpu(ri->i_pino);
@@ -374,7 +358,7 @@ static int do_read_inode(struct inode *inode)
 
        if (!sanity_check_inode(inode, node_page)) {
                f2fs_put_page(node_page, 1);
-               return -EINVAL;
+               return -EFSCORRUPTED;
        }
 
        /* check data exist */
@@ -783,8 +767,7 @@ void f2fs_handle_failed_inode(struct inode *inode)
        err = f2fs_get_node_info(sbi, inode->i_ino, &ni);
        if (err) {
                set_sbi_flag(sbi, SBI_NEED_FSCK);
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                       "May loss orphan inode, run fsck to fix.");
+               f2fs_warn(sbi, "May loss orphan inode, run fsck to fix.");
                goto out;
        }
 
@@ -792,8 +775,7 @@ void f2fs_handle_failed_inode(struct inode *inode)
                err = f2fs_acquire_orphan_inode(sbi);
                if (err) {
                        set_sbi_flag(sbi, SBI_NEED_FSCK);
-                       f2fs_msg(sbi->sb, KERN_WARNING,
-                               "Too many orphan inodes, run fsck to fix.");
+                       f2fs_warn(sbi, "Too many orphan inodes, run fsck to fix.");
                } else {
                        f2fs_add_orphan_inode(inode);
                }
index 0f77f92..c5b9904 100644 (file)
@@ -385,9 +385,8 @@ static int __recover_dot_dentries(struct inode *dir, nid_t pino)
        int err = 0;
 
        if (f2fs_readonly(sbi->sb)) {
-               f2fs_msg(sbi->sb, KERN_INFO,
-                       "skip recovering inline_dots inode (ino:%lu, pino:%u) "
-                       "in readonly mountpoint", dir->i_ino, pino);
+               f2fs_info(sbi, "skip recovering inline_dots inode (ino:%lu, pino:%u) in readonly mountpoint",
+                         dir->i_ino, pino);
                return 0;
        }
 
@@ -484,9 +483,8 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
        if (IS_ENCRYPTED(dir) &&
            (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) &&
            !fscrypt_has_permitted_context(dir, inode)) {
-               f2fs_msg(inode->i_sb, KERN_WARNING,
-                        "Inconsistent encryption contexts: %lu/%lu",
-                        dir->i_ino, inode->i_ino);
+               f2fs_warn(F2FS_I_SB(inode), "Inconsistent encryption contexts: %lu/%lu",
+                         dir->i_ino, inode->i_ino);
                err = -EPERM;
                goto out_iput;
        }
index 18a038a..a18b2a8 100644 (file)
@@ -34,10 +34,9 @@ int f2fs_check_nid_range(struct f2fs_sb_info *sbi, nid_t nid)
 {
        if (unlikely(nid < F2FS_ROOT_INO(sbi) || nid >= NM_I(sbi)->max_nid)) {
                set_sbi_flag(sbi, SBI_NEED_FSCK);
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                               "%s: out-of-range nid=%x, run fsck to fix.",
-                               __func__, nid);
-               return -EINVAL;
+               f2fs_warn(sbi, "%s: out-of-range nid=%x, run fsck to fix.",
+                         __func__, nid);
+               return -EFSCORRUPTED;
        }
        return 0;
 }
@@ -1189,10 +1188,8 @@ int f2fs_remove_inode_page(struct inode *inode)
        }
 
        if (unlikely(inode->i_blocks != 0 && inode->i_blocks != 8)) {
-               f2fs_msg(F2FS_I_SB(inode)->sb, KERN_WARNING,
-                       "Inconsistent i_blocks, ino:%lu, iblocks:%llu",
-                       inode->i_ino,
-                       (unsigned long long)inode->i_blocks);
+               f2fs_warn(F2FS_I_SB(inode), "Inconsistent i_blocks, ino:%lu, iblocks:%llu",
+                         inode->i_ino, (unsigned long long)inode->i_blocks);
                set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK);
        }
 
@@ -1291,7 +1288,7 @@ static int read_node_page(struct page *page, int op_flags)
        if (PageUptodate(page)) {
                if (!f2fs_inode_chksum_verify(sbi, page)) {
                        ClearPageUptodate(page);
-                       return -EBADMSG;
+                       return -EFSBADCRC;
                }
                return LOCKED_PAGE;
        }
@@ -1375,16 +1372,15 @@ repeat:
        }
 
        if (!f2fs_inode_chksum_verify(sbi, page)) {
-               err = -EBADMSG;
+               err = -EFSBADCRC;
                goto out_err;
        }
 page_hit:
        if(unlikely(nid != nid_of_node(page))) {
-               f2fs_msg(sbi->sb, KERN_WARNING, "inconsistent node block, "
-                       "nid:%lu, node_footer[nid:%u,ino:%u,ofs:%u,cpver:%llu,blkaddr:%u]",
-                       nid, nid_of_node(page), ino_of_node(page),
-                       ofs_of_node(page), cpver_of_node(page),
-                       next_blkaddr_of_node(page));
+               f2fs_warn(sbi, "inconsistent node block, nid:%lu, node_footer[nid:%u,ino:%u,ofs:%u,cpver:%llu,blkaddr:%u]",
+                         nid, nid_of_node(page), ino_of_node(page),
+                         ofs_of_node(page), cpver_of_node(page),
+                         next_blkaddr_of_node(page));
                err = -EINVAL;
 out_err:
                ClearPageUptodate(page);
@@ -1752,9 +1748,8 @@ continue_unlock:
                        break;
        }
        if (!ret && atomic && !marked) {
-               f2fs_msg(sbi->sb, KERN_DEBUG,
-                       "Retry to write fsync mark: ino=%u, idx=%lx",
-                                       ino, last_page->index);
+               f2fs_debug(sbi, "Retry to write fsync mark: ino=%u, idx=%lx",
+                          ino, last_page->index);
                lock_page(last_page);
                f2fs_wait_on_page_writeback(last_page, NODE, true, true);
                set_page_dirty(last_page);
@@ -2304,8 +2299,7 @@ static int __f2fs_build_free_nids(struct f2fs_sb_info *sbi,
                        if (ret) {
                                up_read(&nm_i->nat_tree_lock);
                                f2fs_bug_on(sbi, !mount);
-                               f2fs_msg(sbi->sb, KERN_ERR,
-                                       "NAT is corrupt, run fsck to fix it");
+                               f2fs_err(sbi, "NAT is corrupt, run fsck to fix it");
                                return ret;
                        }
                }
@@ -2725,7 +2719,7 @@ static void __update_nat_bits(struct f2fs_sb_info *sbi, nid_t start_nid,
                i = 1;
        }
        for (; i < NAT_ENTRY_PER_BLOCK; i++) {
-               if (nat_blk->entries[i].block_addr != NULL_ADDR)
+               if (le32_to_cpu(nat_blk->entries[i].block_addr) != NULL_ADDR)
                        valid++;
        }
        if (valid == 0) {
@@ -2915,7 +2909,7 @@ static int __get_nat_bitmaps(struct f2fs_sb_info *sbi)
        nm_i->full_nat_bits = nm_i->nat_bits + 8;
        nm_i->empty_nat_bits = nm_i->full_nat_bits + nat_bits_bytes;
 
-       f2fs_msg(sbi->sb, KERN_NOTICE, "Found nat_bits in checkpoint");
+       f2fs_notice(sbi, "Found nat_bits in checkpoint");
        return 0;
 }
 
index e04f82b..783773e 100644 (file)
@@ -188,10 +188,9 @@ out:
                name = "<encrypted>";
        else
                name = raw_inode->i_name;
-       f2fs_msg(inode->i_sb, KERN_NOTICE,
-                       "%s: ino = %x, name = %s, dir = %lx, err = %d",
-                       __func__, ino_of_node(ipage), name,
-                       IS_ERR(dir) ? 0 : dir->i_ino, err);
+       f2fs_notice(F2FS_I_SB(inode), "%s: ino = %x, name = %s, dir = %lx, err = %d",
+                   __func__, ino_of_node(ipage), name,
+                   IS_ERR(dir) ? 0 : dir->i_ino, err);
        return err;
 }
 
@@ -292,9 +291,8 @@ static int recover_inode(struct inode *inode, struct page *page)
        else
                name = F2FS_INODE(page)->i_name;
 
-       f2fs_msg(inode->i_sb, KERN_NOTICE,
-               "recover_inode: ino = %x, name = %s, inline = %x",
-                       ino_of_node(page), name, raw->i_inline);
+       f2fs_notice(F2FS_I_SB(inode), "recover_inode: ino = %x, name = %s, inline = %x",
+                   ino_of_node(page), name, raw->i_inline);
        return 0;
 }
 
@@ -371,10 +369,9 @@ next:
                /* sanity check in order to detect looped node chain */
                if (++loop_cnt >= free_blocks ||
                        blkaddr == next_blkaddr_of_node(page)) {
-                       f2fs_msg(sbi->sb, KERN_NOTICE,
-                               "%s: detect looped node chain, "
-                               "blkaddr:%u, next:%u",
-                               __func__, blkaddr, next_blkaddr_of_node(page));
+                       f2fs_notice(sbi, "%s: detect looped node chain, blkaddr:%u, next:%u",
+                                   __func__, blkaddr,
+                                   next_blkaddr_of_node(page));
                        f2fs_put_page(page, 1);
                        err = -EINVAL;
                        break;
@@ -553,11 +550,10 @@ retry_dn:
        f2fs_bug_on(sbi, ni.ino != ino_of_node(page));
 
        if (ofs_of_node(dn.node_page) != ofs_of_node(page)) {
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                       "Inconsistent ofs_of_node, ino:%lu, ofs:%u, %u",
-                       inode->i_ino, ofs_of_node(dn.node_page),
-                       ofs_of_node(page));
-               err = -EFAULT;
+               f2fs_warn(sbi, "Inconsistent ofs_of_node, ino:%lu, ofs:%u, %u",
+                         inode->i_ino, ofs_of_node(dn.node_page),
+                         ofs_of_node(page));
+               err = -EFSCORRUPTED;
                goto err;
        }
 
@@ -569,13 +565,13 @@ retry_dn:
 
                if (__is_valid_data_blkaddr(src) &&
                        !f2fs_is_valid_blkaddr(sbi, src, META_POR)) {
-                       err = -EFAULT;
+                       err = -EFSCORRUPTED;
                        goto err;
                }
 
                if (__is_valid_data_blkaddr(dest) &&
                        !f2fs_is_valid_blkaddr(sbi, dest, META_POR)) {
-                       err = -EFAULT;
+                       err = -EFSCORRUPTED;
                        goto err;
                }
 
@@ -642,11 +638,9 @@ retry_prev:
 err:
        f2fs_put_dnode(&dn);
 out:
-       f2fs_msg(sbi->sb, KERN_NOTICE,
-               "recover_data: ino = %lx (i_size: %s) recovered = %d, err = %d",
-               inode->i_ino,
-               file_keep_isize(inode) ? "keep" : "recover",
-               recovered, err);
+       f2fs_notice(sbi, "recover_data: ino = %lx (i_size: %s) recovered = %d, err = %d",
+                   inode->i_ino, file_keep_isize(inode) ? "keep" : "recover",
+                   recovered, err);
        return err;
 }
 
@@ -734,8 +728,7 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
 #endif
 
        if (s_flags & SB_RDONLY) {
-               f2fs_msg(sbi->sb, KERN_INFO,
-                               "recover fsync data on readonly fs");
+               f2fs_info(sbi, "recover fsync data on readonly fs");
                sbi->sb->s_flags &= ~SB_RDONLY;
        }
 
index 8dee063..a661ac3 100644 (file)
@@ -546,9 +546,13 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
                if (test_opt(sbi, DATA_FLUSH)) {
                        struct blk_plug plug;
 
+                       mutex_lock(&sbi->flush_lock);
+
                        blk_start_plug(&plug);
                        f2fs_sync_dirty_inodes(sbi, FILE_INODE);
                        blk_finish_plug(&plug);
+
+                       mutex_unlock(&sbi->flush_lock);
                }
                f2fs_sync_fs(sbi->sb, true);
                stat_inc_bg_cp_count(sbi->stat_info);
@@ -869,11 +873,14 @@ void f2fs_dirty_to_prefree(struct f2fs_sb_info *sbi)
        mutex_unlock(&dirty_i->seglist_lock);
 }
 
-int f2fs_disable_cp_again(struct f2fs_sb_info *sbi)
+block_t f2fs_get_unusable_blocks(struct f2fs_sb_info *sbi)
 {
+       int ovp_hole_segs =
+               (overprovision_segments(sbi) - reserved_segments(sbi));
+       block_t ovp_holes = ovp_hole_segs << sbi->log_blocks_per_seg;
        struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
-       block_t ovp = overprovision_segments(sbi) << sbi->log_blocks_per_seg;
        block_t holes[2] = {0, 0};      /* DATA and NODE */
+       block_t unusable;
        struct seg_entry *se;
        unsigned int segno;
 
@@ -887,10 +894,20 @@ int f2fs_disable_cp_again(struct f2fs_sb_info *sbi)
        }
        mutex_unlock(&dirty_i->seglist_lock);
 
-       if (holes[DATA] > ovp || holes[NODE] > ovp)
+       unusable = holes[DATA] > holes[NODE] ? holes[DATA] : holes[NODE];
+       if (unusable > ovp_holes)
+               return unusable - ovp_holes;
+       return 0;
+}
+
+int f2fs_disable_cp_again(struct f2fs_sb_info *sbi, block_t unusable)
+{
+       int ovp_hole_segs =
+               (overprovision_segments(sbi) - reserved_segments(sbi));
+       if (unusable > F2FS_OPTION(sbi).unusable_cap)
                return -EAGAIN;
        if (is_sbi_flag_set(sbi, SBI_CP_DISABLED_QUICK) &&
-               dirty_segments(sbi) > overprovision_segments(sbi))
+               dirty_segments(sbi) > ovp_hole_segs)
                return -EAGAIN;
        return 0;
 }
@@ -1480,6 +1497,10 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi,
                list_for_each_entry_safe(dc, tmp, pend_list, list) {
                        f2fs_bug_on(sbi, dc->state != D_PREP);
 
+                       if (dpolicy->timeout != 0 &&
+                               f2fs_time_over(sbi, dpolicy->timeout))
+                               break;
+
                        if (dpolicy->io_aware && i < dpolicy->io_aware_gran &&
                                                !is_idle(sbi, DISCARD_TIME)) {
                                io_interrupted = true;
@@ -1740,8 +1761,7 @@ static int __f2fs_issue_discard_zone(struct f2fs_sb_info *sbi,
                devi = f2fs_target_device_index(sbi, blkstart);
                if (blkstart < FDEV(devi).start_blk ||
                    blkstart > FDEV(devi).end_blk) {
-                       f2fs_msg(sbi->sb, KERN_ERR, "Invalid block %x",
-                                blkstart);
+                       f2fs_err(sbi, "Invalid block %x", blkstart);
                        return -EIO;
                }
                blkstart -= FDEV(devi).start_blk;
@@ -1754,10 +1774,9 @@ static int __f2fs_issue_discard_zone(struct f2fs_sb_info *sbi,
 
                if (sector & (bdev_zone_sectors(bdev) - 1) ||
                                nr_sects != bdev_zone_sectors(bdev)) {
-                       f2fs_msg(sbi->sb, KERN_ERR,
-                               "(%d) %s: Unaligned zone reset attempted (block %x + %x)",
-                               devi, sbi->s_ndevs ? FDEV(devi).path: "",
-                               blkstart, blklen);
+                       f2fs_err(sbi, "(%d) %s: Unaligned zone reset attempted (block %x + %x)",
+                                devi, sbi->s_ndevs ? FDEV(devi).path : "",
+                                blkstart, blklen);
                        return -EIO;
                }
                trace_f2fs_issue_reset_zone(bdev, blkstart);
@@ -2121,15 +2140,14 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
                mir_exist = f2fs_test_and_set_bit(offset,
                                                se->cur_valid_map_mir);
                if (unlikely(exist != mir_exist)) {
-                       f2fs_msg(sbi->sb, KERN_ERR, "Inconsistent error "
-                               "when setting bitmap, blk:%u, old bit:%d",
-                               blkaddr, exist);
+                       f2fs_err(sbi, "Inconsistent error when setting bitmap, blk:%u, old bit:%d",
+                                blkaddr, exist);
                        f2fs_bug_on(sbi, 1);
                }
 #endif
                if (unlikely(exist)) {
-                       f2fs_msg(sbi->sb, KERN_ERR,
-                               "Bitmap was wrongly set, blk:%u", blkaddr);
+                       f2fs_err(sbi, "Bitmap was wrongly set, blk:%u",
+                                blkaddr);
                        f2fs_bug_on(sbi, 1);
                        se->valid_blocks--;
                        del = 0;
@@ -2150,15 +2168,14 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
                mir_exist = f2fs_test_and_clear_bit(offset,
                                                se->cur_valid_map_mir);
                if (unlikely(exist != mir_exist)) {
-                       f2fs_msg(sbi->sb, KERN_ERR, "Inconsistent error "
-                               "when clearing bitmap, blk:%u, old bit:%d",
-                               blkaddr, exist);
+                       f2fs_err(sbi, "Inconsistent error when clearing bitmap, blk:%u, old bit:%d",
+                                blkaddr, exist);
                        f2fs_bug_on(sbi, 1);
                }
 #endif
                if (unlikely(!exist)) {
-                       f2fs_msg(sbi->sb, KERN_ERR,
-                               "Bitmap was wrongly cleared, blk:%u", blkaddr);
+                       f2fs_err(sbi, "Bitmap was wrongly cleared, blk:%u",
+                                blkaddr);
                        f2fs_bug_on(sbi, 1);
                        se->valid_blocks++;
                        del = 0;
@@ -2640,6 +2657,39 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi,
        stat_inc_seg_type(sbi, curseg);
 }
 
+void allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type,
+                                       unsigned int start, unsigned int end)
+{
+       struct curseg_info *curseg = CURSEG_I(sbi, type);
+       unsigned int segno;
+
+       down_read(&SM_I(sbi)->curseg_lock);
+       mutex_lock(&curseg->curseg_mutex);
+       down_write(&SIT_I(sbi)->sentry_lock);
+
+       segno = CURSEG_I(sbi, type)->segno;
+       if (segno < start || segno > end)
+               goto unlock;
+
+       if (f2fs_need_SSR(sbi) && get_ssr_segment(sbi, type))
+               change_curseg(sbi, type);
+       else
+               new_curseg(sbi, type, true);
+
+       stat_inc_seg_type(sbi, curseg);
+
+       locate_dirty_segment(sbi, segno);
+unlock:
+       up_write(&SIT_I(sbi)->sentry_lock);
+
+       if (segno != curseg->segno)
+               f2fs_notice(sbi, "For resize: curseg of type %d: %u ==> %u",
+                           type, segno, curseg->segno);
+
+       mutex_unlock(&curseg->curseg_mutex);
+       up_read(&SM_I(sbi)->curseg_lock);
+}
+
 void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi)
 {
        struct curseg_info *curseg;
@@ -2772,9 +2822,8 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
                goto out;
 
        if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) {
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                       "Found FS corruption, run fsck to fix.");
-               return -EIO;
+               f2fs_warn(sbi, "Found FS corruption, run fsck to fix.");
+               return -EFSCORRUPTED;
        }
 
        /* start/end segment number in main_area */
@@ -3197,12 +3246,17 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio)
 
        if (!IS_DATASEG(get_seg_entry(sbi, segno)->type)) {
                set_sbi_flag(sbi, SBI_NEED_FSCK);
-               return -EFAULT;
+               f2fs_warn(sbi, "%s: incorrect segment(%u) type, run fsck to fix.",
+                         __func__, segno);
+               return -EFSCORRUPTED;
        }
 
        stat_inc_inplace_blocks(fio->sbi);
 
-       err = f2fs_submit_page_bio(fio);
+       if (fio->bio)
+               err = f2fs_merge_page_bio(fio);
+       else
+               err = f2fs_submit_page_bio(fio);
        if (!err) {
                update_device_state(fio);
                f2fs_update_iostat(fio->sbi, fio->io_type, F2FS_BLKSIZE);
@@ -3393,6 +3447,11 @@ static int read_compacted_summaries(struct f2fs_sb_info *sbi)
                seg_i = CURSEG_I(sbi, i);
                segno = le32_to_cpu(ckpt->cur_data_segno[i]);
                blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]);
+               if (blk_off > ENTRIES_IN_SUM) {
+                       f2fs_bug_on(sbi, 1);
+                       f2fs_put_page(page, 1);
+                       return -EFAULT;
+               }
                seg_i->next_segno = segno;
                reset_curseg(sbi, i, 0);
                seg_i->alloc_type = ckpt->alloc_type[i];
@@ -3530,8 +3589,11 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi)
 
        /* sanity check for summary blocks */
        if (nats_in_cursum(nat_j) > NAT_JOURNAL_ENTRIES ||
-                       sits_in_cursum(sit_j) > SIT_JOURNAL_ENTRIES)
+                       sits_in_cursum(sit_j) > SIT_JOURNAL_ENTRIES) {
+               f2fs_err(sbi, "invalid journal entries nats %u sits %u\n",
+                        nats_in_cursum(nat_j), sits_in_cursum(sit_j));
                return -EINVAL;
+       }
 
        return 0;
 }
@@ -3762,7 +3824,7 @@ void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        struct f2fs_journal *journal = curseg->journal;
        struct sit_entry_set *ses, *tmp;
        struct list_head *head = &SM_I(sbi)->sit_entry_set;
-       bool to_journal = true;
+       bool to_journal = !is_sbi_flag_set(sbi, SBI_IS_RESIZEFS);
        struct seg_entry *se;
 
        down_write(&sit_i->sentry_lock);
@@ -3781,7 +3843,8 @@ void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
         * entries, remove all entries from journal and add and account
         * them in sit entry set.
         */
-       if (!__has_cursum_space(journal, sit_i->dirty_sentries, SIT_JOURNAL))
+       if (!__has_cursum_space(journal, sit_i->dirty_sentries, SIT_JOURNAL) ||
+                                                               !to_journal)
                remove_sits_in_journal(sbi);
 
        /*
@@ -4096,11 +4159,10 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
 
                start = le32_to_cpu(segno_in_journal(journal, i));
                if (start >= MAIN_SEGS(sbi)) {
-                       f2fs_msg(sbi->sb, KERN_ERR,
-                                       "Wrong journal entry on segno %u",
-                                       start);
+                       f2fs_err(sbi, "Wrong journal entry on segno %u",
+                                start);
                        set_sbi_flag(sbi, SBI_NEED_FSCK);
-                       err = -EINVAL;
+                       err = -EFSCORRUPTED;
                        break;
                }
 
@@ -4137,11 +4199,10 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
        up_read(&curseg->journal_rwsem);
 
        if (!err && total_node_blocks != valid_node_count(sbi)) {
-               f2fs_msg(sbi->sb, KERN_ERR,
-                       "SIT is corrupted node# %u vs %u",
-                       total_node_blocks, valid_node_count(sbi));
+               f2fs_err(sbi, "SIT is corrupted node# %u vs %u",
+                        total_node_blocks, valid_node_count(sbi));
                set_sbi_flag(sbi, SBI_NEED_FSCK);
-               err = -EINVAL;
+               err = -EFSCORRUPTED;
        }
 
        return err;
@@ -4232,6 +4293,39 @@ static int build_dirty_segmap(struct f2fs_sb_info *sbi)
        return init_victim_secmap(sbi);
 }
 
+static int sanity_check_curseg(struct f2fs_sb_info *sbi)
+{
+       int i;
+
+       /*
+        * In LFS/SSR curseg, .next_blkoff should point to an unused blkaddr;
+        * In LFS curseg, all blkaddr after .next_blkoff should be unused.
+        */
+       for (i = 0; i < NO_CHECK_TYPE; i++) {
+               struct curseg_info *curseg = CURSEG_I(sbi, i);
+               struct seg_entry *se = get_seg_entry(sbi, curseg->segno);
+               unsigned int blkofs = curseg->next_blkoff;
+
+               if (f2fs_test_bit(blkofs, se->cur_valid_map))
+                       goto out;
+
+               if (curseg->alloc_type == SSR)
+                       continue;
+
+               for (blkofs += 1; blkofs < sbi->blocks_per_seg; blkofs++) {
+                       if (!f2fs_test_bit(blkofs, se->cur_valid_map))
+                               continue;
+out:
+                       f2fs_err(sbi,
+                                "Current segment's next free block offset is inconsistent with bitmap, logtype:%u, segno:%u, type:%u, next_blkoff:%u, blkofs:%u",
+                                i, curseg->segno, curseg->alloc_type,
+                                curseg->next_blkoff, blkofs);
+                       return -EFSCORRUPTED;
+               }
+       }
+       return 0;
+}
+
 /*
  * Update min, max modified time for cost-benefit GC algorithm
  */
@@ -4327,6 +4421,10 @@ int f2fs_build_segment_manager(struct f2fs_sb_info *sbi)
        if (err)
                return err;
 
+       err = sanity_check_curseg(sbi);
+       if (err)
+               return err;
+
        init_min_max_mtime(sbi);
        return 0;
 }
index 429007b..b746028 100644 (file)
 #define        START_SEGNO(segno)              \
        (SIT_BLOCK_OFFSET(segno) * SIT_ENTRY_PER_BLOCK)
 #define SIT_BLK_CNT(sbi)                       \
-       ((MAIN_SEGS(sbi) + SIT_ENTRY_PER_BLOCK - 1) / SIT_ENTRY_PER_BLOCK)
+       DIV_ROUND_UP(MAIN_SEGS(sbi), SIT_ENTRY_PER_BLOCK)
 #define f2fs_bitmap_size(nr)                   \
        (BITS_TO_LONGS(nr) * sizeof(unsigned long))
 
@@ -693,21 +693,19 @@ static inline int check_block_count(struct f2fs_sb_info *sbi,
        } while (cur_pos < sbi->blocks_per_seg);
 
        if (unlikely(GET_SIT_VBLOCKS(raw_sit) != valid_blocks)) {
-               f2fs_msg(sbi->sb, KERN_ERR,
-                               "Mismatch valid blocks %d vs. %d",
-                                       GET_SIT_VBLOCKS(raw_sit), valid_blocks);
+               f2fs_err(sbi, "Mismatch valid blocks %d vs. %d",
+                        GET_SIT_VBLOCKS(raw_sit), valid_blocks);
                set_sbi_flag(sbi, SBI_NEED_FSCK);
-               return -EINVAL;
+               return -EFSCORRUPTED;
        }
 
        /* check segment usage, and check boundary of a given segment number */
        if (unlikely(GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg
                                        || segno > TOTAL_SEGS(sbi) - 1)) {
-               f2fs_msg(sbi->sb, KERN_ERR,
-                               "Wrong valid blocks %d or segno %u",
-                                       GET_SIT_VBLOCKS(raw_sit), segno);
+               f2fs_err(sbi, "Wrong valid blocks %d or segno %u",
+                        GET_SIT_VBLOCKS(raw_sit), segno);
                set_sbi_flag(sbi, SBI_NEED_FSCK);
-               return -EINVAL;
+               return -EFSCORRUPTED;
        }
        return 0;
 }
index 6b959bb..d95a681 100644 (file)
@@ -136,7 +136,10 @@ enum {
        Opt_alloc,
        Opt_fsync,
        Opt_test_dummy_encryption,
-       Opt_checkpoint,
+       Opt_checkpoint_disable,
+       Opt_checkpoint_disable_cap,
+       Opt_checkpoint_disable_cap_perc,
+       Opt_checkpoint_enable,
        Opt_err,
 };
 
@@ -195,45 +198,52 @@ static match_table_t f2fs_tokens = {
        {Opt_alloc, "alloc_mode=%s"},
        {Opt_fsync, "fsync_mode=%s"},
        {Opt_test_dummy_encryption, "test_dummy_encryption"},
-       {Opt_checkpoint, "checkpoint=%s"},
+       {Opt_checkpoint_disable, "checkpoint=disable"},
+       {Opt_checkpoint_disable_cap, "checkpoint=disable:%u"},
+       {Opt_checkpoint_disable_cap_perc, "checkpoint=disable:%u%%"},
+       {Opt_checkpoint_enable, "checkpoint=enable"},
        {Opt_err, NULL},
 };
 
-void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...)
+void f2fs_printk(struct f2fs_sb_info *sbi, const char *fmt, ...)
 {
        struct va_format vaf;
        va_list args;
+       int level;
 
        va_start(args, fmt);
-       vaf.fmt = fmt;
+
+       level = printk_get_level(fmt);
+       vaf.fmt = printk_skip_level(fmt);
        vaf.va = &args;
-       printk("%sF2FS-fs (%s): %pV\n", level, sb->s_id, &vaf);
+       printk("%c%cF2FS-fs (%s): %pV\n",
+              KERN_SOH_ASCII, level, sbi->sb->s_id, &vaf);
+
        va_end(args);
 }
 
 static inline void limit_reserve_root(struct f2fs_sb_info *sbi)
 {
-       block_t limit = (sbi->user_block_count << 1) / 1000;
+       block_t limit = min((sbi->user_block_count << 1) / 1000,
+                       sbi->user_block_count - sbi->reserved_blocks);
 
        /* limit is 0.2% */
        if (test_opt(sbi, RESERVE_ROOT) &&
                        F2FS_OPTION(sbi).root_reserved_blocks > limit) {
                F2FS_OPTION(sbi).root_reserved_blocks = limit;
-               f2fs_msg(sbi->sb, KERN_INFO,
-                       "Reduce reserved blocks for root = %u",
-                       F2FS_OPTION(sbi).root_reserved_blocks);
+               f2fs_info(sbi, "Reduce reserved blocks for root = %u",
+                         F2FS_OPTION(sbi).root_reserved_blocks);
        }
        if (!test_opt(sbi, RESERVE_ROOT) &&
                (!uid_eq(F2FS_OPTION(sbi).s_resuid,
                                make_kuid(&init_user_ns, F2FS_DEF_RESUID)) ||
                !gid_eq(F2FS_OPTION(sbi).s_resgid,
                                make_kgid(&init_user_ns, F2FS_DEF_RESGID))))
-               f2fs_msg(sbi->sb, KERN_INFO,
-                       "Ignore s_resuid=%u, s_resgid=%u w/o reserve_root",
-                               from_kuid_munged(&init_user_ns,
-                                       F2FS_OPTION(sbi).s_resuid),
-                               from_kgid_munged(&init_user_ns,
-                                       F2FS_OPTION(sbi).s_resgid));
+               f2fs_info(sbi, "Ignore s_resuid=%u, s_resgid=%u w/o reserve_root",
+                         from_kuid_munged(&init_user_ns,
+                                          F2FS_OPTION(sbi).s_resuid),
+                         from_kgid_munged(&init_user_ns,
+                                          F2FS_OPTION(sbi).s_resgid));
 }
 
 static void init_once(void *foo)
@@ -254,35 +264,29 @@ static int f2fs_set_qf_name(struct super_block *sb, int qtype,
        int ret = -EINVAL;
 
        if (sb_any_quota_loaded(sb) && !F2FS_OPTION(sbi).s_qf_names[qtype]) {
-               f2fs_msg(sb, KERN_ERR,
-                       "Cannot change journaled "
-                       "quota options when quota turned on");
+               f2fs_err(sbi, "Cannot change journaled quota options when quota turned on");
                return -EINVAL;
        }
        if (f2fs_sb_has_quota_ino(sbi)) {
-               f2fs_msg(sb, KERN_INFO,
-                       "QUOTA feature is enabled, so ignore qf_name");
+               f2fs_info(sbi, "QUOTA feature is enabled, so ignore qf_name");
                return 0;
        }
 
        qname = match_strdup(args);
        if (!qname) {
-               f2fs_msg(sb, KERN_ERR,
-                       "Not enough memory for storing quotafile name");
+               f2fs_err(sbi, "Not enough memory for storing quotafile name");
                return -ENOMEM;
        }
        if (F2FS_OPTION(sbi).s_qf_names[qtype]) {
                if (strcmp(F2FS_OPTION(sbi).s_qf_names[qtype], qname) == 0)
                        ret = 0;
                else
-                       f2fs_msg(sb, KERN_ERR,
-                                "%s quota file already specified",
+                       f2fs_err(sbi, "%s quota file already specified",
                                 QTYPE2NAME(qtype));
                goto errout;
        }
        if (strchr(qname, '/')) {
-               f2fs_msg(sb, KERN_ERR,
-                       "quotafile must be on filesystem root");
+               f2fs_err(sbi, "quotafile must be on filesystem root");
                goto errout;
        }
        F2FS_OPTION(sbi).s_qf_names[qtype] = qname;
@@ -298,8 +302,7 @@ static int f2fs_clear_qf_name(struct super_block *sb, int qtype)
        struct f2fs_sb_info *sbi = F2FS_SB(sb);
 
        if (sb_any_quota_loaded(sb) && F2FS_OPTION(sbi).s_qf_names[qtype]) {
-               f2fs_msg(sb, KERN_ERR, "Cannot change journaled quota options"
-                       " when quota turned on");
+               f2fs_err(sbi, "Cannot change journaled quota options when quota turned on");
                return -EINVAL;
        }
        kvfree(F2FS_OPTION(sbi).s_qf_names[qtype]);
@@ -315,8 +318,7 @@ static int f2fs_check_quota_options(struct f2fs_sb_info *sbi)
         * to support legacy quotas in quota files.
         */
        if (test_opt(sbi, PRJQUOTA) && !f2fs_sb_has_project_quota(sbi)) {
-               f2fs_msg(sbi->sb, KERN_ERR, "Project quota feature not enabled. "
-                        "Cannot enable project quota enforcement.");
+               f2fs_err(sbi, "Project quota feature not enabled. Cannot enable project quota enforcement.");
                return -1;
        }
        if (F2FS_OPTION(sbi).s_qf_names[USRQUOTA] ||
@@ -336,21 +338,18 @@ static int f2fs_check_quota_options(struct f2fs_sb_info *sbi)
 
                if (test_opt(sbi, GRPQUOTA) || test_opt(sbi, USRQUOTA) ||
                                test_opt(sbi, PRJQUOTA)) {
-                       f2fs_msg(sbi->sb, KERN_ERR, "old and new quota "
-                                       "format mixing");
+                       f2fs_err(sbi, "old and new quota format mixing");
                        return -1;
                }
 
                if (!F2FS_OPTION(sbi).s_jquota_fmt) {
-                       f2fs_msg(sbi->sb, KERN_ERR, "journaled quota format "
-                                       "not specified");
+                       f2fs_err(sbi, "journaled quota format not specified");
                        return -1;
                }
        }
 
        if (f2fs_sb_has_quota_ino(sbi) && F2FS_OPTION(sbi).s_jquota_fmt) {
-               f2fs_msg(sbi->sb, KERN_INFO,
-                       "QUOTA feature is enabled, so ignore jquota_fmt");
+               f2fs_info(sbi, "QUOTA feature is enabled, so ignore jquota_fmt");
                F2FS_OPTION(sbi).s_jquota_fmt = 0;
        }
        return 0;
@@ -418,8 +417,7 @@ static int parse_options(struct super_block *sb, char *options)
                        break;
                case Opt_nodiscard:
                        if (f2fs_sb_has_blkzoned(sbi)) {
-                               f2fs_msg(sb, KERN_WARNING,
-                                       "discard is required for zoned block devices");
+                               f2fs_warn(sbi, "discard is required for zoned block devices");
                                return -EINVAL;
                        }
                        clear_opt(sbi, DISCARD);
@@ -451,20 +449,16 @@ static int parse_options(struct super_block *sb, char *options)
                        break;
 #else
                case Opt_user_xattr:
-                       f2fs_msg(sb, KERN_INFO,
-                               "user_xattr options not supported");
+                       f2fs_info(sbi, "user_xattr options not supported");
                        break;
                case Opt_nouser_xattr:
-                       f2fs_msg(sb, KERN_INFO,
-                               "nouser_xattr options not supported");
+                       f2fs_info(sbi, "nouser_xattr options not supported");
                        break;
                case Opt_inline_xattr:
-                       f2fs_msg(sb, KERN_INFO,
-                               "inline_xattr options not supported");
+                       f2fs_info(sbi, "inline_xattr options not supported");
                        break;
                case Opt_noinline_xattr:
-                       f2fs_msg(sb, KERN_INFO,
-                               "noinline_xattr options not supported");
+                       f2fs_info(sbi, "noinline_xattr options not supported");
                        break;
 #endif
 #ifdef CONFIG_F2FS_FS_POSIX_ACL
@@ -476,10 +470,10 @@ static int parse_options(struct super_block *sb, char *options)
                        break;
 #else
                case Opt_acl:
-                       f2fs_msg(sb, KERN_INFO, "acl options not supported");
+                       f2fs_info(sbi, "acl options not supported");
                        break;
                case Opt_noacl:
-                       f2fs_msg(sb, KERN_INFO, "noacl options not supported");
+                       f2fs_info(sbi, "noacl options not supported");
                        break;
 #endif
                case Opt_active_logs:
@@ -529,9 +523,8 @@ static int parse_options(struct super_block *sb, char *options)
                        if (args->from && match_int(args, &arg))
                                return -EINVAL;
                        if (test_opt(sbi, RESERVE_ROOT)) {
-                               f2fs_msg(sb, KERN_INFO,
-                                       "Preserve previous reserve_root=%u",
-                                       F2FS_OPTION(sbi).root_reserved_blocks);
+                               f2fs_info(sbi, "Preserve previous reserve_root=%u",
+                                         F2FS_OPTION(sbi).root_reserved_blocks);
                        } else {
                                F2FS_OPTION(sbi).root_reserved_blocks = arg;
                                set_opt(sbi, RESERVE_ROOT);
@@ -542,8 +535,7 @@ static int parse_options(struct super_block *sb, char *options)
                                return -EINVAL;
                        uid = make_kuid(current_user_ns(), arg);
                        if (!uid_valid(uid)) {
-                               f2fs_msg(sb, KERN_ERR,
-                                       "Invalid uid value %d", arg);
+                               f2fs_err(sbi, "Invalid uid value %d", arg);
                                return -EINVAL;
                        }
                        F2FS_OPTION(sbi).s_resuid = uid;
@@ -553,8 +545,7 @@ static int parse_options(struct super_block *sb, char *options)
                                return -EINVAL;
                        gid = make_kgid(current_user_ns(), arg);
                        if (!gid_valid(gid)) {
-                               f2fs_msg(sb, KERN_ERR,
-                                       "Invalid gid value %d", arg);
+                               f2fs_err(sbi, "Invalid gid value %d", arg);
                                return -EINVAL;
                        }
                        F2FS_OPTION(sbi).s_resgid = gid;
@@ -567,9 +558,7 @@ static int parse_options(struct super_block *sb, char *options)
                        if (strlen(name) == 8 &&
                                        !strncmp(name, "adaptive", 8)) {
                                if (f2fs_sb_has_blkzoned(sbi)) {
-                                       f2fs_msg(sb, KERN_WARNING,
-                                                "adaptive mode is not allowed with "
-                                                "zoned block device feature");
+                                       f2fs_warn(sbi, "adaptive mode is not allowed with zoned block device feature");
                                        kvfree(name);
                                        return -EINVAL;
                                }
@@ -587,9 +576,8 @@ static int parse_options(struct super_block *sb, char *options)
                        if (args->from && match_int(args, &arg))
                                return -EINVAL;
                        if (arg <= 0 || arg > __ilog2_u32(BIO_MAX_PAGES)) {
-                               f2fs_msg(sb, KERN_WARNING,
-                                       "Not support %d, larger than %d",
-                                       1 << arg, BIO_MAX_PAGES);
+                               f2fs_warn(sbi, "Not support %d, larger than %d",
+                                         1 << arg, BIO_MAX_PAGES);
                                return -EINVAL;
                        }
                        F2FS_OPTION(sbi).write_io_size_bits = arg;
@@ -610,13 +598,11 @@ static int parse_options(struct super_block *sb, char *options)
                        break;
 #else
                case Opt_fault_injection:
-                       f2fs_msg(sb, KERN_INFO,
-                               "fault_injection options not supported");
+                       f2fs_info(sbi, "fault_injection options not supported");
                        break;
 
                case Opt_fault_type:
-                       f2fs_msg(sb, KERN_INFO,
-                               "fault_type options not supported");
+                       f2fs_info(sbi, "fault_type options not supported");
                        break;
 #endif
                case Opt_lazytime:
@@ -696,8 +682,7 @@ static int parse_options(struct super_block *sb, char *options)
                case Opt_jqfmt_vfsv0:
                case Opt_jqfmt_vfsv1:
                case Opt_noquota:
-                       f2fs_msg(sb, KERN_INFO,
-                                       "quota operations not supported");
+                       f2fs_info(sbi, "quota operations not supported");
                        break;
 #endif
                case Opt_whint:
@@ -759,39 +744,44 @@ static int parse_options(struct super_block *sb, char *options)
                case Opt_test_dummy_encryption:
 #ifdef CONFIG_FS_ENCRYPTION
                        if (!f2fs_sb_has_encrypt(sbi)) {
-                               f2fs_msg(sb, KERN_ERR, "Encrypt feature is off");
+                               f2fs_err(sbi, "Encrypt feature is off");
                                return -EINVAL;
                        }
 
                        F2FS_OPTION(sbi).test_dummy_encryption = true;
-                       f2fs_msg(sb, KERN_INFO,
-                                       "Test dummy encryption mode enabled");
+                       f2fs_info(sbi, "Test dummy encryption mode enabled");
 #else
-                       f2fs_msg(sb, KERN_INFO,
-                                       "Test dummy encryption mount option ignored");
+                       f2fs_info(sbi, "Test dummy encryption mount option ignored");
 #endif
                        break;
-               case Opt_checkpoint:
-                       name = match_strdup(&args[0]);
-                       if (!name)
-                               return -ENOMEM;
-
-                       if (strlen(name) == 6 &&
-                                       !strncmp(name, "enable", 6)) {
-                               clear_opt(sbi, DISABLE_CHECKPOINT);
-                       } else if (strlen(name) == 7 &&
-                                       !strncmp(name, "disable", 7)) {
-                               set_opt(sbi, DISABLE_CHECKPOINT);
-                       } else {
-                               kvfree(name);
+               case Opt_checkpoint_disable_cap_perc:
+                       if (args->from && match_int(args, &arg))
                                return -EINVAL;
-                       }
-                       kvfree(name);
+                       if (arg < 0 || arg > 100)
+                               return -EINVAL;
+                       if (arg == 100)
+                               F2FS_OPTION(sbi).unusable_cap =
+                                       sbi->user_block_count;
+                       else
+                               F2FS_OPTION(sbi).unusable_cap =
+                                       (sbi->user_block_count / 100) * arg;
+                       set_opt(sbi, DISABLE_CHECKPOINT);
+                       break;
+               case Opt_checkpoint_disable_cap:
+                       if (args->from && match_int(args, &arg))
+                               return -EINVAL;
+                       F2FS_OPTION(sbi).unusable_cap = arg;
+                       set_opt(sbi, DISABLE_CHECKPOINT);
+                       break;
+               case Opt_checkpoint_disable:
+                       set_opt(sbi, DISABLE_CHECKPOINT);
+                       break;
+               case Opt_checkpoint_enable:
+                       clear_opt(sbi, DISABLE_CHECKPOINT);
                        break;
                default:
-                       f2fs_msg(sb, KERN_ERR,
-                               "Unrecognized mount option \"%s\" or missing value",
-                               p);
+                       f2fs_err(sbi, "Unrecognized mount option \"%s\" or missing value",
+                                p);
                        return -EINVAL;
                }
        }
@@ -800,23 +790,18 @@ static int parse_options(struct super_block *sb, char *options)
                return -EINVAL;
 #else
        if (f2fs_sb_has_quota_ino(sbi) && !f2fs_readonly(sbi->sb)) {
-               f2fs_msg(sbi->sb, KERN_INFO,
-                        "Filesystem with quota feature cannot be mounted RDWR "
-                        "without CONFIG_QUOTA");
+               f2fs_info(sbi, "Filesystem with quota feature cannot be mounted RDWR without CONFIG_QUOTA");
                return -EINVAL;
        }
        if (f2fs_sb_has_project_quota(sbi) && !f2fs_readonly(sbi->sb)) {
-               f2fs_msg(sb, KERN_ERR,
-                       "Filesystem with project quota feature cannot be "
-                       "mounted RDWR without CONFIG_QUOTA");
+               f2fs_err(sbi, "Filesystem with project quota feature cannot be mounted RDWR without CONFIG_QUOTA");
                return -EINVAL;
        }
 #endif
 
        if (F2FS_IO_SIZE_BITS(sbi) && !test_opt(sbi, LFS)) {
-               f2fs_msg(sb, KERN_ERR,
-                               "Should set mode=lfs with %uKB-sized IO",
-                               F2FS_IO_SIZE_KB(sbi));
+               f2fs_err(sbi, "Should set mode=lfs with %uKB-sized IO",
+                        F2FS_IO_SIZE_KB(sbi));
                return -EINVAL;
        }
 
@@ -825,15 +810,11 @@ static int parse_options(struct super_block *sb, char *options)
 
                if (!f2fs_sb_has_extra_attr(sbi) ||
                        !f2fs_sb_has_flexible_inline_xattr(sbi)) {
-                       f2fs_msg(sb, KERN_ERR,
-                                       "extra_attr or flexible_inline_xattr "
-                                       "feature is off");
+                       f2fs_err(sbi, "extra_attr or flexible_inline_xattr feature is off");
                        return -EINVAL;
                }
                if (!test_opt(sbi, INLINE_XATTR)) {
-                       f2fs_msg(sb, KERN_ERR,
-                                       "inline_xattr_size option should be "
-                                       "set with inline_xattr option");
+                       f2fs_err(sbi, "inline_xattr_size option should be set with inline_xattr option");
                        return -EINVAL;
                }
 
@@ -842,16 +823,14 @@ static int parse_options(struct super_block *sb, char *options)
 
                if (F2FS_OPTION(sbi).inline_xattr_size < min_size ||
                                F2FS_OPTION(sbi).inline_xattr_size > max_size) {
-                       f2fs_msg(sb, KERN_ERR,
-                               "inline xattr size is out of range: %d ~ %d",
-                               min_size, max_size);
+                       f2fs_err(sbi, "inline xattr size is out of range: %d ~ %d",
+                                min_size, max_size);
                        return -EINVAL;
                }
        }
 
        if (test_opt(sbi, DISABLE_CHECKPOINT) && test_opt(sbi, LFS)) {
-               f2fs_msg(sb, KERN_ERR,
-                               "LFS not compatible with checkpoint=disable\n");
+               f2fs_err(sbi, "LFS not compatible with checkpoint=disable\n");
                return -EINVAL;
        }
 
@@ -1313,6 +1292,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
                seq_puts(seq, ",disable_roll_forward");
        if (test_opt(sbi, DISCARD))
                seq_puts(seq, ",discard");
+       else
+               seq_puts(seq, ",nodiscard");
        if (test_opt(sbi, NOHEAP))
                seq_puts(seq, ",no_heap");
        else
@@ -1409,8 +1390,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
                seq_printf(seq, ",alloc_mode=%s", "reuse");
 
        if (test_opt(sbi, DISABLE_CHECKPOINT))
-               seq_puts(seq, ",checkpoint=disable");
-
+               seq_printf(seq, ",checkpoint=disable:%u",
+                               F2FS_OPTION(sbi).unusable_cap);
        if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_POSIX)
                seq_printf(seq, ",fsync_mode=%s", "posix");
        else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT)
@@ -1439,6 +1420,7 @@ static void default_options(struct f2fs_sb_info *sbi)
        set_opt(sbi, EXTENT_CACHE);
        set_opt(sbi, NOHEAP);
        clear_opt(sbi, DISABLE_CHECKPOINT);
+       F2FS_OPTION(sbi).unusable_cap = 0;
        sbi->sb->s_flags |= SB_LAZYTIME;
        set_opt(sbi, FLUSH_MERGE);
        set_opt(sbi, DISCARD);
@@ -1467,10 +1449,10 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
        struct cp_control cpc;
        int err = 0;
        int ret;
+       block_t unusable;
 
        if (s_flags & SB_RDONLY) {
-               f2fs_msg(sbi->sb, KERN_ERR,
-                               "checkpoint=disable on readonly fs");
+               f2fs_err(sbi, "checkpoint=disable on readonly fs");
                return -EINVAL;
        }
        sbi->sb->s_flags |= SB_ACTIVE;
@@ -1494,7 +1476,8 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
                goto restore_flag;
        }
 
-       if (f2fs_disable_cp_again(sbi)) {
+       unusable = f2fs_get_unusable_blocks(sbi);
+       if (f2fs_disable_cp_again(sbi, unusable)) {
                err = -EAGAIN;
                goto restore_flag;
        }
@@ -1507,7 +1490,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
                goto out_unlock;
 
        spin_lock(&sbi->stat_lock);
-       sbi->unusable_block_count = 0;
+       sbi->unusable_block_count = unusable;
        spin_unlock(&sbi->stat_lock);
 
 out_unlock:
@@ -1572,8 +1555,8 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
        /* recover superblocks we couldn't write due to previous RO mount */
        if (!(*flags & SB_RDONLY) && is_sbi_flag_set(sbi, SBI_NEED_SB_WRITE)) {
                err = f2fs_commit_super(sbi, false);
-               f2fs_msg(sb, KERN_INFO,
-                       "Try to recover all the superblocks, ret: %d", err);
+               f2fs_info(sbi, "Try to recover all the superblocks, ret: %d",
+                         err);
                if (!err)
                        clear_sbi_flag(sbi, SBI_NEED_SB_WRITE);
        }
@@ -1614,15 +1597,13 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
        /* disallow enable/disable extent_cache dynamically */
        if (no_extent_cache == !!test_opt(sbi, EXTENT_CACHE)) {
                err = -EINVAL;
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                               "switch extent_cache option is not allowed");
+               f2fs_warn(sbi, "switch extent_cache option is not allowed");
                goto restore_opts;
        }
 
        if ((*flags & SB_RDONLY) && test_opt(sbi, DISABLE_CHECKPOINT)) {
                err = -EINVAL;
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                       "disabling checkpoint not compatible with read-only");
+               f2fs_warn(sbi, "disabling checkpoint not compatible with read-only");
                goto restore_opts;
        }
 
@@ -1692,8 +1673,7 @@ skip:
 restore_gc:
        if (need_restart_gc) {
                if (f2fs_start_gc_thread(sbi))
-                       f2fs_msg(sbi->sb, KERN_WARNING,
-                               "background gc thread has stopped");
+                       f2fs_warn(sbi, "background gc thread has stopped");
        } else if (need_stop_gc) {
                f2fs_stop_gc_thread(sbi);
        }
@@ -1832,8 +1812,7 @@ static qsize_t *f2fs_get_reserved_space(struct inode *inode)
 static int f2fs_quota_on_mount(struct f2fs_sb_info *sbi, int type)
 {
        if (is_set_ckpt_flags(sbi, CP_QUOTA_NEED_FSCK_FLAG)) {
-               f2fs_msg(sbi->sb, KERN_ERR,
-                       "quota sysfile may be corrupted, skip loading it");
+               f2fs_err(sbi, "quota sysfile may be corrupted, skip loading it");
                return 0;
        }
 
@@ -1849,8 +1828,7 @@ int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly)
        if (f2fs_sb_has_quota_ino(sbi) && rdonly) {
                err = f2fs_enable_quotas(sbi->sb);
                if (err) {
-                       f2fs_msg(sbi->sb, KERN_ERR,
-                                       "Cannot turn on quota_ino: %d", err);
+                       f2fs_err(sbi, "Cannot turn on quota_ino: %d", err);
                        return 0;
                }
                return 1;
@@ -1863,8 +1841,8 @@ int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly)
                                enabled = 1;
                                continue;
                        }
-                       f2fs_msg(sbi->sb, KERN_ERR,
-                               "Cannot turn on quotas: %d on %d", err, i);
+                       f2fs_err(sbi, "Cannot turn on quotas: %d on %d",
+                                err, i);
                }
        }
        return enabled;
@@ -1885,8 +1863,7 @@ static int f2fs_quota_enable(struct super_block *sb, int type, int format_id,
 
        qf_inode = f2fs_iget(sb, qf_inum);
        if (IS_ERR(qf_inode)) {
-               f2fs_msg(sb, KERN_ERR,
-                       "Bad quota inode %u:%lu", type, qf_inum);
+               f2fs_err(F2FS_SB(sb), "Bad quota inode %u:%lu", type, qf_inum);
                return PTR_ERR(qf_inode);
        }
 
@@ -1899,17 +1876,17 @@ static int f2fs_quota_enable(struct super_block *sb, int type, int format_id,
 
 static int f2fs_enable_quotas(struct super_block *sb)
 {
+       struct f2fs_sb_info *sbi = F2FS_SB(sb);
        int type, err = 0;
        unsigned long qf_inum;
        bool quota_mopt[MAXQUOTAS] = {
-               test_opt(F2FS_SB(sb), USRQUOTA),
-               test_opt(F2FS_SB(sb), GRPQUOTA),
-               test_opt(F2FS_SB(sb), PRJQUOTA),
+               test_opt(sbi, USRQUOTA),
+               test_opt(sbi, GRPQUOTA),
+               test_opt(sbi, PRJQUOTA),
        };
 
        if (is_set_ckpt_flags(F2FS_SB(sb), CP_QUOTA_NEED_FSCK_FLAG)) {
-               f2fs_msg(sb, KERN_ERR,
-                       "quota file may be corrupted, skip loading it");
+               f2fs_err(sbi, "quota file may be corrupted, skip loading it");
                return 0;
        }
 
@@ -1922,10 +1899,8 @@ static int f2fs_enable_quotas(struct super_block *sb)
                                DQUOT_USAGE_ENABLED |
                                (quota_mopt[type] ? DQUOT_LIMITS_ENABLED : 0));
                        if (err) {
-                               f2fs_msg(sb, KERN_ERR,
-                                       "Failed to enable quota tracking "
-                                       "(type=%d, err=%d). Please run "
-                                       "fsck to fix.", type, err);
+                               f2fs_err(sbi, "Failed to enable quota tracking (type=%d, err=%d). Please run fsck to fix.",
+                                        type, err);
                                for (type--; type >= 0; type--)
                                        dquot_quota_off(sb, type);
                                set_sbi_flag(F2FS_SB(sb),
@@ -1944,6 +1919,18 @@ int f2fs_quota_sync(struct super_block *sb, int type)
        int cnt;
        int ret;
 
+       /*
+        * do_quotactl
+        *  f2fs_quota_sync
+        *  down_read(quota_sem)
+        *  dquot_writeback_dquots()
+        *  f2fs_dquot_commit
+        *                            block_operation
+        *                            down_read(quota_sem)
+        */
+       f2fs_lock_op(sbi);
+
+       down_read(&sbi->quota_sem);
        ret = dquot_writeback_dquots(sb, type);
        if (ret)
                goto out;
@@ -1981,6 +1968,8 @@ int f2fs_quota_sync(struct super_block *sb, int type)
 out:
        if (ret)
                set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR);
+       up_read(&sbi->quota_sem);
+       f2fs_unlock_op(sbi);
        return ret;
 }
 
@@ -2045,10 +2034,8 @@ void f2fs_quota_off_umount(struct super_block *sb)
                if (err) {
                        int ret = dquot_quota_off(sb, type);
 
-                       f2fs_msg(sb, KERN_ERR,
-                               "Fail to turn off disk quota "
-                               "(type: %d, err: %d, ret:%d), Please "
-                               "run fsck to fix it.", type, err, ret);
+                       f2fs_err(F2FS_SB(sb), "Fail to turn off disk quota (type: %d, err: %d, ret:%d), Please run fsck to fix it.",
+                                type, err, ret);
                        set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR);
                }
        }
@@ -2074,32 +2061,40 @@ static void f2fs_truncate_quota_inode_pages(struct super_block *sb)
 
 static int f2fs_dquot_commit(struct dquot *dquot)
 {
+       struct f2fs_sb_info *sbi = F2FS_SB(dquot->dq_sb);
        int ret;
 
+       down_read(&sbi->quota_sem);
        ret = dquot_commit(dquot);
        if (ret < 0)
-               set_sbi_flag(F2FS_SB(dquot->dq_sb), SBI_QUOTA_NEED_REPAIR);
+               set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
+       up_read(&sbi->quota_sem);
        return ret;
 }
 
 static int f2fs_dquot_acquire(struct dquot *dquot)
 {
+       struct f2fs_sb_info *sbi = F2FS_SB(dquot->dq_sb);
        int ret;
 
+       down_read(&sbi->quota_sem);
        ret = dquot_acquire(dquot);
        if (ret < 0)
-               set_sbi_flag(F2FS_SB(dquot->dq_sb), SBI_QUOTA_NEED_REPAIR);
-
+               set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
+       up_read(&sbi->quota_sem);
        return ret;
 }
 
 static int f2fs_dquot_release(struct dquot *dquot)
 {
+       struct f2fs_sb_info *sbi = F2FS_SB(dquot->dq_sb);
        int ret;
 
+       down_read(&sbi->quota_sem);
        ret = dquot_release(dquot);
        if (ret < 0)
-               set_sbi_flag(F2FS_SB(dquot->dq_sb), SBI_QUOTA_NEED_REPAIR);
+               set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
+       up_read(&sbi->quota_sem);
        return ret;
 }
 
@@ -2109,22 +2104,27 @@ static int f2fs_dquot_mark_dquot_dirty(struct dquot *dquot)
        struct f2fs_sb_info *sbi = F2FS_SB(sb);
        int ret;
 
+       down_read(&sbi->quota_sem);
        ret = dquot_mark_dquot_dirty(dquot);
 
        /* if we are using journalled quota */
        if (is_journalled_quota(sbi))
                set_sbi_flag(sbi, SBI_QUOTA_NEED_FLUSH);
 
+       up_read(&sbi->quota_sem);
        return ret;
 }
 
 static int f2fs_dquot_commit_info(struct super_block *sb, int type)
 {
+       struct f2fs_sb_info *sbi = F2FS_SB(sb);
        int ret;
 
+       down_read(&sbi->quota_sem);
        ret = dquot_commit_info(sb, type);
        if (ret < 0)
-               set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR);
+               set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
+       up_read(&sbi->quota_sem);
        return ret;
 }
 
@@ -2341,55 +2341,49 @@ static inline bool sanity_check_area_boundary(struct f2fs_sb_info *sbi,
                                (segment_count << log_blocks_per_seg);
 
        if (segment0_blkaddr != cp_blkaddr) {
-               f2fs_msg(sb, KERN_INFO,
-                       "Mismatch start address, segment0(%u) cp_blkaddr(%u)",
-                       segment0_blkaddr, cp_blkaddr);
+               f2fs_info(sbi, "Mismatch start address, segment0(%u) cp_blkaddr(%u)",
+                         segment0_blkaddr, cp_blkaddr);
                return true;
        }
 
        if (cp_blkaddr + (segment_count_ckpt << log_blocks_per_seg) !=
                                                        sit_blkaddr) {
-               f2fs_msg(sb, KERN_INFO,
-                       "Wrong CP boundary, start(%u) end(%u) blocks(%u)",
-                       cp_blkaddr, sit_blkaddr,
-                       segment_count_ckpt << log_blocks_per_seg);
+               f2fs_info(sbi, "Wrong CP boundary, start(%u) end(%u) blocks(%u)",
+                         cp_blkaddr, sit_blkaddr,
+                         segment_count_ckpt << log_blocks_per_seg);
                return true;
        }
 
        if (sit_blkaddr + (segment_count_sit << log_blocks_per_seg) !=
                                                        nat_blkaddr) {
-               f2fs_msg(sb, KERN_INFO,
-                       "Wrong SIT boundary, start(%u) end(%u) blocks(%u)",
-                       sit_blkaddr, nat_blkaddr,
-                       segment_count_sit << log_blocks_per_seg);
+               f2fs_info(sbi, "Wrong SIT boundary, start(%u) end(%u) blocks(%u)",
+                         sit_blkaddr, nat_blkaddr,
+                         segment_count_sit << log_blocks_per_seg);
                return true;
        }
 
        if (nat_blkaddr + (segment_count_nat << log_blocks_per_seg) !=
                                                        ssa_blkaddr) {
-               f2fs_msg(sb, KERN_INFO,
-                       "Wrong NAT boundary, start(%u) end(%u) blocks(%u)",
-                       nat_blkaddr, ssa_blkaddr,
-                       segment_count_nat << log_blocks_per_seg);
+               f2fs_info(sbi, "Wrong NAT boundary, start(%u) end(%u) blocks(%u)",
+                         nat_blkaddr, ssa_blkaddr,
+                         segment_count_nat << log_blocks_per_seg);
                return true;
        }
 
        if (ssa_blkaddr + (segment_count_ssa << log_blocks_per_seg) !=
                                                        main_blkaddr) {
-               f2fs_msg(sb, KERN_INFO,
-                       "Wrong SSA boundary, start(%u) end(%u) blocks(%u)",
-                       ssa_blkaddr, main_blkaddr,
-                       segment_count_ssa << log_blocks_per_seg);
+               f2fs_info(sbi, "Wrong SSA boundary, start(%u) end(%u) blocks(%u)",
+                         ssa_blkaddr, main_blkaddr,
+                         segment_count_ssa << log_blocks_per_seg);
                return true;
        }
 
        if (main_end_blkaddr > seg_end_blkaddr) {
-               f2fs_msg(sb, KERN_INFO,
-                       "Wrong MAIN_AREA boundary, start(%u) end(%u) block(%u)",
-                       main_blkaddr,
-                       segment0_blkaddr +
-                               (segment_count << log_blocks_per_seg),
-                       segment_count_main << log_blocks_per_seg);
+               f2fs_info(sbi, "Wrong MAIN_AREA boundary, start(%u) end(%u) block(%u)",
+                         main_blkaddr,
+                         segment0_blkaddr +
+                         (segment_count << log_blocks_per_seg),
+                         segment_count_main << log_blocks_per_seg);
                return true;
        } else if (main_end_blkaddr < seg_end_blkaddr) {
                int err = 0;
@@ -2406,12 +2400,11 @@ static inline bool sanity_check_area_boundary(struct f2fs_sb_info *sbi,
                        err = __f2fs_commit_super(bh, NULL);
                        res = err ? "failed" : "done";
                }
-               f2fs_msg(sb, KERN_INFO,
-                       "Fix alignment : %s, start(%u) end(%u) block(%u)",
-                       res, main_blkaddr,
-                       segment0_blkaddr +
-                               (segment_count << log_blocks_per_seg),
-                       segment_count_main << log_blocks_per_seg);
+               f2fs_info(sbi, "Fix alignment : %s, start(%u) end(%u) block(%u)",
+                         res, main_blkaddr,
+                         segment0_blkaddr +
+                         (segment_count << log_blocks_per_seg),
+                         segment_count_main << log_blocks_per_seg);
                if (err)
                        return true;
        }
@@ -2425,7 +2418,6 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
        block_t total_sections, blocks_per_seg;
        struct f2fs_super_block *raw_super = (struct f2fs_super_block *)
                                        (bh->b_data + F2FS_SUPER_OFFSET);
-       struct super_block *sb = sbi->sb;
        unsigned int blocksize;
        size_t crc_offset = 0;
        __u32 crc = 0;
@@ -2435,48 +2427,42 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
                crc_offset = le32_to_cpu(raw_super->checksum_offset);
                if (crc_offset !=
                        offsetof(struct f2fs_super_block, crc)) {
-                       f2fs_msg(sb, KERN_INFO,
-                               "Invalid SB checksum offset: %zu",
-                               crc_offset);
+                       f2fs_info(sbi, "Invalid SB checksum offset: %zu",
+                                 crc_offset);
                        return 1;
                }
                crc = le32_to_cpu(raw_super->crc);
                if (!f2fs_crc_valid(sbi, crc, raw_super, crc_offset)) {
-                       f2fs_msg(sb, KERN_INFO,
-                               "Invalid SB checksum value: %u", crc);
+                       f2fs_info(sbi, "Invalid SB checksum value: %u", crc);
                        return 1;
                }
        }
 
        if (F2FS_SUPER_MAGIC != le32_to_cpu(raw_super->magic)) {
-               f2fs_msg(sb, KERN_INFO,
-                       "Magic Mismatch, valid(0x%x) - read(0x%x)",
-                       F2FS_SUPER_MAGIC, le32_to_cpu(raw_super->magic));
+               f2fs_info(sbi, "Magic Mismatch, valid(0x%x) - read(0x%x)",
+                         F2FS_SUPER_MAGIC, le32_to_cpu(raw_super->magic));
                return 1;
        }
 
        /* Currently, support only 4KB page cache size */
        if (F2FS_BLKSIZE != PAGE_SIZE) {
-               f2fs_msg(sb, KERN_INFO,
-                       "Invalid page_cache_size (%lu), supports only 4KB",
-                       PAGE_SIZE);
+               f2fs_info(sbi, "Invalid page_cache_size (%lu), supports only 4KB",
+                         PAGE_SIZE);
                return 1;
        }
 
        /* Currently, support only 4KB block size */
        blocksize = 1 << le32_to_cpu(raw_super->log_blocksize);
        if (blocksize != F2FS_BLKSIZE) {
-               f2fs_msg(sb, KERN_INFO,
-                       "Invalid blocksize (%u), supports only 4KB",
-                       blocksize);
+               f2fs_info(sbi, "Invalid blocksize (%u), supports only 4KB",
+                         blocksize);
                return 1;
        }
 
        /* check log blocks per segment */
        if (le32_to_cpu(raw_super->log_blocks_per_seg) != 9) {
-               f2fs_msg(sb, KERN_INFO,
-                       "Invalid log blocks per segment (%u)",
-                       le32_to_cpu(raw_super->log_blocks_per_seg));
+               f2fs_info(sbi, "Invalid log blocks per segment (%u)",
+                         le32_to_cpu(raw_super->log_blocks_per_seg));
                return 1;
        }
 
@@ -2485,17 +2471,16 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
                                F2FS_MAX_LOG_SECTOR_SIZE ||
                le32_to_cpu(raw_super->log_sectorsize) <
                                F2FS_MIN_LOG_SECTOR_SIZE) {
-               f2fs_msg(sb, KERN_INFO, "Invalid log sectorsize (%u)",
-                       le32_to_cpu(raw_super->log_sectorsize));
+               f2fs_info(sbi, "Invalid log sectorsize (%u)",
+                         le32_to_cpu(raw_super->log_sectorsize));
                return 1;
        }
        if (le32_to_cpu(raw_super->log_sectors_per_block) +
                le32_to_cpu(raw_super->log_sectorsize) !=
                        F2FS_MAX_LOG_SECTOR_SIZE) {
-               f2fs_msg(sb, KERN_INFO,
-                       "Invalid log sectors per block(%u) log sectorsize(%u)",
-                       le32_to_cpu(raw_super->log_sectors_per_block),
-                       le32_to_cpu(raw_super->log_sectorsize));
+               f2fs_info(sbi, "Invalid log sectors per block(%u) log sectorsize(%u)",
+                         le32_to_cpu(raw_super->log_sectors_per_block),
+                         le32_to_cpu(raw_super->log_sectorsize));
                return 1;
        }
 
@@ -2509,59 +2494,51 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
 
        if (segment_count > F2FS_MAX_SEGMENT ||
                                segment_count < F2FS_MIN_SEGMENTS) {
-               f2fs_msg(sb, KERN_INFO,
-                       "Invalid segment count (%u)",
-                       segment_count);
+               f2fs_info(sbi, "Invalid segment count (%u)", segment_count);
                return 1;
        }
 
        if (total_sections > segment_count ||
                        total_sections < F2FS_MIN_SEGMENTS ||
                        segs_per_sec > segment_count || !segs_per_sec) {
-               f2fs_msg(sb, KERN_INFO,
-                       "Invalid segment/section count (%u, %u x %u)",
-                       segment_count, total_sections, segs_per_sec);
+               f2fs_info(sbi, "Invalid segment/section count (%u, %u x %u)",
+                         segment_count, total_sections, segs_per_sec);
                return 1;
        }
 
        if ((segment_count / segs_per_sec) < total_sections) {
-               f2fs_msg(sb, KERN_INFO,
-                       "Small segment_count (%u < %u * %u)",
-                       segment_count, segs_per_sec, total_sections);
+               f2fs_info(sbi, "Small segment_count (%u < %u * %u)",
+                         segment_count, segs_per_sec, total_sections);
                return 1;
        }
 
        if (segment_count > (le64_to_cpu(raw_super->block_count) >> 9)) {
-               f2fs_msg(sb, KERN_INFO,
-                       "Wrong segment_count / block_count (%u > %llu)",
-                       segment_count, le64_to_cpu(raw_super->block_count));
+               f2fs_info(sbi, "Wrong segment_count / block_count (%u > %llu)",
+                         segment_count, le64_to_cpu(raw_super->block_count));
                return 1;
        }
 
        if (secs_per_zone > total_sections || !secs_per_zone) {
-               f2fs_msg(sb, KERN_INFO,
-                       "Wrong secs_per_zone / total_sections (%u, %u)",
-                       secs_per_zone, total_sections);
+               f2fs_info(sbi, "Wrong secs_per_zone / total_sections (%u, %u)",
+                         secs_per_zone, total_sections);
                return 1;
        }
        if (le32_to_cpu(raw_super->extension_count) > F2FS_MAX_EXTENSION ||
                        raw_super->hot_ext_count > F2FS_MAX_EXTENSION ||
                        (le32_to_cpu(raw_super->extension_count) +
                        raw_super->hot_ext_count) > F2FS_MAX_EXTENSION) {
-               f2fs_msg(sb, KERN_INFO,
-                       "Corrupted extension count (%u + %u > %u)",
-                       le32_to_cpu(raw_super->extension_count),
-                       raw_super->hot_ext_count,
-                       F2FS_MAX_EXTENSION);
+               f2fs_info(sbi, "Corrupted extension count (%u + %u > %u)",
+                         le32_to_cpu(raw_super->extension_count),
+                         raw_super->hot_ext_count,
+                         F2FS_MAX_EXTENSION);
                return 1;
        }
 
        if (le32_to_cpu(raw_super->cp_payload) >
                                (blocks_per_seg - F2FS_CP_PACKS)) {
-               f2fs_msg(sb, KERN_INFO,
-                       "Insane cp_payload (%u > %u)",
-                       le32_to_cpu(raw_super->cp_payload),
-                       blocks_per_seg - F2FS_CP_PACKS);
+               f2fs_info(sbi, "Insane cp_payload (%u > %u)",
+                         le32_to_cpu(raw_super->cp_payload),
+                         blocks_per_seg - F2FS_CP_PACKS);
                return 1;
        }
 
@@ -2569,11 +2546,10 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
        if (le32_to_cpu(raw_super->node_ino) != 1 ||
                le32_to_cpu(raw_super->meta_ino) != 2 ||
                le32_to_cpu(raw_super->root_ino) != 3) {
-               f2fs_msg(sb, KERN_INFO,
-                       "Invalid Fs Meta Ino: node(%u) meta(%u) root(%u)",
-                       le32_to_cpu(raw_super->node_ino),
-                       le32_to_cpu(raw_super->meta_ino),
-                       le32_to_cpu(raw_super->root_ino));
+               f2fs_info(sbi, "Invalid Fs Meta Ino: node(%u) meta(%u) root(%u)",
+                         le32_to_cpu(raw_super->node_ino),
+                         le32_to_cpu(raw_super->meta_ino),
+                         le32_to_cpu(raw_super->root_ino));
                return 1;
        }
 
@@ -2617,8 +2593,7 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
 
        if (unlikely(fsmeta < F2FS_MIN_SEGMENTS ||
                        ovp_segments == 0 || reserved_segments == 0)) {
-               f2fs_msg(sbi->sb, KERN_ERR,
-                       "Wrong layout: check mkfs.f2fs version");
+               f2fs_err(sbi, "Wrong layout: check mkfs.f2fs version");
                return 1;
        }
 
@@ -2627,16 +2602,15 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
        log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
        if (!user_block_count || user_block_count >=
                        segment_count_main << log_blocks_per_seg) {
-               f2fs_msg(sbi->sb, KERN_ERR,
-                       "Wrong user_block_count: %u", user_block_count);
+               f2fs_err(sbi, "Wrong user_block_count: %u",
+                        user_block_count);
                return 1;
        }
 
        valid_user_blocks = le64_to_cpu(ckpt->valid_block_count);
        if (valid_user_blocks > user_block_count) {
-               f2fs_msg(sbi->sb, KERN_ERR,
-                       "Wrong valid_user_blocks: %u, user_block_count: %u",
-                       valid_user_blocks, user_block_count);
+               f2fs_err(sbi, "Wrong valid_user_blocks: %u, user_block_count: %u",
+                        valid_user_blocks, user_block_count);
                return 1;
        }
 
@@ -2644,9 +2618,8 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
        avail_node_count = sbi->total_node_count - sbi->nquota_files -
                                                F2FS_RESERVED_NODE_NUM;
        if (valid_node_count > avail_node_count) {
-               f2fs_msg(sbi->sb, KERN_ERR,
-                       "Wrong valid_node_count: %u, avail_node_count: %u",
-                       valid_node_count, avail_node_count);
+               f2fs_err(sbi, "Wrong valid_node_count: %u, avail_node_count: %u",
+                        valid_node_count, avail_node_count);
                return 1;
        }
 
@@ -2660,10 +2633,9 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
                for (j = i + 1; j < NR_CURSEG_NODE_TYPE; j++) {
                        if (le32_to_cpu(ckpt->cur_node_segno[i]) ==
                                le32_to_cpu(ckpt->cur_node_segno[j])) {
-                               f2fs_msg(sbi->sb, KERN_ERR,
-                                       "Node segment (%u, %u) has the same "
-                                       "segno: %u", i, j,
-                                       le32_to_cpu(ckpt->cur_node_segno[i]));
+                               f2fs_err(sbi, "Node segment (%u, %u) has the same segno: %u",
+                                        i, j,
+                                        le32_to_cpu(ckpt->cur_node_segno[i]));
                                return 1;
                        }
                }
@@ -2675,10 +2647,9 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
                for (j = i + 1; j < NR_CURSEG_DATA_TYPE; j++) {
                        if (le32_to_cpu(ckpt->cur_data_segno[i]) ==
                                le32_to_cpu(ckpt->cur_data_segno[j])) {
-                               f2fs_msg(sbi->sb, KERN_ERR,
-                                       "Data segment (%u, %u) has the same "
-                                       "segno: %u", i, j,
-                                       le32_to_cpu(ckpt->cur_data_segno[i]));
+                               f2fs_err(sbi, "Data segment (%u, %u) has the same segno: %u",
+                                        i, j,
+                                        le32_to_cpu(ckpt->cur_data_segno[i]));
                                return 1;
                        }
                }
@@ -2687,10 +2658,9 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
                for (j = i; j < NR_CURSEG_DATA_TYPE; j++) {
                        if (le32_to_cpu(ckpt->cur_node_segno[i]) ==
                                le32_to_cpu(ckpt->cur_data_segno[j])) {
-                               f2fs_msg(sbi->sb, KERN_ERR,
-                                       "Data segment (%u) and Data segment (%u)"
-                                       " has the same segno: %u", i, j,
-                                       le32_to_cpu(ckpt->cur_node_segno[i]));
+                               f2fs_err(sbi, "Data segment (%u) and Data segment (%u) has the same segno: %u",
+                                        i, j,
+                                        le32_to_cpu(ckpt->cur_node_segno[i]));
                                return 1;
                        }
                }
@@ -2701,9 +2671,8 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
 
        if (sit_bitmap_size != ((sit_segs / 2) << log_blocks_per_seg) / 8 ||
                nat_bitmap_size != ((nat_segs / 2) << log_blocks_per_seg) / 8) {
-               f2fs_msg(sbi->sb, KERN_ERR,
-                       "Wrong bitmap size: sit: %u, nat:%u",
-                       sit_bitmap_size, nat_bitmap_size);
+               f2fs_err(sbi, "Wrong bitmap size: sit: %u, nat:%u",
+                        sit_bitmap_size, nat_bitmap_size);
                return 1;
        }
 
@@ -2712,14 +2681,22 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
        if (cp_pack_start_sum < cp_payload + 1 ||
                cp_pack_start_sum > blocks_per_seg - 1 -
                        NR_CURSEG_TYPE) {
-               f2fs_msg(sbi->sb, KERN_ERR,
-                       "Wrong cp_pack_start_sum: %u",
-                       cp_pack_start_sum);
+               f2fs_err(sbi, "Wrong cp_pack_start_sum: %u",
+                        cp_pack_start_sum);
+               return 1;
+       }
+
+       if (__is_set_ckpt_flags(ckpt, CP_LARGE_NAT_BITMAP_FLAG) &&
+               le32_to_cpu(ckpt->checksum_offset) != CP_MIN_CHKSUM_OFFSET) {
+               f2fs_warn(sbi, "using deprecated layout of large_nat_bitmap, "
+                         "please run fsck v1.13.0 or higher to repair, chksum_offset: %u, "
+                         "fixed with patch: \"f2fs-tools: relocate chksum_offset for large_nat_bitmap feature\"",
+                         le32_to_cpu(ckpt->checksum_offset));
                return 1;
        }
 
        if (unlikely(f2fs_cp_error(sbi))) {
-               f2fs_msg(sbi->sb, KERN_ERR, "A bug case: need to run fsck");
+               f2fs_err(sbi, "A bug case: need to run fsck");
                return 1;
        }
        return 0;
@@ -2888,18 +2865,17 @@ static int read_raw_super_block(struct f2fs_sb_info *sbi,
        for (block = 0; block < 2; block++) {
                bh = sb_bread(sb, block);
                if (!bh) {
-                       f2fs_msg(sb, KERN_ERR, "Unable to read %dth superblock",
-                               block + 1);
+                       f2fs_err(sbi, "Unable to read %dth superblock",
+                                block + 1);
                        err = -EIO;
                        continue;
                }
 
                /* sanity checking of raw super */
                if (sanity_check_raw_super(sbi, bh)) {
-                       f2fs_msg(sb, KERN_ERR,
-                               "Can't find valid F2FS filesystem in %dth superblock",
-                               block + 1);
-                       err = -EINVAL;
+                       f2fs_err(sbi, "Can't find valid F2FS filesystem in %dth superblock",
+                                block + 1);
+                       err = -EFSCORRUPTED;
                        brelse(bh);
                        continue;
                }
@@ -3028,36 +3004,32 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
 #ifdef CONFIG_BLK_DEV_ZONED
                if (bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HM &&
                                !f2fs_sb_has_blkzoned(sbi)) {
-                       f2fs_msg(sbi->sb, KERN_ERR,
-                               "Zoned block device feature not enabled\n");
+                       f2fs_err(sbi, "Zoned block device feature not enabled\n");
                        return -EINVAL;
                }
                if (bdev_zoned_model(FDEV(i).bdev) != BLK_ZONED_NONE) {
                        if (init_blkz_info(sbi, i)) {
-                               f2fs_msg(sbi->sb, KERN_ERR,
-                                       "Failed to initialize F2FS blkzone information");
+                               f2fs_err(sbi, "Failed to initialize F2FS blkzone information");
                                return -EINVAL;
                        }
                        if (max_devices == 1)
                                break;
-                       f2fs_msg(sbi->sb, KERN_INFO,
-                               "Mount Device [%2d]: %20s, %8u, %8x - %8x (zone: %s)",
-                               i, FDEV(i).path,
-                               FDEV(i).total_segments,
-                               FDEV(i).start_blk, FDEV(i).end_blk,
-                               bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HA ?
-                               "Host-aware" : "Host-managed");
+                       f2fs_info(sbi, "Mount Device [%2d]: %20s, %8u, %8x - %8x (zone: %s)",
+                                 i, FDEV(i).path,
+                                 FDEV(i).total_segments,
+                                 FDEV(i).start_blk, FDEV(i).end_blk,
+                                 bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HA ?
+                                 "Host-aware" : "Host-managed");
                        continue;
                }
 #endif
-               f2fs_msg(sbi->sb, KERN_INFO,
-                       "Mount Device [%2d]: %20s, %8u, %8x - %8x",
-                               i, FDEV(i).path,
-                               FDEV(i).total_segments,
-                               FDEV(i).start_blk, FDEV(i).end_blk);
-       }
-       f2fs_msg(sbi->sb, KERN_INFO,
-                       "IO Block Size: %8d KB", F2FS_IO_SIZE_KB(sbi));
+               f2fs_info(sbi, "Mount Device [%2d]: %20s, %8u, %8x - %8x",
+                         i, FDEV(i).path,
+                         FDEV(i).total_segments,
+                         FDEV(i).start_blk, FDEV(i).end_blk);
+       }
+       f2fs_info(sbi,
+                 "IO Block Size: %8d KB", F2FS_IO_SIZE_KB(sbi));
        return 0;
 }
 
@@ -3103,7 +3075,7 @@ try_onemore:
        /* Load the checksum driver */
        sbi->s_chksum_driver = crypto_alloc_shash("crc32", 0, 0);
        if (IS_ERR(sbi->s_chksum_driver)) {
-               f2fs_msg(sb, KERN_ERR, "Cannot load crc32 driver.");
+               f2fs_err(sbi, "Cannot load crc32 driver.");
                err = PTR_ERR(sbi->s_chksum_driver);
                sbi->s_chksum_driver = NULL;
                goto free_sbi;
@@ -3111,7 +3083,7 @@ try_onemore:
 
        /* set a block size */
        if (unlikely(!sb_set_blocksize(sb, F2FS_BLKSIZE))) {
-               f2fs_msg(sb, KERN_ERR, "unable to set blocksize");
+               f2fs_err(sbi, "unable to set blocksize");
                goto free_sbi;
        }
 
@@ -3135,8 +3107,7 @@ try_onemore:
         */
 #ifndef CONFIG_BLK_DEV_ZONED
        if (f2fs_sb_has_blkzoned(sbi)) {
-               f2fs_msg(sb, KERN_ERR,
-                        "Zoned block device support is not enabled");
+               f2fs_err(sbi, "Zoned block device support is not enabled");
                err = -EOPNOTSUPP;
                goto free_sb_buf;
        }
@@ -3160,10 +3131,7 @@ try_onemore:
 
 #ifdef CONFIG_QUOTA
        sb->dq_op = &f2fs_quota_operations;
-       if (f2fs_sb_has_quota_ino(sbi))
-               sb->s_qcop = &dquot_quotactl_sysfile_ops;
-       else
-               sb->s_qcop = &f2fs_quotactl_ops;
+       sb->s_qcop = &f2fs_quotactl_ops;
        sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ;
 
        if (f2fs_sb_has_quota_ino(sbi)) {
@@ -3192,6 +3160,7 @@ try_onemore:
        mutex_init(&sbi->gc_mutex);
        mutex_init(&sbi->writepages);
        mutex_init(&sbi->cp_mutex);
+       mutex_init(&sbi->resize_mutex);
        init_rwsem(&sbi->node_write);
        init_rwsem(&sbi->node_change);
 
@@ -3227,6 +3196,7 @@ try_onemore:
        }
 
        init_rwsem(&sbi->cp_rwsem);
+       init_rwsem(&sbi->quota_sem);
        init_waitqueue_head(&sbi->cp_wait);
        init_sb_info(sbi);
 
@@ -3246,14 +3216,14 @@ try_onemore:
        /* get an inode for meta space */
        sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi));
        if (IS_ERR(sbi->meta_inode)) {
-               f2fs_msg(sb, KERN_ERR, "Failed to read F2FS meta data inode");
+               f2fs_err(sbi, "Failed to read F2FS meta data inode");
                err = PTR_ERR(sbi->meta_inode);
                goto free_io_dummy;
        }
 
        err = f2fs_get_valid_checkpoint(sbi);
        if (err) {
-               f2fs_msg(sb, KERN_ERR, "Failed to get valid F2FS checkpoint");
+               f2fs_err(sbi, "Failed to get valid F2FS checkpoint");
                goto free_meta_inode;
        }
 
@@ -3264,10 +3234,13 @@ try_onemore:
                sbi->interval_time[DISABLE_TIME] = DEF_DISABLE_QUICK_INTERVAL;
        }
 
+       if (__is_set_ckpt_flags(F2FS_CKPT(sbi), CP_FSCK_FLAG))
+               set_sbi_flag(sbi, SBI_NEED_FSCK);
+
        /* Initialize device list */
        err = f2fs_scan_devices(sbi);
        if (err) {
-               f2fs_msg(sb, KERN_ERR, "Failed to find devices");
+               f2fs_err(sbi, "Failed to find devices");
                goto free_devices;
        }
 
@@ -3287,6 +3260,7 @@ try_onemore:
                INIT_LIST_HEAD(&sbi->inode_list[i]);
                spin_lock_init(&sbi->inode_lock[i]);
        }
+       mutex_init(&sbi->flush_lock);
 
        f2fs_init_extent_cache_info(sbi);
 
@@ -3297,14 +3271,14 @@ try_onemore:
        /* setup f2fs internal modules */
        err = f2fs_build_segment_manager(sbi);
        if (err) {
-               f2fs_msg(sb, KERN_ERR,
-                       "Failed to initialize F2FS segment manager");
+               f2fs_err(sbi, "Failed to initialize F2FS segment manager (%d)",
+                        err);
                goto free_sm;
        }
        err = f2fs_build_node_manager(sbi);
        if (err) {
-               f2fs_msg(sb, KERN_ERR,
-                       "Failed to initialize F2FS node manager");
+               f2fs_err(sbi, "Failed to initialize F2FS node manager (%d)",
+                        err);
                goto free_nm;
        }
 
@@ -3329,7 +3303,7 @@ try_onemore:
        /* get an inode for node space */
        sbi->node_inode = f2fs_iget(sb, F2FS_NODE_INO(sbi));
        if (IS_ERR(sbi->node_inode)) {
-               f2fs_msg(sb, KERN_ERR, "Failed to read node inode");
+               f2fs_err(sbi, "Failed to read node inode");
                err = PTR_ERR(sbi->node_inode);
                goto free_stats;
        }
@@ -3337,7 +3311,7 @@ try_onemore:
        /* read root inode and dentry */
        root = f2fs_iget(sb, F2FS_ROOT_INO(sbi));
        if (IS_ERR(root)) {
-               f2fs_msg(sb, KERN_ERR, "Failed to read root inode");
+               f2fs_err(sbi, "Failed to read root inode");
                err = PTR_ERR(root);
                goto free_node_inode;
        }
@@ -3363,8 +3337,7 @@ try_onemore:
        if (f2fs_sb_has_quota_ino(sbi) && !f2fs_readonly(sb)) {
                err = f2fs_enable_quotas(sb);
                if (err)
-                       f2fs_msg(sb, KERN_ERR,
-                               "Cannot turn on quotas: error %d", err);
+                       f2fs_err(sbi, "Cannot turn on quotas: error %d", err);
        }
 #endif
        /* if there are nt orphan nodes free them */
@@ -3384,13 +3357,10 @@ try_onemore:
                if (f2fs_hw_is_readonly(sbi)) {
                        if (!is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) {
                                err = -EROFS;
-                               f2fs_msg(sb, KERN_ERR,
-                                       "Need to recover fsync data, but "
-                                       "write access unavailable");
+                               f2fs_err(sbi, "Need to recover fsync data, but write access unavailable");
                                goto free_meta;
                        }
-                       f2fs_msg(sbi->sb, KERN_INFO, "write access "
-                               "unavailable, skipping recovery");
+                       f2fs_info(sbi, "write access unavailable, skipping recovery");
                        goto reset_checkpoint;
                }
 
@@ -3405,8 +3375,8 @@ try_onemore:
                        if (err != -ENOMEM)
                                skip_recovery = true;
                        need_fsck = true;
-                       f2fs_msg(sb, KERN_ERR,
-                               "Cannot recover all fsync data errno=%d", err);
+                       f2fs_err(sbi, "Cannot recover all fsync data errno=%d",
+                                err);
                        goto free_meta;
                }
        } else {
@@ -3414,8 +3384,7 @@ try_onemore:
 
                if (!f2fs_readonly(sb) && err > 0) {
                        err = -EINVAL;
-                       f2fs_msg(sb, KERN_ERR,
-                               "Need to recover fsync data");
+                       f2fs_err(sbi, "Need to recover fsync data");
                        goto free_meta;
                }
        }
@@ -3446,17 +3415,16 @@ reset_checkpoint:
        /* recover broken superblock */
        if (recovery) {
                err = f2fs_commit_super(sbi, true);
-               f2fs_msg(sb, KERN_INFO,
-                       "Try to recover %dth superblock, ret: %d",
-                       sbi->valid_super_block ? 1 : 2, err);
+               f2fs_info(sbi, "Try to recover %dth superblock, ret: %d",
+                         sbi->valid_super_block ? 1 : 2, err);
        }
 
        f2fs_join_shrinker(sbi);
 
        f2fs_tuning_parameters(sbi);
 
-       f2fs_msg(sbi->sb, KERN_NOTICE, "Mounted with checkpoint version = %llx",
-                               cur_cp_version(F2FS_CKPT(sbi)));
+       f2fs_notice(sbi, "Mounted with checkpoint version = %llx",
+                   cur_cp_version(F2FS_CKPT(sbi)));
        f2fs_update_time(sbi, CP_TIME);
        f2fs_update_time(sbi, REQ_TIME);
        clear_sbi_flag(sbi, SBI_CP_DISABLED_QUICK);
index 729f46a..3aeacd0 100644 (file)
@@ -68,6 +68,20 @@ static ssize_t dirty_segments_show(struct f2fs_attr *a,
                (unsigned long long)(dirty_segments(sbi)));
 }
 
+static ssize_t unusable_show(struct f2fs_attr *a,
+               struct f2fs_sb_info *sbi, char *buf)
+{
+       block_t unusable;
+
+       if (test_opt(sbi, DISABLE_CHECKPOINT))
+               unusable = sbi->unusable_block_count;
+       else
+               unusable = f2fs_get_unusable_blocks(sbi);
+       return snprintf(buf, PAGE_SIZE, "%llu\n",
+               (unsigned long long)unusable);
+}
+
+
 static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a,
                struct f2fs_sb_info *sbi, char *buf)
 {
@@ -440,6 +454,7 @@ F2FS_GENERAL_RO_ATTR(dirty_segments);
 F2FS_GENERAL_RO_ATTR(lifetime_write_kbytes);
 F2FS_GENERAL_RO_ATTR(features);
 F2FS_GENERAL_RO_ATTR(current_reserved_blocks);
+F2FS_GENERAL_RO_ATTR(unusable);
 
 #ifdef CONFIG_FS_ENCRYPTION
 F2FS_FEATURE_RO_ATTR(encryption, FEAT_CRYPTO);
@@ -495,12 +510,14 @@ static struct attribute *f2fs_attrs[] = {
        ATTR_LIST(inject_type),
 #endif
        ATTR_LIST(dirty_segments),
+       ATTR_LIST(unusable),
        ATTR_LIST(lifetime_write_kbytes),
        ATTR_LIST(features),
        ATTR_LIST(reserved_blocks),
        ATTR_LIST(current_reserved_blocks),
        NULL,
 };
+ATTRIBUTE_GROUPS(f2fs);
 
 static struct attribute *f2fs_feat_attrs[] = {
 #ifdef CONFIG_FS_ENCRYPTION
@@ -520,6 +537,7 @@ static struct attribute *f2fs_feat_attrs[] = {
        ATTR_LIST(sb_checksum),
        NULL,
 };
+ATTRIBUTE_GROUPS(f2fs_feat);
 
 static const struct sysfs_ops f2fs_attr_ops = {
        .show   = f2fs_attr_show,
@@ -527,7 +545,7 @@ static const struct sysfs_ops f2fs_attr_ops = {
 };
 
 static struct kobj_type f2fs_sb_ktype = {
-       .default_attrs  = f2fs_attrs,
+       .default_groups = f2fs_groups,
        .sysfs_ops      = &f2fs_attr_ops,
        .release        = f2fs_sb_release,
 };
@@ -541,7 +559,7 @@ static struct kset f2fs_kset = {
 };
 
 static struct kobj_type f2fs_feat_ktype = {
-       .default_attrs  = f2fs_feat_attrs,
+       .default_groups = f2fs_feat_groups,
        .sysfs_ops      = &f2fs_attr_ops,
 };
 
@@ -566,8 +584,7 @@ static int __maybe_unused segment_info_seq_show(struct seq_file *seq,
 
                if ((i % 10) == 0)
                        seq_printf(seq, "%-10d", i);
-               seq_printf(seq, "%d|%-3u", se->type,
-                                       get_valid_blocks(sbi, i, false));
+               seq_printf(seq, "%d|%-3u", se->type, se->valid_blocks);
                if ((i % 10) == 9 || i == (total_segs - 1))
                        seq_putc(seq, '\n');
                else
@@ -593,8 +610,7 @@ static int __maybe_unused segment_bits_seq_show(struct seq_file *seq,
                struct seg_entry *se = get_seg_entry(sbi, i);
 
                seq_printf(seq, "%-10d", i);
-               seq_printf(seq, "%d|%-3u|", se->type,
-                                       get_valid_blocks(sbi, i, false));
+               seq_printf(seq, "%d|%-3u|", se->type, se->valid_blocks);
                for (j = 0; j < SIT_VBLOCK_MAP_SIZE; j++)
                        seq_printf(seq, " %.2x", se->cur_valid_map[j]);
                seq_putc(seq, '\n');
index e791741..b32c456 100644 (file)
@@ -346,7 +346,10 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
 
        *xe = __find_xattr(cur_addr, last_txattr_addr, index, len, name);
        if (!*xe) {
-               err = -EFAULT;
+               f2fs_err(F2FS_I_SB(inode), "inode (%lu) has corrupted xattr",
+                                                               inode->i_ino);
+               set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK);
+               err = -EFSCORRUPTED;
                goto out;
        }
 check:
@@ -622,7 +625,10 @@ static int __f2fs_setxattr(struct inode *inode, int index,
        /* find entry with wanted name. */
        here = __find_xattr(base_addr, last_base_addr, index, len, name);
        if (!here) {
-               error = -EFAULT;
+               f2fs_err(F2FS_I_SB(inode), "inode (%lu) has corrupted xattr",
+                                                               inode->i_ino);
+               set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK);
+               error = -EFSCORRUPTED;
                goto exit;
        }
 
index 8b0c2bf..52fa1ef 100644 (file)
@@ -136,27 +136,36 @@ static struct {
        {FS_JOURNAL_DATA_FL, GFS2_DIF_JDATA | GFS2_DIF_INHERIT_JDATA},
 };
 
+static inline u32 gfs2_gfsflags_to_fsflags(struct inode *inode, u32 gfsflags)
+{
+       int i;
+       u32 fsflags = 0;
+
+       if (S_ISDIR(inode->i_mode))
+               gfsflags &= ~GFS2_DIF_JDATA;
+       else
+               gfsflags &= ~GFS2_DIF_INHERIT_JDATA;
+
+       for (i = 0; i < ARRAY_SIZE(fsflag_gfs2flag); i++)
+               if (gfsflags & fsflag_gfs2flag[i].gfsflag)
+                       fsflags |= fsflag_gfs2flag[i].fsflag;
+       return fsflags;
+}
+
 static int gfs2_get_flags(struct file *filp, u32 __user *ptr)
 {
        struct inode *inode = file_inode(filp);
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_holder gh;
-       int i, error;
-       u32 gfsflags, fsflags = 0;
+       int error;
+       u32 fsflags;
 
        gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
        error = gfs2_glock_nq(&gh);
        if (error)
                goto out_uninit;
 
-       gfsflags = ip->i_diskflags;
-       if (S_ISDIR(inode->i_mode))
-               gfsflags &= ~GFS2_DIF_JDATA;
-       else
-               gfsflags &= ~GFS2_DIF_INHERIT_JDATA;
-       for (i = 0; i < ARRAY_SIZE(fsflag_gfs2flag); i++)
-               if (gfsflags & fsflag_gfs2flag[i].gfsflag)
-                       fsflags |= fsflag_gfs2flag[i].fsflag;
+       fsflags = gfs2_gfsflags_to_fsflags(inode, ip->i_diskflags);
 
        if (put_user(fsflags, ptr))
                error = -EFAULT;
@@ -200,9 +209,11 @@ void gfs2_set_inode_flags(struct inode *inode)
  * @filp: file pointer
  * @reqflags: The flags to set
  * @mask: Indicates which flags are valid
+ * @fsflags: The FS_* inode flags passed in
  *
  */
-static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
+static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask,
+                            const u32 fsflags)
 {
        struct inode *inode = file_inode(filp);
        struct gfs2_inode *ip = GFS2_I(inode);
@@ -210,7 +221,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
        struct buffer_head *bh;
        struct gfs2_holder gh;
        int error;
-       u32 new_flags, flags;
+       u32 new_flags, flags, oldflags;
 
        error = mnt_want_write_file(filp);
        if (error)
@@ -220,6 +231,11 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
        if (error)
                goto out_drop_write;
 
+       oldflags = gfs2_gfsflags_to_fsflags(inode, ip->i_diskflags);
+       error = vfs_ioc_setflags_prepare(inode, oldflags, fsflags);
+       if (error)
+               goto out;
+
        error = -EACCES;
        if (!inode_owner_or_capable(inode))
                goto out;
@@ -308,7 +324,7 @@ static int gfs2_set_flags(struct file *filp, u32 __user *ptr)
                mask &= ~(GFS2_DIF_TOPDIR | GFS2_DIF_INHERIT_JDATA);
        }
 
-       return do_gfs2_set_flags(filp, gfsflags, mask);
+       return do_gfs2_set_flags(filp, gfsflags, mask, fsflags);
 }
 
 static int gfs2_getlabel(struct file *filp, char __user *label)
index 2893288..dd15b8e 100644 (file)
@@ -296,6 +296,7 @@ static struct attribute *gfs2_attrs[] = {
        &gfs2_attr_demote_rq.attr,
        NULL,
 };
+ATTRIBUTE_GROUPS(gfs2);
 
 static void gfs2_sbd_release(struct kobject *kobj)
 {
@@ -306,7 +307,7 @@ static void gfs2_sbd_release(struct kobject *kobj)
 
 static struct kobj_type gfs2_ktype = {
        .release = gfs2_sbd_release,
-       .default_attrs = gfs2_attrs,
+       .default_groups = gfs2_groups,
        .sysfs_ops     = &gfs2_attr_ops,
 };
 
index 5e6502e..ce15b94 100644 (file)
@@ -57,9 +57,8 @@ static int hfsplus_ioctl_bless(struct file *file, int __user *user_flags)
        return 0;
 }
 
-static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
+static inline unsigned int hfsplus_getflags(struct inode *inode)
 {
-       struct inode *inode = file_inode(file);
        struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
        unsigned int flags = 0;
 
@@ -69,6 +68,13 @@ static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
                flags |= FS_APPEND_FL;
        if (hip->userflags & HFSPLUS_FLG_NODUMP)
                flags |= FS_NODUMP_FL;
+       return flags;
+}
+
+static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
+{
+       struct inode *inode = file_inode(file);
+       unsigned int flags = hfsplus_getflags(inode);
 
        return put_user(flags, user_flags);
 }
@@ -78,6 +84,7 @@ static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags)
        struct inode *inode = file_inode(file);
        struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
        unsigned int flags, new_fl = 0;
+       unsigned int oldflags = hfsplus_getflags(inode);
        int err = 0;
 
        err = mnt_want_write_file(file);
@@ -96,13 +103,9 @@ static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags)
 
        inode_lock(inode);
 
-       if ((flags & (FS_IMMUTABLE_FL|FS_APPEND_FL)) ||
-           inode->i_flags & (S_IMMUTABLE|S_APPEND)) {
-               if (!capable(CAP_LINUX_IMMUTABLE)) {
-                       err = -EPERM;
-                       goto out_unlock_inode;
-               }
-       }
+       err = vfs_ioc_setflags_prepare(inode, oldflags, flags);
+       if (err)
+               goto out_unlock_inode;
 
        /* don't silently ignore unsupported ext2 flags */
        if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) {
index 5f5431e..0f1e3b5 100644 (file)
@@ -2190,3 +2190,89 @@ struct timespec64 current_time(struct inode *inode)
        return timespec64_trunc(now, inode->i_sb->s_time_gran);
 }
 EXPORT_SYMBOL(current_time);
+
+/*
+ * Generic function to check FS_IOC_SETFLAGS values and reject any invalid
+ * configurations.
+ *
+ * Note: the caller should be holding i_mutex, or else be sure that they have
+ * exclusive access to the inode structure.
+ */
+int vfs_ioc_setflags_prepare(struct inode *inode, unsigned int oldflags,
+                            unsigned int flags)
+{
+       /*
+        * The IMMUTABLE and APPEND_ONLY flags can only be changed by
+        * the relevant capability.
+        *
+        * This test looks nicer. Thanks to Pauline Middelink
+        */
+       if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL) &&
+           !capable(CAP_LINUX_IMMUTABLE))
+               return -EPERM;
+
+       return 0;
+}
+EXPORT_SYMBOL(vfs_ioc_setflags_prepare);
+
+/*
+ * Generic function to check FS_IOC_FSSETXATTR values and reject any invalid
+ * configurations.
+ *
+ * Note: the caller should be holding i_mutex, or else be sure that they have
+ * exclusive access to the inode structure.
+ */
+int vfs_ioc_fssetxattr_check(struct inode *inode, const struct fsxattr *old_fa,
+                            struct fsxattr *fa)
+{
+       /*
+        * Can't modify an immutable/append-only file unless we have
+        * appropriate permission.
+        */
+       if ((old_fa->fsx_xflags ^ fa->fsx_xflags) &
+                       (FS_XFLAG_IMMUTABLE | FS_XFLAG_APPEND) &&
+           !capable(CAP_LINUX_IMMUTABLE))
+               return -EPERM;
+
+       /*
+        * Project Quota ID state is only allowed to change from within the init
+        * namespace. Enforce that restriction only if we are trying to change
+        * the quota ID state. Everything else is allowed in user namespaces.
+        */
+       if (current_user_ns() != &init_user_ns) {
+               if (old_fa->fsx_projid != fa->fsx_projid)
+                       return -EINVAL;
+               if ((old_fa->fsx_xflags ^ fa->fsx_xflags) &
+                               FS_XFLAG_PROJINHERIT)
+                       return -EINVAL;
+       }
+
+       /* Check extent size hints. */
+       if ((fa->fsx_xflags & FS_XFLAG_EXTSIZE) && !S_ISREG(inode->i_mode))
+               return -EINVAL;
+
+       if ((fa->fsx_xflags & FS_XFLAG_EXTSZINHERIT) &&
+                       !S_ISDIR(inode->i_mode))
+               return -EINVAL;
+
+       if ((fa->fsx_xflags & FS_XFLAG_COWEXTSIZE) &&
+           !S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
+               return -EINVAL;
+
+       /*
+        * It is only valid to set the DAX flag on regular files and
+        * directories on filesystems.
+        */
+       if ((fa->fsx_xflags & FS_XFLAG_DAX) &&
+           !(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
+               return -EINVAL;
+
+       /* Extent size hints of zero turn off the flags. */
+       if (fa->fsx_extsize == 0)
+               fa->fsx_xflags &= ~(FS_XFLAG_EXTSIZE | FS_XFLAG_EXTSZINHERIT);
+       if (fa->fsx_cowextsize == 0)
+               fa->fsx_xflags &= ~FS_XFLAG_COWEXTSIZE;
+
+       return 0;
+}
+EXPORT_SYMBOL(vfs_ioc_fssetxattr_check);
index 4ed4b11..3fd884b 100644 (file)
@@ -231,6 +231,7 @@ struct io_ring_ctx {
        struct task_struct      *sqo_thread;    /* if using sq thread polling */
        struct mm_struct        *sqo_mm;
        wait_queue_head_t       sqo_wait;
+       struct completion       sqo_thread_started;
 
        struct {
                /* CQ ring */
@@ -322,6 +323,7 @@ struct io_kiocb {
 
        struct io_ring_ctx      *ctx;
        struct list_head        list;
+       struct list_head        link_list;
        unsigned int            flags;
        refcount_t              refs;
 #define REQ_F_NOWAIT           1       /* must not punt to workers */
@@ -330,8 +332,10 @@ struct io_kiocb {
 #define REQ_F_SEQ_PREV         8       /* sequential with previous */
 #define REQ_F_IO_DRAIN         16      /* drain existing IO first */
 #define REQ_F_IO_DRAINED       32      /* drain done */
+#define REQ_F_LINK             64      /* linked sqes */
+#define REQ_F_FAIL_LINK                128     /* fail rest of links */
        u64                     user_data;
-       u32                     error;  /* iopoll result from callback */
+       u32                     result;
        u32                     sequence;
 
        struct work_struct      work;
@@ -403,6 +407,7 @@ static struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
        ctx->flags = p->flags;
        init_waitqueue_head(&ctx->cq_wait);
        init_completion(&ctx->ctx_done);
+       init_completion(&ctx->sqo_thread_started);
        mutex_init(&ctx->uring_lock);
        init_waitqueue_head(&ctx->wait);
        for (i = 0; i < ARRAY_SIZE(ctx->pending_async); i++) {
@@ -584,6 +589,7 @@ static struct io_kiocb *io_get_req(struct io_ring_ctx *ctx,
        req->flags = 0;
        /* one is dropped after submission, the other at completion */
        refcount_set(&req->refs, 2);
+       req->result = 0;
        return req;
 out:
        io_ring_drop_ctx_refs(ctx, 1);
@@ -599,7 +605,7 @@ static void io_free_req_many(struct io_ring_ctx *ctx, void **reqs, int *nr)
        }
 }
 
-static void io_free_req(struct io_kiocb *req)
+static void __io_free_req(struct io_kiocb *req)
 {
        if (req->file && !(req->flags & REQ_F_FIXED_FILE))
                fput(req->file);
@@ -607,6 +613,63 @@ static void io_free_req(struct io_kiocb *req)
        kmem_cache_free(req_cachep, req);
 }
 
+static void io_req_link_next(struct io_kiocb *req)
+{
+       struct io_kiocb *nxt;
+
+       /*
+        * The list should never be empty when we are called here. But could
+        * potentially happen if the chain is messed up, check to be on the
+        * safe side.
+        */
+       nxt = list_first_entry_or_null(&req->link_list, struct io_kiocb, list);
+       if (nxt) {
+               list_del(&nxt->list);
+               if (!list_empty(&req->link_list)) {
+                       INIT_LIST_HEAD(&nxt->link_list);
+                       list_splice(&req->link_list, &nxt->link_list);
+                       nxt->flags |= REQ_F_LINK;
+               }
+
+               INIT_WORK(&nxt->work, io_sq_wq_submit_work);
+               queue_work(req->ctx->sqo_wq, &nxt->work);
+       }
+}
+
+/*
+ * Called if REQ_F_LINK is set, and we fail the head request
+ */
+static void io_fail_links(struct io_kiocb *req)
+{
+       struct io_kiocb *link;
+
+       while (!list_empty(&req->link_list)) {
+               link = list_first_entry(&req->link_list, struct io_kiocb, list);
+               list_del(&link->list);
+
+               io_cqring_add_event(req->ctx, link->user_data, -ECANCELED);
+               __io_free_req(link);
+       }
+}
+
+static void io_free_req(struct io_kiocb *req)
+{
+       /*
+        * If LINK is set, we have dependent requests in this chain. If we
+        * didn't fail this request, queue the first one up, moving any other
+        * dependencies to the next request. In case of failure, fail the rest
+        * of the chain.
+        */
+       if (req->flags & REQ_F_LINK) {
+               if (req->flags & REQ_F_FAIL_LINK)
+                       io_fail_links(req);
+               else
+                       io_req_link_next(req);
+       }
+
+       __io_free_req(req);
+}
+
 static void io_put_req(struct io_kiocb *req)
 {
        if (refcount_dec_and_test(&req->refs))
@@ -628,16 +691,17 @@ static void io_iopoll_complete(struct io_ring_ctx *ctx, unsigned int *nr_events,
                req = list_first_entry(done, struct io_kiocb, list);
                list_del(&req->list);
 
-               io_cqring_fill_event(ctx, req->user_data, req->error);
+               io_cqring_fill_event(ctx, req->user_data, req->result);
                (*nr_events)++;
 
                if (refcount_dec_and_test(&req->refs)) {
                        /* If we're not using fixed files, we have to pair the
                         * completion part with the file put. Use regular
                         * completions for those, only batch free for fixed
-                        * file.
+                        * file and non-linked commands.
                         */
-                       if (req->flags & REQ_F_FIXED_FILE) {
+                       if ((req->flags & (REQ_F_FIXED_FILE|REQ_F_LINK)) ==
+                           REQ_F_FIXED_FILE) {
                                reqs[to_free++] = req;
                                if (to_free == ARRAY_SIZE(reqs))
                                        io_free_req_many(ctx, reqs, &to_free);
@@ -776,6 +840,8 @@ static void io_complete_rw(struct kiocb *kiocb, long res, long res2)
 
        kiocb_end_write(kiocb);
 
+       if ((req->flags & REQ_F_LINK) && res != req->result)
+               req->flags |= REQ_F_FAIL_LINK;
        io_cqring_add_event(req->ctx, req->user_data, res);
        io_put_req(req);
 }
@@ -786,7 +852,9 @@ static void io_complete_rw_iopoll(struct kiocb *kiocb, long res, long res2)
 
        kiocb_end_write(kiocb);
 
-       req->error = res;
+       if ((req->flags & REQ_F_LINK) && res != req->result)
+               req->flags |= REQ_F_FAIL_LINK;
+       req->result = res;
        if (res != -EAGAIN)
                req->flags |= REQ_F_IOPOLL_COMPLETED;
 }
@@ -929,7 +997,6 @@ static int io_prep_rw(struct io_kiocb *req, const struct sqe_submit *s,
                    !kiocb->ki_filp->f_op->iopoll)
                        return -EOPNOTSUPP;
 
-               req->error = 0;
                kiocb->ki_flags |= IOCB_HIPRI;
                kiocb->ki_complete = io_complete_rw_iopoll;
        } else {
@@ -1001,9 +1068,9 @@ static int io_import_fixed(struct io_ring_ctx *ctx, int rw,
        return 0;
 }
 
-static int io_import_iovec(struct io_ring_ctx *ctx, int rw,
-                          const struct sqe_submit *s, struct iovec **iovec,
-                          struct iov_iter *iter)
+static ssize_t io_import_iovec(struct io_ring_ctx *ctx, int rw,
+                              const struct sqe_submit *s, struct iovec **iovec,
+                              struct iov_iter *iter)
 {
        const struct io_uring_sqe *sqe = s->sqe;
        void __user *buf = u64_to_user_ptr(READ_ONCE(sqe->addr));
@@ -1021,7 +1088,7 @@ static int io_import_iovec(struct io_ring_ctx *ctx, int rw,
        opcode = READ_ONCE(sqe->opcode);
        if (opcode == IORING_OP_READ_FIXED ||
            opcode == IORING_OP_WRITE_FIXED) {
-               int ret = io_import_fixed(ctx, rw, sqe, iter);
+               ssize_t ret = io_import_fixed(ctx, rw, sqe, iter);
                *iovec = NULL;
                return ret;
        }
@@ -1087,7 +1154,7 @@ static int io_read(struct io_kiocb *req, const struct sqe_submit *s,
        struct iov_iter iter;
        struct file *file;
        size_t iov_count;
-       int ret;
+       ssize_t read_size, ret;
 
        ret = io_prep_rw(req, s, force_nonblock);
        if (ret)
@@ -1100,16 +1167,30 @@ static int io_read(struct io_kiocb *req, const struct sqe_submit *s,
                return -EINVAL;
 
        ret = io_import_iovec(req->ctx, READ, s, &iovec, &iter);
-       if (ret)
+       if (ret < 0)
                return ret;
 
+       read_size = ret;
+       if (req->flags & REQ_F_LINK)
+               req->result = read_size;
+
        iov_count = iov_iter_count(&iter);
        ret = rw_verify_area(READ, file, &kiocb->ki_pos, iov_count);
        if (!ret) {
                ssize_t ret2;
 
-               /* Catch -EAGAIN return for forced non-blocking submission */
                ret2 = call_read_iter(file, kiocb, &iter);
+               /*
+                * In case of a short read, punt to async. This can happen
+                * if we have data partially cached. Alternatively we can
+                * return the short read, in which case the application will
+                * need to issue another SQE and wait for it. That SQE will
+                * need async punt anyway, so it's more efficient to do it
+                * here.
+                */
+               if (force_nonblock && ret2 > 0 && ret2 < read_size)
+                       ret2 = -EAGAIN;
+               /* Catch -EAGAIN return for forced non-blocking submission */
                if (!force_nonblock || ret2 != -EAGAIN) {
                        io_rw_done(kiocb, ret2);
                } else {
@@ -1134,7 +1215,7 @@ static int io_write(struct io_kiocb *req, const struct sqe_submit *s,
        struct iov_iter iter;
        struct file *file;
        size_t iov_count;
-       int ret;
+       ssize_t ret;
 
        ret = io_prep_rw(req, s, force_nonblock);
        if (ret)
@@ -1147,9 +1228,12 @@ static int io_write(struct io_kiocb *req, const struct sqe_submit *s,
                return -EINVAL;
 
        ret = io_import_iovec(req->ctx, WRITE, s, &iovec, &iter);
-       if (ret)
+       if (ret < 0)
                return ret;
 
+       if (req->flags & REQ_F_LINK)
+               req->result = ret;
+
        iov_count = iov_iter_count(&iter);
 
        ret = -EAGAIN;
@@ -1253,6 +1337,8 @@ static int io_fsync(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                                end > 0 ? end : LLONG_MAX,
                                fsync_flags & IORING_FSYNC_DATASYNC);
 
+       if (ret < 0 && (req->flags & REQ_F_LINK))
+               req->flags |= REQ_F_FAIL_LINK;
        io_cqring_add_event(req->ctx, sqe->user_data, ret);
        io_put_req(req);
        return 0;
@@ -1297,11 +1383,70 @@ static int io_sync_file_range(struct io_kiocb *req,
 
        ret = sync_file_range(req->rw.ki_filp, sqe_off, sqe_len, flags);
 
+       if (ret < 0 && (req->flags & REQ_F_LINK))
+               req->flags |= REQ_F_FAIL_LINK;
        io_cqring_add_event(req->ctx, sqe->user_data, ret);
        io_put_req(req);
        return 0;
 }
 
+#if defined(CONFIG_NET)
+static int io_send_recvmsg(struct io_kiocb *req, const struct io_uring_sqe *sqe,
+                          bool force_nonblock,
+                  long (*fn)(struct socket *, struct user_msghdr __user *,
+                               unsigned int))
+{
+       struct socket *sock;
+       int ret;
+
+       if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
+               return -EINVAL;
+
+       sock = sock_from_file(req->file, &ret);
+       if (sock) {
+               struct user_msghdr __user *msg;
+               unsigned flags;
+
+               flags = READ_ONCE(sqe->msg_flags);
+               if (flags & MSG_DONTWAIT)
+                       req->flags |= REQ_F_NOWAIT;
+               else if (force_nonblock)
+                       flags |= MSG_DONTWAIT;
+
+               msg = (struct user_msghdr __user *) (unsigned long)
+                       READ_ONCE(sqe->addr);
+
+               ret = fn(sock, msg, flags);
+               if (force_nonblock && ret == -EAGAIN)
+                       return ret;
+       }
+
+       io_cqring_add_event(req->ctx, sqe->user_data, ret);
+       io_put_req(req);
+       return 0;
+}
+#endif
+
+static int io_sendmsg(struct io_kiocb *req, const struct io_uring_sqe *sqe,
+                     bool force_nonblock)
+{
+#if defined(CONFIG_NET)
+       return io_send_recvmsg(req, sqe, force_nonblock, __sys_sendmsg_sock);
+#else
+       return -EOPNOTSUPP;
+#endif
+}
+
+static int io_recvmsg(struct io_kiocb *req, const struct io_uring_sqe *sqe,
+                     bool force_nonblock)
+{
+#if defined(CONFIG_NET)
+       return io_send_recvmsg(req, sqe, force_nonblock, __sys_recvmsg_sock);
+#else
+       return -EOPNOTSUPP;
+#endif
+}
+
 static void io_poll_remove_one(struct io_kiocb *req)
 {
        struct io_poll_iocb *poll = &req->poll;
@@ -1549,9 +1694,10 @@ static int __io_submit_sqe(struct io_ring_ctx *ctx, struct io_kiocb *req,
 {
        int ret, opcode;
 
+       req->user_data = READ_ONCE(s->sqe->user_data);
+
        if (unlikely(s->index >= ctx->sq_entries))
                return -EINVAL;
-       req->user_data = READ_ONCE(s->sqe->user_data);
 
        opcode = READ_ONCE(s->sqe->opcode);
        switch (opcode) {
@@ -1586,6 +1732,12 @@ static int __io_submit_sqe(struct io_ring_ctx *ctx, struct io_kiocb *req,
        case IORING_OP_SYNC_FILE_RANGE:
                ret = io_sync_file_range(req, s->sqe, force_nonblock);
                break;
+       case IORING_OP_SENDMSG:
+               ret = io_sendmsg(req, s->sqe, force_nonblock);
+               break;
+       case IORING_OP_RECVMSG:
+               ret = io_recvmsg(req, s->sqe, force_nonblock);
+               break;
        default:
                ret = -EINVAL;
                break;
@@ -1595,7 +1747,7 @@ static int __io_submit_sqe(struct io_ring_ctx *ctx, struct io_kiocb *req,
                return ret;
 
        if (ctx->flags & IORING_SETUP_IOPOLL) {
-               if (req->error == -EAGAIN)
+               if (req->result == -EAGAIN)
                        return -EAGAIN;
 
                /* workqueue context doesn't hold uring_lock, grab it now */
@@ -1819,31 +1971,11 @@ static int io_req_set_file(struct io_ring_ctx *ctx, const struct sqe_submit *s,
        return 0;
 }
 
-static int io_submit_sqe(struct io_ring_ctx *ctx, struct sqe_submit *s,
-                        struct io_submit_state *state)
+static int io_queue_sqe(struct io_ring_ctx *ctx, struct io_kiocb *req,
+                       struct sqe_submit *s)
 {
-       struct io_kiocb *req;
        int ret;
 
-       /* enforce forwards compatibility on users */
-       if (unlikely(s->sqe->flags & ~(IOSQE_FIXED_FILE | IOSQE_IO_DRAIN)))
-               return -EINVAL;
-
-       req = io_get_req(ctx, state);
-       if (unlikely(!req))
-               return -EAGAIN;
-
-       ret = io_req_set_file(ctx, s, state, req);
-       if (unlikely(ret))
-               goto out;
-
-       ret = io_req_defer(ctx, req, s->sqe);
-       if (ret) {
-               if (ret == -EIOCBQUEUED)
-                       ret = 0;
-               return ret;
-       }
-
        ret = __io_submit_sqe(ctx, req, s, true);
        if (ret == -EAGAIN && !(req->flags & REQ_F_NOWAIT)) {
                struct io_uring_sqe *sqe_copy;
@@ -1866,24 +1998,93 @@ static int io_submit_sqe(struct io_ring_ctx *ctx, struct sqe_submit *s,
 
                        /*
                         * Queued up for async execution, worker will release
-                        * submit reference when the iocb is actually
-                        * submitted.
+                        * submit reference when the iocb is actually submitted.
                         */
                        return 0;
                }
        }
 
-out:
        /* drop submission reference */
        io_put_req(req);
 
        /* and drop final reference, if we failed */
-       if (ret)
+       if (ret) {
+               io_cqring_add_event(ctx, req->user_data, ret);
+               if (req->flags & REQ_F_LINK)
+                       req->flags |= REQ_F_FAIL_LINK;
                io_put_req(req);
+       }
 
        return ret;
 }
 
+#define SQE_VALID_FLAGS        (IOSQE_FIXED_FILE|IOSQE_IO_DRAIN|IOSQE_IO_LINK)
+
+static void io_submit_sqe(struct io_ring_ctx *ctx, struct sqe_submit *s,
+                         struct io_submit_state *state, struct io_kiocb **link)
+{
+       struct io_uring_sqe *sqe_copy;
+       struct io_kiocb *req;
+       int ret;
+
+       /* enforce forwards compatibility on users */
+       if (unlikely(s->sqe->flags & ~SQE_VALID_FLAGS)) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       req = io_get_req(ctx, state);
+       if (unlikely(!req)) {
+               ret = -EAGAIN;
+               goto err;
+       }
+
+       ret = io_req_set_file(ctx, s, state, req);
+       if (unlikely(ret)) {
+err_req:
+               io_free_req(req);
+err:
+               io_cqring_add_event(ctx, s->sqe->user_data, ret);
+               return;
+       }
+
+       ret = io_req_defer(ctx, req, s->sqe);
+       if (ret) {
+               if (ret != -EIOCBQUEUED)
+                       goto err_req;
+               return;
+       }
+
+       /*
+        * If we already have a head request, queue this one for async
+        * submittal once the head completes. If we don't have a head but
+        * IOSQE_IO_LINK is set in the sqe, start a new head. This one will be
+        * submitted sync once the chain is complete. If none of those
+        * conditions are true (normal request), then just queue it.
+        */
+       if (*link) {
+               struct io_kiocb *prev = *link;
+
+               sqe_copy = kmemdup(s->sqe, sizeof(*sqe_copy), GFP_KERNEL);
+               if (!sqe_copy) {
+                       ret = -EAGAIN;
+                       goto err_req;
+               }
+
+               s->sqe = sqe_copy;
+               memcpy(&req->submit, s, sizeof(*s));
+               list_add_tail(&req->list, &prev->link_list);
+       } else if (s->sqe->flags & IOSQE_IO_LINK) {
+               req->flags |= REQ_F_LINK;
+
+               memcpy(&req->submit, s, sizeof(*s));
+               INIT_LIST_HEAD(&req->link_list);
+               *link = req;
+       } else {
+               io_queue_sqe(ctx, req, s);
+       }
+}
+
 /*
  * Batched submission is done, ensure local IO is flushed out.
  */
@@ -1966,7 +2167,9 @@ static int io_submit_sqes(struct io_ring_ctx *ctx, struct sqe_submit *sqes,
                          unsigned int nr, bool has_user, bool mm_fault)
 {
        struct io_submit_state state, *statep = NULL;
-       int ret, i, submitted = 0;
+       struct io_kiocb *link = NULL;
+       bool prev_was_link = false;
+       int i, submitted = 0;
 
        if (nr > IO_PLUG_THRESHOLD) {
                io_submit_state_start(&state, ctx, nr);
@@ -1974,22 +2177,30 @@ static int io_submit_sqes(struct io_ring_ctx *ctx, struct sqe_submit *sqes,
        }
 
        for (i = 0; i < nr; i++) {
+               /*
+                * If previous wasn't linked and we have a linked command,
+                * that's the end of the chain. Submit the previous link.
+                */
+               if (!prev_was_link && link) {
+                       io_queue_sqe(ctx, link, &link->submit);
+                       link = NULL;
+               }
+               prev_was_link = (sqes[i].sqe->flags & IOSQE_IO_LINK) != 0;
+
                if (unlikely(mm_fault)) {
-                       ret = -EFAULT;
+                       io_cqring_add_event(ctx, sqes[i].sqe->user_data,
+                                               -EFAULT);
                } else {
                        sqes[i].has_user = has_user;
                        sqes[i].needs_lock = true;
                        sqes[i].needs_fixed_file = true;
-                       ret = io_submit_sqe(ctx, &sqes[i], statep);
-               }
-               if (!ret) {
+                       io_submit_sqe(ctx, &sqes[i], statep, &link);
                        submitted++;
-                       continue;
                }
-
-               io_cqring_add_event(ctx, sqes[i].sqe->user_data, ret);
        }
 
+       if (link)
+               io_queue_sqe(ctx, link, &link->submit);
        if (statep)
                io_submit_state_end(&state);
 
@@ -2006,6 +2217,8 @@ static int io_sq_thread(void *data)
        unsigned inflight;
        unsigned long timeout;
 
+       complete(&ctx->sqo_thread_started);
+
        old_fs = get_fs();
        set_fs(USER_DS);
 
@@ -2130,6 +2343,8 @@ static int io_sq_thread(void *data)
 static int io_ring_submit(struct io_ring_ctx *ctx, unsigned int to_submit)
 {
        struct io_submit_state state, *statep = NULL;
+       struct io_kiocb *link = NULL;
+       bool prev_was_link = false;
        int i, submit = 0;
 
        if (to_submit > IO_PLUG_THRESHOLD) {
@@ -2139,22 +2354,30 @@ static int io_ring_submit(struct io_ring_ctx *ctx, unsigned int to_submit)
 
        for (i = 0; i < to_submit; i++) {
                struct sqe_submit s;
-               int ret;
 
                if (!io_get_sqring(ctx, &s))
                        break;
 
+               /*
+                * If previous wasn't linked and we have a linked command,
+                * that's the end of the chain. Submit the previous link.
+                */
+               if (!prev_was_link && link) {
+                       io_queue_sqe(ctx, link, &link->submit);
+                       link = NULL;
+               }
+               prev_was_link = (s.sqe->flags & IOSQE_IO_LINK) != 0;
+
                s.has_user = true;
                s.needs_lock = false;
                s.needs_fixed_file = false;
                submit++;
-
-               ret = io_submit_sqe(ctx, &s, statep);
-               if (ret)
-                       io_cqring_add_event(ctx, s.sqe->user_data, ret);
+               io_submit_sqe(ctx, &s, statep, &link);
        }
        io_commit_sqring(ctx);
 
+       if (link)
+               io_queue_sqe(ctx, link, &link->submit);
        if (statep)
                io_submit_state_end(statep);
 
@@ -2240,6 +2463,7 @@ static int io_sqe_files_unregister(struct io_ring_ctx *ctx)
 static void io_sq_thread_stop(struct io_ring_ctx *ctx)
 {
        if (ctx->sqo_thread) {
+               wait_for_completion(&ctx->sqo_thread_started);
                /*
                 * The park is a bit of a work-around, without it we get
                 * warning spews on shutdown with SQPOLL set and affinity
index 7d8654a..f8fb89b 100644 (file)
@@ -109,9 +109,9 @@ static int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg)
        return ret;
 }
 
-int jffs2_do_readpage_unlock(struct inode *inode, struct page *pg)
+int jffs2_do_readpage_unlock(void *data, struct page *pg)
 {
-       int ret = jffs2_do_readpage_nolock(inode, pg);
+       int ret = jffs2_do_readpage_nolock(data, pg);
        unlock_page(pg);
        return ret;
 }
index 112d858..8a20ddd 100644 (file)
@@ -687,7 +687,7 @@ unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
        struct page *pg;
 
        pg = read_cache_page(inode->i_mapping, offset >> PAGE_SHIFT,
-                            (void *)jffs2_do_readpage_unlock, inode);
+                            jffs2_do_readpage_unlock, inode);
        if (IS_ERR(pg))
                return (void *)pg;
 
index a2dbbb3..bd3d5f0 100644 (file)
@@ -155,7 +155,7 @@ extern const struct file_operations jffs2_file_operations;
 extern const struct inode_operations jffs2_file_inode_operations;
 extern const struct address_space_operations jffs2_file_address_operations;
 int jffs2_fsync(struct file *, loff_t, loff_t, int);
-int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg);
+int jffs2_do_readpage_unlock(void *data, struct page *pg);
 
 /* ioctl.c */
 long jffs2_ioctl(struct file *, unsigned int, unsigned long);
index ba34dae..10ee0ec 100644 (file)
@@ -98,24 +98,16 @@ long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                /* Lock against other parallel changes of flags */
                inode_lock(inode);
 
-               oldflags = jfs_inode->mode2;
-
-               /*
-                * The IMMUTABLE and APPEND_ONLY flags can only be changed by
-                * the relevant capability.
-                */
-               if ((oldflags & JFS_IMMUTABLE_FL) ||
-                       ((flags ^ oldflags) &
-                       (JFS_APPEND_FL | JFS_IMMUTABLE_FL))) {
-                       if (!capable(CAP_LINUX_IMMUTABLE)) {
-                               inode_unlock(inode);
-                               err = -EPERM;
-                               goto setflags_out;
-                       }
+               oldflags = jfs_map_ext2(jfs_inode->mode2 & JFS_FL_USER_VISIBLE,
+                                       0);
+               err = vfs_ioc_setflags_prepare(inode, oldflags, flags);
+               if (err) {
+                       inode_unlock(inode);
+                       goto setflags_out;
                }
 
                flags = flags & JFS_FL_USER_MODIFIABLE;
-               flags |= oldflags & ~JFS_FL_USER_MODIFIABLE;
+               flags |= jfs_inode->mode2 & ~JFS_FL_USER_MODIFIABLE;
                jfs_inode->mode2 = flags;
 
                jfs_set_inode_flags(inode);
index 8483125..76bee0a 100644 (file)
@@ -127,24 +127,16 @@ static struct nfsd_fault_inject_op inject_ops[] = {
        },
 };
 
-int nfsd_fault_inject_init(void)
+void nfsd_fault_inject_init(void)
 {
        unsigned int i;
        struct nfsd_fault_inject_op *op;
        umode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
 
        debug_dir = debugfs_create_dir("nfsd", NULL);
-       if (!debug_dir)
-               goto fail;
 
        for (i = 0; i < ARRAY_SIZE(inject_ops); i++) {
                op = &inject_ops[i];
-               if (!debugfs_create_file(op->file, mode, debug_dir, op, &fops_nfsd))
-                       goto fail;
+               debugfs_create_file(op->file, mode, debug_dir, op, &fops_nfsd);
        }
-       return 0;
-
-fail:
-       nfsd_fault_inject_cleanup();
-       return -ENOMEM;
 }
index 72fad54..0a9a49d 100644 (file)
@@ -1514,9 +1514,7 @@ static int __init init_nfsd(void)
        retval = nfsd4_init_pnfs();
        if (retval)
                goto out_free_slabs;
-       retval = nfsd_fault_inject_init(); /* nfsd fault injection controls */
-       if (retval)
-               goto out_exit_pnfs;
+       nfsd_fault_inject_init(); /* nfsd fault injection controls */
        nfsd_stat_init();       /* Statistics */
        nfsd_lockd_init();      /* lockd->nfsd callbacks */
        retval = create_proc_exports_entry();
@@ -1533,7 +1531,6 @@ out_free_lockd:
        nfsd_lockd_shutdown();
        nfsd_stat_shutdown();
        nfsd_fault_inject_cleanup();
-out_exit_pnfs:
        nfsd4_exit_pnfs();
 out_free_slabs:
        nfsd4_free_slabs();
index 8cb20ca..5dbd169 100644 (file)
@@ -672,7 +672,7 @@ extern void nfsd4_record_grace_done(struct nfsd_net *nn);
 
 /* nfs fault injection functions */
 #ifdef CONFIG_NFSD_FAULT_INJECTION
-int nfsd_fault_inject_init(void);
+void nfsd_fault_inject_init(void);
 void nfsd_fault_inject_cleanup(void);
 
 u64 nfsd_inject_print_clients(void);
@@ -693,7 +693,7 @@ u64 nfsd_inject_forget_delegations(u64);
 u64 nfsd_inject_recall_client_delegations(struct sockaddr_storage *, size_t);
 u64 nfsd_inject_recall_delegations(u64);
 #else /* CONFIG_NFSD_FAULT_INJECTION */
-static inline int nfsd_fault_inject_init(void) { return 0; }
+static inline void nfsd_fault_inject_init(void) {}
 static inline void nfsd_fault_inject_cleanup(void) {}
 #endif /* CONFIG_NFSD_FAULT_INJECTION */
 
index 9b96d79..91b9dac 100644 (file)
@@ -148,13 +148,8 @@ static int nilfs_ioctl_setflags(struct inode *inode, struct file *filp,
 
        oldflags = NILFS_I(inode)->i_flags;
 
-       /*
-        * The IMMUTABLE and APPEND_ONLY flags can only be changed by the
-        * relevant capability.
-        */
-       ret = -EPERM;
-       if (((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) &&
-           !capable(CAP_LINUX_IMMUTABLE))
+       ret = vfs_ioc_setflags_prepare(inode, oldflags, flags);
+       if (ret)
                goto out;
 
        ret = nilfs_transaction_begin(inode->i_sb, &ti, 0);
index b428c29..5778d13 100644 (file)
@@ -288,10 +288,13 @@ struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
        /*
         * For queues with unlimited length lost events are not expected and
         * can possibly have security implications. Avoid losing events when
-        * memory is short.
+        * memory is short. For the limited size queues, avoid OOM killer in the
+        * target monitoring memcg as it may have security repercussion.
         */
        if (group->max_events == UINT_MAX)
                gfp |= __GFP_NOFAIL;
+       else
+               gfp |= __GFP_RETRY_MAYFAIL;
 
        /* Whoever is interested in the event, pays for the allocation. */
        memalloc_use_memcg(group->memcg);
index 2fda08b..d510223 100644 (file)
@@ -90,9 +90,13 @@ int inotify_handle_event(struct fsnotify_group *group,
        i_mark = container_of(inode_mark, struct inotify_inode_mark,
                              fsn_mark);
 
-       /* Whoever is interested in the event, pays for the allocation. */
+       /*
+        * Whoever is interested in the event, pays for the allocation. Do not
+        * trigger OOM killer in the target monitoring memcg as it may have
+        * security repercussion.
+        */
        memalloc_use_memcg(group->memcg);
-       event = kmalloc(alloc_len, GFP_KERNEL_ACCOUNT);
+       event = kmalloc(alloc_len, GFP_KERNEL_ACCOUNT | __GFP_RETRY_MAYFAIL);
        memalloc_unuse_memcg();
 
        if (unlikely(!event)) {
index d1348fc..0c335b5 100644 (file)
@@ -6191,17 +6191,17 @@ int ocfs2_begin_truncate_log_recovery(struct ocfs2_super *osb,
        if (le16_to_cpu(tl->tl_used)) {
                trace_ocfs2_truncate_log_recovery_num(le16_to_cpu(tl->tl_used));
 
-               *tl_copy = kmalloc(tl_bh->b_size, GFP_KERNEL);
+               /*
+                * Assuming the write-out below goes well, this copy will be
+                * passed back to recovery for processing.
+                */
+               *tl_copy = kmemdup(tl_bh->b_data, tl_bh->b_size, GFP_KERNEL);
                if (!(*tl_copy)) {
                        status = -ENOMEM;
                        mlog_errno(status);
                        goto bail;
                }
 
-               /* Assuming the write-out below goes well, this copy
-                * will be passed back to recovery for processing. */
-               memcpy(*tl_copy, tl_bh->b_data, tl_bh->b_size);
-
                /* All we need to do to clear the truncate log is set
                 * tl_used. */
                tl->tl_used = 0;
index 005b813..429e6a8 100644 (file)
@@ -242,57 +242,29 @@ static struct dentry *blockcheck_debugfs_create(const char *name,
 static void ocfs2_blockcheck_debug_remove(struct ocfs2_blockcheck_stats *stats)
 {
        if (stats) {
-               debugfs_remove(stats->b_debug_check);
-               stats->b_debug_check = NULL;
-               debugfs_remove(stats->b_debug_failure);
-               stats->b_debug_failure = NULL;
-               debugfs_remove(stats->b_debug_recover);
-               stats->b_debug_recover = NULL;
-               debugfs_remove(stats->b_debug_dir);
+               debugfs_remove_recursive(stats->b_debug_dir);
                stats->b_debug_dir = NULL;
        }
 }
 
-static int ocfs2_blockcheck_debug_install(struct ocfs2_blockcheck_stats *stats,
-                                         struct dentry *parent)
+static void ocfs2_blockcheck_debug_install(struct ocfs2_blockcheck_stats *stats,
+                                          struct dentry *parent)
 {
-       int rc = -EINVAL;
-
-       if (!stats)
-               goto out;
-
        stats->b_debug_dir = debugfs_create_dir("blockcheck", parent);
-       if (!stats->b_debug_dir)
-               goto out;
 
-       stats->b_debug_check =
-               blockcheck_debugfs_create("blocks_checked",
-                                         stats->b_debug_dir,
-                                         &stats->b_check_count);
+       blockcheck_debugfs_create("blocks_checked", stats->b_debug_dir,
+                                 &stats->b_check_count);
 
-       stats->b_debug_failure =
-               blockcheck_debugfs_create("checksums_failed",
-                                         stats->b_debug_dir,
-                                         &stats->b_failure_count);
+       blockcheck_debugfs_create("checksums_failed", stats->b_debug_dir,
+                                 &stats->b_failure_count);
 
-       stats->b_debug_recover =
-               blockcheck_debugfs_create("ecc_recoveries",
-                                         stats->b_debug_dir,
-                                         &stats->b_recover_count);
-       if (stats->b_debug_check && stats->b_debug_failure &&
-           stats->b_debug_recover)
-               rc = 0;
-
-out:
-       if (rc)
-               ocfs2_blockcheck_debug_remove(stats);
-       return rc;
+       blockcheck_debugfs_create("ecc_recoveries", stats->b_debug_dir,
+                                 &stats->b_recover_count);
 }
 #else
-static inline int ocfs2_blockcheck_debug_install(struct ocfs2_blockcheck_stats *stats,
-                                                struct dentry *parent)
+static inline void ocfs2_blockcheck_debug_install(struct ocfs2_blockcheck_stats *stats,
+                                                 struct dentry *parent)
 {
-       return 0;
 }
 
 static inline void ocfs2_blockcheck_debug_remove(struct ocfs2_blockcheck_stats *stats)
@@ -301,10 +273,10 @@ static inline void ocfs2_blockcheck_debug_remove(struct ocfs2_blockcheck_stats *
 #endif  /* CONFIG_DEBUG_FS */
 
 /* Always-called wrappers for starting and stopping the debugfs files */
-int ocfs2_blockcheck_stats_debugfs_install(struct ocfs2_blockcheck_stats *stats,
-                                          struct dentry *parent)
+void ocfs2_blockcheck_stats_debugfs_install(struct ocfs2_blockcheck_stats *stats,
+                                           struct dentry *parent)
 {
-       return ocfs2_blockcheck_debug_install(stats, parent);
+       ocfs2_blockcheck_debug_install(stats, parent);
 }
 
 void ocfs2_blockcheck_stats_debugfs_remove(struct ocfs2_blockcheck_stats *stats)
index f2d2689..8f17d2c 100644 (file)
@@ -25,9 +25,6 @@ struct ocfs2_blockcheck_stats {
         * ocfs2_blockcheck_stats_debugfs_install()
         */
        struct dentry *b_debug_dir;     /* Parent of the debugfs  files */
-       struct dentry *b_debug_check;   /* Exposes b_check_count */
-       struct dentry *b_debug_failure; /* Exposes b_failure_count */
-       struct dentry *b_debug_recover; /* Exposes b_recover_count */
 };
 
 
@@ -56,8 +53,8 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
                                   struct ocfs2_blockcheck_stats *stats);
 
 /* Debug Initialization */
-int ocfs2_blockcheck_stats_debugfs_install(struct ocfs2_blockcheck_stats *stats,
-                                          struct dentry *parent);
+void ocfs2_blockcheck_stats_debugfs_install(struct ocfs2_blockcheck_stats *stats,
+                                           struct dentry *parent);
 void ocfs2_blockcheck_stats_debugfs_remove(struct ocfs2_blockcheck_stats *stats);
 
 /*
index 7a3a096..f1b6133 100644 (file)
@@ -92,10 +92,6 @@ static struct o2hb_debug_buf *o2hb_db_failedregions;
 #define O2HB_DEBUG_REGION_PINNED       "pinned"
 
 static struct dentry *o2hb_debug_dir;
-static struct dentry *o2hb_debug_livenodes;
-static struct dentry *o2hb_debug_liveregions;
-static struct dentry *o2hb_debug_quorumregions;
-static struct dentry *o2hb_debug_failedregions;
 
 static LIST_HEAD(o2hb_all_regions);
 
@@ -1184,7 +1180,7 @@ bail:
        if (atomic_read(&reg->hr_steady_iterations) != 0) {
                if (atomic_dec_and_test(&reg->hr_unsteady_iterations)) {
                        printk(KERN_NOTICE "o2hb: Unable to stabilize "
-                              "heartbeart on region %s (%s)\n",
+                              "heartbeat on region %s (%s)\n",
                               config_item_name(&reg->hr_item),
                               reg->hr_dev_name);
                        atomic_set(&reg->hr_steady_iterations, 0);
@@ -1391,11 +1387,7 @@ static const struct file_operations o2hb_debug_fops = {
 
 void o2hb_exit(void)
 {
-       debugfs_remove(o2hb_debug_failedregions);
-       debugfs_remove(o2hb_debug_quorumregions);
-       debugfs_remove(o2hb_debug_liveregions);
-       debugfs_remove(o2hb_debug_livenodes);
-       debugfs_remove(o2hb_debug_dir);
+       debugfs_remove_recursive(o2hb_debug_dir);
        kfree(o2hb_db_livenodes);
        kfree(o2hb_db_liveregions);
        kfree(o2hb_db_quorumregions);
@@ -1419,79 +1411,37 @@ static struct dentry *o2hb_debug_create(const char *name, struct dentry *dir,
                                   &o2hb_debug_fops);
 }
 
-static int o2hb_debug_init(void)
+static void o2hb_debug_init(void)
 {
-       int ret = -ENOMEM;
-
        o2hb_debug_dir = debugfs_create_dir(O2HB_DEBUG_DIR, NULL);
-       if (!o2hb_debug_dir) {
-               mlog_errno(ret);
-               goto bail;
-       }
 
-       o2hb_debug_livenodes = o2hb_debug_create(O2HB_DEBUG_LIVENODES,
-                                                o2hb_debug_dir,
-                                                &o2hb_db_livenodes,
-                                                sizeof(*o2hb_db_livenodes),
-                                                O2HB_DB_TYPE_LIVENODES,
-                                                sizeof(o2hb_live_node_bitmap),
-                                                O2NM_MAX_NODES,
-                                                o2hb_live_node_bitmap);
-       if (!o2hb_debug_livenodes) {
-               mlog_errno(ret);
-               goto bail;
-       }
+       o2hb_debug_create(O2HB_DEBUG_LIVENODES, o2hb_debug_dir,
+                         &o2hb_db_livenodes, sizeof(*o2hb_db_livenodes),
+                         O2HB_DB_TYPE_LIVENODES, sizeof(o2hb_live_node_bitmap),
+                         O2NM_MAX_NODES, o2hb_live_node_bitmap);
 
-       o2hb_debug_liveregions = o2hb_debug_create(O2HB_DEBUG_LIVEREGIONS,
-                                                  o2hb_debug_dir,
-                                                  &o2hb_db_liveregions,
-                                                  sizeof(*o2hb_db_liveregions),
-                                                  O2HB_DB_TYPE_LIVEREGIONS,
-                                                  sizeof(o2hb_live_region_bitmap),
-                                                  O2NM_MAX_REGIONS,
-                                                  o2hb_live_region_bitmap);
-       if (!o2hb_debug_liveregions) {
-               mlog_errno(ret);
-               goto bail;
-       }
+       o2hb_debug_create(O2HB_DEBUG_LIVEREGIONS, o2hb_debug_dir,
+                         &o2hb_db_liveregions, sizeof(*o2hb_db_liveregions),
+                         O2HB_DB_TYPE_LIVEREGIONS,
+                         sizeof(o2hb_live_region_bitmap), O2NM_MAX_REGIONS,
+                         o2hb_live_region_bitmap);
 
-       o2hb_debug_quorumregions =
-                       o2hb_debug_create(O2HB_DEBUG_QUORUMREGIONS,
-                                         o2hb_debug_dir,
-                                         &o2hb_db_quorumregions,
-                                         sizeof(*o2hb_db_quorumregions),
-                                         O2HB_DB_TYPE_QUORUMREGIONS,
-                                         sizeof(o2hb_quorum_region_bitmap),
-                                         O2NM_MAX_REGIONS,
-                                         o2hb_quorum_region_bitmap);
-       if (!o2hb_debug_quorumregions) {
-               mlog_errno(ret);
-               goto bail;
-       }
-
-       o2hb_debug_failedregions =
-                       o2hb_debug_create(O2HB_DEBUG_FAILEDREGIONS,
-                                         o2hb_debug_dir,
-                                         &o2hb_db_failedregions,
-                                         sizeof(*o2hb_db_failedregions),
-                                         O2HB_DB_TYPE_FAILEDREGIONS,
-                                         sizeof(o2hb_failed_region_bitmap),
-                                         O2NM_MAX_REGIONS,
-                                         o2hb_failed_region_bitmap);
-       if (!o2hb_debug_failedregions) {
-               mlog_errno(ret);
-               goto bail;
-       }
+       o2hb_debug_create(O2HB_DEBUG_QUORUMREGIONS, o2hb_debug_dir,
+                         &o2hb_db_quorumregions,
+                         sizeof(*o2hb_db_quorumregions),
+                         O2HB_DB_TYPE_QUORUMREGIONS,
+                         sizeof(o2hb_quorum_region_bitmap), O2NM_MAX_REGIONS,
+                         o2hb_quorum_region_bitmap);
 
-       ret = 0;
-bail:
-       if (ret)
-               o2hb_exit();
-
-       return ret;
+       o2hb_debug_create(O2HB_DEBUG_FAILEDREGIONS, o2hb_debug_dir,
+                         &o2hb_db_failedregions,
+                         sizeof(*o2hb_db_failedregions),
+                         O2HB_DB_TYPE_FAILEDREGIONS,
+                         sizeof(o2hb_failed_region_bitmap), O2NM_MAX_REGIONS,
+                         o2hb_failed_region_bitmap);
 }
 
-int o2hb_init(void)
+void o2hb_init(void)
 {
        int i;
 
@@ -1511,7 +1461,7 @@ int o2hb_init(void)
 
        o2hb_dependent_users = 0;
 
-       return o2hb_debug_init();
+       o2hb_debug_init();
 }
 
 /* if we're already in a callback then we're already serialized by the sem */
index 7f37540..beed31e 100644 (file)
@@ -63,7 +63,7 @@ void o2hb_unregister_callback(const char *region_uuid,
 void o2hb_fill_node_map(unsigned long *map,
                        unsigned bytes);
 void o2hb_exit(void);
-int o2hb_init(void);
+void o2hb_init(void);
 int o2hb_check_node_heartbeating_no_sem(u8 node_num);
 int o2hb_check_node_heartbeating_from_callback(u8 node_num);
 void o2hb_stop_all_regions(void);
index 0784575..02bf4a1 100644 (file)
 #define SHOW_SOCK_STATS                1
 
 static struct dentry *o2net_dentry;
-static struct dentry *sc_dentry;
-static struct dentry *nst_dentry;
-static struct dentry *stats_dentry;
-static struct dentry *nodes_dentry;
 
 static DEFINE_SPINLOCK(o2net_debug_lock);
 
@@ -490,36 +486,23 @@ static const struct file_operations nodes_fops = {
 
 void o2net_debugfs_exit(void)
 {
-       debugfs_remove(nodes_dentry);
-       debugfs_remove(stats_dentry);
-       debugfs_remove(sc_dentry);
-       debugfs_remove(nst_dentry);
-       debugfs_remove(o2net_dentry);
+       debugfs_remove_recursive(o2net_dentry);
 }
 
-int o2net_debugfs_init(void)
+void o2net_debugfs_init(void)
 {
        umode_t mode = S_IFREG|S_IRUSR;
 
        o2net_dentry = debugfs_create_dir(O2NET_DEBUG_DIR, NULL);
-       if (o2net_dentry)
-               nst_dentry = debugfs_create_file(NST_DEBUG_NAME, mode,
-                                       o2net_dentry, NULL, &nst_seq_fops);
-       if (nst_dentry)
-               sc_dentry = debugfs_create_file(SC_DEBUG_NAME, mode,
-                                       o2net_dentry, NULL, &sc_seq_fops);
-       if (sc_dentry)
-               stats_dentry = debugfs_create_file(STATS_DEBUG_NAME, mode,
-                                       o2net_dentry, NULL, &stats_seq_fops);
-       if (stats_dentry)
-               nodes_dentry = debugfs_create_file(NODES_DEBUG_NAME, mode,
-                                       o2net_dentry, NULL, &nodes_fops);
-       if (nodes_dentry)
-               return 0;
-
-       o2net_debugfs_exit();
-       mlog_errno(-ENOMEM);
-       return -ENOMEM;
+
+       debugfs_create_file(NST_DEBUG_NAME, mode, o2net_dentry, NULL,
+                           &nst_seq_fops);
+       debugfs_create_file(SC_DEBUG_NAME, mode, o2net_dentry, NULL,
+                           &sc_seq_fops);
+       debugfs_create_file(STATS_DEBUG_NAME, mode, o2net_dentry, NULL,
+                           &stats_seq_fops);
+       debugfs_create_file(NODES_DEBUG_NAME, mode, o2net_dentry, NULL,
+                           &nodes_fops);
 }
 
 #endif /* CONFIG_DEBUG_FS */
index 2234f7f..7a7640c 100644 (file)
@@ -828,9 +828,7 @@ static int __init init_o2nm(void)
 {
        int ret = -1;
 
-       ret = o2hb_init();
-       if (ret)
-               goto out;
+       o2hb_init();
 
        ret = o2net_init();
        if (ret)
index 3d5d4b2..5c424a0 100644 (file)
@@ -76,7 +76,7 @@ static void o2quo_fence_self(void)
        };
 }
 
-/* Indicate that a timeout occurred on a hearbeat region write. The
+/* Indicate that a timeout occurred on a heartbeat region write. The
  * other nodes in the cluster may consider us dead at that time so we
  * want to "fence" ourselves so that we don't scribble on the disk
  * after they think they've recovered us. This can't solve all
index c599463..48a3398 100644 (file)
@@ -1762,7 +1762,7 @@ static void o2net_hb_node_up_cb(struct o2nm_node *node, int node_num,
                (msecs_to_jiffies(o2net_reconnect_delay()) + 1);
 
        if (node_num != o2nm_this_node()) {
-               /* believe it or not, accept and node hearbeating testing
+               /* believe it or not, accept and node heartbeating testing
                 * can succeed for this node before we got here.. so
                 * only use set_nn_state to clear the persistent error
                 * if that hasn't already happened */
@@ -2129,8 +2129,7 @@ int o2net_init(void)
 
        o2quo_init();
 
-       if (o2net_debugfs_init())
-               goto out;
+       o2net_debugfs_init();
 
        o2net_hand = kzalloc(sizeof(struct o2net_handshake), GFP_KERNEL);
        o2net_keep_req = kzalloc(sizeof(struct o2net_msg), GFP_KERNEL);
index dd4242b..de87cbf 100644 (file)
@@ -109,16 +109,15 @@ struct o2net_send_tracking;
 struct o2net_sock_container;
 
 #ifdef CONFIG_DEBUG_FS
-int o2net_debugfs_init(void);
+void o2net_debugfs_init(void);
 void o2net_debugfs_exit(void);
 void o2net_debug_add_nst(struct o2net_send_tracking *nst);
 void o2net_debug_del_nst(struct o2net_send_tracking *nst);
 void o2net_debug_add_sc(struct o2net_sock_container *sc);
 void o2net_debug_del_sc(struct o2net_sock_container *sc);
 #else
-static inline int o2net_debugfs_init(void)
+static inline void o2net_debugfs_init(void)
 {
-       return 0;
 }
 static inline void o2net_debugfs_exit(void)
 {
index c8af5bc..a4b58ba 100644 (file)
@@ -851,7 +851,7 @@ static const struct file_operations debug_state_fops = {
 /* end  - debug state funcs */
 
 /* files in subroot */
-int dlm_debug_init(struct dlm_ctxt *dlm)
+void dlm_debug_init(struct dlm_ctxt *dlm)
 {
        struct dlm_debug_ctxt *dc = dlm->dlm_debug_ctxt;
 
@@ -860,10 +860,6 @@ int dlm_debug_init(struct dlm_ctxt *dlm)
                                                     S_IFREG|S_IRUSR,
                                                     dlm->dlm_debugfs_subroot,
                                                     dlm, &debug_state_fops);
-       if (!dc->debug_state_dentry) {
-               mlog_errno(-ENOMEM);
-               goto bail;
-       }
 
        /* for dumping lockres */
        dc->debug_lockres_dentry =
@@ -871,20 +867,12 @@ int dlm_debug_init(struct dlm_ctxt *dlm)
                                            S_IFREG|S_IRUSR,
                                            dlm->dlm_debugfs_subroot,
                                            dlm, &debug_lockres_fops);
-       if (!dc->debug_lockres_dentry) {
-               mlog_errno(-ENOMEM);
-               goto bail;
-       }
 
        /* for dumping mles */
        dc->debug_mle_dentry = debugfs_create_file(DLM_DEBUGFS_MLE_STATE,
                                                   S_IFREG|S_IRUSR,
                                                   dlm->dlm_debugfs_subroot,
                                                   dlm, &debug_mle_fops);
-       if (!dc->debug_mle_dentry) {
-               mlog_errno(-ENOMEM);
-               goto bail;
-       }
 
        /* for dumping lockres on the purge list */
        dc->debug_purgelist_dentry =
@@ -892,15 +880,6 @@ int dlm_debug_init(struct dlm_ctxt *dlm)
                                            S_IFREG|S_IRUSR,
                                            dlm->dlm_debugfs_subroot,
                                            dlm, &debug_purgelist_fops);
-       if (!dc->debug_purgelist_dentry) {
-               mlog_errno(-ENOMEM);
-               goto bail;
-       }
-
-       return 0;
-
-bail:
-       return -ENOMEM;
 }
 
 void dlm_debug_shutdown(struct dlm_ctxt *dlm)
@@ -920,24 +899,16 @@ void dlm_debug_shutdown(struct dlm_ctxt *dlm)
 /* subroot - domain dir */
 int dlm_create_debugfs_subroot(struct dlm_ctxt *dlm)
 {
-       dlm->dlm_debugfs_subroot = debugfs_create_dir(dlm->name,
-                                                     dlm_debugfs_root);
-       if (!dlm->dlm_debugfs_subroot) {
-               mlog_errno(-ENOMEM);
-               goto bail;
-       }
-
        dlm->dlm_debug_ctxt = kzalloc(sizeof(struct dlm_debug_ctxt),
                                      GFP_KERNEL);
        if (!dlm->dlm_debug_ctxt) {
                mlog_errno(-ENOMEM);
-               goto bail;
+               return -ENOMEM;
        }
 
+       dlm->dlm_debugfs_subroot = debugfs_create_dir(dlm->name,
+                                                     dlm_debugfs_root);
        return 0;
-bail:
-       dlm_destroy_debugfs_subroot(dlm);
-       return -ENOMEM;
 }
 
 void dlm_destroy_debugfs_subroot(struct dlm_ctxt *dlm)
@@ -946,14 +917,9 @@ void dlm_destroy_debugfs_subroot(struct dlm_ctxt *dlm)
 }
 
 /* debugfs root */
-int dlm_create_debugfs_root(void)
+void dlm_create_debugfs_root(void)
 {
        dlm_debugfs_root = debugfs_create_dir(DLM_DEBUGFS_DIR, NULL);
-       if (!dlm_debugfs_root) {
-               mlog_errno(-ENOMEM);
-               return -ENOMEM;
-       }
-       return 0;
 }
 
 void dlm_destroy_debugfs_root(void)
index 74d0196..7d0c7c9 100644 (file)
@@ -28,20 +28,19 @@ struct debug_lockres {
        struct dlm_lock_resource *dl_res;
 };
 
-int dlm_debug_init(struct dlm_ctxt *dlm);
+void dlm_debug_init(struct dlm_ctxt *dlm);
 void dlm_debug_shutdown(struct dlm_ctxt *dlm);
 
 int dlm_create_debugfs_subroot(struct dlm_ctxt *dlm);
 void dlm_destroy_debugfs_subroot(struct dlm_ctxt *dlm);
 
-int dlm_create_debugfs_root(void);
+void dlm_create_debugfs_root(void);
 void dlm_destroy_debugfs_root(void);
 
 #else
 
-static inline int dlm_debug_init(struct dlm_ctxt *dlm)
+static inline void dlm_debug_init(struct dlm_ctxt *dlm)
 {
-       return 0;
 }
 static inline void dlm_debug_shutdown(struct dlm_ctxt *dlm)
 {
@@ -53,9 +52,8 @@ static inline int dlm_create_debugfs_subroot(struct dlm_ctxt *dlm)
 static inline void dlm_destroy_debugfs_subroot(struct dlm_ctxt *dlm)
 {
 }
-static inline int dlm_create_debugfs_root(void)
+static inline void dlm_create_debugfs_root(void)
 {
-       return 0;
 }
 static inline void dlm_destroy_debugfs_root(void)
 {
index 9021e72..7338b5d 100644 (file)
@@ -1881,11 +1881,7 @@ static int dlm_join_domain(struct dlm_ctxt *dlm)
                goto bail;
        }
 
-       status = dlm_debug_init(dlm);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail;
-       }
+       dlm_debug_init(dlm);
 
        snprintf(wq_name, O2NM_MAX_NAME_LEN, "dlm_wq-%s", dlm->name);
        dlm->dlm_worker = alloc_workqueue(wq_name, WQ_MEM_RECLAIM, 0);
@@ -2346,9 +2342,7 @@ static int __init dlm_init(void)
                goto error;
        }
 
-       status = dlm_create_debugfs_root();
-       if (status)
-               goto error;
+       dlm_create_debugfs_root();
 
        return 0;
 error:
index 810f841..74b768c 100644 (file)
@@ -2161,7 +2161,7 @@ put:
  * think that $RECOVERY is currently mastered by a dead node.  If so,
  * we wait a short time to allow that node to get notified by its own
  * heartbeat stack, then check again.  All $RECOVERY lock resources
- * mastered by dead nodes are purged when the hearbeat callback is
+ * mastered by dead nodes are purged when the heartbeat callback is
  * fired, so we can know for sure that it is safe to continue once
  * the node returns a live node or no node.  */
 static int dlm_pre_master_reco_lockres(struct dlm_ctxt *dlm,
index e22d6a1..064ce5b 100644 (file)
@@ -1109,7 +1109,7 @@ static int dlm_send_mig_lockres_msg(struct dlm_ctxt *dlm,
 {
        u64 mig_cookie = be64_to_cpu(mres->mig_cookie);
        int mres_total_locks = be32_to_cpu(mres->total_locks);
-       int sz, ret = 0, status = 0;
+       int ret = 0, status = 0;
        u8 orig_flags = mres->flags,
           orig_master = mres->master;
 
@@ -1117,9 +1117,6 @@ static int dlm_send_mig_lockres_msg(struct dlm_ctxt *dlm,
        if (!mres->num_locks)
                return 0;
 
-       sz = sizeof(struct dlm_migratable_lockres) +
-               (mres->num_locks * sizeof(struct dlm_migratable_lock));
-
        /* add an all-done flag if we reached the last lock */
        orig_flags = mres->flags;
        BUG_ON(total_locks > mres_total_locks);
@@ -1133,7 +1130,8 @@ static int dlm_send_mig_lockres_msg(struct dlm_ctxt *dlm,
 
        /* send it */
        ret = o2net_send_message(DLM_MIG_LOCKRES_MSG, dlm->key, mres,
-                                sz, send_to, &status);
+                                struct_size(mres, ml, mres->num_locks),
+                                send_to, &status);
        if (ret < 0) {
                /* XXX: negative status is not handled.
                 * this will end up killing this node. */
index b5fc5d3..1420723 100644 (file)
@@ -426,6 +426,7 @@ static void ocfs2_remove_lockres_tracking(struct ocfs2_lock_res *res)
 static void ocfs2_init_lock_stats(struct ocfs2_lock_res *res)
 {
        res->l_lock_refresh = 0;
+       res->l_lock_wait = 0;
        memset(&res->l_lock_prmode, 0, sizeof(struct ocfs2_lock_stats));
        memset(&res->l_lock_exmode, 0, sizeof(struct ocfs2_lock_stats));
 }
@@ -460,6 +461,8 @@ static void ocfs2_update_lock_stats(struct ocfs2_lock_res *res, int level,
 
        if (ret)
                stats->ls_fail++;
+
+       stats->ls_last = ktime_to_us(ktime_get_real());
 }
 
 static inline void ocfs2_track_lock_refresh(struct ocfs2_lock_res *lockres)
@@ -467,6 +470,21 @@ static inline void ocfs2_track_lock_refresh(struct ocfs2_lock_res *lockres)
        lockres->l_lock_refresh++;
 }
 
+static inline void ocfs2_track_lock_wait(struct ocfs2_lock_res *lockres)
+{
+       struct ocfs2_mask_waiter *mw;
+
+       if (list_empty(&lockres->l_mask_waiters)) {
+               lockres->l_lock_wait = 0;
+               return;
+       }
+
+       mw = list_first_entry(&lockres->l_mask_waiters,
+                               struct ocfs2_mask_waiter, mw_item);
+       lockres->l_lock_wait =
+                       ktime_to_us(ktime_mono_to_real(mw->mw_lock_start));
+}
+
 static inline void ocfs2_init_start_time(struct ocfs2_mask_waiter *mw)
 {
        mw->mw_lock_start = ktime_get();
@@ -482,6 +500,9 @@ static inline void ocfs2_update_lock_stats(struct ocfs2_lock_res *res,
 static inline void ocfs2_track_lock_refresh(struct ocfs2_lock_res *lockres)
 {
 }
+static inline void ocfs2_track_lock_wait(struct ocfs2_lock_res *lockres)
+{
+}
 static inline void ocfs2_init_start_time(struct ocfs2_mask_waiter *mw)
 {
 }
@@ -875,6 +896,7 @@ static void lockres_set_flags(struct ocfs2_lock_res *lockres,
                list_del_init(&mw->mw_item);
                mw->mw_status = 0;
                complete(&mw->mw_complete);
+               ocfs2_track_lock_wait(lockres);
        }
 }
 static void lockres_or_flags(struct ocfs2_lock_res *lockres, unsigned long or)
@@ -1386,6 +1408,7 @@ static void lockres_add_mask_waiter(struct ocfs2_lock_res *lockres,
        list_add_tail(&mw->mw_item, &lockres->l_mask_waiters);
        mw->mw_mask = mask;
        mw->mw_goal = goal;
+       ocfs2_track_lock_wait(lockres);
 }
 
 /* returns 0 if the mw that was removed was already satisfied, -EBUSY
@@ -1402,6 +1425,7 @@ static int __lockres_remove_mask_waiter(struct ocfs2_lock_res *lockres,
 
                list_del_init(&mw->mw_item);
                init_completion(&mw->mw_complete);
+               ocfs2_track_lock_wait(lockres);
        }
 
        return ret;
@@ -2989,6 +3013,8 @@ struct ocfs2_dlm_debug *ocfs2_new_dlm_debug(void)
        kref_init(&dlm_debug->d_refcnt);
        INIT_LIST_HEAD(&dlm_debug->d_lockres_tracking);
        dlm_debug->d_locking_state = NULL;
+       dlm_debug->d_locking_filter = NULL;
+       dlm_debug->d_filter_secs = 0;
 out:
        return dlm_debug;
 }
@@ -3079,17 +3105,43 @@ static void *ocfs2_dlm_seq_next(struct seq_file *m, void *v, loff_t *pos)
  *     - Lock stats printed
  * New in version 3
  *     - Max time in lock stats is in usecs (instead of nsecs)
+ * New in version 4
+ *     - Add last pr/ex unlock times and first lock wait time in usecs
  */
-#define OCFS2_DLM_DEBUG_STR_VERSION 3
+#define OCFS2_DLM_DEBUG_STR_VERSION 4
 static int ocfs2_dlm_seq_show(struct seq_file *m, void *v)
 {
        int i;
        char *lvb;
        struct ocfs2_lock_res *lockres = v;
+#ifdef CONFIG_OCFS2_FS_STATS
+       u64 now, last;
+       struct ocfs2_dlm_debug *dlm_debug =
+                       ((struct ocfs2_dlm_seq_priv *)m->private)->p_dlm_debug;
+#endif
 
        if (!lockres)
                return -EINVAL;
 
+#ifdef CONFIG_OCFS2_FS_STATS
+       if (!lockres->l_lock_wait && dlm_debug->d_filter_secs) {
+               now = ktime_to_us(ktime_get_real());
+               if (lockres->l_lock_prmode.ls_last >
+                   lockres->l_lock_exmode.ls_last)
+                       last = lockres->l_lock_prmode.ls_last;
+               else
+                       last = lockres->l_lock_exmode.ls_last;
+               /*
+                * Use d_filter_secs field to filter lock resources dump,
+                * the default d_filter_secs(0) value filters nothing,
+                * otherwise, only dump the last N seconds active lock
+                * resources.
+                */
+               if (div_u64(now - last, 1000000) > dlm_debug->d_filter_secs)
+                       return 0;
+       }
+#endif
+
        seq_printf(m, "0x%x\t", OCFS2_DLM_DEBUG_STR_VERSION);
 
        if (lockres->l_type == OCFS2_LOCK_TYPE_DENTRY)
@@ -3131,6 +3183,9 @@ static int ocfs2_dlm_seq_show(struct seq_file *m, void *v)
 # define lock_max_prmode(_l)           ((_l)->l_lock_prmode.ls_max)
 # define lock_max_exmode(_l)           ((_l)->l_lock_exmode.ls_max)
 # define lock_refresh(_l)              ((_l)->l_lock_refresh)
+# define lock_last_prmode(_l)          ((_l)->l_lock_prmode.ls_last)
+# define lock_last_exmode(_l)          ((_l)->l_lock_exmode.ls_last)
+# define lock_wait(_l)                 ((_l)->l_lock_wait)
 #else
 # define lock_num_prmode(_l)           (0)
 # define lock_num_exmode(_l)           (0)
@@ -3141,6 +3196,9 @@ static int ocfs2_dlm_seq_show(struct seq_file *m, void *v)
 # define lock_max_prmode(_l)           (0)
 # define lock_max_exmode(_l)           (0)
 # define lock_refresh(_l)              (0)
+# define lock_last_prmode(_l)          (0ULL)
+# define lock_last_exmode(_l)          (0ULL)
+# define lock_wait(_l)                 (0ULL)
 #endif
        /* The following seq_print was added in version 2 of this output */
        seq_printf(m, "%u\t"
@@ -3151,7 +3209,10 @@ static int ocfs2_dlm_seq_show(struct seq_file *m, void *v)
                   "%llu\t"
                   "%u\t"
                   "%u\t"
-                  "%u\t",
+                  "%u\t"
+                  "%llu\t"
+                  "%llu\t"
+                  "%llu\t",
                   lock_num_prmode(lockres),
                   lock_num_exmode(lockres),
                   lock_num_prmode_failed(lockres),
@@ -3160,7 +3221,10 @@ static int ocfs2_dlm_seq_show(struct seq_file *m, void *v)
                   lock_total_exmode(lockres),
                   lock_max_prmode(lockres),
                   lock_max_exmode(lockres),
-                  lock_refresh(lockres));
+                  lock_refresh(lockres),
+                  lock_last_prmode(lockres),
+                  lock_last_exmode(lockres),
+                  lock_wait(lockres));
 
        /* End the line */
        seq_printf(m, "\n");
@@ -3214,9 +3278,8 @@ static const struct file_operations ocfs2_dlm_debug_fops = {
        .llseek =       seq_lseek,
 };
 
-static int ocfs2_dlm_init_debug(struct ocfs2_super *osb)
+static void ocfs2_dlm_init_debug(struct ocfs2_super *osb)
 {
-       int ret = 0;
        struct ocfs2_dlm_debug *dlm_debug = osb->osb_dlm_debug;
 
        dlm_debug->d_locking_state = debugfs_create_file("locking_state",
@@ -3224,16 +3287,11 @@ static int ocfs2_dlm_init_debug(struct ocfs2_super *osb)
                                                         osb->osb_debug_root,
                                                         osb,
                                                         &ocfs2_dlm_debug_fops);
-       if (!dlm_debug->d_locking_state) {
-               ret = -EINVAL;
-               mlog(ML_ERROR,
-                    "Unable to create locking state debugfs file.\n");
-               goto out;
-       }
 
-       ocfs2_get_dlm_debug(dlm_debug);
-out:
-       return ret;
+       dlm_debug->d_locking_filter = debugfs_create_u32("locking_filter",
+                                               0600,
+                                               osb->osb_debug_root,
+                                               &dlm_debug->d_filter_secs);
 }
 
 static void ocfs2_dlm_shutdown_debug(struct ocfs2_super *osb)
@@ -3242,6 +3300,7 @@ static void ocfs2_dlm_shutdown_debug(struct ocfs2_super *osb)
 
        if (dlm_debug) {
                debugfs_remove(dlm_debug->d_locking_state);
+               debugfs_remove(dlm_debug->d_locking_filter);
                ocfs2_put_dlm_debug(dlm_debug);
        }
 }
@@ -3256,11 +3315,7 @@ int ocfs2_dlm_init(struct ocfs2_super *osb)
                goto local;
        }
 
-       status = ocfs2_dlm_init_debug(osb);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail;
-       }
+       ocfs2_dlm_init_debug(osb);
 
        /* launch downconvert thread */
        osb->dc_task = kthread_run(ocfs2_downconvert_thread, osb, "ocfs2dc-%s",
@@ -4352,7 +4407,6 @@ static int ocfs2_downconvert_thread_should_wake(struct ocfs2_super *osb)
 
 static int ocfs2_downconvert_thread(void *arg)
 {
-       int status = 0;
        struct ocfs2_super *osb = arg;
 
        /* only quit once we've been asked to stop and there is no more
@@ -4370,7 +4424,7 @@ static int ocfs2_downconvert_thread(void *arg)
        }
 
        osb->dc_task = NULL;
-       return status;
+       return 0;
 }
 
 void ocfs2_wake_downconvert_thread(struct ocfs2_super *osb)
index 994726a..d6f7b29 100644 (file)
@@ -106,16 +106,9 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
        flags = flags & mask;
        flags |= oldflags & ~mask;
 
-       /*
-        * The IMMUTABLE and APPEND_ONLY flags can only be changed by
-        * the relevant capability.
-        */
-       status = -EPERM;
-       if ((oldflags & OCFS2_IMMUTABLE_FL) || ((flags ^ oldflags) &
-               (OCFS2_APPEND_FL | OCFS2_IMMUTABLE_FL))) {
-               if (!capable(CAP_LINUX_IMMUTABLE))
-                       goto bail_unlock;
-       }
+       status = vfs_ioc_setflags_prepare(inode, oldflags, flags);
+       if (status)
+               goto bail_unlock;
 
        handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
        if (IS_ERR(handle)) {
index f03674a..158e5af 100644 (file)
@@ -424,12 +424,11 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)
        bh = osb->local_alloc_bh;
        alloc = (struct ocfs2_dinode *) bh->b_data;
 
-       alloc_copy = kmalloc(bh->b_size, GFP_NOFS);
+       alloc_copy = kmemdup(alloc, bh->b_size, GFP_NOFS);
        if (!alloc_copy) {
                status = -ENOMEM;
                goto out_commit;
        }
-       memcpy(alloc_copy, alloc, bh->b_size);
 
        status = ocfs2_journal_access_di(handle, INODE_CACHE(local_alloc_inode),
                                         bh, OCFS2_JOURNAL_ACCESS_WRITE);
@@ -1272,13 +1271,12 @@ static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,
         * local alloc shutdown won't try to double free main bitmap
         * bits. Make a copy so the sync function knows which bits to
         * free. */
-       alloc_copy = kmalloc(osb->local_alloc_bh->b_size, GFP_NOFS);
+       alloc_copy = kmemdup(alloc, osb->local_alloc_bh->b_size, GFP_NOFS);
        if (!alloc_copy) {
                status = -ENOMEM;
                mlog_errno(status);
                goto bail;
        }
-       memcpy(alloc_copy, alloc, osb->local_alloc_bh->b_size);
 
        status = ocfs2_journal_access_di(handle,
                                         INODE_CACHE(local_alloc_inode),
index a4647a6..fddbbd6 100644 (file)
@@ -150,6 +150,7 @@ struct ocfs2_lock_stats {
 
        /* Storing max wait in usecs saves 24 bytes per inode */
        u32             ls_max;         /* Max wait in USEC */
+       u64             ls_last;        /* Last unlock time in USEC */
 };
 #endif
 
@@ -191,6 +192,7 @@ struct ocfs2_lock_res {
 #ifdef CONFIG_OCFS2_FS_STATS
        struct ocfs2_lock_stats  l_lock_prmode;         /* PR mode stats */
        u32                      l_lock_refresh;        /* Disk refreshes */
+       u64                      l_lock_wait;   /* First lock wait time */
        struct ocfs2_lock_stats  l_lock_exmode;         /* EX mode stats */
 #endif
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
@@ -222,6 +224,8 @@ struct ocfs2_orphan_scan {
 struct ocfs2_dlm_debug {
        struct kref d_refcnt;
        struct dentry *d_locking_state;
+       struct dentry *d_locking_filter;
+       u32 d_filter_secs;
        struct list_head d_lockres_tracking;
 };
 
index a201f97..8b2f395 100644 (file)
@@ -1079,33 +1079,15 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 
        osb->osb_debug_root = debugfs_create_dir(osb->uuid_str,
                                                 ocfs2_debugfs_root);
-       if (!osb->osb_debug_root) {
-               status = -EINVAL;
-               mlog(ML_ERROR, "Unable to create per-mount debugfs root.\n");
-               goto read_super_error;
-       }
 
        osb->osb_ctxt = debugfs_create_file("fs_state", S_IFREG|S_IRUSR,
                                            osb->osb_debug_root,
                                            osb,
                                            &ocfs2_osb_debug_fops);
-       if (!osb->osb_ctxt) {
-               status = -EINVAL;
-               mlog_errno(status);
-               goto read_super_error;
-       }
 
-       if (ocfs2_meta_ecc(osb)) {
-               status = ocfs2_blockcheck_stats_debugfs_install(
-                                               &osb->osb_ecc_stats,
-                                               osb->osb_debug_root);
-               if (status) {
-                       mlog(ML_ERROR,
-                            "Unable to create blockcheck statistics "
-                            "files\n");
-                       goto read_super_error;
-               }
-       }
+       if (ocfs2_meta_ecc(osb))
+               ocfs2_blockcheck_stats_debugfs_install( &osb->osb_ecc_stats,
+                                                       osb->osb_debug_root);
 
        status = ocfs2_mount_volume(sb);
        if (status < 0)
@@ -1592,11 +1574,6 @@ static int __init ocfs2_init(void)
                goto out2;
 
        ocfs2_debugfs_root = debugfs_create_dir("ocfs2", NULL);
-       if (!ocfs2_debugfs_root) {
-               status = -ENOMEM;
-               mlog(ML_ERROR, "Unable to create ocfs2 debugfs root.\n");
-               goto out3;
-       }
 
        ocfs2_set_locking_protocol();
 
index a35c170..679a3c8 100644 (file)
@@ -357,11 +357,28 @@ static ssize_t orangefs_file_write_iter(struct kiocb *iocb,
        return ret;
 }
 
+static int orangefs_getflags(struct inode *inode, unsigned long *uval)
+{
+       __u64 val = 0;
+       int ret;
+
+       ret = orangefs_inode_getxattr(inode,
+                                     "user.pvfs2.meta_hint",
+                                     &val, sizeof(val));
+       if (ret < 0 && ret != -ENODATA)
+               return ret;
+       else if (ret == -ENODATA)
+               val = 0;
+       *uval = val;
+       return 0;
+}
+
 /*
  * Perform a miscellaneous operation on a file.
  */
 static long orangefs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
+       struct inode *inode = file_inode(file);
        int ret = -ENOTTY;
        __u64 val = 0;
        unsigned long uval;
@@ -375,20 +392,16 @@ static long orangefs_ioctl(struct file *file, unsigned int cmd, unsigned long ar
         * and append flags
         */
        if (cmd == FS_IOC_GETFLAGS) {
-               val = 0;
-               ret = orangefs_inode_getxattr(file_inode(file),
-                                             "user.pvfs2.meta_hint",
-                                             &val, sizeof(val));
-               if (ret < 0 && ret != -ENODATA)
+               ret = orangefs_getflags(inode, &uval);
+               if (ret)
                        return ret;
-               else if (ret == -ENODATA)
-                       val = 0;
-               uval = val;
                gossip_debug(GOSSIP_FILE_DEBUG,
                             "orangefs_ioctl: FS_IOC_GETFLAGS: %llu\n",
                             (unsigned long long)uval);
                return put_user(uval, (int __user *)arg);
        } else if (cmd == FS_IOC_SETFLAGS) {
+               unsigned long old_uval;
+
                ret = 0;
                if (get_user(uval, (int __user *)arg))
                        return -EFAULT;
@@ -404,11 +417,17 @@ static long orangefs_ioctl(struct file *file, unsigned int cmd, unsigned long ar
                        gossip_err("orangefs_ioctl: the FS_IOC_SETFLAGS only supports setting one of FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NOATIME_FL\n");
                        return -EINVAL;
                }
+               ret = orangefs_getflags(inode, &old_uval);
+               if (ret)
+                       return ret;
+               ret = vfs_ioc_setflags_prepare(inode, old_uval, uval);
+               if (ret)
+                       return ret;
                val = uval;
                gossip_debug(GOSSIP_FILE_DEBUG,
                             "orangefs_ioctl: FS_IOC_SETFLAGS: %llu\n",
                             (unsigned long long)val);
-               ret = orangefs_inode_setxattr(file_inode(file),
+               ret = orangefs_inode_setxattr(inode,
                                              "user.pvfs2.meta_hint",
                                              &val, sizeof(val), 0);
        }
index 87b1a6f..25543a9 100644 (file)
@@ -64,7 +64,7 @@ struct client_debug_mask {
        __u64 mask2;
 };
 
-static int orangefs_kernel_debug_init(void);
+static void orangefs_kernel_debug_init(void);
 
 static int orangefs_debug_help_open(struct inode *, struct file *);
 static void *help_start(struct seq_file *, loff_t *);
@@ -99,7 +99,6 @@ static char *debug_help_string;
 static char client_debug_string[ORANGEFS_MAX_DEBUG_STRING_LEN];
 static char client_debug_array_string[ORANGEFS_MAX_DEBUG_STRING_LEN];
 
-static struct dentry *help_file_dentry;
 static struct dentry *client_debug_dentry;
 static struct dentry *debug_dir;
 
@@ -151,10 +150,8 @@ static DEFINE_MUTEX(orangefs_help_file_lock);
  * initialize kmod debug operations, create orangefs debugfs dir and
  * ORANGEFS_KMOD_DEBUG_HELP_FILE.
  */
-int orangefs_debugfs_init(int debug_mask)
+void orangefs_debugfs_init(int debug_mask)
 {
-       int rc = -ENOMEM;
-
        /* convert input debug mask to a 64-bit unsigned integer */
         orangefs_gossip_debug_mask = (unsigned long long)debug_mask;
 
@@ -183,37 +180,21 @@ int orangefs_debugfs_init(int debug_mask)
                (unsigned long long)orangefs_gossip_debug_mask);
 
        debug_dir = debugfs_create_dir("orangefs", NULL);
-       if (!debug_dir) {
-               pr_info("%s: debugfs_create_dir failed.\n", __func__);
-               goto out;
-       }
 
-       help_file_dentry = debugfs_create_file(ORANGEFS_KMOD_DEBUG_HELP_FILE,
-                                 0444,
-                                 debug_dir,
-                                 debug_help_string,
-                                 &debug_help_fops);
-       if (!help_file_dentry) {
-               pr_info("%s: debugfs_create_file failed.\n", __func__);
-               goto out;
-       }
+       debugfs_create_file(ORANGEFS_KMOD_DEBUG_HELP_FILE, 0444, debug_dir,
+                           debug_help_string, &debug_help_fops);
 
        orangefs_debug_disabled = 0;
 
-       rc = orangefs_kernel_debug_init();
-
-out:
-
-       return rc;
+       orangefs_kernel_debug_init();
 }
 
 /*
  * initialize the kernel-debug file.
  */
-static int orangefs_kernel_debug_init(void)
+static void orangefs_kernel_debug_init(void)
 {
        int rc = -ENOMEM;
-       struct dentry *ret;
        char *k_buffer = NULL;
 
        gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: start\n", __func__);
@@ -230,24 +211,11 @@ static int orangefs_kernel_debug_init(void)
                pr_info("%s: overflow 1!\n", __func__);
        }
 
-       ret = debugfs_create_file(ORANGEFS_KMOD_DEBUG_FILE,
-                                 0444,
-                                 debug_dir,
-                                 k_buffer,
-                                 &kernel_debug_fops);
-       if (!ret) {
-               pr_info("%s: failed to create %s.\n",
-                       __func__,
-                       ORANGEFS_KMOD_DEBUG_FILE);
-               goto out;
-       }
-
-       rc = 0;
+       debugfs_create_file(ORANGEFS_KMOD_DEBUG_FILE, 0444, debug_dir, k_buffer,
+                           &kernel_debug_fops);
 
 out:
-
        gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: rc:%d:\n", __func__, rc);
-       return rc;
 }
 
 
@@ -353,12 +321,6 @@ static int orangefs_client_debug_init(void)
                                                  debug_dir,
                                                  c_buffer,
                                                  &kernel_debug_fops);
-       if (!client_debug_dentry) {
-               pr_info("%s: failed to create updated %s.\n",
-                       __func__,
-                       ORANGEFS_CLIENT_DEBUG_FILE);
-               goto out;
-       }
 
        rc = 0;
 
index 51147f9..502f6de 100644 (file)
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-int orangefs_debugfs_init(int);
+void orangefs_debugfs_init(int);
 void orangefs_debugfs_cleanup(void);
 int orangefs_prepare_debugfs_help_string(int);
 int orangefs_debugfs_new_client_mask(void __user *);
index 4f2d7ee..c010c1f 100644 (file)
@@ -129,9 +129,7 @@ static int __init orangefs_init(void)
        if (ret)
                goto cleanup_key_table;
 
-       ret = orangefs_debugfs_init(module_parm_debug_mask);
-       if (ret)
-               goto debugfs_init_failed;
+       orangefs_debugfs_init(module_parm_debug_mask);
 
        ret = orangefs_sysfs_init();
        if (ret)
@@ -161,8 +159,6 @@ cleanup_device:
        orangefs_dev_cleanup();
 
 sysfs_init_failed:
-
-debugfs_init_failed:
        orangefs_debugfs_cleanup();
 
 cleanup_key_table:
index c40fca9..77eb628 100644 (file)
@@ -532,8 +532,7 @@ static int proc_oom_score(struct seq_file *m, struct pid_namespace *ns,
        unsigned long totalpages = totalram_pages() + total_swap_pages;
        unsigned long points = 0;
 
-       points = oom_badness(task, NULL, NULL, totalpages) *
-                                       1000 / totalpages;
+       points = oom_badness(task, totalpages) * 1000 / totalpages;
        seq_printf(m, "%lu\n", points);
 
        return 0;
@@ -1962,9 +1961,12 @@ static int map_files_d_revalidate(struct dentry *dentry, unsigned int flags)
                goto out;
 
        if (!dname_to_vma_addr(dentry, &vm_start, &vm_end)) {
-               down_read(&mm->mmap_sem);
-               exact_vma_exists = !!find_exact_vma(mm, vm_start, vm_end);
-               up_read(&mm->mmap_sem);
+               status = down_read_killable(&mm->mmap_sem);
+               if (!status) {
+                       exact_vma_exists = !!find_exact_vma(mm, vm_start,
+                                                           vm_end);
+                       up_read(&mm->mmap_sem);
+               }
        }
 
        mmput(mm);
@@ -2010,8 +2012,11 @@ static int map_files_get_link(struct dentry *dentry, struct path *path)
        if (rc)
                goto out_mmput;
 
+       rc = down_read_killable(&mm->mmap_sem);
+       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) {
                *path = vma->vm_file->f_path;
@@ -2107,7 +2112,11 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,
        if (!mm)
                goto out_put_task;
 
-       down_read(&mm->mmap_sem);
+       result = ERR_PTR(-EINTR);
+       if (down_read_killable(&mm->mmap_sem))
+               goto out_put_mm;
+
+       result = ERR_PTR(-ENOENT);
        vma = find_exact_vma(mm, vm_start, vm_end);
        if (!vma)
                goto out_no_vma;
@@ -2118,6 +2127,7 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,
 
 out_no_vma:
        up_read(&mm->mmap_sem);
+out_put_mm:
        mmput(mm);
 out_put_task:
        put_task_struct(task);
@@ -2160,7 +2170,12 @@ proc_map_files_readdir(struct file *file, struct dir_context *ctx)
        mm = get_task_mm(task);
        if (!mm)
                goto out_put_task;
-       down_read(&mm->mmap_sem);
+
+       ret = down_read_killable(&mm->mmap_sem);
+       if (ret) {
+               mmput(mm);
+               goto out_put_task;
+       }
 
        nr_files = 0;
 
index 568d90e..465ea01 100644 (file)
@@ -120,7 +120,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
        show_val_kb(m, "Committed_AS:   ", committed);
        seq_printf(m, "VmallocTotal:   %8lu kB\n",
                   (unsigned long)VMALLOC_TOTAL >> 10);
-       show_val_kb(m, "VmallocUsed:    ", 0ul);
+       show_val_kb(m, "VmallocUsed:    ", vmalloc_nr_pages());
        show_val_kb(m, "VmallocChunk:   ", 0ul);
        show_val_kb(m, "Percpu:         ", pcpu_nr_pages());
 
index 01d4eb0..dedca3d 100644 (file)
@@ -166,7 +166,11 @@ static void *m_start(struct seq_file *m, loff_t *ppos)
        if (!mm || !mmget_not_zero(mm))
                return NULL;
 
-       down_read(&mm->mmap_sem);
+       if (down_read_killable(&mm->mmap_sem)) {
+               mmput(mm);
+               return ERR_PTR(-EINTR);
+       }
+
        hold_task_mempolicy(priv);
        priv->tail_vma = get_gate_vma(mm);
 
@@ -417,17 +421,53 @@ struct mem_size_stats {
        unsigned long shared_hugetlb;
        unsigned long private_hugetlb;
        u64 pss;
+       u64 pss_anon;
+       u64 pss_file;
+       u64 pss_shmem;
        u64 pss_locked;
        u64 swap_pss;
        bool check_shmem_swap;
 };
 
+static void smaps_page_accumulate(struct mem_size_stats *mss,
+               struct page *page, unsigned long size, unsigned long pss,
+               bool dirty, bool locked, bool private)
+{
+       mss->pss += pss;
+
+       if (PageAnon(page))
+               mss->pss_anon += pss;
+       else if (PageSwapBacked(page))
+               mss->pss_shmem += pss;
+       else
+               mss->pss_file += pss;
+
+       if (locked)
+               mss->pss_locked += pss;
+
+       if (dirty || PageDirty(page)) {
+               if (private)
+                       mss->private_dirty += size;
+               else
+                       mss->shared_dirty += size;
+       } else {
+               if (private)
+                       mss->private_clean += size;
+               else
+                       mss->shared_clean += size;
+       }
+}
+
 static void smaps_account(struct mem_size_stats *mss, struct page *page,
                bool compound, bool young, bool dirty, bool locked)
 {
        int i, nr = compound ? 1 << compound_order(page) : 1;
        unsigned long size = nr * PAGE_SIZE;
 
+       /*
+        * First accumulate quantities that depend only on |size| and the type
+        * of the compound page.
+        */
        if (PageAnon(page)) {
                mss->anonymous += size;
                if (!PageSwapBacked(page) && !dirty && !PageDirty(page))
@@ -440,42 +480,25 @@ static void smaps_account(struct mem_size_stats *mss, struct page *page,
                mss->referenced += size;
 
        /*
+        * Then accumulate quantities that may depend on sharing, or that may
+        * differ page-by-page.
+        *
         * page_count(page) == 1 guarantees the page is mapped exactly once.
         * If any subpage of the compound page mapped with PTE it would elevate
         * page_count().
         */
        if (page_count(page) == 1) {
-               if (dirty || PageDirty(page))
-                       mss->private_dirty += size;
-               else
-                       mss->private_clean += size;
-               mss->pss += (u64)size << PSS_SHIFT;
-               if (locked)
-                       mss->pss_locked += (u64)size << PSS_SHIFT;
+               smaps_page_accumulate(mss, page, size, size << PSS_SHIFT, dirty,
+                       locked, true);
                return;
        }
-
        for (i = 0; i < nr; i++, page++) {
                int mapcount = page_mapcount(page);
-               unsigned long pss = (PAGE_SIZE << PSS_SHIFT);
-
-               if (mapcount >= 2) {
-                       if (dirty || PageDirty(page))
-                               mss->shared_dirty += PAGE_SIZE;
-                       else
-                               mss->shared_clean += PAGE_SIZE;
-                       mss->pss += pss / mapcount;
-                       if (locked)
-                               mss->pss_locked += pss / mapcount;
-               } else {
-                       if (dirty || PageDirty(page))
-                               mss->private_dirty += PAGE_SIZE;
-                       else
-                               mss->private_clean += PAGE_SIZE;
-                       mss->pss += pss;
-                       if (locked)
-                               mss->pss_locked += pss;
-               }
+               unsigned long pss = PAGE_SIZE << PSS_SHIFT;
+               if (mapcount >= 2)
+                       pss /= mapcount;
+               smaps_page_accumulate(mss, page, PAGE_SIZE, pss, dirty, locked,
+                                     mapcount < 2);
        }
 }
 
@@ -754,10 +777,23 @@ static void smap_gather_stats(struct vm_area_struct *vma,
                seq_put_decimal_ull_width(m, str, (val) >> 10, 8)
 
 /* Show the contents common for smaps and smaps_rollup */
-static void __show_smap(struct seq_file *m, const struct mem_size_stats *mss)
+static void __show_smap(struct seq_file *m, const struct mem_size_stats *mss,
+       bool rollup_mode)
 {
        SEQ_PUT_DEC("Rss:            ", mss->resident);
        SEQ_PUT_DEC(" kB\nPss:            ", mss->pss >> PSS_SHIFT);
+       if (rollup_mode) {
+               /*
+                * These are meaningful only for smaps_rollup, otherwise two of
+                * them are zero, and the other one is the same as Pss.
+                */
+               SEQ_PUT_DEC(" kB\nPss_Anon:       ",
+                       mss->pss_anon >> PSS_SHIFT);
+               SEQ_PUT_DEC(" kB\nPss_File:       ",
+                       mss->pss_file >> PSS_SHIFT);
+               SEQ_PUT_DEC(" kB\nPss_Shmem:      ",
+                       mss->pss_shmem >> PSS_SHIFT);
+       }
        SEQ_PUT_DEC(" kB\nShared_Clean:   ", mss->shared_clean);
        SEQ_PUT_DEC(" kB\nShared_Dirty:   ", mss->shared_dirty);
        SEQ_PUT_DEC(" kB\nPrivate_Clean:  ", mss->private_clean);
@@ -794,7 +830,7 @@ static int show_smap(struct seq_file *m, void *v)
        SEQ_PUT_DEC(" kB\nMMUPageSize:    ", vma_mmu_pagesize(vma));
        seq_puts(m, " kB\n");
 
-       __show_smap(m, &mss);
+       __show_smap(m, &mss, false);
 
        seq_printf(m, "THPeligible:    %d\n", transparent_hugepage_enabled(vma));
 
@@ -828,7 +864,10 @@ static int show_smaps_rollup(struct seq_file *m, void *v)
 
        memset(&mss, 0, sizeof(mss));
 
-       down_read(&mm->mmap_sem);
+       ret = down_read_killable(&mm->mmap_sem);
+       if (ret)
+               goto out_put_mm;
+
        hold_task_mempolicy(priv);
 
        for (vma = priv->mm->mmap; vma; vma = vma->vm_next) {
@@ -841,12 +880,13 @@ static int show_smaps_rollup(struct seq_file *m, void *v)
        seq_pad(m, ' ');
        seq_puts(m, "[rollup]\n");
 
-       __show_smap(m, &mss);
+       __show_smap(m, &mss, true);
 
        release_task_mempolicy(priv);
        up_read(&mm->mmap_sem);
-       mmput(mm);
 
+out_put_mm:
+       mmput(mm);
 out_put_task:
        put_task_struct(priv->task);
        priv->task = NULL;
@@ -1132,7 +1172,10 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
                        goto out_mm;
                }
 
-               down_read(&mm->mmap_sem);
+               if (down_read_killable(&mm->mmap_sem)) {
+                       count = -EINTR;
+                       goto out_mm;
+               }
                tlb_gather_mmu(&tlb, mm, 0, -1);
                if (type == CLEAR_REFS_SOFT_DIRTY) {
                        for (vma = mm->mmap; vma; vma = vma->vm_next) {
@@ -1539,7 +1582,9 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
                /* overflow ? */
                if (end < start_vaddr || end > end_vaddr)
                        end = end_vaddr;
-               down_read(&mm->mmap_sem);
+               ret = down_read_killable(&mm->mmap_sem);
+               if (ret)
+                       goto out_free;
                ret = walk_page_range(start_vaddr, end, &pagemap_walk);
                up_read(&mm->mmap_sem);
                start_vaddr = end;
index 36bf0f2..7907e64 100644 (file)
@@ -211,7 +211,11 @@ static void *m_start(struct seq_file *m, loff_t *pos)
        if (!mm || !mmget_not_zero(mm))
                return NULL;
 
-       down_read(&mm->mmap_sem);
+       if (down_read_killable(&mm->mmap_sem)) {
+               mmput(mm);
+               return ERR_PTR(-EINTR);
+       }
+
        /* start from the Nth VMA */
        for (p = rb_first(&mm->mm_rb); p; p = rb_next(p))
                if (n-- == 0)
index 8e0a17c..bfbfc26 100644 (file)
@@ -112,27 +112,13 @@ static struct dentry *pstore_ftrace_dir;
 
 void pstore_register_ftrace(void)
 {
-       struct dentry *file;
-
        if (!psinfo->write)
                return;
 
        pstore_ftrace_dir = debugfs_create_dir("pstore", NULL);
-       if (!pstore_ftrace_dir) {
-               pr_err("%s: unable to create pstore directory\n", __func__);
-               return;
-       }
-
-       file = debugfs_create_file("record_ftrace", 0600, pstore_ftrace_dir,
-                                  NULL, &pstore_knob_fops);
-       if (!file) {
-               pr_err("%s: unable to create record_ftrace file\n", __func__);
-               goto err_file;
-       }
 
-       return;
-err_file:
-       debugfs_remove(pstore_ftrace_dir);
+       debugfs_create_file("record_ftrace", 0600, pstore_ftrace_dir, NULL,
+                           &pstore_knob_fops);
 }
 
 void pstore_unregister_ftrace(void)
index 89a80b5..7fbe8f0 100644 (file)
@@ -318,22 +318,21 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record)
                goto fail;
        inode->i_mode = S_IFREG | 0444;
        inode->i_fop = &pstore_file_operations;
-       private = kzalloc(sizeof(*private), GFP_KERNEL);
-       if (!private)
-               goto fail_alloc;
-       private->record = record;
-
        scnprintf(name, sizeof(name), "%s-%s-%llu%s",
                        pstore_type_to_name(record->type),
                        record->psi->name, record->id,
                        record->compressed ? ".enc.z" : "");
 
+       private = kzalloc(sizeof(*private), GFP_KERNEL);
+       if (!private)
+               goto fail_inode;
+
        dentry = d_alloc_name(root, name);
        if (!dentry)
                goto fail_private;
 
+       private->record = record;
        inode->i_size = private->total_size = size;
-
        inode->i_private = private;
 
        if (record->time.tv_sec)
@@ -349,7 +348,7 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record)
 
 fail_private:
        free_pstore_private(private);
-fail_alloc:
+fail_inode:
        iput(inode);
 
 fail:
index 5b77098..2bb3468 100644 (file)
@@ -655,6 +655,7 @@ static int ramoops_parse_dt(struct platform_device *pdev,
                            struct ramoops_platform_data *pdata)
 {
        struct device_node *of_node = pdev->dev.of_node;
+       struct device_node *parent_node;
        struct resource *res;
        u32 value;
        int ret;
@@ -689,6 +690,26 @@ static int ramoops_parse_dt(struct platform_device *pdev,
 
 #undef parse_size
 
+       /*
+        * Some old Chromebooks relied on the kernel setting the
+        * console_size and pmsg_size to the record size since that's
+        * what the downstream kernel did.  These same Chromebooks had
+        * "ramoops" straight under the root node which isn't
+        * according to the current upstream bindings (though it was
+        * arguably acceptable under a prior version of the bindings).
+        * Let's make those old Chromebooks work by detecting that
+        * we're not a child of "reserved-memory" and mimicking the
+        * expected behavior.
+        */
+       parent_node = of_get_parent(of_node);
+       if (!of_node_name_eq(parent_node, "reserved-memory") &&
+           !pdata->console_size && !pdata->ftrace_size &&
+           !pdata->pmsg_size && !pdata->ecc_info.ecc_size) {
+               pdata->console_size = pdata->record_size;
+               pdata->pmsg_size = pdata->record_size;
+       }
+       of_node_put(parent_node);
+
        return 0;
 }
 
index acbbaf7..45e1a5d 100644 (file)
@@ -74,13 +74,11 @@ long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                                err = -EPERM;
                                goto setflags_out;
                        }
-                       if (((flags ^ REISERFS_I(inode)->
-                             i_attrs) & (REISERFS_IMMUTABLE_FL |
-                                         REISERFS_APPEND_FL))
-                           && !capable(CAP_LINUX_IMMUTABLE)) {
-                               err = -EPERM;
+                       err = vfs_ioc_setflags_prepare(inode,
+                                                    REISERFS_I(inode)->i_attrs,
+                                                    flags);
+                       if (err)
                                goto setflags_out;
-                       }
                        if ((flags & REISERFS_NOTAIL_FL) &&
                            S_ISREG(inode->i_mode)) {
                                int result;
index 14cb602..9841272 100644 (file)
@@ -1356,7 +1356,7 @@ SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, uiov,
        struct iovec iovstack[UIO_FASTIOV];
        struct iovec *iov = iovstack;
        struct iov_iter iter;
-       long error;
+       ssize_t error;
        struct fd f;
        int type;
 
@@ -1367,7 +1367,7 @@ SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, uiov,
 
        error = import_iovec(type, uiov, nr_segs,
                             ARRAY_SIZE(iovstack), &iov, &iter);
-       if (!error) {
+       if (error >= 0) {
                error = do_vmsplice(f.file, &iter, flags);
                kfree(iov);
        }
@@ -1382,7 +1382,7 @@ COMPAT_SYSCALL_DEFINE4(vmsplice, int, fd, const struct compat_iovec __user *, io
        struct iovec iovstack[UIO_FASTIOV];
        struct iovec *iov = iovstack;
        struct iov_iter iter;
-       long error;
+       ssize_t error;
        struct fd f;
        int type;
 
@@ -1393,7 +1393,7 @@ COMPAT_SYSCALL_DEFINE4(vmsplice, int, fd, const struct compat_iovec __user *, io
 
        error = compat_import_iovec(type, iov32, nr_segs,
                             ARRAY_SIZE(iovstack), &iov, &iter);
-       if (!error) {
+       if (error >= 0) {
                error = do_vmsplice(f.file, &iter, flags);
                kfree(iov);
        }
index 138c5b0..a5f10d7 100644 (file)
@@ -2800,115 +2800,69 @@ static const struct file_operations dfs_fops = {
  * dbg_debugfs_init_fs - initialize debugfs for UBIFS instance.
  * @c: UBIFS file-system description object
  *
- * This function creates all debugfs files for this instance of UBIFS. Returns
- * zero in case of success and a negative error code in case of failure.
+ * This function creates all debugfs files for this instance of UBIFS.
  *
  * Note, the only reason we have not merged this function with the
  * 'ubifs_debugging_init()' function is because it is better to initialize
  * debugfs interfaces at the very end of the mount process, and remove them at
  * the very beginning of the mount process.
  */
-int dbg_debugfs_init_fs(struct ubifs_info *c)
+void dbg_debugfs_init_fs(struct ubifs_info *c)
 {
-       int err, n;
+       int n;
        const char *fname;
-       struct dentry *dent;
        struct ubifs_debug_info *d = c->dbg;
 
-       if (!IS_ENABLED(CONFIG_DEBUG_FS))
-               return 0;
-
        n = snprintf(d->dfs_dir_name, UBIFS_DFS_DIR_LEN + 1, UBIFS_DFS_DIR_NAME,
                     c->vi.ubi_num, c->vi.vol_id);
        if (n == UBIFS_DFS_DIR_LEN) {
                /* The array size is too small */
                fname = UBIFS_DFS_DIR_NAME;
-               dent = ERR_PTR(-EINVAL);
-               goto out;
+               return;
        }
 
        fname = d->dfs_dir_name;
-       dent = debugfs_create_dir(fname, dfs_rootdir);
-       if (IS_ERR_OR_NULL(dent))
-               goto out;
-       d->dfs_dir = dent;
+       d->dfs_dir = debugfs_create_dir(fname, dfs_rootdir);
 
        fname = "dump_lprops";
-       dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops);
-       if (IS_ERR_OR_NULL(dent))
-               goto out_remove;
-       d->dfs_dump_lprops = dent;
+       d->dfs_dump_lprops = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c,
+                                                &dfs_fops);
 
        fname = "dump_budg";
-       dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops);
-       if (IS_ERR_OR_NULL(dent))
-               goto out_remove;
-       d->dfs_dump_budg = dent;
+       d->dfs_dump_budg = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c,
+                                              &dfs_fops);
 
        fname = "dump_tnc";
-       dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops);
-       if (IS_ERR_OR_NULL(dent))
-               goto out_remove;
-       d->dfs_dump_tnc = dent;
+       d->dfs_dump_tnc = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c,
+                                             &dfs_fops);
 
        fname = "chk_general";
-       dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
-                                  &dfs_fops);
-       if (IS_ERR_OR_NULL(dent))
-               goto out_remove;
-       d->dfs_chk_gen = dent;
+       d->dfs_chk_gen = debugfs_create_file(fname, S_IRUSR | S_IWUSR,
+                                            d->dfs_dir, c, &dfs_fops);
 
        fname = "chk_index";
-       dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
-                                  &dfs_fops);
-       if (IS_ERR_OR_NULL(dent))
-               goto out_remove;
-       d->dfs_chk_index = dent;
+       d->dfs_chk_index = debugfs_create_file(fname, S_IRUSR | S_IWUSR,
+                                              d->dfs_dir, c, &dfs_fops);
 
        fname = "chk_orphans";
-       dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
-                                  &dfs_fops);
-       if (IS_ERR_OR_NULL(dent))
-               goto out_remove;
-       d->dfs_chk_orph = dent;
+       d->dfs_chk_orph = debugfs_create_file(fname, S_IRUSR | S_IWUSR,
+                                             d->dfs_dir, c, &dfs_fops);
 
        fname = "chk_lprops";
-       dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
-                                  &dfs_fops);
-       if (IS_ERR_OR_NULL(dent))
-               goto out_remove;
-       d->dfs_chk_lprops = dent;
+       d->dfs_chk_lprops = debugfs_create_file(fname, S_IRUSR | S_IWUSR,
+                                               d->dfs_dir, c, &dfs_fops);
 
        fname = "chk_fs";
-       dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
-                                  &dfs_fops);
-       if (IS_ERR_OR_NULL(dent))
-               goto out_remove;
-       d->dfs_chk_fs = dent;
+       d->dfs_chk_fs = debugfs_create_file(fname, S_IRUSR | S_IWUSR,
+                                           d->dfs_dir, c, &dfs_fops);
 
        fname = "tst_recovery";
-       dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
-                                  &dfs_fops);
-       if (IS_ERR_OR_NULL(dent))
-               goto out_remove;
-       d->dfs_tst_rcvry = dent;
+       d->dfs_tst_rcvry = debugfs_create_file(fname, S_IRUSR | S_IWUSR,
+                                              d->dfs_dir, c, &dfs_fops);
 
        fname = "ro_error";
-       dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
-                                  &dfs_fops);
-       if (IS_ERR_OR_NULL(dent))
-               goto out_remove;
-       d->dfs_ro_error = dent;
-
-       return 0;
-
-out_remove:
-       debugfs_remove_recursive(d->dfs_dir);
-out:
-       err = dent ? PTR_ERR(dent) : -ENODEV;
-       ubifs_err(c, "cannot create \"%s\" debugfs file or directory, error %d\n",
-                 fname, err);
-       return err;
+       d->dfs_ro_error = debugfs_create_file(fname, S_IRUSR | S_IWUSR,
+                                             d->dfs_dir, c, &dfs_fops);
 }
 
 /**
@@ -2917,8 +2871,7 @@ out:
  */
 void dbg_debugfs_exit_fs(struct ubifs_info *c)
 {
-       if (IS_ENABLED(CONFIG_DEBUG_FS))
-               debugfs_remove_recursive(c->dbg->dfs_dir);
+       debugfs_remove_recursive(c->dbg->dfs_dir);
 }
 
 struct ubifs_global_debug_info ubifs_dbg;
@@ -2994,75 +2947,38 @@ static const struct file_operations dfs_global_fops = {
  *
  * UBIFS uses debugfs file-system to expose various debugging knobs to
  * user-space. This function creates "ubifs" directory in the debugfs
- * file-system. Returns zero in case of success and a negative error code in
- * case of failure.
+ * file-system.
  */
-int dbg_debugfs_init(void)
+void dbg_debugfs_init(void)
 {
-       int err;
        const char *fname;
-       struct dentry *dent;
-
-       if (!IS_ENABLED(CONFIG_DEBUG_FS))
-               return 0;
 
        fname = "ubifs";
-       dent = debugfs_create_dir(fname, NULL);
-       if (IS_ERR_OR_NULL(dent))
-               goto out;
-       dfs_rootdir = dent;
+       dfs_rootdir = debugfs_create_dir(fname, NULL);
 
        fname = "chk_general";
-       dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
-                                  &dfs_global_fops);
-       if (IS_ERR_OR_NULL(dent))
-               goto out_remove;
-       dfs_chk_gen = dent;
+       dfs_chk_gen = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir,
+                                         NULL, &dfs_global_fops);
 
        fname = "chk_index";
-       dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
-                                  &dfs_global_fops);
-       if (IS_ERR_OR_NULL(dent))
-               goto out_remove;
-       dfs_chk_index = dent;
+       dfs_chk_index = debugfs_create_file(fname, S_IRUSR | S_IWUSR,
+                                           dfs_rootdir, NULL, &dfs_global_fops);
 
        fname = "chk_orphans";
-       dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
-                                  &dfs_global_fops);
-       if (IS_ERR_OR_NULL(dent))
-               goto out_remove;
-       dfs_chk_orph = dent;
+       dfs_chk_orph = debugfs_create_file(fname, S_IRUSR | S_IWUSR,
+                                          dfs_rootdir, NULL, &dfs_global_fops);
 
        fname = "chk_lprops";
-       dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
-                                  &dfs_global_fops);
-       if (IS_ERR_OR_NULL(dent))
-               goto out_remove;
-       dfs_chk_lprops = dent;
+       dfs_chk_lprops = debugfs_create_file(fname, S_IRUSR | S_IWUSR,
+                                            dfs_rootdir, NULL, &dfs_global_fops);
 
        fname = "chk_fs";
-       dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
-                                  &dfs_global_fops);
-       if (IS_ERR_OR_NULL(dent))
-               goto out_remove;
-       dfs_chk_fs = dent;
+       dfs_chk_fs = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir,
+                                        NULL, &dfs_global_fops);
 
        fname = "tst_recovery";
-       dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
-                                  &dfs_global_fops);
-       if (IS_ERR_OR_NULL(dent))
-               goto out_remove;
-       dfs_tst_rcvry = dent;
-
-       return 0;
-
-out_remove:
-       debugfs_remove_recursive(dfs_rootdir);
-out:
-       err = dent ? PTR_ERR(dent) : -ENODEV;
-       pr_err("UBIFS error (pid %d): cannot create \"%s\" debugfs file or directory, error %d\n",
-              current->pid, fname, err);
-       return err;
+       dfs_tst_rcvry = debugfs_create_file(fname, S_IRUSR | S_IWUSR,
+                                           dfs_rootdir, NULL, &dfs_global_fops);
 }
 
 /**
@@ -3070,8 +2986,7 @@ out:
  */
 void dbg_debugfs_exit(void)
 {
-       if (IS_ENABLED(CONFIG_DEBUG_FS))
-               debugfs_remove_recursive(dfs_rootdir);
+       debugfs_remove_recursive(dfs_rootdir);
 }
 
 void ubifs_assert_failed(struct ubifs_info *c, const char *expr,
index eb26097..7763639 100644 (file)
@@ -297,9 +297,9 @@ int dbg_leb_unmap(struct ubifs_info *c, int lnum);
 int dbg_leb_map(struct ubifs_info *c, int lnum);
 
 /* Debugfs-related stuff */
-int dbg_debugfs_init(void);
+void dbg_debugfs_init(void);
 void dbg_debugfs_exit(void);
-int dbg_debugfs_init_fs(struct ubifs_info *c);
+void dbg_debugfs_init_fs(struct ubifs_info *c);
 void dbg_debugfs_exit_fs(struct ubifs_info *c);
 
 #endif /* !__UBIFS_DEBUG_H__ */
index 4f1a397..034ad14 100644 (file)
@@ -107,18 +107,11 @@ static int setflags(struct inode *inode, int flags)
        if (err)
                return err;
 
-       /*
-        * The IMMUTABLE and APPEND_ONLY flags can only be changed by
-        * the relevant capability.
-        */
        mutex_lock(&ui->ui_mutex);
        oldflags = ubifs2ioctl(ui->flags);
-       if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) {
-               if (!capable(CAP_LINUX_IMMUTABLE)) {
-                       err = -EPERM;
-                       goto out_unlock;
-               }
-       }
+       err = vfs_ioc_setflags_prepare(inode, oldflags, flags);
+       if (err)
+               goto out_unlock;
 
        ui->flags = ioctl2ubifs(flags);
        ubifs_set_inode_flags(inode);
index 6cfc494..fd1977b 100644 (file)
@@ -1465,9 +1465,7 @@ static int mount_ubifs(struct ubifs_info *c)
        if (err)
                goto out_infos;
 
-       err = dbg_debugfs_init_fs(c);
-       if (err)
-               goto out_infos;
+       dbg_debugfs_init_fs(c);
 
        c->mounting = 0;
 
@@ -2352,9 +2350,7 @@ static int __init ubifs_init(void)
        if (err)
                goto out_shrinker;
 
-       err = dbg_debugfs_init();
-       if (err)
-               goto out_compr;
+       dbg_debugfs_init();
 
        err = register_filesystem(&ubifs_fs_type);
        if (err) {
@@ -2366,7 +2362,6 @@ static int __init ubifs_init(void)
 
 out_dbg:
        dbg_debugfs_exit();
-out_compr:
        ubifs_compressors_exit();
 out_shrinker:
        unregister_shrinker(&ubifs_shrinker_info);
index 9183197..b74a471 100644 (file)
@@ -62,6 +62,7 @@ xfs-y                         += xfs_aops.o \
                                   xfs_attr_inactive.o \
                                   xfs_attr_list.o \
                                   xfs_bmap_util.o \
+                                  xfs_bio_io.o \
                                   xfs_buf.o \
                                   xfs_dir2_readdir.o \
                                   xfs_discard.o \
@@ -80,9 +81,11 @@ xfs-y                                += xfs_aops.o \
                                   xfs_iops.o \
                                   xfs_inode.o \
                                   xfs_itable.o \
+                                  xfs_iwalk.o \
                                   xfs_message.o \
                                   xfs_mount.o \
                                   xfs_mru_cache.o \
+                                  xfs_pwork.o \
                                   xfs_reflink.o \
                                   xfs_stats.o \
                                   xfs_super.o \
@@ -104,12 +107,8 @@ xfs-y                              += xfs_log.o \
                                   xfs_rmap_item.o \
                                   xfs_log_recover.o \
                                   xfs_trans_ail.o \
-                                  xfs_trans_bmap.o \
                                   xfs_trans_buf.o \
-                                  xfs_trans_extfree.o \
-                                  xfs_trans_inode.o \
-                                  xfs_trans_refcount.o \
-                                  xfs_trans_rmap.o \
+                                  xfs_trans_inode.o
 
 # optional features
 xfs-$(CONFIG_XFS_QUOTA)                += xfs_dquot.o \
index fdd9d6e..16bb9a3 100644 (file)
@@ -3,12 +3,7 @@
  * Copyright (c) 2000-2005 Silicon Graphics, Inc.
  * All Rights Reserved.
  */
-#include <linux/mm.h>
 #include <linux/sched/mm.h>
-#include <linux/highmem.h>
-#include <linux/slab.h>
-#include <linux/swap.h>
-#include <linux/blkdev.h>
 #include <linux/backing-dev.h>
 #include "kmem.h"
 #include "xfs_message.h"
index 8e6b3ba..267655a 100644 (file)
@@ -124,4 +124,12 @@ kmem_zone_zalloc(kmem_zone_t *zone, xfs_km_flags_t flags)
        return kmem_zone_alloc(zone, flags | KM_ZERO);
 }
 
+static inline struct page *
+kmem_to_page(void *addr)
+{
+       if (is_vmalloc_addr(addr))
+               return vmalloc_to_page(addr);
+       return virt_to_page(addr);
+}
+
 #endif /* __XFS_SUPPORT_KMEM_H__ */
index b0c89f5..5de296b 100644 (file)
@@ -10,6 +10,7 @@
 #include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
+#include "xfs_bit.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_btree.h"
@@ -44,6 +45,12 @@ xfs_get_aghdr_buf(
        return bp;
 }
 
+static inline bool is_log_ag(struct xfs_mount *mp, struct aghdr_init_data *id)
+{
+       return mp->m_sb.sb_logstart > 0 &&
+              id->agno == XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart);
+}
+
 /*
  * Generic btree root block init function
  */
@@ -53,40 +60,85 @@ xfs_btroot_init(
        struct xfs_buf          *bp,
        struct aghdr_init_data  *id)
 {
-       xfs_btree_init_block(mp, bp, id->type, 0, 0, id->agno, 0);
+       xfs_btree_init_block(mp, bp, id->type, 0, 0, id->agno);
 }
 
-/*
- * Alloc btree root block init functions
- */
+/* Finish initializing a free space btree. */
 static void
-xfs_bnoroot_init(
+xfs_freesp_init_recs(
        struct xfs_mount        *mp,
        struct xfs_buf          *bp,
        struct aghdr_init_data  *id)
 {
        struct xfs_alloc_rec    *arec;
+       struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
 
-       xfs_btree_init_block(mp, bp, XFS_BTNUM_BNO, 0, 1, id->agno, 0);
        arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1);
        arec->ar_startblock = cpu_to_be32(mp->m_ag_prealloc_blocks);
+
+       if (is_log_ag(mp, id)) {
+               struct xfs_alloc_rec    *nrec;
+               xfs_agblock_t           start = XFS_FSB_TO_AGBNO(mp,
+                                                       mp->m_sb.sb_logstart);
+
+               ASSERT(start >= mp->m_ag_prealloc_blocks);
+               if (start != mp->m_ag_prealloc_blocks) {
+                       /*
+                        * Modify first record to pad stripe align of log
+                        */
+                       arec->ar_blockcount = cpu_to_be32(start -
+                                               mp->m_ag_prealloc_blocks);
+                       nrec = arec + 1;
+
+                       /*
+                        * Insert second record at start of internal log
+                        * which then gets trimmed.
+                        */
+                       nrec->ar_startblock = cpu_to_be32(
+                                       be32_to_cpu(arec->ar_startblock) +
+                                       be32_to_cpu(arec->ar_blockcount));
+                       arec = nrec;
+                       be16_add_cpu(&block->bb_numrecs, 1);
+               }
+               /*
+                * Change record start to after the internal log
+                */
+               be32_add_cpu(&arec->ar_startblock, mp->m_sb.sb_logblocks);
+       }
+
+       /*
+        * Calculate the record block count and check for the case where
+        * the log might have consumed all available space in the AG. If
+        * so, reset the record count to 0 to avoid exposure of an invalid
+        * record start block.
+        */
        arec->ar_blockcount = cpu_to_be32(id->agsize -
                                          be32_to_cpu(arec->ar_startblock));
+       if (!arec->ar_blockcount)
+               block->bb_numrecs = 0;
 }
 
+/*
+ * Alloc btree root block init functions
+ */
 static void
-xfs_cntroot_init(
+xfs_bnoroot_init(
        struct xfs_mount        *mp,
        struct xfs_buf          *bp,
        struct aghdr_init_data  *id)
 {
-       struct xfs_alloc_rec    *arec;
+       xfs_btree_init_block(mp, bp, XFS_BTNUM_BNO, 0, 1, id->agno);
+       xfs_freesp_init_recs(mp, bp, id);
+}
 
-       xfs_btree_init_block(mp, bp, XFS_BTNUM_CNT, 0, 1, id->agno, 0);
-       arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1);
-       arec->ar_startblock = cpu_to_be32(mp->m_ag_prealloc_blocks);
-       arec->ar_blockcount = cpu_to_be32(id->agsize -
-                                         be32_to_cpu(arec->ar_startblock));
+static void
+xfs_cntroot_init(
+       struct xfs_mount        *mp,
+       struct xfs_buf          *bp,
+       struct aghdr_init_data  *id)
+{
+       xfs_btree_init_block(mp, bp, XFS_BTNUM_CNT, 0, 1, id->agno);
+       xfs_freesp_init_recs(mp, bp, id);
 }
 
 /*
@@ -101,7 +153,7 @@ xfs_rmaproot_init(
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
        struct xfs_rmap_rec     *rrec;
 
-       xfs_btree_init_block(mp, bp, XFS_BTNUM_RMAP, 0, 4, id->agno, 0);
+       xfs_btree_init_block(mp, bp, XFS_BTNUM_RMAP, 0, 4, id->agno);
 
        /*
         * mark the AG header regions as static metadata The BNO
@@ -149,6 +201,18 @@ xfs_rmaproot_init(
                rrec->rm_offset = 0;
                be16_add_cpu(&block->bb_numrecs, 1);
        }
+
+       /* account for the log space */
+       if (is_log_ag(mp, id)) {
+               rrec = XFS_RMAP_REC_ADDR(block,
+                               be16_to_cpu(block->bb_numrecs) + 1);
+               rrec->rm_startblock = cpu_to_be32(
+                               XFS_FSB_TO_AGBNO(mp, mp->m_sb.sb_logstart));
+               rrec->rm_blockcount = cpu_to_be32(mp->m_sb.sb_logblocks);
+               rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_LOG);
+               rrec->rm_offset = 0;
+               be16_add_cpu(&block->bb_numrecs, 1);
+       }
 }
 
 /*
@@ -209,6 +273,14 @@ xfs_agfblock_init(
                agf->agf_refcount_level = cpu_to_be32(1);
                agf->agf_refcount_blocks = cpu_to_be32(1);
        }
+
+       if (is_log_ag(mp, id)) {
+               int64_t logblocks = mp->m_sb.sb_logblocks;
+
+               be32_add_cpu(&agf->agf_freeblks, -logblocks);
+               agf->agf_longest = cpu_to_be32(id->agsize -
+                       XFS_FSB_TO_AGBNO(mp, mp->m_sb.sb_logstart) - logblocks);
+       }
 }
 
 static void
index e2ba2a3..87a9747 100644 (file)
@@ -9,20 +9,12 @@
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_alloc.h"
 #include "xfs_errortag.h"
 #include "xfs_error.h"
 #include "xfs_trace.h"
-#include "xfs_cksum.h"
 #include "xfs_trans.h"
-#include "xfs_bit.h"
-#include "xfs_bmap.h"
-#include "xfs_bmap_btree.h"
-#include "xfs_ag_resv.h"
-#include "xfs_trans_space.h"
 #include "xfs_rmap_btree.h"
 #include "xfs_btree.h"
 #include "xfs_refcount_btree.h"
index a9ff3cf..372ad55 100644 (file)
@@ -13,7 +13,6 @@
 #include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_defer.h"
-#include "xfs_inode.h"
 #include "xfs_btree.h"
 #include "xfs_rmap.h"
 #include "xfs_alloc_btree.h"
@@ -21,7 +20,6 @@
 #include "xfs_extent_busy.h"
 #include "xfs_errortag.h"
 #include "xfs_error.h"
-#include "xfs_cksum.h"
 #include "xfs_trace.h"
 #include "xfs_trans.h"
 #include "xfs_buf_item.h"
@@ -41,8 +39,6 @@ struct workqueue_struct *xfs_alloc_wq;
 STATIC int xfs_alloc_ag_vextent_exact(xfs_alloc_arg_t *);
 STATIC int xfs_alloc_ag_vextent_near(xfs_alloc_arg_t *);
 STATIC int xfs_alloc_ag_vextent_size(xfs_alloc_arg_t *);
-STATIC int xfs_alloc_ag_vextent_small(xfs_alloc_arg_t *,
-               xfs_btree_cur_t *, xfs_agblock_t *, xfs_extlen_t *, int *);
 
 /*
  * Size of the AGFL.  For CRC-enabled filesystes we steal a couple of slots in
@@ -555,7 +551,7 @@ static xfs_failaddr_t
 xfs_agfl_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount *mp = bp->b_target->bt_mount;
+       struct xfs_mount *mp = bp->b_mount;
        struct xfs_agfl *agfl = XFS_BUF_TO_AGFL(bp);
        int             i;
 
@@ -596,7 +592,7 @@ static void
 xfs_agfl_read_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount *mp = bp->b_target->bt_mount;
+       struct xfs_mount *mp = bp->b_mount;
        xfs_failaddr_t  fa;
 
        /*
@@ -621,7 +617,7 @@ static void
 xfs_agfl_write_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_buf_log_item *bip = bp->b_log_item;
        xfs_failaddr_t          fa;
 
@@ -699,6 +695,107 @@ xfs_alloc_update_counters(
  * Allocation group level functions.
  */
 
+/*
+ * Deal with the case where only small freespaces remain. Either return the
+ * contents of the last freespace record, or allocate space from the freelist if
+ * there is nothing in the tree.
+ */
+STATIC int                     /* error */
+xfs_alloc_ag_vextent_small(
+       struct xfs_alloc_arg    *args,  /* allocation argument structure */
+       struct xfs_btree_cur    *ccur,  /* optional by-size cursor */
+       xfs_agblock_t           *fbnop, /* result block number */
+       xfs_extlen_t            *flenp, /* result length */
+       int                     *stat)  /* status: 0-freelist, 1-normal/none */
+{
+       int                     error = 0;
+       xfs_agblock_t           fbno = NULLAGBLOCK;
+       xfs_extlen_t            flen = 0;
+       int                     i = 0;
+
+       /*
+        * If a cntbt cursor is provided, try to allocate the largest record in
+        * the tree. Try the AGFL if the cntbt is empty, otherwise fail the
+        * allocation. Make sure to respect minleft even when pulling from the
+        * freelist.
+        */
+       if (ccur)
+               error = xfs_btree_decrement(ccur, 0, &i);
+       if (error)
+               goto error;
+       if (i) {
+               error = xfs_alloc_get_rec(ccur, &fbno, &flen, &i);
+               if (error)
+                       goto error;
+               XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error);
+               goto out;
+       }
+
+       if (args->minlen != 1 || args->alignment != 1 ||
+           args->resv == XFS_AG_RESV_AGFL ||
+           (be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_flcount) <=
+            args->minleft))
+               goto out;
+
+       error = xfs_alloc_get_freelist(args->tp, args->agbp, &fbno, 0);
+       if (error)
+               goto error;
+       if (fbno == NULLAGBLOCK)
+               goto out;
+
+       xfs_extent_busy_reuse(args->mp, args->agno, fbno, 1,
+                             xfs_alloc_allow_busy_reuse(args->datatype));
+
+       if (xfs_alloc_is_userdata(args->datatype)) {
+               struct xfs_buf  *bp;
+
+               bp = xfs_btree_get_bufs(args->mp, args->tp, args->agno, fbno);
+               if (!bp) {
+                       error = -EFSCORRUPTED;
+                       goto error;
+               }
+               xfs_trans_binval(args->tp, bp);
+       }
+       *fbnop = args->agbno = fbno;
+       *flenp = args->len = 1;
+       XFS_WANT_CORRUPTED_GOTO(args->mp,
+               fbno < be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length),
+               error);
+       args->wasfromfl = 1;
+       trace_xfs_alloc_small_freelist(args);
+
+       /*
+        * If we're feeding an AGFL block to something that doesn't live in the
+        * free space, we need to clear out the OWN_AG rmap.
+        */
+       error = xfs_rmap_free(args->tp, args->agbp, args->agno, fbno, 1,
+                             &XFS_RMAP_OINFO_AG);
+       if (error)
+               goto error;
+
+       *stat = 0;
+       return 0;
+
+out:
+       /*
+        * Can't do the allocation, give up.
+        */
+       if (flen < args->minlen) {
+               args->agbno = NULLAGBLOCK;
+               trace_xfs_alloc_small_notenough(args);
+               flen = 0;
+       }
+       *fbnop = fbno;
+       *flenp = flen;
+       *stat = 1;
+       trace_xfs_alloc_small_done(args);
+       return 0;
+
+error:
+       trace_xfs_alloc_small_error(args);
+       return error;
+}
+
 /*
  * Allocate a variable extent in the allocation group agno.
  * Type and bno are used to determine where in the allocation group the
@@ -1582,112 +1679,6 @@ out_nominleft:
        return 0;
 }
 
-/*
- * Deal with the case where only small freespaces remain.
- * Either return the contents of the last freespace record,
- * or allocate space from the freelist if there is nothing in the tree.
- */
-STATIC int                     /* error */
-xfs_alloc_ag_vextent_small(
-       xfs_alloc_arg_t *args,  /* allocation argument structure */
-       xfs_btree_cur_t *ccur,  /* by-size cursor */
-       xfs_agblock_t   *fbnop, /* result block number */
-       xfs_extlen_t    *flenp, /* result length */
-       int             *stat)  /* status: 0-freelist, 1-normal/none */
-{
-       int             error;
-       xfs_agblock_t   fbno;
-       xfs_extlen_t    flen;
-       int             i;
-
-       if ((error = xfs_btree_decrement(ccur, 0, &i)))
-               goto error0;
-       if (i) {
-               if ((error = xfs_alloc_get_rec(ccur, &fbno, &flen, &i)))
-                       goto error0;
-               XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
-       }
-       /*
-        * Nothing in the btree, try the freelist.  Make sure
-        * to respect minleft even when pulling from the
-        * freelist.
-        */
-       else if (args->minlen == 1 && args->alignment == 1 &&
-                args->resv != XFS_AG_RESV_AGFL &&
-                (be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_flcount)
-                 > args->minleft)) {
-               error = xfs_alloc_get_freelist(args->tp, args->agbp, &fbno, 0);
-               if (error)
-                       goto error0;
-               if (fbno != NULLAGBLOCK) {
-                       xfs_extent_busy_reuse(args->mp, args->agno, fbno, 1,
-                             xfs_alloc_allow_busy_reuse(args->datatype));
-
-                       if (xfs_alloc_is_userdata(args->datatype)) {
-                               xfs_buf_t       *bp;
-
-                               bp = xfs_btree_get_bufs(args->mp, args->tp,
-                                       args->agno, fbno, 0);
-                               if (!bp) {
-                                       error = -EFSCORRUPTED;
-                                       goto error0;
-                               }
-                               xfs_trans_binval(args->tp, bp);
-                       }
-                       args->len = 1;
-                       args->agbno = fbno;
-                       XFS_WANT_CORRUPTED_GOTO(args->mp,
-                               args->agbno + args->len <=
-                               be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length),
-                               error0);
-                       args->wasfromfl = 1;
-                       trace_xfs_alloc_small_freelist(args);
-
-                       /*
-                        * If we're feeding an AGFL block to something that
-                        * doesn't live in the free space, we need to clear
-                        * out the OWN_AG rmap.
-                        */
-                       error = xfs_rmap_free(args->tp, args->agbp, args->agno,
-                                       fbno, 1, &XFS_RMAP_OINFO_AG);
-                       if (error)
-                               goto error0;
-
-                       *stat = 0;
-                       return 0;
-               }
-               /*
-                * Nothing in the freelist.
-                */
-               else
-                       flen = 0;
-       }
-       /*
-        * Can't allocate from the freelist for some reason.
-        */
-       else {
-               fbno = NULLAGBLOCK;
-               flen = 0;
-       }
-       /*
-        * Can't do the allocation, give up.
-        */
-       if (flen < args->minlen) {
-               args->agbno = NULLAGBLOCK;
-               trace_xfs_alloc_small_notenough(args);
-               flen = 0;
-       }
-       *fbnop = fbno;
-       *flenp = flen;
-       *stat = 1;
-       trace_xfs_alloc_small_done(args);
-       return 0;
-
-error0:
-       trace_xfs_alloc_small_error(args);
-       return error;
-}
-
 /*
  * Free the extent starting at agno/bno for length.
  */
@@ -2095,7 +2086,7 @@ xfs_free_agfl_block(
        if (error)
                return error;
 
-       bp = xfs_btree_get_bufs(tp->t_mountp, tp, agno, agbno, 0);
+       bp = xfs_btree_get_bufs(tp->t_mountp, tp, agno, agbno);
        if (!bp)
                return -EFSCORRUPTED;
        xfs_trans_binval(tp, bp);
@@ -2586,7 +2577,7 @@ static xfs_failaddr_t
 xfs_agf_verify(
        struct xfs_buf          *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_agf          *agf = XFS_BUF_TO_AGF(bp);
 
        if (xfs_sb_version_hascrc(&mp->m_sb)) {
@@ -2644,7 +2635,7 @@ static void
 xfs_agf_read_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount *mp = bp->b_target->bt_mount;
+       struct xfs_mount *mp = bp->b_mount;
        xfs_failaddr_t  fa;
 
        if (xfs_sb_version_hascrc(&mp->m_sb) &&
@@ -2661,7 +2652,7 @@ static void
 xfs_agf_write_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_buf_log_item *bip = bp->b_log_item;
        xfs_failaddr_t          fa;
 
@@ -3146,7 +3137,7 @@ xfs_alloc_has_record(
 
 /*
  * Walk all the blocks in the AGFL.  The @walk_fn can return any negative
- * error code or XFS_BTREE_QUERY_RANGE_ABORT.
+ * error code or XFS_ITER_*.
  */
 int
 xfs_agfl_walk(
index 9fe949f..2a94543 100644 (file)
@@ -17,7 +17,6 @@
 #include "xfs_extent_busy.h"
 #include "xfs_error.h"
 #include "xfs_trace.h"
-#include "xfs_cksum.h"
 #include "xfs_trans.h"
 
 
@@ -292,7 +291,7 @@ static xfs_failaddr_t
 xfs_allocbt_verify(
        struct xfs_buf          *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
        struct xfs_perag        *pag = bp->b_pag;
        xfs_failaddr_t          fa;
index c441f41..d48fcf1 100644 (file)
@@ -9,23 +9,18 @@
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_bit.h"
 #include "xfs_mount.h"
 #include "xfs_defer.h"
 #include "xfs_da_format.h"
 #include "xfs_da_btree.h"
 #include "xfs_attr_sf.h"
 #include "xfs_inode.h"
-#include "xfs_alloc.h"
 #include "xfs_trans.h"
-#include "xfs_inode_item.h"
 #include "xfs_bmap.h"
-#include "xfs_bmap_util.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_attr.h"
 #include "xfs_attr_leaf.h"
 #include "xfs_attr_remote.h"
-#include "xfs_error.h"
 #include "xfs_quota.h"
 #include "xfs_trans_space.h"
 #include "xfs_trace.h"
index 3b0dce0..ff28ebf 100644 (file)
@@ -112,7 +112,13 @@ typedef struct xfs_attr_list_context {
        struct xfs_inode                *dp;            /* inode */
        struct attrlist_cursor_kern     *cursor;        /* position in list */
        char                            *alist;         /* output buffer */
-       int                             seen_enough;    /* T/F: seen enough of list? */
+
+       /*
+        * Abort attribute list iteration if non-zero.  Can be used to pass
+        * error values to the xfs_attr_list caller.
+        */
+       int                             seen_enough;
+
        ssize_t                         count;          /* num used entries */
        int                             dupcnt;         /* count dup hashvals seen */
        int                             bufsize;        /* total buffer size */
index 1f6e396..70eb941 100644 (file)
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_bit.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_da_format.h"
 #include "xfs_da_btree.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
-#include "xfs_inode_item.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_bmap.h"
 #include "xfs_attr_sf.h"
@@ -27,7 +25,6 @@
 #include "xfs_error.h"
 #include "xfs_trace.h"
 #include "xfs_buf_item.h"
-#include "xfs_cksum.h"
 #include "xfs_dir2.h"
 #include "xfs_log.h"
 
@@ -240,7 +237,7 @@ xfs_attr3_leaf_verify(
        struct xfs_buf                  *bp)
 {
        struct xfs_attr3_icleaf_hdr     ichdr;
-       struct xfs_mount                *mp = bp->b_target->bt_mount;
+       struct xfs_mount                *mp = bp->b_mount;
        struct xfs_attr_leafblock       *leaf = bp->b_addr;
        struct xfs_attr_leaf_entry      *entries;
        uint32_t                        end;    /* must be 32bit - see below */
@@ -313,7 +310,7 @@ static void
 xfs_attr3_leaf_write_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_buf_log_item *bip = bp->b_log_item;
        struct xfs_attr3_leaf_hdr *hdr3 = bp->b_addr;
        xfs_failaddr_t          fa;
@@ -343,7 +340,7 @@ static void
 xfs_attr3_leaf_read_verify(
        struct xfs_buf          *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        xfs_failaddr_t          fa;
 
        if (xfs_sb_version_hascrc(&mp->m_sb) &&
@@ -865,7 +862,7 @@ xfs_attr_shortform_allfit(
        struct xfs_attr3_icleaf_hdr leafhdr;
        int                     bytes;
        int                     i;
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
 
        leaf = bp->b_addr;
        xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
@@ -1525,7 +1522,7 @@ xfs_attr_leaf_order(
 {
        struct xfs_attr3_icleaf_hdr ichdr1;
        struct xfs_attr3_icleaf_hdr ichdr2;
-       struct xfs_mount *mp = leaf1_bp->b_target->bt_mount;
+       struct xfs_mount *mp = leaf1_bp->b_mount;
 
        xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr1, leaf1_bp->b_addr);
        xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr2, leaf2_bp->b_addr);
@@ -2568,7 +2565,7 @@ xfs_attr_leaf_lasthash(
 {
        struct xfs_attr3_icleaf_hdr ichdr;
        struct xfs_attr_leaf_entry *entries;
-       struct xfs_mount *mp = bp->b_target->bt_mount;
+       struct xfs_mount *mp = bp->b_mount;
 
        xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, bp->b_addr);
        entries = xfs_attr3_leaf_entryp(bp->b_addr);
index 65ff600..4eb30d3 100644 (file)
 #include "xfs_da_format.h"
 #include "xfs_da_btree.h"
 #include "xfs_inode.h"
-#include "xfs_alloc.h"
 #include "xfs_trans.h"
-#include "xfs_inode_item.h"
 #include "xfs_bmap.h"
-#include "xfs_bmap_util.h"
 #include "xfs_attr.h"
-#include "xfs_attr_leaf.h"
-#include "xfs_attr_remote.h"
-#include "xfs_trans_space.h"
 #include "xfs_trace.h"
-#include "xfs_cksum.h"
-#include "xfs_buf_item.h"
 #include "xfs_error.h"
 
 #define ATTR_RMTVALUE_MAPSIZE  1       /* # of map entries at once */
@@ -111,7 +103,7 @@ __xfs_attr3_rmt_read_verify(
        bool            check_crc,
        xfs_failaddr_t  *failaddr)
 {
-       struct xfs_mount *mp = bp->b_target->bt_mount;
+       struct xfs_mount *mp = bp->b_mount;
        char            *ptr;
        int             len;
        xfs_daddr_t     bno;
@@ -175,7 +167,7 @@ static void
 xfs_attr3_rmt_write_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount *mp = bp->b_target->bt_mount;
+       struct xfs_mount *mp = bp->b_mount;
        xfs_failaddr_t  fa;
        int             blksize = mp->m_attr_geo->blksize;
        char            *ptr;
@@ -535,7 +527,7 @@ xfs_attr_rmtval_set(
                dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
                dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
 
-               bp = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, 0);
+               bp = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt);
                if (!bp)
                        return -ENOMEM;
                bp->b_ops = &xfs_attr3_rmt_buf_ops;
index 40ce5f3..7071ff9 100644 (file)
@@ -5,7 +5,6 @@
  */
 #include "xfs.h"
 #include "xfs_log_format.h"
-#include "xfs_bit.h"
 
 /*
  * XFS bit manipulation routines, used in non-realtime code.
index 356ebd1..baf0b72 100644 (file)
 #include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_defer.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_dir2.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
 #include "xfs_trans.h"
-#include "xfs_inode_item.h"
-#include "xfs_extfree_item.h"
 #include "xfs_alloc.h"
 #include "xfs_bmap.h"
 #include "xfs_bmap_util.h"
@@ -32,7 +28,6 @@
 #include "xfs_trans_space.h"
 #include "xfs_buf_item.h"
 #include "xfs_trace.h"
-#include "xfs_symlink.h"
 #include "xfs_attr_leaf.h"
 #include "xfs_filestream.h"
 #include "xfs_rmap.h"
@@ -370,7 +365,7 @@ xfs_bmap_check_leaf_extents(
                bp = xfs_bmap_get_bp(cur, XFS_FSB_TO_DADDR(mp, bno));
                if (!bp) {
                        bp_release = 1;
-                       error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp,
+                       error = xfs_btree_read_bufl(mp, NULL, bno, &bp,
                                                XFS_BMAP_BTREE_REF,
                                                &xfs_bmbt_buf_ops);
                        if (error)
@@ -454,7 +449,7 @@ xfs_bmap_check_leaf_extents(
                bp = xfs_bmap_get_bp(cur, XFS_FSB_TO_DADDR(mp, bno));
                if (!bp) {
                        bp_release = 1;
-                       error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp,
+                       error = xfs_btree_read_bufl(mp, NULL, bno, &bp,
                                                XFS_BMAP_BTREE_REF,
                                                &xfs_bmbt_buf_ops);
                        if (error)
@@ -619,7 +614,7 @@ xfs_bmap_btree_to_extents(
        XFS_WANT_CORRUPTED_RETURN(cur->bc_mp,
                        xfs_btree_check_lptr(cur, cbno, 1));
 #endif
-       error = xfs_btree_read_bufl(mp, tp, cbno, 0, &cbp, XFS_BMAP_BTREE_REF,
+       error = xfs_btree_read_bufl(mp, tp, cbno, &cbp, XFS_BMAP_BTREE_REF,
                                &xfs_bmbt_buf_ops);
        if (error)
                return error;
@@ -732,7 +727,7 @@ xfs_bmap_extents_to_btree(
        cur->bc_private.b.allocated++;
        ip->i_d.di_nblocks++;
        xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
-       abp = xfs_btree_get_bufl(mp, tp, args.fsbno, 0);
+       abp = xfs_btree_get_bufl(mp, tp, args.fsbno);
        if (!abp) {
                error = -EFSCORRUPTED;
                goto out_unreserve_dquot;
@@ -878,7 +873,7 @@ xfs_bmap_local_to_extents(
        ASSERT(args.fsbno != NULLFSBLOCK);
        ASSERT(args.len == 1);
        tp->t_firstblock = args.fsbno;
-       bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0);
+       bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno);
 
        /*
         * Initialize the block, copy the data and log the remote buffer.
@@ -1203,7 +1198,7 @@ xfs_iread_extents(
         * pointer (leftmost) at each level.
         */
        while (level-- > 0) {
-               error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp,
+               error = xfs_btree_read_bufl(mp, tp, bno, &bp,
                                XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops);
                if (error)
                        goto out;
@@ -1276,7 +1271,7 @@ xfs_iread_extents(
                 */
                if (bno == NULLFSBLOCK)
                        break;
-               error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp,
+               error = xfs_btree_read_bufl(mp, tp, bno, &bp,
                                XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops);
                if (error)
                        goto out;
index aff82ed..fbb18ba 100644 (file)
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
-#include "xfs_inode_item.h"
 #include "xfs_alloc.h"
 #include "xfs_btree.h"
 #include "xfs_bmap_btree.h"
@@ -22,7 +20,6 @@
 #include "xfs_error.h"
 #include "xfs_quota.h"
 #include "xfs_trace.h"
-#include "xfs_cksum.h"
 #include "xfs_rmap.h"
 
 /*
@@ -411,7 +408,7 @@ static xfs_failaddr_t
 xfs_bmbt_verify(
        struct xfs_buf          *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
        xfs_failaddr_t          fa;
        unsigned int            level;
index bbdae2b..f1048ef 100644 (file)
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
-#include "xfs_inode_item.h"
 #include "xfs_buf_item.h"
 #include "xfs_btree.h"
 #include "xfs_errortag.h"
 #include "xfs_error.h"
 #include "xfs_trace.h"
-#include "xfs_cksum.h"
 #include "xfs_alloc.h"
 #include "xfs_log.h"
 
@@ -276,7 +273,7 @@ xfs_btree_lblock_calc_crc(
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
        struct xfs_buf_log_item *bip = bp->b_log_item;
 
-       if (!xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb))
+       if (!xfs_sb_version_hascrc(&bp->b_mount->m_sb))
                return;
        if (bip)
                block->bb_u.l.bb_lsn = cpu_to_be64(bip->bli_item.li_lsn);
@@ -288,7 +285,7 @@ xfs_btree_lblock_verify_crc(
        struct xfs_buf          *bp)
 {
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
 
        if (xfs_sb_version_hascrc(&mp->m_sb)) {
                if (!xfs_log_check_lsn(mp, be64_to_cpu(block->bb_u.l.bb_lsn)))
@@ -314,7 +311,7 @@ xfs_btree_sblock_calc_crc(
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
        struct xfs_buf_log_item *bip = bp->b_log_item;
 
-       if (!xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb))
+       if (!xfs_sb_version_hascrc(&bp->b_mount->m_sb))
                return;
        if (bip)
                block->bb_u.s.bb_lsn = cpu_to_be64(bip->bli_item.li_lsn);
@@ -326,7 +323,7 @@ xfs_btree_sblock_verify_crc(
        struct xfs_buf          *bp)
 {
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
 
        if (xfs_sb_version_hascrc(&mp->m_sb)) {
                if (!xfs_log_check_lsn(mp, be64_to_cpu(block->bb_u.s.bb_lsn)))
@@ -691,14 +688,13 @@ xfs_buf_t *                               /* buffer for fsbno */
 xfs_btree_get_bufl(
        xfs_mount_t     *mp,            /* file system mount point */
        xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_fsblock_t   fsbno,          /* file system block number */
-       uint            lock)           /* lock flags for get_buf */
+       xfs_fsblock_t   fsbno)          /* file system block number */
 {
        xfs_daddr_t             d;              /* real disk block address */
 
        ASSERT(fsbno != NULLFSBLOCK);
        d = XFS_FSB_TO_DADDR(mp, fsbno);
-       return xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock);
+       return xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, 0);
 }
 
 /*
@@ -710,15 +706,14 @@ xfs_btree_get_bufs(
        xfs_mount_t     *mp,            /* file system mount point */
        xfs_trans_t     *tp,            /* transaction pointer */
        xfs_agnumber_t  agno,           /* allocation group number */
-       xfs_agblock_t   agbno,          /* allocation group block number */
-       uint            lock)           /* lock flags for get_buf */
+       xfs_agblock_t   agbno)          /* allocation group block number */
 {
        xfs_daddr_t             d;              /* real disk block address */
 
        ASSERT(agno != NULLAGNUMBER);
        ASSERT(agbno != NULLAGBLOCK);
        d = XFS_AGB_TO_DADDR(mp, agno, agbno);
-       return xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock);
+       return xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, 0);
 }
 
 /*
@@ -845,7 +840,6 @@ xfs_btree_read_bufl(
        struct xfs_mount        *mp,            /* file system mount point */
        struct xfs_trans        *tp,            /* transaction pointer */
        xfs_fsblock_t           fsbno,          /* file system block number */
-       uint                    lock,           /* lock flags for read_buf */
        struct xfs_buf          **bpp,          /* buffer for fsbno */
        int                     refval,         /* ref count value for buffer */
        const struct xfs_buf_ops *ops)
@@ -858,7 +852,7 @@ xfs_btree_read_bufl(
                return -EFSCORRUPTED;
        d = XFS_FSB_TO_DADDR(mp, fsbno);
        error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d,
-                                  mp->m_bsize, lock, &bp, ops);
+                                  mp->m_bsize, 0, &bp, ops);
        if (error)
                return error;
        if (bp)
@@ -1185,11 +1179,10 @@ xfs_btree_init_block(
        xfs_btnum_t     btnum,
        __u16           level,
        __u16           numrecs,
-       __u64           owner,
-       unsigned int    flags)
+       __u64           owner)
 {
        xfs_btree_init_block_int(mp, XFS_BUF_TO_BLOCK(bp), bp->b_bn,
-                                btnum, level, numrecs, owner, flags);
+                                btnum, level, numrecs, owner, 0);
 }
 
 STATIC void
@@ -1288,7 +1281,6 @@ STATIC int
 xfs_btree_get_buf_block(
        struct xfs_btree_cur    *cur,
        union xfs_btree_ptr     *ptr,
-       int                     flags,
        struct xfs_btree_block  **block,
        struct xfs_buf          **bpp)
 {
@@ -1296,14 +1288,11 @@ xfs_btree_get_buf_block(
        xfs_daddr_t             d;
        int                     error;
 
-       /* need to sort out how callers deal with failures first */
-       ASSERT(!(flags & XBF_TRYLOCK));
-
        error = xfs_btree_ptr_to_daddr(cur, ptr, &d);
        if (error)
                return error;
        *bpp = xfs_trans_get_buf(cur->bc_tp, mp->m_ddev_targp, d,
-                                mp->m_bsize, flags);
+                                mp->m_bsize, 0);
 
        if (!*bpp)
                return -ENOMEM;
@@ -2706,7 +2695,7 @@ __xfs_btree_split(
        XFS_BTREE_STATS_INC(cur, alloc);
 
        /* Set up the new block as "right". */
-       error = xfs_btree_get_buf_block(cur, &rptr, 0, &right, &rbp);
+       error = xfs_btree_get_buf_block(cur, &rptr, &right, &rbp);
        if (error)
                goto error0;
 
@@ -2961,7 +2950,7 @@ xfs_btree_new_iroot(
        XFS_BTREE_STATS_INC(cur, alloc);
 
        /* Copy the root into a real block. */
-       error = xfs_btree_get_buf_block(cur, &nptr, 0, &cblock, &cbp);
+       error = xfs_btree_get_buf_block(cur, &nptr, &cblock, &cbp);
        if (error)
                goto error0;
 
@@ -3058,7 +3047,7 @@ xfs_btree_new_root(
        XFS_BTREE_STATS_INC(cur, alloc);
 
        /* Set up the new block. */
-       error = xfs_btree_get_buf_block(cur, &lptr, 0, &new, &nbp);
+       error = xfs_btree_get_buf_block(cur, &lptr, &new, &nbp);
        if (error)
                goto error0;
 
@@ -4433,7 +4422,7 @@ xfs_btree_lblock_v5hdr_verify(
        struct xfs_buf          *bp,
        uint64_t                owner)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
 
        if (!xfs_sb_version_hascrc(&mp->m_sb))
@@ -4454,7 +4443,7 @@ xfs_btree_lblock_verify(
        struct xfs_buf          *bp,
        unsigned int            max_recs)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
 
        /* numrecs verification */
@@ -4484,7 +4473,7 @@ xfs_failaddr_t
 xfs_btree_sblock_v5hdr_verify(
        struct xfs_buf          *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
        struct xfs_perag        *pag = bp->b_pag;
 
@@ -4510,7 +4499,7 @@ xfs_btree_sblock_verify(
        struct xfs_buf          *bp,
        unsigned int            max_recs)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
        xfs_agblock_t           agno;
 
index e3b3e9d..fa3cd8a 100644 (file)
@@ -301,8 +301,7 @@ struct xfs_buf *                            /* buffer for fsbno */
 xfs_btree_get_bufl(
        struct xfs_mount        *mp,    /* file system mount point */
        struct xfs_trans        *tp,    /* transaction pointer */
-       xfs_fsblock_t           fsbno,  /* file system block number */
-       uint                    lock);  /* lock flags for get_buf */
+       xfs_fsblock_t           fsbno); /* file system block number */
 
 /*
  * Get a buffer for the block, return it with no data read.
@@ -313,8 +312,7 @@ xfs_btree_get_bufs(
        struct xfs_mount        *mp,    /* file system mount point */
        struct xfs_trans        *tp,    /* transaction pointer */
        xfs_agnumber_t          agno,   /* allocation group number */
-       xfs_agblock_t           agbno,  /* allocation group block number */
-       uint                    lock);  /* lock flags for get_buf */
+       xfs_agblock_t           agbno); /* allocation group block number */
 
 /*
  * Check for the cursor referring to the last block at the given level.
@@ -345,7 +343,6 @@ xfs_btree_read_bufl(
        struct xfs_mount        *mp,    /* file system mount point */
        struct xfs_trans        *tp,    /* transaction pointer */
        xfs_fsblock_t           fsbno,  /* file system block number */
-       uint                    lock,   /* lock flags for read_buf */
        struct xfs_buf          **bpp,  /* buffer for fsbno */
        int                     refval, /* ref count value for buffer */
        const struct xfs_buf_ops *ops);
@@ -383,8 +380,7 @@ xfs_btree_init_block(
        xfs_btnum_t     btnum,
        __u16           level,
        __u16           numrecs,
-       __u64           owner,
-       unsigned int    flags);
+       __u64           owner);
 
 void
 xfs_btree_init_block_int(
@@ -469,8 +465,8 @@ uint xfs_btree_compute_maxlevels(uint *limits, unsigned long len);
 unsigned long long xfs_btree_calc_size(uint *limits, unsigned long long len);
 
 /* return codes */
-#define XFS_BTREE_QUERY_RANGE_CONTINUE 0       /* keep iterating */
-#define XFS_BTREE_QUERY_RANGE_ABORT    1       /* stop iterating */
+#define XFS_BTREE_QUERY_RANGE_CONTINUE (XFS_ITER_CONTINUE) /* keep iterating */
+#define XFS_BTREE_QUERY_RANGE_ABORT    (XFS_ITER_ABORT)    /* stop iterating */
 typedef int (*xfs_btree_query_range_fn)(struct xfs_btree_cur *cur,
                union xfs_btree_rec *rec, void *priv);
 
index e2737e2..d1c77fd 100644 (file)
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
 #include "xfs_mount.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_dir2.h"
 #include "xfs_dir2_priv.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
-#include "xfs_inode_item.h"
-#include "xfs_alloc.h"
 #include "xfs_bmap.h"
-#include "xfs_attr.h"
 #include "xfs_attr_leaf.h"
 #include "xfs_error.h"
 #include "xfs_trace.h"
-#include "xfs_cksum.h"
 #include "xfs_buf_item.h"
 #include "xfs_log.h"
 
@@ -126,7 +120,7 @@ xfs_da3_blkinfo_verify(
        struct xfs_buf          *bp,
        struct xfs_da3_blkinfo  *hdr3)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_da_blkinfo   *hdr = &hdr3->hdr;
 
        if (!xfs_verify_magic16(bp, hdr->magic))
@@ -148,7 +142,7 @@ static xfs_failaddr_t
 xfs_da3_node_verify(
        struct xfs_buf          *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_da_intnode   *hdr = bp->b_addr;
        struct xfs_da3_icnode_hdr ichdr;
        const struct xfs_dir_ops *ops;
@@ -186,7 +180,7 @@ static void
 xfs_da3_node_write_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_buf_log_item *bip = bp->b_log_item;
        struct xfs_da3_node_hdr *hdr3 = bp->b_addr;
        xfs_failaddr_t          fa;
index b39053d..b1ae572 100644 (file)
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_inode.h"
 #include "xfs_dir2.h"
-#include "xfs_dir2_priv.h"
 
 /*
  * Shortform directory ops
index 1c6bf21..eb2be2a 100644 (file)
@@ -9,8 +9,6 @@
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_bit.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_defer.h"
 #include "xfs_trans.h"
index 156ce95..6784072 100644 (file)
@@ -5,20 +5,16 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
-#include "xfs_inode_item.h"
 #include "xfs_bmap.h"
 #include "xfs_dir2.h"
 #include "xfs_dir2_priv.h"
-#include "xfs_ialloc.h"
 #include "xfs_errortag.h"
 #include "xfs_error.h"
 #include "xfs_trace.h"
index b7d6d78..a6fb0cc 100644 (file)
@@ -6,22 +6,19 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
-#include "xfs_inode_item.h"
 #include "xfs_bmap.h"
 #include "xfs_buf_item.h"
 #include "xfs_dir2.h"
 #include "xfs_dir2_priv.h"
 #include "xfs_error.h"
 #include "xfs_trace.h"
-#include "xfs_cksum.h"
 #include "xfs_log.h"
 
 /*
@@ -50,7 +47,7 @@ static xfs_failaddr_t
 xfs_dir3_block_verify(
        struct xfs_buf          *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
 
        if (!xfs_verify_magic(bp, hdr3->magic))
@@ -71,7 +68,7 @@ static void
 xfs_dir3_block_read_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        xfs_failaddr_t          fa;
 
        if (xfs_sb_version_hascrc(&mp->m_sb) &&
@@ -88,7 +85,7 @@ static void
 xfs_dir3_block_write_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_buf_log_item *bip = bp->b_log_item;
        struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
        xfs_failaddr_t          fa;
index b7b9ce0..2c79be4 100644 (file)
@@ -6,19 +6,16 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_inode.h"
 #include "xfs_dir2.h"
-#include "xfs_dir2_priv.h"
 #include "xfs_error.h"
 #include "xfs_trans.h"
 #include "xfs_buf_item.h"
-#include "xfs_cksum.h"
 #include "xfs_log.h"
 
 static xfs_failaddr_t xfs_dir2_data_freefind_verify(
@@ -50,14 +47,13 @@ __xfs_dir3_data_check(
        int                     i;              /* leaf index */
        int                     lastfree;       /* last entry was unused */
        xfs_dir2_leaf_entry_t   *lep=NULL;      /* block leaf entries */
-       xfs_mount_t             *mp;            /* filesystem mount point */
+       struct xfs_mount        *mp = bp->b_mount;
        char                    *p;             /* current data position */
        int                     stale;          /* count of stale leaves */
        struct xfs_name         name;
        const struct xfs_dir_ops *ops;
        struct xfs_da_geometry  *geo;
 
-       mp = bp->b_target->bt_mount;
        geo = mp->m_dir_geo;
 
        /*
@@ -249,7 +245,7 @@ static xfs_failaddr_t
 xfs_dir3_data_verify(
        struct xfs_buf          *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
 
        if (!xfs_verify_magic(bp, hdr3->magic))
@@ -298,7 +294,7 @@ static void
 xfs_dir3_data_read_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        xfs_failaddr_t          fa;
 
        if (xfs_sb_version_hascrc(&mp->m_sb) &&
@@ -315,7 +311,7 @@ static void
 xfs_dir3_data_write_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_buf_log_item *bip = bp->b_log_item;
        struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
        xfs_failaddr_t          fa;
index 9c2a0a1..a53e458 100644 (file)
@@ -6,12 +6,11 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_inode.h"
 #include "xfs_bmap.h"
 #include "xfs_dir2.h"
@@ -20,8 +19,6 @@
 #include "xfs_trace.h"
 #include "xfs_trans.h"
 #include "xfs_buf_item.h"
-#include "xfs_cksum.h"
-#include "xfs_log.h"
 
 /*
  * Local function declarations.
@@ -144,7 +141,7 @@ static xfs_failaddr_t
 xfs_dir3_leaf_verify(
        struct xfs_buf          *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_dir2_leaf    *leaf = bp->b_addr;
        xfs_failaddr_t          fa;
 
@@ -159,7 +156,7 @@ static void
 xfs_dir3_leaf_read_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        xfs_failaddr_t          fa;
 
        if (xfs_sb_version_hascrc(&mp->m_sb) &&
@@ -176,7 +173,7 @@ static void
 xfs_dir3_leaf_write_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_buf_log_item *bip = bp->b_log_item;
        struct xfs_dir3_leaf_hdr *hdr3 = bp->b_addr;
        xfs_failaddr_t          fa;
index 16731d2..afcc664 100644 (file)
@@ -6,12 +6,11 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_inode.h"
 #include "xfs_bmap.h"
 #include "xfs_dir2.h"
@@ -20,7 +19,6 @@
 #include "xfs_trace.h"
 #include "xfs_trans.h"
 #include "xfs_buf_item.h"
-#include "xfs_cksum.h"
 #include "xfs_log.h"
 
 /*
@@ -84,7 +82,7 @@ static xfs_failaddr_t
 xfs_dir3_free_verify(
        struct xfs_buf          *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_dir2_free_hdr *hdr = bp->b_addr;
 
        if (!xfs_verify_magic(bp, hdr->magic))
@@ -110,7 +108,7 @@ static void
 xfs_dir3_free_read_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        xfs_failaddr_t          fa;
 
        if (xfs_sb_version_hascrc(&mp->m_sb) &&
@@ -127,7 +125,7 @@ static void
 xfs_dir3_free_write_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_buf_log_item *bip = bp->b_log_item;
        struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
        xfs_failaddr_t          fa;
index 585dfdb..0335892 100644 (file)
@@ -5,16 +5,13 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
-#include "xfs_inode_item.h"
-#include "xfs_error.h"
 #include "xfs_dir2.h"
 #include "xfs_dir2_priv.h"
 #include "xfs_trace.h"
index 88fa110..e8bd688 100644 (file)
@@ -16,8 +16,6 @@
 #include "xfs_trans.h"
 #include "xfs_qm.h"
 #include "xfs_error.h"
-#include "xfs_cksum.h"
-#include "xfs_trace.h"
 
 int
 xfs_calc_dquots_per_chunk(
@@ -224,7 +222,7 @@ static xfs_failaddr_t
 xfs_dquot_buf_verify_struct(
        struct xfs_buf          *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
 
        return xfs_dquot_buf_verify(mp, bp, false);
 }
@@ -233,7 +231,7 @@ static void
 xfs_dquot_buf_read_verify(
        struct xfs_buf          *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
 
        if (!xfs_dquot_buf_verify_crc(mp, bp, false))
                return;
@@ -250,7 +248,7 @@ static void
 xfs_dquot_buf_readahead_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
 
        if (!xfs_dquot_buf_verify_crc(mp, bp, true) ||
            xfs_dquot_buf_verify(mp, bp, true) != NULL) {
@@ -268,7 +266,7 @@ static void
 xfs_dquot_buf_write_verify(
        struct xfs_buf          *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
 
        xfs_dquot_buf_verify(mp, bp, false);
 }
index 9bb3c48..c968b60 100644 (file)
@@ -1071,7 +1071,7 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
 #define        XFS_INO_MASK(k)                 (uint32_t)((1ULL << (k)) - 1)
 #define        XFS_INO_OFFSET_BITS(mp)         (mp)->m_sb.sb_inopblog
 #define        XFS_INO_AGBNO_BITS(mp)          (mp)->m_sb.sb_agblklog
-#define        XFS_INO_AGINO_BITS(mp)          (mp)->m_agino_log
+#define        XFS_INO_AGINO_BITS(mp)          ((mp)->m_ino_geo.agino_log)
 #define        XFS_INO_AGNO_BITS(mp)           (mp)->m_agno_log
 #define        XFS_INO_BITS(mp)                \
        XFS_INO_AGNO_BITS(mp) + XFS_INO_AGINO_BITS(mp)
index e7382c7..52d03a3 100644 (file)
@@ -97,7 +97,7 @@ struct getbmapx {
  * For use by backup and restore programs to set the XFS on-disk inode
  * fields di_dmevmask and di_dmstate.  These must be set to exactly and
  * only values previously obtained via xfs_bulkstat!  (Specifically the
- * xfs_bstat_t fields bs_dmevmask and bs_dmstate.)
+ * struct xfs_bstat fields bs_dmevmask and bs_dmstate.)
  */
 #ifndef HAVE_FSDMIDATA
 struct fsdmidata {
@@ -328,7 +328,7 @@ typedef struct xfs_bstime {
        __s32           tv_nsec;        /* and nanoseconds      */
 } xfs_bstime_t;
 
-typedef struct xfs_bstat {
+struct xfs_bstat {
        __u64           bs_ino;         /* inode number                 */
        __u16           bs_mode;        /* type and mode                */
        __u16           bs_nlink;       /* number of links              */
@@ -356,7 +356,53 @@ typedef struct xfs_bstat {
        __u32           bs_dmevmask;    /* DMIG event mask              */
        __u16           bs_dmstate;     /* DMIG state info              */
        __u16           bs_aextents;    /* attribute number of extents  */
-} xfs_bstat_t;
+};
+
+/* New bulkstat structure that reports v5 features and fixes padding issues */
+struct xfs_bulkstat {
+       uint64_t        bs_ino;         /* inode number                 */
+       uint64_t        bs_size;        /* file size                    */
+
+       uint64_t        bs_blocks;      /* number of blocks             */
+       uint64_t        bs_xflags;      /* extended flags               */
+
+       uint64_t        bs_atime;       /* access time, seconds         */
+       uint64_t        bs_mtime;       /* modify time, seconds         */
+
+       uint64_t        bs_ctime;       /* inode change time, seconds   */
+       uint64_t        bs_btime;       /* creation time, seconds       */
+
+       uint32_t        bs_gen;         /* generation count             */
+       uint32_t        bs_uid;         /* user id                      */
+       uint32_t        bs_gid;         /* group id                     */
+       uint32_t        bs_projectid;   /* project id                   */
+
+       uint32_t        bs_atime_nsec;  /* access time, nanoseconds     */
+       uint32_t        bs_mtime_nsec;  /* modify time, nanoseconds     */
+       uint32_t        bs_ctime_nsec;  /* inode change time, nanoseconds */
+       uint32_t        bs_btime_nsec;  /* creation time, nanoseconds   */
+
+       uint32_t        bs_blksize;     /* block size                   */
+       uint32_t        bs_rdev;        /* device value                 */
+       uint32_t        bs_cowextsize_blks; /* cow extent size hint, blocks */
+       uint32_t        bs_extsize_blks; /* extent size hint, blocks    */
+
+       uint32_t        bs_nlink;       /* number of links              */
+       uint32_t        bs_extents;     /* number of extents            */
+       uint32_t        bs_aextents;    /* attribute number of extents  */
+       uint16_t        bs_version;     /* structure version            */
+       uint16_t        bs_forkoff;     /* inode fork offset in bytes   */
+
+       uint16_t        bs_sick;        /* sick inode metadata          */
+       uint16_t        bs_checked;     /* checked inode metadata       */
+       uint16_t        bs_mode;        /* type and mode                */
+       uint16_t        bs_pad2;        /* zeroed                       */
+
+       uint64_t        bs_pad[7];      /* zeroed                       */
+};
+
+#define XFS_BULKSTAT_VERSION_V1        (1)
+#define XFS_BULKSTAT_VERSION_V5        (5)
 
 /* bs_sick flags */
 #define XFS_BS_SICK_INODE      (1 << 0)  /* inode core */
@@ -374,7 +420,7 @@ typedef struct xfs_bstat {
  * to retain compatibility with "old" filesystems).
  */
 static inline uint32_t
-bstat_get_projid(struct xfs_bstat *bs)
+bstat_get_projid(const struct xfs_bstat *bs)
 {
        return (uint32_t)bs->bs_projid_hi << 16 | bs->bs_projid_lo;
 }
@@ -382,23 +428,79 @@ bstat_get_projid(struct xfs_bstat *bs)
 /*
  * The user-level BulkStat Request interface structure.
  */
-typedef struct xfs_fsop_bulkreq {
+struct xfs_fsop_bulkreq {
        __u64           __user *lastip; /* last inode # pointer         */
        __s32           icount;         /* count of entries in buffer   */
        void            __user *ubuffer;/* user buffer for inode desc.  */
        __s32           __user *ocount; /* output count pointer         */
-} xfs_fsop_bulkreq_t;
-
+};
 
 /*
  * Structures returned from xfs_inumbers routine (XFS_IOC_FSINUMBERS).
  */
-typedef struct xfs_inogrp {
+struct xfs_inogrp {
        __u64           xi_startino;    /* starting inode number        */
        __s32           xi_alloccount;  /* # bits set in allocmask      */
        __u64           xi_allocmask;   /* mask of allocated inodes     */
-} xfs_inogrp_t;
+};
 
+/* New inumbers structure that reports v5 features and fixes padding issues */
+struct xfs_inumbers {
+       uint64_t        xi_startino;    /* starting inode number        */
+       uint64_t        xi_allocmask;   /* mask of allocated inodes     */
+       uint8_t         xi_alloccount;  /* # bits set in allocmask      */
+       uint8_t         xi_version;     /* version                      */
+       uint8_t         xi_padding[6];  /* zero                         */
+};
+
+#define XFS_INUMBERS_VERSION_V1        (1)
+#define XFS_INUMBERS_VERSION_V5        (5)
+
+/* Header for bulk inode requests. */
+struct xfs_bulk_ireq {
+       uint64_t        ino;            /* I/O: start with this inode   */
+       uint32_t        flags;          /* I/O: operation flags         */
+       uint32_t        icount;         /* I: count of entries in buffer */
+       uint32_t        ocount;         /* O: count of entries filled out */
+       uint32_t        agno;           /* I: see comment for IREQ_AGNO */
+       uint64_t        reserved[5];    /* must be zero                 */
+};
+
+/*
+ * Only return results from the specified @agno.  If @ino is zero, start
+ * with the first inode of @agno.
+ */
+#define XFS_BULK_IREQ_AGNO     (1 << 0)
+
+/*
+ * Return bulkstat information for a single inode, where @ino value is a
+ * special value, not a literal inode number.  See the XFS_BULK_IREQ_SPECIAL_*
+ * values below.  Not compatible with XFS_BULK_IREQ_AGNO.
+ */
+#define XFS_BULK_IREQ_SPECIAL  (1 << 1)
+
+#define XFS_BULK_IREQ_FLAGS_ALL        (XFS_BULK_IREQ_AGNO | \
+                                XFS_BULK_IREQ_SPECIAL)
+
+/* Operate on the root directory inode. */
+#define XFS_BULK_IREQ_SPECIAL_ROOT     (1)
+
+/*
+ * ioctl structures for v5 bulkstat and inumbers requests
+ */
+struct xfs_bulkstat_req {
+       struct xfs_bulk_ireq    hdr;
+       struct xfs_bulkstat     bulkstat[];
+};
+#define XFS_BULKSTAT_REQ_SIZE(nr)      (sizeof(struct xfs_bulkstat_req) + \
+                                        (nr) * sizeof(struct xfs_bulkstat))
+
+struct xfs_inumbers_req {
+       struct xfs_bulk_ireq    hdr;
+       struct xfs_inumbers     inumbers[];
+};
+#define XFS_INUMBERS_REQ_SIZE(nr)      (sizeof(struct xfs_inumbers_req) + \
+                                        (nr) * sizeof(struct xfs_inumbers))
 
 /*
  * Error injection.
@@ -529,7 +631,7 @@ typedef struct xfs_swapext
        xfs_off_t       sx_offset;      /* offset into file */
        xfs_off_t       sx_length;      /* leng from offset */
        char            sx_pad[16];     /* pad space, unused */
-       xfs_bstat_t     sx_stat;        /* stat of target b4 copy */
+       struct xfs_bstat sx_stat;       /* stat of target b4 copy */
 } xfs_swapext_t;
 
 /*
@@ -701,6 +803,8 @@ struct xfs_scrub_metadata {
 #define XFS_IOC_FSGEOMETRY_V4       _IOR ('X', 124, struct xfs_fsop_geom_v4)
 #define XFS_IOC_GOINGDOWN           _IOR ('X', 125, uint32_t)
 #define XFS_IOC_FSGEOMETRY          _IOR ('X', 126, struct xfs_fsop_geom)
+#define XFS_IOC_BULKSTAT            _IOR ('X', 127, struct xfs_bulkstat_req)
+#define XFS_IOC_INUMBERS            _IOR ('X', 128, struct xfs_inumbers_req)
 /*     XFS_IOC_GETFSUUID ---------- deprecated 140      */
 
 
index 49ddfea..272005a 100644 (file)
@@ -185,6 +185,6 @@ xfs_inode_is_healthy(struct xfs_inode *ip)
 
 void xfs_fsop_geom_health(struct xfs_mount *mp, struct xfs_fsop_geom *geo);
 void xfs_ag_geom_health(struct xfs_perag *pag, struct xfs_ag_geometry *ageo);
-void xfs_bulkstat_health(struct xfs_inode *ip, struct xfs_bstat *bs);
+void xfs_bulkstat_health(struct xfs_inode *ip, struct xfs_bulkstat *bs);
 
 #endif /* __XFS_HEALTH_H__ */
index fe98988..04377ab 100644 (file)
 #include "xfs_bit.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
 #include "xfs_ialloc.h"
 #include "xfs_ialloc_btree.h"
 #include "xfs_alloc.h"
-#include "xfs_rtalloc.h"
 #include "xfs_errortag.h"
 #include "xfs_error.h"
 #include "xfs_bmap.h"
-#include "xfs_cksum.h"
 #include "xfs_trans.h"
 #include "xfs_buf_item.h"
 #include "xfs_icreate_item.h"
 #include "xfs_log.h"
 #include "xfs_rmap.h"
 
-
-/*
- * Allocation group level functions.
- */
-int
-xfs_ialloc_cluster_alignment(
-       struct xfs_mount        *mp)
-{
-       if (xfs_sb_version_hasalign(&mp->m_sb) &&
-           mp->m_sb.sb_inoalignmt >= xfs_icluster_size_fsb(mp))
-               return mp->m_sb.sb_inoalignmt;
-       return 1;
-}
-
 /*
  * Lookup a record by ino in the btree given by cur.
  */
@@ -299,7 +282,7 @@ xfs_ialloc_inode_init(
         * sizes, manipulate the inodes in buffers  which are multiples of the
         * blocks size.
         */
-       nbufs = length / mp->m_blocks_per_cluster;
+       nbufs = length / M_IGEO(mp)->blocks_per_cluster;
 
        /*
         * Figure out what version number to use in the inodes we create.  If
@@ -343,9 +326,10 @@ xfs_ialloc_inode_init(
                 * Get the block.
                 */
                d = XFS_AGB_TO_DADDR(mp, agno, agbno +
-                               (j * mp->m_blocks_per_cluster));
+                               (j * M_IGEO(mp)->blocks_per_cluster));
                fbuf = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
-                                        mp->m_bsize * mp->m_blocks_per_cluster,
+                                        mp->m_bsize *
+                                        M_IGEO(mp)->blocks_per_cluster,
                                         XBF_UNMAPPED);
                if (!fbuf)
                        return -ENOMEM;
@@ -353,7 +337,7 @@ xfs_ialloc_inode_init(
                /* Initialize the inode buffers and log them appropriately. */
                fbuf->b_ops = &xfs_inode_buf_ops;
                xfs_buf_zero(fbuf, 0, BBTOB(fbuf->b_length));
-               for (i = 0; i < mp->m_inodes_per_cluster; i++) {
+               for (i = 0; i < M_IGEO(mp)->inodes_per_cluster; i++) {
                        int     ioffset = i << mp->m_sb.sb_inodelog;
                        uint    isize = xfs_dinode_size(version);
 
@@ -616,24 +600,26 @@ error:
  * Allocate new inodes in the allocation group specified by agbp.
  * Return 0 for success, else error code.
  */
-STATIC int                             /* error code or 0 */
+STATIC int
 xfs_ialloc_ag_alloc(
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_buf_t       *agbp,          /* alloc group buffer */
-       int             *alloc)
+       struct xfs_trans        *tp,
+       struct xfs_buf          *agbp,
+       int                     *alloc)
 {
-       xfs_agi_t       *agi;           /* allocation group header */
-       xfs_alloc_arg_t args;           /* allocation argument structure */
-       xfs_agnumber_t  agno;
-       int             error;
-       xfs_agino_t     newino;         /* new first inode's number */
-       xfs_agino_t     newlen;         /* new number of inodes */
-       int             isaligned = 0;  /* inode allocation at stripe unit */
-                                       /* boundary */
-       uint16_t        allocmask = (uint16_t) -1; /* init. to full chunk */
+       struct xfs_agi          *agi;
+       struct xfs_alloc_arg    args;
+       xfs_agnumber_t          agno;
+       int                     error;
+       xfs_agino_t             newino;         /* new first inode's number */
+       xfs_agino_t             newlen;         /* new number of inodes */
+       int                     isaligned = 0;  /* inode allocation at stripe */
+                                               /* unit boundary */
+       /* init. to full chunk */
+       uint16_t                allocmask = (uint16_t) -1;
        struct xfs_inobt_rec_incore rec;
-       struct xfs_perag *pag;
-       int             do_sparse = 0;
+       struct xfs_perag        *pag;
+       struct xfs_ino_geometry *igeo = M_IGEO(tp->t_mountp);
+       int                     do_sparse = 0;
 
        memset(&args, 0, sizeof(args));
        args.tp = tp;
@@ -644,7 +630,7 @@ xfs_ialloc_ag_alloc(
 #ifdef DEBUG
        /* randomly do sparse inode allocations */
        if (xfs_sb_version_hassparseinodes(&tp->t_mountp->m_sb) &&
-           args.mp->m_ialloc_min_blks < args.mp->m_ialloc_blks)
+           igeo->ialloc_min_blks < igeo->ialloc_blks)
                do_sparse = prandom_u32() & 1;
 #endif
 
@@ -652,12 +638,12 @@ xfs_ialloc_ag_alloc(
         * Locking will ensure that we don't have two callers in here
         * at one time.
         */
-       newlen = args.mp->m_ialloc_inos;
-       if (args.mp->m_maxicount &&
+       newlen = igeo->ialloc_inos;
+       if (igeo->maxicount &&
            percpu_counter_read_positive(&args.mp->m_icount) + newlen >
-                                                       args.mp->m_maxicount)
+                                                       igeo->maxicount)
                return -ENOSPC;
-       args.minlen = args.maxlen = args.mp->m_ialloc_blks;
+       args.minlen = args.maxlen = igeo->ialloc_blks;
        /*
         * First try to allocate inodes contiguous with the last-allocated
         * chunk of inodes.  If the filesystem is striped, this will fill
@@ -667,7 +653,7 @@ xfs_ialloc_ag_alloc(
        newino = be32_to_cpu(agi->agi_newino);
        agno = be32_to_cpu(agi->agi_seqno);
        args.agbno = XFS_AGINO_TO_AGBNO(args.mp, newino) +
-                    args.mp->m_ialloc_blks;
+                    igeo->ialloc_blks;
        if (do_sparse)
                goto sparse_alloc;
        if (likely(newino != NULLAGINO &&
@@ -690,10 +676,10 @@ xfs_ialloc_ag_alloc(
                 * but not to use them in the actual exact allocation.
                 */
                args.alignment = 1;
-               args.minalignslop = args.mp->m_cluster_align - 1;
+               args.minalignslop = igeo->cluster_align - 1;
 
                /* Allow space for the inode btree to split. */
-               args.minleft = args.mp->m_in_maxlevels - 1;
+               args.minleft = igeo->inobt_maxlevels - 1;
                if ((error = xfs_alloc_vextent(&args)))
                        return error;
 
@@ -720,12 +706,12 @@ xfs_ialloc_ag_alloc(
                 * pieces, so don't need alignment anyway.
                 */
                isaligned = 0;
-               if (args.mp->m_sinoalign) {
+               if (igeo->ialloc_align) {
                        ASSERT(!(args.mp->m_flags & XFS_MOUNT_NOALIGN));
                        args.alignment = args.mp->m_dalign;
                        isaligned = 1;
                } else
-                       args.alignment = args.mp->m_cluster_align;
+                       args.alignment = igeo->cluster_align;
                /*
                 * Need to figure out where to allocate the inode blocks.
                 * Ideally they should be spaced out through the a.g.
@@ -741,7 +727,7 @@ xfs_ialloc_ag_alloc(
                /*
                 * Allow space for the inode btree to split.
                 */
-               args.minleft = args.mp->m_in_maxlevels - 1;
+               args.minleft = igeo->inobt_maxlevels - 1;
                if ((error = xfs_alloc_vextent(&args)))
                        return error;
        }
@@ -754,7 +740,7 @@ xfs_ialloc_ag_alloc(
                args.type = XFS_ALLOCTYPE_NEAR_BNO;
                args.agbno = be32_to_cpu(agi->agi_root);
                args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno);
-               args.alignment = args.mp->m_cluster_align;
+               args.alignment = igeo->cluster_align;
                if ((error = xfs_alloc_vextent(&args)))
                        return error;
        }
@@ -764,7 +750,7 @@ xfs_ialloc_ag_alloc(
         * the sparse allocation length is smaller than a full chunk.
         */
        if (xfs_sb_version_hassparseinodes(&args.mp->m_sb) &&
-           args.mp->m_ialloc_min_blks < args.mp->m_ialloc_blks &&
+           igeo->ialloc_min_blks < igeo->ialloc_blks &&
            args.fsbno == NULLFSBLOCK) {
 sparse_alloc:
                args.type = XFS_ALLOCTYPE_NEAR_BNO;
@@ -773,7 +759,7 @@ sparse_alloc:
                args.alignment = args.mp->m_sb.sb_spino_align;
                args.prod = 1;
 
-               args.minlen = args.mp->m_ialloc_min_blks;
+               args.minlen = igeo->ialloc_min_blks;
                args.maxlen = args.minlen;
 
                /*
@@ -789,7 +775,7 @@ sparse_alloc:
                args.min_agbno = args.mp->m_sb.sb_inoalignmt;
                args.max_agbno = round_down(args.mp->m_sb.sb_agblocks,
                                            args.mp->m_sb.sb_inoalignmt) -
-                                args.mp->m_ialloc_blks;
+                                igeo->ialloc_blks;
 
                error = xfs_alloc_vextent(&args);
                if (error)
@@ -1006,7 +992,7 @@ xfs_ialloc_ag_select(
                 * space needed for alignment of inode chunks when checking the
                 * longest contiguous free space in the AG - this prevents us
                 * from getting ENOSPC because we have free space larger than
-                * m_ialloc_blks but alignment constraints prevent us from using
+                * ialloc_blks but alignment constraints prevent us from using
                 * it.
                 *
                 * If we can't find an AG with space for full alignment slack to
@@ -1015,9 +1001,9 @@ xfs_ialloc_ag_select(
                 * if we fail allocation due to alignment issues then it is most
                 * likely a real ENOSPC condition.
                 */
-               ineed = mp->m_ialloc_min_blks;
+               ineed = M_IGEO(mp)->ialloc_min_blks;
                if (flags && ineed > 1)
-                       ineed += mp->m_cluster_align;
+                       ineed += M_IGEO(mp)->cluster_align;
                longest = pag->pagf_longest;
                if (!longest)
                        longest = pag->pagf_flcount > 0;
@@ -1703,6 +1689,7 @@ xfs_dialloc(
        int                     noroom = 0;
        xfs_agnumber_t          start_agno;
        struct xfs_perag        *pag;
+       struct xfs_ino_geometry *igeo = M_IGEO(mp);
        int                     okalloc = 1;
 
        if (*IO_agbp) {
@@ -1733,9 +1720,9 @@ xfs_dialloc(
         * Read rough value of mp->m_icount by percpu_counter_read_positive,
         * which will sacrifice the preciseness but improve the performance.
         */
-       if (mp->m_maxicount &&
-           percpu_counter_read_positive(&mp->m_icount) + mp->m_ialloc_inos
-                                                       > mp->m_maxicount) {
+       if (igeo->maxicount &&
+           percpu_counter_read_positive(&mp->m_icount) + igeo->ialloc_inos
+                                                       > igeo->maxicount) {
                noroom = 1;
                okalloc = 0;
        }
@@ -1852,7 +1839,8 @@ xfs_difree_inode_chunk(
        if (!xfs_inobt_issparse(rec->ir_holemask)) {
                /* not sparse, calculate extent info directly */
                xfs_bmap_add_free(tp, XFS_AGB_TO_FSB(mp, agno, sagbno),
-                                 mp->m_ialloc_blks, &XFS_RMAP_OINFO_INODES);
+                                 M_IGEO(mp)->ialloc_blks,
+                                 &XFS_RMAP_OINFO_INODES);
                return;
        }
 
@@ -2261,7 +2249,7 @@ xfs_imap_lookup(
 
        /* check that the returned record contains the required inode */
        if (rec.ir_startino > agino ||
-           rec.ir_startino + mp->m_ialloc_inos <= agino)
+           rec.ir_startino + M_IGEO(mp)->ialloc_inos <= agino)
                return -EINVAL;
 
        /* for untrusted inodes check it is allocated first */
@@ -2352,7 +2340,7 @@ xfs_imap(
         * If the inode cluster size is the same as the blocksize or
         * smaller we get to the buffer by simple arithmetics.
         */
-       if (mp->m_blocks_per_cluster == 1) {
+       if (M_IGEO(mp)->blocks_per_cluster == 1) {
                offset = XFS_INO_TO_OFFSET(mp, ino);
                ASSERT(offset < mp->m_sb.sb_inopblock);
 
@@ -2368,8 +2356,8 @@ xfs_imap(
         * find the location. Otherwise we have to do a btree
         * lookup to find the location.
         */
-       if (mp->m_inoalign_mask) {
-               offset_agbno = agbno & mp->m_inoalign_mask;
+       if (M_IGEO(mp)->inoalign_mask) {
+               offset_agbno = agbno & M_IGEO(mp)->inoalign_mask;
                chunk_agbno = agbno - offset_agbno;
        } else {
                error = xfs_imap_lookup(mp, tp, agno, agino, agbno,
@@ -2381,13 +2369,13 @@ xfs_imap(
 out_map:
        ASSERT(agbno >= chunk_agbno);
        cluster_agbno = chunk_agbno +
-               ((offset_agbno / mp->m_blocks_per_cluster) *
-                mp->m_blocks_per_cluster);
+               ((offset_agbno / M_IGEO(mp)->blocks_per_cluster) *
+                M_IGEO(mp)->blocks_per_cluster);
        offset = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) +
                XFS_INO_TO_OFFSET(mp, ino);
 
        imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, cluster_agbno);
-       imap->im_len = XFS_FSB_TO_BB(mp, mp->m_blocks_per_cluster);
+       imap->im_len = XFS_FSB_TO_BB(mp, M_IGEO(mp)->blocks_per_cluster);
        imap->im_boffset = (unsigned short)(offset << mp->m_sb.sb_inodelog);
 
        /*
@@ -2408,20 +2396,6 @@ out_map:
        return 0;
 }
 
-/*
- * Compute and fill in value of m_in_maxlevels.
- */
-void
-xfs_ialloc_compute_maxlevels(
-       xfs_mount_t     *mp)            /* file system mount structure */
-{
-       uint            inodes;
-
-       inodes = (1LL << XFS_INO_AGINO_BITS(mp)) >> XFS_INODES_PER_CHUNK_LOG;
-       mp->m_in_maxlevels = xfs_btree_compute_maxlevels(mp->m_inobt_mnr,
-                                                        inodes);
-}
-
 /*
  * Log specified fields for the ag hdr (inode section). The growth of the agi
  * structure over time requires that we interpret the buffer as two logical
@@ -2493,7 +2467,7 @@ static xfs_failaddr_t
 xfs_agi_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount *mp = bp->b_target->bt_mount;
+       struct xfs_mount *mp = bp->b_mount;
        struct xfs_agi  *agi = XFS_BUF_TO_AGI(bp);
        int             i;
 
@@ -2545,7 +2519,7 @@ static void
 xfs_agi_read_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount *mp = bp->b_target->bt_mount;
+       struct xfs_mount *mp = bp->b_mount;
        xfs_failaddr_t  fa;
 
        if (xfs_sb_version_hascrc(&mp->m_sb) &&
@@ -2562,7 +2536,7 @@ static void
 xfs_agi_write_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_buf_log_item *bip = bp->b_log_item;
        xfs_failaddr_t          fa;
 
@@ -2768,3 +2742,110 @@ xfs_ialloc_count_inodes(
        *freecount = ci.freecount;
        return 0;
 }
+
+/*
+ * Initialize inode-related geometry information.
+ *
+ * Compute the inode btree min and max levels and set maxicount.
+ *
+ * Set the inode cluster size.  This may still be overridden by the file
+ * system block size if it is larger than the chosen cluster size.
+ *
+ * For v5 filesystems, scale the cluster size with the inode size to keep a
+ * constant ratio of inode per cluster buffer, but only if mkfs has set the
+ * inode alignment value appropriately for larger cluster sizes.
+ *
+ * Then compute the inode cluster alignment information.
+ */
+void
+xfs_ialloc_setup_geometry(
+       struct xfs_mount        *mp)
+{
+       struct xfs_sb           *sbp = &mp->m_sb;
+       struct xfs_ino_geometry *igeo = M_IGEO(mp);
+       uint64_t                icount;
+       uint                    inodes;
+
+       /* Compute inode btree geometry. */
+       igeo->agino_log = sbp->sb_inopblog + sbp->sb_agblklog;
+       igeo->inobt_mxr[0] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 1);
+       igeo->inobt_mxr[1] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 0);
+       igeo->inobt_mnr[0] = igeo->inobt_mxr[0] / 2;
+       igeo->inobt_mnr[1] = igeo->inobt_mxr[1] / 2;
+
+       igeo->ialloc_inos = max_t(uint16_t, XFS_INODES_PER_CHUNK,
+                       sbp->sb_inopblock);
+       igeo->ialloc_blks = igeo->ialloc_inos >> sbp->sb_inopblog;
+
+       if (sbp->sb_spino_align)
+               igeo->ialloc_min_blks = sbp->sb_spino_align;
+       else
+               igeo->ialloc_min_blks = igeo->ialloc_blks;
+
+       /* Compute and fill in value of m_ino_geo.inobt_maxlevels. */
+       inodes = (1LL << XFS_INO_AGINO_BITS(mp)) >> XFS_INODES_PER_CHUNK_LOG;
+       igeo->inobt_maxlevels = xfs_btree_compute_maxlevels(igeo->inobt_mnr,
+                       inodes);
+
+       /* Set the maximum inode count for this filesystem. */
+       if (sbp->sb_imax_pct) {
+               /*
+                * Make sure the maximum inode count is a multiple
+                * of the units we allocate inodes in.
+                */
+               icount = sbp->sb_dblocks * sbp->sb_imax_pct;
+               do_div(icount, 100);
+               do_div(icount, igeo->ialloc_blks);
+               igeo->maxicount = XFS_FSB_TO_INO(mp,
+                               icount * igeo->ialloc_blks);
+       } else {
+               igeo->maxicount = 0;
+       }
+
+       /*
+        * Compute the desired size of an inode cluster buffer size, which
+        * starts at 8K and (on v5 filesystems) scales up with larger inode
+        * sizes.
+        *
+        * Preserve the desired inode cluster size because the sparse inodes
+        * feature uses that desired size (not the actual size) to compute the
+        * sparse inode alignment.  The mount code validates this value, so we
+        * cannot change the behavior.
+        */
+       igeo->inode_cluster_size_raw = XFS_INODE_BIG_CLUSTER_SIZE;
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               int     new_size = igeo->inode_cluster_size_raw;
+
+               new_size *= mp->m_sb.sb_inodesize / XFS_DINODE_MIN_SIZE;
+               if (mp->m_sb.sb_inoalignmt >= XFS_B_TO_FSBT(mp, new_size))
+                       igeo->inode_cluster_size_raw = new_size;
+       }
+
+       /* Calculate inode cluster ratios. */
+       if (igeo->inode_cluster_size_raw > mp->m_sb.sb_blocksize)
+               igeo->blocks_per_cluster = XFS_B_TO_FSBT(mp,
+                               igeo->inode_cluster_size_raw);
+       else
+               igeo->blocks_per_cluster = 1;
+       igeo->inode_cluster_size = XFS_FSB_TO_B(mp, igeo->blocks_per_cluster);
+       igeo->inodes_per_cluster = XFS_FSB_TO_INO(mp, igeo->blocks_per_cluster);
+
+       /* Calculate inode cluster alignment. */
+       if (xfs_sb_version_hasalign(&mp->m_sb) &&
+           mp->m_sb.sb_inoalignmt >= igeo->blocks_per_cluster)
+               igeo->cluster_align = mp->m_sb.sb_inoalignmt;
+       else
+               igeo->cluster_align = 1;
+       igeo->inoalign_mask = igeo->cluster_align - 1;
+       igeo->cluster_align_inodes = XFS_FSB_TO_INO(mp, igeo->cluster_align);
+
+       /*
+        * If we are using stripe alignment, check whether
+        * the stripe unit is a multiple of the inode alignment
+        */
+       if (mp->m_dalign && igeo->inoalign_mask &&
+           !(mp->m_dalign & igeo->inoalign_mask))
+               igeo->ialloc_align = mp->m_dalign;
+       else
+               igeo->ialloc_align = 0;
+}
index e936b7c..323592d 100644 (file)
@@ -23,16 +23,6 @@ struct xfs_icluster {
                                         * sparse chunks */
 };
 
-/* Calculate and return the number of filesystem blocks per inode cluster */
-static inline int
-xfs_icluster_size_fsb(
-       struct xfs_mount        *mp)
-{
-       if (mp->m_sb.sb_blocksize >= mp->m_inode_cluster_size)
-               return 1;
-       return mp->m_inode_cluster_size >> mp->m_sb.sb_blocklog;
-}
-
 /*
  * Make an inode pointer out of the buffer/offset.
  */
@@ -95,13 +85,6 @@ xfs_imap(
        struct xfs_imap *imap,          /* location map structure */
        uint            flags);         /* flags for inode btree lookup */
 
-/*
- * Compute and fill in value of m_in_maxlevels.
- */
-void
-xfs_ialloc_compute_maxlevels(
-       struct xfs_mount *mp);          /* file system mount structure */
-
 /*
  * Log specified fields for the ag hdr (inode section)
  */
@@ -168,5 +151,6 @@ int xfs_inobt_insert_rec(struct xfs_btree_cur *cur, uint16_t holemask,
                int *stat);
 
 int xfs_ialloc_cluster_alignment(struct xfs_mount *mp);
+void xfs_ialloc_setup_geometry(struct xfs_mount *mp);
 
 #endif /* __XFS_IALLOC_H__ */
index bc2dfac..b82992f 100644 (file)
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
 #include "xfs_mount.h"
-#include "xfs_inode.h"
 #include "xfs_btree.h"
 #include "xfs_ialloc.h"
 #include "xfs_ialloc_btree.h"
 #include "xfs_alloc.h"
 #include "xfs_error.h"
 #include "xfs_trace.h"
-#include "xfs_cksum.h"
 #include "xfs_trans.h"
 #include "xfs_rmap.h"
 
@@ -28,7 +26,7 @@ xfs_inobt_get_minrecs(
        struct xfs_btree_cur    *cur,
        int                     level)
 {
-       return cur->bc_mp->m_inobt_mnr[level != 0];
+       return M_IGEO(cur->bc_mp)->inobt_mnr[level != 0];
 }
 
 STATIC struct xfs_btree_cur *
@@ -164,7 +162,7 @@ xfs_inobt_get_maxrecs(
        struct xfs_btree_cur    *cur,
        int                     level)
 {
-       return cur->bc_mp->m_inobt_mxr[level != 0];
+       return M_IGEO(cur->bc_mp)->inobt_mxr[level != 0];
 }
 
 STATIC void
@@ -255,7 +253,7 @@ static xfs_failaddr_t
 xfs_inobt_verify(
        struct xfs_buf          *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
        xfs_failaddr_t          fa;
        unsigned int            level;
@@ -281,10 +279,11 @@ xfs_inobt_verify(
 
        /* level verification */
        level = be16_to_cpu(block->bb_level);
-       if (level >= mp->m_in_maxlevels)
+       if (level >= M_IGEO(mp)->inobt_maxlevels)
                return __this_address;
 
-       return xfs_btree_sblock_verify(bp, mp->m_inobt_mxr[level != 0]);
+       return xfs_btree_sblock_verify(bp,
+                       M_IGEO(mp)->inobt_mxr[level != 0]);
 }
 
 static void
@@ -546,7 +545,7 @@ xfs_inobt_max_size(
        xfs_agblock_t           agblocks = xfs_ag_block_count(mp, agno);
 
        /* Bail out if we're uninitialized, which can happen in mkfs. */
-       if (mp->m_inobt_mxr[0] == 0)
+       if (M_IGEO(mp)->inobt_mxr[0] == 0)
                return 0;
 
        /*
@@ -558,11 +557,41 @@ xfs_inobt_max_size(
            XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == agno)
                agblocks -= mp->m_sb.sb_logblocks;
 
-       return xfs_btree_calc_size(mp->m_inobt_mnr,
+       return xfs_btree_calc_size(M_IGEO(mp)->inobt_mnr,
                                (uint64_t)agblocks * mp->m_sb.sb_inopblock /
                                        XFS_INODES_PER_CHUNK);
 }
 
+/* Read AGI and create inobt cursor. */
+int
+xfs_inobt_cur(
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       xfs_agnumber_t          agno,
+       xfs_btnum_t             which,
+       struct xfs_btree_cur    **curpp,
+       struct xfs_buf          **agi_bpp)
+{
+       struct xfs_btree_cur    *cur;
+       int                     error;
+
+       ASSERT(*agi_bpp == NULL);
+       ASSERT(*curpp == NULL);
+
+       error = xfs_ialloc_read_agi(mp, tp, agno, agi_bpp);
+       if (error)
+               return error;
+
+       cur = xfs_inobt_init_cursor(mp, tp, *agi_bpp, agno, which);
+       if (!cur) {
+               xfs_trans_brelse(tp, *agi_bpp);
+               *agi_bpp = NULL;
+               return -ENOMEM;
+       }
+       *curpp = cur;
+       return 0;
+}
+
 static int
 xfs_inobt_count_blocks(
        struct xfs_mount        *mp,
@@ -571,15 +600,14 @@ xfs_inobt_count_blocks(
        xfs_btnum_t             btnum,
        xfs_extlen_t            *tree_blocks)
 {
-       struct xfs_buf          *agbp;
-       struct xfs_btree_cur    *cur;
+       struct xfs_buf          *agbp = NULL;
+       struct xfs_btree_cur    *cur = NULL;
        int                     error;
 
-       error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
+       error = xfs_inobt_cur(mp, tp, agno, btnum, &cur, &agbp);
        if (error)
                return error;
 
-       cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum);
        error = xfs_btree_count_blocks(cur, tree_blocks);
        xfs_btree_del_cursor(cur, error);
        xfs_trans_brelse(tp, agbp);
@@ -619,5 +647,5 @@ xfs_iallocbt_calc_size(
        struct xfs_mount        *mp,
        unsigned long long      len)
 {
-       return xfs_btree_calc_size(mp->m_inobt_mnr, len);
+       return xfs_btree_calc_size(M_IGEO(mp)->inobt_mnr, len);
 }
index ebdd0c6..951305e 100644 (file)
@@ -64,5 +64,8 @@ int xfs_finobt_calc_reserves(struct xfs_mount *mp, struct xfs_trans *tp,
                xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used);
 extern xfs_extlen_t xfs_iallocbt_calc_size(struct xfs_mount *mp,
                unsigned long long len);
+int xfs_inobt_cur(struct xfs_mount *mp, struct xfs_trans *tp,
+               xfs_agnumber_t agno, xfs_btnum_t btnum,
+               struct xfs_btree_cur **curpp, struct xfs_buf **agi_bpp);
 
 #endif /* __XFS_IALLOC_BTREE_H__ */
index bc690f2..27aa3f2 100644 (file)
@@ -3,18 +3,14 @@
  * Copyright (c) 2017 Christoph Hellwig.
  */
 
-#include <linux/cache.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
 #include "xfs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_bit.h"
 #include "xfs_log_format.h"
 #include "xfs_inode.h"
-#include "xfs_inode_fork.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_bmap.h"
 #include "xfs_trace.h"
 
 /*
index e021d51..28ab3c5 100644 (file)
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_errortag.h"
 #include "xfs_error.h"
-#include "xfs_cksum.h"
 #include "xfs_icache.h"
 #include "xfs_trans.h"
 #include "xfs_ialloc.h"
@@ -33,12 +31,9 @@ xfs_inobp_check(
        xfs_buf_t       *bp)
 {
        int             i;
-       int             j;
        xfs_dinode_t    *dip;
 
-       j = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog;
-
-       for (i = 0; i < j; i++) {
+       for (i = 0; i < M_IGEO(mp)->inodes_per_cluster; i++) {
                dip = xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize);
                if (!dip->di_next_unlinked)  {
                        xfs_alert(mp,
@@ -80,7 +75,7 @@ xfs_inode_buf_verify(
        struct xfs_buf  *bp,
        bool            readahead)
 {
-       struct xfs_mount *mp = bp->b_target->bt_mount;
+       struct xfs_mount *mp = bp->b_mount;
        xfs_agnumber_t  agno;
        int             i;
        int             ni;
index f9acf1d..bf3e040 100644 (file)
@@ -3,10 +3,10 @@
  * Copyright (c) 2000-2006 Silicon Graphics, Inc.
  * All Rights Reserved.
  */
-#include <linux/log2.h>
 
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_bmap.h"
 #include "xfs_error.h"
 #include "xfs_trace.h"
-#include "xfs_attr_sf.h"
 #include "xfs_da_format.h"
 #include "xfs_da_btree.h"
 #include "xfs_dir2_priv.h"
 #include "xfs_attr_leaf.h"
-#include "xfs_shared.h"
 
 kmem_zone_t *xfs_ifork_zone;
 
index 1b542ec..7f55eb3 100644 (file)
@@ -12,9 +12,7 @@
 #include "xfs_mount.h"
 #include "xfs_da_format.h"
 #include "xfs_trans_space.h"
-#include "xfs_inode.h"
 #include "xfs_da_btree.h"
-#include "xfs_attr_leaf.h"
 #include "xfs_bmap_btree.h"
 
 /*
index 542aa14..51bb9bd 100644 (file)
@@ -9,7 +9,6 @@
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_defer.h"
 #include "xfs_btree.h"
@@ -19,7 +18,6 @@
 #include "xfs_errortag.h"
 #include "xfs_error.h"
 #include "xfs_trace.h"
-#include "xfs_cksum.h"
 #include "xfs_trans.h"
 #include "xfs_bit.h"
 #include "xfs_refcount.h"
index 5d9de9b..38529db 100644 (file)
 #include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_btree.h"
-#include "xfs_bmap.h"
 #include "xfs_refcount_btree.h"
 #include "xfs_alloc.h"
 #include "xfs_error.h"
 #include "xfs_trace.h"
-#include "xfs_cksum.h"
 #include "xfs_trans.h"
 #include "xfs_bit.h"
 #include "xfs_rmap.h"
@@ -203,7 +201,7 @@ STATIC xfs_failaddr_t
 xfs_refcountbt_verify(
        struct xfs_buf          *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
        struct xfs_perag        *pag = bp->b_pag;
        xfs_failaddr_t          fa;
index 8ed8855..e6aeb39 100644 (file)
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_defer.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_btree.h"
 #include "xfs_trans.h"
 #include "xfs_alloc.h"
 #include "xfs_rmap.h"
 #include "xfs_rmap_btree.h"
-#include "xfs_trans_space.h"
 #include "xfs_trace.h"
 #include "xfs_errortag.h"
 #include "xfs_error.h"
-#include "xfs_extent_busy.h"
-#include "xfs_bmap.h"
 #include "xfs_inode.h"
-#include "xfs_ialloc.h"
 
 /*
  * Lookup the first record less than or equal to [bno, len, owner, offset]
index 5d1f888..fc78efa 100644 (file)
@@ -9,18 +9,14 @@
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_bit.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
-#include "xfs_inode.h"
 #include "xfs_trans.h"
 #include "xfs_alloc.h"
 #include "xfs_btree.h"
 #include "xfs_rmap.h"
 #include "xfs_rmap_btree.h"
 #include "xfs_trace.h"
-#include "xfs_cksum.h"
 #include "xfs_error.h"
 #include "xfs_extent_busy.h"
 #include "xfs_ag_resv.h"
@@ -292,7 +288,7 @@ static xfs_failaddr_t
 xfs_rmapbt_verify(
        struct xfs_buf          *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
        struct xfs_perag        *pag = bp->b_pag;
        xfs_failaddr_t          fa;
index eaaff67..8ea1efc 100644 (file)
 #include "xfs_mount.h"
 #include "xfs_inode.h"
 #include "xfs_bmap.h"
-#include "xfs_bmap_util.h"
-#include "xfs_bmap_btree.h"
-#include "xfs_alloc.h"
-#include "xfs_error.h"
 #include "xfs_trans.h"
-#include "xfs_trans_space.h"
-#include "xfs_trace.h"
-#include "xfs_buf.h"
-#include "xfs_icache.h"
 #include "xfs_rtalloc.h"
 
 
index e76a3e5..a08dd8f 100644 (file)
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
-#include "xfs_inode.h"
 #include "xfs_ialloc.h"
 #include "xfs_alloc.h"
 #include "xfs_error.h"
 #include "xfs_trace.h"
-#include "xfs_cksum.h"
 #include "xfs_trans.h"
 #include "xfs_buf_item.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
 #include "xfs_log.h"
 #include "xfs_rmap_btree.h"
-#include "xfs_bmap.h"
 #include "xfs_refcount_btree.h"
 #include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_health.h"
 
 /*
@@ -686,7 +679,7 @@ xfs_sb_read_verify(
        struct xfs_buf          *bp)
 {
        struct xfs_sb           sb;
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_dsb          *dsb = XFS_BUF_TO_SBP(bp);
        int                     error;
 
@@ -752,7 +745,7 @@ xfs_sb_write_verify(
        struct xfs_buf          *bp)
 {
        struct xfs_sb           sb;
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_buf_log_item *bip = bp->b_log_item;
        int                     error;
 
@@ -800,12 +793,14 @@ const struct xfs_buf_ops xfs_sb_quiet_buf_ops = {
  *
  * Mount initialization code establishing various mount
  * fields from the superblock associated with the given
- * mount structure
+ * mount structure.
+ *
+ * Inode geometry are calculated in xfs_ialloc_setup_geometry.
  */
 void
 xfs_sb_mount_common(
-       struct xfs_mount *mp,
-       struct xfs_sb   *sbp)
+       struct xfs_mount        *mp,
+       struct xfs_sb           *sbp)
 {
        mp->m_agfrotor = mp->m_agirotor = 0;
        mp->m_maxagi = mp->m_sb.sb_agcount;
@@ -813,7 +808,6 @@ xfs_sb_mount_common(
        mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT;
        mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT;
        mp->m_agno_log = xfs_highbit32(sbp->sb_agcount - 1) + 1;
-       mp->m_agino_log = sbp->sb_inopblog + sbp->sb_agblklog;
        mp->m_blockmask = sbp->sb_blocksize - 1;
        mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG;
        mp->m_blockwmask = mp->m_blockwsize - 1;
@@ -823,11 +817,6 @@ xfs_sb_mount_common(
        mp->m_alloc_mnr[0] = mp->m_alloc_mxr[0] / 2;
        mp->m_alloc_mnr[1] = mp->m_alloc_mxr[1] / 2;
 
-       mp->m_inobt_mxr[0] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 1);
-       mp->m_inobt_mxr[1] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 0);
-       mp->m_inobt_mnr[0] = mp->m_inobt_mxr[0] / 2;
-       mp->m_inobt_mnr[1] = mp->m_inobt_mxr[1] / 2;
-
        mp->m_bmap_dmxr[0] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 1);
        mp->m_bmap_dmxr[1] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 0);
        mp->m_bmap_dmnr[0] = mp->m_bmap_dmxr[0] / 2;
@@ -844,14 +833,6 @@ xfs_sb_mount_common(
        mp->m_refc_mnr[1] = mp->m_refc_mxr[1] / 2;
 
        mp->m_bsize = XFS_FSB_TO_BB(mp, 1);
-       mp->m_ialloc_inos = max_t(uint16_t, XFS_INODES_PER_CHUNK,
-                                       sbp->sb_inopblock);
-       mp->m_ialloc_blks = mp->m_ialloc_inos >> sbp->sb_inopblog;
-
-       if (sbp->sb_spino_align)
-               mp->m_ialloc_min_blks = sbp->sb_spino_align;
-       else
-               mp->m_ialloc_min_blks = mp->m_ialloc_blks;
        mp->m_alloc_set_aside = xfs_alloc_set_aside(mp);
        mp->m_ag_max_usable = xfs_alloc_ag_max_usable(mp);
 }
@@ -939,7 +920,7 @@ xfs_log_sb(
        struct xfs_trans        *tp)
 {
        struct xfs_mount        *mp = tp->t_mountp;
-       struct xfs_buf          *bp = xfs_trans_getsb(tp, mp, 0);
+       struct xfs_buf          *bp = xfs_trans_getsb(tp, mp);
 
        mp->m_sb.sb_icount = percpu_counter_sum(&mp->m_icount);
        mp->m_sb.sb_ifree = percpu_counter_sum(&mp->m_ifree);
@@ -1005,7 +986,7 @@ xfs_update_secondary_sbs(
 
                bp = xfs_buf_get(mp->m_ddev_targp,
                                 XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
-                                XFS_FSS_TO_BB(mp, 1), 0);
+                                XFS_FSS_TO_BB(mp, 1));
                /*
                 * If we get an error reading or writing alternate superblocks,
                 * continue.  xfs_repair chooses the "best" superblock based
@@ -1069,7 +1050,7 @@ xfs_sync_sb_buf(
        if (error)
                return error;
 
-       bp = xfs_trans_getsb(tp, mp, 0);
+       bp = xfs_trans_getsb(tp, mp);
        xfs_log_sb(tp);
        xfs_trans_bhold(tp, bp);
        xfs_trans_set_sync(tp);
index 4e90979..e0641b7 100644 (file)
@@ -65,7 +65,6 @@ void  xfs_log_get_max_trans_res(struct xfs_mount *mp,
 #define XFS_TRANS_DQ_DIRTY     0x10    /* at least one dquot in trx dirty */
 #define XFS_TRANS_RESERVE      0x20    /* OK to use reserved data blocks */
 #define XFS_TRANS_NO_WRITECOUNT 0x40   /* do not elevate SB writecount */
-#define XFS_TRANS_NOFS         0x80    /* pass KM_NOFS to kmem_alloc */
 /*
  * LOWMODE is used by the allocator to activate the lowspace algorithm - when
  * free space is running low the extent allocator may choose to allocate an
@@ -136,4 +135,52 @@ void xfs_symlink_local_to_remote(struct xfs_trans *tp, struct xfs_buf *bp,
                                 struct xfs_inode *ip, struct xfs_ifork *ifp);
 xfs_failaddr_t xfs_symlink_shortform_verify(struct xfs_inode *ip);
 
+/* Computed inode geometry for the filesystem. */
+struct xfs_ino_geometry {
+       /* Maximum inode count in this filesystem. */
+       uint64_t        maxicount;
+
+       /* Actual inode cluster buffer size, in bytes. */
+       unsigned int    inode_cluster_size;
+
+       /*
+        * Desired inode cluster buffer size, in bytes.  This value is not
+        * rounded up to at least one filesystem block, which is necessary for
+        * the sole purpose of validating sb_spino_align.  Runtime code must
+        * only ever use inode_cluster_size.
+        */
+       unsigned int    inode_cluster_size_raw;
+
+       /* Inode cluster sizes, adjusted to be at least 1 fsb. */
+       unsigned int    inodes_per_cluster;
+       unsigned int    blocks_per_cluster;
+
+       /* Inode cluster alignment. */
+       unsigned int    cluster_align;
+       unsigned int    cluster_align_inodes;
+       unsigned int    inoalign_mask;  /* mask sb_inoalignmt if used */
+
+       unsigned int    inobt_mxr[2]; /* max inobt btree records */
+       unsigned int    inobt_mnr[2]; /* min inobt btree records */
+       unsigned int    inobt_maxlevels; /* max inobt btree levels. */
+
+       /* Size of inode allocations under normal operation. */
+       unsigned int    ialloc_inos;
+       unsigned int    ialloc_blks;
+
+       /* Minimum inode blocks for a sparse allocation. */
+       unsigned int    ialloc_min_blks;
+
+       /* stripe unit inode alignment */
+       unsigned int    ialloc_align;
+
+       unsigned int    agino_log;      /* #bits for agino in inum */
+};
+
+/* Keep iterating the data structure. */
+#define XFS_ITER_CONTINUE      (0)
+
+/* Stop iterating the data structure. */
+#define XFS_ITER_ABORT         (1)
+
 #endif /* __XFS_SHARED_H__ */
index a0ccc25..3b8260c 100644 (file)
 #include "xfs_shared.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_bmap_btree.h"
 #include "xfs_inode.h"
 #include "xfs_error.h"
-#include "xfs_trace.h"
-#include "xfs_symlink.h"
-#include "xfs_cksum.h"
 #include "xfs_trans.h"
 #include "xfs_buf_item.h"
 #include "xfs_log.h"
@@ -90,7 +86,7 @@ static xfs_failaddr_t
 xfs_symlink_verify(
        struct xfs_buf          *bp)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        struct xfs_dsymlink_hdr *dsl = bp->b_addr;
 
        if (!xfs_sb_version_hascrc(&mp->m_sb))
@@ -116,7 +112,7 @@ static void
 xfs_symlink_read_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount *mp = bp->b_target->bt_mount;
+       struct xfs_mount *mp = bp->b_mount;
        xfs_failaddr_t  fa;
 
        /* no verification of non-crc buffers */
@@ -136,7 +132,7 @@ static void
 xfs_symlink_write_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_mount *mp = bp->b_target->bt_mount;
+       struct xfs_mount *mp = bp->b_mount;
        struct xfs_buf_log_item *bip = bp->b_log_item;
        xfs_failaddr_t          fa;
 
index 83f4ee2..d12bbd5 100644 (file)
 #include "xfs_da_btree.h"
 #include "xfs_inode.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_ialloc.h"
 #include "xfs_quota.h"
 #include "xfs_trans.h"
 #include "xfs_qm.h"
 #include "xfs_trans_space.h"
-#include "xfs_trace.h"
 
 #define _ALLOC true
 #define _FREE  false
@@ -136,9 +134,10 @@ STATIC uint
 xfs_calc_inobt_res(
        struct xfs_mount        *mp)
 {
-       return xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) +
-               xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1),
-                                XFS_FSB_TO_B(mp, 1));
+       return xfs_calc_buf_res(M_IGEO(mp)->inobt_maxlevels,
+                       XFS_FSB_TO_B(mp, 1)) +
+                               xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1),
+                       XFS_FSB_TO_B(mp, 1));
 }
 
 /*
@@ -167,7 +166,7 @@ xfs_calc_finobt_res(
  * includes:
  *
  * the allocation btrees: 2 trees * (max depth - 1) * block size
- * the inode chunk: m_ialloc_blks * N
+ * the inode chunk: m_ino_geo.ialloc_blks * N
  *
  * The size N of the inode chunk reservation depends on whether it is for
  * allocation or free and which type of create transaction is in use. An inode
@@ -193,7 +192,7 @@ xfs_calc_inode_chunk_res(
                size = XFS_FSB_TO_B(mp, 1);
        }
 
-       res += xfs_calc_buf_res(mp->m_ialloc_blks, size);
+       res += xfs_calc_buf_res(M_IGEO(mp)->ialloc_blks, size);
        return res;
 }
 
@@ -307,7 +306,7 @@ xfs_calc_iunlink_remove_reservation(
        struct xfs_mount        *mp)
 {
        return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
-              2 * max_t(uint, XFS_FSB_TO_B(mp, 1), mp->m_inode_cluster_size);
+              2 * M_IGEO(mp)->inode_cluster_size;
 }
 
 /*
@@ -345,7 +344,7 @@ STATIC uint
 xfs_calc_iunlink_add_reservation(xfs_mount_t *mp)
 {
        return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
-               max_t(uint, XFS_FSB_TO_B(mp, 1), mp->m_inode_cluster_size);
+                       M_IGEO(mp)->inode_cluster_size;
 }
 
 /*
index a62fb95..88221c7 100644 (file)
@@ -56,9 +56,9 @@
 #define        XFS_DIRREMOVE_SPACE_RES(mp)     \
        XFS_DAREMOVE_SPACE_RES(mp, XFS_DATA_FORK)
 #define        XFS_IALLOC_SPACE_RES(mp)        \
-       ((mp)->m_ialloc_blks + \
+       (M_IGEO(mp)->ialloc_blks + \
         (xfs_sb_version_hasfinobt(&mp->m_sb) ? 2 : 1 * \
-         ((mp)->m_in_maxlevels - 1)))
+         (M_IGEO(mp)->inobt_maxlevels - 1)))
 
 /*
  * Space reservation values for various transactions.
@@ -94,7 +94,8 @@
 #define        XFS_SYMLINK_SPACE_RES(mp,nl,b)  \
        (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b))
 #define XFS_IFREE_SPACE_RES(mp)                \
-       (xfs_sb_version_hasfinobt(&mp->m_sb) ? (mp)->m_in_maxlevels : 0)
+       (xfs_sb_version_hasfinobt(&mp->m_sb) ? \
+                       M_IGEO(mp)->inobt_maxlevels : 0)
 
 
 #endif /* __XFS_TRANS_SPACE_H__ */
index d51acc9..4f59554 100644 (file)
@@ -7,19 +7,10 @@
 #include "xfs.h"
 #include "xfs_fs.h"
 #include "xfs_format.h"
-#include "xfs_log_format.h"
 #include "xfs_shared.h"
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
-#include "xfs_inode.h"
-#include "xfs_btree.h"
-#include "xfs_rmap.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_alloc.h"
-#include "xfs_ialloc.h"
 
 /* Find the size of the AG, in blocks. */
 xfs_agblock_t
@@ -87,14 +78,14 @@ xfs_agino_range(
         * Calculate the first inode, which will be in the first
         * cluster-aligned block after the AGFL.
         */
-       bno = round_up(XFS_AGFL_BLOCK(mp) + 1, mp->m_cluster_align);
+       bno = round_up(XFS_AGFL_BLOCK(mp) + 1, M_IGEO(mp)->cluster_align);
        *first = XFS_AGB_TO_AGINO(mp, bno);
 
        /*
         * Calculate the last inode, which will be at the end of the
         * last (aligned) cluster that can be allocated in the AG.
         */
-       bno = round_down(eoag, mp->m_cluster_align);
+       bno = round_down(eoag, M_IGEO(mp)->cluster_align);
        *last = XFS_AGB_TO_AGINO(mp, bno) - 1;
 }
 
index adaeabd..16b09b9 100644 (file)
@@ -9,20 +9,13 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_btree.h"
-#include "xfs_bit.h"
-#include "xfs_log_format.h"
-#include "xfs_trans.h"
 #include "xfs_sb.h"
-#include "xfs_inode.h"
 #include "xfs_alloc.h"
 #include "xfs_ialloc.h"
 #include "xfs_rmap.h"
-#include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
-#include "scrub/trace.h"
 
 /* Superblock */
 
@@ -646,7 +639,7 @@ xchk_agfl_block(
        xchk_agfl_block_xref(sc, agbno);
 
        if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
-               return XFS_BTREE_QUERY_RANGE_ABORT;
+               return XFS_ITER_ABORT;
 
        return 0;
 }
@@ -737,7 +730,7 @@ xchk_agfl(
        /* Check the blocks in the AGFL. */
        error = xfs_agfl_walk(sc->mp, XFS_BUF_TO_AGF(sc->sa.agf_bp),
                        sc->sa.agfl_bp, xchk_agfl_block, &sai);
-       if (error == XFS_BTREE_QUERY_RANGE_ABORT) {
+       if (error == XFS_ITER_ABORT) {
                error = 0;
                goto out_free;
        }
index 64e31f8..7a1a38b 100644 (file)
@@ -9,22 +9,17 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_btree.h"
-#include "xfs_bit.h"
 #include "xfs_log_format.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
-#include "xfs_inode.h"
 #include "xfs_alloc.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc.h"
 #include "xfs_ialloc_btree.h"
 #include "xfs_rmap.h"
 #include "xfs_rmap_btree.h"
-#include "xfs_refcount.h"
 #include "xfs_refcount_btree.h"
-#include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/trace.h"
index 44883e9..a43d181 100644 (file)
@@ -9,19 +9,12 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_btree.h"
-#include "xfs_bit.h"
-#include "xfs_log_format.h"
-#include "xfs_trans.h"
-#include "xfs_sb.h"
 #include "xfs_alloc.h"
 #include "xfs_rmap.h"
-#include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/btree.h"
-#include "scrub/trace.h"
 
 /*
  * Set us up to scrub free space btrees.
index dce74ec..1afc58b 100644 (file)
@@ -9,26 +9,62 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
-#include "xfs_btree.h"
-#include "xfs_bit.h"
 #include "xfs_log_format.h"
-#include "xfs_trans.h"
-#include "xfs_sb.h"
 #include "xfs_inode.h"
 #include "xfs_da_format.h"
 #include "xfs_da_btree.h"
-#include "xfs_dir2.h"
 #include "xfs_attr.h"
 #include "xfs_attr_leaf.h"
-#include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/dabtree.h"
-#include "scrub/trace.h"
+#include "scrub/attr.h"
 
-#include <linux/posix_acl_xattr.h>
-#include <linux/xattr.h>
+/*
+ * Allocate enough memory to hold an attr value and attr block bitmaps,
+ * reallocating the buffer if necessary.  Buffer contents are not preserved
+ * across a reallocation.
+ */
+int
+xchk_setup_xattr_buf(
+       struct xfs_scrub        *sc,
+       size_t                  value_size,
+       xfs_km_flags_t          flags)
+{
+       size_t                  sz;
+       struct xchk_xattr_buf   *ab = sc->buf;
+
+       /*
+        * We need enough space to read an xattr value from the file or enough
+        * space to hold three copies of the xattr free space bitmap.  We don't
+        * need the buffer space for both purposes at the same time.
+        */
+       sz = 3 * sizeof(long) * BITS_TO_LONGS(sc->mp->m_attr_geo->blksize);
+       sz = max_t(size_t, sz, value_size);
+
+       /*
+        * If there's already a buffer, figure out if we need to reallocate it
+        * to accommodate a larger size.
+        */
+       if (ab) {
+               if (sz <= ab->sz)
+                       return 0;
+               kmem_free(ab);
+               sc->buf = NULL;
+       }
+
+       /*
+        * Don't zero the buffer upon allocation to avoid runtime overhead.
+        * All users must be careful never to read uninitialized contents.
+        */
+       ab = kmem_alloc_large(sizeof(*ab) + sz, flags);
+       if (!ab)
+               return -ENOMEM;
+
+       ab->sz = sz;
+       sc->buf = ab;
+       return 0;
+}
 
 /* Set us up to scrub an inode's extended attributes. */
 int
@@ -36,19 +72,18 @@ xchk_setup_xattr(
        struct xfs_scrub        *sc,
        struct xfs_inode        *ip)
 {
-       size_t                  sz;
+       int                     error;
 
        /*
-        * Allocate the buffer without the inode lock held.  We need enough
-        * space to read every xattr value in the file or enough space to
-        * hold three copies of the xattr free space bitmap.  (Not both at
-        * the same time.)
+        * We failed to get memory while checking attrs, so this time try to
+        * get all the memory we're ever going to need.  Allocate the buffer
+        * without the inode lock held, which means we can sleep.
         */
-       sz = max_t(size_t, XATTR_SIZE_MAX, 3 * sizeof(long) *
-                       BITS_TO_LONGS(sc->mp->m_attr_geo->blksize));
-       sc->buf = kmem_zalloc_large(sz, KM_SLEEP);
-       if (!sc->buf)
-               return -ENOMEM;
+       if (sc->flags & XCHK_TRY_HARDER) {
+               error = xchk_setup_xattr_buf(sc, XATTR_SIZE_MAX, KM_SLEEP);
+               if (error)
+                       return error;
+       }
 
        return xchk_setup_inode_contents(sc, ip, 0);
 }
@@ -83,7 +118,7 @@ xchk_xattr_listent(
        sx = container_of(context, struct xchk_xattr, context);
 
        if (xchk_should_terminate(sx->sc, &error)) {
-               context->seen_enough = 1;
+               context->seen_enough = error;
                return;
        }
 
@@ -99,6 +134,19 @@ xchk_xattr_listent(
                return;
        }
 
+       /*
+        * Try to allocate enough memory to extrat the attr value.  If that
+        * doesn't work, we overload the seen_enough variable to convey
+        * the error message back to the main scrub function.
+        */
+       error = xchk_setup_xattr_buf(sx->sc, valuelen, KM_MAYFAIL);
+       if (error == -ENOMEM)
+               error = -EDEADLOCK;
+       if (error) {
+               context->seen_enough = error;
+               return;
+       }
+
        args.flags = ATTR_KERNOTIME;
        if (flags & XFS_ATTR_ROOT)
                args.flags |= ATTR_ROOT;
@@ -111,8 +159,8 @@ xchk_xattr_listent(
        args.namelen = namelen;
        args.hashval = xfs_da_hashname(args.name, args.namelen);
        args.trans = context->tp;
-       args.value = sx->sc->buf;
-       args.valuelen = XATTR_SIZE_MAX;
+       args.value = xchk_xattr_valuebuf(sx->sc);
+       args.valuelen = valuelen;
 
        error = xfs_attr_get_ilocked(context->dp, &args);
        if (error == -EEXIST)
@@ -125,7 +173,7 @@ xchk_xattr_listent(
                                             args.blkno);
 fail_xref:
        if (sx->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
-               context->seen_enough = 1;
+               context->seen_enough = XFS_ITER_ABORT;
        return;
 }
 
@@ -170,13 +218,12 @@ xchk_xattr_check_freemap(
        unsigned long                   *map,
        struct xfs_attr3_icleaf_hdr     *leafhdr)
 {
-       unsigned long                   *freemap;
-       unsigned long                   *dstmap;
+       unsigned long                   *freemap = xchk_xattr_freemap(sc);
+       unsigned long                   *dstmap = xchk_xattr_dstmap(sc);
        unsigned int                    mapsize = sc->mp->m_attr_geo->blksize;
        int                             i;
 
        /* Construct bitmap of freemap contents. */
-       freemap = (unsigned long *)sc->buf + BITS_TO_LONGS(mapsize);
        bitmap_zero(freemap, mapsize);
        for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
                if (!xchk_xattr_set_map(sc, freemap,
@@ -186,7 +233,6 @@ xchk_xattr_check_freemap(
        }
 
        /* Look for bits that are set in freemap and are marked in use. */
-       dstmap = freemap + BITS_TO_LONGS(mapsize);
        return bitmap_and(dstmap, freemap, map, mapsize) == 0;
 }
 
@@ -201,13 +247,13 @@ xchk_xattr_entry(
        char                            *buf_end,
        struct xfs_attr_leafblock       *leaf,
        struct xfs_attr3_icleaf_hdr     *leafhdr,
-       unsigned long                   *usedmap,
        struct xfs_attr_leaf_entry      *ent,
        int                             idx,
        unsigned int                    *usedbytes,
        __u32                           *last_hashval)
 {
        struct xfs_mount                *mp = ds->state->mp;
+       unsigned long                   *usedmap = xchk_xattr_usedmap(ds->sc);
        char                            *name_end;
        struct xfs_attr_leaf_name_local *lentry;
        struct xfs_attr_leaf_name_remote *rentry;
@@ -267,16 +313,26 @@ xchk_xattr_block(
        struct xfs_attr_leafblock       *leaf = bp->b_addr;
        struct xfs_attr_leaf_entry      *ent;
        struct xfs_attr_leaf_entry      *entries;
-       unsigned long                   *usedmap = ds->sc->buf;
+       unsigned long                   *usedmap;
        char                            *buf_end;
        size_t                          off;
        __u32                           last_hashval = 0;
        unsigned int                    usedbytes = 0;
        unsigned int                    hdrsize;
        int                             i;
+       int                             error;
 
        if (*last_checked == blk->blkno)
                return 0;
+
+       /* Allocate memory for block usage checking. */
+       error = xchk_setup_xattr_buf(ds->sc, 0, KM_MAYFAIL);
+       if (error == -ENOMEM)
+               return -EDEADLOCK;
+       if (error)
+               return error;
+       usedmap = xchk_xattr_usedmap(ds->sc);
+
        *last_checked = blk->blkno;
        bitmap_zero(usedmap, mp->m_attr_geo->blksize);
 
@@ -324,7 +380,7 @@ xchk_xattr_block(
 
                /* Check the entry and nameval. */
                xchk_xattr_entry(ds, level, buf_end, leaf, &leafhdr,
-                               usedmap, ent, i, &usedbytes, &last_hashval);
+                               ent, i, &usedbytes, &last_hashval);
 
                if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
                        goto out;
@@ -464,6 +520,10 @@ xchk_xattr(
        error = xfs_attr_list_int_ilocked(&sx.context);
        if (!xchk_fblock_process_error(sc, XFS_ATTR_FORK, 0, &error))
                goto out;
+
+       /* Did our listent function try to return any errors? */
+       if (sx.context.seen_enough < 0)
+               error = sx.context.seen_enough;
 out:
        return error;
 }
diff --git a/fs/xfs/scrub/attr.h b/fs/xfs/scrub/attr.h
new file mode 100644 (file)
index 0000000..13a1d2e
--- /dev/null
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2019 Oracle.  All Rights Reserved.
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ */
+#ifndef __XFS_SCRUB_ATTR_H__
+#define __XFS_SCRUB_ATTR_H__
+
+/*
+ * Temporary storage for online scrub and repair of extended attributes.
+ */
+struct xchk_xattr_buf {
+       /* Size of @buf, in bytes. */
+       size_t                  sz;
+
+       /*
+        * Memory buffer -- either used for extracting attr values while
+        * walking the attributes; or for computing attr block bitmaps when
+        * checking the attribute tree.
+        *
+        * Each bitmap contains enough bits to track every byte in an attr
+        * block (rounded up to the size of an unsigned long).  The attr block
+        * used space bitmap starts at the beginning of the buffer; the free
+        * space bitmap follows immediately after; and we have a third buffer
+        * for storing intermediate bitmap results.
+        */
+       uint8_t                 buf[0];
+};
+
+/* A place to store attribute values. */
+static inline uint8_t *
+xchk_xattr_valuebuf(
+       struct xfs_scrub        *sc)
+{
+       struct xchk_xattr_buf   *ab = sc->buf;
+
+       return ab->buf;
+}
+
+/* A bitmap of space usage computed by walking an attr leaf block. */
+static inline unsigned long *
+xchk_xattr_usedmap(
+       struct xfs_scrub        *sc)
+{
+       struct xchk_xattr_buf   *ab = sc->buf;
+
+       return (unsigned long *)ab->buf;
+}
+
+/* A bitmap of free space computed by walking attr leaf block free info. */
+static inline unsigned long *
+xchk_xattr_freemap(
+       struct xfs_scrub        *sc)
+{
+       return xchk_xattr_usedmap(sc) +
+                       BITS_TO_LONGS(sc->mp->m_attr_geo->blksize);
+}
+
+/* A bitmap used to hold temporary results. */
+static inline unsigned long *
+xchk_xattr_dstmap(
+       struct xfs_scrub        *sc)
+{
+       return xchk_xattr_freemap(sc) +
+                       BITS_TO_LONGS(sc->mp->m_attr_geo->blksize);
+}
+
+int xchk_setup_xattr_buf(struct xfs_scrub *sc, size_t value_size,
+               xfs_km_flags_t flags);
+
+#endif /* __XFS_SCRUB_ATTR_H__ */
index fdadc9e..3d47d11 100644 (file)
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
 #include "xfs_btree.h"
-#include "scrub/xfs_scrub.h"
-#include "scrub/scrub.h"
-#include "scrub/common.h"
-#include "scrub/trace.h"
-#include "scrub/repair.h"
 #include "scrub/bitmap.h"
 
 /*
index a703cd5..1bd29fd 100644 (file)
@@ -9,27 +9,19 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_btree.h"
 #include "xfs_bit.h"
 #include "xfs_log_format.h"
 #include "xfs_trans.h"
-#include "xfs_sb.h"
 #include "xfs_inode.h"
-#include "xfs_inode_fork.h"
 #include "xfs_alloc.h"
-#include "xfs_rtalloc.h"
 #include "xfs_bmap.h"
-#include "xfs_bmap_util.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_rmap.h"
 #include "xfs_rmap_btree.h"
-#include "xfs_refcount.h"
-#include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/btree.h"
-#include "scrub/trace.h"
 
 /* Set us up with an inode's bmap. */
 int
index 117910d..f52a7b8 100644 (file)
@@ -9,14 +9,7 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_btree.h"
-#include "xfs_bit.h"
-#include "xfs_log_format.h"
-#include "xfs_trans.h"
-#include "xfs_sb.h"
-#include "xfs_inode.h"
-#include "xfs_alloc.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/btree.h"
index 973aa59..1887605 100644 (file)
@@ -9,22 +9,16 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_btree.h"
-#include "xfs_bit.h"
 #include "xfs_log_format.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_inode.h"
 #include "xfs_icache.h"
-#include "xfs_itable.h"
 #include "xfs_alloc.h"
 #include "xfs_alloc_btree.h"
-#include "xfs_bmap.h"
-#include "xfs_bmap_btree.h"
 #include "xfs_ialloc.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_refcount.h"
 #include "xfs_refcount_btree.h"
 #include "xfs_rmap.h"
 #include "xfs_rmap_btree.h"
 #include "xfs_trans_priv.h"
 #include "xfs_attr.h"
 #include "xfs_reflink.h"
-#include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/trace.h"
-#include "scrub/btree.h"
 #include "scrub/repair.h"
 #include "scrub/health.h"
 
index 90527b0..94c4f1d 100644 (file)
@@ -9,20 +9,12 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
-#include "xfs_btree.h"
-#include "xfs_bit.h"
 #include "xfs_log_format.h"
 #include "xfs_trans.h"
-#include "xfs_sb.h"
 #include "xfs_inode.h"
-#include "xfs_inode_fork.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_dir2.h"
 #include "xfs_dir2_priv.h"
 #include "xfs_attr_leaf.h"
-#include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/trace.h"
index a38a227..1e2e117 100644 (file)
@@ -9,24 +9,14 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
-#include "xfs_btree.h"
-#include "xfs_bit.h"
 #include "xfs_log_format.h"
 #include "xfs_trans.h"
-#include "xfs_sb.h"
 #include "xfs_inode.h"
 #include "xfs_icache.h"
-#include "xfs_itable.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_dir2.h"
 #include "xfs_dir2_priv.h"
-#include "xfs_ialloc.h"
-#include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
-#include "scrub/trace.h"
 #include "scrub/dabtree.h"
 
 /* Set us up to scrub directories. */
index 07c11e3..fc3f510 100644 (file)
@@ -9,22 +9,10 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
-#include "xfs_btree.h"
-#include "xfs_bit.h"
-#include "xfs_log_format.h"
-#include "xfs_trans.h"
 #include "xfs_sb.h"
-#include "xfs_inode.h"
 #include "xfs_alloc.h"
 #include "xfs_ialloc.h"
-#include "xfs_rmap.h"
-#include "xfs_error.h"
-#include "xfs_errortag.h"
-#include "xfs_icache.h"
 #include "xfs_health.h"
-#include "xfs_bmap.h"
-#include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/trace.h"
index 23cf8e2..b2f6028 100644 (file)
@@ -7,18 +7,10 @@
 #include "xfs_fs.h"
 #include "xfs_shared.h"
 #include "xfs_format.h"
-#include "xfs_trans_resv.h"
-#include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_btree.h"
-#include "xfs_bit.h"
-#include "xfs_log_format.h"
-#include "xfs_trans.h"
 #include "xfs_sb.h"
-#include "xfs_inode.h"
 #include "xfs_health.h"
 #include "scrub/scrub.h"
-#include "scrub/health.h"
 
 /*
  * Scrub and In-Core Filesystem Health Assessments
index 9b47117..6817587 100644 (file)
@@ -9,21 +9,14 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_btree.h"
-#include "xfs_bit.h"
 #include "xfs_log_format.h"
 #include "xfs_trans.h"
-#include "xfs_sb.h"
 #include "xfs_inode.h"
-#include "xfs_alloc.h"
 #include "xfs_ialloc.h"
 #include "xfs_ialloc_btree.h"
 #include "xfs_icache.h"
 #include "xfs_rmap.h"
-#include "xfs_log.h"
-#include "xfs_trans_priv.h"
-#include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/btree.h"
@@ -230,7 +223,7 @@ xchk_iallocbt_check_cluster(
        int                             error = 0;
 
        nr_inodes = min_t(unsigned int, XFS_INODES_PER_CHUNK,
-                       mp->m_inodes_per_cluster);
+                       M_IGEO(mp)->inodes_per_cluster);
 
        /* Map this inode cluster */
        agbno = XFS_AGINO_TO_AGBNO(mp, irec->ir_startino + cluster_base);
@@ -251,7 +244,7 @@ xchk_iallocbt_check_cluster(
         */
        ir_holemask = (irec->ir_holemask & cluster_mask);
        imap.im_blkno = XFS_AGB_TO_DADDR(mp, agno, agbno);
-       imap.im_len = XFS_FSB_TO_BB(mp, mp->m_blocks_per_cluster);
+       imap.im_len = XFS_FSB_TO_BB(mp, M_IGEO(mp)->blocks_per_cluster);
        imap.im_boffset = XFS_INO_TO_OFFSET(mp, irec->ir_startino) <<
                        mp->m_sb.sb_inodelog;
 
@@ -276,12 +269,12 @@ xchk_iallocbt_check_cluster(
        /* If any part of this is a hole, skip it. */
        if (ir_holemask) {
                xchk_xref_is_not_owned_by(bs->sc, agbno,
-                               mp->m_blocks_per_cluster,
+                               M_IGEO(mp)->blocks_per_cluster,
                                &XFS_RMAP_OINFO_INODES);
                return 0;
        }
 
-       xchk_xref_is_owned_by(bs->sc, agbno, mp->m_blocks_per_cluster,
+       xchk_xref_is_owned_by(bs->sc, agbno, M_IGEO(mp)->blocks_per_cluster,
                        &XFS_RMAP_OINFO_INODES);
 
        /* Grab the inode cluster buffer. */
@@ -333,7 +326,7 @@ xchk_iallocbt_check_clusters(
         */
        for (cluster_base = 0;
             cluster_base < XFS_INODES_PER_CHUNK;
-            cluster_base += bs->sc->mp->m_inodes_per_cluster) {
+            cluster_base += M_IGEO(bs->sc->mp)->inodes_per_cluster) {
                error = xchk_iallocbt_check_cluster(bs, irec, cluster_base);
                if (error)
                        break;
@@ -355,6 +348,7 @@ xchk_iallocbt_rec_alignment(
 {
        struct xfs_mount                *mp = bs->sc->mp;
        struct xchk_iallocbt            *iabt = bs->private;
+       struct xfs_ino_geometry         *igeo = M_IGEO(mp);
 
        /*
         * finobt records have different positioning requirements than inobt
@@ -372,7 +366,7 @@ xchk_iallocbt_rec_alignment(
                unsigned int    imask;
 
                imask = min_t(unsigned int, XFS_INODES_PER_CHUNK,
-                               mp->m_cluster_align_inodes) - 1;
+                               igeo->cluster_align_inodes) - 1;
                if (irec->ir_startino & imask)
                        xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
                return;
@@ -400,17 +394,17 @@ xchk_iallocbt_rec_alignment(
        }
 
        /* inobt records must be aligned to cluster and inoalignmnt size. */
-       if (irec->ir_startino & (mp->m_cluster_align_inodes - 1)) {
+       if (irec->ir_startino & (igeo->cluster_align_inodes - 1)) {
                xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
                return;
        }
 
-       if (irec->ir_startino & (mp->m_inodes_per_cluster - 1)) {
+       if (irec->ir_startino & (igeo->inodes_per_cluster - 1)) {
                xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
                return;
        }
 
-       if (mp->m_inodes_per_cluster <= XFS_INODES_PER_CHUNK)
+       if (igeo->inodes_per_cluster <= XFS_INODES_PER_CHUNK)
                return;
 
        /*
@@ -419,7 +413,7 @@ xchk_iallocbt_rec_alignment(
         * after this one.
         */
        iabt->next_startino = irec->ir_startino + XFS_INODES_PER_CHUNK;
-       iabt->next_cluster_ino = irec->ir_startino + mp->m_inodes_per_cluster;
+       iabt->next_cluster_ino = irec->ir_startino + igeo->inodes_per_cluster;
 }
 
 /* Scrub an inobt/finobt record. */
index e213efc..6d483ab 100644 (file)
@@ -9,27 +9,17 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_btree.h"
-#include "xfs_bit.h"
 #include "xfs_log_format.h"
-#include "xfs_trans.h"
-#include "xfs_sb.h"
 #include "xfs_inode.h"
-#include "xfs_icache.h"
-#include "xfs_inode_buf.h"
-#include "xfs_inode_fork.h"
 #include "xfs_ialloc.h"
 #include "xfs_da_format.h"
 #include "xfs_reflink.h"
 #include "xfs_rmap.h"
-#include "xfs_bmap.h"
 #include "xfs_bmap_util.h"
-#include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/btree.h"
-#include "scrub/trace.h"
 
 /*
  * Grab total control of the inode metadata.  It doesn't matter here if
index d5d197f..c962bd5 100644 (file)
@@ -9,21 +9,13 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
-#include "xfs_btree.h"
-#include "xfs_bit.h"
 #include "xfs_log_format.h"
-#include "xfs_trans.h"
-#include "xfs_sb.h"
 #include "xfs_inode.h"
 #include "xfs_icache.h"
 #include "xfs_dir2.h"
 #include "xfs_dir2_priv.h"
-#include "xfs_ialloc.h"
-#include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
-#include "scrub/trace.h"
 
 /* Set us up to scrub parents. */
 int
index 5dfe2b5..0a33b44 100644 (file)
@@ -9,24 +9,13 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
-#include "xfs_btree.h"
-#include "xfs_bit.h"
 #include "xfs_log_format.h"
 #include "xfs_trans.h"
-#include "xfs_sb.h"
 #include "xfs_inode.h"
-#include "xfs_inode_fork.h"
-#include "xfs_alloc.h"
-#include "xfs_bmap.h"
 #include "xfs_quota.h"
 #include "xfs_qm.h"
-#include "xfs_dquot.h"
-#include "xfs_dquot_item.h"
-#include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
-#include "scrub/trace.h"
 
 /* Convert a scrub type code to a DQ flag, or return 0 if error. */
 static inline uint
@@ -144,7 +133,7 @@ xchk_quota_item(
        if (bsoft > bhard)
                xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
 
-       if (ihard > mp->m_maxicount)
+       if (ihard > M_IGEO(mp)->maxicount)
                xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
        if (isoft > ihard)
                xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
index 708b415..93b3793 100644 (file)
@@ -7,22 +7,12 @@
 #include "xfs_fs.h"
 #include "xfs_shared.h"
 #include "xfs_format.h"
-#include "xfs_trans_resv.h"
-#include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_btree.h"
-#include "xfs_bit.h"
-#include "xfs_log_format.h"
-#include "xfs_trans.h"
-#include "xfs_sb.h"
-#include "xfs_alloc.h"
 #include "xfs_rmap.h"
 #include "xfs_refcount.h"
-#include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/btree.h"
-#include "scrub/trace.h"
 
 /*
  * Set us up to scrub reference count btrees.
index eb358f0..4cfeec5 100644 (file)
@@ -9,29 +9,21 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_btree.h"
-#include "xfs_bit.h"
 #include "xfs_log_format.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_inode.h"
-#include "xfs_icache.h"
 #include "xfs_alloc.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc.h"
 #include "xfs_ialloc_btree.h"
 #include "xfs_rmap.h"
 #include "xfs_rmap_btree.h"
-#include "xfs_refcount.h"
 #include "xfs_refcount_btree.h"
 #include "xfs_extent_busy.h"
 #include "xfs_ag_resv.h"
-#include "xfs_trans_space.h"
 #include "xfs_quota.h"
-#include "xfs_attr.h"
-#include "xfs_reflink.h"
-#include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/trace.h"
@@ -357,7 +349,7 @@ xrep_init_btblock(
        bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, XFS_FSB_TO_DADDR(mp, fsb),
                        XFS_FSB_TO_BB(mp, 1), 0);
        xfs_buf_zero(bp, 0, BBTOB(bp->b_length));
-       xfs_btree_init_block(mp, bp, btnum, 0, 0, sc->sa.agno, 0);
+       xfs_btree_init_block(mp, bp, btnum, 0, 0, sc->sa.agno);
        xfs_trans_buf_set_type(tp, bp, XFS_BLFT_BTREE_BUF);
        xfs_trans_log_buf(tp, bp, 0, bp->b_length);
        bp->b_ops = ops;
@@ -672,7 +664,7 @@ xrep_findroot_agfl_walk(
 {
        xfs_agblock_t           *agbno = priv;
 
-       return (*agbno == bno) ? XFS_BTREE_QUERY_RANGE_ABORT : 0;
+       return (*agbno == bno) ? XFS_ITER_ABORT : 0;
 }
 
 /* Does this block match the btree information passed in? */
@@ -702,7 +694,7 @@ xrep_findroot_block(
        if (owner == XFS_RMAP_OWN_AG) {
                error = xfs_agfl_walk(mp, ri->agf, ri->agfl_bp,
                                xrep_findroot_agfl_walk, &agbno);
-               if (error == XFS_BTREE_QUERY_RANGE_ABORT)
+               if (error == XFS_ITER_ABORT)
                        return 0;
                if (error)
                        return error;
index 92a140c..8d4cefd 100644 (file)
@@ -9,21 +9,12 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_btree.h"
-#include "xfs_bit.h"
-#include "xfs_log_format.h"
-#include "xfs_trans.h"
-#include "xfs_sb.h"
-#include "xfs_alloc.h"
-#include "xfs_ialloc.h"
 #include "xfs_rmap.h"
 #include "xfs_refcount.h"
-#include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/btree.h"
-#include "scrub/trace.h"
 
 /*
  * Set us up to scrub reverse mapping btrees.
index dbe115b..c642bc2 100644 (file)
@@ -9,19 +9,12 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
-#include "xfs_btree.h"
-#include "xfs_bit.h"
 #include "xfs_log_format.h"
 #include "xfs_trans.h"
-#include "xfs_sb.h"
-#include "xfs_alloc.h"
 #include "xfs_rtalloc.h"
 #include "xfs_inode.h"
-#include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
-#include "scrub/trace.h"
 
 /* Set us up with the realtime metadata locked. */
 int
index f630389..15c8c5f 100644 (file)
@@ -9,36 +9,16 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
-#include "xfs_btree.h"
-#include "xfs_bit.h"
 #include "xfs_log_format.h"
 #include "xfs_trans.h"
-#include "xfs_sb.h"
 #include "xfs_inode.h"
-#include "xfs_icache.h"
-#include "xfs_itable.h"
-#include "xfs_alloc.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_bmap.h"
-#include "xfs_bmap_btree.h"
-#include "xfs_ialloc.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_refcount.h"
-#include "xfs_refcount_btree.h"
-#include "xfs_rmap.h"
-#include "xfs_rmap_btree.h"
 #include "xfs_quota.h"
 #include "xfs_qm.h"
 #include "xfs_errortag.h"
 #include "xfs_error.h"
-#include "xfs_log.h"
-#include "xfs_trans_priv.h"
-#include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/trace.h"
-#include "scrub/btree.h"
 #include "scrub/repair.h"
 #include "scrub/health.h"
 
index f7ebaa9..99c0b12 100644 (file)
@@ -9,19 +9,11 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
-#include "xfs_btree.h"
-#include "xfs_bit.h"
 #include "xfs_log_format.h"
-#include "xfs_trans.h"
-#include "xfs_sb.h"
 #include "xfs_inode.h"
-#include "xfs_inode_fork.h"
 #include "xfs_symlink.h"
-#include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
-#include "scrub/trace.h"
 
 /* Set us up to scrub a symbolic link. */
 int
index 96feaf8..9eaab2e 100644 (file)
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
-#include "xfs_da_format.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
-#include "xfs_trans.h"
-#include "xfs_bit.h"
-#include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
-#include "scrub/common.h"
 
 /* Figure out which block the btree cursor was pointing to. */
 static inline xfs_fsblock_t
index 8039e35..cbda40d 100644 (file)
@@ -4,16 +4,14 @@
  * All Rights Reserved.
  */
 #include "xfs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
 #include "xfs_inode.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_trace.h"
-#include <linux/slab.h>
-#include <linux/xattr.h>
 #include <linux/posix_acl_xattr.h>
 
 
index 11f703d..761248e 100644 (file)
 #include "xfs_mount.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
-#include "xfs_inode_item.h"
-#include "xfs_alloc.h"
-#include "xfs_error.h"
 #include "xfs_iomap.h"
 #include "xfs_trace.h"
 #include "xfs_bmap.h"
 #include "xfs_bmap_util.h"
-#include "xfs_bmap_btree.h"
 #include "xfs_reflink.h"
-#include <linux/writeback.h>
 
 /*
  * structure owned by writepages passed to individual writepage calls
@@ -138,8 +133,7 @@ xfs_setfilesize_trans_alloc(
        struct xfs_trans        *tp;
        int                     error;
 
-       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0,
-                               XFS_TRANS_NOFS, &tp);
+       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp);
        if (error)
                return error;
 
@@ -240,8 +234,16 @@ xfs_end_ioend(
        struct xfs_inode        *ip = XFS_I(ioend->io_inode);
        xfs_off_t               offset = ioend->io_offset;
        size_t                  size = ioend->io_size;
+       unsigned int            nofs_flag;
        int                     error;
 
+       /*
+        * We can allocate memory here while doing writeback on behalf of
+        * memory reclaim.  To avoid memory allocation deadlocks set the
+        * task-wide nofs context for the following operations.
+        */
+       nofs_flag = memalloc_nofs_save();
+
        /*
         * Just clean up the in-memory strutures if the fs has been shut down.
         */
@@ -282,6 +284,8 @@ done:
                list_del_init(&ioend->io_list);
                xfs_destroy_ioend(ioend, error);
        }
+
+       memalloc_nofs_restore(nofs_flag);
 }
 
 /*
@@ -290,13 +294,9 @@ done:
 static bool
 xfs_ioend_can_merge(
        struct xfs_ioend        *ioend,
-       int                     ioend_error,
        struct xfs_ioend        *next)
 {
-       int                     next_error;
-
-       next_error = blk_status_to_errno(next->io_bio->bi_status);
-       if (ioend_error != next_error)
+       if (ioend->io_bio->bi_status != next->io_bio->bi_status)
                return false;
        if ((ioend->io_fork == XFS_COW_FORK) ^ (next->io_fork == XFS_COW_FORK))
                return false;
@@ -305,11 +305,28 @@ xfs_ioend_can_merge(
                return false;
        if (ioend->io_offset + ioend->io_size != next->io_offset)
                return false;
-       if (xfs_ioend_is_append(ioend) != xfs_ioend_is_append(next))
-               return false;
        return true;
 }
 
+/*
+ * If the to be merged ioend has a preallocated transaction for file
+ * size updates we need to ensure the ioend it is merged into also
+ * has one.  If it already has one we can simply cancel the transaction
+ * as it is guaranteed to be clean.
+ */
+static void
+xfs_ioend_merge_append_transactions(
+       struct xfs_ioend        *ioend,
+       struct xfs_ioend        *next)
+{
+       if (!ioend->io_append_trans) {
+               ioend->io_append_trans = next->io_append_trans;
+               next->io_append_trans = NULL;
+       } else {
+               xfs_setfilesize_ioend(next, -ECANCELED);
+       }
+}
+
 /* Try to merge adjacent completions. */
 STATIC void
 xfs_ioend_try_merge(
@@ -317,25 +334,16 @@ xfs_ioend_try_merge(
        struct list_head        *more_ioends)
 {
        struct xfs_ioend        *next_ioend;
-       int                     ioend_error;
-       int                     error;
-
-       if (list_empty(more_ioends))
-               return;
-
-       ioend_error = blk_status_to_errno(ioend->io_bio->bi_status);
 
        while (!list_empty(more_ioends)) {
                next_ioend = list_first_entry(more_ioends, struct xfs_ioend,
                                io_list);
-               if (!xfs_ioend_can_merge(ioend, ioend_error, next_ioend))
+               if (!xfs_ioend_can_merge(ioend, next_ioend))
                        break;
                list_move_tail(&next_ioend->io_list, &ioend->io_list);
                ioend->io_size += next_ioend->io_size;
-               if (ioend->io_append_trans) {
-                       error = xfs_setfilesize_ioend(next_ioend, 1);
-                       ASSERT(error == 1);
-               }
+               if (next_ioend->io_append_trans)
+                       xfs_ioend_merge_append_transactions(ioend, next_ioend);
        }
 }
 
@@ -626,7 +634,7 @@ allocate_blocks:
  * reference to the ioend to ensure that the ioend completion is only done once
  * all bios have been submitted and the ioend is really done.
  *
- * If @fail is non-zero, it means that we have a situation where some part of
+ * If @status is non-zero, it means that we have a situation where some part of
  * the submission process has failed after we have marked paged for writeback
  * and unlocked them. In this situation, we need to fail the bio and ioend
  * rather than submit it to IO. This typically only happens on a filesystem
@@ -638,21 +646,19 @@ xfs_submit_ioend(
        struct xfs_ioend        *ioend,
        int                     status)
 {
+       unsigned int            nofs_flag;
+
+       /*
+        * We can allocate memory here while doing writeback on behalf of
+        * memory reclaim.  To avoid memory allocation deadlocks set the
+        * task-wide nofs context for the following operations.
+        */
+       nofs_flag = memalloc_nofs_save();
+
        /* Convert CoW extents to regular */
        if (!status && ioend->io_fork == XFS_COW_FORK) {
-               /*
-                * Yuk. This can do memory allocation, but is not a
-                * transactional operation so everything is done in GFP_KERNEL
-                * context. That can deadlock, because we hold pages in
-                * writeback state and GFP_KERNEL allocations can block on them.
-                * Hence we must operate in nofs conditions here.
-                */
-               unsigned nofs_flag;
-
-               nofs_flag = memalloc_nofs_save();
                status = xfs_reflink_convert_cow(XFS_I(ioend->io_inode),
                                ioend->io_offset, ioend->io_size);
-               memalloc_nofs_restore(nofs_flag);
        }
 
        /* Reserve log space if we might write beyond the on-disk inode size. */
@@ -663,9 +669,10 @@ xfs_submit_ioend(
            !ioend->io_append_trans)
                status = xfs_setfilesize_trans_alloc(ioend);
 
+       memalloc_nofs_restore(nofs_flag);
+
        ioend->io_bio->bi_private = ioend;
        ioend->io_bio->bi_end_io = xfs_end_bio;
-       ioend->io_bio->bi_opf = REQ_OP_WRITE | wbc_to_write_flags(wbc);
 
        /*
         * If we are failing the IO now, just mark the ioend with an
@@ -679,7 +686,6 @@ xfs_submit_ioend(
                return status;
        }
 
-       ioend->io_bio->bi_write_hint = ioend->io_inode->i_write_hint;
        submit_bio(ioend->io_bio);
        return 0;
 }
@@ -691,7 +697,8 @@ xfs_alloc_ioend(
        xfs_exntst_t            state,
        xfs_off_t               offset,
        struct block_device     *bdev,
-       sector_t                sector)
+       sector_t                sector,
+       struct writeback_control *wbc)
 {
        struct xfs_ioend        *ioend;
        struct bio              *bio;
@@ -699,6 +706,9 @@ xfs_alloc_ioend(
        bio = bio_alloc_bioset(GFP_NOFS, BIO_MAX_PAGES, &xfs_ioend_bioset);
        bio_set_dev(bio, bdev);
        bio->bi_iter.bi_sector = sector;
+       bio->bi_opf = REQ_OP_WRITE | wbc_to_write_flags(wbc);
+       bio->bi_write_hint = inode->i_write_hint;
+       wbc_init_bio(wbc, bio);
 
        ioend = container_of(bio, struct xfs_ioend, io_inline_bio);
        INIT_LIST_HEAD(&ioend->io_list);
@@ -719,24 +729,22 @@ xfs_alloc_ioend(
  * so that the bi_private linkage is set up in the right direction for the
  * traversal in xfs_destroy_ioend().
  */
-static void
+static struct bio *
 xfs_chain_bio(
-       struct xfs_ioend        *ioend,
-       struct writeback_control *wbc,
-       struct block_device     *bdev,
-       sector_t                sector)
+       struct bio              *prev)
 {
        struct bio *new;
 
        new = bio_alloc(GFP_NOFS, BIO_MAX_PAGES);
-       bio_set_dev(new, bdev);
-       new->bi_iter.bi_sector = sector;
-       bio_chain(ioend->io_bio, new);
-       bio_get(ioend->io_bio);         /* for xfs_destroy_ioend */
-       ioend->io_bio->bi_opf = REQ_OP_WRITE | wbc_to_write_flags(wbc);
-       ioend->io_bio->bi_write_hint = ioend->io_inode->i_write_hint;
-       submit_bio(ioend->io_bio);
-       ioend->io_bio = new;
+       bio_copy_dev(new, prev);/* also copies over blkcg information */
+       new->bi_iter.bi_sector = bio_end_sector(prev);
+       new->bi_opf = prev->bi_opf;
+       new->bi_write_hint = prev->bi_write_hint;
+
+       bio_chain(prev, new);
+       bio_get(prev);          /* for xfs_destroy_ioend */
+       submit_bio(prev);
+       return new;
 }
 
 /*
@@ -772,7 +780,7 @@ xfs_add_to_ioend(
                if (wpc->ioend)
                        list_add(&wpc->ioend->io_list, iolist);
                wpc->ioend = xfs_alloc_ioend(inode, wpc->fork,
-                               wpc->imap.br_state, offset, bdev, sector);
+                               wpc->imap.br_state, offset, bdev, sector, wbc);
        }
 
        merged = __bio_try_merge_page(wpc->ioend->io_bio, page, len, poff,
@@ -783,11 +791,12 @@ xfs_add_to_ioend(
 
        if (!merged) {
                if (bio_full(wpc->ioend->io_bio, len))
-                       xfs_chain_bio(wpc->ioend, wbc, bdev, sector);
+                       wpc->ioend->io_bio = xfs_chain_bio(wpc->ioend->io_bio);
                bio_add_page(wpc->ioend->io_bio, page, len, poff);
        }
 
        wpc->ioend->io_size += len;
+       wbc_account_io(wbc, page, len);
 }
 
 STATIC void
index f62b031..45a1ea2 100644 (file)
@@ -28,7 +28,6 @@ extern const struct address_space_operations xfs_dax_aops;
 
 int    xfs_setfilesize(struct xfs_inode *ip, xfs_off_t offset, size_t size);
 
-extern void xfs_count_page_state(struct page *, int *, int *);
 extern struct block_device *xfs_find_bdev_for_inode(struct inode *);
 extern struct dax_device *xfs_find_daxdev_for_inode(struct inode *);
 
index 228821b..dc93c51 100644 (file)
 #include "xfs_da_format.h"
 #include "xfs_da_btree.h"
 #include "xfs_inode.h"
-#include "xfs_alloc.h"
 #include "xfs_attr_remote.h"
 #include "xfs_trans.h"
-#include "xfs_inode_item.h"
 #include "xfs_bmap.h"
 #include "xfs_attr.h"
 #include "xfs_attr_leaf.h"
-#include "xfs_error.h"
 #include "xfs_quota.h"
-#include "xfs_trace.h"
 #include "xfs_dir2.h"
-#include "xfs_defer.h"
 
 /*
  * Look at all the extents for this logical region,
@@ -121,7 +116,7 @@ xfs_attr3_leaf_inactive(
        int                     size;
        int                     tmp;
        int                     i;
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
 
        leaf = bp->b_addr;
        xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf);
index 3d213a7..58fc820 100644 (file)
@@ -6,25 +6,20 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_bit.h"
 #include "xfs_mount.h"
 #include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
-#include "xfs_inode_item.h"
 #include "xfs_bmap.h"
 #include "xfs_attr.h"
 #include "xfs_attr_sf.h"
-#include "xfs_attr_remote.h"
 #include "xfs_attr_leaf.h"
 #include "xfs_error.h"
 #include "xfs_trace.h"
-#include "xfs_buf_item.h"
-#include "xfs_cksum.h"
 #include "xfs_dir2.h"
 
 STATIC int
diff --git a/fs/xfs/xfs_bio_io.c b/fs/xfs/xfs_bio_io.c
new file mode 100644 (file)
index 0000000..e2148f2
--- /dev/null
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Christoph Hellwig.
+ */
+#include "xfs.h"
+
+static inline unsigned int bio_max_vecs(unsigned int count)
+{
+       return min_t(unsigned, howmany(count, PAGE_SIZE), BIO_MAX_PAGES);
+}
+
+int
+xfs_rw_bdev(
+       struct block_device     *bdev,
+       sector_t                sector,
+       unsigned int            count,
+       char                    *data,
+       unsigned int            op)
+
+{
+       unsigned int            is_vmalloc = is_vmalloc_addr(data);
+       unsigned int            left = count;
+       int                     error;
+       struct bio              *bio;
+
+       if (is_vmalloc && op == REQ_OP_WRITE)
+               flush_kernel_vmap_range(data, count);
+
+       bio = bio_alloc(GFP_KERNEL, bio_max_vecs(left));
+       bio_set_dev(bio, bdev);
+       bio->bi_iter.bi_sector = sector;
+       bio->bi_opf = op | REQ_META | REQ_SYNC;
+
+       do {
+               struct page     *page = kmem_to_page(data);
+               unsigned int    off = offset_in_page(data);
+               unsigned int    len = min_t(unsigned, left, PAGE_SIZE - off);
+
+               while (bio_add_page(bio, page, len, off) != len) {
+                       struct bio      *prev = bio;
+
+                       bio = bio_alloc(GFP_KERNEL, bio_max_vecs(left));
+                       bio_copy_dev(bio, prev);
+                       bio->bi_iter.bi_sector = bio_end_sector(prev);
+                       bio->bi_opf = prev->bi_opf;
+                       bio_chain(prev, bio);
+
+                       submit_bio(prev);
+               }
+
+               data += len;
+               left -= len;
+       } while (left > 0);
+
+       error = submit_bio_wait(bio);
+       bio_put(bio);
+
+       if (is_vmalloc && op == REQ_OP_READ)
+               invalidate_kernel_vmap_range(data, count);
+       return error;
+}
index ce45f06..9fa4a7e 100644 (file)
@@ -9,17 +9,16 @@
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
+#include "xfs_shared.h"
 #include "xfs_mount.h"
 #include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
 #include "xfs_trans_priv.h"
-#include "xfs_buf_item.h"
 #include "xfs_bmap_item.h"
 #include "xfs_log.h"
 #include "xfs_bmap.h"
 #include "xfs_icache.h"
-#include "xfs_trace.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_trans_space.h"
 
@@ -95,15 +94,6 @@ xfs_bui_item_format(
                        xfs_bui_log_format_sizeof(buip->bui_format.bui_nextents));
 }
 
-/*
- * Pinning has no meaning for an bui item, so just return.
- */
-STATIC void
-xfs_bui_item_pin(
-       struct xfs_log_item     *lip)
-{
-}
-
 /*
  * The unpin operation is the last place an BUI is manipulated in the log. It is
  * either inserted in the AIL or aborted in the event of a log I/O error. In
@@ -122,72 +112,23 @@ xfs_bui_item_unpin(
        xfs_bui_release(buip);
 }
 
-/*
- * BUI items have no locking or pushing.  However, since BUIs are pulled from
- * the AIL when their corresponding BUDs are committed to disk, their situation
- * is very similar to being pinned.  Return XFS_ITEM_PINNED so that the caller
- * will eventually flush the log.  This should help in getting the BUI out of
- * the AIL.
- */
-STATIC uint
-xfs_bui_item_push(
-       struct xfs_log_item     *lip,
-       struct list_head        *buffer_list)
-{
-       return XFS_ITEM_PINNED;
-}
-
 /*
  * The BUI has been either committed or aborted if the transaction has been
  * cancelled. If the transaction was cancelled, an BUD isn't going to be
  * constructed and thus we free the BUI here directly.
  */
 STATIC void
-xfs_bui_item_unlock(
+xfs_bui_item_release(
        struct xfs_log_item     *lip)
 {
-       if (test_bit(XFS_LI_ABORTED, &lip->li_flags))
-               xfs_bui_release(BUI_ITEM(lip));
-}
-
-/*
- * The BUI is logged only once and cannot be moved in the log, so simply return
- * the lsn at which it's been logged.
- */
-STATIC xfs_lsn_t
-xfs_bui_item_committed(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
-{
-       return lsn;
+       xfs_bui_release(BUI_ITEM(lip));
 }
 
-/*
- * The BUI dependency tracking op doesn't do squat.  It can't because
- * it doesn't know where the free extent is coming from.  The dependency
- * tracking has to be handled by the "enclosing" metadata object.  For
- * example, for inodes, the inode is locked throughout the extent freeing
- * so the dependency should be recorded there.
- */
-STATIC void
-xfs_bui_item_committing(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
-{
-}
-
-/*
- * This is the ops vector shared by all bui log items.
- */
 static const struct xfs_item_ops xfs_bui_item_ops = {
        .iop_size       = xfs_bui_item_size,
        .iop_format     = xfs_bui_item_format,
-       .iop_pin        = xfs_bui_item_pin,
        .iop_unpin      = xfs_bui_item_unpin,
-       .iop_unlock     = xfs_bui_item_unlock,
-       .iop_committed  = xfs_bui_item_committed,
-       .iop_push       = xfs_bui_item_push,
-       .iop_committing = xfs_bui_item_committing,
+       .iop_release    = xfs_bui_item_release,
 };
 
 /*
@@ -249,126 +190,241 @@ xfs_bud_item_format(
 }
 
 /*
- * Pinning has no meaning for an bud item, so just return.
+ * The BUD is either committed or aborted if the transaction is cancelled. If
+ * the transaction is cancelled, drop our reference to the BUI and free the
+ * BUD.
  */
 STATIC void
-xfs_bud_item_pin(
+xfs_bud_item_release(
        struct xfs_log_item     *lip)
 {
+       struct xfs_bud_log_item *budp = BUD_ITEM(lip);
+
+       xfs_bui_release(budp->bud_buip);
+       kmem_zone_free(xfs_bud_zone, budp);
 }
 
-/*
- * Since pinning has no meaning for an bud item, unpinning does
- * not either.
- */
-STATIC void
-xfs_bud_item_unpin(
-       struct xfs_log_item     *lip,
-       int                     remove)
+static const struct xfs_item_ops xfs_bud_item_ops = {
+       .flags          = XFS_ITEM_RELEASE_WHEN_COMMITTED,
+       .iop_size       = xfs_bud_item_size,
+       .iop_format     = xfs_bud_item_format,
+       .iop_release    = xfs_bud_item_release,
+};
+
+static struct xfs_bud_log_item *
+xfs_trans_get_bud(
+       struct xfs_trans                *tp,
+       struct xfs_bui_log_item         *buip)
 {
+       struct xfs_bud_log_item         *budp;
+
+       budp = kmem_zone_zalloc(xfs_bud_zone, KM_SLEEP);
+       xfs_log_item_init(tp->t_mountp, &budp->bud_item, XFS_LI_BUD,
+                         &xfs_bud_item_ops);
+       budp->bud_buip = buip;
+       budp->bud_format.bud_bui_id = buip->bui_format.bui_id;
+
+       xfs_trans_add_item(tp, &budp->bud_item);
+       return budp;
 }
 
 /*
- * There isn't much you can do to push on an bud item.  It is simply stuck
- * waiting for the log to be flushed to disk.
+ * Finish an bmap update and log it to the BUD. Note that the
+ * transaction is marked dirty regardless of whether the bmap update
+ * succeeds or fails to support the BUI/BUD lifecycle rules.
  */
-STATIC uint
-xfs_bud_item_push(
-       struct xfs_log_item     *lip,
-       struct list_head        *buffer_list)
+static int
+xfs_trans_log_finish_bmap_update(
+       struct xfs_trans                *tp,
+       struct xfs_bud_log_item         *budp,
+       enum xfs_bmap_intent_type       type,
+       struct xfs_inode                *ip,
+       int                             whichfork,
+       xfs_fileoff_t                   startoff,
+       xfs_fsblock_t                   startblock,
+       xfs_filblks_t                   *blockcount,
+       xfs_exntst_t                    state)
 {
-       return XFS_ITEM_PINNED;
+       int                             error;
+
+       error = xfs_bmap_finish_one(tp, ip, type, whichfork, startoff,
+                       startblock, blockcount, state);
+
+       /*
+        * Mark the transaction dirty, even on error. This ensures the
+        * transaction is aborted, which:
+        *
+        * 1.) releases the BUI and frees the BUD
+        * 2.) shuts down the filesystem
+        */
+       tp->t_flags |= XFS_TRANS_DIRTY;
+       set_bit(XFS_LI_DIRTY, &budp->bud_item.li_flags);
+
+       return error;
 }
 
-/*
- * The BUD is either committed or aborted if the transaction is cancelled. If
- * the transaction is cancelled, drop our reference to the BUI and free the
- * BUD.
- */
-STATIC void
-xfs_bud_item_unlock(
-       struct xfs_log_item     *lip)
+/* Sort bmap intents by inode. */
+static int
+xfs_bmap_update_diff_items(
+       void                            *priv,
+       struct list_head                *a,
+       struct list_head                *b)
 {
-       struct xfs_bud_log_item *budp = BUD_ITEM(lip);
+       struct xfs_bmap_intent          *ba;
+       struct xfs_bmap_intent          *bb;
 
-       if (test_bit(XFS_LI_ABORTED, &lip->li_flags)) {
-               xfs_bui_release(budp->bud_buip);
-               kmem_zone_free(xfs_bud_zone, budp);
-       }
+       ba = container_of(a, struct xfs_bmap_intent, bi_list);
+       bb = container_of(b, struct xfs_bmap_intent, bi_list);
+       return ba->bi_owner->i_ino - bb->bi_owner->i_ino;
 }
 
-/*
- * When the bud item is committed to disk, all we need to do is delete our
- * reference to our partner bui item and then free ourselves. Since we're
- * freeing ourselves we must return -1 to keep the transaction code from
- * further referencing this item.
- */
-STATIC xfs_lsn_t
-xfs_bud_item_committed(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
+/* Get an BUI. */
+STATIC void *
+xfs_bmap_update_create_intent(
+       struct xfs_trans                *tp,
+       unsigned int                    count)
 {
-       struct xfs_bud_log_item *budp = BUD_ITEM(lip);
+       struct xfs_bui_log_item         *buip;
+
+       ASSERT(count == XFS_BUI_MAX_FAST_EXTENTS);
+       ASSERT(tp != NULL);
+
+       buip = xfs_bui_init(tp->t_mountp);
+       ASSERT(buip != NULL);
 
        /*
-        * Drop the BUI reference regardless of whether the BUD has been
-        * aborted. Once the BUD transaction is constructed, it is the sole
-        * responsibility of the BUD to release the BUI (even if the BUI is
-        * aborted due to log I/O error).
+        * Get a log_item_desc to point at the new item.
         */
-       xfs_bui_release(budp->bud_buip);
-       kmem_zone_free(xfs_bud_zone, budp);
+       xfs_trans_add_item(tp, &buip->bui_item);
+       return buip;
+}
 
-       return (xfs_lsn_t)-1;
+/* Set the map extent flags for this mapping. */
+static void
+xfs_trans_set_bmap_flags(
+       struct xfs_map_extent           *bmap,
+       enum xfs_bmap_intent_type       type,
+       int                             whichfork,
+       xfs_exntst_t                    state)
+{
+       bmap->me_flags = 0;
+       switch (type) {
+       case XFS_BMAP_MAP:
+       case XFS_BMAP_UNMAP:
+               bmap->me_flags = type;
+               break;
+       default:
+               ASSERT(0);
+       }
+       if (state == XFS_EXT_UNWRITTEN)
+               bmap->me_flags |= XFS_BMAP_EXTENT_UNWRITTEN;
+       if (whichfork == XFS_ATTR_FORK)
+               bmap->me_flags |= XFS_BMAP_EXTENT_ATTR_FORK;
 }
 
-/*
- * The BUD dependency tracking op doesn't do squat.  It can't because
- * it doesn't know where the free extent is coming from.  The dependency
- * tracking has to be handled by the "enclosing" metadata object.  For
- * example, for inodes, the inode is locked throughout the extent freeing
- * so the dependency should be recorded there.
- */
+/* Log bmap updates in the intent item. */
 STATIC void
-xfs_bud_item_committing(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
+xfs_bmap_update_log_item(
+       struct xfs_trans                *tp,
+       void                            *intent,
+       struct list_head                *item)
 {
+       struct xfs_bui_log_item         *buip = intent;
+       struct xfs_bmap_intent          *bmap;
+       uint                            next_extent;
+       struct xfs_map_extent           *map;
+
+       bmap = container_of(item, struct xfs_bmap_intent, bi_list);
+
+       tp->t_flags |= XFS_TRANS_DIRTY;
+       set_bit(XFS_LI_DIRTY, &buip->bui_item.li_flags);
+
+       /*
+        * atomic_inc_return gives us the value after the increment;
+        * we want to use it as an array index so we need to subtract 1 from
+        * it.
+        */
+       next_extent = atomic_inc_return(&buip->bui_next_extent) - 1;
+       ASSERT(next_extent < buip->bui_format.bui_nextents);
+       map = &buip->bui_format.bui_extents[next_extent];
+       map->me_owner = bmap->bi_owner->i_ino;
+       map->me_startblock = bmap->bi_bmap.br_startblock;
+       map->me_startoff = bmap->bi_bmap.br_startoff;
+       map->me_len = bmap->bi_bmap.br_blockcount;
+       xfs_trans_set_bmap_flags(map, bmap->bi_type, bmap->bi_whichfork,
+                       bmap->bi_bmap.br_state);
 }
 
-/*
- * This is the ops vector shared by all bud log items.
- */
-static const struct xfs_item_ops xfs_bud_item_ops = {
-       .iop_size       = xfs_bud_item_size,
-       .iop_format     = xfs_bud_item_format,
-       .iop_pin        = xfs_bud_item_pin,
-       .iop_unpin      = xfs_bud_item_unpin,
-       .iop_unlock     = xfs_bud_item_unlock,
-       .iop_committed  = xfs_bud_item_committed,
-       .iop_push       = xfs_bud_item_push,
-       .iop_committing = xfs_bud_item_committing,
-};
+/* Get an BUD so we can process all the deferred rmap updates. */
+STATIC void *
+xfs_bmap_update_create_done(
+       struct xfs_trans                *tp,
+       void                            *intent,
+       unsigned int                    count)
+{
+       return xfs_trans_get_bud(tp, intent);
+}
 
-/*
- * Allocate and initialize an bud item with the given number of extents.
- */
-struct xfs_bud_log_item *
-xfs_bud_init(
-       struct xfs_mount                *mp,
-       struct xfs_bui_log_item         *buip)
+/* Process a deferred rmap update. */
+STATIC int
+xfs_bmap_update_finish_item(
+       struct xfs_trans                *tp,
+       struct list_head                *item,
+       void                            *done_item,
+       void                            **state)
+{
+       struct xfs_bmap_intent          *bmap;
+       xfs_filblks_t                   count;
+       int                             error;
+
+       bmap = container_of(item, struct xfs_bmap_intent, bi_list);
+       count = bmap->bi_bmap.br_blockcount;
+       error = xfs_trans_log_finish_bmap_update(tp, done_item,
+                       bmap->bi_type,
+                       bmap->bi_owner, bmap->bi_whichfork,
+                       bmap->bi_bmap.br_startoff,
+                       bmap->bi_bmap.br_startblock,
+                       &count,
+                       bmap->bi_bmap.br_state);
+       if (!error && count > 0) {
+               ASSERT(bmap->bi_type == XFS_BMAP_UNMAP);
+               bmap->bi_bmap.br_blockcount = count;
+               return -EAGAIN;
+       }
+       kmem_free(bmap);
+       return error;
+}
 
+/* Abort all pending BUIs. */
+STATIC void
+xfs_bmap_update_abort_intent(
+       void                            *intent)
 {
-       struct xfs_bud_log_item *budp;
+       xfs_bui_release(intent);
+}
 
-       budp = kmem_zone_zalloc(xfs_bud_zone, KM_SLEEP);
-       xfs_log_item_init(mp, &budp->bud_item, XFS_LI_BUD, &xfs_bud_item_ops);
-       budp->bud_buip = buip;
-       budp->bud_format.bud_bui_id = buip->bui_format.bui_id;
+/* Cancel a deferred rmap update. */
+STATIC void
+xfs_bmap_update_cancel_item(
+       struct list_head                *item)
+{
+       struct xfs_bmap_intent          *bmap;
 
-       return budp;
+       bmap = container_of(item, struct xfs_bmap_intent, bi_list);
+       kmem_free(bmap);
 }
 
+const struct xfs_defer_op_type xfs_bmap_update_defer_type = {
+       .max_items      = XFS_BUI_MAX_FAST_EXTENTS,
+       .diff_items     = xfs_bmap_update_diff_items,
+       .create_intent  = xfs_bmap_update_create_intent,
+       .abort_intent   = xfs_bmap_update_abort_intent,
+       .log_item       = xfs_bmap_update_log_item,
+       .create_done    = xfs_bmap_update_create_done,
+       .finish_item    = xfs_bmap_update_finish_item,
+       .cancel_item    = xfs_bmap_update_cancel_item,
+};
+
 /*
  * Process a bmap update intent item that was recovered from the log.
  * We need to update some inode's bmbt.
index 89e043a..ad479cc 100644 (file)
@@ -75,8 +75,6 @@ extern struct kmem_zone       *xfs_bui_zone;
 extern struct kmem_zone        *xfs_bud_zone;
 
 struct xfs_bui_log_item *xfs_bui_init(struct xfs_mount *);
-struct xfs_bud_log_item *xfs_bud_init(struct xfs_mount *,
-               struct xfs_bui_log_item *);
 void xfs_bui_item_free(struct xfs_bui_log_item *);
 void xfs_bui_release(struct xfs_bui_log_item *);
 int xfs_bui_recover(struct xfs_trans *parent_tp, struct xfs_bui_log_item *buip);
index 06d07f1..98c6a7a 100644 (file)
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
 #include "xfs_mount.h"
-#include "xfs_da_format.h"
 #include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
 #include "xfs_trans.h"
-#include "xfs_extfree_item.h"
 #include "xfs_alloc.h"
 #include "xfs_bmap.h"
 #include "xfs_bmap_util.h"
 #include "xfs_trans_space.h"
 #include "xfs_trace.h"
 #include "xfs_icache.h"
-#include "xfs_log.h"
-#include "xfs_rmap_btree.h"
 #include "xfs_iomap.h"
 #include "xfs_reflink.h"
-#include "xfs_refcount.h"
 
 /* Kernel only BMAP related definitions and functions */
 
@@ -276,7 +271,7 @@ xfs_bmap_count_tree(
        struct xfs_btree_block  *block, *nextblock;
        int                     numrecs;
 
-       error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, XFS_BMAP_BTREE_REF,
+       error = xfs_btree_read_bufl(mp, tp, bno, &bp, XFS_BMAP_BTREE_REF,
                                                &xfs_bmbt_buf_ops);
        if (error)
                return error;
@@ -287,7 +282,7 @@ xfs_bmap_count_tree(
                /* Not at node above leaves, count this level of nodes */
                nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
                while (nextbno != NULLFSBLOCK) {
-                       error = xfs_btree_read_bufl(mp, tp, nextbno, 0, &nbp,
+                       error = xfs_btree_read_bufl(mp, tp, nextbno, &nbp,
                                                XFS_BMAP_BTREE_REF,
                                                &xfs_bmbt_buf_ops);
                        if (error)
@@ -321,7 +316,7 @@ xfs_bmap_count_tree(
                        if (nextbno == NULLFSBLOCK)
                                break;
                        bno = nextbno;
-                       error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp,
+                       error = xfs_btree_read_bufl(mp, tp, bno, &bp,
                                                XFS_BMAP_BTREE_REF,
                                                &xfs_bmbt_buf_ops);
                        if (error)
index 548344e..ca08490 100644 (file)
@@ -4,24 +4,9 @@
  * All Rights Reserved.
  */
 #include "xfs.h"
-#include <linux/stddef.h>
-#include <linux/errno.h>
-#include <linux/gfp.h>
-#include <linux/pagemap.h>
-#include <linux/init.h>
-#include <linux/vmalloc.h>
-#include <linux/bio.h>
-#include <linux/sysctl.h>
-#include <linux/proc_fs.h>
-#include <linux/workqueue.h>
-#include <linux/percpu.h>
-#include <linux/blkdev.h>
-#include <linux/hash.h>
-#include <linux/kthread.h>
-#include <linux/migrate.h>
 #include <linux/backing-dev.h>
-#include <linux/freezer.h>
 
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
@@ -213,7 +198,7 @@ xfs_buf_free_maps(
        }
 }
 
-struct xfs_buf *
+static struct xfs_buf *
 _xfs_buf_alloc(
        struct xfs_buftarg      *target,
        struct xfs_buf_map      *map,
@@ -243,6 +228,7 @@ _xfs_buf_alloc(
        sema_init(&bp->b_sema, 0); /* held, no waiters */
        spin_lock_init(&bp->b_lock);
        bp->b_target = target;
+       bp->b_mount = target->bt_mount;
        bp->b_flags = flags;
 
        /*
@@ -263,12 +249,11 @@ _xfs_buf_alloc(
                bp->b_maps[i].bm_len = map[i].bm_len;
                bp->b_length += map[i].bm_len;
        }
-       bp->b_io_length = bp->b_length;
 
        atomic_set(&bp->b_pin_count, 0);
        init_waitqueue_head(&bp->b_waiters);
 
-       XFS_STATS_INC(target->bt_mount, xb_create);
+       XFS_STATS_INC(bp->b_mount, xb_create);
        trace_xfs_buf_init(bp, _RET_IP_);
 
        return bp;
@@ -425,12 +410,12 @@ retry:
                                        current->comm, current->pid,
                                        __func__, gfp_mask);
 
-                       XFS_STATS_INC(bp->b_target->bt_mount, xb_page_retries);
+                       XFS_STATS_INC(bp->b_mount, xb_page_retries);
                        congestion_wait(BLK_RW_ASYNC, HZ/50);
                        goto retry;
                }
 
-               XFS_STATS_INC(bp->b_target->bt_mount, xb_page_found);
+               XFS_STATS_INC(bp->b_mount, xb_page_found);
 
                nbytes = min_t(size_t, size, PAGE_SIZE - offset);
                size -= nbytes;
@@ -909,83 +894,6 @@ xfs_buf_read_uncached(
        return 0;
 }
 
-/*
- * Return a buffer allocated as an empty buffer and associated to external
- * memory via xfs_buf_associate_memory() back to it's empty state.
- */
-void
-xfs_buf_set_empty(
-       struct xfs_buf          *bp,
-       size_t                  numblks)
-{
-       if (bp->b_pages)
-               _xfs_buf_free_pages(bp);
-
-       bp->b_pages = NULL;
-       bp->b_page_count = 0;
-       bp->b_addr = NULL;
-       bp->b_length = numblks;
-       bp->b_io_length = numblks;
-
-       ASSERT(bp->b_map_count == 1);
-       bp->b_bn = XFS_BUF_DADDR_NULL;
-       bp->b_maps[0].bm_bn = XFS_BUF_DADDR_NULL;
-       bp->b_maps[0].bm_len = bp->b_length;
-}
-
-static inline struct page *
-mem_to_page(
-       void                    *addr)
-{
-       if ((!is_vmalloc_addr(addr))) {
-               return virt_to_page(addr);
-       } else {
-               return vmalloc_to_page(addr);
-       }
-}
-
-int
-xfs_buf_associate_memory(
-       xfs_buf_t               *bp,
-       void                    *mem,
-       size_t                  len)
-{
-       int                     rval;
-       int                     i = 0;
-       unsigned long           pageaddr;
-       unsigned long           offset;
-       size_t                  buflen;
-       int                     page_count;
-
-       pageaddr = (unsigned long)mem & PAGE_MASK;
-       offset = (unsigned long)mem - pageaddr;
-       buflen = PAGE_ALIGN(len + offset);
-       page_count = buflen >> PAGE_SHIFT;
-
-       /* Free any previous set of page pointers */
-       if (bp->b_pages)
-               _xfs_buf_free_pages(bp);
-
-       bp->b_pages = NULL;
-       bp->b_addr = mem;
-
-       rval = _xfs_buf_get_pages(bp, page_count);
-       if (rval)
-               return rval;
-
-       bp->b_offset = offset;
-
-       for (i = 0; i < bp->b_page_count; i++) {
-               bp->b_pages[i] = mem_to_page((void *)pageaddr);
-               pageaddr += PAGE_SIZE;
-       }
-
-       bp->b_io_length = BTOBB(len);
-       bp->b_length = BTOBB(buflen);
-
-       return 0;
-}
-
 xfs_buf_t *
 xfs_buf_get_uncached(
        struct xfs_buftarg      *target,
@@ -1180,7 +1088,7 @@ xfs_buf_lock(
        trace_xfs_buf_lock(bp, _RET_IP_);
 
        if (atomic_read(&bp->b_pin_count) && (bp->b_flags & XBF_STALE))
-               xfs_log_force(bp->b_target->bt_mount, 0);
+               xfs_log_force(bp->b_mount, 0);
        down(&bp->b_sema);
 
        trace_xfs_buf_lock_done(bp, _RET_IP_);
@@ -1269,7 +1177,7 @@ xfs_buf_ioend_async(
        struct xfs_buf  *bp)
 {
        INIT_WORK(&bp->b_ioend_work, xfs_buf_ioend_work);
-       queue_work(bp->b_ioend_wq, &bp->b_ioend_work);
+       queue_work(bp->b_mount->m_buf_workqueue, &bp->b_ioend_work);
 }
 
 void
@@ -1288,7 +1196,7 @@ xfs_buf_ioerror_alert(
        struct xfs_buf          *bp,
        const char              *func)
 {
-       xfs_alert(bp->b_target->bt_mount,
+       xfs_alert(bp->b_mount,
 "metadata I/O error in \"%s\" at daddr 0x%llx len %d error %d",
                        func, (uint64_t)XFS_BUF_ADDR(bp), bp->b_length,
                        -bp->b_error);
@@ -1307,10 +1215,8 @@ xfs_bwrite(
                         XBF_WRITE_FAIL | XBF_DONE);
 
        error = xfs_buf_submit(bp);
-       if (error) {
-               xfs_force_shutdown(bp->b_target->bt_mount,
-                                  SHUTDOWN_META_IO_ERROR);
-       }
+       if (error)
+               xfs_force_shutdown(bp->b_mount, SHUTDOWN_META_IO_ERROR);
        return error;
 }
 
@@ -1436,21 +1342,8 @@ _xfs_buf_ioapply(
         */
        bp->b_error = 0;
 
-       /*
-        * Initialize the I/O completion workqueue if we haven't yet or the
-        * submitter has not opted to specify a custom one.
-        */
-       if (!bp->b_ioend_wq)
-               bp->b_ioend_wq = bp->b_target->bt_mount->m_buf_workqueue;
-
        if (bp->b_flags & XBF_WRITE) {
                op = REQ_OP_WRITE;
-               if (bp->b_flags & XBF_SYNCIO)
-                       op_flags = REQ_SYNC;
-               if (bp->b_flags & XBF_FUA)
-                       op_flags |= REQ_FUA;
-               if (bp->b_flags & XBF_FLUSH)
-                       op_flags |= REQ_PREFLUSH;
 
                /*
                 * Run the write verifier callback function if it exists. If
@@ -1460,12 +1353,12 @@ _xfs_buf_ioapply(
                if (bp->b_ops) {
                        bp->b_ops->verify_write(bp);
                        if (bp->b_error) {
-                               xfs_force_shutdown(bp->b_target->bt_mount,
+                               xfs_force_shutdown(bp->b_mount,
                                                   SHUTDOWN_CORRUPT_INCORE);
                                return;
                        }
                } else if (bp->b_bn != XFS_BUF_DADDR_NULL) {
-                       struct xfs_mount *mp = bp->b_target->bt_mount;
+                       struct xfs_mount *mp = bp->b_mount;
 
                        /*
                         * non-crc filesystems don't attach verifiers during
@@ -1497,7 +1390,7 @@ _xfs_buf_ioapply(
         * subsequent call.
         */
        offset = bp->b_offset;
-       size = BBTOB(bp->b_io_length);
+       size = BBTOB(bp->b_length);
        blk_start_plug(&plug);
        for (i = 0; i < bp->b_map_count; i++) {
                xfs_buf_ioapply_map(bp, i, &offset, &size, op, op_flags);
@@ -1543,7 +1436,7 @@ __xfs_buf_submit(
        ASSERT(!(bp->b_flags & _XBF_DELWRI_Q));
 
        /* on shutdown we stale and complete the buffer immediately */
-       if (XFS_FORCED_SHUTDOWN(bp->b_target->bt_mount)) {
+       if (XFS_FORCED_SHUTDOWN(bp->b_mount)) {
                xfs_buf_ioerror(bp, -EIO);
                bp->b_flags &= ~XBF_DONE;
                xfs_buf_stale(bp);
@@ -1613,16 +1506,11 @@ xfs_buf_offset(
        return page_address(page) + (offset & (PAGE_SIZE-1));
 }
 
-/*
- *     Move data into or out of a buffer.
- */
 void
-xfs_buf_iomove(
-       xfs_buf_t               *bp,    /* buffer to process            */
-       size_t                  boff,   /* starting buffer offset       */
-       size_t                  bsize,  /* length to copy               */
-       void                    *data,  /* data address                 */
-       xfs_buf_rw_t            mode)   /* read/write/zero flag         */
+xfs_buf_zero(
+       struct xfs_buf          *bp,
+       size_t                  boff,
+       size_t                  bsize)
 {
        size_t                  bend;
 
@@ -1635,23 +1523,13 @@ xfs_buf_iomove(
                page_offset = (boff + bp->b_offset) & ~PAGE_MASK;
                page = bp->b_pages[page_index];
                csize = min_t(size_t, PAGE_SIZE - page_offset,
-                                     BBTOB(bp->b_io_length) - boff);
+                                     BBTOB(bp->b_length) - boff);
 
                ASSERT((csize + page_offset) <= PAGE_SIZE);
 
-               switch (mode) {
-               case XBRW_ZERO:
-                       memset(page_address(page) + page_offset, 0, csize);
-                       break;
-               case XBRW_READ:
-                       memcpy(data, page_address(page) + page_offset, csize);
-                       break;
-               case XBRW_WRITE:
-                       memcpy(page_address(page) + page_offset, data, csize);
-               }
+               memset(page_address(page) + page_offset, 0, csize);
 
                boff += csize;
-               data += csize;
        }
 }
 
@@ -2198,8 +2076,7 @@ void xfs_buf_set_ref(struct xfs_buf *bp, int lru_ref)
         * This allows userspace to disrupt buffer caching for debug/testing
         * purposes.
         */
-       if (XFS_TEST_ERROR(false, bp->b_target->bt_mount,
-                          XFS_ERRTAG_BUF_LRU_REF))
+       if (XFS_TEST_ERROR(false, bp->b_mount, XFS_ERRTAG_BUF_LRU_REF))
                lru_ref = 0;
 
        atomic_set(&bp->b_lru_ref, lru_ref);
@@ -2215,7 +2092,7 @@ xfs_verify_magic(
        struct xfs_buf          *bp,
        __be32                  dmagic)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        int                     idx;
 
        idx = xfs_sb_version_hascrc(&mp->m_sb);
@@ -2233,7 +2110,7 @@ xfs_verify_magic16(
        struct xfs_buf          *bp,
        __be16                  dmagic)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        int                     idx;
 
        idx = xfs_sb_version_hascrc(&mp->m_sb);
index d0b96e0..c6e57a3 100644 (file)
 
 #define XFS_BUF_DADDR_NULL     ((xfs_daddr_t) (-1LL))
 
-typedef enum {
-       XBRW_READ = 1,                  /* transfer into target memory */
-       XBRW_WRITE = 2,                 /* transfer from target memory */
-       XBRW_ZERO = 3,                  /* Zero target memory */
-} xfs_buf_rw_t;
-
 #define XBF_READ        (1 << 0) /* buffer intended for reading from device */
 #define XBF_WRITE       (1 << 1) /* buffer intended for writing to device */
 #define XBF_READ_AHEAD  (1 << 2) /* asynchronous read-ahead */
@@ -34,12 +28,7 @@ typedef enum {
 #define XBF_ASYNC       (1 << 4) /* initiator will not wait for completion */
 #define XBF_DONE        (1 << 5) /* all pages in the buffer uptodate */
 #define XBF_STALE       (1 << 6) /* buffer has been staled, do not find it */
-#define XBF_WRITE_FAIL  (1 << 24)/* async writes have failed on this buffer */
-
-/* I/O hints for the BIO layer */
-#define XBF_SYNCIO      (1 << 10)/* treat this buffer as synchronous I/O */
-#define XBF_FUA                 (1 << 11)/* force cache write through mode */
-#define XBF_FLUSH       (1 << 12)/* flush the disk cache before a write */
+#define XBF_WRITE_FAIL  (1 << 7) /* async writes have failed on this buffer */
 
 /* flags used only as arguments to access routines */
 #define XBF_TRYLOCK     (1 << 16)/* lock requested, but do not wait */
@@ -49,7 +38,6 @@ typedef enum {
 #define _XBF_PAGES      (1 << 20)/* backed by refcounted pages */
 #define _XBF_KMEM       (1 << 21)/* backed by heap memory */
 #define _XBF_DELWRI_Q   (1 << 22)/* buffer on a delwri queue */
-#define _XBF_COMPOUND   (1 << 23)/* compound buffer */
 
 typedef unsigned int xfs_buf_flags_t;
 
@@ -62,15 +50,11 @@ typedef unsigned int xfs_buf_flags_t;
        { XBF_DONE,             "DONE" }, \
        { XBF_STALE,            "STALE" }, \
        { XBF_WRITE_FAIL,       "WRITE_FAIL" }, \
-       { XBF_SYNCIO,           "SYNCIO" }, \
-       { XBF_FUA,              "FUA" }, \
-       { XBF_FLUSH,            "FLUSH" }, \
        { XBF_TRYLOCK,          "TRYLOCK" },    /* should never be set */\
        { XBF_UNMAPPED,         "UNMAPPED" },   /* ditto */\
        { _XBF_PAGES,           "PAGES" }, \
        { _XBF_KMEM,            "KMEM" }, \
-       { _XBF_DELWRI_Q,        "DELWRI_Q" }, \
-       { _XBF_COMPOUND,        "COMPOUND" }
+       { _XBF_DELWRI_Q,        "DELWRI_Q" }
 
 
 /*
@@ -161,13 +145,13 @@ typedef struct xfs_buf {
        wait_queue_head_t       b_waiters;      /* unpin waiters */
        struct list_head        b_list;
        struct xfs_perag        *b_pag;         /* contains rbtree root */
+       struct xfs_mount        *b_mount;
        xfs_buftarg_t           *b_target;      /* buffer target (device) */
        void                    *b_addr;        /* virtual address of buffer */
        struct work_struct      b_ioend_work;
-       struct workqueue_struct *b_ioend_wq;    /* I/O completion wq */
        xfs_buf_iodone_t        b_iodone;       /* I/O completion function */
        struct completion       b_iowait;       /* queue for I/O waiters */
-       void                    *b_log_item;
+       struct xfs_buf_log_item *b_log_item;
        struct list_head        b_li_list;      /* Log items list head */
        struct xfs_trans        *b_transp;
        struct page             **b_pages;      /* array of page pointers */
@@ -175,7 +159,6 @@ typedef struct xfs_buf {
        struct xfs_buf_map      *b_maps;        /* compound buffer map */
        struct xfs_buf_map      __b_map;        /* inline compound buffer map */
        int                     b_map_count;
-       int                     b_io_length;    /* IO size in BBs */
        atomic_t                b_pin_count;    /* pin count */
        atomic_t                b_io_remaining; /* #outstanding I/O requests */
        unsigned int            b_page_count;   /* size of page array */
@@ -209,21 +192,6 @@ struct xfs_buf *xfs_buf_incore(struct xfs_buftarg *target,
                           xfs_daddr_t blkno, size_t numblks,
                           xfs_buf_flags_t flags);
 
-struct xfs_buf *_xfs_buf_alloc(struct xfs_buftarg *target,
-                              struct xfs_buf_map *map, int nmaps,
-                              xfs_buf_flags_t flags);
-
-static inline struct xfs_buf *
-xfs_buf_alloc(
-       struct xfs_buftarg      *target,
-       xfs_daddr_t             blkno,
-       size_t                  numblks,
-       xfs_buf_flags_t         flags)
-{
-       DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
-       return _xfs_buf_alloc(target, &map, 1, flags);
-}
-
 struct xfs_buf *xfs_buf_get_map(struct xfs_buftarg *target,
                               struct xfs_buf_map *map, int nmaps,
                               xfs_buf_flags_t flags);
@@ -239,11 +207,10 @@ static inline struct xfs_buf *
 xfs_buf_get(
        struct xfs_buftarg      *target,
        xfs_daddr_t             blkno,
-       size_t                  numblks,
-       xfs_buf_flags_t         flags)
+       size_t                  numblks)
 {
        DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
-       return xfs_buf_get_map(target, &map, 1, flags);
+       return xfs_buf_get_map(target, &map, 1, 0);
 }
 
 static inline struct xfs_buf *
@@ -269,9 +236,6 @@ xfs_buf_readahead(
        return xfs_buf_readahead_map(target, &map, 1, ops);
 }
 
-void xfs_buf_set_empty(struct xfs_buf *bp, size_t numblks);
-int xfs_buf_associate_memory(struct xfs_buf *bp, void *mem, size_t length);
-
 struct xfs_buf *xfs_buf_get_uncached(struct xfs_buftarg *target, size_t numblks,
                                int flags);
 int xfs_buf_read_uncached(struct xfs_buftarg *target, xfs_daddr_t daddr,
@@ -305,10 +269,7 @@ static inline int xfs_buf_submit(struct xfs_buf *bp)
        return __xfs_buf_submit(bp, wait);
 }
 
-extern void xfs_buf_iomove(xfs_buf_t *, size_t, size_t, void *,
-                               xfs_buf_rw_t);
-#define xfs_buf_zero(bp, off, len) \
-           xfs_buf_iomove((bp), (off), (len), NULL, XBRW_ZERO)
+void xfs_buf_zero(struct xfs_buf *bp, size_t boff, size_t bsize);
 
 /* Buffer Utility Routines */
 extern void *xfs_buf_offset(struct xfs_buf *, size_t);
index 65b32ac..7dcaec5 100644 (file)
@@ -5,19 +5,17 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_trans.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_priv.h"
-#include "xfs_error.h"
 #include "xfs_trace.h"
 #include "xfs_log.h"
-#include "xfs_inode.h"
 
 
 kmem_zone_t    *xfs_buf_item_zone;
@@ -520,7 +518,7 @@ xfs_buf_item_push(
        /* has a previous flush failed due to IO errors? */
        if ((bp->b_flags & XBF_WRITE_FAIL) &&
            ___ratelimit(&xfs_buf_write_fail_rl_state, "XFS: Failing async write")) {
-               xfs_warn(bp->b_target->bt_mount,
+               xfs_warn(bp->b_mount,
 "Failing async write on buffer block 0x%llx. Retrying async write.",
                         (long long)bp->b_bn);
        }
@@ -594,7 +592,7 @@ xfs_buf_item_put(
  * free the item.
  */
 STATIC void
-xfs_buf_item_unlock(
+xfs_buf_item_release(
        struct xfs_log_item     *lip)
 {
        struct xfs_buf_log_item *bip = BUF_ITEM(lip);
@@ -609,7 +607,7 @@ xfs_buf_item_unlock(
                                                   &lip->li_flags);
 #endif
 
-       trace_xfs_buf_item_unlock(bip);
+       trace_xfs_buf_item_release(bip);
 
        /*
         * The bli dirty state should match whether the blf has logged segments
@@ -639,6 +637,14 @@ xfs_buf_item_unlock(
        xfs_buf_relse(bp);
 }
 
+STATIC void
+xfs_buf_item_committing(
+       struct xfs_log_item     *lip,
+       xfs_lsn_t               commit_lsn)
+{
+       return xfs_buf_item_release(lip);
+}
+
 /*
  * This is called to find out where the oldest active copy of the
  * buf log item in the on disk log resides now that the last log
@@ -671,25 +677,15 @@ xfs_buf_item_committed(
        return lsn;
 }
 
-STATIC void
-xfs_buf_item_committing(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               commit_lsn)
-{
-}
-
-/*
- * This is the ops vector shared by all buf log items.
- */
 static const struct xfs_item_ops xfs_buf_item_ops = {
        .iop_size       = xfs_buf_item_size,
        .iop_format     = xfs_buf_item_format,
        .iop_pin        = xfs_buf_item_pin,
        .iop_unpin      = xfs_buf_item_unpin,
-       .iop_unlock     = xfs_buf_item_unlock,
+       .iop_release    = xfs_buf_item_release,
+       .iop_committing = xfs_buf_item_committing,
        .iop_committed  = xfs_buf_item_committed,
        .iop_push       = xfs_buf_item_push,
-       .iop_committing = xfs_buf_item_committing
 };
 
 STATIC int
@@ -743,7 +739,7 @@ xfs_buf_item_init(
         * this buffer. If we do already have one, there is
         * nothing to do here so return.
         */
-       ASSERT(bp->b_target->bt_mount == mp);
+       ASSERT(bp->b_mount == mp);
        if (bip) {
                ASSERT(bip->bli_item.li_type == XFS_LI_BUF);
                ASSERT(!bp->b_transp);
@@ -980,9 +976,9 @@ xfs_buf_item_relse(
  */
 void
 xfs_buf_attach_iodone(
-       xfs_buf_t       *bp,
-       void            (*cb)(xfs_buf_t *, xfs_log_item_t *),
-       xfs_log_item_t  *lip)
+       struct xfs_buf          *bp,
+       void                    (*cb)(struct xfs_buf *, struct xfs_log_item *),
+       struct xfs_log_item     *lip)
 {
        ASSERT(xfs_buf_islocked(bp));
 
index 90f65f8..4a054b1 100644 (file)
@@ -39,7 +39,7 @@ struct xfs_buf_log_item;
  * locked, and which 128 byte chunks of the buffer are dirty.
  */
 struct xfs_buf_log_item {
-       xfs_log_item_t          bli_item;       /* common item structure */
+       struct xfs_log_item     bli_item;       /* common item structure */
        struct xfs_buf          *bli_buf;       /* real buffer pointer */
        unsigned int            bli_flags;      /* misc flags */
        unsigned int            bli_recur;      /* lock recursion count */
@@ -55,8 +55,8 @@ bool  xfs_buf_item_put(struct xfs_buf_log_item *);
 void   xfs_buf_item_log(struct xfs_buf_log_item *, uint, uint);
 bool   xfs_buf_item_dirty_format(struct xfs_buf_log_item *);
 void   xfs_buf_attach_iodone(struct xfs_buf *,
-                             void(*)(struct xfs_buf *, xfs_log_item_t *),
-                             xfs_log_item_t *);
+                             void(*)(struct xfs_buf *, struct xfs_log_item *),
+                             struct xfs_log_item *);
 void   xfs_buf_iodone_callbacks(struct xfs_buf *);
 void   xfs_buf_iodone(struct xfs_buf *, struct xfs_log_item *);
 bool   xfs_buf_resubmit_failed_buffers(struct xfs_buf *,
index 5142e64..283df89 100644 (file)
@@ -6,17 +6,14 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_bit.h"
 #include "xfs_mount.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_inode.h"
 #include "xfs_dir2.h"
 #include "xfs_dir2_priv.h"
-#include "xfs_error.h"
 #include "xfs_trace.h"
 #include "xfs_bmap.h"
 #include "xfs_trans.h"
index d0df0ed..8ec7aab 100644 (file)
@@ -4,19 +4,17 @@
  * All Rights Reserved.
  */
 #include "xfs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
-#include "xfs_quota.h"
-#include "xfs_inode.h"
 #include "xfs_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_alloc.h"
 #include "xfs_error.h"
 #include "xfs_extent_busy.h"
-#include "xfs_discard.h"
 #include "xfs_trace.h"
 #include "xfs_log.h"
 
index a1af984..fb1ad44 100644 (file)
 #include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_bmap.h"
-#include "xfs_bmap_util.h"
-#include "xfs_alloc.h"
 #include "xfs_quota.h"
-#include "xfs_error.h"
 #include "xfs_trans.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_space.h"
 #include "xfs_trans_priv.h"
 #include "xfs_qm.h"
-#include "xfs_cksum.h"
 #include "xfs_trace.h"
 #include "xfs_log.h"
 #include "xfs_bmap_btree.h"
@@ -1243,7 +1239,7 @@ xfs_qm_exit(void)
 /*
  * Iterate every dquot of a particular type.  The caller must ensure that the
  * particular quota type is active.  iter_fn can return negative error codes,
- * or XFS_BTREE_QUERY_RANGE_ABORT to indicate that it wants to stop iterating.
+ * or XFS_ITER_ABORT to indicate that it wants to stop iterating.
  */
 int
 xfs_qm_dqiterate(
index 64bd864..4fe8570 100644 (file)
@@ -34,7 +34,6 @@ typedef struct xfs_dquot {
        uint             dq_flags;      /* various flags (XFS_DQ_*) */
        struct list_head q_lru;         /* global free list of dquots */
        struct xfs_mount*q_mount;       /* filesystem this relates to */
-       struct xfs_trans*q_transp;      /* trans this belongs to currently */
        uint             q_nrefs;       /* # active refs from inodes */
        xfs_daddr_t      q_blkno;       /* blkno of dquot buffer */
        int              q_bufoffset;   /* off of dq in buffer (# dquots) */
index 7dedd17..282ec5a 100644 (file)
@@ -5,13 +5,13 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
 #include "xfs_inode.h"
 #include "xfs_quota.h"
-#include "xfs_error.h"
 #include "xfs_trans.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_priv.h"
@@ -94,18 +94,6 @@ xfs_qm_dquot_logitem_unpin(
                wake_up(&dqp->q_pinwait);
 }
 
-STATIC xfs_lsn_t
-xfs_qm_dquot_logitem_committed(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
-{
-       /*
-        * We always re-log the entire dquot when it becomes dirty,
-        * so, the latest copy _is_ the only one that matters.
-        */
-       return lsn;
-}
-
 /*
  * This is called to wait for the given dquot to be unpinned.
  * Most of these pin/unpin routines are plagiarized from inode code.
@@ -209,25 +197,14 @@ out_unlock:
        return rval;
 }
 
-/*
- * Unlock the dquot associated with the log item.
- * Clear the fields of the dquot and dquot log item that
- * are specific to the current transaction.  If the
- * hold flags is set, do not unlock the dquot.
- */
 STATIC void
-xfs_qm_dquot_logitem_unlock(
+xfs_qm_dquot_logitem_release(
        struct xfs_log_item     *lip)
 {
        struct xfs_dquot        *dqp = DQUOT_ITEM(lip)->qli_dquot;
 
        ASSERT(XFS_DQ_IS_LOCKED(dqp));
 
-       /*
-        * Clear the transaction pointer in the dquot
-        */
-       dqp->q_transp = NULL;
-
        /*
         * dquots are never 'held' from getting unlocked at the end of
         * a transaction.  Their locking and unlocking is hidden inside the
@@ -237,30 +214,22 @@ xfs_qm_dquot_logitem_unlock(
        xfs_dqunlock(dqp);
 }
 
-/*
- * this needs to stamp an lsn into the dquot, I think.
- * rpc's that look at user dquot's would then have to
- * push on the dependency recorded in the dquot
- */
 STATIC void
 xfs_qm_dquot_logitem_committing(
        struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
+       xfs_lsn_t               commit_lsn)
 {
+       return xfs_qm_dquot_logitem_release(lip);
 }
 
-/*
- * This is the ops vector for dquots
- */
 static const struct xfs_item_ops xfs_dquot_item_ops = {
        .iop_size       = xfs_qm_dquot_logitem_size,
        .iop_format     = xfs_qm_dquot_logitem_format,
        .iop_pin        = xfs_qm_dquot_logitem_pin,
        .iop_unpin      = xfs_qm_dquot_logitem_unpin,
-       .iop_unlock     = xfs_qm_dquot_logitem_unlock,
-       .iop_committed  = xfs_qm_dquot_logitem_committed,
+       .iop_release    = xfs_qm_dquot_logitem_release,
+       .iop_committing = xfs_qm_dquot_logitem_committing,
        .iop_push       = xfs_qm_dquot_logitem_push,
-       .iop_committing = xfs_qm_dquot_logitem_committing,
        .iop_error      = xfs_dquot_item_error
 };
 
@@ -319,26 +288,6 @@ xfs_qm_qoff_logitem_format(
        xlog_finish_iovec(lv, vecp, sizeof(struct xfs_qoff_logitem));
 }
 
-/*
- * Pinning has no meaning for an quotaoff item, so just return.
- */
-STATIC void
-xfs_qm_qoff_logitem_pin(
-       struct xfs_log_item     *lip)
-{
-}
-
-/*
- * Since pinning has no meaning for an quotaoff item, unpinning does
- * not either.
- */
-STATIC void
-xfs_qm_qoff_logitem_unpin(
-       struct xfs_log_item     *lip,
-       int                     remove)
-{
-}
-
 /*
  * There isn't much you can do to push a quotaoff item.  It is simply
  * stuck waiting for the log to be flushed to disk.
@@ -351,28 +300,6 @@ xfs_qm_qoff_logitem_push(
        return XFS_ITEM_LOCKED;
 }
 
-/*
- * Quotaoff items have no locking or pushing, so return failure
- * so that the caller doesn't bother with us.
- */
-STATIC void
-xfs_qm_qoff_logitem_unlock(
-       struct xfs_log_item     *lip)
-{
-}
-
-/*
- * The quotaoff-start-item is logged only once and cannot be moved in the log,
- * so simply return the lsn at which it's been logged.
- */
-STATIC xfs_lsn_t
-xfs_qm_qoff_logitem_committed(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
-{
-       return lsn;
-}
-
 STATIC xfs_lsn_t
 xfs_qm_qoffend_logitem_committed(
        struct xfs_log_item     *lip,
@@ -396,50 +323,17 @@ xfs_qm_qoffend_logitem_committed(
        return (xfs_lsn_t)-1;
 }
 
-/*
- * XXX rcc - don't know quite what to do with this.  I think we can
- * just ignore it.  The only time that isn't the case is if we allow
- * the client to somehow see that quotas have been turned off in which
- * we can't allow that to get back until the quotaoff hits the disk.
- * So how would that happen?  Also, do we need different routines for
- * quotaoff start and quotaoff end?  I suspect the answer is yes but
- * to be sure, I need to look at the recovery code and see how quota off
- * recovery is handled (do we roll forward or back or do something else).
- * If we roll forwards or backwards, then we need two separate routines,
- * one that does nothing and one that stamps in the lsn that matters
- * (truly makes the quotaoff irrevocable).  If we do something else,
- * then maybe we don't need two.
- */
-STATIC void
-xfs_qm_qoff_logitem_committing(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               commit_lsn)
-{
-}
-
 static const struct xfs_item_ops xfs_qm_qoffend_logitem_ops = {
        .iop_size       = xfs_qm_qoff_logitem_size,
        .iop_format     = xfs_qm_qoff_logitem_format,
-       .iop_pin        = xfs_qm_qoff_logitem_pin,
-       .iop_unpin      = xfs_qm_qoff_logitem_unpin,
-       .iop_unlock     = xfs_qm_qoff_logitem_unlock,
        .iop_committed  = xfs_qm_qoffend_logitem_committed,
        .iop_push       = xfs_qm_qoff_logitem_push,
-       .iop_committing = xfs_qm_qoff_logitem_committing
 };
 
-/*
- * This is the ops vector shared by all quotaoff-start log items.
- */
 static const struct xfs_item_ops xfs_qm_qoff_logitem_ops = {
        .iop_size       = xfs_qm_qoff_logitem_size,
        .iop_format     = xfs_qm_qoff_logitem_format,
-       .iop_pin        = xfs_qm_qoff_logitem_pin,
-       .iop_unpin      = xfs_qm_qoff_logitem_unpin,
-       .iop_unlock     = xfs_qm_qoff_logitem_unlock,
-       .iop_committed  = xfs_qm_qoff_logitem_committed,
        .iop_push       = xfs_qm_qoff_logitem_push,
-       .iop_committing = xfs_qm_qoff_logitem_committing
 };
 
 /*
index db9df71..1aed34c 100644 (file)
@@ -12,13 +12,13 @@ struct xfs_mount;
 struct xfs_qoff_logitem;
 
 typedef struct xfs_dq_logitem {
-       xfs_log_item_t           qli_item;         /* common portion */
+       struct xfs_log_item      qli_item;         /* common portion */
        struct xfs_dquot        *qli_dquot;        /* dquot ptr */
        xfs_lsn_t                qli_flush_lsn;    /* lsn at last flush */
 } xfs_dq_logitem_t;
 
 typedef struct xfs_qoff_logitem {
-       xfs_log_item_t           qql_item;      /* common portion */
+       struct xfs_log_item      qql_item;      /* common portion */
        struct xfs_qoff_logitem *qql_start_lip; /* qoff-start logitem, if any */
        unsigned int            qql_flags;
 } xfs_qoff_logitem_t;
index a1e177f..544c948 100644 (file)
@@ -4,6 +4,7 @@
  * All Rights Reserved.
  */
 #include "xfs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_fs.h"
 #include "xfs_log_format.h"
@@ -353,7 +354,7 @@ xfs_buf_verifier_error(
        size_t                  bufsz,
        xfs_failaddr_t          failaddr)
 {
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_mount        *mp = bp->b_mount;
        xfs_failaddr_t          fa;
        int                     sz;
 
index f2284ce..f1372f9 100644 (file)
@@ -4,18 +4,16 @@
  * All Rights Reserved.
  */
 #include "xfs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_dir2.h"
 #include "xfs_export.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
 #include "xfs_inode_item.h"
-#include "xfs_trace.h"
 #include "xfs_icache.h"
 #include "xfs_log.h"
 #include "xfs_pnfs.h"
index 74ddf66..86f6512 100644 (file)
@@ -9,14 +9,18 @@
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
+#include "xfs_shared.h"
 #include "xfs_mount.h"
+#include "xfs_defer.h"
 #include "xfs_trans.h"
 #include "xfs_trans_priv.h"
-#include "xfs_buf_item.h"
 #include "xfs_extfree_item.h"
 #include "xfs_log.h"
 #include "xfs_btree.h"
 #include "xfs_rmap.h"
+#include "xfs_alloc.h"
+#include "xfs_bmap.h"
+#include "xfs_trace.h"
 
 
 kmem_zone_t    *xfs_efi_zone;
@@ -106,15 +110,6 @@ xfs_efi_item_format(
 }
 
 
-/*
- * Pinning has no meaning for an efi item, so just return.
- */
-STATIC void
-xfs_efi_item_pin(
-       struct xfs_log_item     *lip)
-{
-}
-
 /*
  * The unpin operation is the last place an EFI is manipulated in the log. It is
  * either inserted in the AIL or aborted in the event of a log I/O error. In
@@ -132,72 +127,23 @@ xfs_efi_item_unpin(
        xfs_efi_release(efip);
 }
 
-/*
- * Efi items have no locking or pushing.  However, since EFIs are pulled from
- * the AIL when their corresponding EFDs are committed to disk, their situation
- * is very similar to being pinned.  Return XFS_ITEM_PINNED so that the caller
- * will eventually flush the log.  This should help in getting the EFI out of
- * the AIL.
- */
-STATIC uint
-xfs_efi_item_push(
-       struct xfs_log_item     *lip,
-       struct list_head        *buffer_list)
-{
-       return XFS_ITEM_PINNED;
-}
-
 /*
  * The EFI has been either committed or aborted if the transaction has been
  * cancelled. If the transaction was cancelled, an EFD isn't going to be
  * constructed and thus we free the EFI here directly.
  */
 STATIC void
-xfs_efi_item_unlock(
+xfs_efi_item_release(
        struct xfs_log_item     *lip)
 {
-       if (test_bit(XFS_LI_ABORTED, &lip->li_flags))
-               xfs_efi_release(EFI_ITEM(lip));
-}
-
-/*
- * The EFI is logged only once and cannot be moved in the log, so simply return
- * the lsn at which it's been logged.
- */
-STATIC xfs_lsn_t
-xfs_efi_item_committed(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
-{
-       return lsn;
-}
-
-/*
- * The EFI dependency tracking op doesn't do squat.  It can't because
- * it doesn't know where the free extent is coming from.  The dependency
- * tracking has to be handled by the "enclosing" metadata object.  For
- * example, for inodes, the inode is locked throughout the extent freeing
- * so the dependency should be recorded there.
- */
-STATIC void
-xfs_efi_item_committing(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
-{
+       xfs_efi_release(EFI_ITEM(lip));
 }
 
-/*
- * This is the ops vector shared by all efi log items.
- */
 static const struct xfs_item_ops xfs_efi_item_ops = {
        .iop_size       = xfs_efi_item_size,
        .iop_format     = xfs_efi_item_format,
-       .iop_pin        = xfs_efi_item_pin,
        .iop_unpin      = xfs_efi_item_unpin,
-       .iop_unlock     = xfs_efi_item_unlock,
-       .iop_committed  = xfs_efi_item_committed,
-       .iop_push       = xfs_efi_item_push,
-       .iop_committing = xfs_efi_item_committing
+       .iop_release    = xfs_efi_item_release,
 };
 
 
@@ -349,136 +295,298 @@ xfs_efd_item_format(
 }
 
 /*
- * Pinning has no meaning for an efd item, so just return.
+ * The EFD is either committed or aborted if the transaction is cancelled. If
+ * the transaction is cancelled, drop our reference to the EFI and free the EFD.
  */
 STATIC void
-xfs_efd_item_pin(
+xfs_efd_item_release(
        struct xfs_log_item     *lip)
 {
+       struct xfs_efd_log_item *efdp = EFD_ITEM(lip);
+
+       xfs_efi_release(efdp->efd_efip);
+       xfs_efd_item_free(efdp);
 }
 
+static const struct xfs_item_ops xfs_efd_item_ops = {
+       .flags          = XFS_ITEM_RELEASE_WHEN_COMMITTED,
+       .iop_size       = xfs_efd_item_size,
+       .iop_format     = xfs_efd_item_format,
+       .iop_release    = xfs_efd_item_release,
+};
+
 /*
- * Since pinning has no meaning for an efd item, unpinning does
- * not either.
+ * Allocate an "extent free done" log item that will hold nextents worth of
+ * extents.  The caller must use all nextents extents, because we are not
+ * flexible about this at all.
  */
-STATIC void
-xfs_efd_item_unpin(
-       struct xfs_log_item     *lip,
-       int                     remove)
+static struct xfs_efd_log_item *
+xfs_trans_get_efd(
+       struct xfs_trans                *tp,
+       struct xfs_efi_log_item         *efip,
+       unsigned int                    nextents)
 {
+       struct xfs_efd_log_item         *efdp;
+
+       ASSERT(nextents > 0);
+
+       if (nextents > XFS_EFD_MAX_FAST_EXTENTS) {
+               efdp = kmem_zalloc(sizeof(struct xfs_efd_log_item) +
+                               (nextents - 1) * sizeof(struct xfs_extent),
+                               KM_SLEEP);
+       } else {
+               efdp = kmem_zone_zalloc(xfs_efd_zone, KM_SLEEP);
+       }
+
+       xfs_log_item_init(tp->t_mountp, &efdp->efd_item, XFS_LI_EFD,
+                         &xfs_efd_item_ops);
+       efdp->efd_efip = efip;
+       efdp->efd_format.efd_nextents = nextents;
+       efdp->efd_format.efd_efi_id = efip->efi_format.efi_id;
+
+       xfs_trans_add_item(tp, &efdp->efd_item);
+       return efdp;
 }
 
 /*
- * There isn't much you can do to push on an efd item.  It is simply stuck
- * waiting for the log to be flushed to disk.
+ * Free an extent and log it to the EFD. Note that the transaction is marked
+ * dirty regardless of whether the extent free succeeds or fails to support the
+ * EFI/EFD lifecycle rules.
  */
-STATIC uint
-xfs_efd_item_push(
-       struct xfs_log_item     *lip,
-       struct list_head        *buffer_list)
+static int
+xfs_trans_free_extent(
+       struct xfs_trans                *tp,
+       struct xfs_efd_log_item         *efdp,
+       xfs_fsblock_t                   start_block,
+       xfs_extlen_t                    ext_len,
+       const struct xfs_owner_info     *oinfo,
+       bool                            skip_discard)
 {
-       return XFS_ITEM_PINNED;
+       struct xfs_mount                *mp = tp->t_mountp;
+       struct xfs_extent               *extp;
+       uint                            next_extent;
+       xfs_agnumber_t                  agno = XFS_FSB_TO_AGNO(mp, start_block);
+       xfs_agblock_t                   agbno = XFS_FSB_TO_AGBNO(mp,
+                                                               start_block);
+       int                             error;
+
+       trace_xfs_bmap_free_deferred(tp->t_mountp, agno, 0, agbno, ext_len);
+
+       error = __xfs_free_extent(tp, start_block, ext_len,
+                                 oinfo, XFS_AG_RESV_NONE, skip_discard);
+       /*
+        * Mark the transaction dirty, even on error. This ensures the
+        * transaction is aborted, which:
+        *
+        * 1.) releases the EFI and frees the EFD
+        * 2.) shuts down the filesystem
+        */
+       tp->t_flags |= XFS_TRANS_DIRTY;
+       set_bit(XFS_LI_DIRTY, &efdp->efd_item.li_flags);
+
+       next_extent = efdp->efd_next_extent;
+       ASSERT(next_extent < efdp->efd_format.efd_nextents);
+       extp = &(efdp->efd_format.efd_extents[next_extent]);
+       extp->ext_start = start_block;
+       extp->ext_len = ext_len;
+       efdp->efd_next_extent++;
+
+       return error;
 }
 
-/*
- * The EFD is either committed or aborted if the transaction is cancelled. If
- * the transaction is cancelled, drop our reference to the EFI and free the EFD.
- */
-STATIC void
-xfs_efd_item_unlock(
-       struct xfs_log_item     *lip)
+/* Sort bmap items by AG. */
+static int
+xfs_extent_free_diff_items(
+       void                            *priv,
+       struct list_head                *a,
+       struct list_head                *b)
 {
-       struct xfs_efd_log_item *efdp = EFD_ITEM(lip);
+       struct xfs_mount                *mp = priv;
+       struct xfs_extent_free_item     *ra;
+       struct xfs_extent_free_item     *rb;
+
+       ra = container_of(a, struct xfs_extent_free_item, xefi_list);
+       rb = container_of(b, struct xfs_extent_free_item, xefi_list);
+       return  XFS_FSB_TO_AGNO(mp, ra->xefi_startblock) -
+               XFS_FSB_TO_AGNO(mp, rb->xefi_startblock);
+}
 
-       if (test_bit(XFS_LI_ABORTED, &lip->li_flags)) {
-               xfs_efi_release(efdp->efd_efip);
-               xfs_efd_item_free(efdp);
-       }
+/* Get an EFI. */
+STATIC void *
+xfs_extent_free_create_intent(
+       struct xfs_trans                *tp,
+       unsigned int                    count)
+{
+       struct xfs_efi_log_item         *efip;
+
+       ASSERT(tp != NULL);
+       ASSERT(count > 0);
+
+       efip = xfs_efi_init(tp->t_mountp, count);
+       ASSERT(efip != NULL);
+
+       /*
+        * Get a log_item_desc to point at the new item.
+        */
+       xfs_trans_add_item(tp, &efip->efi_item);
+       return efip;
 }
 
-/*
- * When the efd item is committed to disk, all we need to do is delete our
- * reference to our partner efi item and then free ourselves. Since we're
- * freeing ourselves we must return -1 to keep the transaction code from further
- * referencing this item.
- */
-STATIC xfs_lsn_t
-xfs_efd_item_committed(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
+/* Log a free extent to the intent item. */
+STATIC void
+xfs_extent_free_log_item(
+       struct xfs_trans                *tp,
+       void                            *intent,
+       struct list_head                *item)
 {
-       struct xfs_efd_log_item *efdp = EFD_ITEM(lip);
+       struct xfs_efi_log_item         *efip = intent;
+       struct xfs_extent_free_item     *free;
+       uint                            next_extent;
+       struct xfs_extent               *extp;
+
+       free = container_of(item, struct xfs_extent_free_item, xefi_list);
+
+       tp->t_flags |= XFS_TRANS_DIRTY;
+       set_bit(XFS_LI_DIRTY, &efip->efi_item.li_flags);
 
        /*
-        * Drop the EFI reference regardless of whether the EFD has been
-        * aborted. Once the EFD transaction is constructed, it is the sole
-        * responsibility of the EFD to release the EFI (even if the EFI is
-        * aborted due to log I/O error).
+        * atomic_inc_return gives us the value after the increment;
+        * we want to use it as an array index so we need to subtract 1 from
+        * it.
         */
-       xfs_efi_release(efdp->efd_efip);
-       xfs_efd_item_free(efdp);
+       next_extent = atomic_inc_return(&efip->efi_next_extent) - 1;
+       ASSERT(next_extent < efip->efi_format.efi_nextents);
+       extp = &efip->efi_format.efi_extents[next_extent];
+       extp->ext_start = free->xefi_startblock;
+       extp->ext_len = free->xefi_blockcount;
+}
 
-       return (xfs_lsn_t)-1;
+/* Get an EFD so we can process all the free extents. */
+STATIC void *
+xfs_extent_free_create_done(
+       struct xfs_trans                *tp,
+       void                            *intent,
+       unsigned int                    count)
+{
+       return xfs_trans_get_efd(tp, intent, count);
 }
 
-/*
- * The EFD dependency tracking op doesn't do squat.  It can't because
- * it doesn't know where the free extent is coming from.  The dependency
- * tracking has to be handled by the "enclosing" metadata object.  For
- * example, for inodes, the inode is locked throughout the extent freeing
- * so the dependency should be recorded there.
- */
+/* Process a free extent. */
+STATIC int
+xfs_extent_free_finish_item(
+       struct xfs_trans                *tp,
+       struct list_head                *item,
+       void                            *done_item,
+       void                            **state)
+{
+       struct xfs_extent_free_item     *free;
+       int                             error;
+
+       free = container_of(item, struct xfs_extent_free_item, xefi_list);
+       error = xfs_trans_free_extent(tp, done_item,
+                       free->xefi_startblock,
+                       free->xefi_blockcount,
+                       &free->xefi_oinfo, free->xefi_skip_discard);
+       kmem_free(free);
+       return error;
+}
+
+/* Abort all pending EFIs. */
 STATIC void
-xfs_efd_item_committing(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
+xfs_extent_free_abort_intent(
+       void                            *intent)
 {
+       xfs_efi_release(intent);
 }
 
-/*
- * This is the ops vector shared by all efd log items.
- */
-static const struct xfs_item_ops xfs_efd_item_ops = {
-       .iop_size       = xfs_efd_item_size,
-       .iop_format     = xfs_efd_item_format,
-       .iop_pin        = xfs_efd_item_pin,
-       .iop_unpin      = xfs_efd_item_unpin,
-       .iop_unlock     = xfs_efd_item_unlock,
-       .iop_committed  = xfs_efd_item_committed,
-       .iop_push       = xfs_efd_item_push,
-       .iop_committing = xfs_efd_item_committing
+/* Cancel a free extent. */
+STATIC void
+xfs_extent_free_cancel_item(
+       struct list_head                *item)
+{
+       struct xfs_extent_free_item     *free;
+
+       free = container_of(item, struct xfs_extent_free_item, xefi_list);
+       kmem_free(free);
+}
+
+const struct xfs_defer_op_type xfs_extent_free_defer_type = {
+       .max_items      = XFS_EFI_MAX_FAST_EXTENTS,
+       .diff_items     = xfs_extent_free_diff_items,
+       .create_intent  = xfs_extent_free_create_intent,
+       .abort_intent   = xfs_extent_free_abort_intent,
+       .log_item       = xfs_extent_free_log_item,
+       .create_done    = xfs_extent_free_create_done,
+       .finish_item    = xfs_extent_free_finish_item,
+       .cancel_item    = xfs_extent_free_cancel_item,
 };
 
 /*
- * Allocate and initialize an efd item with the given number of extents.
+ * AGFL blocks are accounted differently in the reserve pools and are not
+ * inserted into the busy extent list.
  */
-struct xfs_efd_log_item *
-xfs_efd_init(
-       struct xfs_mount        *mp,
-       struct xfs_efi_log_item *efip,
-       uint                    nextents)
-
+STATIC int
+xfs_agfl_free_finish_item(
+       struct xfs_trans                *tp,
+       struct list_head                *item,
+       void                            *done_item,
+       void                            **state)
 {
-       struct xfs_efd_log_item *efdp;
-       uint                    size;
+       struct xfs_mount                *mp = tp->t_mountp;
+       struct xfs_efd_log_item         *efdp = done_item;
+       struct xfs_extent_free_item     *free;
+       struct xfs_extent               *extp;
+       struct xfs_buf                  *agbp;
+       int                             error;
+       xfs_agnumber_t                  agno;
+       xfs_agblock_t                   agbno;
+       uint                            next_extent;
+
+       free = container_of(item, struct xfs_extent_free_item, xefi_list);
+       ASSERT(free->xefi_blockcount == 1);
+       agno = XFS_FSB_TO_AGNO(mp, free->xefi_startblock);
+       agbno = XFS_FSB_TO_AGBNO(mp, free->xefi_startblock);
+
+       trace_xfs_agfl_free_deferred(mp, agno, 0, agbno, free->xefi_blockcount);
+
+       error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
+       if (!error)
+               error = xfs_free_agfl_block(tp, agno, agbno, agbp,
+                                           &free->xefi_oinfo);
 
-       ASSERT(nextents > 0);
-       if (nextents > XFS_EFD_MAX_FAST_EXTENTS) {
-               size = (uint)(sizeof(xfs_efd_log_item_t) +
-                       ((nextents - 1) * sizeof(xfs_extent_t)));
-               efdp = kmem_zalloc(size, KM_SLEEP);
-       } else {
-               efdp = kmem_zone_zalloc(xfs_efd_zone, KM_SLEEP);
-       }
+       /*
+        * Mark the transaction dirty, even on error. This ensures the
+        * transaction is aborted, which:
+        *
+        * 1.) releases the EFI and frees the EFD
+        * 2.) shuts down the filesystem
+        */
+       tp->t_flags |= XFS_TRANS_DIRTY;
+       set_bit(XFS_LI_DIRTY, &efdp->efd_item.li_flags);
 
-       xfs_log_item_init(mp, &efdp->efd_item, XFS_LI_EFD, &xfs_efd_item_ops);
-       efdp->efd_efip = efip;
-       efdp->efd_format.efd_nextents = nextents;
-       efdp->efd_format.efd_efi_id = efip->efi_format.efi_id;
+       next_extent = efdp->efd_next_extent;
+       ASSERT(next_extent < efdp->efd_format.efd_nextents);
+       extp = &(efdp->efd_format.efd_extents[next_extent]);
+       extp->ext_start = free->xefi_startblock;
+       extp->ext_len = free->xefi_blockcount;
+       efdp->efd_next_extent++;
 
-       return efdp;
+       kmem_free(free);
+       return error;
 }
 
+/* sub-type with special handling for AGFL deferred frees */
+const struct xfs_defer_op_type xfs_agfl_free_defer_type = {
+       .max_items      = XFS_EFI_MAX_FAST_EXTENTS,
+       .diff_items     = xfs_extent_free_diff_items,
+       .create_intent  = xfs_extent_free_create_intent,
+       .abort_intent   = xfs_extent_free_abort_intent,
+       .log_item       = xfs_extent_free_log_item,
+       .create_done    = xfs_extent_free_create_done,
+       .finish_item    = xfs_agfl_free_finish_item,
+       .cancel_item    = xfs_extent_free_cancel_item,
+};
+
 /*
  * Process an extent free intent item that was recovered from
  * the log.  We need to free the extents that it describes.
index 2a6a895..16aaab0 100644 (file)
@@ -51,7 +51,7 @@ struct kmem_zone;
  * AIL, so at this point both the EFI and EFD are freed.
  */
 typedef struct xfs_efi_log_item {
-       xfs_log_item_t          efi_item;
+       struct xfs_log_item     efi_item;
        atomic_t                efi_refcount;
        atomic_t                efi_next_extent;
        unsigned long           efi_flags;      /* misc flags */
@@ -64,7 +64,7 @@ typedef struct xfs_efi_log_item {
  * have been freed.
  */
 typedef struct xfs_efd_log_item {
-       xfs_log_item_t          efd_item;
+       struct xfs_log_item     efd_item;
        xfs_efi_log_item_t      *efd_efip;
        uint                    efd_next_extent;
        xfs_efd_log_format_t    efd_format;
@@ -79,8 +79,6 @@ extern struct kmem_zone       *xfs_efi_zone;
 extern struct kmem_zone        *xfs_efd_zone;
 
 xfs_efi_log_item_t     *xfs_efi_init(struct xfs_mount *, uint);
-xfs_efd_log_item_t     *xfs_efd_init(struct xfs_mount *, xfs_efi_log_item_t *,
-                                     uint);
 int                    xfs_efi_copy_format(xfs_log_iovec_t *buf,
                                            xfs_efi_log_format_t *dst_efi_fmt);
 void                   xfs_efi_item_free(xfs_efi_log_item_t *);
index 916a35c..e93bacb 100644 (file)
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
 #include "xfs_inode_item.h"
 #include "xfs_bmap.h"
 #include "xfs_bmap_util.h"
-#include "xfs_error.h"
 #include "xfs_dir2.h"
 #include "xfs_dir2_priv.h"
 #include "xfs_ioctl.h"
@@ -28,9 +25,7 @@
 #include "xfs_iomap.h"
 #include "xfs_reflink.h"
 
-#include <linux/dcache.h>
 #include <linux/falloc.h>
-#include <linux/pagevec.h>
 #include <linux/backing-dev.h>
 #include <linux/mman.h>
 
@@ -379,6 +374,7 @@ xfs_dio_write_end_io(
        struct inode            *inode = file_inode(iocb->ki_filp);
        struct xfs_inode        *ip = XFS_I(inode);
        loff_t                  offset = iocb->ki_pos;
+       unsigned int            nofs_flag;
        int                     error = 0;
 
        trace_xfs_end_io_direct_write(ip, offset, size);
@@ -395,10 +391,17 @@ xfs_dio_write_end_io(
         */
        XFS_STATS_ADD(ip->i_mount, xs_write_bytes, size);
 
+       /*
+        * We can allocate memory here while doing writeback on behalf of
+        * memory reclaim.  To avoid memory allocation deadlocks set the
+        * task-wide nofs context for the following operations.
+        */
+       nofs_flag = memalloc_nofs_save();
+
        if (flags & IOMAP_DIO_COW) {
                error = xfs_reflink_end_cow(ip, offset, size);
                if (error)
-                       return error;
+                       goto out;
        }
 
        /*
@@ -407,8 +410,10 @@ xfs_dio_write_end_io(
         * earlier allows a racing dio read to find unwritten extents before
         * they are converted.
         */
-       if (flags & IOMAP_DIO_UNWRITTEN)
-               return xfs_iomap_write_unwritten(ip, offset, size, true);
+       if (flags & IOMAP_DIO_UNWRITTEN) {
+               error = xfs_iomap_write_unwritten(ip, offset, size, true);
+               goto out;
+       }
 
        /*
         * We need to update the in-core inode size here so that we don't end up
@@ -430,6 +435,8 @@ xfs_dio_write_end_io(
                spin_unlock(&ip->i_flags_lock);
        }
 
+out:
+       memalloc_nofs_restore(nofs_flag);
        return error;
 }
 
index 1825013..574a7a8 100644 (file)
@@ -5,22 +5,19 @@
  * All Rights Reserved.
  */
 #include "xfs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_bmap.h"
-#include "xfs_bmap_util.h"
 #include "xfs_alloc.h"
 #include "xfs_mru_cache.h"
-#include "xfs_filestream.h"
 #include "xfs_trace.h"
 #include "xfs_ag_resv.h"
 #include "xfs_trans.h"
-#include "xfs_shared.h"
 
 struct xfs_fstrm_item {
        struct xfs_mru_cache_elem       mru;
index 3d76a9e..5a8f964 100644 (file)
@@ -9,16 +9,12 @@
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
-#include "xfs_error.h"
 #include "xfs_btree.h"
 #include "xfs_rmap_btree.h"
 #include "xfs_trace.h"
-#include "xfs_log.h"
 #include "xfs_rmap.h"
 #include "xfs_alloc.h"
 #include "xfs_bit.h"
index 3d0e057..3e61d0c 100644 (file)
 #include "xfs_trans_resv.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_trans.h"
 #include "xfs_error.h"
-#include "xfs_btree.h"
 #include "xfs_alloc.h"
 #include "xfs_fsops.h"
 #include "xfs_trans_space.h"
-#include "xfs_rtalloc.h"
-#include "xfs_trace.h"
 #include "xfs_log.h"
 #include "xfs_ag.h"
 #include "xfs_ag_resv.h"
@@ -251,9 +247,9 @@ xfs_growfs_data(
        if (mp->m_sb.sb_imax_pct) {
                uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct;
                do_div(icount, 100);
-               mp->m_maxicount = XFS_FSB_TO_INO(mp, icount);
+               M_IGEO(mp)->maxicount = XFS_FSB_TO_INO(mp, icount);
        } else
-               mp->m_maxicount = 0;
+               M_IGEO(mp)->maxicount = 0;
 
        /* Update secondary superblocks now the physical grow has completed */
        error = xfs_update_secondary_sbs(mp);
index d0d3773..fa55ab8 100644 (file)
@@ -4,7 +4,6 @@
  * All Rights Reserved.
  */
 #include "xfs.h"
-#include "xfs_sysctl.h"
 
 /*
  * Tunable XFS parameters.  xfs_params is required even when CONFIG_SYSCTL=n,
@@ -41,4 +40,7 @@ struct xfs_globals xfs_globals = {
 #else
        .bug_on_assert          =       false,  /* assert failures WARN() */
 #endif
+#ifdef DEBUG
+       .pwork_threads          =       -1,     /* automatic thread detection */
+#endif
 };
index 4c4929f..8e0cb05 100644 (file)
@@ -9,12 +9,8 @@
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_bit.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_inode.h"
 #include "xfs_trace.h"
 #include "xfs_health.h"
@@ -373,7 +369,7 @@ static const struct ioctl_sick_map ino_map[] = {
 void
 xfs_bulkstat_health(
        struct xfs_inode                *ip,
-       struct xfs_bstat                *bs)
+       struct xfs_bulkstat             *bs)
 {
        const struct ioctl_sick_map     *m;
        unsigned int                    sick;
index a76b275..0b0fd10 100644 (file)
@@ -5,13 +5,13 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_inode.h"
-#include "xfs_error.h"
 #include "xfs_trans.h"
 #include "xfs_trans_priv.h"
 #include "xfs_inode_item.h"
@@ -23,8 +23,6 @@
 #include "xfs_dquot.h"
 #include "xfs_reflink.h"
 
-#include <linux/kthread.h>
-#include <linux/freezer.h>
 #include <linux/iversion.h>
 
 /*
index 8381d34..d99a0a3 100644 (file)
@@ -6,14 +6,9 @@
 #include "xfs.h"
 #include "xfs_fs.h"
 #include "xfs_shared.h"
-#include "xfs_format.h"
 #include "xfs_log_format.h"
-#include "xfs_trans_resv.h"
-#include "xfs_bit.h"
-#include "xfs_mount.h"
 #include "xfs_trans.h"
 #include "xfs_trans_priv.h"
-#include "xfs_error.h"
 #include "xfs_icreate_item.h"
 #include "xfs_log.h"
 
@@ -56,80 +51,18 @@ xfs_icreate_item_format(
                        sizeof(struct xfs_icreate_log));
 }
 
-
-/* Pinning has no meaning for the create item, so just return. */
 STATIC void
-xfs_icreate_item_pin(
+xfs_icreate_item_release(
        struct xfs_log_item     *lip)
 {
+       kmem_zone_free(xfs_icreate_zone, ICR_ITEM(lip));
 }
 
-
-/* pinning has no meaning for the create item, so just return. */
-STATIC void
-xfs_icreate_item_unpin(
-       struct xfs_log_item     *lip,
-       int                     remove)
-{
-}
-
-STATIC void
-xfs_icreate_item_unlock(
-       struct xfs_log_item     *lip)
-{
-       struct xfs_icreate_item *icp = ICR_ITEM(lip);
-
-       if (test_bit(XFS_LI_ABORTED, &lip->li_flags))
-               kmem_zone_free(xfs_icreate_zone, icp);
-       return;
-}
-
-/*
- * Because we have ordered buffers being tracked in the AIL for the inode
- * creation, we don't need the create item after this. Hence we can free
- * the log item and return -1 to tell the caller we're done with the item.
- */
-STATIC xfs_lsn_t
-xfs_icreate_item_committed(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
-{
-       struct xfs_icreate_item *icp = ICR_ITEM(lip);
-
-       kmem_zone_free(xfs_icreate_zone, icp);
-       return (xfs_lsn_t)-1;
-}
-
-/* item can never get into the AIL */
-STATIC uint
-xfs_icreate_item_push(
-       struct xfs_log_item     *lip,
-       struct list_head        *buffer_list)
-{
-       ASSERT(0);
-       return XFS_ITEM_SUCCESS;
-}
-
-/* Ordered buffers do the dependency tracking here, so this does nothing. */
-STATIC void
-xfs_icreate_item_committing(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
-{
-}
-
-/*
- * This is the ops vector shared by all buf log items.
- */
 static const struct xfs_item_ops xfs_icreate_item_ops = {
+       .flags          = XFS_ITEM_RELEASE_WHEN_COMMITTED,
        .iop_size       = xfs_icreate_item_size,
        .iop_format     = xfs_icreate_item_format,
-       .iop_pin        = xfs_icreate_item_pin,
-       .iop_unpin      = xfs_icreate_item_unpin,
-       .iop_push       = xfs_icreate_item_push,
-       .iop_unlock     = xfs_icreate_item_unlock,
-       .iop_committed  = xfs_icreate_item_committed,
-       .iop_committing = xfs_icreate_item_committing,
+       .iop_release    = xfs_icreate_item_release,
 };
 
 
index 71d216c..6467d5e 100644 (file)
@@ -3,7 +3,6 @@
  * Copyright (c) 2000-2006 Silicon Graphics, Inc.
  * All Rights Reserved.
  */
-#include <linux/log2.h>
 #include <linux/iversion.h>
 
 #include "xfs.h"
 #include "xfs_mount.h"
 #include "xfs_defer.h"
 #include "xfs_inode.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_dir2.h"
-#include "xfs_attr_sf.h"
 #include "xfs_attr.h"
 #include "xfs_trans_space.h"
 #include "xfs_trans.h"
@@ -32,7 +28,6 @@
 #include "xfs_error.h"
 #include "xfs_quota.h"
 #include "xfs_filestream.h"
-#include "xfs_cksum.h"
 #include "xfs_trace.h"
 #include "xfs_icache.h"
 #include "xfs_symlink.h"
@@ -40,7 +35,6 @@
 #include "xfs_log.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_reflink.h"
-#include "xfs_dir2_priv.h"
 
 kmem_zone_t *xfs_inode_zone;
 
@@ -441,12 +435,12 @@ xfs_lock_inumorder(int lock_mode, int subclass)
  */
 static void
 xfs_lock_inodes(
-       xfs_inode_t     **ips,
-       int             inodes,
-       uint            lock_mode)
+       struct xfs_inode        **ips,
+       int                     inodes,
+       uint                    lock_mode)
 {
-       int             attempts = 0, i, j, try_lock;
-       xfs_log_item_t  *lp;
+       int                     attempts = 0, i, j, try_lock;
+       struct xfs_log_item     *lp;
 
        /*
         * Currently supports between 2 and 5 inodes with exclusive locking.  We
@@ -485,7 +479,7 @@ again:
                 */
                if (!try_lock) {
                        for (j = (i - 1); j >= 0 && !try_lock; j--) {
-                               lp = (xfs_log_item_t *)ips[j]->i_itemp;
+                               lp = &ips[j]->i_itemp->ili_item;
                                if (lp && test_bit(XFS_LI_IN_AIL, &lp->li_flags))
                                        try_lock++;
                        }
@@ -551,7 +545,7 @@ xfs_lock_two_inodes(
        struct xfs_inode        *temp;
        uint                    mode_temp;
        int                     attempts = 0;
-       xfs_log_item_t          *lp;
+       struct xfs_log_item     *lp;
 
        ASSERT(hweight32(ip0_mode) == 1);
        ASSERT(hweight32(ip1_mode) == 1);
@@ -585,7 +579,7 @@ xfs_lock_two_inodes(
         * the second lock. If we can't get it, we must release the first one
         * and try again.
         */
-       lp = (xfs_log_item_t *)ip0->i_itemp;
+       lp = &ip0->i_itemp->ili_item;
        if (lp && test_bit(XFS_LI_IN_AIL, &lp->li_flags)) {
                if (!xfs_ilock_nowait(ip1, xfs_lock_inumorder(ip1_mode, 1))) {
                        xfs_iunlock(ip0, ip0_mode);
@@ -2537,13 +2531,14 @@ xfs_ifree_cluster(
        xfs_inode_log_item_t    *iip;
        struct xfs_log_item     *lip;
        struct xfs_perag        *pag;
+       struct xfs_ino_geometry *igeo = M_IGEO(mp);
        xfs_ino_t               inum;
 
        inum = xic->first_ino;
        pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, inum));
-       nbufs = mp->m_ialloc_blks / mp->m_blocks_per_cluster;
+       nbufs = igeo->ialloc_blks / igeo->blocks_per_cluster;
 
-       for (j = 0; j < nbufs; j++, inum += mp->m_inodes_per_cluster) {
+       for (j = 0; j < nbufs; j++, inum += igeo->inodes_per_cluster) {
                /*
                 * The allocation bitmap tells us which inodes of the chunk were
                 * physically allocated. Skip the cluster if an inode falls into
@@ -2551,7 +2546,7 @@ xfs_ifree_cluster(
                 */
                ioffset = inum - xic->first_ino;
                if ((xic->alloc & XFS_INOBT_MASK(ioffset)) == 0) {
-                       ASSERT(ioffset % mp->m_inodes_per_cluster == 0);
+                       ASSERT(ioffset % igeo->inodes_per_cluster == 0);
                        continue;
                }
 
@@ -2567,7 +2562,7 @@ xfs_ifree_cluster(
                 * to mark all the active inodes on the buffer stale.
                 */
                bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno,
-                                       mp->m_bsize * mp->m_blocks_per_cluster,
+                                       mp->m_bsize * igeo->blocks_per_cluster,
                                        XBF_UNMAPPED);
 
                if (!bp)
@@ -2614,7 +2609,7 @@ xfs_ifree_cluster(
                 * transaction stale above, which means there is no point in
                 * even trying to lock them.
                 */
-               for (i = 0; i < mp->m_inodes_per_cluster; i++) {
+               for (i = 0; i < igeo->inodes_per_cluster; i++) {
 retry:
                        rcu_read_lock();
                        ip = radix_tree_lookup(&pag->pag_ici_root,
@@ -3472,28 +3467,27 @@ xfs_iflush_cluster(
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_perag        *pag;
        unsigned long           first_index, mask;
-       unsigned long           inodes_per_cluster;
        int                     cilist_size;
        struct xfs_inode        **cilist;
        struct xfs_inode        *cip;
+       struct xfs_ino_geometry *igeo = M_IGEO(mp);
        int                     nr_found;
        int                     clcount = 0;
        int                     i;
 
        pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
 
-       inodes_per_cluster = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog;
-       cilist_size = inodes_per_cluster * sizeof(xfs_inode_t *);
+       cilist_size = igeo->inodes_per_cluster * sizeof(struct xfs_inode *);
        cilist = kmem_alloc(cilist_size, KM_MAYFAIL|KM_NOFS);
        if (!cilist)
                goto out_put;
 
-       mask = ~(((mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog)) - 1);
+       mask = ~(igeo->inodes_per_cluster - 1);
        first_index = XFS_INO_TO_AGINO(mp, ip->i_ino) & mask;
        rcu_read_lock();
        /* really need a gang lookup range call here */
        nr_found = radix_tree_gang_lookup(&pag->pag_ici_root, (void**)cilist,
-                                       first_index, inodes_per_cluster);
+                                       first_index, igeo->inodes_per_cluster);
        if (nr_found == 0)
                goto out_free;
 
index fa1c4fe..c9a502e 100644 (file)
@@ -5,6 +5,7 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
@@ -12,7 +13,6 @@
 #include "xfs_inode.h"
 #include "xfs_trans.h"
 #include "xfs_inode_item.h"
-#include "xfs_error.h"
 #include "xfs_trace.h"
 #include "xfs_trans_priv.h"
 #include "xfs_buf_item.h"
@@ -565,7 +565,7 @@ out_unlock:
  * Unlock the inode associated with the inode log item.
  */
 STATIC void
-xfs_inode_item_unlock(
+xfs_inode_item_release(
        struct xfs_log_item     *lip)
 {
        struct xfs_inode_log_item *iip = INODE_ITEM(lip);
@@ -621,23 +621,21 @@ xfs_inode_item_committed(
 STATIC void
 xfs_inode_item_committing(
        struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
+       xfs_lsn_t               commit_lsn)
 {
-       INODE_ITEM(lip)->ili_last_lsn = lsn;
+       INODE_ITEM(lip)->ili_last_lsn = commit_lsn;
+       return xfs_inode_item_release(lip);
 }
 
-/*
- * This is the ops vector shared by all buf log items.
- */
 static const struct xfs_item_ops xfs_inode_item_ops = {
        .iop_size       = xfs_inode_item_size,
        .iop_format     = xfs_inode_item_format,
        .iop_pin        = xfs_inode_item_pin,
        .iop_unpin      = xfs_inode_item_unpin,
-       .iop_unlock     = xfs_inode_item_unlock,
+       .iop_release    = xfs_inode_item_release,
        .iop_committed  = xfs_inode_item_committed,
        .iop_push       = xfs_inode_item_push,
-       .iop_committing = xfs_inode_item_committing,
+       .iop_committing = xfs_inode_item_committing,
        .iop_error      = xfs_inode_item_error
 };
 
index 27081eb..07a60e7 100644 (file)
@@ -14,7 +14,7 @@ struct xfs_inode;
 struct xfs_mount;
 
 typedef struct xfs_inode_log_item {
-       xfs_log_item_t          ili_item;          /* common portion */
+       struct xfs_log_item     ili_item;          /* common portion */
        struct xfs_inode        *ili_inode;        /* inode ptr */
        xfs_lsn_t               ili_flush_lsn;     /* lsn at last flush */
        xfs_lsn_t               ili_last_lsn;      /* lsn at last transaction */
index d7dfc13..6f7848c 100644 (file)
@@ -11,9 +11,8 @@
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
 #include "xfs_inode.h"
-#include "xfs_ioctl.h"
-#include "xfs_alloc.h"
 #include "xfs_rtalloc.h"
+#include "xfs_iwalk.h"
 #include "xfs_itable.h"
 #include "xfs_error.h"
 #include "xfs_attr.h"
@@ -25,7 +24,6 @@
 #include "xfs_export.h"
 #include "xfs_trace.h"
 #include "xfs_icache.h"
-#include "xfs_symlink.h"
 #include "xfs_trans.h"
 #include "xfs_acl.h"
 #include "xfs_btree.h"
 #include "xfs_ag.h"
 #include "xfs_health.h"
 
-#include <linux/capability.h>
-#include <linux/cred.h>
-#include <linux/dcache.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
-#include <linux/pagemap.h>
-#include <linux/slab.h>
-#include <linux/exportfs.h>
 
 /*
  * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to
@@ -721,16 +713,45 @@ out_unlock:
        return error;
 }
 
+/* Return 0 on success or positive error */
+int
+xfs_fsbulkstat_one_fmt(
+       struct xfs_ibulk                *breq,
+       const struct xfs_bulkstat       *bstat)
+{
+       struct xfs_bstat                bs1;
+
+       xfs_bulkstat_to_bstat(breq->mp, &bs1, bstat);
+       if (copy_to_user(breq->ubuffer, &bs1, sizeof(bs1)))
+               return -EFAULT;
+       return xfs_ibulk_advance(breq, sizeof(struct xfs_bstat));
+}
+
+int
+xfs_fsinumbers_fmt(
+       struct xfs_ibulk                *breq,
+       const struct xfs_inumbers       *igrp)
+{
+       struct xfs_inogrp               ig1;
+
+       xfs_inumbers_to_inogrp(&ig1, igrp);
+       if (copy_to_user(breq->ubuffer, &ig1, sizeof(struct xfs_inogrp)))
+               return -EFAULT;
+       return xfs_ibulk_advance(breq, sizeof(struct xfs_inogrp));
+}
+
 STATIC int
-xfs_ioc_bulkstat(
+xfs_ioc_fsbulkstat(
        xfs_mount_t             *mp,
        unsigned int            cmd,
        void                    __user *arg)
 {
-       xfs_fsop_bulkreq_t      bulkreq;
-       int                     count;  /* # of records returned */
-       xfs_ino_t               inlast; /* last inode number */
-       int                     done;
+       struct xfs_fsop_bulkreq bulkreq;
+       struct xfs_ibulk        breq = {
+               .mp             = mp,
+               .ocount         = 0,
+       };
+       xfs_ino_t               lastino;
        int                     error;
 
        /* done = 1 if there are more stats to get and if bulkstat */
@@ -742,41 +763,243 @@ xfs_ioc_bulkstat(
        if (XFS_FORCED_SHUTDOWN(mp))
                return -EIO;
 
-       if (copy_from_user(&bulkreq, arg, sizeof(xfs_fsop_bulkreq_t)))
+       if (copy_from_user(&bulkreq, arg, sizeof(struct xfs_fsop_bulkreq)))
                return -EFAULT;
 
-       if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64)))
+       if (copy_from_user(&lastino, bulkreq.lastip, sizeof(__s64)))
                return -EFAULT;
 
-       if ((count = bulkreq.icount) <= 0)
+       if (bulkreq.icount <= 0)
                return -EINVAL;
 
        if (bulkreq.ubuffer == NULL)
                return -EINVAL;
 
-       if (cmd == XFS_IOC_FSINUMBERS)
-               error = xfs_inumbers(mp, &inlast, &count,
-                                       bulkreq.ubuffer, xfs_inumbers_fmt);
-       else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE)
-               error = xfs_bulkstat_one(mp, inlast, bulkreq.ubuffer,
-                                       sizeof(xfs_bstat_t), NULL, &done);
-       else    /* XFS_IOC_FSBULKSTAT */
-               error = xfs_bulkstat(mp, &inlast, &count, xfs_bulkstat_one,
-                                    sizeof(xfs_bstat_t), bulkreq.ubuffer,
-                                    &done);
+       breq.ubuffer = bulkreq.ubuffer;
+       breq.icount = bulkreq.icount;
+
+       /*
+        * FSBULKSTAT_SINGLE expects that *lastip contains the inode number
+        * that we want to stat.  However, FSINUMBERS and FSBULKSTAT expect
+        * that *lastip contains either zero or the number of the last inode to
+        * be examined by the previous call and return results starting with
+        * the next inode after that.  The new bulk request back end functions
+        * take the inode to start with, so we have to compute the startino
+        * parameter from lastino to maintain correct function.  lastino == 0
+        * is a special case because it has traditionally meant "first inode
+        * in filesystem".
+        */
+       if (cmd == XFS_IOC_FSINUMBERS) {
+               breq.startino = lastino ? lastino + 1 : 0;
+               error = xfs_inumbers(&breq, xfs_fsinumbers_fmt);
+               lastino = breq.startino - 1;
+       } else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) {
+               breq.startino = lastino;
+               breq.icount = 1;
+               error = xfs_bulkstat_one(&breq, xfs_fsbulkstat_one_fmt);
+       } else {        /* XFS_IOC_FSBULKSTAT */
+               breq.startino = lastino ? lastino + 1 : 0;
+               error = xfs_bulkstat(&breq, xfs_fsbulkstat_one_fmt);
+               lastino = breq.startino - 1;
+       }
 
        if (error)
                return error;
 
-       if (bulkreq.ocount != NULL) {
-               if (copy_to_user(bulkreq.lastip, &inlast,
-                                               sizeof(xfs_ino_t)))
-                       return -EFAULT;
+       if (bulkreq.lastip != NULL &&
+           copy_to_user(bulkreq.lastip, &lastino, sizeof(xfs_ino_t)))
+               return -EFAULT;
 
-               if (copy_to_user(bulkreq.ocount, &count, sizeof(count)))
-                       return -EFAULT;
+       if (bulkreq.ocount != NULL &&
+           copy_to_user(bulkreq.ocount, &breq.ocount, sizeof(__s32)))
+               return -EFAULT;
+
+       return 0;
+}
+
+/* Return 0 on success or positive error */
+static int
+xfs_bulkstat_fmt(
+       struct xfs_ibulk                *breq,
+       const struct xfs_bulkstat       *bstat)
+{
+       if (copy_to_user(breq->ubuffer, bstat, sizeof(struct xfs_bulkstat)))
+               return -EFAULT;
+       return xfs_ibulk_advance(breq, sizeof(struct xfs_bulkstat));
+}
+
+/*
+ * Check the incoming bulk request @hdr from userspace and initialize the
+ * internal @breq bulk request appropriately.  Returns 0 if the bulk request
+ * should proceed; XFS_ITER_ABORT if there's nothing to do; or the usual
+ * negative error code.
+ */
+static int
+xfs_bulk_ireq_setup(
+       struct xfs_mount        *mp,
+       struct xfs_bulk_ireq    *hdr,
+       struct xfs_ibulk        *breq,
+       void __user             *ubuffer)
+{
+       if (hdr->icount == 0 ||
+           (hdr->flags & ~XFS_BULK_IREQ_FLAGS_ALL) ||
+           memchr_inv(hdr->reserved, 0, sizeof(hdr->reserved)))
+               return -EINVAL;
+
+       breq->startino = hdr->ino;
+       breq->ubuffer = ubuffer;
+       breq->icount = hdr->icount;
+       breq->ocount = 0;
+       breq->flags = 0;
+
+       /*
+        * The @ino parameter is a special value, so we must look it up here.
+        * We're not allowed to have IREQ_AGNO, and we only return one inode
+        * worth of data.
+        */
+       if (hdr->flags & XFS_BULK_IREQ_SPECIAL) {
+               if (hdr->flags & XFS_BULK_IREQ_AGNO)
+                       return -EINVAL;
+
+               switch (hdr->ino) {
+               case XFS_BULK_IREQ_SPECIAL_ROOT:
+                       hdr->ino = mp->m_sb.sb_rootino;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               breq->icount = 1;
        }
 
+       /*
+        * The IREQ_AGNO flag means that we only want results from a given AG.
+        * If @hdr->ino is zero, we start iterating in that AG.  If @hdr->ino is
+        * beyond the specified AG then we return no results.
+        */
+       if (hdr->flags & XFS_BULK_IREQ_AGNO) {
+               if (hdr->agno >= mp->m_sb.sb_agcount)
+                       return -EINVAL;
+
+               if (breq->startino == 0)
+                       breq->startino = XFS_AGINO_TO_INO(mp, hdr->agno, 0);
+               else if (XFS_INO_TO_AGNO(mp, breq->startino) < hdr->agno)
+                       return -EINVAL;
+
+               breq->flags |= XFS_IBULK_SAME_AG;
+
+               /* Asking for an inode past the end of the AG?  We're done! */
+               if (XFS_INO_TO_AGNO(mp, breq->startino) > hdr->agno)
+                       return XFS_ITER_ABORT;
+       } else if (hdr->agno)
+               return -EINVAL;
+
+       /* Asking for an inode past the end of the FS?  We're done! */
+       if (XFS_INO_TO_AGNO(mp, breq->startino) >= mp->m_sb.sb_agcount)
+               return XFS_ITER_ABORT;
+
+       return 0;
+}
+
+/*
+ * Update the userspace bulk request @hdr to reflect the end state of the
+ * internal bulk request @breq.
+ */
+static void
+xfs_bulk_ireq_teardown(
+       struct xfs_bulk_ireq    *hdr,
+       struct xfs_ibulk        *breq)
+{
+       hdr->ino = breq->startino;
+       hdr->ocount = breq->ocount;
+}
+
+/* Handle the v5 bulkstat ioctl. */
+STATIC int
+xfs_ioc_bulkstat(
+       struct xfs_mount                *mp,
+       unsigned int                    cmd,
+       struct xfs_bulkstat_req __user  *arg)
+{
+       struct xfs_bulk_ireq            hdr;
+       struct xfs_ibulk                breq = {
+               .mp                     = mp,
+       };
+       int                             error;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (XFS_FORCED_SHUTDOWN(mp))
+               return -EIO;
+
+       if (copy_from_user(&hdr, &arg->hdr, sizeof(hdr)))
+               return -EFAULT;
+
+       error = xfs_bulk_ireq_setup(mp, &hdr, &breq, arg->bulkstat);
+       if (error == XFS_ITER_ABORT)
+               goto out_teardown;
+       if (error < 0)
+               return error;
+
+       error = xfs_bulkstat(&breq, xfs_bulkstat_fmt);
+       if (error)
+               return error;
+
+out_teardown:
+       xfs_bulk_ireq_teardown(&hdr, &breq);
+       if (copy_to_user(&arg->hdr, &hdr, sizeof(hdr)))
+               return -EFAULT;
+
+       return 0;
+}
+
+STATIC int
+xfs_inumbers_fmt(
+       struct xfs_ibulk                *breq,
+       const struct xfs_inumbers       *igrp)
+{
+       if (copy_to_user(breq->ubuffer, igrp, sizeof(struct xfs_inumbers)))
+               return -EFAULT;
+       return xfs_ibulk_advance(breq, sizeof(struct xfs_inumbers));
+}
+
+/* Handle the v5 inumbers ioctl. */
+STATIC int
+xfs_ioc_inumbers(
+       struct xfs_mount                *mp,
+       unsigned int                    cmd,
+       struct xfs_inumbers_req __user  *arg)
+{
+       struct xfs_bulk_ireq            hdr;
+       struct xfs_ibulk                breq = {
+               .mp                     = mp,
+       };
+       int                             error;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (XFS_FORCED_SHUTDOWN(mp))
+               return -EIO;
+
+       if (copy_from_user(&hdr, &arg->hdr, sizeof(hdr)))
+               return -EFAULT;
+
+       error = xfs_bulk_ireq_setup(mp, &hdr, &breq, arg->inumbers);
+       if (error == XFS_ITER_ABORT)
+               goto out_teardown;
+       if (error < 0)
+               return error;
+
+       error = xfs_inumbers(&breq, xfs_inumbers_fmt);
+       if (error)
+               return error;
+
+out_teardown:
+       xfs_bulk_ireq_teardown(&hdr, &breq);
+       if (copy_to_user(&arg->hdr, &hdr, sizeof(hdr)))
+               return -EFAULT;
+
        return 0;
 }
 
@@ -879,37 +1102,44 @@ xfs_di2lxflags(
        return flags;
 }
 
-STATIC int
-xfs_ioc_fsgetxattr(
-       xfs_inode_t             *ip,
-       int                     attr,
-       void                    __user *arg)
+static void
+xfs_fill_fsxattr(
+       struct xfs_inode        *ip,
+       bool                    attr,
+       struct fsxattr          *fa)
 {
-       struct fsxattr          fa;
-
-       memset(&fa, 0, sizeof(struct fsxattr));
-
-       xfs_ilock(ip, XFS_ILOCK_SHARED);
-       fa.fsx_xflags = xfs_ip2xflags(ip);
-       fa.fsx_extsize = ip->i_d.di_extsize << ip->i_mount->m_sb.sb_blocklog;
-       fa.fsx_cowextsize = ip->i_d.di_cowextsize <<
+       simple_fill_fsxattr(fa, xfs_ip2xflags(ip));
+       fa->fsx_extsize = ip->i_d.di_extsize << ip->i_mount->m_sb.sb_blocklog;
+       fa->fsx_cowextsize = ip->i_d.di_cowextsize <<
                        ip->i_mount->m_sb.sb_blocklog;
-       fa.fsx_projid = xfs_get_projid(ip);
+       fa->fsx_projid = xfs_get_projid(ip);
 
        if (attr) {
                if (ip->i_afp) {
                        if (ip->i_afp->if_flags & XFS_IFEXTENTS)
-                               fa.fsx_nextents = xfs_iext_count(ip->i_afp);
+                               fa->fsx_nextents = xfs_iext_count(ip->i_afp);
                        else
-                               fa.fsx_nextents = ip->i_d.di_anextents;
+                               fa->fsx_nextents = ip->i_d.di_anextents;
                } else
-                       fa.fsx_nextents = 0;
+                       fa->fsx_nextents = 0;
        } else {
                if (ip->i_df.if_flags & XFS_IFEXTENTS)
-                       fa.fsx_nextents = xfs_iext_count(&ip->i_df);
+                       fa->fsx_nextents = xfs_iext_count(&ip->i_df);
                else
-                       fa.fsx_nextents = ip->i_d.di_nextents;
+                       fa->fsx_nextents = ip->i_d.di_nextents;
        }
+}
+
+STATIC int
+xfs_ioc_fsgetxattr(
+       xfs_inode_t             *ip,
+       int                     attr,
+       void                    __user *arg)
+{
+       struct fsxattr          fa;
+
+       xfs_ilock(ip, XFS_ILOCK_SHARED);
+       xfs_fill_fsxattr(ip, attr, &fa);
        xfs_iunlock(ip, XFS_ILOCK_SHARED);
 
        if (copy_to_user(arg, &fa, sizeof(fa)))
@@ -1035,15 +1265,6 @@ xfs_ioctl_setattr_xflags(
        if ((fa->fsx_xflags & FS_XFLAG_DAX) && xfs_is_reflink_inode(ip))
                return -EINVAL;
 
-       /*
-        * Can't modify an immutable/append-only file unless
-        * we have appropriate permission.
-        */
-       if (((ip->i_d.di_flags & (XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND)) ||
-            (fa->fsx_xflags & (FS_XFLAG_IMMUTABLE | FS_XFLAG_APPEND))) &&
-           !capable(CAP_LINUX_IMMUTABLE))
-               return -EPERM;
-
        /* diflags2 only valid for v3 inodes. */
        di_flags2 = xfs_flags2diflags2(ip, fa->fsx_xflags);
        if (di_flags2 && ip->i_d.di_version < 3)
@@ -1202,39 +1423,31 @@ xfs_ioctl_setattr_check_extsize(
        struct fsxattr          *fa)
 {
        struct xfs_mount        *mp = ip->i_mount;
-
-       if ((fa->fsx_xflags & FS_XFLAG_EXTSIZE) && !S_ISREG(VFS_I(ip)->i_mode))
-               return -EINVAL;
-
-       if ((fa->fsx_xflags & FS_XFLAG_EXTSZINHERIT) &&
-           !S_ISDIR(VFS_I(ip)->i_mode))
-               return -EINVAL;
+       xfs_extlen_t            size;
+       xfs_fsblock_t           extsize_fsb;
 
        if (S_ISREG(VFS_I(ip)->i_mode) && ip->i_d.di_nextents &&
            ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != fa->fsx_extsize))
                return -EINVAL;
 
-       if (fa->fsx_extsize != 0) {
-               xfs_extlen_t    size;
-               xfs_fsblock_t   extsize_fsb;
-
-               extsize_fsb = XFS_B_TO_FSB(mp, fa->fsx_extsize);
-               if (extsize_fsb > MAXEXTLEN)
-                       return -EINVAL;
+       if (fa->fsx_extsize == 0)
+               return 0;
 
-               if (XFS_IS_REALTIME_INODE(ip) ||
-                   (fa->fsx_xflags & FS_XFLAG_REALTIME)) {
-                       size = mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog;
-               } else {
-                       size = mp->m_sb.sb_blocksize;
-                       if (extsize_fsb > mp->m_sb.sb_agblocks / 2)
-                               return -EINVAL;
-               }
+       extsize_fsb = XFS_B_TO_FSB(mp, fa->fsx_extsize);
+       if (extsize_fsb > MAXEXTLEN)
+               return -EINVAL;
 
-               if (fa->fsx_extsize % size)
+       if (XFS_IS_REALTIME_INODE(ip) ||
+           (fa->fsx_xflags & FS_XFLAG_REALTIME)) {
+               size = mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog;
+       } else {
+               size = mp->m_sb.sb_blocksize;
+               if (extsize_fsb > mp->m_sb.sb_agblocks / 2)
                        return -EINVAL;
-       } else
-               fa->fsx_xflags &= ~(FS_XFLAG_EXTSIZE | FS_XFLAG_EXTSZINHERIT);
+       }
+
+       if (fa->fsx_extsize % size)
+               return -EINVAL;
 
        return 0;
 }
@@ -1260,6 +1473,8 @@ xfs_ioctl_setattr_check_cowextsize(
        struct fsxattr          *fa)
 {
        struct xfs_mount        *mp = ip->i_mount;
+       xfs_extlen_t            size;
+       xfs_fsblock_t           cowextsize_fsb;
 
        if (!(fa->fsx_xflags & FS_XFLAG_COWEXTSIZE))
                return 0;
@@ -1268,25 +1483,19 @@ xfs_ioctl_setattr_check_cowextsize(
            ip->i_d.di_version != 3)
                return -EINVAL;
 
-       if (!S_ISREG(VFS_I(ip)->i_mode) && !S_ISDIR(VFS_I(ip)->i_mode))
-               return -EINVAL;
-
-       if (fa->fsx_cowextsize != 0) {
-               xfs_extlen_t    size;
-               xfs_fsblock_t   cowextsize_fsb;
+       if (fa->fsx_cowextsize == 0)
+               return 0;
 
-               cowextsize_fsb = XFS_B_TO_FSB(mp, fa->fsx_cowextsize);
-               if (cowextsize_fsb > MAXEXTLEN)
-                       return -EINVAL;
+       cowextsize_fsb = XFS_B_TO_FSB(mp, fa->fsx_cowextsize);
+       if (cowextsize_fsb > MAXEXTLEN)
+               return -EINVAL;
 
-               size = mp->m_sb.sb_blocksize;
-               if (cowextsize_fsb > mp->m_sb.sb_agblocks / 2)
-                       return -EINVAL;
+       size = mp->m_sb.sb_blocksize;
+       if (cowextsize_fsb > mp->m_sb.sb_agblocks / 2)
+               return -EINVAL;
 
-               if (fa->fsx_cowextsize % size)
-                       return -EINVAL;
-       } else
-               fa->fsx_xflags &= ~FS_XFLAG_COWEXTSIZE;
+       if (fa->fsx_cowextsize % size)
+               return -EINVAL;
 
        return 0;
 }
@@ -1300,21 +1509,6 @@ xfs_ioctl_setattr_check_projid(
        if (fa->fsx_projid > (uint16_t)-1 &&
            !xfs_sb_version_hasprojid32bit(&ip->i_mount->m_sb))
                return -EINVAL;
-
-       /*
-        * Project Quota ID state is only allowed to change from within the init
-        * namespace. Enforce that restriction only if we are trying to change
-        * the quota ID state. Everything else is allowed in user namespaces.
-        */
-       if (current_user_ns() == &init_user_ns)
-               return 0;
-
-       if (xfs_get_projid(ip) != fa->fsx_projid)
-               return -EINVAL;
-       if ((fa->fsx_xflags & FS_XFLAG_PROJINHERIT) !=
-           (ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT))
-               return -EINVAL;
-
        return 0;
 }
 
@@ -1323,6 +1517,7 @@ xfs_ioctl_setattr(
        xfs_inode_t             *ip,
        struct fsxattr          *fa)
 {
+       struct fsxattr          old_fa;
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_trans        *tp;
        struct xfs_dquot        *udqp = NULL;
@@ -1370,7 +1565,6 @@ xfs_ioctl_setattr(
                goto error_free_dquots;
        }
 
-
        if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp) &&
            xfs_get_projid(ip) != fa->fsx_projid) {
                code = xfs_qm_vop_chown_reserve(tp, ip, udqp, NULL, pdqp,
@@ -1379,6 +1573,11 @@ xfs_ioctl_setattr(
                        goto error_trans_cancel;
        }
 
+       xfs_fill_fsxattr(ip, false, &old_fa);
+       code = vfs_ioc_fssetxattr_check(VFS_I(ip), &old_fa, fa);
+       if (code)
+               goto error_trans_cancel;
+
        code = xfs_ioctl_setattr_check_extsize(ip, fa);
        if (code)
                goto error_trans_cancel;
@@ -1489,6 +1688,7 @@ xfs_ioc_setxflags(
 {
        struct xfs_trans        *tp;
        struct fsxattr          fa;
+       struct fsxattr          old_fa;
        unsigned int            flags;
        int                     join_flags = 0;
        int                     error;
@@ -1524,6 +1724,13 @@ xfs_ioc_setxflags(
                goto out_drop_write;
        }
 
+       xfs_fill_fsxattr(ip, false, &old_fa);
+       error = vfs_ioc_fssetxattr_check(VFS_I(ip), &old_fa, &fa);
+       if (error) {
+               xfs_trans_cancel(tp);
+               goto out_drop_write;
+       }
+
        error = xfs_ioctl_setattr_xflags(tp, ip, &fa);
        if (error) {
                xfs_trans_cancel(tp);
@@ -1942,7 +2149,12 @@ xfs_file_ioctl(
        case XFS_IOC_FSBULKSTAT_SINGLE:
        case XFS_IOC_FSBULKSTAT:
        case XFS_IOC_FSINUMBERS:
+               return xfs_ioc_fsbulkstat(mp, cmd, arg);
+
+       case XFS_IOC_BULKSTAT:
                return xfs_ioc_bulkstat(mp, cmd, arg);
+       case XFS_IOC_INUMBERS:
+               return xfs_ioc_inumbers(mp, cmd, arg);
 
        case XFS_IOC_FSGEOMETRY_V1:
                return xfs_ioc_fsgeometry(mp, arg, 3);
index 4b17f67..654c0bb 100644 (file)
@@ -77,4 +77,12 @@ xfs_set_dmattrs(
        uint                    evmask,
        uint16_t                state);
 
+struct xfs_ibulk;
+struct xfs_bstat;
+struct xfs_inogrp;
+
+int xfs_fsbulkstat_one_fmt(struct xfs_ibulk *breq,
+                          const struct xfs_bulkstat *bstat);
+int xfs_fsinumbers_fmt(struct xfs_ibulk *breq, const struct xfs_inumbers *igrp);
+
 #endif
index 614fc68..7fcf756 100644 (file)
@@ -3,23 +3,19 @@
  * Copyright (c) 2004-2005 Silicon Graphics, Inc.
  * All Rights Reserved.
  */
-#include <linux/compat.h>
-#include <linux/ioctl.h>
 #include <linux/mount.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
 #include <linux/fsmap.h>
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
 #include "xfs_inode.h"
+#include "xfs_iwalk.h"
 #include "xfs_itable.h"
-#include "xfs_error.h"
 #include "xfs_fsops.h"
-#include "xfs_alloc.h"
 #include "xfs_rtalloc.h"
 #include "xfs_attr.h"
 #include "xfs_ioctl.h"
@@ -84,27 +80,26 @@ xfs_compat_growfs_rt_copyin(
 }
 
 STATIC int
-xfs_inumbers_fmt_compat(
-       void                    __user *ubuffer,
-       const struct xfs_inogrp *buffer,
-       long                    count,
-       long                    *written)
+xfs_fsinumbers_fmt_compat(
+       struct xfs_ibulk                *breq,
+       const struct xfs_inumbers       *ig)
 {
-       compat_xfs_inogrp_t     __user *p32 = ubuffer;
-       long                    i;
+       struct compat_xfs_inogrp __user *p32 = breq->ubuffer;
+       struct xfs_inogrp               ig1;
+       struct xfs_inogrp               *igrp = &ig1;
 
-       for (i = 0; i < count; i++) {
-               if (put_user(buffer[i].xi_startino,   &p32[i].xi_startino) ||
-                   put_user(buffer[i].xi_alloccount, &p32[i].xi_alloccount) ||
-                   put_user(buffer[i].xi_allocmask,  &p32[i].xi_allocmask))
-                       return -EFAULT;
-       }
-       *written = count * sizeof(*p32);
-       return 0;
+       xfs_inumbers_to_inogrp(&ig1, ig);
+
+       if (put_user(igrp->xi_startino,   &p32->xi_startino) ||
+           put_user(igrp->xi_alloccount, &p32->xi_alloccount) ||
+           put_user(igrp->xi_allocmask,  &p32->xi_allocmask))
+               return -EFAULT;
+
+       return xfs_ibulk_advance(breq, sizeof(struct compat_xfs_inogrp));
 }
 
 #else
-#define xfs_inumbers_fmt_compat xfs_inumbers_fmt
+#define xfs_fsinumbers_fmt_compat xfs_fsinumbers_fmt
 #endif /* BROKEN_X86_ALIGNMENT */
 
 STATIC int
@@ -121,11 +116,14 @@ xfs_ioctl32_bstime_copyin(
        return 0;
 }
 
-/* xfs_bstat_t has differing alignment on intel, & bstime_t sizes everywhere */
+/*
+ * struct xfs_bstat has differing alignment on intel, & bstime_t sizes
+ * everywhere
+ */
 STATIC int
 xfs_ioctl32_bstat_copyin(
-       xfs_bstat_t             *bstat,
-       compat_xfs_bstat_t      __user *bstat32)
+       struct xfs_bstat                *bstat,
+       struct compat_xfs_bstat __user  *bstat32)
 {
        if (get_user(bstat->bs_ino,     &bstat32->bs_ino)       ||
            get_user(bstat->bs_mode,    &bstat32->bs_mode)      ||
@@ -171,16 +169,15 @@ xfs_bstime_store_compat(
 
 /* Return 0 on success or positive error (to xfs_bulkstat()) */
 STATIC int
-xfs_bulkstat_one_fmt_compat(
-       void                    __user *ubuffer,
-       int                     ubsize,
-       int                     *ubused,
-       const xfs_bstat_t       *buffer)
+xfs_fsbulkstat_one_fmt_compat(
+       struct xfs_ibulk                *breq,
+       const struct xfs_bulkstat       *bstat)
 {
-       compat_xfs_bstat_t      __user *p32 = ubuffer;
+       struct compat_xfs_bstat __user  *p32 = breq->ubuffer;
+       struct xfs_bstat                bs1;
+       struct xfs_bstat                *buffer = &bs1;
 
-       if (ubsize < sizeof(*p32))
-               return -ENOMEM;
+       xfs_bulkstat_to_bstat(breq->mp, &bs1, bstat);
 
        if (put_user(buffer->bs_ino,      &p32->bs_ino)         ||
            put_user(buffer->bs_mode,     &p32->bs_mode)        ||
@@ -205,37 +202,24 @@ xfs_bulkstat_one_fmt_compat(
            put_user(buffer->bs_dmstate,  &p32->bs_dmstate)     ||
            put_user(buffer->bs_aextents, &p32->bs_aextents))
                return -EFAULT;
-       if (ubused)
-               *ubused = sizeof(*p32);
-       return 0;
-}
 
-STATIC int
-xfs_bulkstat_one_compat(
-       xfs_mount_t     *mp,            /* mount point for filesystem */
-       xfs_ino_t       ino,            /* inode number to get data for */
-       void            __user *buffer, /* buffer to place output in */
-       int             ubsize,         /* size of buffer */
-       int             *ubused,        /* bytes used by me */
-       int             *stat)          /* BULKSTAT_RV_... */
-{
-       return xfs_bulkstat_one_int(mp, ino, buffer, ubsize,
-                                   xfs_bulkstat_one_fmt_compat,
-                                   ubused, stat);
+       return xfs_ibulk_advance(breq, sizeof(struct compat_xfs_bstat));
 }
 
 /* copied from xfs_ioctl.c */
 STATIC int
-xfs_compat_ioc_bulkstat(
+xfs_compat_ioc_fsbulkstat(
        xfs_mount_t               *mp,
        unsigned int              cmd,
-       compat_xfs_fsop_bulkreq_t __user *p32)
+       struct compat_xfs_fsop_bulkreq __user *p32)
 {
        u32                     addr;
-       xfs_fsop_bulkreq_t      bulkreq;
-       int                     count;  /* # of records returned */
-       xfs_ino_t               inlast; /* last inode number */
-       int                     done;
+       struct xfs_fsop_bulkreq bulkreq;
+       struct xfs_ibulk        breq = {
+               .mp             = mp,
+               .ocount         = 0,
+       };
+       xfs_ino_t               lastino;
        int                     error;
 
        /*
@@ -244,9 +228,8 @@ xfs_compat_ioc_bulkstat(
         * to userpace memory via bulkreq.ubuffer.  Normally the compat
         * functions and structure size are the correct ones to use ...
         */
-       inumbers_fmt_pf inumbers_func = xfs_inumbers_fmt_compat;
-       bulkstat_one_pf bs_one_func = xfs_bulkstat_one_compat;
-       size_t bs_one_size = sizeof(struct compat_xfs_bstat);
+       inumbers_fmt_pf         inumbers_func = xfs_fsinumbers_fmt_compat;
+       bulkstat_one_fmt_pf     bs_one_func = xfs_fsbulkstat_one_fmt_compat;
 
 #ifdef CONFIG_X86_X32
        if (in_x32_syscall()) {
@@ -258,9 +241,8 @@ xfs_compat_ioc_bulkstat(
                 * the data written out in compat layout will not match what
                 * x32 userspace expects.
                 */
-               inumbers_func = xfs_inumbers_fmt;
-               bs_one_func = xfs_bulkstat_one;
-               bs_one_size = sizeof(struct xfs_bstat);
+               inumbers_func = xfs_fsinumbers_fmt;
+               bs_one_func = xfs_fsbulkstat_one_fmt;
        }
 #endif
 
@@ -284,40 +266,55 @@ xfs_compat_ioc_bulkstat(
                return -EFAULT;
        bulkreq.ocount = compat_ptr(addr);
 
-       if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64)))
+       if (copy_from_user(&lastino, bulkreq.lastip, sizeof(__s64)))
                return -EFAULT;
 
-       if ((count = bulkreq.icount) <= 0)
+       if (bulkreq.icount <= 0)
                return -EINVAL;
 
        if (bulkreq.ubuffer == NULL)
                return -EINVAL;
 
+       breq.ubuffer = bulkreq.ubuffer;
+       breq.icount = bulkreq.icount;
+
+       /*
+        * FSBULKSTAT_SINGLE expects that *lastip contains the inode number
+        * that we want to stat.  However, FSINUMBERS and FSBULKSTAT expect
+        * that *lastip contains either zero or the number of the last inode to
+        * be examined by the previous call and return results starting with
+        * the next inode after that.  The new bulk request back end functions
+        * take the inode to start with, so we have to compute the startino
+        * parameter from lastino to maintain correct function.  lastino == 0
+        * is a special case because it has traditionally meant "first inode
+        * in filesystem".
+        */
        if (cmd == XFS_IOC_FSINUMBERS_32) {
-               error = xfs_inumbers(mp, &inlast, &count,
-                               bulkreq.ubuffer, inumbers_func);
+               breq.startino = lastino ? lastino + 1 : 0;
+               error = xfs_inumbers(&breq, inumbers_func);
+               lastino = breq.startino - 1;
        } else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE_32) {
-               int res;
-
-               error = bs_one_func(mp, inlast, bulkreq.ubuffer,
-                               bs_one_size, NULL, &res);
+               breq.startino = lastino;
+               breq.icount = 1;
+               error = xfs_bulkstat_one(&breq, bs_one_func);
+               lastino = breq.startino;
        } else if (cmd == XFS_IOC_FSBULKSTAT_32) {
-               error = xfs_bulkstat(mp, &inlast, &count,
-                       bs_one_func, bs_one_size,
-                       bulkreq.ubuffer, &done);
-       } else
+               breq.startino = lastino ? lastino + 1 : 0;
+               error = xfs_bulkstat(&breq, bs_one_func);
+               lastino = breq.startino - 1;
+       } else {
                error = -EINVAL;
+       }
        if (error)
                return error;
 
-       if (bulkreq.ocount != NULL) {
-               if (copy_to_user(bulkreq.lastip, &inlast,
-                                               sizeof(xfs_ino_t)))
-                       return -EFAULT;
+       if (bulkreq.lastip != NULL &&
+           copy_to_user(bulkreq.lastip, &lastino, sizeof(xfs_ino_t)))
+               return -EFAULT;
 
-               if (copy_to_user(bulkreq.ocount, &count, sizeof(count)))
-                       return -EFAULT;
-       }
+       if (bulkreq.ocount != NULL &&
+           copy_to_user(bulkreq.ocount, &breq.ocount, sizeof(__s32)))
+               return -EFAULT;
 
        return 0;
 }
@@ -577,6 +574,8 @@ xfs_file_compat_ioctl(
        case XFS_IOC_ERROR_CLEARALL:
        case FS_IOC_GETFSMAP:
        case XFS_IOC_SCRUB_METADATA:
+       case XFS_IOC_BULKSTAT:
+       case XFS_IOC_INUMBERS:
                return xfs_file_ioctl(filp, cmd, p);
 #if !defined(BROKEN_X86_ALIGNMENT) || defined(CONFIG_X86_X32)
        /*
@@ -674,7 +673,7 @@ xfs_file_compat_ioctl(
        case XFS_IOC_FSBULKSTAT_32:
        case XFS_IOC_FSBULKSTAT_SINGLE_32:
        case XFS_IOC_FSINUMBERS_32:
-               return xfs_compat_ioc_bulkstat(mp, cmd, arg);
+               return xfs_compat_ioc_fsbulkstat(mp, cmd, arg);
        case XFS_IOC_FD_TO_HANDLE_32:
        case XFS_IOC_PATH_TO_HANDLE_32:
        case XFS_IOC_PATH_TO_FSHANDLE_32: {
index d28fa82..7985344 100644 (file)
@@ -36,7 +36,7 @@ typedef struct compat_xfs_bstime {
        __s32           tv_nsec;        /* and nanoseconds      */
 } compat_xfs_bstime_t;
 
-typedef struct compat_xfs_bstat {
+struct compat_xfs_bstat {
        __u64           bs_ino;         /* inode number                 */
        __u16           bs_mode;        /* type and mode                */
        __u16           bs_nlink;       /* number of links              */
@@ -61,14 +61,14 @@ typedef struct compat_xfs_bstat {
        __u32           bs_dmevmask;    /* DMIG event mask              */
        __u16           bs_dmstate;     /* DMIG state info              */
        __u16           bs_aextents;    /* attribute number of extents  */
-} __compat_packed compat_xfs_bstat_t;
+} __compat_packed;
 
-typedef struct compat_xfs_fsop_bulkreq {
+struct compat_xfs_fsop_bulkreq {
        compat_uptr_t   lastip;         /* last inode # pointer         */
        __s32           icount;         /* count of entries in buffer   */
        compat_uptr_t   ubuffer;        /* user buffer for inode desc.  */
        compat_uptr_t   ocount;         /* output count pointer         */
-} compat_xfs_fsop_bulkreq_t;
+};
 
 #define XFS_IOC_FSBULKSTAT_32 \
        _IOWR('X', 101, struct compat_xfs_fsop_bulkreq)
@@ -106,7 +106,7 @@ typedef struct compat_xfs_swapext {
        xfs_off_t               sx_offset;      /* offset into file */
        xfs_off_t               sx_length;      /* leng from offset */
        char                    sx_pad[16];     /* pad space, unused */
-       compat_xfs_bstat_t      sx_stat;        /* stat of target b4 copy */
+       struct compat_xfs_bstat sx_stat;        /* stat of target b4 copy */
 } __compat_packed compat_xfs_swapext_t;
 
 #define XFS_IOC_SWAPEXT_32     _IOWR('X', 109, struct compat_xfs_swapext)
@@ -201,11 +201,11 @@ typedef struct compat_xfs_fsop_geom_v1 {
 #define XFS_IOC_FSGEOMETRY_V1_32  \
        _IOR('X', 100, struct compat_xfs_fsop_geom_v1)
 
-typedef struct compat_xfs_inogrp {
+struct compat_xfs_inogrp {
        __u64           xi_startino;    /* starting inode number        */
        __s32           xi_alloccount;  /* # bits set in allocmask      */
        __u64           xi_allocmask;   /* mask of allocated inodes     */
-} __attribute__((packed)) compat_xfs_inogrp_t;
+} __attribute__((packed));
 
 /* These growfs input structures have padding on the end, so must translate */
 typedef struct compat_xfs_growfs_data {
index 63d3239..3a4310d 100644 (file)
@@ -4,7 +4,6 @@
  * Copyright (c) 2016-2018 Christoph Hellwig.
  * All Rights Reserved.
  */
-#include <linux/iomap.h>
 #include "xfs.h"
 #include "xfs_fs.h"
 #include "xfs_shared.h"
@@ -12,7 +11,6 @@
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
 #include "xfs_bmap_btree.h"
@@ -25,7 +23,6 @@
 #include "xfs_inode_item.h"
 #include "xfs_iomap.h"
 #include "xfs_trace.h"
-#include "xfs_icache.h"
 #include "xfs_quota.h"
 #include "xfs_dquot_item.h"
 #include "xfs_dquot.h"
@@ -779,7 +776,7 @@ xfs_iomap_write_unwritten(
                 * complete here and might deadlock on the iolock.
                 */
                error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0,
-                               XFS_TRANS_RESERVE | XFS_TRANS_NOFS, &tp);
+                               XFS_TRANS_RESERVE, &tp);
                if (error)
                        return error;
 
index 74047bd..ff3c1fa 100644 (file)
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_da_format.h"
 #include "xfs_inode.h"
-#include "xfs_bmap.h"
-#include "xfs_bmap_util.h"
 #include "xfs_acl.h"
 #include "xfs_quota.h"
-#include "xfs_error.h"
 #include "xfs_attr.h"
 #include "xfs_trans.h"
 #include "xfs_trace.h"
 #include "xfs_icache.h"
 #include "xfs_symlink.h"
-#include "xfs_da_btree.h"
 #include "xfs_dir2.h"
-#include "xfs_trans_space.h"
 #include "xfs_iomap.h"
-#include "xfs_defer.h"
 
-#include <linux/capability.h>
 #include <linux/xattr.h>
 #include <linux/posix_acl.h>
 #include <linux/security.h>
-#include <linux/iomap.h>
-#include <linux/slab.h>
 #include <linux/iversion.h>
 
 /*
index 1e1a0af..a8a06bb 100644 (file)
 #include "xfs_btree.h"
 #include "xfs_ialloc.h"
 #include "xfs_ialloc_btree.h"
+#include "xfs_iwalk.h"
 #include "xfs_itable.h"
 #include "xfs_error.h"
-#include "xfs_trace.h"
 #include "xfs_icache.h"
 #include "xfs_health.h"
 
 /*
- * Return stat information for one inode.
- * Return 0 if ok, else errno.
+ * Bulk Stat
+ * =========
+ *
+ * Use the inode walking functions to fill out struct xfs_bulkstat for every
+ * allocated inode, then pass the stat information to some externally provided
+ * iteration function.
  */
-int
+
+struct xfs_bstat_chunk {
+       bulkstat_one_fmt_pf     formatter;
+       struct xfs_ibulk        *breq;
+       struct xfs_bulkstat     *buf;
+};
+
+/*
+ * Fill out the bulkstat info for a single inode and report it somewhere.
+ *
+ * bc->breq->lastino is effectively the inode cursor as we walk through the
+ * filesystem.  Therefore, we update it any time we need to move the cursor
+ * forward, regardless of whether or not we're sending any bstat information
+ * back to userspace.  If the inode is internal metadata or, has been freed
+ * out from under us, we just simply keep going.
+ *
+ * However, if any other type of error happens we want to stop right where we
+ * are so that userspace will call back with exact number of the bad inode and
+ * we can send back an error code.
+ *
+ * Note that if the formatter tells us there's no space left in the buffer we
+ * move the cursor forward and abort the walk.
+ */
+STATIC int
 xfs_bulkstat_one_int(
-       struct xfs_mount        *mp,            /* mount point for filesystem */
-       xfs_ino_t               ino,            /* inode to get data for */
-       void __user             *buffer,        /* buffer to place output in */
-       int                     ubsize,         /* size of buffer */
-       bulkstat_one_fmt_pf     formatter,      /* formatter, copy to user */
-       int                     *ubused,        /* bytes used by me */
-       int                     *stat)          /* BULKSTAT_RV_... */
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       xfs_ino_t               ino,
+       struct xfs_bstat_chunk  *bc)
 {
        struct xfs_icdinode     *dic;           /* dinode core info pointer */
        struct xfs_inode        *ip;            /* incore inode pointer */
        struct inode            *inode;
-       struct xfs_bstat        *buf;           /* return buffer */
-       int                     error = 0;      /* error value */
+       struct xfs_bulkstat     *buf = bc->buf;
+       int                     error = -EINVAL;
 
-       *stat = BULKSTAT_RV_NOTHING;
+       if (xfs_internal_inum(mp, ino))
+               goto out_advance;
 
-       if (!buffer || xfs_internal_inum(mp, ino))
-               return -EINVAL;
-
-       buf = kmem_zalloc(sizeof(*buf), KM_SLEEP | KM_MAYFAIL);
-       if (!buf)
-               return -ENOMEM;
-
-       error = xfs_iget(mp, NULL, ino,
+       error = xfs_iget(mp, tp, ino,
                         (XFS_IGET_DONTCACHE | XFS_IGET_UNTRUSTED),
                         XFS_ILOCK_SHARED, &ip);
+       if (error == -ENOENT || error == -EINVAL)
+               goto out_advance;
        if (error)
-               goto out_free;
+               goto out;
 
        ASSERT(ip != NULL);
        ASSERT(ip->i_imap.im_blkno != 0);
@@ -64,37 +84,35 @@ xfs_bulkstat_one_int(
        /* xfs_iget returns the following without needing
         * further change.
         */
-       buf->bs_projid_lo = dic->di_projid_lo;
-       buf->bs_projid_hi = dic->di_projid_hi;
+       buf->bs_projectid = xfs_get_projid(ip);
        buf->bs_ino = ino;
        buf->bs_uid = dic->di_uid;
        buf->bs_gid = dic->di_gid;
        buf->bs_size = dic->di_size;
 
        buf->bs_nlink = inode->i_nlink;
-       buf->bs_atime.tv_sec = inode->i_atime.tv_sec;
-       buf->bs_atime.tv_nsec = inode->i_atime.tv_nsec;
-       buf->bs_mtime.tv_sec = inode->i_mtime.tv_sec;
-       buf->bs_mtime.tv_nsec = inode->i_mtime.tv_nsec;
-       buf->bs_ctime.tv_sec = inode->i_ctime.tv_sec;
-       buf->bs_ctime.tv_nsec = inode->i_ctime.tv_nsec;
+       buf->bs_atime = inode->i_atime.tv_sec;
+       buf->bs_atime_nsec = inode->i_atime.tv_nsec;
+       buf->bs_mtime = inode->i_mtime.tv_sec;
+       buf->bs_mtime_nsec = inode->i_mtime.tv_nsec;
+       buf->bs_ctime = inode->i_ctime.tv_sec;
+       buf->bs_ctime_nsec = inode->i_ctime.tv_nsec;
+       buf->bs_btime = dic->di_crtime.t_sec;
+       buf->bs_btime_nsec = dic->di_crtime.t_nsec;
        buf->bs_gen = inode->i_generation;
        buf->bs_mode = inode->i_mode;
 
        buf->bs_xflags = xfs_ip2xflags(ip);
-       buf->bs_extsize = dic->di_extsize << mp->m_sb.sb_blocklog;
+       buf->bs_extsize_blks = dic->di_extsize;
        buf->bs_extents = dic->di_nextents;
-       memset(buf->bs_pad, 0, sizeof(buf->bs_pad));
        xfs_bulkstat_health(ip, buf);
-       buf->bs_dmevmask = dic->di_dmevmask;
-       buf->bs_dmstate = dic->di_dmstate;
        buf->bs_aextents = dic->di_anextents;
        buf->bs_forkoff = XFS_IFORK_BOFF(ip);
+       buf->bs_version = XFS_BULKSTAT_VERSION_V5;
 
        if (dic->di_version == 3) {
                if (dic->di_flags2 & XFS_DIFLAG2_COWEXTSIZE)
-                       buf->bs_cowextsize = dic->di_cowextsize <<
-                                       mp->m_sb.sb_blocklog;
+                       buf->bs_cowextsize_blks = dic->di_cowextsize;
        }
 
        switch (dic->di_format) {
@@ -118,385 +136,121 @@ xfs_bulkstat_one_int(
        xfs_iunlock(ip, XFS_ILOCK_SHARED);
        xfs_irele(ip);
 
-       error = formatter(buffer, ubsize, ubused, buf);
-       if (!error)
-               *stat = BULKSTAT_RV_DIDONE;
+       error = bc->formatter(bc->breq, buf);
+       if (error == XFS_IBULK_ABORT)
+               goto out_advance;
+       if (error)
+               goto out;
 
- out_free:
-       kmem_free(buf);
+out_advance:
+       /*
+        * Advance the cursor to the inode that comes after the one we just
+        * looked at.  We want the caller to move along if the bulkstat
+        * information was copied successfully; if we tried to grab the inode
+        * but it's no longer allocated; or if it's internal metadata.
+        */
+       bc->breq->startino = ino + 1;
+out:
        return error;
 }
 
-/* Return 0 on success or positive error */
-STATIC int
-xfs_bulkstat_one_fmt(
-       void                    __user *ubuffer,
-       int                     ubsize,
-       int                     *ubused,
-       const xfs_bstat_t       *buffer)
-{
-       if (ubsize < sizeof(*buffer))
-               return -ENOMEM;
-       if (copy_to_user(ubuffer, buffer, sizeof(*buffer)))
-               return -EFAULT;
-       if (ubused)
-               *ubused = sizeof(*buffer);
-       return 0;
-}
-
+/* Bulkstat a single inode. */
 int
 xfs_bulkstat_one(
-       xfs_mount_t     *mp,            /* mount point for filesystem */
-       xfs_ino_t       ino,            /* inode number to get data for */
-       void            __user *buffer, /* buffer to place output in */
-       int             ubsize,         /* size of buffer */
-       int             *ubused,        /* bytes used by me */
-       int             *stat)          /* BULKSTAT_RV_... */
+       struct xfs_ibulk        *breq,
+       bulkstat_one_fmt_pf     formatter)
 {
-       return xfs_bulkstat_one_int(mp, ino, buffer, ubsize,
-                                   xfs_bulkstat_one_fmt, ubused, stat);
-}
+       struct xfs_bstat_chunk  bc = {
+               .formatter      = formatter,
+               .breq           = breq,
+       };
+       int                     error;
 
-/*
- * Loop over all clusters in a chunk for a given incore inode allocation btree
- * record.  Do a readahead if there are any allocated inodes in that cluster.
- */
-STATIC void
-xfs_bulkstat_ichunk_ra(
-       struct xfs_mount                *mp,
-       xfs_agnumber_t                  agno,
-       struct xfs_inobt_rec_incore     *irec)
-{
-       xfs_agblock_t                   agbno;
-       struct blk_plug                 plug;
-       int                             i;      /* inode chunk index */
-
-       agbno = XFS_AGINO_TO_AGBNO(mp, irec->ir_startino);
-
-       blk_start_plug(&plug);
-       for (i = 0; i < XFS_INODES_PER_CHUNK;
-            i += mp->m_inodes_per_cluster, agbno += mp->m_blocks_per_cluster) {
-               if (xfs_inobt_maskn(i, mp->m_inodes_per_cluster) &
-                   ~irec->ir_free) {
-                       xfs_btree_reada_bufs(mp, agno, agbno,
-                                       mp->m_blocks_per_cluster,
-                                       &xfs_inode_buf_ops);
-               }
-       }
-       blk_finish_plug(&plug);
-}
+       ASSERT(breq->icount == 1);
 
-/*
- * Lookup the inode chunk that the given inode lives in and then get the record
- * if we found the chunk.  If the inode was not the last in the chunk and there
- * are some left allocated, update the data for the pointed-to record as well as
- * return the count of grabbed inodes.
- */
-STATIC int
-xfs_bulkstat_grab_ichunk(
-       struct xfs_btree_cur            *cur,   /* btree cursor */
-       xfs_agino_t                     agino,  /* starting inode of chunk */
-       int                             *icount,/* return # of inodes grabbed */
-       struct xfs_inobt_rec_incore     *irec)  /* btree record */
-{
-       int                             idx;    /* index into inode chunk */
-       int                             stat;
-       int                             error = 0;
-
-       /* Lookup the inode chunk that this inode lives in */
-       error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &stat);
-       if (error)
-               return error;
-       if (!stat) {
-               *icount = 0;
-               return error;
-       }
+       bc.buf = kmem_zalloc(sizeof(struct xfs_bulkstat),
+                       KM_SLEEP | KM_MAYFAIL);
+       if (!bc.buf)
+               return -ENOMEM;
 
-       /* Get the record, should always work */
-       error = xfs_inobt_get_rec(cur, irec, &stat);
-       if (error)
-               return error;
-       XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, stat == 1);
+       error = xfs_bulkstat_one_int(breq->mp, NULL, breq->startino, &bc);
 
-       /* Check if the record contains the inode in request */
-       if (irec->ir_startino + XFS_INODES_PER_CHUNK <= agino) {
-               *icount = 0;
-               return 0;
-       }
+       kmem_free(bc.buf);
 
-       idx = agino - irec->ir_startino + 1;
-       if (idx < XFS_INODES_PER_CHUNK &&
-           (xfs_inobt_maskn(idx, XFS_INODES_PER_CHUNK - idx) & ~irec->ir_free)) {
-               int     i;
-
-               /* We got a right chunk with some left inodes allocated at it.
-                * Grab the chunk record.  Mark all the uninteresting inodes
-                * free -- because they're before our start point.
-                */
-               for (i = 0; i < idx; i++) {
-                       if (XFS_INOBT_MASK(i) & ~irec->ir_free)
-                               irec->ir_freecount++;
-               }
-
-               irec->ir_free |= xfs_inobt_maskn(0, idx);
-               *icount = irec->ir_count - irec->ir_freecount;
-       }
+       /*
+        * If we reported one inode to userspace then we abort because we hit
+        * the end of the buffer.  Don't leak that back to userspace.
+        */
+       if (error == XFS_IWALK_ABORT)
+               error = 0;
 
-       return 0;
+       return error;
 }
 
-#define XFS_BULKSTAT_UBLEFT(ubleft)    ((ubleft) >= statstruct_size)
-
-struct xfs_bulkstat_agichunk {
-       char            __user **ac_ubuffer;/* pointer into user's buffer */
-       int             ac_ubleft;      /* bytes left in user's buffer */
-       int             ac_ubelem;      /* spaces used in user's buffer */
-};
-
-/*
- * Process inodes in chunk with a pointer to a formatter function
- * that will iget the inode and fill in the appropriate structure.
- */
 static int
-xfs_bulkstat_ag_ichunk(
-       struct xfs_mount                *mp,
-       xfs_agnumber_t                  agno,
-       struct xfs_inobt_rec_incore     *irbp,
-       bulkstat_one_pf                 formatter,
-       size_t                          statstruct_size,
-       struct xfs_bulkstat_agichunk    *acp,
-       xfs_agino_t                     *last_agino)
+xfs_bulkstat_iwalk(
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       xfs_ino_t               ino,
+       void                    *data)
 {
-       char                            __user **ubufp = acp->ac_ubuffer;
-       int                             chunkidx;
-       int                             error = 0;
-       xfs_agino_t                     agino = irbp->ir_startino;
-
-       for (chunkidx = 0; chunkidx < XFS_INODES_PER_CHUNK;
-            chunkidx++, agino++) {
-               int             fmterror;
-               int             ubused;
-
-               /* inode won't fit in buffer, we are done */
-               if (acp->ac_ubleft < statstruct_size)
-                       break;
-
-               /* Skip if this inode is free */
-               if (XFS_INOBT_MASK(chunkidx) & irbp->ir_free)
-                       continue;
-
-               /* Get the inode and fill in a single buffer */
-               ubused = statstruct_size;
-               error = formatter(mp, XFS_AGINO_TO_INO(mp, agno, agino),
-                                 *ubufp, acp->ac_ubleft, &ubused, &fmterror);
-
-               if (fmterror == BULKSTAT_RV_GIVEUP ||
-                   (error && error != -ENOENT && error != -EINVAL)) {
-                       acp->ac_ubleft = 0;
-                       ASSERT(error);
-                       break;
-               }
-
-               /* be careful not to leak error if at end of chunk */
-               if (fmterror == BULKSTAT_RV_NOTHING || error) {
-                       error = 0;
-                       continue;
-               }
-
-               *ubufp += ubused;
-               acp->ac_ubleft -= ubused;
-               acp->ac_ubelem++;
-       }
-
-       /*
-        * Post-update *last_agino. At this point, agino will always point one
-        * inode past the last inode we processed successfully. Hence we
-        * substract that inode when setting the *last_agino cursor so that we
-        * return the correct cookie to userspace. On the next bulkstat call,
-        * the inode under the lastino cookie will be skipped as we have already
-        * processed it here.
-        */
-       *last_agino = agino - 1;
+       int                     error;
 
+       error = xfs_bulkstat_one_int(mp, tp, ino, data);
+       /* bulkstat just skips over missing inodes */
+       if (error == -ENOENT || error == -EINVAL)
+               return 0;
        return error;
 }
 
 /*
- * Return stat information in bulk (by-inode) for the filesystem.
+ * Check the incoming lastino parameter.
+ *
+ * We allow any inode value that could map to physical space inside the
+ * filesystem because if there are no inodes there, bulkstat moves on to the
+ * next chunk.  In other words, the magic agino value of zero takes us to the
+ * first chunk in the AG, and an agino value past the end of the AG takes us to
+ * the first chunk in the next AG.
+ *
+ * Therefore we can end early if the requested inode is beyond the end of the
+ * filesystem or doesn't map properly.
  */
-int                                    /* error status */
-xfs_bulkstat(
-       xfs_mount_t             *mp,    /* mount point for filesystem */
-       xfs_ino_t               *lastinop, /* last inode returned */
-       int                     *ubcountp, /* size of buffer/count returned */
-       bulkstat_one_pf         formatter, /* func that'd fill a single buf */
-       size_t                  statstruct_size, /* sizeof struct filling */
-       char                    __user *ubuffer, /* buffer with inode stats */
-       int                     *done)  /* 1 if there are more stats to get */
+static inline bool
+xfs_bulkstat_already_done(
+       struct xfs_mount        *mp,
+       xfs_ino_t               startino)
 {
-       xfs_buf_t               *agbp;  /* agi header buffer */
-       xfs_agino_t             agino;  /* inode # in allocation group */
-       xfs_agnumber_t          agno;   /* allocation group number */
-       xfs_btree_cur_t         *cur;   /* btree cursor for ialloc btree */
-       xfs_inobt_rec_incore_t  *irbuf; /* start of irec buffer */
-       int                     nirbuf; /* size of irbuf */
-       int                     ubcount; /* size of user's buffer */
-       struct xfs_bulkstat_agichunk ac;
-       int                     error = 0;
+       xfs_agnumber_t          agno = XFS_INO_TO_AGNO(mp, startino);
+       xfs_agino_t             agino = XFS_INO_TO_AGINO(mp, startino);
 
-       /*
-        * Get the last inode value, see if there's nothing to do.
-        */
-       agno = XFS_INO_TO_AGNO(mp, *lastinop);
-       agino = XFS_INO_TO_AGINO(mp, *lastinop);
-       if (agno >= mp->m_sb.sb_agcount ||
-           *lastinop != XFS_AGINO_TO_INO(mp, agno, agino)) {
-               *done = 1;
-               *ubcountp = 0;
-               return 0;
-       }
+       return agno >= mp->m_sb.sb_agcount ||
+              startino != XFS_AGINO_TO_INO(mp, agno, agino);
+}
 
-       ubcount = *ubcountp; /* statstruct's */
-       ac.ac_ubuffer = &ubuffer;
-       ac.ac_ubleft = ubcount * statstruct_size; /* bytes */;
-       ac.ac_ubelem = 0;
+/* Return stat information in bulk (by-inode) for the filesystem. */
+int
+xfs_bulkstat(
+       struct xfs_ibulk        *breq,
+       bulkstat_one_fmt_pf     formatter)
+{
+       struct xfs_bstat_chunk  bc = {
+               .formatter      = formatter,
+               .breq           = breq,
+       };
+       int                     error;
 
-       *ubcountp = 0;
-       *done = 0;
+       if (xfs_bulkstat_already_done(breq->mp, breq->startino))
+               return 0;
 
-       irbuf = kmem_zalloc_large(PAGE_SIZE * 4, KM_SLEEP);
-       if (!irbuf)
+       bc.buf = kmem_zalloc(sizeof(struct xfs_bulkstat),
+                       KM_SLEEP | KM_MAYFAIL);
+       if (!bc.buf)
                return -ENOMEM;
-       nirbuf = (PAGE_SIZE * 4) / sizeof(*irbuf);
 
-       /*
-        * Loop over the allocation groups, starting from the last
-        * inode returned; 0 means start of the allocation group.
-        */
-       while (agno < mp->m_sb.sb_agcount) {
-               struct xfs_inobt_rec_incore     *irbp = irbuf;
-               struct xfs_inobt_rec_incore     *irbufend = irbuf + nirbuf;
-               bool                            end_of_ag = false;
-               int                             icount = 0;
-               int                             stat;
-
-               error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
-               if (error)
-                       break;
-               /*
-                * Allocate and initialize a btree cursor for ialloc btree.
-                */
-               cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno,
-                                           XFS_BTNUM_INO);
-               if (agino > 0) {
-                       /*
-                        * In the middle of an allocation group, we need to get
-                        * the remainder of the chunk we're in.
-                        */
-                       struct xfs_inobt_rec_incore     r;
-
-                       error = xfs_bulkstat_grab_ichunk(cur, agino, &icount, &r);
-                       if (error)
-                               goto del_cursor;
-                       if (icount) {
-                               irbp->ir_startino = r.ir_startino;
-                               irbp->ir_holemask = r.ir_holemask;
-                               irbp->ir_count = r.ir_count;
-                               irbp->ir_freecount = r.ir_freecount;
-                               irbp->ir_free = r.ir_free;
-                               irbp++;
-                       }
-                       /* Increment to the next record */
-                       error = xfs_btree_increment(cur, 0, &stat);
-               } else {
-                       /* Start of ag.  Lookup the first inode chunk */
-                       error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &stat);
-               }
-               if (error || stat == 0) {
-                       end_of_ag = true;
-                       goto del_cursor;
-               }
-
-               /*
-                * Loop through inode btree records in this ag,
-                * until we run out of inodes or space in the buffer.
-                */
-               while (irbp < irbufend && icount < ubcount) {
-                       struct xfs_inobt_rec_incore     r;
-
-                       error = xfs_inobt_get_rec(cur, &r, &stat);
-                       if (error || stat == 0) {
-                               end_of_ag = true;
-                               goto del_cursor;
-                       }
-
-                       /*
-                        * If this chunk has any allocated inodes, save it.
-                        * Also start read-ahead now for this chunk.
-                        */
-                       if (r.ir_freecount < r.ir_count) {
-                               xfs_bulkstat_ichunk_ra(mp, agno, &r);
-                               irbp->ir_startino = r.ir_startino;
-                               irbp->ir_holemask = r.ir_holemask;
-                               irbp->ir_count = r.ir_count;
-                               irbp->ir_freecount = r.ir_freecount;
-                               irbp->ir_free = r.ir_free;
-                               irbp++;
-                               icount += r.ir_count - r.ir_freecount;
-                       }
-                       error = xfs_btree_increment(cur, 0, &stat);
-                       if (error || stat == 0) {
-                               end_of_ag = true;
-                               goto del_cursor;
-                       }
-                       cond_resched();
-               }
-
-               /*
-                * Drop the btree buffers and the agi buffer as we can't hold any
-                * of the locks these represent when calling iget. If there is a
-                * pending error, then we are done.
-                */
-del_cursor:
-               xfs_btree_del_cursor(cur, error);
-               xfs_buf_relse(agbp);
-               if (error)
-                       break;
-               /*
-                * Now format all the good inodes into the user's buffer. The
-                * call to xfs_bulkstat_ag_ichunk() sets up the agino pointer
-                * for the next loop iteration.
-                */
-               irbufend = irbp;
-               for (irbp = irbuf;
-                    irbp < irbufend && ac.ac_ubleft >= statstruct_size;
-                    irbp++) {
-                       error = xfs_bulkstat_ag_ichunk(mp, agno, irbp,
-                                       formatter, statstruct_size, &ac,
-                                       &agino);
-                       if (error)
-                               break;
-
-                       cond_resched();
-               }
-
-               /*
-                * If we've run out of space or had a formatting error, we
-                * are now done
-                */
-               if (ac.ac_ubleft < statstruct_size || error)
-                       break;
-
-               if (end_of_ag) {
-                       agno++;
-                       agino = 0;
-               }
-       }
-       /*
-        * Done, we're either out of filesystem or space to put the data.
-        */
-       kmem_free(irbuf);
-       *ubcountp = ac.ac_ubelem;
+       error = xfs_iwalk(breq->mp, NULL, breq->startino, breq->flags,
+                       xfs_bulkstat_iwalk, breq->icount, &bc);
+
+       kmem_free(bc.buf);
 
        /*
         * We found some inodes, so clear the error status and return them.
@@ -505,135 +259,136 @@ del_cursor:
         * triggered again and propagated to userspace as there will be no
         * formatted inodes in the buffer.
         */
-       if (ac.ac_ubelem)
+       if (breq->ocount > 0)
                error = 0;
 
-       /*
-        * If we ran out of filesystem, lastino will point off the end of
-        * the filesystem so the next call will return immediately.
-        */
-       *lastinop = XFS_AGINO_TO_INO(mp, agno, agino);
-       if (agno >= mp->m_sb.sb_agcount)
-               *done = 1;
-
        return error;
 }
 
-int
-xfs_inumbers_fmt(
-       void                    __user *ubuffer, /* buffer to write to */
-       const struct xfs_inogrp *buffer,        /* buffer to read from */
-       long                    count,          /* # of elements to read */
-       long                    *written)       /* # of bytes written */
+/* Convert bulkstat (v5) to bstat (v1). */
+void
+xfs_bulkstat_to_bstat(
+       struct xfs_mount                *mp,
+       struct xfs_bstat                *bs1,
+       const struct xfs_bulkstat       *bstat)
 {
-       if (copy_to_user(ubuffer, buffer, count * sizeof(*buffer)))
-               return -EFAULT;
-       *written = count * sizeof(*buffer);
-       return 0;
+       memset(bs1, 0, sizeof(struct xfs_bstat));
+       bs1->bs_ino = bstat->bs_ino;
+       bs1->bs_mode = bstat->bs_mode;
+       bs1->bs_nlink = bstat->bs_nlink;
+       bs1->bs_uid = bstat->bs_uid;
+       bs1->bs_gid = bstat->bs_gid;
+       bs1->bs_rdev = bstat->bs_rdev;
+       bs1->bs_blksize = bstat->bs_blksize;
+       bs1->bs_size = bstat->bs_size;
+       bs1->bs_atime.tv_sec = bstat->bs_atime;
+       bs1->bs_mtime.tv_sec = bstat->bs_mtime;
+       bs1->bs_ctime.tv_sec = bstat->bs_ctime;
+       bs1->bs_atime.tv_nsec = bstat->bs_atime_nsec;
+       bs1->bs_mtime.tv_nsec = bstat->bs_mtime_nsec;
+       bs1->bs_ctime.tv_nsec = bstat->bs_ctime_nsec;
+       bs1->bs_blocks = bstat->bs_blocks;
+       bs1->bs_xflags = bstat->bs_xflags;
+       bs1->bs_extsize = XFS_FSB_TO_B(mp, bstat->bs_extsize_blks);
+       bs1->bs_extents = bstat->bs_extents;
+       bs1->bs_gen = bstat->bs_gen;
+       bs1->bs_projid_lo = bstat->bs_projectid & 0xFFFF;
+       bs1->bs_forkoff = bstat->bs_forkoff;
+       bs1->bs_projid_hi = bstat->bs_projectid >> 16;
+       bs1->bs_sick = bstat->bs_sick;
+       bs1->bs_checked = bstat->bs_checked;
+       bs1->bs_cowextsize = XFS_FSB_TO_B(mp, bstat->bs_cowextsize_blks);
+       bs1->bs_dmevmask = 0;
+       bs1->bs_dmstate = 0;
+       bs1->bs_aextents = bstat->bs_aextents;
+}
+
+struct xfs_inumbers_chunk {
+       inumbers_fmt_pf         formatter;
+       struct xfs_ibulk        *breq;
+};
+
+/*
+ * INUMBERS
+ * ========
+ * This is how we export inode btree records to userspace, so that XFS tools
+ * can figure out where inodes are allocated.
+ */
+
+/*
+ * Format the inode group structure and report it somewhere.
+ *
+ * Similar to xfs_bulkstat_one_int, lastino is the inode cursor as we walk
+ * through the filesystem so we move it forward unless there was a runtime
+ * error.  If the formatter tells us the buffer is now full we also move the
+ * cursor forward and abort the walk.
+ */
+STATIC int
+xfs_inumbers_walk(
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       xfs_agnumber_t          agno,
+       const struct xfs_inobt_rec_incore *irec,
+       void                    *data)
+{
+       struct xfs_inumbers     inogrp = {
+               .xi_startino    = XFS_AGINO_TO_INO(mp, agno, irec->ir_startino),
+               .xi_alloccount  = irec->ir_count - irec->ir_freecount,
+               .xi_allocmask   = ~irec->ir_free,
+               .xi_version     = XFS_INUMBERS_VERSION_V5,
+       };
+       struct xfs_inumbers_chunk *ic = data;
+       int                     error;
+
+       error = ic->formatter(ic->breq, &inogrp);
+       if (error && error != XFS_IBULK_ABORT)
+               return error;
+
+       ic->breq->startino = XFS_AGINO_TO_INO(mp, agno, irec->ir_startino) +
+                       XFS_INODES_PER_CHUNK;
+       return error;
 }
 
 /*
  * Return inode number table for the filesystem.
  */
-int                                    /* error status */
+int
 xfs_inumbers(
-       struct xfs_mount        *mp,/* mount point for filesystem */
-       xfs_ino_t               *lastino,/* last inode returned */
-       int                     *count,/* size of buffer/count returned */
-       void                    __user *ubuffer,/* buffer with inode descriptions */
+       struct xfs_ibulk        *breq,
        inumbers_fmt_pf         formatter)
 {
-       xfs_agnumber_t          agno = XFS_INO_TO_AGNO(mp, *lastino);
-       xfs_agino_t             agino = XFS_INO_TO_AGINO(mp, *lastino);
-       struct xfs_btree_cur    *cur = NULL;
-       struct xfs_buf          *agbp = NULL;
-       struct xfs_inogrp       *buffer;
-       int                     bcount;
-       int                     left = *count;
-       int                     bufidx = 0;
+       struct xfs_inumbers_chunk ic = {
+               .formatter      = formatter,
+               .breq           = breq,
+       };
        int                     error = 0;
 
-       *count = 0;
-       if (agno >= mp->m_sb.sb_agcount ||
-           *lastino != XFS_AGINO_TO_INO(mp, agno, agino))
-               return error;
+       if (xfs_bulkstat_already_done(breq->mp, breq->startino))
+               return 0;
 
-       bcount = min(left, (int)(PAGE_SIZE / sizeof(*buffer)));
-       buffer = kmem_zalloc(bcount * sizeof(*buffer), KM_SLEEP);
-       do {
-               struct xfs_inobt_rec_incore     r;
-               int                             stat;
-
-               if (!agbp) {
-                       error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
-                       if (error)
-                               break;
-
-                       cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno,
-                                                   XFS_BTNUM_INO);
-                       error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_GE,
-                                                &stat);
-                       if (error)
-                               break;
-                       if (!stat)
-                               goto next_ag;
-               }
-
-               error = xfs_inobt_get_rec(cur, &r, &stat);
-               if (error)
-                       break;
-               if (!stat)
-                       goto next_ag;
-
-               agino = r.ir_startino + XFS_INODES_PER_CHUNK - 1;
-               buffer[bufidx].xi_startino =
-                       XFS_AGINO_TO_INO(mp, agno, r.ir_startino);
-               buffer[bufidx].xi_alloccount = r.ir_count - r.ir_freecount;
-               buffer[bufidx].xi_allocmask = ~r.ir_free;
-               if (++bufidx == bcount) {
-                       long    written;
-
-                       error = formatter(ubuffer, buffer, bufidx, &written);
-                       if (error)
-                               break;
-                       ubuffer += written;
-                       *count += bufidx;
-                       bufidx = 0;
-               }
-               if (!--left)
-                       break;
-
-               error = xfs_btree_increment(cur, 0, &stat);
-               if (error)
-                       break;
-               if (stat)
-                       continue;
-
-next_ag:
-               xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
-               cur = NULL;
-               xfs_buf_relse(agbp);
-               agbp = NULL;
-               agino = 0;
-               agno++;
-       } while (agno < mp->m_sb.sb_agcount);
-
-       if (!error) {
-               if (bufidx) {
-                       long    written;
-
-                       error = formatter(ubuffer, buffer, bufidx, &written);
-                       if (!error)
-                               *count += bufidx;
-               }
-               *lastino = XFS_AGINO_TO_INO(mp, agno, agino);
-       }
+       error = xfs_inobt_walk(breq->mp, NULL, breq->startino, breq->flags,
+                       xfs_inumbers_walk, breq->icount, &ic);
 
-       kmem_free(buffer);
-       if (cur)
-               xfs_btree_del_cursor(cur, error);
-       if (agbp)
-               xfs_buf_relse(agbp);
+       /*
+        * We found some inode groups, so clear the error status and return
+        * them.  The lastino pointer will point directly at the inode that
+        * triggered any error that occurred, so on the next call the error
+        * will be triggered again and propagated to userspace as there will be
+        * no formatted inode groups in the buffer.
+        */
+       if (breq->ocount > 0)
+               error = 0;
 
        return error;
 }
+
+/* Convert an inumbers (v5) struct to a inogrp (v1) struct. */
+void
+xfs_inumbers_to_inogrp(
+       struct xfs_inogrp               *ig1,
+       const struct xfs_inumbers       *ig)
+{
+       ig1->xi_startino = ig->xi_startino;
+       ig1->xi_alloccount = ig->xi_alloccount;
+       ig1->xi_allocmask = ig->xi_allocmask;
+}
index 8a82228..e90c1fc 100644 (file)
@@ -5,83 +5,55 @@
 #ifndef __XFS_ITABLE_H__
 #define        __XFS_ITABLE_H__
 
-/*
- * xfs_bulkstat() is used to fill in xfs_bstat structures as well as dm_stat
- * structures (by the dmi library). This is a pointer to a formatter function
- * that will iget the inode and fill in the appropriate structure.
- * see xfs_bulkstat_one() and xfs_dm_bulkstat_one() in dmapi_xfs.c
- */
-typedef int (*bulkstat_one_pf)(struct xfs_mount        *mp,
-                              xfs_ino_t        ino,
-                              void             __user *buffer,
-                              int              ubsize,
-                              int              *ubused,
-                              int              *stat);
+/* In-memory representation of a userspace request for batch inode data. */
+struct xfs_ibulk {
+       struct xfs_mount        *mp;
+       void __user             *ubuffer; /* user output buffer */
+       xfs_ino_t               startino; /* start with this inode */
+       unsigned int            icount;   /* number of elements in ubuffer */
+       unsigned int            ocount;   /* number of records returned */
+       unsigned int            flags;    /* see XFS_IBULK_FLAG_* */
+};
+
+/* Only iterate within the same AG as startino */
+#define XFS_IBULK_SAME_AG      (XFS_IWALK_SAME_AG)
+
+/* Return value that means we want to abort the walk. */
+#define XFS_IBULK_ABORT                (XFS_IWALK_ABORT)
 
 /*
- * Values for stat return value.
+ * Advance the user buffer pointer by one record of the given size.  If the
+ * buffer is now full, return the appropriate error code.
  */
-#define BULKSTAT_RV_NOTHING    0
-#define BULKSTAT_RV_DIDONE     1
-#define BULKSTAT_RV_GIVEUP     2
+static inline int
+xfs_ibulk_advance(
+       struct xfs_ibulk        *breq,
+       size_t                  bytes)
+{
+       char __user             *b = breq->ubuffer;
+
+       breq->ubuffer = b + bytes;
+       breq->ocount++;
+       return breq->ocount == breq->icount ? XFS_IBULK_ABORT : 0;
+}
 
 /*
  * Return stat information in bulk (by-inode) for the filesystem.
  */
-int                                    /* error status */
-xfs_bulkstat(
-       xfs_mount_t     *mp,            /* mount point for filesystem */
-       xfs_ino_t       *lastino,       /* last inode returned */
-       int             *count,         /* size of buffer/count returned */
-       bulkstat_one_pf formatter,      /* func that'd fill a single buf */
-       size_t          statstruct_size,/* sizeof struct that we're filling */
-       char            __user *ubuffer,/* buffer with inode stats */
-       int             *done);         /* 1 if there are more stats to get */
-
-typedef int (*bulkstat_one_fmt_pf)(  /* used size in bytes or negative error */
-       void                    __user *ubuffer, /* buffer to write to */
-       int                     ubsize,          /* remaining user buffer sz */
-       int                     *ubused,         /* bytes used by formatter */
-       const xfs_bstat_t       *buffer);        /* buffer to read from */
-
-int
-xfs_bulkstat_one_int(
-       xfs_mount_t             *mp,
-       xfs_ino_t               ino,
-       void                    __user *buffer,
-       int                     ubsize,
-       bulkstat_one_fmt_pf     formatter,
-       int                     *ubused,
-       int                     *stat);
 
-int
-xfs_bulkstat_one(
-       xfs_mount_t             *mp,
-       xfs_ino_t               ino,
-       void                    __user *buffer,
-       int                     ubsize,
-       int                     *ubused,
-       int                     *stat);
+typedef int (*bulkstat_one_fmt_pf)(struct xfs_ibulk *breq,
+               const struct xfs_bulkstat *bstat);
 
-typedef int (*inumbers_fmt_pf)(
-       void                    __user *ubuffer, /* buffer to write to */
-       const xfs_inogrp_t      *buffer,        /* buffer to read from */
-       long                    count,          /* # of elements to read */
-       long                    *written);      /* # of bytes written */
+int xfs_bulkstat_one(struct xfs_ibulk *breq, bulkstat_one_fmt_pf formatter);
+int xfs_bulkstat(struct xfs_ibulk *breq, bulkstat_one_fmt_pf formatter);
+void xfs_bulkstat_to_bstat(struct xfs_mount *mp, struct xfs_bstat *bs1,
+               const struct xfs_bulkstat *bstat);
 
-int
-xfs_inumbers_fmt(
-       void                    __user *ubuffer, /* buffer to write to */
-       const xfs_inogrp_t      *buffer,        /* buffer to read from */
-       long                    count,          /* # of elements to read */
-       long                    *written);      /* # of bytes written */
+typedef int (*inumbers_fmt_pf)(struct xfs_ibulk *breq,
+               const struct xfs_inumbers *igrp);
 
-int                                    /* error status */
-xfs_inumbers(
-       xfs_mount_t             *mp,    /* mount point for filesystem */
-       xfs_ino_t               *last,  /* last inode returned */
-       int                     *count, /* size of buffer/count returned */
-       void                    __user *buffer, /* buffer with inode info */
-       inumbers_fmt_pf         formatter);
+int xfs_inumbers(struct xfs_ibulk *breq, inumbers_fmt_pf formatter);
+void xfs_inumbers_to_inogrp(struct xfs_inogrp *ig1,
+               const struct xfs_inumbers *ig);
 
 #endif /* __XFS_ITABLE_H__ */
diff --git a/fs/xfs/xfs_iwalk.c b/fs/xfs/xfs_iwalk.c
new file mode 100644 (file)
index 0000000..8c7d727
--- /dev/null
@@ -0,0 +1,720 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 Oracle.  All Rights Reserved.
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_shared.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_mount.h"
+#include "xfs_inode.h"
+#include "xfs_btree.h"
+#include "xfs_ialloc.h"
+#include "xfs_ialloc_btree.h"
+#include "xfs_iwalk.h"
+#include "xfs_error.h"
+#include "xfs_trace.h"
+#include "xfs_icache.h"
+#include "xfs_health.h"
+#include "xfs_trans.h"
+#include "xfs_pwork.h"
+
+/*
+ * Walking Inodes in the Filesystem
+ * ================================
+ *
+ * This iterator function walks a subset of filesystem inodes in increasing
+ * order from @startino until there are no more inodes.  For each allocated
+ * inode it finds, it calls a walk function with the relevant inode number and
+ * a pointer to caller-provided data.  The walk function can return the usual
+ * negative error code to stop the iteration; 0 to continue the iteration; or
+ * XFS_IWALK_ABORT to stop the iteration.  This return value is returned to the
+ * caller.
+ *
+ * Internally, we allow the walk function to do anything, which means that we
+ * cannot maintain the inobt cursor or our lock on the AGI buffer.  We
+ * therefore cache the inobt records in kernel memory and only call the walk
+ * function when our memory buffer is full.  @nr_recs is the number of records
+ * that we've cached, and @sz_recs is the size of our cache.
+ *
+ * It is the responsibility of the walk function to ensure it accesses
+ * allocated inodes, as the inobt records may be stale by the time they are
+ * acted upon.
+ */
+
+struct xfs_iwalk_ag {
+       /* parallel work control data; will be null if single threaded */
+       struct xfs_pwork                pwork;
+
+       struct xfs_mount                *mp;
+       struct xfs_trans                *tp;
+
+       /* Where do we start the traversal? */
+       xfs_ino_t                       startino;
+
+       /* Array of inobt records we cache. */
+       struct xfs_inobt_rec_incore     *recs;
+
+       /* Number of entries allocated for the @recs array. */
+       unsigned int                    sz_recs;
+
+       /* Number of entries in the @recs array that are in use. */
+       unsigned int                    nr_recs;
+
+       /* Inode walk function and data pointer. */
+       xfs_iwalk_fn                    iwalk_fn;
+       xfs_inobt_walk_fn               inobt_walk_fn;
+       void                            *data;
+
+       /*
+        * Make it look like the inodes up to startino are free so that
+        * bulkstat can start its inode iteration at the correct place without
+        * needing to special case everywhere.
+        */
+       unsigned int                    trim_start:1;
+
+       /* Skip empty inobt records? */
+       unsigned int                    skip_empty:1;
+};
+
+/*
+ * Loop over all clusters in a chunk for a given incore inode allocation btree
+ * record.  Do a readahead if there are any allocated inodes in that cluster.
+ */
+STATIC void
+xfs_iwalk_ichunk_ra(
+       struct xfs_mount                *mp,
+       xfs_agnumber_t                  agno,
+       struct xfs_inobt_rec_incore     *irec)
+{
+       struct xfs_ino_geometry         *igeo = M_IGEO(mp);
+       xfs_agblock_t                   agbno;
+       struct blk_plug                 plug;
+       int                             i;      /* inode chunk index */
+
+       agbno = XFS_AGINO_TO_AGBNO(mp, irec->ir_startino);
+
+       blk_start_plug(&plug);
+       for (i = 0; i < XFS_INODES_PER_CHUNK; i += igeo->inodes_per_cluster) {
+               xfs_inofree_t   imask;
+
+               imask = xfs_inobt_maskn(i, igeo->inodes_per_cluster);
+               if (imask & ~irec->ir_free) {
+                       xfs_btree_reada_bufs(mp, agno, agbno,
+                                       igeo->blocks_per_cluster,
+                                       &xfs_inode_buf_ops);
+               }
+               agbno += igeo->blocks_per_cluster;
+       }
+       blk_finish_plug(&plug);
+}
+
+/*
+ * Set the bits in @irec's free mask that correspond to the inodes before
+ * @agino so that we skip them.  This is how we restart an inode walk that was
+ * interrupted in the middle of an inode record.
+ */
+STATIC void
+xfs_iwalk_adjust_start(
+       xfs_agino_t                     agino,  /* starting inode of chunk */
+       struct xfs_inobt_rec_incore     *irec)  /* btree record */
+{
+       int                             idx;    /* index into inode chunk */
+       int                             i;
+
+       idx = agino - irec->ir_startino;
+
+       /*
+        * We got a right chunk with some left inodes allocated at it.  Grab
+        * the chunk record.  Mark all the uninteresting inodes free because
+        * they're before our start point.
+        */
+       for (i = 0; i < idx; i++) {
+               if (XFS_INOBT_MASK(i) & ~irec->ir_free)
+                       irec->ir_freecount++;
+       }
+
+       irec->ir_free |= xfs_inobt_maskn(0, idx);
+}
+
+/* Allocate memory for a walk. */
+STATIC int
+xfs_iwalk_alloc(
+       struct xfs_iwalk_ag     *iwag)
+{
+       size_t                  size;
+
+       ASSERT(iwag->recs == NULL);
+       iwag->nr_recs = 0;
+
+       /* Allocate a prefetch buffer for inobt records. */
+       size = iwag->sz_recs * sizeof(struct xfs_inobt_rec_incore);
+       iwag->recs = kmem_alloc(size, KM_MAYFAIL);
+       if (iwag->recs == NULL)
+               return -ENOMEM;
+
+       return 0;
+}
+
+/* Free memory we allocated for a walk. */
+STATIC void
+xfs_iwalk_free(
+       struct xfs_iwalk_ag     *iwag)
+{
+       kmem_free(iwag->recs);
+       iwag->recs = NULL;
+}
+
+/* For each inuse inode in each cached inobt record, call our function. */
+STATIC int
+xfs_iwalk_ag_recs(
+       struct xfs_iwalk_ag             *iwag)
+{
+       struct xfs_mount                *mp = iwag->mp;
+       struct xfs_trans                *tp = iwag->tp;
+       xfs_ino_t                       ino;
+       unsigned int                    i, j;
+       xfs_agnumber_t                  agno;
+       int                             error;
+
+       agno = XFS_INO_TO_AGNO(mp, iwag->startino);
+       for (i = 0; i < iwag->nr_recs; i++) {
+               struct xfs_inobt_rec_incore     *irec = &iwag->recs[i];
+
+               trace_xfs_iwalk_ag_rec(mp, agno, irec);
+
+               if (xfs_pwork_want_abort(&iwag->pwork))
+                       return 0;
+
+               if (iwag->inobt_walk_fn) {
+                       error = iwag->inobt_walk_fn(mp, tp, agno, irec,
+                                       iwag->data);
+                       if (error)
+                               return error;
+               }
+
+               if (!iwag->iwalk_fn)
+                       continue;
+
+               for (j = 0; j < XFS_INODES_PER_CHUNK; j++) {
+                       if (xfs_pwork_want_abort(&iwag->pwork))
+                               return 0;
+
+                       /* Skip if this inode is free */
+                       if (XFS_INOBT_MASK(j) & irec->ir_free)
+                               continue;
+
+                       /* Otherwise call our function. */
+                       ino = XFS_AGINO_TO_INO(mp, agno, irec->ir_startino + j);
+                       error = iwag->iwalk_fn(mp, tp, ino, iwag->data);
+                       if (error)
+                               return error;
+               }
+       }
+
+       return 0;
+}
+
+/* Delete cursor and let go of AGI. */
+static inline void
+xfs_iwalk_del_inobt(
+       struct xfs_trans        *tp,
+       struct xfs_btree_cur    **curpp,
+       struct xfs_buf          **agi_bpp,
+       int                     error)
+{
+       if (*curpp) {
+               xfs_btree_del_cursor(*curpp, error);
+               *curpp = NULL;
+       }
+       if (*agi_bpp) {
+               xfs_trans_brelse(tp, *agi_bpp);
+               *agi_bpp = NULL;
+       }
+}
+
+/*
+ * Set ourselves up for walking inobt records starting from a given point in
+ * the filesystem.
+ *
+ * If caller passed in a nonzero start inode number, load the record from the
+ * inobt and make the record look like all the inodes before agino are free so
+ * that we skip them, and then move the cursor to the next inobt record.  This
+ * is how we support starting an iwalk in the middle of an inode chunk.
+ *
+ * If the caller passed in a start number of zero, move the cursor to the first
+ * inobt record.
+ *
+ * The caller is responsible for cleaning up the cursor and buffer pointer
+ * regardless of the error status.
+ */
+STATIC int
+xfs_iwalk_ag_start(
+       struct xfs_iwalk_ag     *iwag,
+       xfs_agnumber_t          agno,
+       xfs_agino_t             agino,
+       struct xfs_btree_cur    **curpp,
+       struct xfs_buf          **agi_bpp,
+       int                     *has_more)
+{
+       struct xfs_mount        *mp = iwag->mp;
+       struct xfs_trans        *tp = iwag->tp;
+       struct xfs_inobt_rec_incore *irec;
+       int                     error;
+
+       /* Set up a fresh cursor and empty the inobt cache. */
+       iwag->nr_recs = 0;
+       error = xfs_inobt_cur(mp, tp, agno, XFS_BTNUM_INO, curpp, agi_bpp);
+       if (error)
+               return error;
+
+       /* Starting at the beginning of the AG?  That's easy! */
+       if (agino == 0)
+               return xfs_inobt_lookup(*curpp, 0, XFS_LOOKUP_GE, has_more);
+
+       /*
+        * Otherwise, we have to grab the inobt record where we left off, stuff
+        * the record into our cache, and then see if there are more records.
+        * We require a lookup cache of at least two elements so that the
+        * caller doesn't have to deal with tearing down the cursor to walk the
+        * records.
+        */
+       error = xfs_inobt_lookup(*curpp, agino, XFS_LOOKUP_LE, has_more);
+       if (error)
+               return error;
+
+       /*
+        * If the LE lookup at @agino yields no records, jump ahead to the
+        * inobt cursor increment to see if there are more records to process.
+        */
+       if (!*has_more)
+               goto out_advance;
+
+       /* Get the record, should always work */
+       irec = &iwag->recs[iwag->nr_recs];
+       error = xfs_inobt_get_rec(*curpp, irec, has_more);
+       if (error)
+               return error;
+       XFS_WANT_CORRUPTED_RETURN(mp, *has_more == 1);
+
+       /*
+        * If the LE lookup yielded an inobt record before the cursor position,
+        * skip it and see if there's another one after it.
+        */
+       if (irec->ir_startino + XFS_INODES_PER_CHUNK <= agino)
+               goto out_advance;
+
+       /*
+        * If agino fell in the middle of the inode record, make it look like
+        * the inodes up to agino are free so that we don't return them again.
+        */
+       if (iwag->trim_start)
+               xfs_iwalk_adjust_start(agino, irec);
+
+       /*
+        * The prefetch calculation is supposed to give us a large enough inobt
+        * record cache that grab_ichunk can stage a partial first record and
+        * the loop body can cache a record without having to check for cache
+        * space until after it reads an inobt record.
+        */
+       iwag->nr_recs++;
+       ASSERT(iwag->nr_recs < iwag->sz_recs);
+
+out_advance:
+       return xfs_btree_increment(*curpp, 0, has_more);
+}
+
+/*
+ * The inobt record cache is full, so preserve the inobt cursor state and
+ * run callbacks on the cached inobt records.  When we're done, restore the
+ * cursor state to wherever the cursor would have been had the cache not been
+ * full (and therefore we could've just incremented the cursor) if *@has_more
+ * is true.  On exit, *@has_more will indicate whether or not the caller should
+ * try for more inode records.
+ */
+STATIC int
+xfs_iwalk_run_callbacks(
+       struct xfs_iwalk_ag             *iwag,
+       xfs_agnumber_t                  agno,
+       struct xfs_btree_cur            **curpp,
+       struct xfs_buf                  **agi_bpp,
+       int                             *has_more)
+{
+       struct xfs_mount                *mp = iwag->mp;
+       struct xfs_trans                *tp = iwag->tp;
+       struct xfs_inobt_rec_incore     *irec;
+       xfs_agino_t                     restart;
+       int                             error;
+
+       ASSERT(iwag->nr_recs > 0);
+
+       /* Delete cursor but remember the last record we cached... */
+       xfs_iwalk_del_inobt(tp, curpp, agi_bpp, 0);
+       irec = &iwag->recs[iwag->nr_recs - 1];
+       restart = irec->ir_startino + XFS_INODES_PER_CHUNK - 1;
+
+       error = xfs_iwalk_ag_recs(iwag);
+       if (error)
+               return error;
+
+       /* ...empty the cache... */
+       iwag->nr_recs = 0;
+
+       if (!has_more)
+               return 0;
+
+       /* ...and recreate the cursor just past where we left off. */
+       error = xfs_inobt_cur(mp, tp, agno, XFS_BTNUM_INO, curpp, agi_bpp);
+       if (error)
+               return error;
+
+       return xfs_inobt_lookup(*curpp, restart, XFS_LOOKUP_GE, has_more);
+}
+
+/* Walk all inodes in a single AG, from @iwag->startino to the end of the AG. */
+STATIC int
+xfs_iwalk_ag(
+       struct xfs_iwalk_ag             *iwag)
+{
+       struct xfs_mount                *mp = iwag->mp;
+       struct xfs_trans                *tp = iwag->tp;
+       struct xfs_buf                  *agi_bp = NULL;
+       struct xfs_btree_cur            *cur = NULL;
+       xfs_agnumber_t                  agno;
+       xfs_agino_t                     agino;
+       int                             has_more;
+       int                             error = 0;
+
+       /* Set up our cursor at the right place in the inode btree. */
+       agno = XFS_INO_TO_AGNO(mp, iwag->startino);
+       agino = XFS_INO_TO_AGINO(mp, iwag->startino);
+       error = xfs_iwalk_ag_start(iwag, agno, agino, &cur, &agi_bp, &has_more);
+
+       while (!error && has_more) {
+               struct xfs_inobt_rec_incore     *irec;
+
+               cond_resched();
+               if (xfs_pwork_want_abort(&iwag->pwork))
+                       goto out;
+
+               /* Fetch the inobt record. */
+               irec = &iwag->recs[iwag->nr_recs];
+               error = xfs_inobt_get_rec(cur, irec, &has_more);
+               if (error || !has_more)
+                       break;
+
+               /* No allocated inodes in this chunk; skip it. */
+               if (iwag->skip_empty && irec->ir_freecount == irec->ir_count) {
+                       error = xfs_btree_increment(cur, 0, &has_more);
+                       if (error)
+                               break;
+                       continue;
+               }
+
+               /*
+                * Start readahead for this inode chunk in anticipation of
+                * walking the inodes.
+                */
+               if (iwag->iwalk_fn)
+                       xfs_iwalk_ichunk_ra(mp, agno, irec);
+
+               /*
+                * If there's space in the buffer for more records, increment
+                * the btree cursor and grab more.
+                */
+               if (++iwag->nr_recs < iwag->sz_recs) {
+                       error = xfs_btree_increment(cur, 0, &has_more);
+                       if (error || !has_more)
+                               break;
+                       continue;
+               }
+
+               /*
+                * Otherwise, we need to save cursor state and run the callback
+                * function on the cached records.  The run_callbacks function
+                * is supposed to return a cursor pointing to the record where
+                * we would be if we had been able to increment like above.
+                */
+               ASSERT(has_more);
+               error = xfs_iwalk_run_callbacks(iwag, agno, &cur, &agi_bp,
+                               &has_more);
+       }
+
+       if (iwag->nr_recs == 0 || error)
+               goto out;
+
+       /* Walk the unprocessed records in the cache. */
+       error = xfs_iwalk_run_callbacks(iwag, agno, &cur, &agi_bp, &has_more);
+
+out:
+       xfs_iwalk_del_inobt(tp, &cur, &agi_bp, error);
+       return error;
+}
+
+/*
+ * We experimentally determined that the reduction in ioctl call overhead
+ * diminishes when userspace asks for more than 2048 inodes, so we'll cap
+ * prefetch at this point.
+ */
+#define IWALK_MAX_INODE_PREFETCH       (2048U)
+
+/*
+ * Given the number of inodes to prefetch, set the number of inobt records that
+ * we cache in memory, which controls the number of inodes we try to read
+ * ahead.  Set the maximum if @inodes == 0.
+ */
+static inline unsigned int
+xfs_iwalk_prefetch(
+       unsigned int            inodes)
+{
+       unsigned int            inobt_records;
+
+       /*
+        * If the caller didn't tell us the number of inodes they wanted,
+        * assume the maximum prefetch possible for best performance.
+        * Otherwise, cap prefetch at that maximum so that we don't start an
+        * absurd amount of prefetch.
+        */
+       if (inodes == 0)
+               inodes = IWALK_MAX_INODE_PREFETCH;
+       inodes = min(inodes, IWALK_MAX_INODE_PREFETCH);
+
+       /* Round the inode count up to a full chunk. */
+       inodes = round_up(inodes, XFS_INODES_PER_CHUNK);
+
+       /*
+        * In order to convert the number of inodes to prefetch into an
+        * estimate of the number of inobt records to cache, we require a
+        * conversion factor that reflects our expectations of the average
+        * loading factor of an inode chunk.  Based on data gathered, most
+        * (but not all) filesystems manage to keep the inode chunks totally
+        * full, so we'll underestimate slightly so that our readahead will
+        * still deliver the performance we want on aging filesystems:
+        *
+        * inobt = inodes / (INODES_PER_CHUNK * (4 / 5));
+        *
+        * The funny math is to avoid integer division.
+        */
+       inobt_records = (inodes * 5) / (4 * XFS_INODES_PER_CHUNK);
+
+       /*
+        * Allocate enough space to prefetch at least two inobt records so that
+        * we can cache both the record where the iwalk started and the next
+        * record.  This simplifies the AG inode walk loop setup code.
+        */
+       return max(inobt_records, 2U);
+}
+
+/*
+ * Walk all inodes in the filesystem starting from @startino.  The @iwalk_fn
+ * will be called for each allocated inode, being passed the inode's number and
+ * @data.  @max_prefetch controls how many inobt records' worth of inodes we
+ * try to readahead.
+ */
+int
+xfs_iwalk(
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       xfs_ino_t               startino,
+       unsigned int            flags,
+       xfs_iwalk_fn            iwalk_fn,
+       unsigned int            inode_records,
+       void                    *data)
+{
+       struct xfs_iwalk_ag     iwag = {
+               .mp             = mp,
+               .tp             = tp,
+               .iwalk_fn       = iwalk_fn,
+               .data           = data,
+               .startino       = startino,
+               .sz_recs        = xfs_iwalk_prefetch(inode_records),
+               .trim_start     = 1,
+               .skip_empty     = 1,
+               .pwork          = XFS_PWORK_SINGLE_THREADED,
+       };
+       xfs_agnumber_t          agno = XFS_INO_TO_AGNO(mp, startino);
+       int                     error;
+
+       ASSERT(agno < mp->m_sb.sb_agcount);
+       ASSERT(!(flags & ~XFS_IWALK_FLAGS_ALL));
+
+       error = xfs_iwalk_alloc(&iwag);
+       if (error)
+               return error;
+
+       for (; agno < mp->m_sb.sb_agcount; agno++) {
+               error = xfs_iwalk_ag(&iwag);
+               if (error)
+                       break;
+               iwag.startino = XFS_AGINO_TO_INO(mp, agno + 1, 0);
+               if (flags & XFS_INOBT_WALK_SAME_AG)
+                       break;
+       }
+
+       xfs_iwalk_free(&iwag);
+       return error;
+}
+
+/* Run per-thread iwalk work. */
+static int
+xfs_iwalk_ag_work(
+       struct xfs_mount        *mp,
+       struct xfs_pwork        *pwork)
+{
+       struct xfs_iwalk_ag     *iwag;
+       int                     error = 0;
+
+       iwag = container_of(pwork, struct xfs_iwalk_ag, pwork);
+       if (xfs_pwork_want_abort(pwork))
+               goto out;
+
+       error = xfs_iwalk_alloc(iwag);
+       if (error)
+               goto out;
+
+       error = xfs_iwalk_ag(iwag);
+       xfs_iwalk_free(iwag);
+out:
+       kmem_free(iwag);
+       return error;
+}
+
+/*
+ * Walk all the inodes in the filesystem using multiple threads to process each
+ * AG.
+ */
+int
+xfs_iwalk_threaded(
+       struct xfs_mount        *mp,
+       xfs_ino_t               startino,
+       unsigned int            flags,
+       xfs_iwalk_fn            iwalk_fn,
+       unsigned int            inode_records,
+       bool                    polled,
+       void                    *data)
+{
+       struct xfs_pwork_ctl    pctl;
+       xfs_agnumber_t          agno = XFS_INO_TO_AGNO(mp, startino);
+       unsigned int            nr_threads;
+       int                     error;
+
+       ASSERT(agno < mp->m_sb.sb_agcount);
+       ASSERT(!(flags & ~XFS_IWALK_FLAGS_ALL));
+
+       nr_threads = xfs_pwork_guess_datadev_parallelism(mp);
+       error = xfs_pwork_init(mp, &pctl, xfs_iwalk_ag_work, "xfs_iwalk",
+                       nr_threads);
+       if (error)
+               return error;
+
+       for (; agno < mp->m_sb.sb_agcount; agno++) {
+               struct xfs_iwalk_ag     *iwag;
+
+               if (xfs_pwork_ctl_want_abort(&pctl))
+                       break;
+
+               iwag = kmem_zalloc(sizeof(struct xfs_iwalk_ag), KM_SLEEP);
+               iwag->mp = mp;
+               iwag->iwalk_fn = iwalk_fn;
+               iwag->data = data;
+               iwag->startino = startino;
+               iwag->sz_recs = xfs_iwalk_prefetch(inode_records);
+               xfs_pwork_queue(&pctl, &iwag->pwork);
+               startino = XFS_AGINO_TO_INO(mp, agno + 1, 0);
+               if (flags & XFS_INOBT_WALK_SAME_AG)
+                       break;
+       }
+
+       if (polled)
+               xfs_pwork_poll(&pctl);
+       return xfs_pwork_destroy(&pctl);
+}
+
+/*
+ * Allow callers to cache up to a page's worth of inobt records.  This reflects
+ * the existing inumbers prefetching behavior.  Since the inobt walk does not
+ * itself do anything with the inobt records, we can set a fairly high limit
+ * here.
+ */
+#define MAX_INOBT_WALK_PREFETCH        \
+       (PAGE_SIZE / sizeof(struct xfs_inobt_rec_incore))
+
+/*
+ * Given the number of records that the user wanted, set the number of inobt
+ * records that we buffer in memory.  Set the maximum if @inobt_records == 0.
+ */
+static inline unsigned int
+xfs_inobt_walk_prefetch(
+       unsigned int            inobt_records)
+{
+       /*
+        * If the caller didn't tell us the number of inobt records they
+        * wanted, assume the maximum prefetch possible for best performance.
+        */
+       if (inobt_records == 0)
+               inobt_records = MAX_INOBT_WALK_PREFETCH;
+
+       /*
+        * Allocate enough space to prefetch at least two inobt records so that
+        * we can cache both the record where the iwalk started and the next
+        * record.  This simplifies the AG inode walk loop setup code.
+        */
+       inobt_records = max(inobt_records, 2U);
+
+       /*
+        * Cap prefetch at that maximum so that we don't use an absurd amount
+        * of memory.
+        */
+       return min_t(unsigned int, inobt_records, MAX_INOBT_WALK_PREFETCH);
+}
+
+/*
+ * Walk all inode btree records in the filesystem starting from @startino.  The
+ * @inobt_walk_fn will be called for each btree record, being passed the incore
+ * record and @data.  @max_prefetch controls how many inobt records we try to
+ * cache ahead of time.
+ */
+int
+xfs_inobt_walk(
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       xfs_ino_t               startino,
+       unsigned int            flags,
+       xfs_inobt_walk_fn       inobt_walk_fn,
+       unsigned int            inobt_records,
+       void                    *data)
+{
+       struct xfs_iwalk_ag     iwag = {
+               .mp             = mp,
+               .tp             = tp,
+               .inobt_walk_fn  = inobt_walk_fn,
+               .data           = data,
+               .startino       = startino,
+               .sz_recs        = xfs_inobt_walk_prefetch(inobt_records),
+               .pwork          = XFS_PWORK_SINGLE_THREADED,
+       };
+       xfs_agnumber_t          agno = XFS_INO_TO_AGNO(mp, startino);
+       int                     error;
+
+       ASSERT(agno < mp->m_sb.sb_agcount);
+       ASSERT(!(flags & ~XFS_INOBT_WALK_FLAGS_ALL));
+
+       error = xfs_iwalk_alloc(&iwag);
+       if (error)
+               return error;
+
+       for (; agno < mp->m_sb.sb_agcount; agno++) {
+               error = xfs_iwalk_ag(&iwag);
+               if (error)
+                       break;
+               iwag.startino = XFS_AGINO_TO_INO(mp, agno + 1, 0);
+               if (flags & XFS_INOBT_WALK_SAME_AG)
+                       break;
+       }
+
+       xfs_iwalk_free(&iwag);
+       return error;
+}
diff --git a/fs/xfs/xfs_iwalk.h b/fs/xfs/xfs_iwalk.h
new file mode 100644 (file)
index 0000000..6c960e1
--- /dev/null
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2019 Oracle.  All Rights Reserved.
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ */
+#ifndef __XFS_IWALK_H__
+#define __XFS_IWALK_H__
+
+/* Walk all inodes in the filesystem starting from @startino. */
+typedef int (*xfs_iwalk_fn)(struct xfs_mount *mp, struct xfs_trans *tp,
+                           xfs_ino_t ino, void *data);
+/* Return values for xfs_iwalk_fn. */
+#define XFS_IWALK_CONTINUE     (XFS_ITER_CONTINUE)
+#define XFS_IWALK_ABORT                (XFS_ITER_ABORT)
+
+int xfs_iwalk(struct xfs_mount *mp, struct xfs_trans *tp, xfs_ino_t startino,
+               unsigned int flags, xfs_iwalk_fn iwalk_fn,
+               unsigned int inode_records, void *data);
+int xfs_iwalk_threaded(struct xfs_mount *mp, xfs_ino_t startino,
+               unsigned int flags, xfs_iwalk_fn iwalk_fn,
+               unsigned int inode_records, bool poll, void *data);
+
+/* Only iterate inodes within the same AG as @startino. */
+#define XFS_IWALK_SAME_AG      (0x1)
+
+#define XFS_IWALK_FLAGS_ALL    (XFS_IWALK_SAME_AG)
+
+/* Walk all inode btree records in the filesystem starting from @startino. */
+typedef int (*xfs_inobt_walk_fn)(struct xfs_mount *mp, struct xfs_trans *tp,
+                                xfs_agnumber_t agno,
+                                const struct xfs_inobt_rec_incore *irec,
+                                void *data);
+/* Return value (for xfs_inobt_walk_fn) that aborts the walk immediately. */
+#define XFS_INOBT_WALK_ABORT   (XFS_IWALK_ABORT)
+
+int xfs_inobt_walk(struct xfs_mount *mp, struct xfs_trans *tp,
+               xfs_ino_t startino, unsigned int flags,
+               xfs_inobt_walk_fn inobt_walk_fn, unsigned int inobt_records,
+               void *data);
+
+/* Only iterate inobt records within the same AG as @startino. */
+#define XFS_INOBT_WALK_SAME_AG (XFS_IWALK_SAME_AG)
+
+#define XFS_INOBT_WALK_FLAGS_ALL (XFS_INOBT_WALK_SAME_AG)
+
+#endif /* __XFS_IWALK_H__ */
index edbd5a2..ca15105 100644 (file)
@@ -110,8 +110,6 @@ typedef __u32                       xfs_nlink_t;
 #define current_restore_flags_nested(sp, f)    \
                (current->flags = ((current->flags & ~(f)) | (*(sp) & (f))))
 
-#define spinlock_destroy(lock)
-
 #define NBBY           8               /* number of bits per byte */
 
 /*
@@ -221,6 +219,9 @@ static inline uint64_t howmany_64(uint64_t x, uint32_t y)
        return x;
 }
 
+int xfs_rw_bdev(struct block_device *bdev, sector_t sector, unsigned int count,
+               char *data, unsigned int op);
+
 #define ASSERT_ALWAYS(expr)    \
        (likely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__))
 
index 2466b0f..00e9f5c 100644 (file)
 #include "xfs_trans_priv.h"
 #include "xfs_log.h"
 #include "xfs_log_priv.h"
-#include "xfs_log_recover.h"
-#include "xfs_inode.h"
 #include "xfs_trace.h"
-#include "xfs_fsops.h"
-#include "xfs_cksum.h"
 #include "xfs_sysfs.h"
 #include "xfs_sb.h"
 #include "xfs_health.h"
@@ -45,21 +41,14 @@ STATIC int
 xlog_space_left(
        struct xlog             *log,
        atomic64_t              *head);
-STATIC int
-xlog_sync(
-       struct xlog             *log,
-       struct xlog_in_core     *iclog);
 STATIC void
 xlog_dealloc_log(
        struct xlog             *log);
 
 /* local state machine functions */
-STATIC void xlog_state_done_syncing(xlog_in_core_t *iclog, int);
-STATIC void
-xlog_state_do_callback(
-       struct xlog             *log,
-       int                     aborted,
-       struct xlog_in_core     *iclog);
+STATIC void xlog_state_done_syncing(
+       struct xlog_in_core     *iclog,
+       bool                    aborted);
 STATIC int
 xlog_state_get_iclog_space(
        struct xlog             *log,
@@ -107,8 +96,7 @@ STATIC void
 xlog_verify_iclog(
        struct xlog             *log,
        struct xlog_in_core     *iclog,
-       int                     count,
-       bool                    syncing);
+       int                     count);
 STATIC void
 xlog_verify_tail_lsn(
        struct xlog             *log,
@@ -117,7 +105,7 @@ xlog_verify_tail_lsn(
 #else
 #define xlog_verify_dest_ptr(a,b)
 #define xlog_verify_grant_tail(a)
-#define xlog_verify_iclog(a,b,c,d)
+#define xlog_verify_iclog(a,b,c)
 #define xlog_verify_tail_lsn(a,b,c)
 #endif
 
@@ -541,32 +529,6 @@ xfs_log_done(
        return lsn;
 }
 
-/*
- * Attaches a new iclog I/O completion callback routine during
- * transaction commit.  If the log is in error state, a non-zero
- * return code is handed back and the caller is responsible for
- * executing the callback at an appropriate time.
- */
-int
-xfs_log_notify(
-       struct xlog_in_core     *iclog,
-       xfs_log_callback_t      *cb)
-{
-       int     abortflg;
-
-       spin_lock(&iclog->ic_callback_lock);
-       abortflg = (iclog->ic_state & XLOG_STATE_IOERROR);
-       if (!abortflg) {
-               ASSERT_ALWAYS((iclog->ic_state == XLOG_STATE_ACTIVE) ||
-                             (iclog->ic_state == XLOG_STATE_WANT_SYNC));
-               cb->cb_next = NULL;
-               *(iclog->ic_callback_tail) = cb;
-               iclog->ic_callback_tail = &(cb->cb_next);
-       }
-       spin_unlock(&iclog->ic_callback_lock);
-       return abortflg;
-}
-
 int
 xfs_log_release_iclog(
        struct xfs_mount        *mp,
@@ -807,16 +769,12 @@ xfs_log_mount_finish(
  * The mount has failed. Cancel the recovery if it hasn't completed and destroy
  * the log.
  */
-int
+void
 xfs_log_mount_cancel(
        struct xfs_mount        *mp)
 {
-       int                     error;
-
-       error = xlog_recover_cancel(mp->m_log);
+       xlog_recover_cancel(mp->m_log);
        xfs_log_unmount(mp);
-
-       return error;
 }
 
 /*
@@ -932,7 +890,7 @@ xfs_log_unmount_write(xfs_mount_t *mp)
         * Or, if we are doing a forced umount (typically because of IO errors).
         */
        if (mp->m_flags & XFS_MOUNT_NORECOVERY ||
-           xfs_readonly_buftarg(log->l_mp->m_logdev_targp)) {
+           xfs_readonly_buftarg(log->l_targ)) {
                ASSERT(mp->m_flags & XFS_MOUNT_RDONLY);
                return 0;
        }
@@ -1244,53 +1202,49 @@ xlog_space_left(
 }
 
 
-/*
- * Log function which is called when an io completes.
- *
- * The log manager needs its own routine, in order to control what
- * happens with the buffer after the write completes.
- */
 static void
-xlog_iodone(xfs_buf_t *bp)
+xlog_ioend_work(
+       struct work_struct      *work)
 {
-       struct xlog_in_core     *iclog = bp->b_log_item;
-       struct xlog             *l = iclog->ic_log;
-       int                     aborted = 0;
+       struct xlog_in_core     *iclog =
+               container_of(work, struct xlog_in_core, ic_end_io_work);
+       struct xlog             *log = iclog->ic_log;
+       bool                    aborted = false;
+       int                     error;
+
+       error = blk_status_to_errno(iclog->ic_bio.bi_status);
+#ifdef DEBUG
+       /* treat writes with injected CRC errors as failed */
+       if (iclog->ic_fail_crc)
+               error = -EIO;
+#endif
 
        /*
-        * Race to shutdown the filesystem if we see an error or the iclog is in
-        * IOABORT state. The IOABORT state is only set in DEBUG mode to inject
-        * CRC errors into log recovery.
+        * Race to shutdown the filesystem if we see an error.
         */
-       if (XFS_TEST_ERROR(bp->b_error, l->l_mp, XFS_ERRTAG_IODONE_IOERR) ||
-           iclog->ic_state & XLOG_STATE_IOABORT) {
-               if (iclog->ic_state & XLOG_STATE_IOABORT)
-                       iclog->ic_state &= ~XLOG_STATE_IOABORT;
-
-               xfs_buf_ioerror_alert(bp, __func__);
-               xfs_buf_stale(bp);
-               xfs_force_shutdown(l->l_mp, SHUTDOWN_LOG_IO_ERROR);
+       if (XFS_TEST_ERROR(error, log->l_mp, XFS_ERRTAG_IODONE_IOERR)) {
+               xfs_alert(log->l_mp, "log I/O error %d", error);
+               xfs_force_shutdown(log->l_mp, SHUTDOWN_LOG_IO_ERROR);
                /*
                 * This flag will be propagated to the trans-committed
                 * callback routines to let them know that the log-commit
                 * didn't succeed.
                 */
-               aborted = XFS_LI_ABORTED;
+               aborted = true;
        } else if (iclog->ic_state & XLOG_STATE_IOERROR) {
-               aborted = XFS_LI_ABORTED;
+               aborted = true;
        }
 
-       /* log I/O is always issued ASYNC */
-       ASSERT(bp->b_flags & XBF_ASYNC);
        xlog_state_done_syncing(iclog, aborted);
+       bio_uninit(&iclog->ic_bio);
 
        /*
-        * drop the buffer lock now that we are done. Nothing references
-        * the buffer after this, so an unmount waiting on this lock can now
-        * tear it down safely. As such, it is unsafe to reference the buffer
-        * (bp) after the unlock as we could race with it being freed.
+        * Drop the lock to signal that we are done. Nothing references the
+        * iclog after this, so an unmount waiting on this lock can now tear it
+        * down safely. As such, it is unsafe to reference the iclog after the
+        * unlock as we could race with it being freed.
         */
-       xfs_buf_unlock(bp);
+       up(&iclog->ic_sema);
 }
 
 /*
@@ -1301,65 +1255,26 @@ xlog_iodone(xfs_buf_t *bp)
  * If the filesystem blocksize is too large, we may need to choose a
  * larger size since the directory code currently logs entire blocks.
  */
-
 STATIC void
 xlog_get_iclog_buffer_size(
        struct xfs_mount        *mp,
        struct xlog             *log)
 {
-       int size;
-       int xhdrs;
-
        if (mp->m_logbufs <= 0)
-               log->l_iclog_bufs = XLOG_MAX_ICLOGS;
-       else
-               log->l_iclog_bufs = mp->m_logbufs;
+               mp->m_logbufs = XLOG_MAX_ICLOGS;
+       if (mp->m_logbsize <= 0)
+               mp->m_logbsize = XLOG_BIG_RECORD_BSIZE;
+
+       log->l_iclog_bufs = mp->m_logbufs;
+       log->l_iclog_size = mp->m_logbsize;
 
        /*
-        * Buffer size passed in from mount system call.
+        * # headers = size / 32k - one header holds cycles from 32k of data.
         */
-       if (mp->m_logbsize > 0) {
-               size = log->l_iclog_size = mp->m_logbsize;
-               log->l_iclog_size_log = 0;
-               while (size != 1) {
-                       log->l_iclog_size_log++;
-                       size >>= 1;
-               }
-
-               if (xfs_sb_version_haslogv2(&mp->m_sb)) {
-                       /* # headers = size / 32k
-                        * one header holds cycles from 32k of data
-                        */
-
-                       xhdrs = mp->m_logbsize / XLOG_HEADER_CYCLE_SIZE;
-                       if (mp->m_logbsize % XLOG_HEADER_CYCLE_SIZE)
-                               xhdrs++;
-                       log->l_iclog_hsize = xhdrs << BBSHIFT;
-                       log->l_iclog_heads = xhdrs;
-               } else {
-                       ASSERT(mp->m_logbsize <= XLOG_BIG_RECORD_BSIZE);
-                       log->l_iclog_hsize = BBSIZE;
-                       log->l_iclog_heads = 1;
-               }
-               goto done;
-       }
-
-       /* All machines use 32kB buffers by default. */
-       log->l_iclog_size = XLOG_BIG_RECORD_BSIZE;
-       log->l_iclog_size_log = XLOG_BIG_RECORD_BSHIFT;
-
-       /* the default log size is 16k or 32k which is one header sector */
-       log->l_iclog_hsize = BBSIZE;
-       log->l_iclog_heads = 1;
-
-done:
-       /* are we being asked to make the sizes selected above visible? */
-       if (mp->m_logbufs == 0)
-               mp->m_logbufs = log->l_iclog_bufs;
-       if (mp->m_logbsize == 0)
-               mp->m_logbsize = log->l_iclog_size;
-}      /* xlog_get_iclog_buffer_size */
-
+       log->l_iclog_heads =
+               DIV_ROUND_UP(mp->m_logbsize, XLOG_HEADER_CYCLE_SIZE);
+       log->l_iclog_hsize = log->l_iclog_heads << BBSHIFT;
+}
 
 void
 xfs_log_work_queue(
@@ -1422,7 +1337,6 @@ xlog_alloc_log(
        xlog_rec_header_t       *head;
        xlog_in_core_t          **iclogp;
        xlog_in_core_t          *iclog, *prev_iclog=NULL;
-       xfs_buf_t               *bp;
        int                     i;
        int                     error = -ENOMEM;
        uint                    log2_size = 0;
@@ -1480,30 +1394,6 @@ xlog_alloc_log(
 
        xlog_get_iclog_buffer_size(mp, log);
 
-       /*
-        * Use a NULL block for the extra log buffer used during splits so that
-        * it will trigger errors if we ever try to do IO on it without first
-        * having set it up properly.
-        */
-       error = -ENOMEM;
-       bp = xfs_buf_alloc(mp->m_logdev_targp, XFS_BUF_DADDR_NULL,
-                          BTOBB(log->l_iclog_size), XBF_NO_IOACCT);
-       if (!bp)
-               goto out_free_log;
-
-       /*
-        * The iclogbuf buffer locks are held over IO but we are not going to do
-        * IO yet.  Hence unlock the buffer so that the log IO path can grab it
-        * when appropriately.
-        */
-       ASSERT(xfs_buf_islocked(bp));
-       xfs_buf_unlock(bp);
-
-       /* use high priority wq for log I/O completion */
-       bp->b_ioend_wq = mp->m_log_workqueue;
-       bp->b_iodone = xlog_iodone;
-       log->l_xbuf = bp;
-
        spin_lock_init(&log->l_icloglock);
        init_waitqueue_head(&log->l_flush_wait);
 
@@ -1516,29 +1406,22 @@ xlog_alloc_log(
         * xlog_in_core_t in xfs_log_priv.h for details.
         */
        ASSERT(log->l_iclog_size >= 4096);
-       for (i=0; i < log->l_iclog_bufs; i++) {
-               *iclogp = kmem_zalloc(sizeof(xlog_in_core_t), KM_MAYFAIL);
-               if (!*iclogp)
+       for (i = 0; i < log->l_iclog_bufs; i++) {
+               size_t bvec_size = howmany(log->l_iclog_size, PAGE_SIZE) *
+                               sizeof(struct bio_vec);
+
+               iclog = kmem_zalloc(sizeof(*iclog) + bvec_size, KM_MAYFAIL);
+               if (!iclog)
                        goto out_free_iclog;
 
-               iclog = *iclogp;
+               *iclogp = iclog;
                iclog->ic_prev = prev_iclog;
                prev_iclog = iclog;
 
-               bp = xfs_buf_get_uncached(mp->m_logdev_targp,
-                                         BTOBB(log->l_iclog_size),
-                                         XBF_NO_IOACCT);
-               if (!bp)
+               iclog->ic_data = kmem_alloc_large(log->l_iclog_size,
+                               KM_MAYFAIL);
+               if (!iclog->ic_data)
                        goto out_free_iclog;
-
-               ASSERT(xfs_buf_islocked(bp));
-               xfs_buf_unlock(bp);
-
-               /* use high priority wq for log I/O completion */
-               bp->b_ioend_wq = mp->m_log_workqueue;
-               bp->b_iodone = xlog_iodone;
-               iclog->ic_bp = bp;
-               iclog->ic_data = bp->b_addr;
 #ifdef DEBUG
                log->l_iclog_bak[i] = &iclog->ic_header;
 #endif
@@ -1552,36 +1435,43 @@ xlog_alloc_log(
                head->h_fmt = cpu_to_be32(XLOG_FMT);
                memcpy(&head->h_fs_uuid, &mp->m_sb.sb_uuid, sizeof(uuid_t));
 
-               iclog->ic_size = BBTOB(bp->b_length) - log->l_iclog_hsize;
+               iclog->ic_size = log->l_iclog_size - log->l_iclog_hsize;
                iclog->ic_state = XLOG_STATE_ACTIVE;
                iclog->ic_log = log;
                atomic_set(&iclog->ic_refcnt, 0);
                spin_lock_init(&iclog->ic_callback_lock);
-               iclog->ic_callback_tail = &(iclog->ic_callback);
+               INIT_LIST_HEAD(&iclog->ic_callbacks);
                iclog->ic_datap = (char *)iclog->ic_data + log->l_iclog_hsize;
 
                init_waitqueue_head(&iclog->ic_force_wait);
                init_waitqueue_head(&iclog->ic_write_wait);
+               INIT_WORK(&iclog->ic_end_io_work, xlog_ioend_work);
+               sema_init(&iclog->ic_sema, 1);
 
                iclogp = &iclog->ic_next;
        }
        *iclogp = log->l_iclog;                 /* complete ring */
        log->l_iclog->ic_prev = prev_iclog;     /* re-write 1st prev ptr */
 
+       log->l_ioend_workqueue = alloc_workqueue("xfs-log/%s",
+                       WQ_MEM_RECLAIM | WQ_FREEZABLE | WQ_HIGHPRI, 0,
+                       mp->m_fsname);
+       if (!log->l_ioend_workqueue)
+               goto out_free_iclog;
+
        error = xlog_cil_init(log);
        if (error)
-               goto out_free_iclog;
+               goto out_destroy_workqueue;
        return log;
 
+out_destroy_workqueue:
+       destroy_workqueue(log->l_ioend_workqueue);
 out_free_iclog:
        for (iclog = log->l_iclog; iclog; iclog = prev_iclog) {
                prev_iclog = iclog->ic_next;
-               if (iclog->ic_bp)
-                       xfs_buf_free(iclog->ic_bp);
+               kmem_free(iclog->ic_data);
                kmem_free(iclog);
        }
-       spinlock_destroy(&log->l_icloglock);
-       xfs_buf_free(log->l_xbuf);
 out_free_log:
        kmem_free(log);
 out:
@@ -1766,42 +1656,155 @@ xlog_cksum(
        return xfs_end_cksum(crc);
 }
 
-/*
- * The bdstrat callback function for log bufs. This gives us a central
- * place to trap bufs in case we get hit by a log I/O error and need to
- * shutdown. Actually, in practice, even when we didn't get a log error,
- * we transition the iclogs to IOERROR state *after* flushing all existing
- * iclogs to disk. This is because we don't want anymore new transactions to be
- * started or completed afterwards.
- *
- * We lock the iclogbufs here so that we can serialise against IO completion
- * during unmount. We might be processing a shutdown triggered during unmount,
- * and that can occur asynchronously to the unmount thread, and hence we need to
- * ensure that completes before tearing down the iclogbufs. Hence we need to
- * hold the buffer lock across the log IO to acheive that.
- */
-STATIC int
-xlog_bdstrat(
-       struct xfs_buf          *bp)
+static void
+xlog_bio_end_io(
+       struct bio              *bio)
 {
-       struct xlog_in_core     *iclog = bp->b_log_item;
+       struct xlog_in_core     *iclog = bio->bi_private;
 
-       xfs_buf_lock(bp);
-       if (iclog->ic_state & XLOG_STATE_IOERROR) {
-               xfs_buf_ioerror(bp, -EIO);
-               xfs_buf_stale(bp);
-               xfs_buf_ioend(bp);
+       queue_work(iclog->ic_log->l_ioend_workqueue,
+                  &iclog->ic_end_io_work);
+}
+
+static void
+xlog_map_iclog_data(
+       struct bio              *bio,
+       void                    *data,
+       size_t                  count)
+{
+       do {
+               struct page     *page = kmem_to_page(data);
+               unsigned int    off = offset_in_page(data);
+               size_t          len = min_t(size_t, count, PAGE_SIZE - off);
+
+               WARN_ON_ONCE(bio_add_page(bio, page, len, off) != len);
+
+               data += len;
+               count -= len;
+       } while (count);
+}
+
+STATIC void
+xlog_write_iclog(
+       struct xlog             *log,
+       struct xlog_in_core     *iclog,
+       uint64_t                bno,
+       unsigned int            count,
+       bool                    need_flush)
+{
+       ASSERT(bno < log->l_logBBsize);
+
+       /*
+        * We lock the iclogbufs here so that we can serialise against I/O
+        * completion during unmount.  We might be processing a shutdown
+        * triggered during unmount, and that can occur asynchronously to the
+        * unmount thread, and hence we need to ensure that completes before
+        * tearing down the iclogbufs.  Hence we need to hold the buffer lock
+        * across the log IO to archieve that.
+        */
+       down(&iclog->ic_sema);
+       if (unlikely(iclog->ic_state & XLOG_STATE_IOERROR)) {
                /*
                 * It would seem logical to return EIO here, but we rely on
                 * the log state machine to propagate I/O errors instead of
-                * doing it here. Similarly, IO completion will unlock the
-                * buffer, so we don't do it here.
+                * doing it here.  We kick of the state machine and unlock
+                * the buffer manually, the code needs to be kept in sync
+                * with the I/O completion path.
                 */
-               return 0;
+               xlog_state_done_syncing(iclog, XFS_LI_ABORTED);
+               up(&iclog->ic_sema);
+               return;
        }
 
-       xfs_buf_submit(bp);
-       return 0;
+       iclog->ic_io_size = count;
+
+       bio_init(&iclog->ic_bio, iclog->ic_bvec, howmany(count, PAGE_SIZE));
+       bio_set_dev(&iclog->ic_bio, log->l_targ->bt_bdev);
+       iclog->ic_bio.bi_iter.bi_sector = log->l_logBBstart + bno;
+       iclog->ic_bio.bi_end_io = xlog_bio_end_io;
+       iclog->ic_bio.bi_private = iclog;
+       iclog->ic_bio.bi_opf = REQ_OP_WRITE | REQ_META | REQ_SYNC | REQ_FUA;
+       if (need_flush)
+               iclog->ic_bio.bi_opf |= REQ_PREFLUSH;
+
+       xlog_map_iclog_data(&iclog->ic_bio, iclog->ic_data, iclog->ic_io_size);
+       if (is_vmalloc_addr(iclog->ic_data))
+               flush_kernel_vmap_range(iclog->ic_data, iclog->ic_io_size);
+
+       /*
+        * If this log buffer would straddle the end of the log we will have
+        * to split it up into two bios, so that we can continue at the start.
+        */
+       if (bno + BTOBB(count) > log->l_logBBsize) {
+               struct bio *split;
+
+               split = bio_split(&iclog->ic_bio, log->l_logBBsize - bno,
+                                 GFP_NOIO, &fs_bio_set);
+               bio_chain(split, &iclog->ic_bio);
+               submit_bio(split);
+
+               /* restart at logical offset zero for the remainder */
+               iclog->ic_bio.bi_iter.bi_sector = log->l_logBBstart;
+       }
+
+       submit_bio(&iclog->ic_bio);
+}
+
+/*
+ * We need to bump cycle number for the part of the iclog that is
+ * written to the start of the log. Watch out for the header magic
+ * number case, though.
+ */
+static void
+xlog_split_iclog(
+       struct xlog             *log,
+       void                    *data,
+       uint64_t                bno,
+       unsigned int            count)
+{
+       unsigned int            split_offset = BBTOB(log->l_logBBsize - bno);
+       unsigned int            i;
+
+       for (i = split_offset; i < count; i += BBSIZE) {
+               uint32_t cycle = get_unaligned_be32(data + i);
+
+               if (++cycle == XLOG_HEADER_MAGIC_NUM)
+                       cycle++;
+               put_unaligned_be32(cycle, data + i);
+       }
+}
+
+static int
+xlog_calc_iclog_size(
+       struct xlog             *log,
+       struct xlog_in_core     *iclog,
+       uint32_t                *roundoff)
+{
+       uint32_t                count_init, count;
+       bool                    use_lsunit;
+
+       use_lsunit = xfs_sb_version_haslogv2(&log->l_mp->m_sb) &&
+                       log->l_mp->m_sb.sb_logsunit > 1;
+
+       /* Add for LR header */
+       count_init = log->l_iclog_hsize + iclog->ic_offset;
+
+       /* Round out the log write size */
+       if (use_lsunit) {
+               /* we have a v2 stripe unit to use */
+               count = XLOG_LSUNITTOB(log, XLOG_BTOLSUNIT(log, count_init));
+       } else {
+               count = BBTOB(BTOBB(count_init));
+       }
+
+       ASSERT(count >= count_init);
+       *roundoff = count - count_init;
+
+       if (use_lsunit)
+               ASSERT(*roundoff < log->l_mp->m_sb.sb_logsunit);
+       else
+               ASSERT(*roundoff < BBTOB(1));
+       return count;
 }
 
 /*
@@ -1824,46 +1827,23 @@ xlog_bdstrat(
  * log will require grabbing the lock though.
  *
  * The entire log manager uses a logical block numbering scheme.  Only
- * log_sync (and then only bwrite()) know about the fact that the log may
- * not start with block zero on a given device.  The log block start offset
- * is added immediately before calling bwrite().
+ * xlog_write_iclog knows about the fact that the log may not start with
+ * block zero on a given device.
  */
-
-STATIC int
+STATIC void
 xlog_sync(
        struct xlog             *log,
        struct xlog_in_core     *iclog)
 {
-       xfs_buf_t       *bp;
-       int             i;
-       uint            count;          /* byte count of bwrite */
-       uint            count_init;     /* initial count before roundup */
-       int             roundoff;       /* roundoff to BB or stripe */
-       int             split = 0;      /* split write into two regions */
-       int             error;
-       int             v2 = xfs_sb_version_haslogv2(&log->l_mp->m_sb);
-       int             size;
+       unsigned int            count;          /* byte count of bwrite */
+       unsigned int            roundoff;       /* roundoff to BB or stripe */
+       uint64_t                bno;
+       unsigned int            size;
+       bool                    need_flush = true, split = false;
 
-       XFS_STATS_INC(log->l_mp, xs_log_writes);
        ASSERT(atomic_read(&iclog->ic_refcnt) == 0);
 
-       /* Add for LR header */
-       count_init = log->l_iclog_hsize + iclog->ic_offset;
-
-       /* Round out the log write size */
-       if (v2 && log->l_mp->m_sb.sb_logsunit > 1) {
-               /* we have a v2 stripe unit to use */
-               count = XLOG_LSUNITTOB(log, XLOG_BTOLSUNIT(log, count_init));
-       } else {
-               count = BBTOB(BTOBB(count_init));
-       }
-       roundoff = count - count_init;
-       ASSERT(roundoff >= 0);
-       ASSERT((v2 && log->l_mp->m_sb.sb_logsunit > 1 && 
-                roundoff < log->l_mp->m_sb.sb_logsunit)
-               || 
-               (log->l_mp->m_sb.sb_logsunit <= 1 && 
-                roundoff < BBTOB(1)));
+       count = xlog_calc_iclog_size(log, iclog, &roundoff);
 
        /* move grant heads by roundoff in sync */
        xlog_grant_add_space(log, &log->l_reserve_head.grant, roundoff);
@@ -1874,41 +1854,19 @@ xlog_sync(
 
        /* real byte length */
        size = iclog->ic_offset;
-       if (v2)
+       if (xfs_sb_version_haslogv2(&log->l_mp->m_sb))
                size += roundoff;
        iclog->ic_header.h_len = cpu_to_be32(size);
 
-       bp = iclog->ic_bp;
-       XFS_BUF_SET_ADDR(bp, BLOCK_LSN(be64_to_cpu(iclog->ic_header.h_lsn)));
-
+       XFS_STATS_INC(log->l_mp, xs_log_writes);
        XFS_STATS_ADD(log->l_mp, xs_log_blocks, BTOBB(count));
 
-       /* Do we need to split this write into 2 parts? */
-       if (XFS_BUF_ADDR(bp) + BTOBB(count) > log->l_logBBsize) {
-               char            *dptr;
-
-               split = count - (BBTOB(log->l_logBBsize - XFS_BUF_ADDR(bp)));
-               count = BBTOB(log->l_logBBsize - XFS_BUF_ADDR(bp));
-               iclog->ic_bwritecnt = 2;
+       bno = BLOCK_LSN(be64_to_cpu(iclog->ic_header.h_lsn));
 
-               /*
-                * Bump the cycle numbers at the start of each block in the
-                * part of the iclog that ends up in the buffer that gets
-                * written to the start of the log.
-                *
-                * Watch out for the header magic number case, though.
-                */
-               dptr = (char *)&iclog->ic_header + count;
-               for (i = 0; i < split; i += BBSIZE) {
-                       uint32_t cycle = be32_to_cpu(*(__be32 *)dptr);
-                       if (++cycle == XLOG_HEADER_MAGIC_NUM)
-                               cycle++;
-                       *(__be32 *)dptr = cpu_to_be32(cycle);
-
-                       dptr += BBSIZE;
-               }
-       } else {
-               iclog->ic_bwritecnt = 1;
+       /* Do we need to split this write into 2 parts? */
+       if (bno + BTOBB(count) > log->l_logBBsize) {
+               xlog_split_iclog(log, &iclog->ic_header, bno, count);
+               split = true;
        }
 
        /* calculcate the checksum */
@@ -1921,18 +1879,15 @@ xlog_sync(
         * write on I/O completion and shutdown the fs. The subsequent mount
         * detects the bad CRC and attempts to recover.
         */
+#ifdef DEBUG
        if (XFS_TEST_ERROR(false, log->l_mp, XFS_ERRTAG_LOG_BAD_CRC)) {
                iclog->ic_header.h_crc &= cpu_to_le32(0xAAAAAAAA);
-               iclog->ic_state |= XLOG_STATE_IOABORT;
+               iclog->ic_fail_crc = true;
                xfs_warn(log->l_mp,
        "Intentionally corrupted log record at LSN 0x%llx. Shutdown imminent.",
                         be64_to_cpu(iclog->ic_header.h_lsn));
        }
-
-       bp->b_io_length = BTOBB(count);
-       bp->b_log_item = iclog;
-       bp->b_flags &= ~XBF_FLUSH;
-       bp->b_flags |= (XBF_ASYNC | XBF_SYNCIO | XBF_WRITE | XBF_FUA);
+#endif
 
        /*
         * Flush the data device before flushing the log to make sure all meta
@@ -1942,50 +1897,14 @@ xlog_sync(
         * synchronously here; for an internal log we can simply use the block
         * layer state machine for preflushes.
         */
-       if (log->l_mp->m_logdev_targp != log->l_mp->m_ddev_targp)
+       if (log->l_targ != log->l_mp->m_ddev_targp || split) {
                xfs_blkdev_issue_flush(log->l_mp->m_ddev_targp);
-       else
-               bp->b_flags |= XBF_FLUSH;
-
-       ASSERT(XFS_BUF_ADDR(bp) <= log->l_logBBsize-1);
-       ASSERT(XFS_BUF_ADDR(bp) + BTOBB(count) <= log->l_logBBsize);
-
-       xlog_verify_iclog(log, iclog, count, true);
-
-       /* account for log which doesn't start at block #0 */
-       XFS_BUF_SET_ADDR(bp, XFS_BUF_ADDR(bp) + log->l_logBBstart);
-
-       /*
-        * Don't call xfs_bwrite here. We do log-syncs even when the filesystem
-        * is shutting down.
-        */
-       error = xlog_bdstrat(bp);
-       if (error) {
-               xfs_buf_ioerror_alert(bp, "xlog_sync");
-               return error;
+               need_flush = false;
        }
-       if (split) {
-               bp = iclog->ic_log->l_xbuf;
-               XFS_BUF_SET_ADDR(bp, 0);             /* logical 0 */
-               xfs_buf_associate_memory(bp,
-                               (char *)&iclog->ic_header + count, split);
-               bp->b_log_item = iclog;
-               bp->b_flags &= ~XBF_FLUSH;
-               bp->b_flags |= (XBF_ASYNC | XBF_SYNCIO | XBF_WRITE | XBF_FUA);
-
-               ASSERT(XFS_BUF_ADDR(bp) <= log->l_logBBsize-1);
-               ASSERT(XFS_BUF_ADDR(bp) + BTOBB(count) <= log->l_logBBsize);
-
-               /* account for internal log which doesn't start at block #0 */
-               XFS_BUF_SET_ADDR(bp, XFS_BUF_ADDR(bp) + log->l_logBBstart);
-               error = xlog_bdstrat(bp);
-               if (error) {
-                       xfs_buf_ioerror_alert(bp, "xlog_sync (split)");
-                       return error;
-               }
-       }
-       return 0;
-}      /* xlog_sync */
+
+       xlog_verify_iclog(log, iclog, count);
+       xlog_write_iclog(log, iclog, bno, count, need_flush);
+}
 
 /*
  * Deallocate a log structure
@@ -2005,31 +1924,21 @@ xlog_dealloc_log(
         */
        iclog = log->l_iclog;
        for (i = 0; i < log->l_iclog_bufs; i++) {
-               xfs_buf_lock(iclog->ic_bp);
-               xfs_buf_unlock(iclog->ic_bp);
+               down(&iclog->ic_sema);
+               up(&iclog->ic_sema);
                iclog = iclog->ic_next;
        }
 
-       /*
-        * Always need to ensure that the extra buffer does not point to memory
-        * owned by another log buffer before we free it. Also, cycle the lock
-        * first to ensure we've completed IO on it.
-        */
-       xfs_buf_lock(log->l_xbuf);
-       xfs_buf_unlock(log->l_xbuf);
-       xfs_buf_set_empty(log->l_xbuf, BTOBB(log->l_iclog_size));
-       xfs_buf_free(log->l_xbuf);
-
        iclog = log->l_iclog;
        for (i = 0; i < log->l_iclog_bufs; i++) {
-               xfs_buf_free(iclog->ic_bp);
                next_iclog = iclog->ic_next;
+               kmem_free(iclog->ic_data);
                kmem_free(iclog);
                iclog = next_iclog;
        }
-       spinlock_destroy(&log->l_icloglock);
 
        log->l_mp->m_log = NULL;
+       destroy_workqueue(log->l_ioend_workqueue);
        kmem_free(log);
 }      /* xlog_dealloc_log */
 
@@ -2610,7 +2519,7 @@ xlog_state_clean_log(
                if (iclog->ic_state == XLOG_STATE_DIRTY) {
                        iclog->ic_state = XLOG_STATE_ACTIVE;
                        iclog->ic_offset       = 0;
-                       ASSERT(iclog->ic_callback == NULL);
+                       ASSERT(list_empty_careful(&iclog->ic_callbacks));
                        /*
                         * If the number of ops in this iclog indicate it just
                         * contains the dummy transaction, we can
@@ -2680,37 +2589,32 @@ xlog_state_clean_log(
 
 STATIC xfs_lsn_t
 xlog_get_lowest_lsn(
-       struct xlog     *log)
+       struct xlog             *log)
 {
-       xlog_in_core_t  *lsn_log;
-       xfs_lsn_t       lowest_lsn, lsn;
+       struct xlog_in_core     *iclog = log->l_iclog;
+       xfs_lsn_t               lowest_lsn = 0, lsn;
 
-       lsn_log = log->l_iclog;
-       lowest_lsn = 0;
        do {
-           if (!(lsn_log->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_DIRTY))) {
-               lsn = be64_to_cpu(lsn_log->ic_header.h_lsn);
-               if ((lsn && !lowest_lsn) ||
-                   (XFS_LSN_CMP(lsn, lowest_lsn) < 0)) {
+               if (iclog->ic_state & (XLOG_STATE_ACTIVE | XLOG_STATE_DIRTY))
+                       continue;
+
+               lsn = be64_to_cpu(iclog->ic_header.h_lsn);
+               if ((lsn && !lowest_lsn) || XFS_LSN_CMP(lsn, lowest_lsn) < 0)
                        lowest_lsn = lsn;
-               }
-           }
-           lsn_log = lsn_log->ic_next;
-       } while (lsn_log != log->l_iclog);
+       } while ((iclog = iclog->ic_next) != log->l_iclog);
+
        return lowest_lsn;
 }
 
-
 STATIC void
 xlog_state_do_callback(
        struct xlog             *log,
-       int                     aborted,
+       bool                    aborted,
        struct xlog_in_core     *ciclog)
 {
        xlog_in_core_t     *iclog;
        xlog_in_core_t     *first_iclog;        /* used to know when we've
                                                 * processed all iclogs once */
-       xfs_log_callback_t *cb, *cb_next;
        int                flushcnt = 0;
        xfs_lsn_t          lowest_lsn;
        int                ioerrors;    /* counter: iclogs with errors */
@@ -2821,7 +2725,7 @@ xlog_state_do_callback(
                                 */
                                ASSERT(XFS_LSN_CMP(atomic64_read(&log->l_last_sync_lsn),
                                        be64_to_cpu(iclog->ic_header.h_lsn)) <= 0);
-                               if (iclog->ic_callback)
+                               if (!list_empty_careful(&iclog->ic_callbacks))
                                        atomic64_set(&log->l_last_sync_lsn,
                                                be64_to_cpu(iclog->ic_header.h_lsn));
 
@@ -2838,26 +2742,20 @@ xlog_state_do_callback(
                         * callbacks being added.
                         */
                        spin_lock(&iclog->ic_callback_lock);
-                       cb = iclog->ic_callback;
-                       while (cb) {
-                               iclog->ic_callback_tail = &(iclog->ic_callback);
-                               iclog->ic_callback = NULL;
-                               spin_unlock(&iclog->ic_callback_lock);
+                       while (!list_empty(&iclog->ic_callbacks)) {
+                               LIST_HEAD(tmp);
 
-                               /* perform callbacks in the order given */
-                               for (; cb; cb = cb_next) {
-                                       cb_next = cb->cb_next;
-                                       cb->cb_func(cb->cb_arg, aborted);
-                               }
+                               list_splice_init(&iclog->ic_callbacks, &tmp);
+
+                               spin_unlock(&iclog->ic_callback_lock);
+                               xlog_cil_process_committed(&tmp, aborted);
                                spin_lock(&iclog->ic_callback_lock);
-                               cb = iclog->ic_callback;
                        }
 
                        loopdidcallbacks++;
                        funcdidcallbacks++;
 
                        spin_lock(&log->l_icloglock);
-                       ASSERT(iclog->ic_callback == NULL);
                        spin_unlock(&iclog->ic_callback_lock);
                        if (!(iclog->ic_state & XLOG_STATE_IOERROR))
                                iclog->ic_state = XLOG_STATE_DIRTY;
@@ -2943,18 +2841,16 @@ xlog_state_do_callback(
  */
 STATIC void
 xlog_state_done_syncing(
-       xlog_in_core_t  *iclog,
-       int             aborted)
+       struct xlog_in_core     *iclog,
+       bool                    aborted)
 {
-       struct xlog        *log = iclog->ic_log;
+       struct xlog             *log = iclog->ic_log;
 
        spin_lock(&log->l_icloglock);
 
        ASSERT(iclog->ic_state == XLOG_STATE_SYNCING ||
               iclog->ic_state == XLOG_STATE_IOERROR);
        ASSERT(atomic_read(&iclog->ic_refcnt) == 0);
-       ASSERT(iclog->ic_bwritecnt == 1 || iclog->ic_bwritecnt == 2);
-
 
        /*
         * If we got an error, either on the first buffer, or in the case of
@@ -2962,13 +2858,8 @@ xlog_state_done_syncing(
         * and none should ever be attempted to be written to disk
         * again.
         */
-       if (iclog->ic_state != XLOG_STATE_IOERROR) {
-               if (--iclog->ic_bwritecnt == 1) {
-                       spin_unlock(&log->l_icloglock);
-                       return;
-               }
+       if (iclog->ic_state != XLOG_STATE_IOERROR)
                iclog->ic_state = XLOG_STATE_DONE_SYNC;
-       }
 
        /*
         * Someone could be sleeping prior to writing out the next
@@ -3237,7 +3128,7 @@ xlog_state_release_iclog(
         * flags after this point.
         */
        if (sync)
-               return xlog_sync(log, iclog);
+               xlog_sync(log, iclog);
        return 0;
 }      /* xlog_state_release_iclog */
 
@@ -3828,8 +3719,7 @@ STATIC void
 xlog_verify_iclog(
        struct xlog             *log,
        struct xlog_in_core     *iclog,
-       int                     count,
-       bool                    syncing)
+       int                     count)
 {
        xlog_op_header_t        *ophead;
        xlog_in_core_t          *icptr;
@@ -3873,7 +3763,7 @@ xlog_verify_iclog(
                /* clientid is only 1 byte */
                p = &ophead->oh_clientid;
                field_offset = p - base_ptr;
-               if (!syncing || (field_offset & 0x1ff)) {
+               if (field_offset & 0x1ff) {
                        clientid = ophead->oh_clientid;
                } else {
                        idx = BTOBBT((char *)&ophead->oh_clientid - iclog->ic_datap);
@@ -3896,7 +3786,7 @@ xlog_verify_iclog(
                /* check length */
                p = &ophead->oh_len;
                field_offset = p - base_ptr;
-               if (!syncing || (field_offset & 0x1ff)) {
+               if (field_offset & 0x1ff) {
                        op_len = be32_to_cpu(ophead->oh_len);
                } else {
                        idx = BTOBBT((uintptr_t)&ophead->oh_len -
@@ -4033,7 +3923,7 @@ xfs_log_force_umount(
         * avoid races.
         */
        wake_up_all(&log->l_cilp->xc_commit_wait);
-       xlog_state_do_callback(log, XFS_LI_ABORTED, NULL);
+       xlog_state_do_callback(log, true, NULL);
 
 #ifdef XFSERRORDEBUG
        {
index 73a64bf..84e0680 100644 (file)
@@ -6,6 +6,8 @@
 #ifndef        __XFS_LOG_H__
 #define __XFS_LOG_H__
 
+struct xfs_cil_ctx;
+
 struct xfs_log_vec {
        struct xfs_log_vec      *lv_next;       /* next lv in build list */
        int                     lv_niovecs;     /* number of iovecs in lv */
@@ -71,16 +73,6 @@ xlog_copy_iovec(struct xfs_log_vec *lv, struct xfs_log_iovec **vecp,
        return buf;
 }
 
-/*
- * Structure used to pass callback function and the function's argument
- * to the log manager.
- */
-typedef struct xfs_log_callback {
-       struct xfs_log_callback *cb_next;
-       void                    (*cb_func)(void *, int);
-       void                    *cb_arg;
-} xfs_log_callback_t;
-
 /*
  * By comparing each component, we don't have to worry about extra
  * endian issues in treating two 32 bit numbers as one 64 bit number
@@ -125,12 +117,10 @@ int         xfs_log_mount(struct xfs_mount        *mp,
                        xfs_daddr_t             start_block,
                        int                     num_bblocks);
 int      xfs_log_mount_finish(struct xfs_mount *mp);
-int    xfs_log_mount_cancel(struct xfs_mount *);
+void   xfs_log_mount_cancel(struct xfs_mount *);
 xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp);
 xfs_lsn_t xlog_assign_tail_lsn_locked(struct xfs_mount *mp);
 void     xfs_log_space_wake(struct xfs_mount *mp);
-int      xfs_log_notify(struct xlog_in_core    *iclog,
-                        struct xfs_log_callback *callback_entry);
 int      xfs_log_release_iclog(struct xfs_mount *mp,
                         struct xlog_in_core     *iclog);
 int      xfs_log_reserve(struct xfs_mount *mp,
@@ -148,6 +138,7 @@ void          xfs_log_ticket_put(struct xlog_ticket *ticket);
 
 void   xfs_log_commit_cil(struct xfs_mount *mp, struct xfs_trans *tp,
                                xfs_lsn_t *commit_lsn, bool regrant);
+void   xlog_cil_process_committed(struct list_head *list, bool aborted);
 bool   xfs_log_item_in_current_chkpt(struct xfs_log_item *lip);
 
 void   xfs_log_work_queue(struct xfs_mount *mp);
index 5e59594..fa5602d 100644 (file)
 #include "xfs_shared.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_error.h"
-#include "xfs_alloc.h"
 #include "xfs_extent_busy.h"
-#include "xfs_discard.h"
 #include "xfs_trans.h"
 #include "xfs_trans_priv.h"
 #include "xfs_log.h"
@@ -246,7 +243,8 @@ xfs_cil_prepare_item(
         * shadow buffer, so update the the pointer to it appropriately.
         */
        if (!old_lv) {
-               lv->lv_item->li_ops->iop_pin(lv->lv_item);
+               if (lv->lv_item->li_ops->iop_pin)
+                       lv->lv_item->li_ops->iop_pin(lv->lv_item);
                lv->lv_item->li_lv_shadow = NULL;
        } else if (old_lv != lv) {
                ASSERT(lv->lv_buf_len != XFS_LOG_VEC_ORDERED);
@@ -576,10 +574,9 @@ xlog_discard_busy_extents(
  */
 static void
 xlog_cil_committed(
-       void    *args,
-       int     abort)
+       struct xfs_cil_ctx      *ctx,
+       bool                    abort)
 {
-       struct xfs_cil_ctx      *ctx = args;
        struct xfs_mount        *mp = ctx->cil->xc_log->l_mp;
 
        /*
@@ -614,6 +611,20 @@ xlog_cil_committed(
                kmem_free(ctx);
 }
 
+void
+xlog_cil_process_committed(
+       struct list_head        *list,
+       bool                    aborted)
+{
+       struct xfs_cil_ctx      *ctx;
+
+       while ((ctx = list_first_entry_or_null(list,
+                       struct xfs_cil_ctx, iclog_entry))) {
+               list_del(&ctx->iclog_entry);
+               xlog_cil_committed(ctx, aborted);
+       }
+}
+
 /*
  * Push the Committed Item List to the log. If @push_seq flag is zero, then it
  * is a background flush and so we can chose to ignore it. Otherwise, if the
@@ -835,12 +846,15 @@ restart:
        if (commit_lsn == -1)
                goto out_abort;
 
-       /* attach all the transactions w/ busy extents to iclog */
-       ctx->log_cb.cb_func = xlog_cil_committed;
-       ctx->log_cb.cb_arg = ctx;
-       error = xfs_log_notify(commit_iclog, &ctx->log_cb);
-       if (error)
+       spin_lock(&commit_iclog->ic_callback_lock);
+       if (commit_iclog->ic_state & XLOG_STATE_IOERROR) {
+               spin_unlock(&commit_iclog->ic_callback_lock);
                goto out_abort;
+       }
+       ASSERT_ALWAYS(commit_iclog->ic_state == XLOG_STATE_ACTIVE ||
+                     commit_iclog->ic_state == XLOG_STATE_WANT_SYNC);
+       list_add_tail(&ctx->iclog_entry, &commit_iclog->ic_callbacks);
+       spin_unlock(&commit_iclog->ic_callback_lock);
 
        /*
         * now the checkpoint commit is complete and we've attached the
@@ -864,7 +878,7 @@ out_skip:
 out_abort_free_ticket:
        xfs_log_ticket_put(tic);
 out_abort:
-       xlog_cil_committed(ctx, XFS_LI_ABORTED);
+       xlog_cil_committed(ctx, true);
        return -EIO;
 }
 
@@ -984,6 +998,7 @@ xfs_log_commit_cil(
 {
        struct xlog             *log = mp->m_log;
        struct xfs_cil          *cil = log->l_cilp;
+       struct xfs_log_item     *lip, *next;
        xfs_lsn_t               xc_commit_lsn;
 
        /*
@@ -1008,7 +1023,7 @@ xfs_log_commit_cil(
 
        /*
         * Once all the items of the transaction have been copied to the CIL,
-        * the items can be unlocked and freed.
+        * the items can be unlocked and possibly freed.
         *
         * This needs to be done before we drop the CIL context lock because we
         * have to update state in the log items and unlock them before they go
@@ -1017,8 +1032,12 @@ xfs_log_commit_cil(
         * the log items. This affects (at least) processing of stale buffers,
         * inodes and EFIs.
         */
-       xfs_trans_free_items(tp, xc_commit_lsn, false);
-
+       trace_xfs_trans_commit_items(tp, _RET_IP_);
+       list_for_each_entry_safe(lip, next, &tp->t_items, li_trans) {
+               xfs_trans_del_item(lip);
+               if (lip->li_ops->iop_committing)
+                       lip->li_ops->iop_committing(lip, xc_commit_lsn);
+       }
        xlog_cil_push_background(log);
 
        up_read(&cil->xc_ctx_lock);
index b5f82cb..b880c23 100644 (file)
@@ -10,7 +10,6 @@ struct xfs_buf;
 struct xlog;
 struct xlog_ticket;
 struct xfs_mount;
-struct xfs_log_callback;
 
 /*
  * Flags for log structure
@@ -50,7 +49,6 @@ static inline uint xlog_get_client_id(__be32 i)
 #define XLOG_STATE_CALLBACK  0x0020 /* Callback functions now */
 #define XLOG_STATE_DIRTY     0x0040 /* Dirty IC log, not ready for ACTIVE status*/
 #define XLOG_STATE_IOERROR   0x0080 /* IO error happened in sync'ing log */
-#define XLOG_STATE_IOABORT   0x0100 /* force abort on I/O completion (debug) */
 #define XLOG_STATE_ALL      0x7FFF /* All possible valid flags */
 #define XLOG_STATE_NOTUSED   0x8000 /* This IC log not being used */
 
@@ -179,11 +177,10 @@ typedef struct xlog_ticket {
  *     the iclog.
  * - ic_forcewait is used to implement synchronous forcing of the iclog to disk.
  * - ic_next is the pointer to the next iclog in the ring.
- * - ic_bp is a pointer to the buffer used to write this incore log to disk.
  * - ic_log is a pointer back to the global log structure.
- * - ic_callback is a linked list of callback function/argument pairs to be
- *     called after an iclog finishes writing.
- * - ic_size is the full size of the header plus data.
+ * - ic_size is the full size of the log buffer, minus the cycle headers.
+ * - ic_io_size is the size of the currently pending log buffer write, which
+ *     might be smaller than ic_size
  * - ic_offset is the current number of bytes written to in this iclog.
  * - ic_refcnt is bumped when someone is writing to the log.
  * - ic_state is the state of the iclog.
@@ -193,7 +190,7 @@ typedef struct xlog_ticket {
  * structure cacheline aligned. The following fields can be contended on
  * by independent processes:
  *
- *     - ic_callback_*
+ *     - ic_callbacks
  *     - ic_refcnt
  *     - fields protected by the global l_icloglock
  *
@@ -206,23 +203,28 @@ typedef struct xlog_in_core {
        wait_queue_head_t       ic_write_wait;
        struct xlog_in_core     *ic_next;
        struct xlog_in_core     *ic_prev;
-       struct xfs_buf          *ic_bp;
        struct xlog             *ic_log;
-       int                     ic_size;
-       int                     ic_offset;
-       int                     ic_bwritecnt;
+       u32                     ic_size;
+       u32                     ic_io_size;
+       u32                     ic_offset;
        unsigned short          ic_state;
        char                    *ic_datap;      /* pointer to iclog data */
 
        /* Callback structures need their own cacheline */
        spinlock_t              ic_callback_lock ____cacheline_aligned_in_smp;
-       struct xfs_log_callback *ic_callback;
-       struct xfs_log_callback **ic_callback_tail;
+       struct list_head        ic_callbacks;
 
        /* reference counts need their own cacheline */
        atomic_t                ic_refcnt ____cacheline_aligned_in_smp;
        xlog_in_core_2_t        *ic_data;
 #define ic_header      ic_data->hic_header
+#ifdef DEBUG
+       bool                    ic_fail_crc : 1;
+#endif
+       struct semaphore        ic_sema;
+       struct work_struct      ic_end_io_work;
+       struct bio              ic_bio;
+       struct bio_vec          ic_bvec[];
 } xlog_in_core_t;
 
 /*
@@ -243,7 +245,7 @@ struct xfs_cil_ctx {
        int                     space_used;     /* aggregate size of regions */
        struct list_head        busy_extents;   /* busy extents in chkpt */
        struct xfs_log_vec      *lv_chain;      /* logvecs being pushed */
-       struct xfs_log_callback log_cb;         /* completion callback hook. */
+       struct list_head        iclog_entry;
        struct list_head        committing;     /* ctx committing list */
        struct work_struct      discard_endio_work;
 };
@@ -350,9 +352,8 @@ struct xlog {
        struct xfs_mount        *l_mp;          /* mount point */
        struct xfs_ail          *l_ailp;        /* AIL log is working with */
        struct xfs_cil          *l_cilp;        /* CIL log is working with */
-       struct xfs_buf          *l_xbuf;        /* extra buffer for log
-                                                * wrapping */
        struct xfs_buftarg      *l_targ;        /* buftarg of log */
+       struct workqueue_struct *l_ioend_workqueue; /* for I/O completions */
        struct delayed_work     l_work;         /* background flush work */
        uint                    l_flags;
        uint                    l_quotaoffs_flag; /* XFS_DQ_*, for QUOTAOFFs */
@@ -361,7 +362,6 @@ struct xlog {
        int                     l_iclog_heads;  /* # of iclog header sectors */
        uint                    l_sectBBsize;   /* sector size in BBs (2^n) */
        int                     l_iclog_size;   /* size of log in bytes */
-       int                     l_iclog_size_log; /* log power size of log */
        int                     l_iclog_bufs;   /* number of iclog buffers */
        xfs_daddr_t             l_logBBstart;   /* start block of log */
        int                     l_logsize;      /* size of log in bytes */
@@ -418,7 +418,7 @@ xlog_recover(
 extern int
 xlog_recover_finish(
        struct xlog             *log);
-extern int
+extern void
 xlog_recover_cancel(struct xlog *);
 
 extern __le32   xlog_cksum(struct xlog *log, struct xlog_rec_header *rhead,
index 9329f5a..13d1d3e 100644 (file)
@@ -13,8 +13,6 @@
 #include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_defer.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
 #include "xfs_log.h"
@@ -26,7 +24,6 @@
 #include "xfs_alloc.h"
 #include "xfs_ialloc.h"
 #include "xfs_quota.h"
-#include "xfs_cksum.h"
 #include "xfs_trace.h"
 #include "xfs_icache.h"
 #include "xfs_bmap_btree.h"
@@ -79,7 +76,7 @@ struct xfs_buf_cancel {
  * are valid, false otherwise.
  */
 static inline bool
-xlog_verify_bp(
+xlog_verify_bno(
        struct xlog     *log,
        xfs_daddr_t     blk_no,
        int             bbcount)
@@ -92,22 +89,19 @@ xlog_verify_bp(
 }
 
 /*
- * Allocate a buffer to hold log data.  The buffer needs to be able
- * to map to a range of nbblks basic blocks at any valid (basic
- * block) offset within the log.
+ * Allocate a buffer to hold log data.  The buffer needs to be able to map to
+ * a range of nbblks basic blocks at any valid offset within the log.
  */
-STATIC xfs_buf_t *
-xlog_get_bp(
+static char *
+xlog_alloc_buffer(
        struct xlog     *log,
        int             nbblks)
 {
-       struct xfs_buf  *bp;
-
        /*
         * Pass log block 0 since we don't have an addr yet, buffer will be
         * verified on read.
         */
-       if (!xlog_verify_bp(log, 0, nbblks)) {
+       if (!xlog_verify_bno(log, 0, nbblks)) {
                xfs_warn(log->l_mp, "Invalid block length (0x%x) for buffer",
                        nbblks);
                XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp);
@@ -115,69 +109,48 @@ xlog_get_bp(
        }
 
        /*
-        * We do log I/O in units of log sectors (a power-of-2
-        * multiple of the basic block size), so we round up the
-        * requested size to accommodate the basic blocks required
-        * for complete log sectors.
+        * We do log I/O in units of log sectors (a power-of-2 multiple of the
+        * basic block size), so we round up the requested size to accommodate
+        * the basic blocks required for complete log sectors.
         *
-        * In addition, the buffer may be used for a non-sector-
-        * aligned block offset, in which case an I/O of the
-        * requested size could extend beyond the end of the
-        * buffer.  If the requested size is only 1 basic block it
-        * will never straddle a sector boundary, so this won't be
-        * an issue.  Nor will this be a problem if the log I/O is
-        * done in basic blocks (sector size 1).  But otherwise we
-        * extend the buffer by one extra log sector to ensure
-        * there's space to accommodate this possibility.
+        * In addition, the buffer may be used for a non-sector-aligned block
+        * offset, in which case an I/O of the requested size could extend
+        * beyond the end of the buffer.  If the requested size is only 1 basic
+        * block it will never straddle a sector boundary, so this won't be an
+        * issue.  Nor will this be a problem if the log I/O is done in basic
+        * blocks (sector size 1).  But otherwise we extend the buffer by one
+        * extra log sector to ensure there's space to accommodate this
+        * possibility.
         */
        if (nbblks > 1 && log->l_sectBBsize > 1)
                nbblks += log->l_sectBBsize;
        nbblks = round_up(nbblks, log->l_sectBBsize);
-
-       bp = xfs_buf_get_uncached(log->l_mp->m_logdev_targp, nbblks, 0);
-       if (bp)
-               xfs_buf_unlock(bp);
-       return bp;
-}
-
-STATIC void
-xlog_put_bp(
-       xfs_buf_t       *bp)
-{
-       xfs_buf_free(bp);
+       return kmem_alloc_large(BBTOB(nbblks), KM_MAYFAIL);
 }
 
 /*
  * Return the address of the start of the given block number's data
  * in a log buffer.  The buffer covers a log sector-aligned region.
  */
-STATIC char *
+static inline unsigned int
 xlog_align(
        struct xlog     *log,
-       xfs_daddr_t     blk_no,
-       int             nbblks,
-       struct xfs_buf  *bp)
+       xfs_daddr_t     blk_no)
 {
-       xfs_daddr_t     offset = blk_no & ((xfs_daddr_t)log->l_sectBBsize - 1);
-
-       ASSERT(offset + nbblks <= bp->b_length);
-       return bp->b_addr + BBTOB(offset);
+       return BBTOB(blk_no & ((xfs_daddr_t)log->l_sectBBsize - 1));
 }
 
-
-/*
- * nbblks should be uint, but oh well.  Just want to catch that 32-bit length.
- */
-STATIC int
-xlog_bread_noalign(
-       struct xlog     *log,
-       xfs_daddr_t     blk_no,
-       int             nbblks,
-       struct xfs_buf  *bp)
+static int
+xlog_do_io(
+       struct xlog             *log,
+       xfs_daddr_t             blk_no,
+       unsigned int            nbblks,
+       char                    *data,
+       unsigned int            op)
 {
-       int             error;
+       int                     error;
 
-       if (!xlog_verify_bp(log, blk_no, nbblks)) {
+       if (!xlog_verify_bno(log, blk_no, nbblks)) {
                xfs_warn(log->l_mp,
                         "Invalid log block/length (0x%llx, 0x%x) for buffer",
                         blk_no, nbblks);
@@ -187,107 +160,53 @@ xlog_bread_noalign(
 
        blk_no = round_down(blk_no, log->l_sectBBsize);
        nbblks = round_up(nbblks, log->l_sectBBsize);
-
        ASSERT(nbblks > 0);
-       ASSERT(nbblks <= bp->b_length);
-
-       XFS_BUF_SET_ADDR(bp, log->l_logBBstart + blk_no);
-       bp->b_flags |= XBF_READ;
-       bp->b_io_length = nbblks;
-       bp->b_error = 0;
 
-       error = xfs_buf_submit(bp);
-       if (error && !XFS_FORCED_SHUTDOWN(log->l_mp))
-               xfs_buf_ioerror_alert(bp, __func__);
+       error = xfs_rw_bdev(log->l_targ->bt_bdev, log->l_logBBstart + blk_no,
+                       BBTOB(nbblks), data, op);
+       if (error && !XFS_FORCED_SHUTDOWN(log->l_mp)) {
+               xfs_alert(log->l_mp,
+                         "log recovery %s I/O error at daddr 0x%llx len %d error %d",
+                         op == REQ_OP_WRITE ? "write" : "read",
+                         blk_no, nbblks, error);
+       }
        return error;
 }
 
 STATIC int
-xlog_bread(
+xlog_bread_noalign(
        struct xlog     *log,
        xfs_daddr_t     blk_no,
        int             nbblks,
-       struct xfs_buf  *bp,
-       char            **offset)
+       char            *data)
 {
-       int             error;
-
-       error = xlog_bread_noalign(log, blk_no, nbblks, bp);
-       if (error)
-               return error;
-
-       *offset = xlog_align(log, blk_no, nbblks, bp);
-       return 0;
+       return xlog_do_io(log, blk_no, nbblks, data, REQ_OP_READ);
 }
 
-/*
- * Read at an offset into the buffer. Returns with the buffer in it's original
- * state regardless of the result of the read.
- */
 STATIC int
-xlog_bread_offset(
+xlog_bread(
        struct xlog     *log,
-       xfs_daddr_t     blk_no,         /* block to read from */
-       int             nbblks,         /* blocks to read */
-       struct xfs_buf  *bp,
-       char            *offset)
+       xfs_daddr_t     blk_no,
+       int             nbblks,
+       char            *data,
+       char            **offset)
 {
-       char            *orig_offset = bp->b_addr;
-       int             orig_len = BBTOB(bp->b_length);
-       int             error, error2;
-
-       error = xfs_buf_associate_memory(bp, offset, BBTOB(nbblks));
-       if (error)
-               return error;
-
-       error = xlog_bread_noalign(log, blk_no, nbblks, bp);
+       int             error;
 
-       /* must reset buffer pointer even on error */
-       error2 = xfs_buf_associate_memory(bp, orig_offset, orig_len);
-       if (error)
-               return error;
-       return error2;
+       error = xlog_do_io(log, blk_no, nbblks, data, REQ_OP_READ);
+       if (!error)
+               *offset = data + xlog_align(log, blk_no);
+       return error;
 }
 
-/*
- * Write out the buffer at the given block for the given number of blocks.
- * The buffer is kept locked across the write and is returned locked.
- * This can only be used for synchronous log writes.
- */
 STATIC int
 xlog_bwrite(
        struct xlog     *log,
        xfs_daddr_t     blk_no,
        int             nbblks,
-       struct xfs_buf  *bp)
+       char            *data)
 {
-       int             error;
-
-       if (!xlog_verify_bp(log, blk_no, nbblks)) {
-               xfs_warn(log->l_mp,
-                        "Invalid log block/length (0x%llx, 0x%x) for buffer",
-                        blk_no, nbblks);
-               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp);
-               return -EFSCORRUPTED;
-       }
-
-       blk_no = round_down(blk_no, log->l_sectBBsize);
-       nbblks = round_up(nbblks, log->l_sectBBsize);
-
-       ASSERT(nbblks > 0);
-       ASSERT(nbblks <= bp->b_length);
-
-       XFS_BUF_SET_ADDR(bp, log->l_logBBstart + blk_no);
-       xfs_buf_hold(bp);
-       xfs_buf_lock(bp);
-       bp->b_io_length = nbblks;
-       bp->b_error = 0;
-
-       error = xfs_bwrite(bp);
-       if (error)
-               xfs_buf_ioerror_alert(bp, __func__);
-       xfs_buf_relse(bp);
-       return error;
+       return xlog_do_io(log, blk_no, nbblks, data, REQ_OP_WRITE);
 }
 
 #ifdef DEBUG
@@ -377,10 +296,9 @@ xlog_recover_iodone(
                 * We're not going to bother about retrying
                 * this during recovery. One strike!
                 */
-               if (!XFS_FORCED_SHUTDOWN(bp->b_target->bt_mount)) {
+               if (!XFS_FORCED_SHUTDOWN(bp->b_mount)) {
                        xfs_buf_ioerror_alert(bp, __func__);
-                       xfs_force_shutdown(bp->b_target->bt_mount,
-                                               SHUTDOWN_META_IO_ERROR);
+                       xfs_force_shutdown(bp->b_mount, SHUTDOWN_META_IO_ERROR);
                }
        }
 
@@ -405,7 +323,7 @@ xlog_recover_iodone(
 STATIC int
 xlog_find_cycle_start(
        struct xlog     *log,
-       struct xfs_buf  *bp,
+       char            *buffer,
        xfs_daddr_t     first_blk,
        xfs_daddr_t     *last_blk,
        uint            cycle)
@@ -419,7 +337,7 @@ xlog_find_cycle_start(
        end_blk = *last_blk;
        mid_blk = BLK_AVG(first_blk, end_blk);
        while (mid_blk != first_blk && mid_blk != end_blk) {
-               error = xlog_bread(log, mid_blk, 1, bp, &offset);
+               error = xlog_bread(log, mid_blk, 1, buffer, &offset);
                if (error)
                        return error;
                mid_cycle = xlog_get_cycle(offset);
@@ -455,7 +373,7 @@ xlog_find_verify_cycle(
 {
        xfs_daddr_t     i, j;
        uint            cycle;
-       xfs_buf_t       *bp;
+       char            *buffer;
        xfs_daddr_t     bufblks;
        char            *buf = NULL;
        int             error = 0;
@@ -469,7 +387,7 @@ xlog_find_verify_cycle(
        bufblks = 1 << ffs(nbblks);
        while (bufblks > log->l_logBBsize)
                bufblks >>= 1;
-       while (!(bp = xlog_get_bp(log, bufblks))) {
+       while (!(buffer = xlog_alloc_buffer(log, bufblks))) {
                bufblks >>= 1;
                if (bufblks < log->l_sectBBsize)
                        return -ENOMEM;
@@ -480,7 +398,7 @@ xlog_find_verify_cycle(
 
                bcount = min(bufblks, (start_blk + nbblks - i));
 
-               error = xlog_bread(log, i, bcount, bp, &buf);
+               error = xlog_bread(log, i, bcount, buffer, &buf);
                if (error)
                        goto out;
 
@@ -498,7 +416,7 @@ xlog_find_verify_cycle(
        *new_blk = -1;
 
 out:
-       xlog_put_bp(bp);
+       kmem_free(buffer);
        return error;
 }
 
@@ -522,7 +440,7 @@ xlog_find_verify_log_record(
        int                     extra_bblks)
 {
        xfs_daddr_t             i;
-       xfs_buf_t               *bp;
+       char                    *buffer;
        char                    *offset = NULL;
        xlog_rec_header_t       *head = NULL;
        int                     error = 0;
@@ -532,12 +450,14 @@ xlog_find_verify_log_record(
 
        ASSERT(start_blk != 0 || *last_blk != start_blk);
 
-       if (!(bp = xlog_get_bp(log, num_blks))) {
-               if (!(bp = xlog_get_bp(log, 1)))
+       buffer = xlog_alloc_buffer(log, num_blks);
+       if (!buffer) {
+               buffer = xlog_alloc_buffer(log, 1);
+               if (!buffer)
                        return -ENOMEM;
                smallmem = 1;
        } else {
-               error = xlog_bread(log, start_blk, num_blks, bp, &offset);
+               error = xlog_bread(log, start_blk, num_blks, buffer, &offset);
                if (error)
                        goto out;
                offset += ((num_blks - 1) << BBSHIFT);
@@ -554,7 +474,7 @@ xlog_find_verify_log_record(
                }
 
                if (smallmem) {
-                       error = xlog_bread(log, i, 1, bp, &offset);
+                       error = xlog_bread(log, i, 1, buffer, &offset);
                        if (error)
                                goto out;
                }
@@ -607,7 +527,7 @@ xlog_find_verify_log_record(
                *last_blk = i;
 
 out:
-       xlog_put_bp(bp);
+       kmem_free(buffer);
        return error;
 }
 
@@ -629,7 +549,7 @@ xlog_find_head(
        struct xlog     *log,
        xfs_daddr_t     *return_head_blk)
 {
-       xfs_buf_t       *bp;
+       char            *buffer;
        char            *offset;
        xfs_daddr_t     new_blk, first_blk, start_blk, last_blk, head_blk;
        int             num_scan_bblks;
@@ -659,20 +579,20 @@ xlog_find_head(
        }
 
        first_blk = 0;                  /* get cycle # of 1st block */
-       bp = xlog_get_bp(log, 1);
-       if (!bp)
+       buffer = xlog_alloc_buffer(log, 1);
+       if (!buffer)
                return -ENOMEM;
 
-       error = xlog_bread(log, 0, 1, bp, &offset);
+       error = xlog_bread(log, 0, 1, buffer, &offset);
        if (error)
-               goto bp_err;
+               goto out_free_buffer;
 
        first_half_cycle = xlog_get_cycle(offset);
 
        last_blk = head_blk = log_bbnum - 1;    /* get cycle # of last block */
-       error = xlog_bread(log, last_blk, 1, bp, &offset);
+       error = xlog_bread(log, last_blk, 1, buffer, &offset);
        if (error)
-               goto bp_err;
+               goto out_free_buffer;
 
        last_half_cycle = xlog_get_cycle(offset);
        ASSERT(last_half_cycle != 0);
@@ -740,9 +660,10 @@ xlog_find_head(
                 *                           ^ we want to locate this spot
                 */
                stop_on_cycle = last_half_cycle;
-               if ((error = xlog_find_cycle_start(log, bp, first_blk,
-                                               &head_blk, last_half_cycle)))
-                       goto bp_err;
+               error = xlog_find_cycle_start(log, buffer, first_blk, &head_blk,
+                               last_half_cycle);
+               if (error)
+                       goto out_free_buffer;
        }
 
        /*
@@ -762,7 +683,7 @@ xlog_find_head(
                if ((error = xlog_find_verify_cycle(log,
                                                start_blk, num_scan_bblks,
                                                stop_on_cycle, &new_blk)))
-                       goto bp_err;
+                       goto out_free_buffer;
                if (new_blk != -1)
                        head_blk = new_blk;
        } else {                /* need to read 2 parts of log */
@@ -799,7 +720,7 @@ xlog_find_head(
                if ((error = xlog_find_verify_cycle(log, start_blk,
                                        num_scan_bblks - (int)head_blk,
                                        (stop_on_cycle - 1), &new_blk)))
-                       goto bp_err;
+                       goto out_free_buffer;
                if (new_blk != -1) {
                        head_blk = new_blk;
                        goto validate_head;
@@ -815,7 +736,7 @@ xlog_find_head(
                if ((error = xlog_find_verify_cycle(log,
                                        start_blk, (int)head_blk,
                                        stop_on_cycle, &new_blk)))
-                       goto bp_err;
+                       goto out_free_buffer;
                if (new_blk != -1)
                        head_blk = new_blk;
        }
@@ -834,13 +755,13 @@ validate_head:
                if (error == 1)
                        error = -EIO;
                if (error)
-                       goto bp_err;
+                       goto out_free_buffer;
        } else {
                start_blk = 0;
                ASSERT(head_blk <= INT_MAX);
                error = xlog_find_verify_log_record(log, start_blk, &head_blk, 0);
                if (error < 0)
-                       goto bp_err;
+                       goto out_free_buffer;
                if (error == 1) {
                        /* We hit the beginning of the log during our search */
                        start_blk = log_bbnum - (num_scan_bblks - head_blk);
@@ -853,14 +774,14 @@ validate_head:
                        if (error == 1)
                                error = -EIO;
                        if (error)
-                               goto bp_err;
+                               goto out_free_buffer;
                        if (new_blk != log_bbnum)
                                head_blk = new_blk;
                } else if (error)
-                       goto bp_err;
+                       goto out_free_buffer;
        }
 
-       xlog_put_bp(bp);
+       kmem_free(buffer);
        if (head_blk == log_bbnum)
                *return_head_blk = 0;
        else
@@ -873,9 +794,8 @@ validate_head:
         */
        return 0;
 
- bp_err:
-       xlog_put_bp(bp);
-
+out_free_buffer:
+       kmem_free(buffer);
        if (error)
                xfs_warn(log->l_mp, "failed to find log head");
        return error;
@@ -895,7 +815,7 @@ xlog_rseek_logrec_hdr(
        xfs_daddr_t             head_blk,
        xfs_daddr_t             tail_blk,
        int                     count,
-       struct xfs_buf          *bp,
+       char                    *buffer,
        xfs_daddr_t             *rblk,
        struct xlog_rec_header  **rhead,
        bool                    *wrapped)
@@ -914,7 +834,7 @@ xlog_rseek_logrec_hdr(
         */
        end_blk = head_blk > tail_blk ? tail_blk : 0;
        for (i = (int) head_blk - 1; i >= end_blk; i--) {
-               error = xlog_bread(log, i, 1, bp, &offset);
+               error = xlog_bread(log, i, 1, buffer, &offset);
                if (error)
                        goto out_error;
 
@@ -933,7 +853,7 @@ xlog_rseek_logrec_hdr(
         */
        if (tail_blk >= head_blk && found != count) {
                for (i = log->l_logBBsize - 1; i >= (int) tail_blk; i--) {
-                       error = xlog_bread(log, i, 1, bp, &offset);
+                       error = xlog_bread(log, i, 1, buffer, &offset);
                        if (error)
                                goto out_error;
 
@@ -969,7 +889,7 @@ xlog_seek_logrec_hdr(
        xfs_daddr_t             head_blk,
        xfs_daddr_t             tail_blk,
        int                     count,
-       struct xfs_buf          *bp,
+       char                    *buffer,
        xfs_daddr_t             *rblk,
        struct xlog_rec_header  **rhead,
        bool                    *wrapped)
@@ -988,7 +908,7 @@ xlog_seek_logrec_hdr(
         */
        end_blk = head_blk > tail_blk ? head_blk : log->l_logBBsize - 1;
        for (i = (int) tail_blk; i <= end_blk; i++) {
-               error = xlog_bread(log, i, 1, bp, &offset);
+               error = xlog_bread(log, i, 1, buffer, &offset);
                if (error)
                        goto out_error;
 
@@ -1006,7 +926,7 @@ xlog_seek_logrec_hdr(
         */
        if (tail_blk > head_blk && found != count) {
                for (i = 0; i < (int) head_blk; i++) {
-                       error = xlog_bread(log, i, 1, bp, &offset);
+                       error = xlog_bread(log, i, 1, buffer, &offset);
                        if (error)
                                goto out_error;
 
@@ -1069,22 +989,22 @@ xlog_verify_tail(
        int                     hsize)
 {
        struct xlog_rec_header  *thead;
-       struct xfs_buf          *bp;
+       char                    *buffer;
        xfs_daddr_t             first_bad;
        int                     error = 0;
        bool                    wrapped;
        xfs_daddr_t             tmp_tail;
        xfs_daddr_t             orig_tail = *tail_blk;
 
-       bp = xlog_get_bp(log, 1);
-       if (!bp)
+       buffer = xlog_alloc_buffer(log, 1);
+       if (!buffer)
                return -ENOMEM;
 
        /*
         * Make sure the tail points to a record (returns positive count on
         * success).
         */
-       error = xlog_seek_logrec_hdr(log, head_blk, *tail_blk, 1, bp,
+       error = xlog_seek_logrec_hdr(log, head_blk, *tail_blk, 1, buffer,
                        &tmp_tail, &thead, &wrapped);
        if (error < 0)
                goto out;
@@ -1113,8 +1033,8 @@ xlog_verify_tail(
                        break;
 
                /* skip to the next record; returns positive count on success */
-               error = xlog_seek_logrec_hdr(log, head_blk, first_bad, 2, bp,
-                               &tmp_tail, &thead, &wrapped);
+               error = xlog_seek_logrec_hdr(log, head_blk, first_bad, 2,
+                               buffer, &tmp_tail, &thead, &wrapped);
                if (error < 0)
                        goto out;
 
@@ -1129,7 +1049,7 @@ xlog_verify_tail(
                "Tail block (0x%llx) overwrite detected. Updated to 0x%llx",
                         orig_tail, *tail_blk);
 out:
-       xlog_put_bp(bp);
+       kmem_free(buffer);
        return error;
 }
 
@@ -1151,13 +1071,13 @@ xlog_verify_head(
        struct xlog             *log,
        xfs_daddr_t             *head_blk,      /* in/out: unverified head */
        xfs_daddr_t             *tail_blk,      /* out: tail block */
-       struct xfs_buf          *bp,
+       char                    *buffer,
        xfs_daddr_t             *rhead_blk,     /* start blk of last record */
        struct xlog_rec_header  **rhead,        /* ptr to last record */
        bool                    *wrapped)       /* last rec. wraps phys. log */
 {
        struct xlog_rec_header  *tmp_rhead;
-       struct xfs_buf          *tmp_bp;
+       char                    *tmp_buffer;
        xfs_daddr_t             first_bad;
        xfs_daddr_t             tmp_rhead_blk;
        int                     found;
@@ -1168,15 +1088,15 @@ xlog_verify_head(
         * Check the head of the log for torn writes. Search backwards from the
         * head until we hit the tail or the maximum number of log record I/Os
         * that could have been in flight at one time. Use a temporary buffer so
-        * we don't trash the rhead/bp pointers from the caller.
+        * we don't trash the rhead/buffer pointers from the caller.
         */
-       tmp_bp = xlog_get_bp(log, 1);
-       if (!tmp_bp)
+       tmp_buffer = xlog_alloc_buffer(log, 1);
+       if (!tmp_buffer)
                return -ENOMEM;
        error = xlog_rseek_logrec_hdr(log, *head_blk, *tail_blk,
-                                     XLOG_MAX_ICLOGS, tmp_bp, &tmp_rhead_blk,
-                                     &tmp_rhead, &tmp_wrapped);
-       xlog_put_bp(tmp_bp);
+                                     XLOG_MAX_ICLOGS, tmp_buffer,
+                                     &tmp_rhead_blk, &tmp_rhead, &tmp_wrapped);
+       kmem_free(tmp_buffer);
        if (error < 0)
                return error;
 
@@ -1205,8 +1125,8 @@ xlog_verify_head(
                 * (i.e., the records with invalid CRC) if the cycle number
                 * matches the the current cycle.
                 */
-               found = xlog_rseek_logrec_hdr(log, first_bad, *tail_blk, 1, bp,
-                                             rhead_blk, rhead, wrapped);
+               found = xlog_rseek_logrec_hdr(log, first_bad, *tail_blk, 1,
+                               buffer, rhead_blk, rhead, wrapped);
                if (found < 0)
                        return found;
                if (found == 0)         /* XXX: right thing to do here? */
@@ -1266,7 +1186,7 @@ xlog_check_unmount_rec(
        xfs_daddr_t             *tail_blk,
        struct xlog_rec_header  *rhead,
        xfs_daddr_t             rhead_blk,
-       struct xfs_buf          *bp,
+       char                    *buffer,
        bool                    *clean)
 {
        struct xlog_op_header   *op_head;
@@ -1309,7 +1229,7 @@ xlog_check_unmount_rec(
        if (*head_blk == after_umount_blk &&
            be32_to_cpu(rhead->h_num_logops) == 1) {
                umount_data_blk = xlog_wrap_logbno(log, rhead_blk + hblks);
-               error = xlog_bread(log, umount_data_blk, 1, bp, &offset);
+               error = xlog_bread(log, umount_data_blk, 1, buffer, &offset);
                if (error)
                        return error;
 
@@ -1388,7 +1308,7 @@ xlog_find_tail(
 {
        xlog_rec_header_t       *rhead;
        char                    *offset = NULL;
-       xfs_buf_t               *bp;
+       char                    *buffer;
        int                     error;
        xfs_daddr_t             rhead_blk;
        xfs_lsn_t               tail_lsn;
@@ -1402,11 +1322,11 @@ xlog_find_tail(
                return error;
        ASSERT(*head_blk < INT_MAX);
 
-       bp = xlog_get_bp(log, 1);
-       if (!bp)
+       buffer = xlog_alloc_buffer(log, 1);
+       if (!buffer)
                return -ENOMEM;
        if (*head_blk == 0) {                           /* special case */
-               error = xlog_bread(log, 0, 1, bp, &offset);
+               error = xlog_bread(log, 0, 1, buffer, &offset);
                if (error)
                        goto done;
 
@@ -1422,7 +1342,7 @@ xlog_find_tail(
         * block. This wraps all the way back around to the head so something is
         * seriously wrong if we can't find it.
         */
-       error = xlog_rseek_logrec_hdr(log, *head_blk, *head_blk, 1, bp,
+       error = xlog_rseek_logrec_hdr(log, *head_blk, *head_blk, 1, buffer,
                                      &rhead_blk, &rhead, &wrapped);
        if (error < 0)
                return error;
@@ -1443,7 +1363,7 @@ xlog_find_tail(
         * state to determine whether recovery is necessary.
         */
        error = xlog_check_unmount_rec(log, head_blk, tail_blk, rhead,
-                                      rhead_blk, bp, &clean);
+                                      rhead_blk, buffer, &clean);
        if (error)
                goto done;
 
@@ -1460,7 +1380,7 @@ xlog_find_tail(
        if (!clean) {
                xfs_daddr_t     orig_head = *head_blk;
 
-               error = xlog_verify_head(log, head_blk, tail_blk, bp,
+               error = xlog_verify_head(log, head_blk, tail_blk, buffer,
                                         &rhead_blk, &rhead, &wrapped);
                if (error)
                        goto done;
@@ -1471,7 +1391,7 @@ xlog_find_tail(
                                       wrapped);
                        tail_lsn = atomic64_read(&log->l_tail_lsn);
                        error = xlog_check_unmount_rec(log, head_blk, tail_blk,
-                                                      rhead, rhead_blk, bp,
+                                                      rhead, rhead_blk, buffer,
                                                       &clean);
                        if (error)
                                goto done;
@@ -1505,11 +1425,11 @@ xlog_find_tail(
         * But... if the -device- itself is readonly, just skip this.
         * We can't recover this device anyway, so it won't matter.
         */
-       if (!xfs_readonly_buftarg(log->l_mp->m_logdev_targp))
+       if (!xfs_readonly_buftarg(log->l_targ))
                error = xlog_clear_stale_blocks(log, tail_lsn);
 
 done:
-       xlog_put_bp(bp);
+       kmem_free(buffer);
 
        if (error)
                xfs_warn(log->l_mp, "failed to locate log tail");
@@ -1537,7 +1457,7 @@ xlog_find_zeroed(
        struct xlog     *log,
        xfs_daddr_t     *blk_no)
 {
-       xfs_buf_t       *bp;
+       char            *buffer;
        char            *offset;
        uint            first_cycle, last_cycle;
        xfs_daddr_t     new_blk, last_blk, start_blk;
@@ -1547,35 +1467,36 @@ xlog_find_zeroed(
        *blk_no = 0;
 
        /* check totally zeroed log */
-       bp = xlog_get_bp(log, 1);
-       if (!bp)
+       buffer = xlog_alloc_buffer(log, 1);
+       if (!buffer)
                return -ENOMEM;
-       error = xlog_bread(log, 0, 1, bp, &offset);
+       error = xlog_bread(log, 0, 1, buffer, &offset);
        if (error)
-               goto bp_err;
+               goto out_free_buffer;
 
        first_cycle = xlog_get_cycle(offset);
        if (first_cycle == 0) {         /* completely zeroed log */
                *blk_no = 0;
-               xlog_put_bp(bp);
+               kmem_free(buffer);
                return 1;
        }
 
        /* check partially zeroed log */
-       error = xlog_bread(log, log_bbnum-1, 1, bp, &offset);
+       error = xlog_bread(log, log_bbnum-1, 1, buffer, &offset);
        if (error)
-               goto bp_err;
+               goto out_free_buffer;
 
        last_cycle = xlog_get_cycle(offset);
        if (last_cycle != 0) {          /* log completely written to */
-               xlog_put_bp(bp);
+               kmem_free(buffer);
                return 0;
        }
 
        /* we have a partially zeroed log */
        last_blk = log_bbnum-1;
-       if ((error = xlog_find_cycle_start(log, bp, 0, &last_blk, 0)))
-               goto bp_err;
+       error = xlog_find_cycle_start(log, buffer, 0, &last_blk, 0);
+       if (error)
+               goto out_free_buffer;
 
        /*
         * Validate the answer.  Because there is no way to guarantee that
@@ -1598,7 +1519,7 @@ xlog_find_zeroed(
         */
        if ((error = xlog_find_verify_cycle(log, start_blk,
                                         (int)num_scan_bblks, 0, &new_blk)))
-               goto bp_err;
+               goto out_free_buffer;
        if (new_blk != -1)
                last_blk = new_blk;
 
@@ -1610,11 +1531,11 @@ xlog_find_zeroed(
        if (error == 1)
                error = -EIO;
        if (error)
-               goto bp_err;
+               goto out_free_buffer;
 
        *blk_no = last_blk;
-bp_err:
-       xlog_put_bp(bp);
+out_free_buffer:
+       kmem_free(buffer);
        if (error)
                return error;
        return 1;
@@ -1657,7 +1578,7 @@ xlog_write_log_records(
        int             tail_block)
 {
        char            *offset;
-       xfs_buf_t       *bp;
+       char            *buffer;
        int             balign, ealign;
        int             sectbb = log->l_sectBBsize;
        int             end_block = start_block + blocks;
@@ -1674,7 +1595,7 @@ xlog_write_log_records(
        bufblks = 1 << ffs(blocks);
        while (bufblks > log->l_logBBsize)
                bufblks >>= 1;
-       while (!(bp = xlog_get_bp(log, bufblks))) {
+       while (!(buffer = xlog_alloc_buffer(log, bufblks))) {
                bufblks >>= 1;
                if (bufblks < sectbb)
                        return -ENOMEM;
@@ -1686,9 +1607,9 @@ xlog_write_log_records(
         */
        balign = round_down(start_block, sectbb);
        if (balign != start_block) {
-               error = xlog_bread_noalign(log, start_block, 1, bp);
+               error = xlog_bread_noalign(log, start_block, 1, buffer);
                if (error)
-                       goto out_put_bp;
+                       goto out_free_buffer;
 
                j = start_block - balign;
        }
@@ -1705,29 +1626,28 @@ xlog_write_log_records(
                 */
                ealign = round_down(end_block, sectbb);
                if (j == 0 && (start_block + endcount > ealign)) {
-                       offset = bp->b_addr + BBTOB(ealign - start_block);
-                       error = xlog_bread_offset(log, ealign, sectbb,
-                                                       bp, offset);
+                       error = xlog_bread_noalign(log, ealign, sectbb,
+                                       buffer + BBTOB(ealign - start_block));
                        if (error)
                                break;
 
                }
 
-               offset = xlog_align(log, start_block, endcount, bp);
+               offset = buffer + xlog_align(log, start_block);
                for (; j < endcount; j++) {
                        xlog_add_record(log, offset, cycle, i+j,
                                        tail_cycle, tail_block);
                        offset += BBSIZE;
                }
-               error = xlog_bwrite(log, start_block, endcount, bp);
+               error = xlog_bwrite(log, start_block, endcount, buffer);
                if (error)
                        break;
                start_block += endcount;
                j = 0;
        }
 
- out_put_bp:
-       xlog_put_bp(bp);
+out_free_buffer:
+       kmem_free(buffer);
        return error;
 }
 
@@ -2162,7 +2082,7 @@ xlog_recover_do_inode_buffer(
        if (xfs_sb_version_hascrc(&mp->m_sb))
                bp->b_ops = &xfs_inode_buf_ops;
 
-       inodes_per_buf = BBTOB(bp->b_io_length) >> mp->m_sb.sb_inodelog;
+       inodes_per_buf = BBTOB(bp->b_length) >> mp->m_sb.sb_inodelog;
        for (i = 0; i < inodes_per_buf; i++) {
                next_unlinked_offset = (i * mp->m_sb.sb_inodesize) +
                        offsetof(xfs_dinode_t, di_next_unlinked);
@@ -2204,8 +2124,7 @@ xlog_recover_do_inode_buffer(
 
                ASSERT(item->ri_buf[item_index].i_addr != NULL);
                ASSERT((item->ri_buf[item_index].i_len % XFS_BLF_CHUNK) == 0);
-               ASSERT((reg_buf_offset + reg_buf_bytes) <=
-                                                       BBTOB(bp->b_io_length));
+               ASSERT((reg_buf_offset + reg_buf_bytes) <= BBTOB(bp->b_length));
 
                /*
                 * The current logged region contains a copy of the
@@ -2670,7 +2589,7 @@ xlog_recover_do_reg_buffer(
                ASSERT(nbits > 0);
                ASSERT(item->ri_buf[i].i_addr != NULL);
                ASSERT(item->ri_buf[i].i_len % XFS_BLF_CHUNK == 0);
-               ASSERT(BBTOB(bp->b_io_length) >=
+               ASSERT(BBTOB(bp->b_length) >=
                       ((uint)bit << XFS_BLF_SHIFT) + (nbits << XFS_BLF_SHIFT));
 
                /*
@@ -2882,23 +2801,22 @@ xlog_recover_buffer_pass2(
         *
         * Also make sure that only inode buffers with good sizes stay in
         * the buffer cache.  The kernel moves inodes in buffers of 1 block
-        * or mp->m_inode_cluster_size bytes, whichever is bigger.  The inode
+        * or inode_cluster_size bytes, whichever is bigger.  The inode
         * buffers in the log can be a different size if the log was generated
         * by an older kernel using unclustered inode buffers or a newer kernel
         * running with a different inode cluster size.  Regardless, if the
-        * the inode buffer size isn't max(blocksize, mp->m_inode_cluster_size)
-        * for *our* value of mp->m_inode_cluster_size, then we need to keep
+        * the inode buffer size isn't max(blocksize, inode_cluster_size)
+        * for *our* value of inode_cluster_size, then we need to keep
         * the buffer out of the buffer cache so that the buffer won't
         * overlap with future reads of those inodes.
         */
        if (XFS_DINODE_MAGIC ==
            be16_to_cpu(*((__be16 *)xfs_buf_offset(bp, 0))) &&
-           (BBTOB(bp->b_io_length) != max(log->l_mp->m_sb.sb_blocksize,
-                       (uint32_t)log->l_mp->m_inode_cluster_size))) {
+           (BBTOB(bp->b_length) != M_IGEO(log->l_mp)->inode_cluster_size)) {
                xfs_buf_stale(bp);
                error = xfs_bwrite(bp);
        } else {
-               ASSERT(bp->b_target->bt_mount == mp);
+               ASSERT(bp->b_mount == mp);
                bp->b_iodone = xlog_recover_iodone;
                xfs_buf_delwri_queue(bp, buffer_list);
        }
@@ -3260,7 +3178,7 @@ out_owner_change:
        /* re-generate the checksum. */
        xfs_dinode_calc_crc(log->l_mp, dip);
 
-       ASSERT(bp->b_target->bt_mount == mp);
+       ASSERT(bp->b_mount == mp);
        bp->b_iodone = xlog_recover_iodone;
        xfs_buf_delwri_queue(bp, buffer_list);
 
@@ -3399,7 +3317,7 @@ xlog_recover_dquot_pass2(
        }
 
        ASSERT(dq_f->qlf_size == 2);
-       ASSERT(bp->b_target->bt_mount == mp);
+       ASSERT(bp->b_mount == mp);
        bp->b_iodone = xlog_recover_iodone;
        xfs_buf_delwri_queue(bp, buffer_list);
 
@@ -3463,7 +3381,7 @@ xlog_recover_efd_pass2(
 {
        xfs_efd_log_format_t    *efd_formatp;
        xfs_efi_log_item_t      *efip = NULL;
-       xfs_log_item_t          *lip;
+       struct xfs_log_item     *lip;
        uint64_t                efi_id;
        struct xfs_ail_cursor   cur;
        struct xfs_ail          *ailp = log->l_ailp;
@@ -3849,6 +3767,7 @@ xlog_recover_do_icreate_pass2(
 {
        struct xfs_mount        *mp = log->l_mp;
        struct xfs_icreate_log  *icl;
+       struct xfs_ino_geometry *igeo = M_IGEO(mp);
        xfs_agnumber_t          agno;
        xfs_agblock_t           agbno;
        unsigned int            count;
@@ -3898,10 +3817,10 @@ xlog_recover_do_icreate_pass2(
 
        /*
         * The inode chunk is either full or sparse and we only support
-        * m_ialloc_min_blks sized sparse allocations at this time.
+        * m_ino_geo.ialloc_min_blks sized sparse allocations at this time.
         */
-       if (length != mp->m_ialloc_blks &&
-           length != mp->m_ialloc_min_blks) {
+       if (length != igeo->ialloc_blks &&
+           length != igeo->ialloc_min_blks) {
                xfs_warn(log->l_mp,
                         "%s: unsupported chunk length", __FUNCTION__);
                return -EINVAL;
@@ -3921,13 +3840,13 @@ xlog_recover_do_icreate_pass2(
         * buffers for cancellation so we don't overwrite anything written after
         * a cancellation.
         */
-       bb_per_cluster = XFS_FSB_TO_BB(mp, mp->m_blocks_per_cluster);
-       nbufs = length / mp->m_blocks_per_cluster;
+       bb_per_cluster = XFS_FSB_TO_BB(mp, igeo->blocks_per_cluster);
+       nbufs = length / igeo->blocks_per_cluster;
        for (i = 0, cancel_count = 0; i < nbufs; i++) {
                xfs_daddr_t     daddr;
 
                daddr = XFS_AGB_TO_DADDR(mp, agno,
-                                        agbno + i * mp->m_blocks_per_cluster);
+                               agbno + i * igeo->blocks_per_cluster);
                if (xlog_check_buffer_cancelled(log, daddr, bb_per_cluster, 0))
                        cancel_count++;
        }
@@ -4956,12 +4875,11 @@ out:
  * A cancel occurs when the mount has failed and we're bailing out.
  * Release all pending log intent items so they don't pin the AIL.
  */
-STATIC int
+STATIC void
 xlog_recover_cancel_intents(
        struct xlog             *log)
 {
        struct xfs_log_item     *lip;
-       int                     error = 0;
        struct xfs_ail_cursor   cur;
        struct xfs_ail          *ailp;
 
@@ -5001,7 +4919,6 @@ xlog_recover_cancel_intents(
 
        xfs_trans_ail_cursor_done(&cur);
        spin_unlock(&ailp->ail_lock);
-       return error;
 }
 
 /*
@@ -5307,7 +5224,7 @@ xlog_do_recovery_pass(
        xfs_daddr_t             blk_no, rblk_no;
        xfs_daddr_t             rhead_blk;
        char                    *offset;
-       xfs_buf_t               *hbp, *dbp;
+       char                    *hbp, *dbp;
        int                     error = 0, h_size, h_len;
        int                     error2 = 0;
        int                     bblks, split_bblks;
@@ -5332,7 +5249,7 @@ xlog_do_recovery_pass(
                 * iclog header and extract the header size from it.  Get a
                 * new hbp that is the correct size.
                 */
-               hbp = xlog_get_bp(log, 1);
+               hbp = xlog_alloc_buffer(log, 1);
                if (!hbp)
                        return -ENOMEM;
 
@@ -5374,23 +5291,23 @@ xlog_do_recovery_pass(
                        hblks = h_size / XLOG_HEADER_CYCLE_SIZE;
                        if (h_size % XLOG_HEADER_CYCLE_SIZE)
                                hblks++;
-                       xlog_put_bp(hbp);
-                       hbp = xlog_get_bp(log, hblks);
+                       kmem_free(hbp);
+                       hbp = xlog_alloc_buffer(log, hblks);
                } else {
                        hblks = 1;
                }
        } else {
                ASSERT(log->l_sectBBsize == 1);
                hblks = 1;
-               hbp = xlog_get_bp(log, 1);
+               hbp = xlog_alloc_buffer(log, 1);
                h_size = XLOG_BIG_RECORD_BSIZE;
        }
 
        if (!hbp)
                return -ENOMEM;
-       dbp = xlog_get_bp(log, BTOBB(h_size));
+       dbp = xlog_alloc_buffer(log, BTOBB(h_size));
        if (!dbp) {
-               xlog_put_bp(hbp);
+               kmem_free(hbp);
                return -ENOMEM;
        }
 
@@ -5405,7 +5322,7 @@ xlog_do_recovery_pass(
                        /*
                         * Check for header wrapping around physical end-of-log
                         */
-                       offset = hbp->b_addr;
+                       offset = hbp;
                        split_hblks = 0;
                        wrapped_hblks = 0;
                        if (blk_no + hblks <= log->l_logBBsize) {
@@ -5441,8 +5358,8 @@ xlog_do_recovery_pass(
                                 *   - order is important.
                                 */
                                wrapped_hblks = hblks - split_hblks;
-                               error = xlog_bread_offset(log, 0,
-                                               wrapped_hblks, hbp,
+                               error = xlog_bread_noalign(log, 0,
+                                               wrapped_hblks,
                                                offset + BBTOB(split_hblks));
                                if (error)
                                        goto bread_err2;
@@ -5473,7 +5390,7 @@ xlog_do_recovery_pass(
                        } else {
                                /* This log record is split across the
                                 * physical end of log */
-                               offset = dbp->b_addr;
+                               offset = dbp;
                                split_bblks = 0;
                                if (blk_no != log->l_logBBsize) {
                                        /* some data is before the physical
@@ -5502,8 +5419,8 @@ xlog_do_recovery_pass(
                                 *   _first_, then the log start (LR header end)
                                 *   - order is important.
                                 */
-                               error = xlog_bread_offset(log, 0,
-                                               bblks - split_bblks, dbp,
+                               error = xlog_bread_noalign(log, 0,
+                                               bblks - split_bblks,
                                                offset + BBTOB(split_bblks));
                                if (error)
                                        goto bread_err2;
@@ -5551,9 +5468,9 @@ xlog_do_recovery_pass(
        }
 
  bread_err2:
-       xlog_put_bp(dbp);
+       kmem_free(dbp);
  bread_err1:
-       xlog_put_bp(hbp);
+       kmem_free(hbp);
 
        /*
         * Submit buffers that have been added from the last record processed,
@@ -5687,7 +5604,7 @@ xlog_do_recover(
         * Now that we've finished replaying all buffer and inode
         * updates, re-read in the superblock and reverify it.
         */
-       bp = xfs_getsb(mp, 0);
+       bp = xfs_getsb(mp);
        bp->b_flags &= ~(XBF_DONE | XBF_ASYNC);
        ASSERT(!(bp->b_flags & XBF_WRITE));
        bp->b_flags |= XBF_READ;
@@ -5860,16 +5777,12 @@ xlog_recover_finish(
        return 0;
 }
 
-int
+void
 xlog_recover_cancel(
        struct xlog     *log)
 {
-       int             error = 0;
-
        if (log->l_flags & XLOG_RECOVERY_NEEDED)
-               error = xlog_recover_cancel_intents(log);
-
-       return error;
+               xlog_recover_cancel_intents(log);
 }
 
 #if defined(DEBUG)
index 6b736ea..9804efe 100644 (file)
@@ -6,8 +6,8 @@
 #include "xfs.h"
 #include "xfs_fs.h"
 #include "xfs_error.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
-#include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
 
index 6b2bfe8..322da69 100644 (file)
@@ -12,9 +12,6 @@
 #include "xfs_bit.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_inode.h"
 #include "xfs_dir2.h"
 #include "xfs_ialloc.h"
@@ -27,7 +24,6 @@
 #include "xfs_error.h"
 #include "xfs_quota.h"
 #include "xfs_fsops.h"
-#include "xfs_trace.h"
 #include "xfs_icache.h"
 #include "xfs_sysfs.h"
 #include "xfs_rmap_btree.h"
@@ -429,30 +425,6 @@ xfs_update_alignment(xfs_mount_t *mp)
        return 0;
 }
 
-/*
- * Set the maximum inode count for this filesystem
- */
-STATIC void
-xfs_set_maxicount(xfs_mount_t *mp)
-{
-       xfs_sb_t        *sbp = &(mp->m_sb);
-       uint64_t        icount;
-
-       if (sbp->sb_imax_pct) {
-               /*
-                * Make sure the maximum inode count is a multiple
-                * of the units we allocate inodes in.
-                */
-               icount = sbp->sb_dblocks * sbp->sb_imax_pct;
-               do_div(icount, 100);
-               do_div(icount, mp->m_ialloc_blks);
-               mp->m_maxicount = (icount * mp->m_ialloc_blks)  <<
-                                  sbp->sb_inopblog;
-       } else {
-               mp->m_maxicount = 0;
-       }
-}
-
 /*
  * Set the default minimum read and write sizes unless
  * already specified in a mount option.
@@ -509,29 +481,6 @@ xfs_set_low_space_thresholds(
        }
 }
 
-
-/*
- * Set whether we're using inode alignment.
- */
-STATIC void
-xfs_set_inoalignment(xfs_mount_t *mp)
-{
-       if (xfs_sb_version_hasalign(&mp->m_sb) &&
-               mp->m_sb.sb_inoalignmt >= xfs_icluster_size_fsb(mp))
-               mp->m_inoalign_mask = mp->m_sb.sb_inoalignmt - 1;
-       else
-               mp->m_inoalign_mask = 0;
-       /*
-        * If we are using stripe alignment, check whether
-        * the stripe unit is a multiple of the inode alignment
-        */
-       if (mp->m_dalign && mp->m_inoalign_mask &&
-           !(mp->m_dalign & mp->m_inoalign_mask))
-               mp->m_sinoalign = mp->m_dalign;
-       else
-               mp->m_sinoalign = 0;
-}
-
 /*
  * Check that the data (and log if separate) is an ok size.
  */
@@ -683,6 +632,7 @@ xfs_mountfs(
 {
        struct xfs_sb           *sbp = &(mp->m_sb);
        struct xfs_inode        *rip;
+       struct xfs_ino_geometry *igeo = M_IGEO(mp);
        uint64_t                resblks;
        uint                    quotamount = 0;
        uint                    quotaflags = 0;
@@ -749,12 +699,10 @@ xfs_mountfs(
        xfs_alloc_compute_maxlevels(mp);
        xfs_bmap_compute_maxlevels(mp, XFS_DATA_FORK);
        xfs_bmap_compute_maxlevels(mp, XFS_ATTR_FORK);
-       xfs_ialloc_compute_maxlevels(mp);
+       xfs_ialloc_setup_geometry(mp);
        xfs_rmapbt_compute_maxlevels(mp);
        xfs_refcountbt_compute_maxlevels(mp);
 
-       xfs_set_maxicount(mp);
-
        /* enable fail_at_unmount as default */
        mp->m_fail_unmount = true;
 
@@ -787,29 +735,6 @@ xfs_mountfs(
        /* set the low space thresholds for dynamic preallocation */
        xfs_set_low_space_thresholds(mp);
 
-       /*
-        * Set the inode cluster size.
-        * This may still be overridden by the file system
-        * block size if it is larger than the chosen cluster size.
-        *
-        * For v5 filesystems, scale the cluster size with the inode size to
-        * keep a constant ratio of inode per cluster buffer, but only if mkfs
-        * has set the inode alignment value appropriately for larger cluster
-        * sizes.
-        */
-       mp->m_inode_cluster_size = XFS_INODE_BIG_CLUSTER_SIZE;
-       if (xfs_sb_version_hascrc(&mp->m_sb)) {
-               int     new_size = mp->m_inode_cluster_size;
-
-               new_size *= mp->m_sb.sb_inodesize / XFS_DINODE_MIN_SIZE;
-               if (mp->m_sb.sb_inoalignmt >= XFS_B_TO_FSBT(mp, new_size))
-                       mp->m_inode_cluster_size = new_size;
-       }
-       mp->m_blocks_per_cluster = xfs_icluster_size_fsb(mp);
-       mp->m_inodes_per_cluster = XFS_FSB_TO_INO(mp, mp->m_blocks_per_cluster);
-       mp->m_cluster_align = xfs_ialloc_cluster_alignment(mp);
-       mp->m_cluster_align_inodes = XFS_FSB_TO_INO(mp, mp->m_cluster_align);
-
        /*
         * If enabled, sparse inode chunk alignment is expected to match the
         * cluster size. Full inode chunk alignment must match the chunk size,
@@ -817,20 +742,15 @@ xfs_mountfs(
         */
        if (xfs_sb_version_hassparseinodes(&mp->m_sb) &&
            mp->m_sb.sb_spino_align !=
-                       XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size)) {
+                       XFS_B_TO_FSBT(mp, igeo->inode_cluster_size_raw)) {
                xfs_warn(mp,
        "Sparse inode block alignment (%u) must match cluster size (%llu).",
                         mp->m_sb.sb_spino_align,
-                        XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size));
+                        XFS_B_TO_FSBT(mp, igeo->inode_cluster_size_raw));
                error = -EINVAL;
                goto out_remove_uuid;
        }
 
-       /*
-        * Set inode alignment fields
-        */
-       xfs_set_inoalignment(mp);
-
        /*
         * Check that the data (and log if separate) is an ok size.
         */
@@ -1385,24 +1305,14 @@ xfs_mod_frextents(
  * xfs_getsb() is called to obtain the buffer for the superblock.
  * The buffer is returned locked and read in from disk.
  * The buffer should be released with a call to xfs_brelse().
- *
- * If the flags parameter is BUF_TRYLOCK, then we'll only return
- * the superblock buffer if it can be locked without sleeping.
- * If it can't then we'll return NULL.
  */
 struct xfs_buf *
 xfs_getsb(
-       struct xfs_mount        *mp,
-       int                     flags)
+       struct xfs_mount        *mp)
 {
        struct xfs_buf          *bp = mp->m_sb_bp;
 
-       if (!xfs_buf_trylock(bp)) {
-               if (flags & XBF_TRYLOCK)
-                       return NULL;
-               xfs_buf_lock(bp);
-       }
-
+       xfs_buf_lock(bp);
        xfs_buf_hold(bp);
        ASSERT(bp->b_flags & XBF_DONE);
        return bp;
index c81a5cd..4adb683 100644 (file)
@@ -105,6 +105,7 @@ typedef struct xfs_mount {
        struct xfs_da_geometry  *m_dir_geo;     /* directory block geometry */
        struct xfs_da_geometry  *m_attr_geo;    /* attribute block geometry */
        struct xlog             *m_log;         /* log specific stuff */
+       struct xfs_ino_geometry m_ino_geo;      /* inode geometry */
        int                     m_logbufs;      /* number of log buffers */
        int                     m_logbsize;     /* size of each log buffer */
        uint                    m_rsumlevels;   /* rt summary levels */
@@ -126,12 +127,6 @@ typedef struct xfs_mount {
        uint8_t                 m_blkbit_log;   /* blocklog + NBBY */
        uint8_t                 m_blkbb_log;    /* blocklog - BBSHIFT */
        uint8_t                 m_agno_log;     /* log #ag's */
-       uint8_t                 m_agino_log;    /* #bits for agino in inum */
-       uint                    m_inode_cluster_size;/* min inode buf size */
-       unsigned int            m_inodes_per_cluster;
-       unsigned int            m_blocks_per_cluster;
-       unsigned int            m_cluster_align;
-       unsigned int            m_cluster_align_inodes;
        uint                    m_blockmask;    /* sb_blocksize-1 */
        uint                    m_blockwsize;   /* sb_blocksize in words */
        uint                    m_blockwmask;   /* blockwsize-1 */
@@ -139,15 +134,12 @@ typedef struct xfs_mount {
        uint                    m_alloc_mnr[2]; /* min alloc btree records */
        uint                    m_bmap_dmxr[2]; /* max bmap btree records */
        uint                    m_bmap_dmnr[2]; /* min bmap btree records */
-       uint                    m_inobt_mxr[2]; /* max inobt btree records */
-       uint                    m_inobt_mnr[2]; /* min inobt btree records */
        uint                    m_rmap_mxr[2];  /* max rmap btree records */
        uint                    m_rmap_mnr[2];  /* min rmap btree records */
        uint                    m_refc_mxr[2];  /* max refc btree records */
        uint                    m_refc_mnr[2];  /* min refc btree records */
        uint                    m_ag_maxlevels; /* XFS_AG_MAXLEVELS */
        uint                    m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */
-       uint                    m_in_maxlevels; /* max inobt btree levels. */
        uint                    m_rmap_maxlevels; /* max rmap btree levels */
        uint                    m_refc_maxlevels; /* max refcount btree level */
        xfs_extlen_t            m_ag_prealloc_blocks; /* reserved ag blocks */
@@ -159,20 +151,13 @@ typedef struct xfs_mount {
        int                     m_fixedfsid[2]; /* unchanged for life of FS */
        uint64_t                m_flags;        /* global mount flags */
        bool                    m_finobt_nores; /* no per-AG finobt resv. */
-       int                     m_ialloc_inos;  /* inodes in inode allocation */
-       int                     m_ialloc_blks;  /* blocks in inode allocation */
-       int                     m_ialloc_min_blks;/* min blocks in sparse inode
-                                                  * allocation */
-       int                     m_inoalign_mask;/* mask sb_inoalignmt if used */
        uint                    m_qflags;       /* quota status flags */
        struct xfs_trans_resv   m_resv;         /* precomputed res values */
-       uint64_t                m_maxicount;    /* maximum inode count */
        uint64_t                m_resblks;      /* total reserved blocks */
        uint64_t                m_resblks_avail;/* available reserved blocks */
        uint64_t                m_resblks_save; /* reserved blks @ remount,ro */
        int                     m_dalign;       /* stripe unit */
        int                     m_swidth;       /* stripe width */
-       int                     m_sinoalign;    /* stripe unit inode alignment */
        uint8_t                 m_sectbb_log;   /* sectlog - BBSHIFT */
        const struct xfs_nameops *m_dirnameops; /* vector of dir name ops */
        const struct xfs_dir_ops *m_dir_inode_ops; /* vector of dir inode ops */
@@ -198,7 +183,6 @@ typedef struct xfs_mount {
        struct workqueue_struct *m_unwritten_workqueue;
        struct workqueue_struct *m_cil_workqueue;
        struct workqueue_struct *m_reclaim_workqueue;
-       struct workqueue_struct *m_log_workqueue;
        struct workqueue_struct *m_eofblocks_workqueue;
        struct workqueue_struct *m_sync_workqueue;
 
@@ -226,6 +210,8 @@ typedef struct xfs_mount {
 #endif
 } xfs_mount_t;
 
+#define M_IGEO(mp)             (&(mp)->m_ino_geo)
+
 /*
  * Flags for m_flags.
  */
@@ -465,7 +451,7 @@ extern int  xfs_mod_fdblocks(struct xfs_mount *mp, int64_t delta,
                                 bool reserved);
 extern int     xfs_mod_frextents(struct xfs_mount *mp, int64_t delta);
 
-extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int);
+extern struct xfs_buf *xfs_getsb(xfs_mount_t *);
 extern int     xfs_readsb(xfs_mount_t *, int);
 extern void    xfs_freesb(xfs_mount_t *);
 extern bool    xfs_fs_writable(struct xfs_mount *mp, int level);
index c8ba98f..b6701b4 100644 (file)
@@ -146,6 +146,11 @@ xfs_check_ondisk_structs(void)
        XFS_CHECK_OFFSET(struct xfs_dir3_data_hdr, hdr.magic,   0);
        XFS_CHECK_OFFSET(struct xfs_dir3_free, hdr.hdr.magic,   0);
        XFS_CHECK_OFFSET(struct xfs_attr3_leafblock, hdr.info.hdr, 0);
+
+       XFS_CHECK_STRUCT_SIZE(struct xfs_bulkstat,              192);
+       XFS_CHECK_STRUCT_SIZE(struct xfs_inumbers,              24);
+       XFS_CHECK_STRUCT_SIZE(struct xfs_bulkstat_req,          64);
+       XFS_CHECK_STRUCT_SIZE(struct xfs_inumbers_req,          64);
 }
 
 #endif /* __XFS_ONDISK_H */
index bde2c9f..0c954ca 100644 (file)
@@ -2,23 +2,16 @@
 /*
  * Copyright (c) 2014 Christoph Hellwig.
  */
-#include <linux/iomap.h>
 #include "xfs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
-#include "xfs_log.h"
 #include "xfs_bmap.h"
-#include "xfs_bmap_util.h"
-#include "xfs_error.h"
 #include "xfs_iomap.h"
-#include "xfs_shared.h"
-#include "xfs_bit.h"
-#include "xfs_pnfs.h"
 
 /*
  * Ensure that we do not have any outstanding pNFS layouts that can be used by
diff --git a/fs/xfs/xfs_pwork.c b/fs/xfs/xfs_pwork.c
new file mode 100644 (file)
index 0000000..4bcc3e6
--- /dev/null
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 Oracle.  All Rights Reserved.
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_shared.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_mount.h"
+#include "xfs_trace.h"
+#include "xfs_sysctl.h"
+#include "xfs_pwork.h"
+#include <linux/nmi.h>
+
+/*
+ * Parallel Work Queue
+ * ===================
+ *
+ * Abstract away the details of running a large and "obviously" parallelizable
+ * task across multiple CPUs.  Callers initialize the pwork control object with
+ * a desired level of parallelization and a work function.  Next, they embed
+ * struct xfs_pwork in whatever structure they use to pass work context to a
+ * worker thread and queue that pwork.  The work function will be passed the
+ * pwork item when it is run (from process context) and any returned error will
+ * be recorded in xfs_pwork_ctl.error.  Work functions should check for errors
+ * and abort if necessary; the non-zeroness of xfs_pwork_ctl.error does not
+ * stop workqueue item processing.
+ *
+ * This is the rough equivalent of the xfsprogs workqueue code, though we can't
+ * reuse that name here.
+ */
+
+/* Invoke our caller's function. */
+static void
+xfs_pwork_work(
+       struct work_struct      *work)
+{
+       struct xfs_pwork        *pwork;
+       struct xfs_pwork_ctl    *pctl;
+       int                     error;
+
+       pwork = container_of(work, struct xfs_pwork, work);
+       pctl = pwork->pctl;
+       error = pctl->work_fn(pctl->mp, pwork);
+       if (error && !pctl->error)
+               pctl->error = error;
+       if (atomic_dec_and_test(&pctl->nr_work))
+               wake_up(&pctl->poll_wait);
+}
+
+/*
+ * Set up control data for parallel work.  @work_fn is the function that will
+ * be called.  @tag will be written into the kernel threads.  @nr_threads is
+ * the level of parallelism desired, or 0 for no limit.
+ */
+int
+xfs_pwork_init(
+       struct xfs_mount        *mp,
+       struct xfs_pwork_ctl    *pctl,
+       xfs_pwork_work_fn       work_fn,
+       const char              *tag,
+       unsigned int            nr_threads)
+{
+#ifdef DEBUG
+       if (xfs_globals.pwork_threads >= 0)
+               nr_threads = xfs_globals.pwork_threads;
+#endif
+       trace_xfs_pwork_init(mp, nr_threads, current->pid);
+
+       pctl->wq = alloc_workqueue("%s-%d", WQ_FREEZABLE, nr_threads, tag,
+                       current->pid);
+       if (!pctl->wq)
+               return -ENOMEM;
+       pctl->work_fn = work_fn;
+       pctl->error = 0;
+       pctl->mp = mp;
+       atomic_set(&pctl->nr_work, 0);
+       init_waitqueue_head(&pctl->poll_wait);
+
+       return 0;
+}
+
+/* Queue some parallel work. */
+void
+xfs_pwork_queue(
+       struct xfs_pwork_ctl    *pctl,
+       struct xfs_pwork        *pwork)
+{
+       INIT_WORK(&pwork->work, xfs_pwork_work);
+       pwork->pctl = pctl;
+       atomic_inc(&pctl->nr_work);
+       queue_work(pctl->wq, &pwork->work);
+}
+
+/* Wait for the work to finish and tear down the control structure. */
+int
+xfs_pwork_destroy(
+       struct xfs_pwork_ctl    *pctl)
+{
+       destroy_workqueue(pctl->wq);
+       pctl->wq = NULL;
+       return pctl->error;
+}
+
+/*
+ * Wait for the work to finish by polling completion status and touch the soft
+ * lockup watchdog.  This is for callers such as mount which hold locks.
+ */
+void
+xfs_pwork_poll(
+       struct xfs_pwork_ctl    *pctl)
+{
+       while (wait_event_timeout(pctl->poll_wait,
+                               atomic_read(&pctl->nr_work) == 0, HZ) == 0)
+               touch_softlockup_watchdog();
+}
+
+/*
+ * Return the amount of parallelism that the data device can handle, or 0 for
+ * no limit.
+ */
+unsigned int
+xfs_pwork_guess_datadev_parallelism(
+       struct xfs_mount        *mp)
+{
+       struct xfs_buftarg      *btp = mp->m_ddev_targp;
+
+       /*
+        * For now we'll go with the most conservative setting possible,
+        * which is two threads for an SSD and 1 thread everywhere else.
+        */
+       return blk_queue_nonrot(btp->bt_bdev->bd_queue) ? 2 : 1;
+}
diff --git a/fs/xfs/xfs_pwork.h b/fs/xfs/xfs_pwork.h
new file mode 100644 (file)
index 0000000..8133124
--- /dev/null
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2019 Oracle.  All Rights Reserved.
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ */
+#ifndef __XFS_PWORK_H__
+#define __XFS_PWORK_H__
+
+struct xfs_pwork;
+struct xfs_mount;
+
+typedef int (*xfs_pwork_work_fn)(struct xfs_mount *mp, struct xfs_pwork *pwork);
+
+/*
+ * Parallel work coordination structure.
+ */
+struct xfs_pwork_ctl {
+       struct workqueue_struct *wq;
+       struct xfs_mount        *mp;
+       xfs_pwork_work_fn       work_fn;
+       struct wait_queue_head  poll_wait;
+       atomic_t                nr_work;
+       int                     error;
+};
+
+/*
+ * Embed this parallel work control item inside your own work structure,
+ * then queue work with it.
+ */
+struct xfs_pwork {
+       struct work_struct      work;
+       struct xfs_pwork_ctl    *pctl;
+};
+
+#define XFS_PWORK_SINGLE_THREADED      { .pctl = NULL }
+
+/* Have we been told to abort? */
+static inline bool
+xfs_pwork_ctl_want_abort(
+       struct xfs_pwork_ctl    *pctl)
+{
+       return pctl && pctl->error;
+}
+
+/* Have we been told to abort? */
+static inline bool
+xfs_pwork_want_abort(
+       struct xfs_pwork        *pwork)
+{
+       return xfs_pwork_ctl_want_abort(pwork->pctl);
+}
+
+int xfs_pwork_init(struct xfs_mount *mp, struct xfs_pwork_ctl *pctl,
+               xfs_pwork_work_fn work_fn, const char *tag,
+               unsigned int nr_threads);
+void xfs_pwork_queue(struct xfs_pwork_ctl *pctl, struct xfs_pwork *pwork);
+int xfs_pwork_destroy(struct xfs_pwork_ctl *pctl);
+void xfs_pwork_poll(struct xfs_pwork_ctl *pctl);
+unsigned int xfs_pwork_guess_datadev_parallelism(struct xfs_mount *mp);
+
+#endif /* __XFS_PWORK_H__ */
index aa6b6db..5e7a37f 100644 (file)
 #include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_inode.h"
-#include "xfs_ialloc.h"
-#include "xfs_itable.h"
+#include "xfs_iwalk.h"
 #include "xfs_quota.h"
-#include "xfs_error.h"
 #include "xfs_bmap.h"
-#include "xfs_bmap_btree.h"
 #include "xfs_bmap_util.h"
 #include "xfs_trans.h"
 #include "xfs_trans_space.h"
 #include "xfs_qm.h"
 #include "xfs_trace.h"
 #include "xfs_icache.h"
-#include "xfs_cksum.h"
 
 /*
  * The global quota manager. There is only one of these for the entire
@@ -1118,17 +1114,15 @@ xfs_qm_quotacheck_dqadjust(
 /* ARGSUSED */
 STATIC int
 xfs_qm_dqusage_adjust(
-       xfs_mount_t     *mp,            /* mount point for filesystem */
-       xfs_ino_t       ino,            /* inode number to get data for */
-       void            __user *buffer, /* not used */
-       int             ubsize,         /* not used */
-       int             *ubused,        /* not used */
-       int             *res)           /* result code value */
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       xfs_ino_t               ino,
+       void                    *data)
 {
-       xfs_inode_t     *ip;
-       xfs_qcnt_t      nblks;
-       xfs_filblks_t   rtblks = 0;     /* total rt blks */
-       int             error;
+       struct xfs_inode        *ip;
+       xfs_qcnt_t              nblks;
+       xfs_filblks_t           rtblks = 0;     /* total rt blks */
+       int                     error;
 
        ASSERT(XFS_IS_QUOTA_RUNNING(mp));
 
@@ -1136,20 +1130,18 @@ xfs_qm_dqusage_adjust(
         * rootino must have its resources accounted for, not so with the quota
         * inodes.
         */
-       if (xfs_is_quota_inode(&mp->m_sb, ino)) {
-               *res = BULKSTAT_RV_NOTHING;
-               return -EINVAL;
-       }
+       if (xfs_is_quota_inode(&mp->m_sb, ino))
+               return 0;
 
        /*
         * We don't _need_ to take the ilock EXCL here because quotacheck runs
         * at mount time and therefore nobody will be racing chown/chproj.
         */
-       error = xfs_iget(mp, NULL, ino, XFS_IGET_DONTCACHE, 0, &ip);
-       if (error) {
-               *res = BULKSTAT_RV_NOTHING;
+       error = xfs_iget(mp, tp, ino, XFS_IGET_DONTCACHE, 0, &ip);
+       if (error == -EINVAL || error == -ENOENT)
+               return 0;
+       if (error)
                return error;
-       }
 
        ASSERT(ip->i_delayed_blks == 0);
 
@@ -1157,7 +1149,7 @@ xfs_qm_dqusage_adjust(
                struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
 
                if (!(ifp->if_flags & XFS_IFEXTENTS)) {
-                       error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK);
+                       error = xfs_iread_extents(tp, ip, XFS_DATA_FORK);
                        if (error)
                                goto error0;
                }
@@ -1200,13 +1192,8 @@ xfs_qm_dqusage_adjust(
                        goto error0;
        }
 
-       xfs_irele(ip);
-       *res = BULKSTAT_RV_DIDONE;
-       return 0;
-
 error0:
        xfs_irele(ip);
-       *res = BULKSTAT_RV_GIVEUP;
        return error;
 }
 
@@ -1270,18 +1257,13 @@ STATIC int
 xfs_qm_quotacheck(
        xfs_mount_t     *mp)
 {
-       int                     done, count, error, error2;
-       xfs_ino_t               lastino;
-       size_t                  structsz;
+       int                     error, error2;
        uint                    flags;
        LIST_HEAD               (buffer_list);
        struct xfs_inode        *uip = mp->m_quotainfo->qi_uquotaip;
        struct xfs_inode        *gip = mp->m_quotainfo->qi_gquotaip;
        struct xfs_inode        *pip = mp->m_quotainfo->qi_pquotaip;
 
-       count = INT_MAX;
-       structsz = 1;
-       lastino = 0;
        flags = 0;
 
        ASSERT(uip || gip || pip);
@@ -1318,18 +1300,10 @@ xfs_qm_quotacheck(
                flags |= XFS_PQUOTA_CHKD;
        }
 
-       do {
-               /*
-                * Iterate thru all the inodes in the file system,
-                * adjusting the corresponding dquot counters in core.
-                */
-               error = xfs_bulkstat(mp, &lastino, &count,
-                                    xfs_qm_dqusage_adjust,
-                                    structsz, NULL, &done);
-               if (error)
-                       break;
-
-       } while (!done);
+       error = xfs_iwalk_threaded(mp, 0, 0, xfs_qm_dqusage_adjust, 0, true,
+                       NULL);
+       if (error)
+               goto error_return;
 
        /*
         * We've made all the changes that we need to make incore.  Flush them
index 3091e4b..5d72e88 100644 (file)
@@ -5,13 +5,13 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_quota.h"
 #include "xfs_mount.h"
 #include "xfs_inode.h"
-#include "xfs_error.h"
 #include "xfs_trans.h"
 #include "xfs_qm.h"
 
index b319089..da7ad03 100644 (file)
@@ -4,7 +4,6 @@
  * All Rights Reserved.
  */
 
-#include <linux/capability.h>
 
 #include "xfs.h"
 #include "xfs_fs.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_bit.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
-#include "xfs_error.h"
 #include "xfs_quota.h"
 #include "xfs_qm.h"
-#include "xfs_trace.h"
 #include "xfs_icache.h"
-#include "xfs_defer.h"
 
 STATIC int     xfs_qm_log_quotaoff(xfs_mount_t *, xfs_qoff_logitem_t **, uint);
 STATIC int     xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *,
index a7c0c65..cd6c721 100644 (file)
@@ -4,6 +4,7 @@
  * All Rights Reserved.
  */
 #include "xfs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_inode.h"
 #include "xfs_quota.h"
 #include "xfs_trans.h"
-#include "xfs_trace.h"
 #include "xfs_icache.h"
 #include "xfs_qm.h"
-#include <linux/quota.h>
 
 
 static void
index fce38b5..d8288aa 100644 (file)
@@ -14,7 +14,6 @@
 #include "xfs_defer.h"
 #include "xfs_trans.h"
 #include "xfs_trans_priv.h"
-#include "xfs_buf_item.h"
 #include "xfs_refcount_item.h"
 #include "xfs_log.h"
 #include "xfs_refcount.h"
@@ -94,15 +93,6 @@ xfs_cui_item_format(
                        xfs_cui_log_format_sizeof(cuip->cui_format.cui_nextents));
 }
 
-/*
- * Pinning has no meaning for an cui item, so just return.
- */
-STATIC void
-xfs_cui_item_pin(
-       struct xfs_log_item     *lip)
-{
-}
-
 /*
  * The unpin operation is the last place an CUI is manipulated in the log. It is
  * either inserted in the AIL or aborted in the event of a log I/O error. In
@@ -121,72 +111,23 @@ xfs_cui_item_unpin(
        xfs_cui_release(cuip);
 }
 
-/*
- * CUI items have no locking or pushing.  However, since CUIs are pulled from
- * the AIL when their corresponding CUDs are committed to disk, their situation
- * is very similar to being pinned.  Return XFS_ITEM_PINNED so that the caller
- * will eventually flush the log.  This should help in getting the CUI out of
- * the AIL.
- */
-STATIC uint
-xfs_cui_item_push(
-       struct xfs_log_item     *lip,
-       struct list_head        *buffer_list)
-{
-       return XFS_ITEM_PINNED;
-}
-
 /*
  * The CUI has been either committed or aborted if the transaction has been
  * cancelled. If the transaction was cancelled, an CUD isn't going to be
  * constructed and thus we free the CUI here directly.
  */
 STATIC void
-xfs_cui_item_unlock(
+xfs_cui_item_release(
        struct xfs_log_item     *lip)
 {
-       if (test_bit(XFS_LI_ABORTED, &lip->li_flags))
-               xfs_cui_release(CUI_ITEM(lip));
+       xfs_cui_release(CUI_ITEM(lip));
 }
 
-/*
- * The CUI is logged only once and cannot be moved in the log, so simply return
- * the lsn at which it's been logged.
- */
-STATIC xfs_lsn_t
-xfs_cui_item_committed(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
-{
-       return lsn;
-}
-
-/*
- * The CUI dependency tracking op doesn't do squat.  It can't because
- * it doesn't know where the free extent is coming from.  The dependency
- * tracking has to be handled by the "enclosing" metadata object.  For
- * example, for inodes, the inode is locked throughout the extent freeing
- * so the dependency should be recorded there.
- */
-STATIC void
-xfs_cui_item_committing(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
-{
-}
-
-/*
- * This is the ops vector shared by all cui log items.
- */
 static const struct xfs_item_ops xfs_cui_item_ops = {
        .iop_size       = xfs_cui_item_size,
        .iop_format     = xfs_cui_item_format,
-       .iop_pin        = xfs_cui_item_pin,
        .iop_unpin      = xfs_cui_item_unpin,
-       .iop_unlock     = xfs_cui_item_unlock,
-       .iop_committed  = xfs_cui_item_committed,
-       .iop_push       = xfs_cui_item_push,
-       .iop_committing = xfs_cui_item_committing,
+       .iop_release    = xfs_cui_item_release,
 };
 
 /*
@@ -254,126 +195,250 @@ xfs_cud_item_format(
 }
 
 /*
- * Pinning has no meaning for an cud item, so just return.
+ * The CUD is either committed or aborted if the transaction is cancelled. If
+ * the transaction is cancelled, drop our reference to the CUI and free the
+ * CUD.
  */
 STATIC void
-xfs_cud_item_pin(
+xfs_cud_item_release(
        struct xfs_log_item     *lip)
 {
+       struct xfs_cud_log_item *cudp = CUD_ITEM(lip);
+
+       xfs_cui_release(cudp->cud_cuip);
+       kmem_zone_free(xfs_cud_zone, cudp);
 }
 
-/*
- * Since pinning has no meaning for an cud item, unpinning does
- * not either.
- */
-STATIC void
-xfs_cud_item_unpin(
-       struct xfs_log_item     *lip,
-       int                     remove)
+static const struct xfs_item_ops xfs_cud_item_ops = {
+       .flags          = XFS_ITEM_RELEASE_WHEN_COMMITTED,
+       .iop_size       = xfs_cud_item_size,
+       .iop_format     = xfs_cud_item_format,
+       .iop_release    = xfs_cud_item_release,
+};
+
+static struct xfs_cud_log_item *
+xfs_trans_get_cud(
+       struct xfs_trans                *tp,
+       struct xfs_cui_log_item         *cuip)
 {
+       struct xfs_cud_log_item         *cudp;
+
+       cudp = kmem_zone_zalloc(xfs_cud_zone, KM_SLEEP);
+       xfs_log_item_init(tp->t_mountp, &cudp->cud_item, XFS_LI_CUD,
+                         &xfs_cud_item_ops);
+       cudp->cud_cuip = cuip;
+       cudp->cud_format.cud_cui_id = cuip->cui_format.cui_id;
+
+       xfs_trans_add_item(tp, &cudp->cud_item);
+       return cudp;
 }
 
 /*
- * There isn't much you can do to push on an cud item.  It is simply stuck
- * waiting for the log to be flushed to disk.
+ * Finish an refcount update and log it to the CUD. Note that the
+ * transaction is marked dirty regardless of whether the refcount
+ * update succeeds or fails to support the CUI/CUD lifecycle rules.
  */
-STATIC uint
-xfs_cud_item_push(
-       struct xfs_log_item     *lip,
-       struct list_head        *buffer_list)
+static int
+xfs_trans_log_finish_refcount_update(
+       struct xfs_trans                *tp,
+       struct xfs_cud_log_item         *cudp,
+       enum xfs_refcount_intent_type   type,
+       xfs_fsblock_t                   startblock,
+       xfs_extlen_t                    blockcount,
+       xfs_fsblock_t                   *new_fsb,
+       xfs_extlen_t                    *new_len,
+       struct xfs_btree_cur            **pcur)
 {
-       return XFS_ITEM_PINNED;
+       int                             error;
+
+       error = xfs_refcount_finish_one(tp, type, startblock,
+                       blockcount, new_fsb, new_len, pcur);
+
+       /*
+        * Mark the transaction dirty, even on error. This ensures the
+        * transaction is aborted, which:
+        *
+        * 1.) releases the CUI and frees the CUD
+        * 2.) shuts down the filesystem
+        */
+       tp->t_flags |= XFS_TRANS_DIRTY;
+       set_bit(XFS_LI_DIRTY, &cudp->cud_item.li_flags);
+
+       return error;
 }
 
-/*
- * The CUD is either committed or aborted if the transaction is cancelled. If
- * the transaction is cancelled, drop our reference to the CUI and free the
- * CUD.
- */
-STATIC void
-xfs_cud_item_unlock(
-       struct xfs_log_item     *lip)
+/* Sort refcount intents by AG. */
+static int
+xfs_refcount_update_diff_items(
+       void                            *priv,
+       struct list_head                *a,
+       struct list_head                *b)
 {
-       struct xfs_cud_log_item *cudp = CUD_ITEM(lip);
+       struct xfs_mount                *mp = priv;
+       struct xfs_refcount_intent      *ra;
+       struct xfs_refcount_intent      *rb;
+
+       ra = container_of(a, struct xfs_refcount_intent, ri_list);
+       rb = container_of(b, struct xfs_refcount_intent, ri_list);
+       return  XFS_FSB_TO_AGNO(mp, ra->ri_startblock) -
+               XFS_FSB_TO_AGNO(mp, rb->ri_startblock);
+}
 
-       if (test_bit(XFS_LI_ABORTED, &lip->li_flags)) {
-               xfs_cui_release(cudp->cud_cuip);
-               kmem_zone_free(xfs_cud_zone, cudp);
+/* Get an CUI. */
+STATIC void *
+xfs_refcount_update_create_intent(
+       struct xfs_trans                *tp,
+       unsigned int                    count)
+{
+       struct xfs_cui_log_item         *cuip;
+
+       ASSERT(tp != NULL);
+       ASSERT(count > 0);
+
+       cuip = xfs_cui_init(tp->t_mountp, count);
+       ASSERT(cuip != NULL);
+
+       /*
+        * Get a log_item_desc to point at the new item.
+        */
+       xfs_trans_add_item(tp, &cuip->cui_item);
+       return cuip;
+}
+
+/* Set the phys extent flags for this reverse mapping. */
+static void
+xfs_trans_set_refcount_flags(
+       struct xfs_phys_extent          *refc,
+       enum xfs_refcount_intent_type   type)
+{
+       refc->pe_flags = 0;
+       switch (type) {
+       case XFS_REFCOUNT_INCREASE:
+       case XFS_REFCOUNT_DECREASE:
+       case XFS_REFCOUNT_ALLOC_COW:
+       case XFS_REFCOUNT_FREE_COW:
+               refc->pe_flags |= type;
+               break;
+       default:
+               ASSERT(0);
        }
 }
 
-/*
- * When the cud item is committed to disk, all we need to do is delete our
- * reference to our partner cui item and then free ourselves. Since we're
- * freeing ourselves we must return -1 to keep the transaction code from
- * further referencing this item.
- */
-STATIC xfs_lsn_t
-xfs_cud_item_committed(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
+/* Log refcount updates in the intent item. */
+STATIC void
+xfs_refcount_update_log_item(
+       struct xfs_trans                *tp,
+       void                            *intent,
+       struct list_head                *item)
 {
-       struct xfs_cud_log_item *cudp = CUD_ITEM(lip);
+       struct xfs_cui_log_item         *cuip = intent;
+       struct xfs_refcount_intent      *refc;
+       uint                            next_extent;
+       struct xfs_phys_extent          *ext;
+
+       refc = container_of(item, struct xfs_refcount_intent, ri_list);
+
+       tp->t_flags |= XFS_TRANS_DIRTY;
+       set_bit(XFS_LI_DIRTY, &cuip->cui_item.li_flags);
 
        /*
-        * Drop the CUI reference regardless of whether the CUD has been
-        * aborted. Once the CUD transaction is constructed, it is the sole
-        * responsibility of the CUD to release the CUI (even if the CUI is
-        * aborted due to log I/O error).
+        * atomic_inc_return gives us the value after the increment;
+        * we want to use it as an array index so we need to subtract 1 from
+        * it.
         */
-       xfs_cui_release(cudp->cud_cuip);
-       kmem_zone_free(xfs_cud_zone, cudp);
+       next_extent = atomic_inc_return(&cuip->cui_next_extent) - 1;
+       ASSERT(next_extent < cuip->cui_format.cui_nextents);
+       ext = &cuip->cui_format.cui_extents[next_extent];
+       ext->pe_startblock = refc->ri_startblock;
+       ext->pe_len = refc->ri_blockcount;
+       xfs_trans_set_refcount_flags(ext, refc->ri_type);
+}
 
-       return (xfs_lsn_t)-1;
+/* Get an CUD so we can process all the deferred refcount updates. */
+STATIC void *
+xfs_refcount_update_create_done(
+       struct xfs_trans                *tp,
+       void                            *intent,
+       unsigned int                    count)
+{
+       return xfs_trans_get_cud(tp, intent);
 }
 
-/*
- * The CUD dependency tracking op doesn't do squat.  It can't because
- * it doesn't know where the free extent is coming from.  The dependency
- * tracking has to be handled by the "enclosing" metadata object.  For
- * example, for inodes, the inode is locked throughout the extent freeing
- * so the dependency should be recorded there.
- */
-STATIC void
-xfs_cud_item_committing(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
+/* Process a deferred refcount update. */
+STATIC int
+xfs_refcount_update_finish_item(
+       struct xfs_trans                *tp,
+       struct list_head                *item,
+       void                            *done_item,
+       void                            **state)
 {
+       struct xfs_refcount_intent      *refc;
+       xfs_fsblock_t                   new_fsb;
+       xfs_extlen_t                    new_aglen;
+       int                             error;
+
+       refc = container_of(item, struct xfs_refcount_intent, ri_list);
+       error = xfs_trans_log_finish_refcount_update(tp, done_item,
+                       refc->ri_type,
+                       refc->ri_startblock,
+                       refc->ri_blockcount,
+                       &new_fsb, &new_aglen,
+                       (struct xfs_btree_cur **)state);
+       /* Did we run out of reservation?  Requeue what we didn't finish. */
+       if (!error && new_aglen > 0) {
+               ASSERT(refc->ri_type == XFS_REFCOUNT_INCREASE ||
+                      refc->ri_type == XFS_REFCOUNT_DECREASE);
+               refc->ri_startblock = new_fsb;
+               refc->ri_blockcount = new_aglen;
+               return -EAGAIN;
+       }
+       kmem_free(refc);
+       return error;
 }
 
-/*
- * This is the ops vector shared by all cud log items.
- */
-static const struct xfs_item_ops xfs_cud_item_ops = {
-       .iop_size       = xfs_cud_item_size,
-       .iop_format     = xfs_cud_item_format,
-       .iop_pin        = xfs_cud_item_pin,
-       .iop_unpin      = xfs_cud_item_unpin,
-       .iop_unlock     = xfs_cud_item_unlock,
-       .iop_committed  = xfs_cud_item_committed,
-       .iop_push       = xfs_cud_item_push,
-       .iop_committing = xfs_cud_item_committing,
-};
+/* Clean up after processing deferred refcounts. */
+STATIC void
+xfs_refcount_update_finish_cleanup(
+       struct xfs_trans        *tp,
+       void                    *state,
+       int                     error)
+{
+       struct xfs_btree_cur    *rcur = state;
 
-/*
- * Allocate and initialize an cud item with the given number of extents.
- */
-struct xfs_cud_log_item *
-xfs_cud_init(
-       struct xfs_mount                *mp,
-       struct xfs_cui_log_item         *cuip)
+       xfs_refcount_finish_one_cleanup(tp, rcur, error);
+}
 
+/* Abort all pending CUIs. */
+STATIC void
+xfs_refcount_update_abort_intent(
+       void                            *intent)
 {
-       struct xfs_cud_log_item *cudp;
+       xfs_cui_release(intent);
+}
 
-       cudp = kmem_zone_zalloc(xfs_cud_zone, KM_SLEEP);
-       xfs_log_item_init(mp, &cudp->cud_item, XFS_LI_CUD, &xfs_cud_item_ops);
-       cudp->cud_cuip = cuip;
-       cudp->cud_format.cud_cui_id = cuip->cui_format.cui_id;
+/* Cancel a deferred refcount update. */
+STATIC void
+xfs_refcount_update_cancel_item(
+       struct list_head                *item)
+{
+       struct xfs_refcount_intent      *refc;
 
-       return cudp;
+       refc = container_of(item, struct xfs_refcount_intent, ri_list);
+       kmem_free(refc);
 }
 
+const struct xfs_defer_op_type xfs_refcount_update_defer_type = {
+       .max_items      = XFS_CUI_MAX_FAST_EXTENTS,
+       .diff_items     = xfs_refcount_update_diff_items,
+       .create_intent  = xfs_refcount_update_create_intent,
+       .abort_intent   = xfs_refcount_update_abort_intent,
+       .log_item       = xfs_refcount_update_log_item,
+       .create_done    = xfs_refcount_update_create_done,
+       .finish_item    = xfs_refcount_update_finish_item,
+       .finish_cleanup = xfs_refcount_update_finish_cleanup,
+       .cancel_item    = xfs_refcount_update_cancel_item,
+};
+
 /*
  * Process a refcount update intent item that was recovered from the log.
  * We need to update the refcountbt.
index 3896dcc..e47530f 100644 (file)
@@ -78,8 +78,6 @@ extern struct kmem_zone       *xfs_cui_zone;
 extern struct kmem_zone        *xfs_cud_zone;
 
 struct xfs_cui_log_item *xfs_cui_init(struct xfs_mount *, uint);
-struct xfs_cud_log_item *xfs_cud_init(struct xfs_mount *,
-               struct xfs_cui_log_item *);
 void xfs_cui_item_free(struct xfs_cui_log_item *);
 void xfs_cui_release(struct xfs_cui_log_item *);
 int xfs_cui_recover(struct xfs_trans *parent_tp, struct xfs_cui_log_item *cuip);
index 680ae76..c4ec7af 100644 (file)
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
 #include "xfs_defer.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
-#include "xfs_inode_item.h"
 #include "xfs_bmap.h"
 #include "xfs_bmap_util.h"
-#include "xfs_error.h"
-#include "xfs_dir2.h"
-#include "xfs_dir2_priv.h"
-#include "xfs_ioctl.h"
 #include "xfs_trace.h"
-#include "xfs_log.h"
 #include "xfs_icache.h"
-#include "xfs_pnfs.h"
 #include "xfs_btree.h"
 #include "xfs_refcount_btree.h"
 #include "xfs_refcount.h"
 #include "xfs_trans_space.h"
 #include "xfs_bit.h"
 #include "xfs_alloc.h"
-#include "xfs_quota_defs.h"
 #include "xfs_quota.h"
 #include "xfs_reflink.h"
 #include "xfs_iomap.h"
-#include "xfs_rmap_btree.h"
 #include "xfs_sb.h"
 #include "xfs_ag_resv.h"
 
@@ -572,7 +561,7 @@ xfs_reflink_cancel_cow_range(
 
        /* Start a rolling transaction to remove the mappings */
        error = xfs_trans_alloc(ip->i_mount, &M_RES(ip->i_mount)->tr_write,
-                       0, 0, XFS_TRANS_NOFS, &tp);
+                       0, 0, 0, &tp);
        if (error)
                goto out;
 
@@ -631,7 +620,7 @@ xfs_reflink_end_cow_extent(
 
        resblks = XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK);
        error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0,
-                       XFS_TRANS_RESERVE | XFS_TRANS_NOFS, &tp);
+                       XFS_TRANS_RESERVE, &tp);
        if (error)
                return error;
 
index 127dc9c..77ed557 100644 (file)
@@ -14,7 +14,6 @@
 #include "xfs_defer.h"
 #include "xfs_trans.h"
 #include "xfs_trans_priv.h"
-#include "xfs_buf_item.h"
 #include "xfs_rmap_item.h"
 #include "xfs_log.h"
 #include "xfs_rmap.h"
@@ -93,15 +92,6 @@ xfs_rui_item_format(
                        xfs_rui_log_format_sizeof(ruip->rui_format.rui_nextents));
 }
 
-/*
- * Pinning has no meaning for an rui item, so just return.
- */
-STATIC void
-xfs_rui_item_pin(
-       struct xfs_log_item     *lip)
-{
-}
-
 /*
  * The unpin operation is the last place an RUI is manipulated in the log. It is
  * either inserted in the AIL or aborted in the event of a log I/O error. In
@@ -120,72 +110,23 @@ xfs_rui_item_unpin(
        xfs_rui_release(ruip);
 }
 
-/*
- * RUI items have no locking or pushing.  However, since RUIs are pulled from
- * the AIL when their corresponding RUDs are committed to disk, their situation
- * is very similar to being pinned.  Return XFS_ITEM_PINNED so that the caller
- * will eventually flush the log.  This should help in getting the RUI out of
- * the AIL.
- */
-STATIC uint
-xfs_rui_item_push(
-       struct xfs_log_item     *lip,
-       struct list_head        *buffer_list)
-{
-       return XFS_ITEM_PINNED;
-}
-
 /*
  * The RUI has been either committed or aborted if the transaction has been
  * cancelled. If the transaction was cancelled, an RUD isn't going to be
  * constructed and thus we free the RUI here directly.
  */
 STATIC void
-xfs_rui_item_unlock(
+xfs_rui_item_release(
        struct xfs_log_item     *lip)
 {
-       if (test_bit(XFS_LI_ABORTED, &lip->li_flags))
-               xfs_rui_release(RUI_ITEM(lip));
+       xfs_rui_release(RUI_ITEM(lip));
 }
 
-/*
- * The RUI is logged only once and cannot be moved in the log, so simply return
- * the lsn at which it's been logged.
- */
-STATIC xfs_lsn_t
-xfs_rui_item_committed(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
-{
-       return lsn;
-}
-
-/*
- * The RUI dependency tracking op doesn't do squat.  It can't because
- * it doesn't know where the free extent is coming from.  The dependency
- * tracking has to be handled by the "enclosing" metadata object.  For
- * example, for inodes, the inode is locked throughout the extent freeing
- * so the dependency should be recorded there.
- */
-STATIC void
-xfs_rui_item_committing(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
-{
-}
-
-/*
- * This is the ops vector shared by all rui log items.
- */
 static const struct xfs_item_ops xfs_rui_item_ops = {
        .iop_size       = xfs_rui_item_size,
        .iop_format     = xfs_rui_item_format,
-       .iop_pin        = xfs_rui_item_pin,
        .iop_unpin      = xfs_rui_item_unpin,
-       .iop_unlock     = xfs_rui_item_unlock,
-       .iop_committed  = xfs_rui_item_committed,
-       .iop_push       = xfs_rui_item_push,
-       .iop_committing = xfs_rui_item_committing,
+       .iop_release    = xfs_rui_item_release,
 };
 
 /*
@@ -275,126 +216,271 @@ xfs_rud_item_format(
 }
 
 /*
- * Pinning has no meaning for an rud item, so just return.
+ * The RUD is either committed or aborted if the transaction is cancelled. If
+ * the transaction is cancelled, drop our reference to the RUI and free the
+ * RUD.
  */
 STATIC void
-xfs_rud_item_pin(
+xfs_rud_item_release(
        struct xfs_log_item     *lip)
 {
+       struct xfs_rud_log_item *rudp = RUD_ITEM(lip);
+
+       xfs_rui_release(rudp->rud_ruip);
+       kmem_zone_free(xfs_rud_zone, rudp);
 }
 
-/*
- * Since pinning has no meaning for an rud item, unpinning does
- * not either.
- */
-STATIC void
-xfs_rud_item_unpin(
-       struct xfs_log_item     *lip,
-       int                     remove)
+static const struct xfs_item_ops xfs_rud_item_ops = {
+       .flags          = XFS_ITEM_RELEASE_WHEN_COMMITTED,
+       .iop_size       = xfs_rud_item_size,
+       .iop_format     = xfs_rud_item_format,
+       .iop_release    = xfs_rud_item_release,
+};
+
+static struct xfs_rud_log_item *
+xfs_trans_get_rud(
+       struct xfs_trans                *tp,
+       struct xfs_rui_log_item         *ruip)
 {
+       struct xfs_rud_log_item         *rudp;
+
+       rudp = kmem_zone_zalloc(xfs_rud_zone, KM_SLEEP);
+       xfs_log_item_init(tp->t_mountp, &rudp->rud_item, XFS_LI_RUD,
+                         &xfs_rud_item_ops);
+       rudp->rud_ruip = ruip;
+       rudp->rud_format.rud_rui_id = ruip->rui_format.rui_id;
+
+       xfs_trans_add_item(tp, &rudp->rud_item);
+       return rudp;
 }
 
-/*
- * There isn't much you can do to push on an rud item.  It is simply stuck
- * waiting for the log to be flushed to disk.
- */
-STATIC uint
-xfs_rud_item_push(
-       struct xfs_log_item     *lip,
-       struct list_head        *buffer_list)
+/* Set the map extent flags for this reverse mapping. */
+static void
+xfs_trans_set_rmap_flags(
+       struct xfs_map_extent           *rmap,
+       enum xfs_rmap_intent_type       type,
+       int                             whichfork,
+       xfs_exntst_t                    state)
 {
-       return XFS_ITEM_PINNED;
+       rmap->me_flags = 0;
+       if (state == XFS_EXT_UNWRITTEN)
+               rmap->me_flags |= XFS_RMAP_EXTENT_UNWRITTEN;
+       if (whichfork == XFS_ATTR_FORK)
+               rmap->me_flags |= XFS_RMAP_EXTENT_ATTR_FORK;
+       switch (type) {
+       case XFS_RMAP_MAP:
+               rmap->me_flags |= XFS_RMAP_EXTENT_MAP;
+               break;
+       case XFS_RMAP_MAP_SHARED:
+               rmap->me_flags |= XFS_RMAP_EXTENT_MAP_SHARED;
+               break;
+       case XFS_RMAP_UNMAP:
+               rmap->me_flags |= XFS_RMAP_EXTENT_UNMAP;
+               break;
+       case XFS_RMAP_UNMAP_SHARED:
+               rmap->me_flags |= XFS_RMAP_EXTENT_UNMAP_SHARED;
+               break;
+       case XFS_RMAP_CONVERT:
+               rmap->me_flags |= XFS_RMAP_EXTENT_CONVERT;
+               break;
+       case XFS_RMAP_CONVERT_SHARED:
+               rmap->me_flags |= XFS_RMAP_EXTENT_CONVERT_SHARED;
+               break;
+       case XFS_RMAP_ALLOC:
+               rmap->me_flags |= XFS_RMAP_EXTENT_ALLOC;
+               break;
+       case XFS_RMAP_FREE:
+               rmap->me_flags |= XFS_RMAP_EXTENT_FREE;
+               break;
+       default:
+               ASSERT(0);
+       }
 }
 
 /*
- * The RUD is either committed or aborted if the transaction is cancelled. If
- * the transaction is cancelled, drop our reference to the RUI and free the
- * RUD.
+ * Finish an rmap update and log it to the RUD. Note that the transaction is
+ * marked dirty regardless of whether the rmap update succeeds or fails to
+ * support the RUI/RUD lifecycle rules.
  */
-STATIC void
-xfs_rud_item_unlock(
-       struct xfs_log_item     *lip)
+static int
+xfs_trans_log_finish_rmap_update(
+       struct xfs_trans                *tp,
+       struct xfs_rud_log_item         *rudp,
+       enum xfs_rmap_intent_type       type,
+       uint64_t                        owner,
+       int                             whichfork,
+       xfs_fileoff_t                   startoff,
+       xfs_fsblock_t                   startblock,
+       xfs_filblks_t                   blockcount,
+       xfs_exntst_t                    state,
+       struct xfs_btree_cur            **pcur)
 {
-       struct xfs_rud_log_item *rudp = RUD_ITEM(lip);
+       int                             error;
 
-       if (test_bit(XFS_LI_ABORTED, &lip->li_flags)) {
-               xfs_rui_release(rudp->rud_ruip);
-               kmem_zone_free(xfs_rud_zone, rudp);
-       }
+       error = xfs_rmap_finish_one(tp, type, owner, whichfork, startoff,
+                       startblock, blockcount, state, pcur);
+
+       /*
+        * Mark the transaction dirty, even on error. This ensures the
+        * transaction is aborted, which:
+        *
+        * 1.) releases the RUI and frees the RUD
+        * 2.) shuts down the filesystem
+        */
+       tp->t_flags |= XFS_TRANS_DIRTY;
+       set_bit(XFS_LI_DIRTY, &rudp->rud_item.li_flags);
+
+       return error;
 }
 
-/*
- * When the rud item is committed to disk, all we need to do is delete our
- * reference to our partner rui item and then free ourselves. Since we're
- * freeing ourselves we must return -1 to keep the transaction code from
- * further referencing this item.
- */
-STATIC xfs_lsn_t
-xfs_rud_item_committed(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
+/* Sort rmap intents by AG. */
+static int
+xfs_rmap_update_diff_items(
+       void                            *priv,
+       struct list_head                *a,
+       struct list_head                *b)
 {
-       struct xfs_rud_log_item *rudp = RUD_ITEM(lip);
+       struct xfs_mount                *mp = priv;
+       struct xfs_rmap_intent          *ra;
+       struct xfs_rmap_intent          *rb;
+
+       ra = container_of(a, struct xfs_rmap_intent, ri_list);
+       rb = container_of(b, struct xfs_rmap_intent, ri_list);
+       return  XFS_FSB_TO_AGNO(mp, ra->ri_bmap.br_startblock) -
+               XFS_FSB_TO_AGNO(mp, rb->ri_bmap.br_startblock);
+}
+
+/* Get an RUI. */
+STATIC void *
+xfs_rmap_update_create_intent(
+       struct xfs_trans                *tp,
+       unsigned int                    count)
+{
+       struct xfs_rui_log_item         *ruip;
+
+       ASSERT(tp != NULL);
+       ASSERT(count > 0);
+
+       ruip = xfs_rui_init(tp->t_mountp, count);
+       ASSERT(ruip != NULL);
 
        /*
-        * Drop the RUI reference regardless of whether the RUD has been
-        * aborted. Once the RUD transaction is constructed, it is the sole
-        * responsibility of the RUD to release the RUI (even if the RUI is
-        * aborted due to log I/O error).
+        * Get a log_item_desc to point at the new item.
         */
-       xfs_rui_release(rudp->rud_ruip);
-       kmem_zone_free(xfs_rud_zone, rudp);
-
-       return (xfs_lsn_t)-1;
+       xfs_trans_add_item(tp, &ruip->rui_item);
+       return ruip;
 }
 
-/*
- * The RUD dependency tracking op doesn't do squat.  It can't because
- * it doesn't know where the free extent is coming from.  The dependency
- * tracking has to be handled by the "enclosing" metadata object.  For
- * example, for inodes, the inode is locked throughout the extent freeing
- * so the dependency should be recorded there.
- */
+/* Log rmap updates in the intent item. */
 STATIC void
-xfs_rud_item_committing(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               lsn)
+xfs_rmap_update_log_item(
+       struct xfs_trans                *tp,
+       void                            *intent,
+       struct list_head                *item)
 {
+       struct xfs_rui_log_item         *ruip = intent;
+       struct xfs_rmap_intent          *rmap;
+       uint                            next_extent;
+       struct xfs_map_extent           *map;
+
+       rmap = container_of(item, struct xfs_rmap_intent, ri_list);
+
+       tp->t_flags |= XFS_TRANS_DIRTY;
+       set_bit(XFS_LI_DIRTY, &ruip->rui_item.li_flags);
+
+       /*
+        * atomic_inc_return gives us the value after the increment;
+        * we want to use it as an array index so we need to subtract 1 from
+        * it.
+        */
+       next_extent = atomic_inc_return(&ruip->rui_next_extent) - 1;
+       ASSERT(next_extent < ruip->rui_format.rui_nextents);
+       map = &ruip->rui_format.rui_extents[next_extent];
+       map->me_owner = rmap->ri_owner;
+       map->me_startblock = rmap->ri_bmap.br_startblock;
+       map->me_startoff = rmap->ri_bmap.br_startoff;
+       map->me_len = rmap->ri_bmap.br_blockcount;
+       xfs_trans_set_rmap_flags(map, rmap->ri_type, rmap->ri_whichfork,
+                       rmap->ri_bmap.br_state);
 }
 
-/*
- * This is the ops vector shared by all rud log items.
- */
-static const struct xfs_item_ops xfs_rud_item_ops = {
-       .iop_size       = xfs_rud_item_size,
-       .iop_format     = xfs_rud_item_format,
-       .iop_pin        = xfs_rud_item_pin,
-       .iop_unpin      = xfs_rud_item_unpin,
-       .iop_unlock     = xfs_rud_item_unlock,
-       .iop_committed  = xfs_rud_item_committed,
-       .iop_push       = xfs_rud_item_push,
-       .iop_committing = xfs_rud_item_committing,
-};
+/* Get an RUD so we can process all the deferred rmap updates. */
+STATIC void *
+xfs_rmap_update_create_done(
+       struct xfs_trans                *tp,
+       void                            *intent,
+       unsigned int                    count)
+{
+       return xfs_trans_get_rud(tp, intent);
+}
 
-/*
- * Allocate and initialize an rud item with the given number of extents.
- */
-struct xfs_rud_log_item *
-xfs_rud_init(
-       struct xfs_mount                *mp,
-       struct xfs_rui_log_item         *ruip)
+/* Process a deferred rmap update. */
+STATIC int
+xfs_rmap_update_finish_item(
+       struct xfs_trans                *tp,
+       struct list_head                *item,
+       void                            *done_item,
+       void                            **state)
+{
+       struct xfs_rmap_intent          *rmap;
+       int                             error;
+
+       rmap = container_of(item, struct xfs_rmap_intent, ri_list);
+       error = xfs_trans_log_finish_rmap_update(tp, done_item,
+                       rmap->ri_type,
+                       rmap->ri_owner, rmap->ri_whichfork,
+                       rmap->ri_bmap.br_startoff,
+                       rmap->ri_bmap.br_startblock,
+                       rmap->ri_bmap.br_blockcount,
+                       rmap->ri_bmap.br_state,
+                       (struct xfs_btree_cur **)state);
+       kmem_free(rmap);
+       return error;
+}
+
+/* Clean up after processing deferred rmaps. */
+STATIC void
+xfs_rmap_update_finish_cleanup(
+       struct xfs_trans        *tp,
+       void                    *state,
+       int                     error)
+{
+       struct xfs_btree_cur    *rcur = state;
+
+       xfs_rmap_finish_one_cleanup(tp, rcur, error);
+}
 
+/* Abort all pending RUIs. */
+STATIC void
+xfs_rmap_update_abort_intent(
+       void                            *intent)
 {
-       struct xfs_rud_log_item *rudp;
+       xfs_rui_release(intent);
+}
 
-       rudp = kmem_zone_zalloc(xfs_rud_zone, KM_SLEEP);
-       xfs_log_item_init(mp, &rudp->rud_item, XFS_LI_RUD, &xfs_rud_item_ops);
-       rudp->rud_ruip = ruip;
-       rudp->rud_format.rud_rui_id = ruip->rui_format.rui_id;
+/* Cancel a deferred rmap update. */
+STATIC void
+xfs_rmap_update_cancel_item(
+       struct list_head                *item)
+{
+       struct xfs_rmap_intent          *rmap;
 
-       return rudp;
+       rmap = container_of(item, struct xfs_rmap_intent, ri_list);
+       kmem_free(rmap);
 }
 
+const struct xfs_defer_op_type xfs_rmap_update_defer_type = {
+       .max_items      = XFS_RUI_MAX_FAST_EXTENTS,
+       .diff_items     = xfs_rmap_update_diff_items,
+       .create_intent  = xfs_rmap_update_create_intent,
+       .abort_intent   = xfs_rmap_update_abort_intent,
+       .log_item       = xfs_rmap_update_log_item,
+       .create_done    = xfs_rmap_update_create_done,
+       .finish_item    = xfs_rmap_update_finish_item,
+       .finish_cleanup = xfs_rmap_update_finish_cleanup,
+       .cancel_item    = xfs_rmap_update_cancel_item,
+};
+
 /*
  * Process an rmap update intent item that was recovered from the log.
  * We need to update the rmapbt.
index 7e482ba..8708e4a 100644 (file)
@@ -78,8 +78,6 @@ extern struct kmem_zone       *xfs_rui_zone;
 extern struct kmem_zone        *xfs_rud_zone;
 
 struct xfs_rui_log_item *xfs_rui_init(struct xfs_mount *, uint);
-struct xfs_rud_log_item *xfs_rud_init(struct xfs_mount *,
-               struct xfs_rui_log_item *);
 int xfs_rui_copy_format(struct xfs_log_iovec *buf,
                struct xfs_rui_log_format *dst_rui_fmt);
 void xfs_rui_item_free(struct xfs_rui_log_item *);
index ac0fcda..5fa4db3 100644 (file)
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
 #include "xfs_mount.h"
-#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_bmap.h"
-#include "xfs_bmap_util.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc.h"
-#include "xfs_error.h"
 #include "xfs_trans.h"
 #include "xfs_trans_space.h"
-#include "xfs_trace.h"
-#include "xfs_buf.h"
 #include "xfs_icache.h"
 #include "xfs_rtalloc.h"
 
index cc50974..113883c 100644 (file)
@@ -4,7 +4,6 @@
  * All Rights Reserved.
  */
 #include "xfs.h"
-#include <linux/proc_fs.h>
 
 struct xstats xfsstats;
 
index a14d11d..f945023 100644 (file)
 #include "xfs_trans_resv.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
-#include "xfs_da_format.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
 #include "xfs_bmap.h"
 #include "xfs_alloc.h"
-#include "xfs_error.h"
 #include "xfs_fsops.h"
 #include "xfs_trans.h"
 #include "xfs_buf_item.h"
 #include "xfs_log.h"
 #include "xfs_log_priv.h"
-#include "xfs_da_btree.h"
 #include "xfs_dir2.h"
 #include "xfs_extfree_item.h"
 #include "xfs_mru_cache.h"
 #include "xfs_refcount_item.h"
 #include "xfs_bmap_item.h"
 #include "xfs_reflink.h"
-#include "xfs_defer.h"
 
-#include <linux/namei.h>
-#include <linux/dax.h>
-#include <linux/init.h>
-#include <linux/slab.h>
 #include <linux/magic.h>
-#include <linux/mount.h>
-#include <linux/mempool.h>
-#include <linux/writeback.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
 #include <linux/parser.h>
 
 static const struct super_operations xfs_super_operations;
@@ -582,7 +569,7 @@ xfs_set_inode_alloc(
         * Calculate how much should be reserved for inodes to meet
         * the max inode percentage.  Used only for inode32.
         */
-       if (mp->m_maxicount) {
+       if (M_IGEO(mp)->maxicount) {
                uint64_t        icount;
 
                icount = sbp->sb_dblocks * sbp->sb_imax_pct;
@@ -840,16 +827,10 @@ xfs_init_mount_workqueues(
        if (!mp->m_reclaim_workqueue)
                goto out_destroy_cil;
 
-       mp->m_log_workqueue = alloc_workqueue("xfs-log/%s",
-                       WQ_MEM_RECLAIM|WQ_FREEZABLE|WQ_HIGHPRI, 0,
-                       mp->m_fsname);
-       if (!mp->m_log_workqueue)
-               goto out_destroy_reclaim;
-
        mp->m_eofblocks_workqueue = alloc_workqueue("xfs-eofblocks/%s",
                        WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_fsname);
        if (!mp->m_eofblocks_workqueue)
-               goto out_destroy_log;
+               goto out_destroy_reclaim;
 
        mp->m_sync_workqueue = alloc_workqueue("xfs-sync/%s", WQ_FREEZABLE, 0,
                                               mp->m_fsname);
@@ -860,8 +841,6 @@ xfs_init_mount_workqueues(
 
 out_destroy_eofb:
        destroy_workqueue(mp->m_eofblocks_workqueue);
-out_destroy_log:
-       destroy_workqueue(mp->m_log_workqueue);
 out_destroy_reclaim:
        destroy_workqueue(mp->m_reclaim_workqueue);
 out_destroy_cil:
@@ -880,7 +859,6 @@ xfs_destroy_mount_workqueues(
 {
        destroy_workqueue(mp->m_sync_workqueue);
        destroy_workqueue(mp->m_eofblocks_workqueue);
-       destroy_workqueue(mp->m_log_workqueue);
        destroy_workqueue(mp->m_reclaim_workqueue);
        destroy_workqueue(mp->m_cil_workqueue);
        destroy_workqueue(mp->m_unwritten_workqueue);
@@ -1131,10 +1109,10 @@ xfs_fs_statfs(
 
        fakeinos = XFS_FSB_TO_INO(mp, statp->f_bfree);
        statp->f_files = min(icount + fakeinos, (uint64_t)XFS_MAXINUMBER);
-       if (mp->m_maxicount)
+       if (M_IGEO(mp)->maxicount)
                statp->f_files = min_t(typeof(statp->f_files),
                                        statp->f_files,
-                                       mp->m_maxicount);
+                                       M_IGEO(mp)->maxicount);
 
        /* If sb_icount overshot maxicount, report actual allocation */
        statp->f_files = max_t(typeof(statp->f_files),
@@ -1685,6 +1663,8 @@ xfs_fs_fill_super(
        sb->s_maxbytes = xfs_max_file_offset(sb->s_blocksize_bits);
        sb->s_max_links = XFS_MAXLINK;
        sb->s_time_gran = 1;
+       sb->s_iflags |= SB_I_CGROUPWB;
+
        set_posix_acl_flag(sb);
 
        /* version 5 superblocks support inode version counters. */
index 21cb49a..763e43d 100644 (file)
@@ -38,6 +38,18 @@ extern void xfs_qm_exit(void);
 # define XFS_SCRUB_STRING
 #endif
 
+#ifdef CONFIG_XFS_ONLINE_REPAIR
+# define XFS_REPAIR_STRING     "repair, "
+#else
+# define XFS_REPAIR_STRING
+#endif
+
+#ifdef CONFIG_XFS_WARN
+# define XFS_WARN_STRING       "verbose warnings, "
+#else
+# define XFS_WARN_STRING
+#endif
+
 #ifdef DEBUG
 # define XFS_DBG_STRING                "debug"
 #else
@@ -49,6 +61,8 @@ extern void xfs_qm_exit(void);
                                XFS_SECURITY_STRING \
                                XFS_REALTIME_STRING \
                                XFS_SCRUB_STRING \
+                               XFS_REPAIR_STRING \
+                               XFS_WARN_STRING \
                                XFS_DBG_STRING /* DBG must be last */
 
 struct xfs_inode;
index b2c1177..ed66fd2 100644 (file)
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
 #include "xfs_mount.h"
-#include "xfs_da_format.h"
-#include "xfs_da_btree.h"
-#include "xfs_defer.h"
 #include "xfs_dir2.h"
 #include "xfs_inode.h"
-#include "xfs_ialloc.h"
-#include "xfs_alloc.h"
 #include "xfs_bmap.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_bmap_util.h"
-#include "xfs_error.h"
 #include "xfs_quota.h"
 #include "xfs_trans_space.h"
 #include "xfs_trace.h"
-#include "xfs_symlink.h"
 #include "xfs_trans.h"
-#include "xfs_log.h"
 
 /* ----- Kernel only functions below ----- */
 int
index 0cc034d..31b3bdb 100644 (file)
@@ -4,10 +4,7 @@
  * All Rights Reserved.
  */
 #include "xfs.h"
-#include <linux/sysctl.h>
-#include <linux/proc_fs.h>
 #include "xfs_error.h"
-#include "xfs_stats.h"
 
 static struct ctl_table_header *xfs_table_header;
 
index ad7f9be..8abf464 100644 (file)
@@ -82,6 +82,9 @@ enum {
 extern xfs_param_t     xfs_params;
 
 struct xfs_globals {
+#ifdef DEBUG
+       int     pwork_threads;          /* parallel workqueue threads */
+#endif
        int     log_recovery_delay;     /* log recovery delay (secs) */
        int     mount_delay;            /* mount setup delay (secs) */
        bool    bug_on_assert;          /* BUG() the kernel on assert failure */
index cabda13..ddd0bf7 100644 (file)
@@ -10,9 +10,7 @@
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_sysfs.h"
-#include "xfs_log.h"
 #include "xfs_log_priv.h"
-#include "xfs_stats.h"
 #include "xfs_mount.h"
 
 struct xfs_sysfs_attr {
@@ -206,11 +204,51 @@ always_cow_show(
 }
 XFS_SYSFS_ATTR_RW(always_cow);
 
+#ifdef DEBUG
+/*
+ * Override how many threads the parallel work queue is allowed to create.
+ * This has to be a debug-only global (instead of an errortag) because one of
+ * the main users of parallel workqueues is mount time quotacheck.
+ */
+STATIC ssize_t
+pwork_threads_store(
+       struct kobject  *kobject,
+       const char      *buf,
+       size_t          count)
+{
+       int             ret;
+       int             val;
+
+       ret = kstrtoint(buf, 0, &val);
+       if (ret)
+               return ret;
+
+       if (val < -1 || val > num_possible_cpus())
+               return -EINVAL;
+
+       xfs_globals.pwork_threads = val;
+
+       return count;
+}
+
+STATIC ssize_t
+pwork_threads_show(
+       struct kobject  *kobject,
+       char            *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", xfs_globals.pwork_threads);
+}
+XFS_SYSFS_ATTR_RW(pwork_threads);
+#endif /* DEBUG */
+
 static struct attribute *xfs_dbg_attrs[] = {
        ATTR_LIST(bug_on_assert),
        ATTR_LIST(log_recovery_delay),
        ATTR_LIST(mount_delay),
        ATTR_LIST(always_cow),
+#ifdef DEBUG
+       ATTR_LIST(pwork_threads),
+#endif
        NULL,
 };
 
index cb6489c..bc85b89 100644 (file)
 #include "xfs_inode.h"
 #include "xfs_btree.h"
 #include "xfs_da_btree.h"
-#include "xfs_ialloc.h"
-#include "xfs_itable.h"
 #include "xfs_alloc.h"
 #include "xfs_bmap.h"
 #include "xfs_attr.h"
-#include "xfs_attr_leaf.h"
 #include "xfs_trans.h"
-#include "xfs_log.h"
 #include "xfs_log_priv.h"
 #include "xfs_buf_item.h"
 #include "xfs_quota.h"
-#include "xfs_iomap.h"
-#include "xfs_aops.h"
 #include "xfs_dquot_item.h"
 #include "xfs_dquot.h"
 #include "xfs_log_recover.h"
-#include "xfs_inode_item.h"
-#include "xfs_bmap_btree.h"
 #include "xfs_filestream.h"
 #include "xfs_fsmap.h"
 
index 2464ea3..8094b19 100644 (file)
@@ -475,7 +475,7 @@ DEFINE_BUF_ITEM_EVENT(xfs_buf_item_ordered);
 DEFINE_BUF_ITEM_EVENT(xfs_buf_item_pin);
 DEFINE_BUF_ITEM_EVENT(xfs_buf_item_unpin);
 DEFINE_BUF_ITEM_EVENT(xfs_buf_item_unpin_stale);
-DEFINE_BUF_ITEM_EVENT(xfs_buf_item_unlock);
+DEFINE_BUF_ITEM_EVENT(xfs_buf_item_release);
 DEFINE_BUF_ITEM_EVENT(xfs_buf_item_committed);
 DEFINE_BUF_ITEM_EVENT(xfs_buf_item_push);
 DEFINE_BUF_ITEM_EVENT(xfs_trans_get_buf);
@@ -3360,6 +3360,7 @@ DEFINE_TRANS_EVENT(xfs_trans_dup);
 DEFINE_TRANS_EVENT(xfs_trans_free);
 DEFINE_TRANS_EVENT(xfs_trans_roll);
 DEFINE_TRANS_EVENT(xfs_trans_add_item);
+DEFINE_TRANS_EVENT(xfs_trans_commit_items);
 DEFINE_TRANS_EVENT(xfs_trans_free_items);
 
 TRACE_EVENT(xfs_iunlink_update_bucket,
@@ -3516,6 +3517,64 @@ DEFINE_EVENT(xfs_inode_corrupt_class, name,      \
 DEFINE_INODE_CORRUPT_EVENT(xfs_inode_mark_sick);
 DEFINE_INODE_CORRUPT_EVENT(xfs_inode_mark_healthy);
 
+TRACE_EVENT(xfs_iwalk_ag,
+       TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno,
+                xfs_agino_t startino),
+       TP_ARGS(mp, agno, startino),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(xfs_agnumber_t, agno)
+               __field(xfs_agino_t, startino)
+       ),
+       TP_fast_assign(
+               __entry->dev = mp->m_super->s_dev;
+               __entry->agno = agno;
+               __entry->startino = startino;
+       ),
+       TP_printk("dev %d:%d agno %d startino %u",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->agno,
+                 __entry->startino)
+)
+
+TRACE_EVENT(xfs_iwalk_ag_rec,
+       TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno,
+                struct xfs_inobt_rec_incore *irec),
+       TP_ARGS(mp, agno, irec),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(xfs_agnumber_t, agno)
+               __field(xfs_agino_t, startino)
+               __field(uint64_t, freemask)
+       ),
+       TP_fast_assign(
+               __entry->dev = mp->m_super->s_dev;
+               __entry->agno = agno;
+               __entry->startino = irec->ir_startino;
+               __entry->freemask = irec->ir_free;
+       ),
+       TP_printk("dev %d:%d agno %d startino %u freemask 0x%llx",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->agno,
+                 __entry->startino, __entry->freemask)
+)
+
+TRACE_EVENT(xfs_pwork_init,
+       TP_PROTO(struct xfs_mount *mp, unsigned int nr_threads, pid_t pid),
+       TP_ARGS(mp, nr_threads, pid),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(unsigned int, nr_threads)
+               __field(pid_t, pid)
+       ),
+       TP_fast_assign(
+               __entry->dev = mp->m_super->s_dev;
+               __entry->nr_threads = nr_threads;
+               __entry->pid = pid;
+       ),
+       TP_printk("dev %d:%d nr_threads %u pid %u",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->nr_threads, __entry->pid)
+)
+
 #endif /* _TRACE_XFS_H */
 
 #undef TRACE_INCLUDE_PATH
index 912b42f..d42a68d 100644 (file)
@@ -11,7 +11,6 @@
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_inode.h"
 #include "xfs_extent_busy.h"
 #include "xfs_quota.h"
 #include "xfs_trans.h"
@@ -264,9 +263,7 @@ xfs_trans_alloc(
         * GFP_NOFS allocation context so that we avoid lockdep false positives
         * by doing GFP_KERNEL allocations inside sb_start_intwrite().
         */
-       tp = kmem_zone_zalloc(xfs_trans_zone,
-               (flags & XFS_TRANS_NOFS) ? KM_NOFS : KM_SLEEP);
-
+       tp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP);
        if (!(flags & XFS_TRANS_NO_WRITECOUNT))
                sb_start_intwrite(mp->m_super);
 
@@ -452,7 +449,7 @@ xfs_trans_apply_sb_deltas(
        xfs_buf_t       *bp;
        int             whole = 0;
 
-       bp = xfs_trans_getsb(tp, tp->t_mountp, 0);
+       bp = xfs_trans_getsb(tp, tp->t_mountp);
        sbp = XFS_BUF_TO_SBP(bp);
 
        /*
@@ -767,10 +764,9 @@ xfs_trans_del_item(
 }
 
 /* Detach and unlock all of the items in a transaction */
-void
+static void
 xfs_trans_free_items(
        struct xfs_trans        *tp,
-       xfs_lsn_t               commit_lsn,
        bool                    abort)
 {
        struct xfs_log_item     *lip, *next;
@@ -779,11 +775,10 @@ xfs_trans_free_items(
 
        list_for_each_entry_safe(lip, next, &tp->t_items, li_trans) {
                xfs_trans_del_item(lip);
-               if (commit_lsn != NULLCOMMITLSN)
-                       lip->li_ops->iop_committing(lip, commit_lsn);
                if (abort)
                        set_bit(XFS_LI_ABORTED, &lip->li_flags);
-               lip->li_ops->iop_unlock(lip);
+               if (lip->li_ops->iop_release)
+                       lip->li_ops->iop_release(lip);
        }
 }
 
@@ -804,7 +799,8 @@ xfs_log_item_batch_insert(
        for (i = 0; i < nr_items; i++) {
                struct xfs_log_item *lip = log_items[i];
 
-               lip->li_ops->iop_unpin(lip, 0);
+               if (lip->li_ops->iop_unpin)
+                       lip->li_ops->iop_unpin(lip, 0);
        }
 }
 
@@ -815,7 +811,7 @@ xfs_log_item_batch_insert(
  *
  * If we are called with the aborted flag set, it is because a log write during
  * a CIL checkpoint commit has failed. In this case, all the items in the
- * checkpoint have already gone through iop_commited and iop_unlock, which
+ * checkpoint have already gone through iop_committed and iop_committing, which
  * means that checkpoint commit abort handling is treated exactly the same
  * as an iclog write error even though we haven't started any IO yet. Hence in
  * this case all we need to do is iop_committed processing, followed by an
@@ -833,7 +829,7 @@ xfs_trans_committed_bulk(
        struct xfs_ail          *ailp,
        struct xfs_log_vec      *log_vector,
        xfs_lsn_t               commit_lsn,
-       int                     aborted)
+       bool                    aborted)
 {
 #define LOG_ITEM_BATCH_SIZE    32
        struct xfs_log_item     *log_items[LOG_ITEM_BATCH_SIZE];
@@ -852,7 +848,16 @@ xfs_trans_committed_bulk(
 
                if (aborted)
                        set_bit(XFS_LI_ABORTED, &lip->li_flags);
-               item_lsn = lip->li_ops->iop_committed(lip, commit_lsn);
+
+               if (lip->li_ops->flags & XFS_ITEM_RELEASE_WHEN_COMMITTED) {
+                       lip->li_ops->iop_release(lip);
+                       continue;
+               }
+
+               if (lip->li_ops->iop_committed)
+                       item_lsn = lip->li_ops->iop_committed(lip, commit_lsn);
+               else
+                       item_lsn = commit_lsn;
 
                /* item_lsn of -1 means the item needs no further processing */
                if (XFS_LSN_CMP(item_lsn, (xfs_lsn_t)-1) == 0)
@@ -864,7 +869,8 @@ xfs_trans_committed_bulk(
                 */
                if (aborted) {
                        ASSERT(XFS_FORCED_SHUTDOWN(ailp->ail_mount));
-                       lip->li_ops->iop_unpin(lip, 1);
+                       if (lip->li_ops->iop_unpin)
+                               lip->li_ops->iop_unpin(lip, 1);
                        continue;
                }
 
@@ -882,7 +888,8 @@ xfs_trans_committed_bulk(
                                xfs_trans_ail_update(ailp, lip, item_lsn);
                        else
                                spin_unlock(&ailp->ail_lock);
-                       lip->li_ops->iop_unpin(lip, 0);
+                       if (lip->li_ops->iop_unpin)
+                               lip->li_ops->iop_unpin(lip, 0);
                        continue;
                }
 
@@ -998,7 +1005,7 @@ out_unreserve:
                tp->t_ticket = NULL;
        }
        current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS);
-       xfs_trans_free_items(tp, NULLCOMMITLSN, !!error);
+       xfs_trans_free_items(tp, !!error);
        xfs_trans_free(tp);
 
        XFS_STATS_INC(mp, xs_trans_empty);
@@ -1060,7 +1067,7 @@ xfs_trans_cancel(
        /* mark this thread as no longer being in a transaction */
        current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS);
 
-       xfs_trans_free_items(tp, NULLCOMMITLSN, dirty);
+       xfs_trans_free_items(tp, dirty);
        xfs_trans_free(tp);
 }
 
index c6e1c57..64d7f17 100644 (file)
@@ -27,7 +27,7 @@ struct xfs_cud_log_item;
 struct xfs_bui_log_item;
 struct xfs_bud_log_item;
 
-typedef struct xfs_log_item {
+struct xfs_log_item {
        struct list_head                li_ail;         /* AIL pointers */
        struct list_head                li_trans;       /* transaction list */
        xfs_lsn_t                       li_lsn;         /* last on-disk lsn */
@@ -48,7 +48,7 @@ typedef struct xfs_log_item {
        struct xfs_log_vec              *li_lv;         /* active log vector */
        struct xfs_log_vec              *li_lv_shadow;  /* standby vector */
        xfs_lsn_t                       li_seq;         /* CIL commit seq */
-} xfs_log_item_t;
+};
 
 /*
  * li_flags use the (set/test/clear)_bit atomic interfaces because updates can
@@ -67,17 +67,24 @@ typedef struct xfs_log_item {
        { (1 << XFS_LI_DIRTY),          "DIRTY" }
 
 struct xfs_item_ops {
-       void (*iop_size)(xfs_log_item_t *, int *, int *);
-       void (*iop_format)(xfs_log_item_t *, struct xfs_log_vec *);
-       void (*iop_pin)(xfs_log_item_t *);
-       void (*iop_unpin)(xfs_log_item_t *, int remove);
+       unsigned flags;
+       void (*iop_size)(struct xfs_log_item *, int *, int *);
+       void (*iop_format)(struct xfs_log_item *, struct xfs_log_vec *);
+       void (*iop_pin)(struct xfs_log_item *);
+       void (*iop_unpin)(struct xfs_log_item *, int remove);
        uint (*iop_push)(struct xfs_log_item *, struct list_head *);
-       void (*iop_unlock)(xfs_log_item_t *);
-       xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t);
-       void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t);
-       void (*iop_error)(xfs_log_item_t *, xfs_buf_t *);
+       void (*iop_committing)(struct xfs_log_item *, xfs_lsn_t commit_lsn);
+       void (*iop_release)(struct xfs_log_item *);
+       xfs_lsn_t (*iop_committed)(struct xfs_log_item *, xfs_lsn_t);
+       void (*iop_error)(struct xfs_log_item *, xfs_buf_t *);
 };
 
+/*
+ * Release the log item as soon as committed.  This is for items just logging
+ * intents that never need to be written back in place.
+ */
+#define XFS_ITEM_RELEASE_WHEN_COMMITTED        (1 << 0)
+
 void   xfs_log_item_init(struct xfs_mount *mp, struct xfs_log_item *item,
                          int type, const struct xfs_item_ops *ops);
 
@@ -203,7 +210,7 @@ xfs_trans_read_buf(
                                      flags, bpp, ops);
 }
 
-struct xfs_buf *xfs_trans_getsb(xfs_trans_t *, struct xfs_mount *, int);
+struct xfs_buf *xfs_trans_getsb(xfs_trans_t *, struct xfs_mount *);
 
 void           xfs_trans_brelse(xfs_trans_t *, struct xfs_buf *);
 void           xfs_trans_bjoin(xfs_trans_t *, struct xfs_buf *);
@@ -223,14 +230,6 @@ void               xfs_trans_dirty_buf(struct xfs_trans *, struct xfs_buf *);
 bool           xfs_trans_buf_is_dirty(struct xfs_buf *bp);
 void           xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
 
-struct xfs_efd_log_item        *xfs_trans_get_efd(struct xfs_trans *,
-                                 struct xfs_efi_log_item *,
-                                 uint);
-int            xfs_trans_free_extent(struct xfs_trans *,
-                                     struct xfs_efd_log_item *, xfs_fsblock_t,
-                                     xfs_extlen_t,
-                                     const struct xfs_owner_info *,
-                                     bool);
 int            xfs_trans_commit(struct xfs_trans *);
 int            xfs_trans_roll(struct xfs_trans **);
 int            xfs_trans_roll_inode(struct xfs_trans **, struct xfs_inode *);
@@ -245,37 +244,4 @@ void               xfs_trans_buf_copy_type(struct xfs_buf *dst_bp,
 
 extern kmem_zone_t     *xfs_trans_zone;
 
-/* rmap updates */
-enum xfs_rmap_intent_type;
-
-struct xfs_rud_log_item *xfs_trans_get_rud(struct xfs_trans *tp,
-               struct xfs_rui_log_item *ruip);
-int xfs_trans_log_finish_rmap_update(struct xfs_trans *tp,
-               struct xfs_rud_log_item *rudp, enum xfs_rmap_intent_type type,
-               uint64_t owner, int whichfork, xfs_fileoff_t startoff,
-               xfs_fsblock_t startblock, xfs_filblks_t blockcount,
-               xfs_exntst_t state, struct xfs_btree_cur **pcur);
-
-/* refcount updates */
-enum xfs_refcount_intent_type;
-
-struct xfs_cud_log_item *xfs_trans_get_cud(struct xfs_trans *tp,
-               struct xfs_cui_log_item *cuip);
-int xfs_trans_log_finish_refcount_update(struct xfs_trans *tp,
-               struct xfs_cud_log_item *cudp,
-               enum xfs_refcount_intent_type type, xfs_fsblock_t startblock,
-               xfs_extlen_t blockcount, xfs_fsblock_t *new_fsb,
-               xfs_extlen_t *new_len, struct xfs_btree_cur **pcur);
-
-/* mapping updates */
-enum xfs_bmap_intent_type;
-
-struct xfs_bud_log_item *xfs_trans_get_bud(struct xfs_trans *tp,
-               struct xfs_bui_log_item *buip);
-int xfs_trans_log_finish_bmap_update(struct xfs_trans *tp,
-               struct xfs_bud_log_item *rudp, enum xfs_bmap_intent_type type,
-               struct xfs_inode *ip, int whichfork, xfs_fileoff_t startoff,
-               xfs_fsblock_t startblock, xfs_filblks_t *blockcount,
-               xfs_exntst_t state);
-
 #endif /* __XFS_TRANS_H__ */
index d3a4e89..6ccfd75 100644 (file)
@@ -6,6 +6,7 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
@@ -74,29 +75,29 @@ xfs_ail_check(
  * Return a pointer to the last item in the AIL.  If the AIL is empty, then
  * return NULL.
  */
-static xfs_log_item_t *
+static struct xfs_log_item *
 xfs_ail_max(
        struct xfs_ail  *ailp)
 {
        if (list_empty(&ailp->ail_head))
                return NULL;
 
-       return list_entry(ailp->ail_head.prev, xfs_log_item_t, li_ail);
+       return list_entry(ailp->ail_head.prev, struct xfs_log_item, li_ail);
 }
 
 /*
  * Return a pointer to the item which follows the given item in the AIL.  If
  * the given item is the last item in the list, then return NULL.
  */
-static xfs_log_item_t *
+static struct xfs_log_item *
 xfs_ail_next(
-       struct xfs_ail  *ailp,
-       xfs_log_item_t  *lip)
+       struct xfs_ail          *ailp,
+       struct xfs_log_item     *lip)
 {
        if (lip->li_ail.next == &ailp->ail_head)
                return NULL;
 
-       return list_first_entry(&lip->li_ail, xfs_log_item_t, li_ail);
+       return list_first_entry(&lip->li_ail, struct xfs_log_item, li_ail);
 }
 
 /*
@@ -109,10 +110,10 @@ xfs_ail_next(
  */
 xfs_lsn_t
 xfs_ail_min_lsn(
-       struct xfs_ail  *ailp)
+       struct xfs_ail          *ailp)
 {
-       xfs_lsn_t       lsn = 0;
-       xfs_log_item_t  *lip;
+       xfs_lsn_t               lsn = 0;
+       struct xfs_log_item     *lip;
 
        spin_lock(&ailp->ail_lock);
        lip = xfs_ail_min(ailp);
@@ -128,10 +129,10 @@ xfs_ail_min_lsn(
  */
 static xfs_lsn_t
 xfs_ail_max_lsn(
-       struct xfs_ail  *ailp)
+       struct xfs_ail          *ailp)
 {
-       xfs_lsn_t       lsn = 0;
-       xfs_log_item_t  *lip;
+       xfs_lsn_t               lsn = 0;
+       struct xfs_log_item     *lip;
 
        spin_lock(&ailp->ail_lock);
        lip = xfs_ail_max(ailp);
@@ -216,13 +217,13 @@ xfs_trans_ail_cursor_clear(
  * ascending traversal.  Pass a @lsn of zero to initialise the cursor to the
  * first item in the AIL. Returns NULL if the list is empty.
  */
-xfs_log_item_t *
+struct xfs_log_item *
 xfs_trans_ail_cursor_first(
        struct xfs_ail          *ailp,
        struct xfs_ail_cursor   *cur,
        xfs_lsn_t               lsn)
 {
-       xfs_log_item_t          *lip;
+       struct xfs_log_item     *lip;
 
        xfs_trans_ail_cursor_init(ailp, cur);
 
@@ -248,7 +249,7 @@ __xfs_trans_ail_cursor_last(
        struct xfs_ail          *ailp,
        xfs_lsn_t               lsn)
 {
-       xfs_log_item_t          *lip;
+       struct xfs_log_item     *lip;
 
        list_for_each_entry_reverse(lip, &ailp->ail_head, li_ail) {
                if (XFS_LSN_CMP(lip->li_lsn, lsn) <= 0)
@@ -327,8 +328,8 @@ xfs_ail_splice(
  */
 static void
 xfs_ail_delete(
-       struct xfs_ail  *ailp,
-       xfs_log_item_t  *lip)
+       struct xfs_ail          *ailp,
+       struct xfs_log_item     *lip)
 {
        xfs_ail_check(ailp, lip);
        list_del(&lip->li_ail);
@@ -347,6 +348,14 @@ xfsaild_push_item(
        if (XFS_TEST_ERROR(false, ailp->ail_mount, XFS_ERRTAG_LOG_ITEM_PIN))
                return XFS_ITEM_PINNED;
 
+       /*
+        * Consider the item pinned if a push callback is not defined so the
+        * caller will force the log. This should only happen for intent items
+        * as they are unpinned once the associated done item is committed to
+        * the on-disk log.
+        */
+       if (!lip->li_ops->iop_push)
+               return XFS_ITEM_PINNED;
        return lip->li_ops->iop_push(lip, &ailp->ail_buf_list);
 }
 
@@ -356,7 +365,7 @@ xfsaild_push(
 {
        xfs_mount_t             *mp = ailp->ail_mount;
        struct xfs_ail_cursor   cur;
-       xfs_log_item_t          *lip;
+       struct xfs_log_item     *lip;
        xfs_lsn_t               lsn;
        xfs_lsn_t               target;
        long                    tout;
@@ -611,10 +620,10 @@ xfsaild(
  */
 void
 xfs_ail_push(
-       struct xfs_ail  *ailp,
-       xfs_lsn_t       threshold_lsn)
+       struct xfs_ail          *ailp,
+       xfs_lsn_t               threshold_lsn)
 {
-       xfs_log_item_t  *lip;
+       struct xfs_log_item     *lip;
 
        lip = xfs_ail_min(ailp);
        if (!lip || XFS_FORCED_SHUTDOWN(ailp->ail_mount) ||
@@ -699,7 +708,7 @@ xfs_trans_ail_update_bulk(
        int                     nr_items,
        xfs_lsn_t               lsn) __releases(ailp->ail_lock)
 {
-       xfs_log_item_t          *mlip;
+       struct xfs_log_item     *mlip;
        int                     mlip_changed = 0;
        int                     i;
        LIST_HEAD(tmp);
diff --git a/fs/xfs/xfs_trans_bmap.c b/fs/xfs/xfs_trans_bmap.c
deleted file mode 100644 (file)
index e1c7d55..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2016 Oracle.  All Rights Reserved.
- * Author: Darrick J. Wong <darrick.wong@oracle.com>
- */
-#include "xfs.h"
-#include "xfs_fs.h"
-#include "xfs_shared.h"
-#include "xfs_format.h"
-#include "xfs_log_format.h"
-#include "xfs_trans_resv.h"
-#include "xfs_mount.h"
-#include "xfs_defer.h"
-#include "xfs_trans.h"
-#include "xfs_trans_priv.h"
-#include "xfs_bmap_item.h"
-#include "xfs_alloc.h"
-#include "xfs_bmap.h"
-#include "xfs_inode.h"
-
-/*
- * This routine is called to allocate a "bmap update done"
- * log item.
- */
-struct xfs_bud_log_item *
-xfs_trans_get_bud(
-       struct xfs_trans                *tp,
-       struct xfs_bui_log_item         *buip)
-{
-       struct xfs_bud_log_item         *budp;
-
-       budp = xfs_bud_init(tp->t_mountp, buip);
-       xfs_trans_add_item(tp, &budp->bud_item);
-       return budp;
-}
-
-/*
- * Finish an bmap update and log it to the BUD. Note that the
- * transaction is marked dirty regardless of whether the bmap update
- * succeeds or fails to support the BUI/BUD lifecycle rules.
- */
-int
-xfs_trans_log_finish_bmap_update(
-       struct xfs_trans                *tp,
-       struct xfs_bud_log_item         *budp,
-       enum xfs_bmap_intent_type       type,
-       struct xfs_inode                *ip,
-       int                             whichfork,
-       xfs_fileoff_t                   startoff,
-       xfs_fsblock_t                   startblock,
-       xfs_filblks_t                   *blockcount,
-       xfs_exntst_t                    state)
-{
-       int                             error;
-
-       error = xfs_bmap_finish_one(tp, ip, type, whichfork, startoff,
-                       startblock, blockcount, state);
-
-       /*
-        * Mark the transaction dirty, even on error. This ensures the
-        * transaction is aborted, which:
-        *
-        * 1.) releases the BUI and frees the BUD
-        * 2.) shuts down the filesystem
-        */
-       tp->t_flags |= XFS_TRANS_DIRTY;
-       set_bit(XFS_LI_DIRTY, &budp->bud_item.li_flags);
-
-       return error;
-}
-
-/* Sort bmap intents by inode. */
-static int
-xfs_bmap_update_diff_items(
-       void                            *priv,
-       struct list_head                *a,
-       struct list_head                *b)
-{
-       struct xfs_bmap_intent          *ba;
-       struct xfs_bmap_intent          *bb;
-
-       ba = container_of(a, struct xfs_bmap_intent, bi_list);
-       bb = container_of(b, struct xfs_bmap_intent, bi_list);
-       return ba->bi_owner->i_ino - bb->bi_owner->i_ino;
-}
-
-/* Get an BUI. */
-STATIC void *
-xfs_bmap_update_create_intent(
-       struct xfs_trans                *tp,
-       unsigned int                    count)
-{
-       struct xfs_bui_log_item         *buip;
-
-       ASSERT(count == XFS_BUI_MAX_FAST_EXTENTS);
-       ASSERT(tp != NULL);
-
-       buip = xfs_bui_init(tp->t_mountp);
-       ASSERT(buip != NULL);
-
-       /*
-        * Get a log_item_desc to point at the new item.
-        */
-       xfs_trans_add_item(tp, &buip->bui_item);
-       return buip;
-}
-
-/* Set the map extent flags for this mapping. */
-static void
-xfs_trans_set_bmap_flags(
-       struct xfs_map_extent           *bmap,
-       enum xfs_bmap_intent_type       type,
-       int                             whichfork,
-       xfs_exntst_t                    state)
-{
-       bmap->me_flags = 0;
-       switch (type) {
-       case XFS_BMAP_MAP:
-       case XFS_BMAP_UNMAP:
-               bmap->me_flags = type;
-               break;
-       default:
-               ASSERT(0);
-       }
-       if (state == XFS_EXT_UNWRITTEN)
-               bmap->me_flags |= XFS_BMAP_EXTENT_UNWRITTEN;
-       if (whichfork == XFS_ATTR_FORK)
-               bmap->me_flags |= XFS_BMAP_EXTENT_ATTR_FORK;
-}
-
-/* Log bmap updates in the intent item. */
-STATIC void
-xfs_bmap_update_log_item(
-       struct xfs_trans                *tp,
-       void                            *intent,
-       struct list_head                *item)
-{
-       struct xfs_bui_log_item         *buip = intent;
-       struct xfs_bmap_intent          *bmap;
-       uint                            next_extent;
-       struct xfs_map_extent           *map;
-
-       bmap = container_of(item, struct xfs_bmap_intent, bi_list);
-
-       tp->t_flags |= XFS_TRANS_DIRTY;
-       set_bit(XFS_LI_DIRTY, &buip->bui_item.li_flags);
-
-       /*
-        * atomic_inc_return gives us the value after the increment;
-        * we want to use it as an array index so we need to subtract 1 from
-        * it.
-        */
-       next_extent = atomic_inc_return(&buip->bui_next_extent) - 1;
-       ASSERT(next_extent < buip->bui_format.bui_nextents);
-       map = &buip->bui_format.bui_extents[next_extent];
-       map->me_owner = bmap->bi_owner->i_ino;
-       map->me_startblock = bmap->bi_bmap.br_startblock;
-       map->me_startoff = bmap->bi_bmap.br_startoff;
-       map->me_len = bmap->bi_bmap.br_blockcount;
-       xfs_trans_set_bmap_flags(map, bmap->bi_type, bmap->bi_whichfork,
-                       bmap->bi_bmap.br_state);
-}
-
-/* Get an BUD so we can process all the deferred rmap updates. */
-STATIC void *
-xfs_bmap_update_create_done(
-       struct xfs_trans                *tp,
-       void                            *intent,
-       unsigned int                    count)
-{
-       return xfs_trans_get_bud(tp, intent);
-}
-
-/* Process a deferred rmap update. */
-STATIC int
-xfs_bmap_update_finish_item(
-       struct xfs_trans                *tp,
-       struct list_head                *item,
-       void                            *done_item,
-       void                            **state)
-{
-       struct xfs_bmap_intent          *bmap;
-       xfs_filblks_t                   count;
-       int                             error;
-
-       bmap = container_of(item, struct xfs_bmap_intent, bi_list);
-       count = bmap->bi_bmap.br_blockcount;
-       error = xfs_trans_log_finish_bmap_update(tp, done_item,
-                       bmap->bi_type,
-                       bmap->bi_owner, bmap->bi_whichfork,
-                       bmap->bi_bmap.br_startoff,
-                       bmap->bi_bmap.br_startblock,
-                       &count,
-                       bmap->bi_bmap.br_state);
-       if (!error && count > 0) {
-               ASSERT(bmap->bi_type == XFS_BMAP_UNMAP);
-               bmap->bi_bmap.br_blockcount = count;
-               return -EAGAIN;
-       }
-       kmem_free(bmap);
-       return error;
-}
-
-/* Abort all pending BUIs. */
-STATIC void
-xfs_bmap_update_abort_intent(
-       void                            *intent)
-{
-       xfs_bui_release(intent);
-}
-
-/* Cancel a deferred rmap update. */
-STATIC void
-xfs_bmap_update_cancel_item(
-       struct list_head                *item)
-{
-       struct xfs_bmap_intent          *bmap;
-
-       bmap = container_of(item, struct xfs_bmap_intent, bi_list);
-       kmem_free(bmap);
-}
-
-const struct xfs_defer_op_type xfs_bmap_update_defer_type = {
-       .max_items      = XFS_BUI_MAX_FAST_EXTENTS,
-       .diff_items     = xfs_bmap_update_diff_items,
-       .create_intent  = xfs_bmap_update_create_intent,
-       .abort_intent   = xfs_bmap_update_abort_intent,
-       .log_item       = xfs_bmap_update_log_item,
-       .create_done    = xfs_bmap_update_create_done,
-       .finish_item    = xfs_bmap_update_finish_item,
-       .cancel_item    = xfs_bmap_update_cancel_item,
-};
index 7d65ebf..b5b3a78 100644 (file)
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_inode.h"
 #include "xfs_trans.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_priv.h"
-#include "xfs_error.h"
 #include "xfs_trace.h"
 
 /*
@@ -174,8 +172,7 @@ xfs_trans_get_buf_map(
 xfs_buf_t *
 xfs_trans_getsb(
        xfs_trans_t             *tp,
-       struct xfs_mount        *mp,
-       int                     flags)
+       struct xfs_mount        *mp)
 {
        xfs_buf_t               *bp;
        struct xfs_buf_log_item *bip;
@@ -185,7 +182,7 @@ xfs_trans_getsb(
         * if tp is NULL.
         */
        if (tp == NULL)
-               return xfs_getsb(mp, flags);
+               return xfs_getsb(mp);
 
        /*
         * If the superblock buffer already has this transaction
@@ -203,7 +200,7 @@ xfs_trans_getsb(
                return bp;
        }
 
-       bp = xfs_getsb(mp, flags);
+       bp = xfs_getsb(mp);
        if (bp == NULL)
                return NULL;
 
@@ -428,7 +425,7 @@ xfs_trans_brelse(
 
 /*
  * Mark the buffer as not needing to be unlocked when the buf item's
- * iop_unlock() routine is called.  The buffer must already be locked
+ * iop_committing() routine is called.  The buffer must already be locked
  * and associated with the given transaction.
  */
 /* ARGSUSED */
index cd664a0..1027c9c 100644 (file)
@@ -11,7 +11,6 @@
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
 #include "xfs_inode.h"
-#include "xfs_error.h"
 #include "xfs_trans.h"
 #include "xfs_trans_priv.h"
 #include "xfs_quota.h"
@@ -29,7 +28,6 @@ xfs_trans_dqjoin(
        xfs_trans_t     *tp,
        xfs_dquot_t     *dqp)
 {
-       ASSERT(dqp->q_transp != tp);
        ASSERT(XFS_DQ_IS_LOCKED(dqp));
        ASSERT(dqp->q_logitem.qli_dquot == dqp);
 
@@ -37,15 +35,8 @@ xfs_trans_dqjoin(
         * Get a log_item_desc to point at the new item.
         */
        xfs_trans_add_item(tp, &dqp->q_logitem.qli_item);
-
-       /*
-        * Initialize d_transp so we can later determine if this dquot is
-        * associated with this transaction.
-        */
-       dqp->q_transp = tp;
 }
 
-
 /*
  * This is called to mark the dquot as needing
  * to be logged when the transaction is committed.  The dquot must
@@ -61,7 +52,6 @@ xfs_trans_log_dquot(
        xfs_trans_t     *tp,
        xfs_dquot_t     *dqp)
 {
-       ASSERT(dqp->q_transp == tp);
        ASSERT(XFS_DQ_IS_LOCKED(dqp));
 
        tp->t_flags |= XFS_TRANS_DIRTY;
@@ -347,7 +337,6 @@ xfs_trans_apply_dquot_deltas(
                                break;
 
                        ASSERT(XFS_DQ_IS_LOCKED(dqp));
-                       ASSERT(dqp->q_transp == tp);
 
                        /*
                         * adjust the actual number of blocks used
diff --git a/fs/xfs/xfs_trans_extfree.c b/fs/xfs/xfs_trans_extfree.c
deleted file mode 100644 (file)
index 8ee7a3f..0000000
+++ /dev/null
@@ -1,286 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2000,2005 Silicon Graphics, Inc.
- * All Rights Reserved.
- */
-#include "xfs.h"
-#include "xfs_fs.h"
-#include "xfs_shared.h"
-#include "xfs_format.h"
-#include "xfs_log_format.h"
-#include "xfs_trans_resv.h"
-#include "xfs_bit.h"
-#include "xfs_mount.h"
-#include "xfs_defer.h"
-#include "xfs_trans.h"
-#include "xfs_trans_priv.h"
-#include "xfs_extfree_item.h"
-#include "xfs_alloc.h"
-#include "xfs_bmap.h"
-#include "xfs_trace.h"
-
-/*
- * This routine is called to allocate an "extent free done"
- * log item that will hold nextents worth of extents.  The
- * caller must use all nextents extents, because we are not
- * flexible about this at all.
- */
-struct xfs_efd_log_item *
-xfs_trans_get_efd(struct xfs_trans             *tp,
-                 struct xfs_efi_log_item       *efip,
-                 uint                          nextents)
-{
-       struct xfs_efd_log_item                 *efdp;
-
-       ASSERT(tp != NULL);
-       ASSERT(nextents > 0);
-
-       efdp = xfs_efd_init(tp->t_mountp, efip, nextents);
-       ASSERT(efdp != NULL);
-
-       /*
-        * Get a log_item_desc to point at the new item.
-        */
-       xfs_trans_add_item(tp, &efdp->efd_item);
-       return efdp;
-}
-
-/*
- * Free an extent and log it to the EFD. Note that the transaction is marked
- * dirty regardless of whether the extent free succeeds or fails to support the
- * EFI/EFD lifecycle rules.
- */
-int
-xfs_trans_free_extent(
-       struct xfs_trans                *tp,
-       struct xfs_efd_log_item         *efdp,
-       xfs_fsblock_t                   start_block,
-       xfs_extlen_t                    ext_len,
-       const struct xfs_owner_info     *oinfo,
-       bool                            skip_discard)
-{
-       struct xfs_mount                *mp = tp->t_mountp;
-       struct xfs_extent               *extp;
-       uint                            next_extent;
-       xfs_agnumber_t                  agno = XFS_FSB_TO_AGNO(mp, start_block);
-       xfs_agblock_t                   agbno = XFS_FSB_TO_AGBNO(mp,
-                                                               start_block);
-       int                             error;
-
-       trace_xfs_bmap_free_deferred(tp->t_mountp, agno, 0, agbno, ext_len);
-
-       error = __xfs_free_extent(tp, start_block, ext_len,
-                                 oinfo, XFS_AG_RESV_NONE, skip_discard);
-       /*
-        * Mark the transaction dirty, even on error. This ensures the
-        * transaction is aborted, which:
-        *
-        * 1.) releases the EFI and frees the EFD
-        * 2.) shuts down the filesystem
-        */
-       tp->t_flags |= XFS_TRANS_DIRTY;
-       set_bit(XFS_LI_DIRTY, &efdp->efd_item.li_flags);
-
-       next_extent = efdp->efd_next_extent;
-       ASSERT(next_extent < efdp->efd_format.efd_nextents);
-       extp = &(efdp->efd_format.efd_extents[next_extent]);
-       extp->ext_start = start_block;
-       extp->ext_len = ext_len;
-       efdp->efd_next_extent++;
-
-       return error;
-}
-
-/* Sort bmap items by AG. */
-static int
-xfs_extent_free_diff_items(
-       void                            *priv,
-       struct list_head                *a,
-       struct list_head                *b)
-{
-       struct xfs_mount                *mp = priv;
-       struct xfs_extent_free_item     *ra;
-       struct xfs_extent_free_item     *rb;
-
-       ra = container_of(a, struct xfs_extent_free_item, xefi_list);
-       rb = container_of(b, struct xfs_extent_free_item, xefi_list);
-       return  XFS_FSB_TO_AGNO(mp, ra->xefi_startblock) -
-               XFS_FSB_TO_AGNO(mp, rb->xefi_startblock);
-}
-
-/* Get an EFI. */
-STATIC void *
-xfs_extent_free_create_intent(
-       struct xfs_trans                *tp,
-       unsigned int                    count)
-{
-       struct xfs_efi_log_item         *efip;
-
-       ASSERT(tp != NULL);
-       ASSERT(count > 0);
-
-       efip = xfs_efi_init(tp->t_mountp, count);
-       ASSERT(efip != NULL);
-
-       /*
-        * Get a log_item_desc to point at the new item.
-        */
-       xfs_trans_add_item(tp, &efip->efi_item);
-       return efip;
-}
-
-/* Log a free extent to the intent item. */
-STATIC void
-xfs_extent_free_log_item(
-       struct xfs_trans                *tp,
-       void                            *intent,
-       struct list_head                *item)
-{
-       struct xfs_efi_log_item         *efip = intent;
-       struct xfs_extent_free_item     *free;
-       uint                            next_extent;
-       struct xfs_extent               *extp;
-
-       free = container_of(item, struct xfs_extent_free_item, xefi_list);
-
-       tp->t_flags |= XFS_TRANS_DIRTY;
-       set_bit(XFS_LI_DIRTY, &efip->efi_item.li_flags);
-
-       /*
-        * atomic_inc_return gives us the value after the increment;
-        * we want to use it as an array index so we need to subtract 1 from
-        * it.
-        */
-       next_extent = atomic_inc_return(&efip->efi_next_extent) - 1;
-       ASSERT(next_extent < efip->efi_format.efi_nextents);
-       extp = &efip->efi_format.efi_extents[next_extent];
-       extp->ext_start = free->xefi_startblock;
-       extp->ext_len = free->xefi_blockcount;
-}
-
-/* Get an EFD so we can process all the free extents. */
-STATIC void *
-xfs_extent_free_create_done(
-       struct xfs_trans                *tp,
-       void                            *intent,
-       unsigned int                    count)
-{
-       return xfs_trans_get_efd(tp, intent, count);
-}
-
-/* Process a free extent. */
-STATIC int
-xfs_extent_free_finish_item(
-       struct xfs_trans                *tp,
-       struct list_head                *item,
-       void                            *done_item,
-       void                            **state)
-{
-       struct xfs_extent_free_item     *free;
-       int                             error;
-
-       free = container_of(item, struct xfs_extent_free_item, xefi_list);
-       error = xfs_trans_free_extent(tp, done_item,
-                       free->xefi_startblock,
-                       free->xefi_blockcount,
-                       &free->xefi_oinfo, free->xefi_skip_discard);
-       kmem_free(free);
-       return error;
-}
-
-/* Abort all pending EFIs. */
-STATIC void
-xfs_extent_free_abort_intent(
-       void                            *intent)
-{
-       xfs_efi_release(intent);
-}
-
-/* Cancel a free extent. */
-STATIC void
-xfs_extent_free_cancel_item(
-       struct list_head                *item)
-{
-       struct xfs_extent_free_item     *free;
-
-       free = container_of(item, struct xfs_extent_free_item, xefi_list);
-       kmem_free(free);
-}
-
-const struct xfs_defer_op_type xfs_extent_free_defer_type = {
-       .max_items      = XFS_EFI_MAX_FAST_EXTENTS,
-       .diff_items     = xfs_extent_free_diff_items,
-       .create_intent  = xfs_extent_free_create_intent,
-       .abort_intent   = xfs_extent_free_abort_intent,
-       .log_item       = xfs_extent_free_log_item,
-       .create_done    = xfs_extent_free_create_done,
-       .finish_item    = xfs_extent_free_finish_item,
-       .cancel_item    = xfs_extent_free_cancel_item,
-};
-
-/*
- * AGFL blocks are accounted differently in the reserve pools and are not
- * inserted into the busy extent list.
- */
-STATIC int
-xfs_agfl_free_finish_item(
-       struct xfs_trans                *tp,
-       struct list_head                *item,
-       void                            *done_item,
-       void                            **state)
-{
-       struct xfs_mount                *mp = tp->t_mountp;
-       struct xfs_efd_log_item         *efdp = done_item;
-       struct xfs_extent_free_item     *free;
-       struct xfs_extent               *extp;
-       struct xfs_buf                  *agbp;
-       int                             error;
-       xfs_agnumber_t                  agno;
-       xfs_agblock_t                   agbno;
-       uint                            next_extent;
-
-       free = container_of(item, struct xfs_extent_free_item, xefi_list);
-       ASSERT(free->xefi_blockcount == 1);
-       agno = XFS_FSB_TO_AGNO(mp, free->xefi_startblock);
-       agbno = XFS_FSB_TO_AGBNO(mp, free->xefi_startblock);
-
-       trace_xfs_agfl_free_deferred(mp, agno, 0, agbno, free->xefi_blockcount);
-
-       error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
-       if (!error)
-               error = xfs_free_agfl_block(tp, agno, agbno, agbp,
-                                           &free->xefi_oinfo);
-
-       /*
-        * Mark the transaction dirty, even on error. This ensures the
-        * transaction is aborted, which:
-        *
-        * 1.) releases the EFI and frees the EFD
-        * 2.) shuts down the filesystem
-        */
-       tp->t_flags |= XFS_TRANS_DIRTY;
-       set_bit(XFS_LI_DIRTY, &efdp->efd_item.li_flags);
-
-       next_extent = efdp->efd_next_extent;
-       ASSERT(next_extent < efdp->efd_format.efd_nextents);
-       extp = &(efdp->efd_format.efd_extents[next_extent]);
-       extp->ext_start = free->xefi_startblock;
-       extp->ext_len = free->xefi_blockcount;
-       efdp->efd_next_extent++;
-
-       kmem_free(free);
-       return error;
-}
-
-
-/* sub-type with special handling for AGFL deferred frees */
-const struct xfs_defer_op_type xfs_agfl_free_defer_type = {
-       .max_items      = XFS_EFI_MAX_FAST_EXTENTS,
-       .diff_items     = xfs_extent_free_diff_items,
-       .create_intent  = xfs_extent_free_create_intent,
-       .abort_intent   = xfs_extent_free_abort_intent,
-       .log_item       = xfs_extent_free_log_item,
-       .create_done    = xfs_extent_free_create_done,
-       .finish_item    = xfs_agfl_free_finish_item,
-       .cancel_item    = xfs_extent_free_cancel_item,
-};
index 5429273..93d14e4 100644 (file)
@@ -8,13 +8,10 @@
 #include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
-#include "xfs_trans_resv.h"
-#include "xfs_mount.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
 #include "xfs_trans_priv.h"
 #include "xfs_inode_item.h"
-#include "xfs_trace.h"
 
 #include <linux/iversion.h>
 
index 091eae9..2e073c1 100644 (file)
@@ -16,12 +16,10 @@ struct xfs_log_vec;
 void   xfs_trans_init(struct xfs_mount *);
 void   xfs_trans_add_item(struct xfs_trans *, struct xfs_log_item *);
 void   xfs_trans_del_item(struct xfs_log_item *);
-void   xfs_trans_free_items(struct xfs_trans *tp, xfs_lsn_t commit_lsn,
-                               bool abort);
 void   xfs_trans_unreserve_and_mod_sb(struct xfs_trans *tp);
 
 void   xfs_trans_committed_bulk(struct xfs_ail *ailp, struct xfs_log_vec *lv,
-                               xfs_lsn_t commit_lsn, int aborted);
+                               xfs_lsn_t commit_lsn, bool aborted);
 /*
  * AIL traversal cursor.
  *
diff --git a/fs/xfs/xfs_trans_refcount.c b/fs/xfs/xfs_trans_refcount.c
deleted file mode 100644 (file)
index 8d73472..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2016 Oracle.  All Rights Reserved.
- * Author: Darrick J. Wong <darrick.wong@oracle.com>
- */
-#include "xfs.h"
-#include "xfs_fs.h"
-#include "xfs_shared.h"
-#include "xfs_format.h"
-#include "xfs_log_format.h"
-#include "xfs_trans_resv.h"
-#include "xfs_mount.h"
-#include "xfs_defer.h"
-#include "xfs_trans.h"
-#include "xfs_trans_priv.h"
-#include "xfs_refcount_item.h"
-#include "xfs_alloc.h"
-#include "xfs_refcount.h"
-
-/*
- * This routine is called to allocate a "refcount update done"
- * log item.
- */
-struct xfs_cud_log_item *
-xfs_trans_get_cud(
-       struct xfs_trans                *tp,
-       struct xfs_cui_log_item         *cuip)
-{
-       struct xfs_cud_log_item         *cudp;
-
-       cudp = xfs_cud_init(tp->t_mountp, cuip);
-       xfs_trans_add_item(tp, &cudp->cud_item);
-       return cudp;
-}
-
-/*
- * Finish an refcount update and log it to the CUD. Note that the
- * transaction is marked dirty regardless of whether the refcount
- * update succeeds or fails to support the CUI/CUD lifecycle rules.
- */
-int
-xfs_trans_log_finish_refcount_update(
-       struct xfs_trans                *tp,
-       struct xfs_cud_log_item         *cudp,
-       enum xfs_refcount_intent_type   type,
-       xfs_fsblock_t                   startblock,
-       xfs_extlen_t                    blockcount,
-       xfs_fsblock_t                   *new_fsb,
-       xfs_extlen_t                    *new_len,
-       struct xfs_btree_cur            **pcur)
-{
-       int                             error;
-
-       error = xfs_refcount_finish_one(tp, type, startblock,
-                       blockcount, new_fsb, new_len, pcur);
-
-       /*
-        * Mark the transaction dirty, even on error. This ensures the
-        * transaction is aborted, which:
-        *
-        * 1.) releases the CUI and frees the CUD
-        * 2.) shuts down the filesystem
-        */
-       tp->t_flags |= XFS_TRANS_DIRTY;
-       set_bit(XFS_LI_DIRTY, &cudp->cud_item.li_flags);
-
-       return error;
-}
-
-/* Sort refcount intents by AG. */
-static int
-xfs_refcount_update_diff_items(
-       void                            *priv,
-       struct list_head                *a,
-       struct list_head                *b)
-{
-       struct xfs_mount                *mp = priv;
-       struct xfs_refcount_intent      *ra;
-       struct xfs_refcount_intent      *rb;
-
-       ra = container_of(a, struct xfs_refcount_intent, ri_list);
-       rb = container_of(b, struct xfs_refcount_intent, ri_list);
-       return  XFS_FSB_TO_AGNO(mp, ra->ri_startblock) -
-               XFS_FSB_TO_AGNO(mp, rb->ri_startblock);
-}
-
-/* Get an CUI. */
-STATIC void *
-xfs_refcount_update_create_intent(
-       struct xfs_trans                *tp,
-       unsigned int                    count)
-{
-       struct xfs_cui_log_item         *cuip;
-
-       ASSERT(tp != NULL);
-       ASSERT(count > 0);
-
-       cuip = xfs_cui_init(tp->t_mountp, count);
-       ASSERT(cuip != NULL);
-
-       /*
-        * Get a log_item_desc to point at the new item.
-        */
-       xfs_trans_add_item(tp, &cuip->cui_item);
-       return cuip;
-}
-
-/* Set the phys extent flags for this reverse mapping. */
-static void
-xfs_trans_set_refcount_flags(
-       struct xfs_phys_extent          *refc,
-       enum xfs_refcount_intent_type   type)
-{
-       refc->pe_flags = 0;
-       switch (type) {
-       case XFS_REFCOUNT_INCREASE:
-       case XFS_REFCOUNT_DECREASE:
-       case XFS_REFCOUNT_ALLOC_COW:
-       case XFS_REFCOUNT_FREE_COW:
-               refc->pe_flags |= type;
-               break;
-       default:
-               ASSERT(0);
-       }
-}
-
-/* Log refcount updates in the intent item. */
-STATIC void
-xfs_refcount_update_log_item(
-       struct xfs_trans                *tp,
-       void                            *intent,
-       struct list_head                *item)
-{
-       struct xfs_cui_log_item         *cuip = intent;
-       struct xfs_refcount_intent      *refc;
-       uint                            next_extent;
-       struct xfs_phys_extent          *ext;
-
-       refc = container_of(item, struct xfs_refcount_intent, ri_list);
-
-       tp->t_flags |= XFS_TRANS_DIRTY;
-       set_bit(XFS_LI_DIRTY, &cuip->cui_item.li_flags);
-
-       /*
-        * atomic_inc_return gives us the value after the increment;
-        * we want to use it as an array index so we need to subtract 1 from
-        * it.
-        */
-       next_extent = atomic_inc_return(&cuip->cui_next_extent) - 1;
-       ASSERT(next_extent < cuip->cui_format.cui_nextents);
-       ext = &cuip->cui_format.cui_extents[next_extent];
-       ext->pe_startblock = refc->ri_startblock;
-       ext->pe_len = refc->ri_blockcount;
-       xfs_trans_set_refcount_flags(ext, refc->ri_type);
-}
-
-/* Get an CUD so we can process all the deferred refcount updates. */
-STATIC void *
-xfs_refcount_update_create_done(
-       struct xfs_trans                *tp,
-       void                            *intent,
-       unsigned int                    count)
-{
-       return xfs_trans_get_cud(tp, intent);
-}
-
-/* Process a deferred refcount update. */
-STATIC int
-xfs_refcount_update_finish_item(
-       struct xfs_trans                *tp,
-       struct list_head                *item,
-       void                            *done_item,
-       void                            **state)
-{
-       struct xfs_refcount_intent      *refc;
-       xfs_fsblock_t                   new_fsb;
-       xfs_extlen_t                    new_aglen;
-       int                             error;
-
-       refc = container_of(item, struct xfs_refcount_intent, ri_list);
-       error = xfs_trans_log_finish_refcount_update(tp, done_item,
-                       refc->ri_type,
-                       refc->ri_startblock,
-                       refc->ri_blockcount,
-                       &new_fsb, &new_aglen,
-                       (struct xfs_btree_cur **)state);
-       /* Did we run out of reservation?  Requeue what we didn't finish. */
-       if (!error && new_aglen > 0) {
-               ASSERT(refc->ri_type == XFS_REFCOUNT_INCREASE ||
-                      refc->ri_type == XFS_REFCOUNT_DECREASE);
-               refc->ri_startblock = new_fsb;
-               refc->ri_blockcount = new_aglen;
-               return -EAGAIN;
-       }
-       kmem_free(refc);
-       return error;
-}
-
-/* Clean up after processing deferred refcounts. */
-STATIC void
-xfs_refcount_update_finish_cleanup(
-       struct xfs_trans        *tp,
-       void                    *state,
-       int                     error)
-{
-       struct xfs_btree_cur    *rcur = state;
-
-       xfs_refcount_finish_one_cleanup(tp, rcur, error);
-}
-
-/* Abort all pending CUIs. */
-STATIC void
-xfs_refcount_update_abort_intent(
-       void                            *intent)
-{
-       xfs_cui_release(intent);
-}
-
-/* Cancel a deferred refcount update. */
-STATIC void
-xfs_refcount_update_cancel_item(
-       struct list_head                *item)
-{
-       struct xfs_refcount_intent      *refc;
-
-       refc = container_of(item, struct xfs_refcount_intent, ri_list);
-       kmem_free(refc);
-}
-
-const struct xfs_defer_op_type xfs_refcount_update_defer_type = {
-       .max_items      = XFS_CUI_MAX_FAST_EXTENTS,
-       .diff_items     = xfs_refcount_update_diff_items,
-       .create_intent  = xfs_refcount_update_create_intent,
-       .abort_intent   = xfs_refcount_update_abort_intent,
-       .log_item       = xfs_refcount_update_log_item,
-       .create_done    = xfs_refcount_update_create_done,
-       .finish_item    = xfs_refcount_update_finish_item,
-       .finish_cleanup = xfs_refcount_update_finish_cleanup,
-       .cancel_item    = xfs_refcount_update_cancel_item,
-};
diff --git a/fs/xfs/xfs_trans_rmap.c b/fs/xfs/xfs_trans_rmap.c
deleted file mode 100644 (file)
index 5c7936b..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2016 Oracle.  All Rights Reserved.
- * Author: Darrick J. Wong <darrick.wong@oracle.com>
- */
-#include "xfs.h"
-#include "xfs_fs.h"
-#include "xfs_shared.h"
-#include "xfs_format.h"
-#include "xfs_log_format.h"
-#include "xfs_trans_resv.h"
-#include "xfs_mount.h"
-#include "xfs_defer.h"
-#include "xfs_trans.h"
-#include "xfs_trans_priv.h"
-#include "xfs_rmap_item.h"
-#include "xfs_alloc.h"
-#include "xfs_rmap.h"
-
-/* Set the map extent flags for this reverse mapping. */
-static void
-xfs_trans_set_rmap_flags(
-       struct xfs_map_extent           *rmap,
-       enum xfs_rmap_intent_type       type,
-       int                             whichfork,
-       xfs_exntst_t                    state)
-{
-       rmap->me_flags = 0;
-       if (state == XFS_EXT_UNWRITTEN)
-               rmap->me_flags |= XFS_RMAP_EXTENT_UNWRITTEN;
-       if (whichfork == XFS_ATTR_FORK)
-               rmap->me_flags |= XFS_RMAP_EXTENT_ATTR_FORK;
-       switch (type) {
-       case XFS_RMAP_MAP:
-               rmap->me_flags |= XFS_RMAP_EXTENT_MAP;
-               break;
-       case XFS_RMAP_MAP_SHARED:
-               rmap->me_flags |= XFS_RMAP_EXTENT_MAP_SHARED;
-               break;
-       case XFS_RMAP_UNMAP:
-               rmap->me_flags |= XFS_RMAP_EXTENT_UNMAP;
-               break;
-       case XFS_RMAP_UNMAP_SHARED:
-               rmap->me_flags |= XFS_RMAP_EXTENT_UNMAP_SHARED;
-               break;
-       case XFS_RMAP_CONVERT:
-               rmap->me_flags |= XFS_RMAP_EXTENT_CONVERT;
-               break;
-       case XFS_RMAP_CONVERT_SHARED:
-               rmap->me_flags |= XFS_RMAP_EXTENT_CONVERT_SHARED;
-               break;
-       case XFS_RMAP_ALLOC:
-               rmap->me_flags |= XFS_RMAP_EXTENT_ALLOC;
-               break;
-       case XFS_RMAP_FREE:
-               rmap->me_flags |= XFS_RMAP_EXTENT_FREE;
-               break;
-       default:
-               ASSERT(0);
-       }
-}
-
-struct xfs_rud_log_item *
-xfs_trans_get_rud(
-       struct xfs_trans                *tp,
-       struct xfs_rui_log_item         *ruip)
-{
-       struct xfs_rud_log_item         *rudp;
-
-       rudp = xfs_rud_init(tp->t_mountp, ruip);
-       xfs_trans_add_item(tp, &rudp->rud_item);
-       return rudp;
-}
-
-/*
- * Finish an rmap update and log it to the RUD. Note that the transaction is
- * marked dirty regardless of whether the rmap update succeeds or fails to
- * support the RUI/RUD lifecycle rules.
- */
-int
-xfs_trans_log_finish_rmap_update(
-       struct xfs_trans                *tp,
-       struct xfs_rud_log_item         *rudp,
-       enum xfs_rmap_intent_type       type,
-       uint64_t                        owner,
-       int                             whichfork,
-       xfs_fileoff_t                   startoff,
-       xfs_fsblock_t                   startblock,
-       xfs_filblks_t                   blockcount,
-       xfs_exntst_t                    state,
-       struct xfs_btree_cur            **pcur)
-{
-       int                             error;
-
-       error = xfs_rmap_finish_one(tp, type, owner, whichfork, startoff,
-                       startblock, blockcount, state, pcur);
-
-       /*
-        * Mark the transaction dirty, even on error. This ensures the
-        * transaction is aborted, which:
-        *
-        * 1.) releases the RUI and frees the RUD
-        * 2.) shuts down the filesystem
-        */
-       tp->t_flags |= XFS_TRANS_DIRTY;
-       set_bit(XFS_LI_DIRTY, &rudp->rud_item.li_flags);
-
-       return error;
-}
-
-/* Sort rmap intents by AG. */
-static int
-xfs_rmap_update_diff_items(
-       void                            *priv,
-       struct list_head                *a,
-       struct list_head                *b)
-{
-       struct xfs_mount                *mp = priv;
-       struct xfs_rmap_intent          *ra;
-       struct xfs_rmap_intent          *rb;
-
-       ra = container_of(a, struct xfs_rmap_intent, ri_list);
-       rb = container_of(b, struct xfs_rmap_intent, ri_list);
-       return  XFS_FSB_TO_AGNO(mp, ra->ri_bmap.br_startblock) -
-               XFS_FSB_TO_AGNO(mp, rb->ri_bmap.br_startblock);
-}
-
-/* Get an RUI. */
-STATIC void *
-xfs_rmap_update_create_intent(
-       struct xfs_trans                *tp,
-       unsigned int                    count)
-{
-       struct xfs_rui_log_item         *ruip;
-
-       ASSERT(tp != NULL);
-       ASSERT(count > 0);
-
-       ruip = xfs_rui_init(tp->t_mountp, count);
-       ASSERT(ruip != NULL);
-
-       /*
-        * Get a log_item_desc to point at the new item.
-        */
-       xfs_trans_add_item(tp, &ruip->rui_item);
-       return ruip;
-}
-
-/* Log rmap updates in the intent item. */
-STATIC void
-xfs_rmap_update_log_item(
-       struct xfs_trans                *tp,
-       void                            *intent,
-       struct list_head                *item)
-{
-       struct xfs_rui_log_item         *ruip = intent;
-       struct xfs_rmap_intent          *rmap;
-       uint                            next_extent;
-       struct xfs_map_extent           *map;
-
-       rmap = container_of(item, struct xfs_rmap_intent, ri_list);
-
-       tp->t_flags |= XFS_TRANS_DIRTY;
-       set_bit(XFS_LI_DIRTY, &ruip->rui_item.li_flags);
-
-       /*
-        * atomic_inc_return gives us the value after the increment;
-        * we want to use it as an array index so we need to subtract 1 from
-        * it.
-        */
-       next_extent = atomic_inc_return(&ruip->rui_next_extent) - 1;
-       ASSERT(next_extent < ruip->rui_format.rui_nextents);
-       map = &ruip->rui_format.rui_extents[next_extent];
-       map->me_owner = rmap->ri_owner;
-       map->me_startblock = rmap->ri_bmap.br_startblock;
-       map->me_startoff = rmap->ri_bmap.br_startoff;
-       map->me_len = rmap->ri_bmap.br_blockcount;
-       xfs_trans_set_rmap_flags(map, rmap->ri_type, rmap->ri_whichfork,
-                       rmap->ri_bmap.br_state);
-}
-
-/* Get an RUD so we can process all the deferred rmap updates. */
-STATIC void *
-xfs_rmap_update_create_done(
-       struct xfs_trans                *tp,
-       void                            *intent,
-       unsigned int                    count)
-{
-       return xfs_trans_get_rud(tp, intent);
-}
-
-/* Process a deferred rmap update. */
-STATIC int
-xfs_rmap_update_finish_item(
-       struct xfs_trans                *tp,
-       struct list_head                *item,
-       void                            *done_item,
-       void                            **state)
-{
-       struct xfs_rmap_intent          *rmap;
-       int                             error;
-
-       rmap = container_of(item, struct xfs_rmap_intent, ri_list);
-       error = xfs_trans_log_finish_rmap_update(tp, done_item,
-                       rmap->ri_type,
-                       rmap->ri_owner, rmap->ri_whichfork,
-                       rmap->ri_bmap.br_startoff,
-                       rmap->ri_bmap.br_startblock,
-                       rmap->ri_bmap.br_blockcount,
-                       rmap->ri_bmap.br_state,
-                       (struct xfs_btree_cur **)state);
-       kmem_free(rmap);
-       return error;
-}
-
-/* Clean up after processing deferred rmaps. */
-STATIC void
-xfs_rmap_update_finish_cleanup(
-       struct xfs_trans        *tp,
-       void                    *state,
-       int                     error)
-{
-       struct xfs_btree_cur    *rcur = state;
-
-       xfs_rmap_finish_one_cleanup(tp, rcur, error);
-}
-
-/* Abort all pending RUIs. */
-STATIC void
-xfs_rmap_update_abort_intent(
-       void                            *intent)
-{
-       xfs_rui_release(intent);
-}
-
-/* Cancel a deferred rmap update. */
-STATIC void
-xfs_rmap_update_cancel_item(
-       struct list_head                *item)
-{
-       struct xfs_rmap_intent          *rmap;
-
-       rmap = container_of(item, struct xfs_rmap_intent, ri_list);
-       kmem_free(rmap);
-}
-
-const struct xfs_defer_op_type xfs_rmap_update_defer_type = {
-       .max_items      = XFS_RUI_MAX_FAST_EXTENTS,
-       .diff_items     = xfs_rmap_update_diff_items,
-       .create_intent  = xfs_rmap_update_create_intent,
-       .abort_intent   = xfs_rmap_update_abort_intent,
-       .log_item       = xfs_rmap_update_log_item,
-       .create_done    = xfs_rmap_update_create_done,
-       .finish_item    = xfs_rmap_update_finish_item,
-       .finish_cleanup = xfs_rmap_update_finish_cleanup,
-       .cancel_item    = xfs_rmap_update_cancel_item,
-};
index 9a63016..3123b5a 100644 (file)
@@ -5,15 +5,12 @@
  */
 
 #include "xfs.h"
+#include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
-#include "xfs_trans_resv.h"
-#include "xfs_mount.h"
 #include "xfs_da_format.h"
 #include "xfs_inode.h"
 #include "xfs_attr.h"
-#include "xfs_attr_leaf.h"
-#include "xfs_acl.h"
 
 #include <linux/posix_acl_xattr.h>
 #include <linux/xattr.h>
diff --git a/include/Kbuild b/include/Kbuild
new file mode 100644 (file)
index 0000000..7e9f1ac
--- /dev/null
@@ -0,0 +1,1270 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+# Add header-test-$(CONFIG_...) guard to headers that are only compiled
+# for particular architectures.
+#
+# Headers listed in header-test- are excluded from the test coverage.
+# Many headers are excluded for now because they fail to build. Please
+# consider to fix headers first before adding new ones to the blacklist.
+#
+# Sorted alphabetically.
+header-test-                   += acpi/acbuffer.h
+header-test-                   += acpi/acpi.h
+header-test-                   += acpi/acpi_bus.h
+header-test-                   += acpi/acpi_drivers.h
+header-test-                   += acpi/acpi_io.h
+header-test-                   += acpi/acpi_lpat.h
+header-test-                   += acpi/acpiosxf.h
+header-test-                   += acpi/acpixf.h
+header-test-                   += acpi/acrestyp.h
+header-test-                   += acpi/actbl.h
+header-test-                   += acpi/actbl1.h
+header-test-                   += acpi/actbl2.h
+header-test-                   += acpi/actbl3.h
+header-test-                   += acpi/actypes.h
+header-test-                   += acpi/battery.h
+header-test-                   += acpi/cppc_acpi.h
+header-test-                   += acpi/nfit.h
+header-test-                   += acpi/platform/acenv.h
+header-test-                   += acpi/platform/acenvex.h
+header-test-                   += acpi/platform/acintel.h
+header-test-                   += acpi/platform/aclinux.h
+header-test-                   += acpi/platform/aclinuxex.h
+header-test-                   += acpi/processor.h
+header-test-                   += clocksource/hyperv_timer.h
+header-test-                   += clocksource/timer-sp804.h
+header-test-                   += crypto/cast_common.h
+header-test-                   += crypto/internal/cryptouser.h
+header-test-                   += crypto/pkcs7.h
+header-test-                   += crypto/poly1305.h
+header-test-                   += crypto/sha3.h
+header-test-                   += drm/ati_pcigart.h
+header-test-                   += drm/bridge/dw_hdmi.h
+header-test-                   += drm/bridge/dw_mipi_dsi.h
+header-test-                   += drm/drm_audio_component.h
+header-test-                   += drm/drm_auth.h
+header-test-                   += drm/drm_debugfs.h
+header-test-                   += drm/drm_debugfs_crc.h
+header-test-                   += drm/drm_displayid.h
+header-test-                   += drm/drm_encoder_slave.h
+header-test-                   += drm/drm_fb_cma_helper.h
+header-test-                   += drm/drm_fb_helper.h
+header-test-                   += drm/drm_fixed.h
+header-test-                   += drm/drm_format_helper.h
+header-test-                   += drm/drm_lease.h
+header-test-                   += drm/drm_legacy.h
+header-test-                   += drm/drm_panel.h
+header-test-                   += drm/drm_plane_helper.h
+header-test-                   += drm/drm_rect.h
+header-test-                   += drm/i915_component.h
+header-test-                   += drm/intel-gtt.h
+header-test-                   += drm/tinydrm/tinydrm-helpers.h
+header-test-                   += drm/ttm/ttm_debug.h
+header-test-                   += keys/asymmetric-parser.h
+header-test-                   += keys/asymmetric-subtype.h
+header-test-                   += keys/asymmetric-type.h
+header-test-                   += keys/big_key-type.h
+header-test-                   += keys/request_key_auth-type.h
+header-test-                   += keys/trusted.h
+header-test-                   += kvm/arm_arch_timer.h
+header-test-                   += kvm/arm_pmu.h
+header-test-$(CONFIG_ARM)      += kvm/arm_psci.h
+header-test-$(CONFIG_ARM64)    += kvm/arm_psci.h
+header-test-                   += kvm/arm_vgic.h
+header-test-                   += linux/8250_pci.h
+header-test-                   += linux/a.out.h
+header-test-                   += linux/adxl.h
+header-test-                   += linux/agpgart.h
+header-test-                   += linux/alcor_pci.h
+header-test-                   += linux/amba/clcd.h
+header-test-                   += linux/amba/pl080.h
+header-test-                   += linux/amd-iommu.h
+header-test-$(CONFIG_ARM)      += linux/arm-cci.h
+header-test-$(CONFIG_ARM64)    += linux/arm-cci.h
+header-test-                   += linux/arm_sdei.h
+header-test-                   += linux/asn1_decoder.h
+header-test-                   += linux/ata_platform.h
+header-test-                   += linux/ath9k_platform.h
+header-test-                   += linux/atm_tcp.h
+header-test-                   += linux/atomic-fallback.h
+header-test-                   += linux/avf/virtchnl.h
+header-test-                   += linux/bcm47xx_sprom.h
+header-test-                   += linux/bcma/bcma_driver_gmac_cmn.h
+header-test-                   += linux/bcma/bcma_driver_mips.h
+header-test-                   += linux/bcma/bcma_driver_pci.h
+header-test-                   += linux/bcma/bcma_driver_pcie2.h
+header-test-                   += linux/bit_spinlock.h
+header-test-                   += linux/blk-mq-rdma.h
+header-test-                   += linux/blk-mq.h
+header-test-                   += linux/blktrace_api.h
+header-test-                   += linux/blockgroup_lock.h
+header-test-                   += linux/bma150.h
+header-test-                   += linux/bpf_lirc.h
+header-test-                   += linux/bpf_types.h
+header-test-                   += linux/bsg-lib.h
+header-test-                   += linux/bsg.h
+header-test-                   += linux/btf.h
+header-test-                   += linux/btree-128.h
+header-test-                   += linux/btree-type.h
+header-test-$(CONFIG_CPU_BIG_ENDIAN) += linux/byteorder/big_endian.h
+header-test-                   += linux/byteorder/generic.h
+header-test-$(CONFIG_CPU_LITTLE_ENDIAN) += linux/byteorder/little_endian.h
+header-test-                   += linux/c2port.h
+header-test-                   += linux/can/dev/peak_canfd.h
+header-test-                   += linux/can/platform/cc770.h
+header-test-                   += linux/can/platform/sja1000.h
+header-test-                   += linux/ceph/ceph_features.h
+header-test-                   += linux/ceph/ceph_frag.h
+header-test-                   += linux/ceph/ceph_fs.h
+header-test-                   += linux/ceph/debugfs.h
+header-test-                   += linux/ceph/msgr.h
+header-test-                   += linux/ceph/rados.h
+header-test-                   += linux/cgroup_subsys.h
+header-test-                   += linux/clk/sunxi-ng.h
+header-test-                   += linux/clk/ti.h
+header-test-                   += linux/cn_proc.h
+header-test-                   += linux/coda_psdev.h
+header-test-                   += linux/compaction.h
+header-test-                   += linux/console_struct.h
+header-test-                   += linux/count_zeros.h
+header-test-                   += linux/cs5535.h
+header-test-                   += linux/cuda.h
+header-test-                   += linux/cyclades.h
+header-test-                   += linux/dcookies.h
+header-test-                   += linux/delayacct.h
+header-test-                   += linux/delayed_call.h
+header-test-                   += linux/device-mapper.h
+header-test-                   += linux/devpts_fs.h
+header-test-                   += linux/dio.h
+header-test-                   += linux/dirent.h
+header-test-                   += linux/dlm_plock.h
+header-test-                   += linux/dm-dirty-log.h
+header-test-                   += linux/dm-region-hash.h
+header-test-                   += linux/dma-debug.h
+header-test-                   += linux/dma/mmp-pdma.h
+header-test-                   += linux/dma/sprd-dma.h
+header-test-                   += linux/dns_resolver.h
+header-test-                   += linux/drbd_genl.h
+header-test-                   += linux/drbd_genl_api.h
+header-test-                   += linux/dw_apb_timer.h
+header-test-                   += linux/dynamic_debug.h
+header-test-                   += linux/dynamic_queue_limits.h
+header-test-                   += linux/ecryptfs.h
+header-test-                   += linux/edma.h
+header-test-                   += linux/eeprom_93cx6.h
+header-test-                   += linux/efs_vh.h
+header-test-                   += linux/elevator.h
+header-test-                   += linux/elfcore-compat.h
+header-test-                   += linux/error-injection.h
+header-test-                   += linux/errseq.h
+header-test-                   += linux/eventpoll.h
+header-test-                   += linux/ext2_fs.h
+header-test-                   += linux/f75375s.h
+header-test-                   += linux/falloc.h
+header-test-                   += linux/fault-inject.h
+header-test-                   += linux/fbcon.h
+header-test-                   += linux/firmware/intel/stratix10-svc-client.h
+header-test-                   += linux/firmware/meson/meson_sm.h
+header-test-                   += linux/firmware/trusted_foundations.h
+header-test-                   += linux/firmware/xlnx-zynqmp.h
+header-test-                   += linux/fixp-arith.h
+header-test-                   += linux/flat.h
+header-test-                   += linux/fs_types.h
+header-test-                   += linux/fs_uart_pd.h
+header-test-                   += linux/fsi-occ.h
+header-test-                   += linux/fsi-sbefifo.h
+header-test-                   += linux/fsl/bestcomm/ata.h
+header-test-                   += linux/fsl/bestcomm/bestcomm.h
+header-test-                   += linux/fsl/bestcomm/bestcomm_priv.h
+header-test-                   += linux/fsl/bestcomm/fec.h
+header-test-                   += linux/fsl/bestcomm/gen_bd.h
+header-test-                   += linux/fsl/bestcomm/sram.h
+header-test-                   += linux/fsl_hypervisor.h
+header-test-                   += linux/fsldma.h
+header-test-                   += linux/ftrace_irq.h
+header-test-                   += linux/gameport.h
+header-test-                   += linux/genl_magic_func.h
+header-test-                   += linux/genl_magic_struct.h
+header-test-                   += linux/gpio/aspeed.h
+header-test-                   += linux/gpio/gpio-reg.h
+header-test-                   += linux/hid-debug.h
+header-test-                   += linux/hiddev.h
+header-test-                   += linux/hippidevice.h
+header-test-                   += linux/hmm.h
+header-test-                   += linux/hp_sdc.h
+header-test-                   += linux/huge_mm.h
+header-test-                   += linux/hugetlb_cgroup.h
+header-test-                   += linux/hugetlb_inline.h
+header-test-                   += linux/hwmon-vid.h
+header-test-                   += linux/hyperv.h
+header-test-                   += linux/i2c-algo-pca.h
+header-test-                   += linux/i2c-algo-pcf.h
+header-test-                   += linux/i3c/ccc.h
+header-test-                   += linux/i3c/device.h
+header-test-                   += linux/i3c/master.h
+header-test-                   += linux/i8042.h
+header-test-                   += linux/ide.h
+header-test-                   += linux/idle_inject.h
+header-test-                   += linux/if_frad.h
+header-test-                   += linux/if_rmnet.h
+header-test-                   += linux/if_tap.h
+header-test-                   += linux/iio/accel/kxcjk_1013.h
+header-test-                   += linux/iio/adc/ad_sigma_delta.h
+header-test-                   += linux/iio/buffer-dma.h
+header-test-                   += linux/iio/buffer_impl.h
+header-test-                   += linux/iio/common/st_sensors.h
+header-test-                   += linux/iio/common/st_sensors_i2c.h
+header-test-                   += linux/iio/common/st_sensors_spi.h
+header-test-                   += linux/iio/dac/ad5421.h
+header-test-                   += linux/iio/dac/ad5504.h
+header-test-                   += linux/iio/dac/ad5791.h
+header-test-                   += linux/iio/dac/max517.h
+header-test-                   += linux/iio/dac/mcp4725.h
+header-test-                   += linux/iio/frequency/ad9523.h
+header-test-                   += linux/iio/frequency/adf4350.h
+header-test-                   += linux/iio/hw-consumer.h
+header-test-                   += linux/iio/imu/adis.h
+header-test-                   += linux/iio/sysfs.h
+header-test-                   += linux/iio/timer/stm32-timer-trigger.h
+header-test-                   += linux/iio/trigger.h
+header-test-                   += linux/iio/triggered_event.h
+header-test-                   += linux/imx-media.h
+header-test-                   += linux/inet_diag.h
+header-test-                   += linux/init_ohci1394_dma.h
+header-test-                   += linux/initrd.h
+header-test-                   += linux/input/adp5589.h
+header-test-                   += linux/input/bu21013.h
+header-test-                   += linux/input/cma3000.h
+header-test-                   += linux/input/kxtj9.h
+header-test-                   += linux/input/lm8333.h
+header-test-                   += linux/input/sparse-keymap.h
+header-test-                   += linux/input/touchscreen.h
+header-test-                   += linux/input/tps6507x-ts.h
+header-test-$(CONFIG_X86)      += linux/intel-iommu.h
+header-test-                   += linux/intel-ish-client-if.h
+header-test-                   += linux/intel-pti.h
+header-test-                   += linux/intel-svm.h
+header-test-                   += linux/interconnect-provider.h
+header-test-                   += linux/ioc3.h
+header-test-                   += linux/ipack.h
+header-test-                   += linux/irq_cpustat.h
+header-test-                   += linux/irq_poll.h
+header-test-                   += linux/irqchip/arm-gic-v3.h
+header-test-                   += linux/irqchip/arm-gic-v4.h
+header-test-                   += linux/irqchip/irq-madera.h
+header-test-                   += linux/irqchip/irq-sa11x0.h
+header-test-                   += linux/irqchip/mxs.h
+header-test-                   += linux/irqchip/versatile-fpga.h
+header-test-                   += linux/irqdesc.h
+header-test-                   += linux/irqflags.h
+header-test-                   += linux/iscsi_boot_sysfs.h
+header-test-                   += linux/isdn/capiutil.h
+header-test-                   += linux/isdn/hdlc.h
+header-test-                   += linux/isdn_ppp.h
+header-test-                   += linux/jbd2.h
+header-test-                   += linux/jump_label.h
+header-test-                   += linux/jump_label_ratelimit.h
+header-test-                   += linux/jz4740-adc.h
+header-test-                   += linux/kasan.h
+header-test-                   += linux/kcore.h
+header-test-                   += linux/kdev_t.h
+header-test-                   += linux/kernelcapi.h
+header-test-                   += linux/khugepaged.h
+header-test-                   += linux/kobj_map.h
+header-test-                   += linux/kobject_ns.h
+header-test-                   += linux/kvm_host.h
+header-test-                   += linux/kvm_irqfd.h
+header-test-                   += linux/kvm_para.h
+header-test-                   += linux/lantiq.h
+header-test-                   += linux/lapb.h
+header-test-                   += linux/latencytop.h
+header-test-                   += linux/led-lm3530.h
+header-test-                   += linux/leds-bd2802.h
+header-test-                   += linux/leds-lp3944.h
+header-test-                   += linux/leds-lp3952.h
+header-test-                   += linux/leds_pwm.h
+header-test-                   += linux/libata.h
+header-test-                   += linux/license.h
+header-test-                   += linux/lightnvm.h
+header-test-                   += linux/lis3lv02d.h
+header-test-                   += linux/list_bl.h
+header-test-                   += linux/list_lru.h
+header-test-                   += linux/list_nulls.h
+header-test-                   += linux/lockd/share.h
+header-test-                   += linux/lzo.h
+header-test-                   += linux/mailbox/zynqmp-ipi-message.h
+header-test-                   += linux/maple.h
+header-test-                   += linux/mbcache.h
+header-test-                   += linux/mbus.h
+header-test-                   += linux/mc146818rtc.h
+header-test-                   += linux/mc6821.h
+header-test-                   += linux/mdev.h
+header-test-                   += linux/mem_encrypt.h
+header-test-                   += linux/memfd.h
+header-test-                   += linux/mfd/88pm80x.h
+header-test-                   += linux/mfd/88pm860x.h
+header-test-                   += linux/mfd/abx500/ab8500-bm.h
+header-test-                   += linux/mfd/abx500/ab8500-gpadc.h
+header-test-                   += linux/mfd/adp5520.h
+header-test-                   += linux/mfd/arizona/pdata.h
+header-test-                   += linux/mfd/as3711.h
+header-test-                   += linux/mfd/as3722.h
+header-test-                   += linux/mfd/cros_ec_commands.h
+header-test-                   += linux/mfd/da903x.h
+header-test-                   += linux/mfd/da9055/pdata.h
+header-test-                   += linux/mfd/da9063/pdata.h
+header-test-                   += linux/mfd/db8500-prcmu.h
+header-test-                   += linux/mfd/dbx500-prcmu.h
+header-test-                   += linux/mfd/dln2.h
+header-test-                   += linux/mfd/dm355evm_msp.h
+header-test-                   += linux/mfd/ds1wm.h
+header-test-                   += linux/mfd/ezx-pcap.h
+header-test-                   += linux/mfd/intel_msic.h
+header-test-                   += linux/mfd/janz.h
+header-test-                   += linux/mfd/kempld.h
+header-test-                   += linux/mfd/lm3533.h
+header-test-                   += linux/mfd/lp8788-isink.h
+header-test-                   += linux/mfd/lpc_ich.h
+header-test-                   += linux/mfd/max77693.h
+header-test-                   += linux/mfd/max8998-private.h
+header-test-                   += linux/mfd/menelaus.h
+header-test-                   += linux/mfd/mt6397/core.h
+header-test-                   += linux/mfd/palmas.h
+header-test-                   += linux/mfd/pcf50633/backlight.h
+header-test-                   += linux/mfd/rc5t583.h
+header-test-                   += linux/mfd/retu.h
+header-test-                   += linux/mfd/samsung/core.h
+header-test-                   += linux/mfd/si476x-platform.h
+header-test-                   += linux/mfd/si476x-reports.h
+header-test-                   += linux/mfd/sky81452.h
+header-test-                   += linux/mfd/smsc.h
+header-test-                   += linux/mfd/sta2x11-mfd.h
+header-test-                   += linux/mfd/stmfx.h
+header-test-                   += linux/mfd/tc3589x.h
+header-test-                   += linux/mfd/tc6387xb.h
+header-test-                   += linux/mfd/tc6393xb.h
+header-test-                   += linux/mfd/tps65090.h
+header-test-                   += linux/mfd/tps6586x.h
+header-test-                   += linux/mfd/tps65910.h
+header-test-                   += linux/mfd/tps80031.h
+header-test-                   += linux/mfd/ucb1x00.h
+header-test-                   += linux/mfd/viperboard.h
+header-test-                   += linux/mfd/wm831x/core.h
+header-test-                   += linux/mfd/wm831x/otp.h
+header-test-                   += linux/mfd/wm831x/pdata.h
+header-test-                   += linux/mfd/wm8994/core.h
+header-test-                   += linux/mfd/wm8994/pdata.h
+header-test-                   += linux/mlx4/doorbell.h
+header-test-                   += linux/mlx4/srq.h
+header-test-                   += linux/mlx5/doorbell.h
+header-test-                   += linux/mlx5/eq.h
+header-test-                   += linux/mlx5/fs_helpers.h
+header-test-                   += linux/mlx5/mlx5_ifc.h
+header-test-                   += linux/mlx5/mlx5_ifc_fpga.h
+header-test-                   += linux/mm-arch-hooks.h
+header-test-                   += linux/mm_inline.h
+header-test-                   += linux/mmu_context.h
+header-test-                   += linux/mpage.h
+header-test-                   += linux/mtd/bbm.h
+header-test-                   += linux/mtd/cfi.h
+header-test-                   += linux/mtd/doc2000.h
+header-test-                   += linux/mtd/flashchip.h
+header-test-                   += linux/mtd/ftl.h
+header-test-                   += linux/mtd/gen_probe.h
+header-test-                   += linux/mtd/jedec.h
+header-test-                   += linux/mtd/nand_bch.h
+header-test-                   += linux/mtd/nand_ecc.h
+header-test-                   += linux/mtd/ndfc.h
+header-test-                   += linux/mtd/onenand.h
+header-test-                   += linux/mtd/pismo.h
+header-test-                   += linux/mtd/plat-ram.h
+header-test-                   += linux/mtd/spi-nor.h
+header-test-                   += linux/mv643xx.h
+header-test-                   += linux/mv643xx_eth.h
+header-test-                   += linux/mvebu-pmsu.h
+header-test-                   += linux/mxm-wmi.h
+header-test-                   += linux/n_r3964.h
+header-test-                   += linux/ndctl.h
+header-test-                   += linux/netfilter/ipset/ip_set.h
+header-test-                   += linux/netfilter/ipset/ip_set_bitmap.h
+header-test-                   += linux/netfilter/ipset/ip_set_comment.h
+header-test-                   += linux/netfilter/ipset/ip_set_counter.h
+header-test-                   += linux/netfilter/ipset/ip_set_getport.h
+header-test-                   += linux/netfilter/ipset/ip_set_hash.h
+header-test-                   += linux/netfilter/ipset/ip_set_list.h
+header-test-                   += linux/netfilter/ipset/ip_set_skbinfo.h
+header-test-                   += linux/netfilter/ipset/ip_set_timeout.h
+header-test-                   += linux/netfilter/nf_conntrack_amanda.h
+header-test-                   += linux/netfilter/nf_conntrack_ftp.h
+header-test-                   += linux/netfilter/nf_conntrack_h323.h
+header-test-                   += linux/netfilter/nf_conntrack_h323_asn1.h
+header-test-                   += linux/netfilter/nf_conntrack_irc.h
+header-test-                   += linux/netfilter/nf_conntrack_pptp.h
+header-test-                   += linux/netfilter/nf_conntrack_proto_gre.h
+header-test-                   += linux/netfilter/nf_conntrack_sip.h
+header-test-                   += linux/netfilter/nf_conntrack_snmp.h
+header-test-                   += linux/netfilter/nf_conntrack_tftp.h
+header-test-                   += linux/netfilter/x_tables.h
+header-test-                   += linux/netfilter_arp/arp_tables.h
+header-test-                   += linux/netfilter_bridge/ebtables.h
+header-test-                   += linux/netfilter_ipv4/ip4_tables.h
+header-test-                   += linux/netfilter_ipv4/ip_tables.h
+header-test-                   += linux/netfilter_ipv6/ip6_tables.h
+header-test-                   += linux/nfs.h
+header-test-                   += linux/nfs_fs_i.h
+header-test-                   += linux/nfs_fs_sb.h
+header-test-                   += linux/nfs_page.h
+header-test-                   += linux/nfs_xdr.h
+header-test-                   += linux/nfsacl.h
+header-test-                   += linux/nl802154.h
+header-test-                   += linux/ns_common.h
+header-test-                   += linux/nsc_gpio.h
+header-test-                   += linux/ntb_transport.h
+header-test-                   += linux/nubus.h
+header-test-                   += linux/nvme-fc-driver.h
+header-test-                   += linux/nvme-fc.h
+header-test-                   += linux/nvme-rdma.h
+header-test-                   += linux/nvram.h
+header-test-                   += linux/objagg.h
+header-test-                   += linux/of_clk.h
+header-test-                   += linux/of_net.h
+header-test-                   += linux/of_pdt.h
+header-test-                   += linux/olpc-ec.h
+header-test-                   += linux/omap-dma.h
+header-test-                   += linux/omap-dmaengine.h
+header-test-                   += linux/omap-gpmc.h
+header-test-                   += linux/omap-iommu.h
+header-test-                   += linux/omap-mailbox.h
+header-test-                   += linux/once.h
+header-test-                   += linux/osq_lock.h
+header-test-                   += linux/overflow.h
+header-test-                   += linux/page-flags-layout.h
+header-test-                   += linux/page-isolation.h
+header-test-                   += linux/page_ext.h
+header-test-                   += linux/page_owner.h
+header-test-                   += linux/parport_pc.h
+header-test-                   += linux/parser.h
+header-test-                   += linux/pci-acpi.h
+header-test-                   += linux/pci-dma-compat.h
+header-test-                   += linux/pci_hotplug.h
+header-test-                   += linux/pda_power.h
+header-test-                   += linux/perf/arm_pmu.h
+header-test-                   += linux/perf_regs.h
+header-test-                   += linux/phy/omap_control_phy.h
+header-test-                   += linux/phy/tegra/xusb.h
+header-test-                   += linux/phy/ulpi_phy.h
+header-test-                   += linux/phy_fixed.h
+header-test-                   += linux/pinctrl/pinconf-generic.h
+header-test-                   += linux/pinctrl/pinconf.h
+header-test-                   += linux/pinctrl/pinctrl.h
+header-test-                   += linux/pipe_fs_i.h
+header-test-                   += linux/pktcdvd.h
+header-test-                   += linux/pl320-ipc.h
+header-test-                   += linux/pl353-smc.h
+header-test-                   += linux/platform_data/ad5449.h
+header-test-                   += linux/platform_data/ad5755.h
+header-test-                   += linux/platform_data/ad7266.h
+header-test-                   += linux/platform_data/ad7291.h
+header-test-                   += linux/platform_data/ad7298.h
+header-test-                   += linux/platform_data/ad7303.h
+header-test-                   += linux/platform_data/ad7791.h
+header-test-                   += linux/platform_data/ad7793.h
+header-test-                   += linux/platform_data/ad7887.h
+header-test-                   += linux/platform_data/adau17x1.h
+header-test-                   += linux/platform_data/adp8870.h
+header-test-                   += linux/platform_data/ads1015.h
+header-test-                   += linux/platform_data/ads7828.h
+header-test-                   += linux/platform_data/apds990x.h
+header-test-                   += linux/platform_data/arm-ux500-pm.h
+header-test-                   += linux/platform_data/asoc-s3c.h
+header-test-                   += linux/platform_data/at91_adc.h
+header-test-                   += linux/platform_data/ata-pxa.h
+header-test-                   += linux/platform_data/atmel.h
+header-test-                   += linux/platform_data/bh1770glc.h
+header-test-                   += linux/platform_data/brcmfmac.h
+header-test-                   += linux/platform_data/clk-u300.h
+header-test-                   += linux/platform_data/cyttsp4.h
+header-test-                   += linux/platform_data/dma-coh901318.h
+header-test-                   += linux/platform_data/dma-imx-sdma.h
+header-test-                   += linux/platform_data/dma-mcf-edma.h
+header-test-                   += linux/platform_data/dma-s3c24xx.h
+header-test-                   += linux/platform_data/dmtimer-omap.h
+header-test-                   += linux/platform_data/dsa.h
+header-test-                   += linux/platform_data/edma.h
+header-test-                   += linux/platform_data/elm.h
+header-test-                   += linux/platform_data/emif_plat.h
+header-test-                   += linux/platform_data/fsa9480.h
+header-test-                   += linux/platform_data/g762.h
+header-test-                   += linux/platform_data/gpio-ath79.h
+header-test-                   += linux/platform_data/gpio-davinci.h
+header-test-                   += linux/platform_data/gpio-dwapb.h
+header-test-                   += linux/platform_data/gpio-htc-egpio.h
+header-test-                   += linux/platform_data/gpmc-omap.h
+header-test-                   += linux/platform_data/hsmmc-omap.h
+header-test-                   += linux/platform_data/hwmon-s3c.h
+header-test-                   += linux/platform_data/i2c-davinci.h
+header-test-                   += linux/platform_data/i2c-imx.h
+header-test-                   += linux/platform_data/i2c-mux-reg.h
+header-test-                   += linux/platform_data/i2c-ocores.h
+header-test-                   += linux/platform_data/i2c-xiic.h
+header-test-                   += linux/platform_data/intel-spi.h
+header-test-                   += linux/platform_data/invensense_mpu6050.h
+header-test-                   += linux/platform_data/irda-pxaficp.h
+header-test-                   += linux/platform_data/irda-sa11x0.h
+header-test-                   += linux/platform_data/itco_wdt.h
+header-test-                   += linux/platform_data/jz4740/jz4740_nand.h
+header-test-                   += linux/platform_data/keyboard-pxa930_rotary.h
+header-test-                   += linux/platform_data/keypad-omap.h
+header-test-                   += linux/platform_data/leds-lp55xx.h
+header-test-                   += linux/platform_data/leds-omap.h
+header-test-                   += linux/platform_data/lp855x.h
+header-test-                   += linux/platform_data/lp8727.h
+header-test-                   += linux/platform_data/max197.h
+header-test-                   += linux/platform_data/max3421-hcd.h
+header-test-                   += linux/platform_data/max732x.h
+header-test-                   += linux/platform_data/mcs.h
+header-test-                   += linux/platform_data/mdio-bcm-unimac.h
+header-test-                   += linux/platform_data/mdio-gpio.h
+header-test-                   += linux/platform_data/media/si4713.h
+header-test-                   += linux/platform_data/mlxreg.h
+header-test-                   += linux/platform_data/mmc-omap.h
+header-test-                   += linux/platform_data/mmc-sdhci-s3c.h
+header-test-                   += linux/platform_data/mmp_audio.h
+header-test-                   += linux/platform_data/mtd-orion_nand.h
+header-test-                   += linux/platform_data/mv88e6xxx.h
+header-test-                   += linux/platform_data/net-cw1200.h
+header-test-                   += linux/platform_data/omap-twl4030.h
+header-test-                   += linux/platform_data/omapdss.h
+header-test-                   += linux/platform_data/pcf857x.h
+header-test-                   += linux/platform_data/pixcir_i2c_ts.h
+header-test-                   += linux/platform_data/pwm_omap_dmtimer.h
+header-test-                   += linux/platform_data/pxa2xx_udc.h
+header-test-                   += linux/platform_data/pxa_sdhci.h
+header-test-                   += linux/platform_data/remoteproc-omap.h
+header-test-                   += linux/platform_data/sa11x0-serial.h
+header-test-                   += linux/platform_data/sc18is602.h
+header-test-                   += linux/platform_data/sdhci-pic32.h
+header-test-                   += linux/platform_data/serial-sccnxp.h
+header-test-                   += linux/platform_data/sht3x.h
+header-test-                   += linux/platform_data/shtc1.h
+header-test-                   += linux/platform_data/si5351.h
+header-test-                   += linux/platform_data/sky81452-backlight.h
+header-test-                   += linux/platform_data/spi-davinci.h
+header-test-                   += linux/platform_data/spi-ep93xx.h
+header-test-                   += linux/platform_data/spi-mt65xx.h
+header-test-                   += linux/platform_data/spi-nuc900.h
+header-test-                   += linux/platform_data/st_sensors_pdata.h
+header-test-                   += linux/platform_data/ti-sysc.h
+header-test-                   += linux/platform_data/timer-ixp4xx.h
+header-test-                   += linux/platform_data/touchscreen-s3c2410.h
+header-test-                   += linux/platform_data/tsc2007.h
+header-test-                   += linux/platform_data/tsl2772.h
+header-test-                   += linux/platform_data/uio_pruss.h
+header-test-                   += linux/platform_data/usb-davinci.h
+header-test-                   += linux/platform_data/usb-ehci-mxc.h
+header-test-                   += linux/platform_data/usb-ehci-orion.h
+header-test-                   += linux/platform_data/usb-mx2.h
+header-test-                   += linux/platform_data/usb-ohci-s3c2410.h
+header-test-                   += linux/platform_data/usb-omap.h
+header-test-                   += linux/platform_data/usb-s3c2410_udc.h
+header-test-                   += linux/platform_data/usb3503.h
+header-test-                   += linux/platform_data/ux500_wdt.h
+header-test-                   += linux/platform_data/video-clcd-versatile.h
+header-test-                   += linux/platform_data/video-imxfb.h
+header-test-                   += linux/platform_data/video-nuc900fb.h
+header-test-                   += linux/platform_data/video-pxafb.h
+header-test-                   += linux/platform_data/video_s3c.h
+header-test-                   += linux/platform_data/voltage-omap.h
+header-test-                   += linux/platform_data/x86/apple.h
+header-test-                   += linux/platform_data/x86/clk-pmc-atom.h
+header-test-                   += linux/platform_data/x86/pmc_atom.h
+header-test-                   += linux/platform_data/xtalk-bridge.h
+header-test-                   += linux/pm2301_charger.h
+header-test-                   += linux/pm_wakeirq.h
+header-test-                   += linux/pm_wakeup.h
+header-test-                   += linux/pmbus.h
+header-test-                   += linux/pmu.h
+header-test-                   += linux/posix_acl.h
+header-test-                   += linux/posix_acl_xattr.h
+header-test-                   += linux/power/ab8500.h
+header-test-                   += linux/power/bq27xxx_battery.h
+header-test-                   += linux/power/generic-adc-battery.h
+header-test-                   += linux/power/jz4740-battery.h
+header-test-                   += linux/power/max17042_battery.h
+header-test-                   += linux/power/max8903_charger.h
+header-test-                   += linux/ppp-comp.h
+header-test-                   += linux/pps-gpio.h
+header-test-                   += linux/pr.h
+header-test-                   += linux/proc_ns.h
+header-test-                   += linux/processor.h
+header-test-                   += linux/psi.h
+header-test-                   += linux/psp-sev.h
+header-test-                   += linux/pstore.h
+header-test-                   += linux/ptr_ring.h
+header-test-                   += linux/ptrace.h
+header-test-                   += linux/qcom-geni-se.h
+header-test-                   += linux/qed/eth_common.h
+header-test-                   += linux/qed/fcoe_common.h
+header-test-                   += linux/qed/iscsi_common.h
+header-test-                   += linux/qed/iwarp_common.h
+header-test-                   += linux/qed/qed_eth_if.h
+header-test-                   += linux/qed/qed_fcoe_if.h
+header-test-                   += linux/qed/rdma_common.h
+header-test-                   += linux/qed/storage_common.h
+header-test-                   += linux/qed/tcp_common.h
+header-test-                   += linux/qnx6_fs.h
+header-test-                   += linux/quicklist.h
+header-test-                   += linux/ramfs.h
+header-test-                   += linux/range.h
+header-test-                   += linux/rcu_node_tree.h
+header-test-                   += linux/rculist_bl.h
+header-test-                   += linux/rculist_nulls.h
+header-test-                   += linux/rcutiny.h
+header-test-                   += linux/rcutree.h
+header-test-                   += linux/reboot-mode.h
+header-test-                   += linux/regulator/fixed.h
+header-test-                   += linux/regulator/gpio-regulator.h
+header-test-                   += linux/regulator/max8973-regulator.h
+header-test-                   += linux/regulator/of_regulator.h
+header-test-                   += linux/regulator/tps51632-regulator.h
+header-test-                   += linux/regulator/tps62360.h
+header-test-                   += linux/regulator/tps6507x.h
+header-test-                   += linux/regulator/userspace-consumer.h
+header-test-                   += linux/remoteproc/st_slim_rproc.h
+header-test-                   += linux/reset/socfpga.h
+header-test-                   += linux/reset/sunxi.h
+header-test-                   += linux/rtc/m48t59.h
+header-test-                   += linux/rtc/rtc-omap.h
+header-test-                   += linux/rtc/sirfsoc_rtciobrg.h
+header-test-                   += linux/rwlock.h
+header-test-                   += linux/rwlock_types.h
+header-test-                   += linux/scc.h
+header-test-                   += linux/sched/deadline.h
+header-test-                   += linux/sched/smt.h
+header-test-                   += linux/sched/sysctl.h
+header-test-                   += linux/sched_clock.h
+header-test-                   += linux/scpi_protocol.h
+header-test-                   += linux/scx200_gpio.h
+header-test-                   += linux/seccomp.h
+header-test-                   += linux/sed-opal.h
+header-test-                   += linux/seg6_iptunnel.h
+header-test-                   += linux/selection.h
+header-test-                   += linux/set_memory.h
+header-test-                   += linux/shrinker.h
+header-test-                   += linux/sirfsoc_dma.h
+header-test-                   += linux/skb_array.h
+header-test-                   += linux/slab_def.h
+header-test-                   += linux/slub_def.h
+header-test-                   += linux/sm501.h
+header-test-                   += linux/smc91x.h
+header-test-                   += linux/static_key.h
+header-test-                   += linux/soc/actions/owl-sps.h
+header-test-                   += linux/soc/amlogic/meson-canvas.h
+header-test-                   += linux/soc/brcmstb/brcmstb.h
+header-test-                   += linux/soc/ixp4xx/npe.h
+header-test-                   += linux/soc/mediatek/infracfg.h
+header-test-                   += linux/soc/qcom/smd-rpm.h
+header-test-                   += linux/soc/qcom/smem.h
+header-test-                   += linux/soc/qcom/smem_state.h
+header-test-                   += linux/soc/qcom/wcnss_ctrl.h
+header-test-                   += linux/soc/renesas/rcar-rst.h
+header-test-                   += linux/soc/samsung/exynos-pmu.h
+header-test-                   += linux/soc/sunxi/sunxi_sram.h
+header-test-                   += linux/soc/ti/ti-msgmgr.h
+header-test-                   += linux/soc/ti/ti_sci_inta_msi.h
+header-test-                   += linux/soc/ti/ti_sci_protocol.h
+header-test-                   += linux/soundwire/sdw.h
+header-test-                   += linux/soundwire/sdw_intel.h
+header-test-                   += linux/soundwire/sdw_type.h
+header-test-                   += linux/spi/ad7877.h
+header-test-                   += linux/spi/ads7846.h
+header-test-                   += linux/spi/at86rf230.h
+header-test-                   += linux/spi/ds1305.h
+header-test-                   += linux/spi/libertas_spi.h
+header-test-                   += linux/spi/lms283gf05.h
+header-test-                   += linux/spi/max7301.h
+header-test-                   += linux/spi/mcp23s08.h
+header-test-                   += linux/spi/rspi.h
+header-test-                   += linux/spi/s3c24xx.h
+header-test-                   += linux/spi/sh_msiof.h
+header-test-                   += linux/spi/spi-fsl-dspi.h
+header-test-                   += linux/spi/spi_bitbang.h
+header-test-                   += linux/spi/spi_gpio.h
+header-test-                   += linux/spi/xilinx_spi.h
+header-test-                   += linux/spinlock_api_smp.h
+header-test-                   += linux/spinlock_api_up.h
+header-test-                   += linux/spinlock_types.h
+header-test-                   += linux/splice.h
+header-test-                   += linux/sram.h
+header-test-                   += linux/srcutiny.h
+header-test-                   += linux/srcutree.h
+header-test-                   += linux/ssb/ssb_driver_chipcommon.h
+header-test-                   += linux/ssb/ssb_driver_extif.h
+header-test-                   += linux/ssb/ssb_driver_mips.h
+header-test-                   += linux/ssb/ssb_driver_pci.h
+header-test-                   += linux/ssbi.h
+header-test-                   += linux/stackdepot.h
+header-test-                   += linux/stmp3xxx_rtc_wdt.h
+header-test-                   += linux/string_helpers.h
+header-test-                   += linux/sungem_phy.h
+header-test-                   += linux/sunrpc/msg_prot.h
+header-test-                   += linux/sunrpc/rpc_pipe_fs.h
+header-test-                   += linux/sunrpc/xprtmultipath.h
+header-test-                   += linux/sunrpc/xprtsock.h
+header-test-                   += linux/sunxi-rsb.h
+header-test-                   += linux/svga.h
+header-test-                   += linux/sw842.h
+header-test-                   += linux/swapfile.h
+header-test-                   += linux/swapops.h
+header-test-                   += linux/swiotlb.h
+header-test-                   += linux/sysv_fs.h
+header-test-                   += linux/t10-pi.h
+header-test-                   += linux/task_io_accounting.h
+header-test-                   += linux/tick.h
+header-test-                   += linux/timb_dma.h
+header-test-                   += linux/timekeeping.h
+header-test-                   += linux/timekeeping32.h
+header-test-                   += linux/ts-nbus.h
+header-test-                   += linux/tsacct_kern.h
+header-test-                   += linux/tty_flip.h
+header-test-                   += linux/tty_ldisc.h
+header-test-                   += linux/ucb1400.h
+header-test-                   += linux/usb/association.h
+header-test-                   += linux/usb/cdc-wdm.h
+header-test-                   += linux/usb/cdc_ncm.h
+header-test-                   += linux/usb/ezusb.h
+header-test-                   += linux/usb/gadget_configfs.h
+header-test-                   += linux/usb/gpio_vbus.h
+header-test-                   += linux/usb/hcd.h
+header-test-                   += linux/usb/iowarrior.h
+header-test-                   += linux/usb/irda.h
+header-test-                   += linux/usb/isp116x.h
+header-test-                   += linux/usb/isp1362.h
+header-test-                   += linux/usb/musb.h
+header-test-                   += linux/usb/net2280.h
+header-test-                   += linux/usb/ohci_pdriver.h
+header-test-                   += linux/usb/otg-fsm.h
+header-test-                   += linux/usb/pd_ado.h
+header-test-                   += linux/usb/r8a66597.h
+header-test-                   += linux/usb/rndis_host.h
+header-test-                   += linux/usb/serial.h
+header-test-                   += linux/usb/sl811.h
+header-test-                   += linux/usb/storage.h
+header-test-                   += linux/usb/uas.h
+header-test-                   += linux/usb/usb338x.h
+header-test-                   += linux/usb/usbnet.h
+header-test-                   += linux/usb/wusb-wa.h
+header-test-                   += linux/usb/xhci-dbgp.h
+header-test-                   += linux/usb_usual.h
+header-test-                   += linux/user-return-notifier.h
+header-test-                   += linux/userfaultfd_k.h
+header-test-                   += linux/verification.h
+header-test-                   += linux/vgaarb.h
+header-test-                   += linux/via_core.h
+header-test-                   += linux/via_i2c.h
+header-test-                   += linux/virtio_byteorder.h
+header-test-                   += linux/virtio_ring.h
+header-test-                   += linux/visorbus.h
+header-test-                   += linux/vme.h
+header-test-                   += linux/vmstat.h
+header-test-                   += linux/vmw_vmci_api.h
+header-test-                   += linux/vmw_vmci_defs.h
+header-test-                   += linux/vringh.h
+header-test-                   += linux/vt_buffer.h
+header-test-                   += linux/zorro.h
+header-test-                   += linux/zpool.h
+header-test-                   += math-emu/double.h
+header-test-                   += math-emu/op-common.h
+header-test-                   += math-emu/quad.h
+header-test-                   += math-emu/single.h
+header-test-                   += math-emu/soft-fp.h
+header-test-                   += media/davinci/dm355_ccdc.h
+header-test-                   += media/davinci/dm644x_ccdc.h
+header-test-                   += media/davinci/isif.h
+header-test-                   += media/davinci/vpbe_osd.h
+header-test-                   += media/davinci/vpbe_types.h
+header-test-                   += media/davinci/vpif_types.h
+header-test-                   += media/demux.h
+header-test-                   += media/drv-intf/soc_mediabus.h
+header-test-                   += media/dvb_net.h
+header-test-                   += media/fwht-ctrls.h
+header-test-                   += media/i2c/ad9389b.h
+header-test-                   += media/i2c/adv7343.h
+header-test-                   += media/i2c/adv7511.h
+header-test-                   += media/i2c/adv7842.h
+header-test-                   += media/i2c/m5mols.h
+header-test-                   += media/i2c/mt9m032.h
+header-test-                   += media/i2c/mt9t112.h
+header-test-                   += media/i2c/mt9v032.h
+header-test-                   += media/i2c/ov2659.h
+header-test-                   += media/i2c/ov7670.h
+header-test-                   += media/i2c/rj54n1cb0c.h
+header-test-                   += media/i2c/saa6588.h
+header-test-                   += media/i2c/saa7115.h
+header-test-                   += media/i2c/sr030pc30.h
+header-test-                   += media/i2c/tc358743.h
+header-test-                   += media/i2c/tda1997x.h
+header-test-                   += media/i2c/ths7303.h
+header-test-                   += media/i2c/tvaudio.h
+header-test-                   += media/i2c/tvp514x.h
+header-test-                   += media/i2c/tvp7002.h
+header-test-                   += media/i2c/wm8775.h
+header-test-                   += media/imx.h
+header-test-                   += media/media-dev-allocator.h
+header-test-                   += media/mpeg2-ctrls.h
+header-test-                   += media/rcar-fcp.h
+header-test-                   += media/tuner-types.h
+header-test-                   += media/tveeprom.h
+header-test-                   += media/v4l2-flash-led-class.h
+header-test-                   += misc/altera.h
+header-test-                   += misc/cxl-base.h
+header-test-                   += misc/cxllib.h
+header-test-                   += net/9p/9p.h
+header-test-                   += net/9p/client.h
+header-test-                   += net/9p/transport.h
+header-test-                   += net/af_vsock.h
+header-test-                   += net/ax88796.h
+header-test-                   += net/bluetooth/hci.h
+header-test-                   += net/bluetooth/hci_core.h
+header-test-                   += net/bluetooth/hci_mon.h
+header-test-                   += net/bluetooth/hci_sock.h
+header-test-                   += net/bluetooth/l2cap.h
+header-test-                   += net/bluetooth/mgmt.h
+header-test-                   += net/bluetooth/rfcomm.h
+header-test-                   += net/bluetooth/sco.h
+header-test-                   += net/bond_options.h
+header-test-                   += net/caif/cfsrvl.h
+header-test-                   += net/codel_impl.h
+header-test-                   += net/codel_qdisc.h
+header-test-                   += net/compat.h
+header-test-                   += net/datalink.h
+header-test-                   += net/dcbevent.h
+header-test-                   += net/dcbnl.h
+header-test-                   += net/dn_dev.h
+header-test-                   += net/dn_fib.h
+header-test-                   += net/dn_neigh.h
+header-test-                   += net/dn_nsp.h
+header-test-                   += net/dn_route.h
+header-test-                   += net/erspan.h
+header-test-                   += net/esp.h
+header-test-                   += net/ethoc.h
+header-test-                   += net/firewire.h
+header-test-                   += net/flow_offload.h
+header-test-                   += net/fq.h
+header-test-                   += net/fq_impl.h
+header-test-                   += net/garp.h
+header-test-                   += net/gtp.h
+header-test-                   += net/gue.h
+header-test-                   += net/hwbm.h
+header-test-                   += net/ila.h
+header-test-                   += net/inet6_connection_sock.h
+header-test-                   += net/inet_common.h
+header-test-                   += net/inet_frag.h
+header-test-                   += net/ip6_route.h
+header-test-                   += net/ip_vs.h
+header-test-                   += net/ipcomp.h
+header-test-                   += net/ipconfig.h
+header-test-                   += net/iucv/af_iucv.h
+header-test-                   += net/iucv/iucv.h
+header-test-                   += net/lapb.h
+header-test-                   += net/llc_c_ac.h
+header-test-                   += net/llc_c_st.h
+header-test-                   += net/llc_s_ac.h
+header-test-                   += net/llc_s_ev.h
+header-test-                   += net/llc_s_st.h
+header-test-                   += net/mpls_iptunnel.h
+header-test-                   += net/mrp.h
+header-test-                   += net/ncsi.h
+header-test-                   += net/netevent.h
+header-test-                   += net/netfilter/br_netfilter.h
+header-test-                   += net/netfilter/ipv4/nf_dup_ipv4.h
+header-test-                   += net/netfilter/ipv6/nf_defrag_ipv6.h
+header-test-                   += net/netfilter/ipv6/nf_dup_ipv6.h
+header-test-                   += net/netfilter/nf_conntrack.h
+header-test-                   += net/netfilter/nf_conntrack_acct.h
+header-test-                   += net/netfilter/nf_conntrack_bridge.h
+header-test-                   += net/netfilter/nf_conntrack_core.h
+header-test-                   += net/netfilter/nf_conntrack_count.h
+header-test-                   += net/netfilter/nf_conntrack_ecache.h
+header-test-                   += net/netfilter/nf_conntrack_expect.h
+header-test-                   += net/netfilter/nf_conntrack_extend.h
+header-test-                   += net/netfilter/nf_conntrack_helper.h
+header-test-                   += net/netfilter/nf_conntrack_l4proto.h
+header-test-                   += net/netfilter/nf_conntrack_labels.h
+header-test-                   += net/netfilter/nf_conntrack_seqadj.h
+header-test-                   += net/netfilter/nf_conntrack_synproxy.h
+header-test-                   += net/netfilter/nf_conntrack_timeout.h
+header-test-                   += net/netfilter/nf_conntrack_timestamp.h
+header-test-                   += net/netfilter/nf_conntrack_tuple.h
+header-test-                   += net/netfilter/nf_dup_netdev.h
+header-test-                   += net/netfilter/nf_flow_table.h
+header-test-                   += net/netfilter/nf_nat.h
+header-test-                   += net/netfilter/nf_nat_helper.h
+header-test-                   += net/netfilter/nf_nat_masquerade.h
+header-test-                   += net/netfilter/nf_nat_redirect.h
+header-test-                   += net/netfilter/nf_queue.h
+header-test-                   += net/netfilter/nf_reject.h
+header-test-                   += net/netfilter/nf_synproxy.h
+header-test-                   += net/netfilter/nf_tables.h
+header-test-                   += net/netfilter/nf_tables_core.h
+header-test-                   += net/netfilter/nf_tables_ipv4.h
+header-test-                   += net/netfilter/nf_tables_ipv6.h
+header-test-                   += net/netfilter/nft_fib.h
+header-test-                   += net/netfilter/nft_meta.h
+header-test-                   += net/netfilter/nft_reject.h
+header-test-                   += net/netns/can.h
+header-test-                   += net/netns/generic.h
+header-test-                   += net/netns/ieee802154_6lowpan.h
+header-test-                   += net/netns/ipv4.h
+header-test-                   += net/netns/ipv6.h
+header-test-                   += net/netns/mpls.h
+header-test-                   += net/netns/nftables.h
+header-test-                   += net/netns/sctp.h
+header-test-                   += net/netrom.h
+header-test-                   += net/p8022.h
+header-test-                   += net/phonet/pep.h
+header-test-                   += net/phonet/phonet.h
+header-test-                   += net/phonet/pn_dev.h
+header-test-                   += net/pptp.h
+header-test-                   += net/psample.h
+header-test-                   += net/psnap.h
+header-test-                   += net/regulatory.h
+header-test-                   += net/rose.h
+header-test-                   += net/sctp/auth.h
+header-test-                   += net/sctp/stream_interleave.h
+header-test-                   += net/sctp/stream_sched.h
+header-test-                   += net/sctp/tsnmap.h
+header-test-                   += net/sctp/ulpevent.h
+header-test-                   += net/sctp/ulpqueue.h
+header-test-                   += net/secure_seq.h
+header-test-                   += net/smc.h
+header-test-                   += net/stp.h
+header-test-                   += net/transp_v6.h
+header-test-                   += net/tun_proto.h
+header-test-                   += net/udplite.h
+header-test-                   += net/xdp.h
+header-test-                   += net/xdp_priv.h
+header-test-                   += pcmcia/cistpl.h
+header-test-                   += pcmcia/ds.h
+header-test-                   += rdma/ib.h
+header-test-                   += rdma/iw_portmap.h
+header-test-                   += rdma/opa_port_info.h
+header-test-                   += rdma/rdma_counter.h
+header-test-                   += rdma/rdmavt_cq.h
+header-test-                   += rdma/restrack.h
+header-test-                   += rdma/signature.h
+header-test-                   += rdma/tid_rdma_defs.h
+header-test-                   += scsi/fc/fc_encaps.h
+header-test-                   += scsi/fc/fc_fc2.h
+header-test-                   += scsi/fc/fc_fcoe.h
+header-test-                   += scsi/fc/fc_fip.h
+header-test-                   += scsi/fc_encode.h
+header-test-                   += scsi/fc_frame.h
+header-test-                   += scsi/iser.h
+header-test-                   += scsi/libfc.h
+header-test-                   += scsi/libfcoe.h
+header-test-                   += scsi/libsas.h
+header-test-                   += scsi/sas_ata.h
+header-test-                   += scsi/scsi_cmnd.h
+header-test-                   += scsi/scsi_dbg.h
+header-test-                   += scsi/scsi_device.h
+header-test-                   += scsi/scsi_dh.h
+header-test-                   += scsi/scsi_eh.h
+header-test-                   += scsi/scsi_host.h
+header-test-                   += scsi/scsi_ioctl.h
+header-test-                   += scsi/scsi_request.h
+header-test-                   += scsi/scsi_tcq.h
+header-test-                   += scsi/scsi_transport.h
+header-test-                   += scsi/scsi_transport_fc.h
+header-test-                   += scsi/scsi_transport_sas.h
+header-test-                   += scsi/scsi_transport_spi.h
+header-test-                   += scsi/scsi_transport_srp.h
+header-test-                   += scsi/scsicam.h
+header-test-                   += scsi/sg.h
+header-test-                   += soc/arc/aux.h
+header-test-                   += soc/arc/mcip.h
+header-test-                   += soc/arc/timers.h
+header-test-                   += soc/brcmstb/common.h
+header-test-                   += soc/fsl/bman.h
+header-test-                   += soc/fsl/qe/qe.h
+header-test-                   += soc/fsl/qe/qe_ic.h
+header-test-                   += soc/fsl/qe/qe_tdm.h
+header-test-                   += soc/fsl/qe/ucc.h
+header-test-                   += soc/fsl/qe/ucc_fast.h
+header-test-                   += soc/fsl/qe/ucc_slow.h
+header-test-                   += soc/fsl/qman.h
+header-test-                   += soc/nps/common.h
+header-test-$(CONFIG_ARC)      += soc/nps/mtm.h
+header-test-                   += soc/qcom/cmd-db.h
+header-test-                   += soc/qcom/rpmh.h
+header-test-                   += soc/qcom/tcs.h
+header-test-                   += soc/tegra/ahb.h
+header-test-                   += soc/tegra/bpmp-abi.h
+header-test-                   += soc/tegra/common.h
+header-test-                   += soc/tegra/flowctrl.h
+header-test-                   += soc/tegra/fuse.h
+header-test-                   += soc/tegra/mc.h
+header-test-                   += sound/ac97/compat.h
+header-test-                   += sound/aci.h
+header-test-                   += sound/ad1843.h
+header-test-                   += sound/adau1373.h
+header-test-                   += sound/ak4113.h
+header-test-                   += sound/ak4114.h
+header-test-                   += sound/ak4117.h
+header-test-                   += sound/cs35l33.h
+header-test-                   += sound/cs35l34.h
+header-test-                   += sound/cs35l35.h
+header-test-                   += sound/cs35l36.h
+header-test-                   += sound/cs4271.h
+header-test-                   += sound/cs42l52.h
+header-test-                   += sound/cs8427.h
+header-test-                   += sound/da7218.h
+header-test-                   += sound/da7219-aad.h
+header-test-                   += sound/da7219.h
+header-test-                   += sound/da9055.h
+header-test-                   += sound/emu8000.h
+header-test-                   += sound/emux_synth.h
+header-test-                   += sound/hda_component.h
+header-test-                   += sound/hda_hwdep.h
+header-test-                   += sound/hda_i915.h
+header-test-                   += sound/hwdep.h
+header-test-                   += sound/i2c.h
+header-test-                   += sound/l3.h
+header-test-                   += sound/max98088.h
+header-test-                   += sound/max98095.h
+header-test-                   += sound/mixer_oss.h
+header-test-                   += sound/omap-hdmi-audio.h
+header-test-                   += sound/pcm_drm_eld.h
+header-test-                   += sound/pcm_iec958.h
+header-test-                   += sound/pcm_oss.h
+header-test-                   += sound/pxa2xx-lib.h
+header-test-                   += sound/rt286.h
+header-test-                   += sound/rt298.h
+header-test-                   += sound/rt5645.h
+header-test-                   += sound/rt5659.h
+header-test-                   += sound/rt5660.h
+header-test-                   += sound/rt5665.h
+header-test-                   += sound/rt5670.h
+header-test-                   += sound/s3c24xx_uda134x.h
+header-test-                   += sound/seq_device.h
+header-test-                   += sound/seq_kernel.h
+header-test-                   += sound/seq_midi_emul.h
+header-test-                   += sound/seq_oss.h
+header-test-                   += sound/soc-acpi-intel-match.h
+header-test-                   += sound/soc-dai.h
+header-test-                   += sound/soc-dapm.h
+header-test-                   += sound/soc-dpcm.h
+header-test-                   += sound/sof/control.h
+header-test-                   += sound/sof/dai-intel.h
+header-test-                   += sound/sof/dai.h
+header-test-                   += sound/sof/header.h
+header-test-                   += sound/sof/info.h
+header-test-                   += sound/sof/pm.h
+header-test-                   += sound/sof/stream.h
+header-test-                   += sound/sof/topology.h
+header-test-                   += sound/sof/trace.h
+header-test-                   += sound/sof/xtensa.h
+header-test-                   += sound/spear_spdif.h
+header-test-                   += sound/sta32x.h
+header-test-                   += sound/sta350.h
+header-test-                   += sound/tea6330t.h
+header-test-                   += sound/tlv320aic32x4.h
+header-test-                   += sound/tlv320dac33-plat.h
+header-test-                   += sound/uda134x.h
+header-test-                   += sound/wavefront.h
+header-test-                   += sound/wm8903.h
+header-test-                   += sound/wm8904.h
+header-test-                   += sound/wm8960.h
+header-test-                   += sound/wm8962.h
+header-test-                   += sound/wm8993.h
+header-test-                   += sound/wm8996.h
+header-test-                   += sound/wm9081.h
+header-test-                   += sound/wm9090.h
+header-test-                   += target/iscsi/iscsi_target_stat.h
+header-test-                   += trace/bpf_probe.h
+header-test-                   += trace/events/9p.h
+header-test-                   += trace/events/afs.h
+header-test-                   += trace/events/asoc.h
+header-test-                   += trace/events/bcache.h
+header-test-                   += trace/events/block.h
+header-test-                   += trace/events/cachefiles.h
+header-test-                   += trace/events/cgroup.h
+header-test-                   += trace/events/clk.h
+header-test-                   += trace/events/cma.h
+header-test-                   += trace/events/ext4.h
+header-test-                   += trace/events/f2fs.h
+header-test-                   += trace/events/fs_dax.h
+header-test-                   += trace/events/fscache.h
+header-test-                   += trace/events/fsi.h
+header-test-                   += trace/events/fsi_master_ast_cf.h
+header-test-                   += trace/events/fsi_master_gpio.h
+header-test-                   += trace/events/huge_memory.h
+header-test-                   += trace/events/ib_mad.h
+header-test-                   += trace/events/ib_umad.h
+header-test-                   += trace/events/iscsi.h
+header-test-                   += trace/events/jbd2.h
+header-test-                   += trace/events/kvm.h
+header-test-                   += trace/events/kyber.h
+header-test-                   += trace/events/libata.h
+header-test-                   += trace/events/mce.h
+header-test-                   += trace/events/mdio.h
+header-test-                   += trace/events/migrate.h
+header-test-                   += trace/events/mmflags.h
+header-test-                   += trace/events/nbd.h
+header-test-                   += trace/events/nilfs2.h
+header-test-                   += trace/events/pwc.h
+header-test-                   += trace/events/rdma.h
+header-test-                   += trace/events/rpcgss.h
+header-test-                   += trace/events/rpcrdma.h
+header-test-                   += trace/events/rxrpc.h
+header-test-                   += trace/events/scsi.h
+header-test-                   += trace/events/siox.h
+header-test-                   += trace/events/spi.h
+header-test-                   += trace/events/swiotlb.h
+header-test-                   += trace/events/syscalls.h
+header-test-                   += trace/events/target.h
+header-test-                   += trace/events/thermal_power_allocator.h
+header-test-                   += trace/events/timer.h
+header-test-                   += trace/events/wbt.h
+header-test-                   += trace/events/xen.h
+header-test-                   += trace/perf.h
+header-test-                   += trace/trace_events.h
+header-test-                   += uapi/drm/vmwgfx_drm.h
+header-test-                   += uapi/linux/a.out.h
+header-test-                   += uapi/linux/coda.h
+header-test-                   += uapi/linux/coda_psdev.h
+header-test-                   += uapi/linux/errqueue.h
+header-test-                   += uapi/linux/eventpoll.h
+header-test-                   += uapi/linux/hdlc/ioctl.h
+header-test-                   += uapi/linux/input.h
+header-test-                   += uapi/linux/kvm.h
+header-test-                   += uapi/linux/kvm_para.h
+header-test-                   += uapi/linux/lightnvm.h
+header-test-                   += uapi/linux/mic_common.h
+header-test-                   += uapi/linux/mman.h
+header-test-                   += uapi/linux/netfilter/ipset/ip_set_bitmap.h
+header-test-                   += uapi/linux/netfilter/ipset/ip_set_hash.h
+header-test-                   += uapi/linux/netfilter/ipset/ip_set_list.h
+header-test-                   += uapi/linux/netfilter/nf_synproxy.h
+header-test-                   += uapi/linux/netfilter/xt_policy.h
+header-test-                   += uapi/linux/netfilter/xt_set.h
+header-test-                   += uapi/linux/netfilter_arp/arp_tables.h
+header-test-                   += uapi/linux/netfilter_arp/arpt_mangle.h
+header-test-                   += uapi/linux/netfilter_ipv4/ip_tables.h
+header-test-                   += uapi/linux/netfilter_ipv4/ipt_LOG.h
+header-test-                   += uapi/linux/netfilter_ipv6/ip6_tables.h
+header-test-                   += uapi/linux/netfilter_ipv6/ip6t_LOG.h
+header-test-                   += uapi/linux/nilfs2_ondisk.h
+header-test-                   += uapi/linux/patchkey.h
+header-test-                   += uapi/linux/ptrace.h
+header-test-                   += uapi/linux/scc.h
+header-test-                   += uapi/linux/seg6_iptunnel.h
+header-test-                   += uapi/linux/smc_diag.h
+header-test-                   += uapi/linux/timex.h
+header-test-                   += uapi/linux/videodev2.h
+header-test-                   += uapi/scsi/scsi_bsg_fc.h
+header-test-                   += uapi/sound/asound.h
+header-test-                   += uapi/sound/sof/eq.h
+header-test-                   += uapi/sound/sof/fw.h
+header-test-                   += uapi/sound/sof/header.h
+header-test-                   += uapi/sound/sof/manifest.h
+header-test-                   += uapi/sound/sof/trace.h
+header-test-                   += uapi/xen/evtchn.h
+header-test-                   += uapi/xen/gntdev.h
+header-test-                   += uapi/xen/privcmd.h
+header-test-                   += vdso/vsyscall.h
+header-test-                   += video/broadsheetfb.h
+header-test-                   += video/cvisionppc.h
+header-test-                   += video/gbe.h
+header-test-                   += video/kyro.h
+header-test-                   += video/maxinefb.h
+header-test-                   += video/metronomefb.h
+header-test-                   += video/neomagic.h
+header-test-                   += video/of_display_timing.h
+header-test-                   += video/omapvrfb.h
+header-test-                   += video/s1d13xxxfb.h
+header-test-                   += video/sstfb.h
+header-test-                   += video/tgafb.h
+header-test-                   += video/udlfb.h
+header-test-                   += video/uvesafb.h
+header-test-                   += video/vga.h
+header-test-                   += video/w100fb.h
+header-test-                   += xen/acpi.h
+header-test-                   += xen/arm/hypercall.h
+header-test-                   += xen/arm/page-coherent.h
+header-test-                   += xen/arm/page.h
+header-test-                   += xen/balloon.h
+header-test-                   += xen/events.h
+header-test-                   += xen/features.h
+header-test-                   += xen/grant_table.h
+header-test-                   += xen/hvm.h
+header-test-                   += xen/interface/callback.h
+header-test-                   += xen/interface/event_channel.h
+header-test-                   += xen/interface/grant_table.h
+header-test-                   += xen/interface/hvm/dm_op.h
+header-test-                   += xen/interface/hvm/hvm_op.h
+header-test-                   += xen/interface/hvm/hvm_vcpu.h
+header-test-                   += xen/interface/hvm/params.h
+header-test-                   += xen/interface/hvm/start_info.h
+header-test-                   += xen/interface/io/9pfs.h
+header-test-                   += xen/interface/io/blkif.h
+header-test-                   += xen/interface/io/console.h
+header-test-                   += xen/interface/io/displif.h
+header-test-                   += xen/interface/io/fbif.h
+header-test-                   += xen/interface/io/kbdif.h
+header-test-                   += xen/interface/io/netif.h
+header-test-                   += xen/interface/io/pciif.h
+header-test-                   += xen/interface/io/protocols.h
+header-test-                   += xen/interface/io/pvcalls.h
+header-test-                   += xen/interface/io/ring.h
+header-test-                   += xen/interface/io/sndif.h
+header-test-                   += xen/interface/io/tpmif.h
+header-test-                   += xen/interface/io/vscsiif.h
+header-test-                   += xen/interface/io/xs_wire.h
+header-test-                   += xen/interface/memory.h
+header-test-                   += xen/interface/nmi.h
+header-test-                   += xen/interface/physdev.h
+header-test-                   += xen/interface/platform.h
+header-test-                   += xen/interface/sched.h
+header-test-                   += xen/interface/vcpu.h
+header-test-                   += xen/interface/version.h
+header-test-                   += xen/interface/xen-mca.h
+header-test-                   += xen/interface/xen.h
+header-test-                   += xen/interface/xenpmu.h
+header-test-                   += xen/mem-reservation.h
+header-test-                   += xen/page.h
+header-test-                   += xen/platform_pci.h
+header-test-                   += xen/swiotlb-xen.h
+header-test-                   += xen/xen-front-pgdir-shbuf.h
+header-test-                   += xen/xen-ops.h
+header-test-                   += xen/xen.h
+header-test-                   += xen/xenbus.h
+
+# Do not include directly
+header-test- += linux/compiler-clang.h
+header-test- += linux/compiler-gcc.h
+header-test- += linux/patchkey.h
+header-test- += linux/rwlock_api_smp.h
+header-test- += linux/spinlock_types_up.h
+header-test- += linux/spinlock_up.h
+header-test- += linux/wimax/debug.h
+header-test- += rdma/uverbs_named_ioctl.h
+
+# asm-generic/*.h is used by asm/*.h, and should not be included directly
+header-test- += asm-generic/% uapi/asm-generic/%
+
+# Timestamp files touched by Kconfig
+header-test- += config/%
+
+# Timestamp files touched by scripts/adjust_autoksyms.sh
+header-test- += ksym/%
+
+# You could compile-test these, but maybe not so useful...
+header-test- += dt-bindings/%
+
+# Do not test generated headers. Stale headers are often left over when you
+# traverse the git history without cleaning.
+header-test- += generated/%
+
+# The rest are compile-tested
+header-test-pattern-y += */*.h */*/*.h */*/*/*.h */*/*/*/*.h
diff --git a/include/asm-generic/bitops-instrumented.h b/include/asm-generic/bitops-instrumented.h
new file mode 100644 (file)
index 0000000..ddd1c6d
--- /dev/null
@@ -0,0 +1,263 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * This file provides wrappers with sanitizer instrumentation for bit
+ * operations.
+ *
+ * To use this functionality, an arch's bitops.h file needs to define each of
+ * the below bit operations with an arch_ prefix (e.g. arch_set_bit(),
+ * arch___set_bit(), etc.).
+ */
+#ifndef _ASM_GENERIC_BITOPS_INSTRUMENTED_H
+#define _ASM_GENERIC_BITOPS_INSTRUMENTED_H
+
+#include <linux/kasan-checks.h>
+
+/**
+ * set_bit - Atomically set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * This is a relaxed atomic operation (no implied memory barriers).
+ *
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
+static inline void set_bit(long nr, volatile unsigned long *addr)
+{
+       kasan_check_write(addr + BIT_WORD(nr), sizeof(long));
+       arch_set_bit(nr, addr);
+}
+
+/**
+ * __set_bit - Set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * Unlike set_bit(), this function is non-atomic. If it is called on the same
+ * region of memory concurrently, the effect may be that only one operation
+ * succeeds.
+ */
+static inline void __set_bit(long nr, volatile unsigned long *addr)
+{
+       kasan_check_write(addr + BIT_WORD(nr), sizeof(long));
+       arch___set_bit(nr, addr);
+}
+
+/**
+ * clear_bit - Clears a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ *
+ * This is a relaxed atomic operation (no implied memory barriers).
+ */
+static inline void clear_bit(long nr, volatile unsigned long *addr)
+{
+       kasan_check_write(addr + BIT_WORD(nr), sizeof(long));
+       arch_clear_bit(nr, addr);
+}
+
+/**
+ * __clear_bit - Clears a bit in memory
+ * @nr: the bit to clear
+ * @addr: the address to start counting from
+ *
+ * Unlike clear_bit(), this function is non-atomic. If it is called on the same
+ * region of memory concurrently, the effect may be that only one operation
+ * succeeds.
+ */
+static inline void __clear_bit(long nr, volatile unsigned long *addr)
+{
+       kasan_check_write(addr + BIT_WORD(nr), sizeof(long));
+       arch___clear_bit(nr, addr);
+}
+
+/**
+ * clear_bit_unlock - Clear a bit in memory, for unlock
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * This operation is atomic and provides release barrier semantics.
+ */
+static inline void clear_bit_unlock(long nr, volatile unsigned long *addr)
+{
+       kasan_check_write(addr + BIT_WORD(nr), sizeof(long));
+       arch_clear_bit_unlock(nr, addr);
+}
+
+/**
+ * __clear_bit_unlock - Clears a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ *
+ * This is a non-atomic operation but implies a release barrier before the
+ * memory operation. It can be used for an unlock if no other CPUs can
+ * concurrently modify other bits in the word.
+ */
+static inline void __clear_bit_unlock(long nr, volatile unsigned long *addr)
+{
+       kasan_check_write(addr + BIT_WORD(nr), sizeof(long));
+       arch___clear_bit_unlock(nr, addr);
+}
+
+/**
+ * change_bit - Toggle a bit in memory
+ * @nr: Bit to change
+ * @addr: Address to start counting from
+ *
+ * This is a relaxed atomic operation (no implied memory barriers).
+ *
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
+static inline void change_bit(long nr, volatile unsigned long *addr)
+{
+       kasan_check_write(addr + BIT_WORD(nr), sizeof(long));
+       arch_change_bit(nr, addr);
+}
+
+/**
+ * __change_bit - Toggle a bit in memory
+ * @nr: the bit to change
+ * @addr: the address to start counting from
+ *
+ * Unlike change_bit(), this function is non-atomic. If it is called on the same
+ * region of memory concurrently, the effect may be that only one operation
+ * succeeds.
+ */
+static inline void __change_bit(long nr, volatile unsigned long *addr)
+{
+       kasan_check_write(addr + BIT_WORD(nr), sizeof(long));
+       arch___change_bit(nr, addr);
+}
+
+/**
+ * test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This is an atomic fully-ordered operation (implied full memory barrier).
+ */
+static inline bool test_and_set_bit(long nr, volatile unsigned long *addr)
+{
+       kasan_check_write(addr + BIT_WORD(nr), sizeof(long));
+       return arch_test_and_set_bit(nr, addr);
+}
+
+/**
+ * __test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic. If two instances of this operation race, one
+ * can appear to succeed but actually fail.
+ */
+static inline bool __test_and_set_bit(long nr, volatile unsigned long *addr)
+{
+       kasan_check_write(addr + BIT_WORD(nr), sizeof(long));
+       return arch___test_and_set_bit(nr, addr);
+}
+
+/**
+ * test_and_set_bit_lock - Set a bit and return its old value, for lock
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and provides acquire barrier semantics if
+ * the returned value is 0.
+ * It can be used to implement bit locks.
+ */
+static inline bool test_and_set_bit_lock(long nr, volatile unsigned long *addr)
+{
+       kasan_check_write(addr + BIT_WORD(nr), sizeof(long));
+       return arch_test_and_set_bit_lock(nr, addr);
+}
+
+/**
+ * test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to clear
+ * @addr: Address to count from
+ *
+ * This is an atomic fully-ordered operation (implied full memory barrier).
+ */
+static inline bool test_and_clear_bit(long nr, volatile unsigned long *addr)
+{
+       kasan_check_write(addr + BIT_WORD(nr), sizeof(long));
+       return arch_test_and_clear_bit(nr, addr);
+}
+
+/**
+ * __test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to clear
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic. If two instances of this operation race, one
+ * can appear to succeed but actually fail.
+ */
+static inline bool __test_and_clear_bit(long nr, volatile unsigned long *addr)
+{
+       kasan_check_write(addr + BIT_WORD(nr), sizeof(long));
+       return arch___test_and_clear_bit(nr, addr);
+}
+
+/**
+ * test_and_change_bit - Change a bit and return its old value
+ * @nr: Bit to change
+ * @addr: Address to count from
+ *
+ * This is an atomic fully-ordered operation (implied full memory barrier).
+ */
+static inline bool test_and_change_bit(long nr, volatile unsigned long *addr)
+{
+       kasan_check_write(addr + BIT_WORD(nr), sizeof(long));
+       return arch_test_and_change_bit(nr, addr);
+}
+
+/**
+ * __test_and_change_bit - Change a bit and return its old value
+ * @nr: Bit to change
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic. If two instances of this operation race, one
+ * can appear to succeed but actually fail.
+ */
+static inline bool __test_and_change_bit(long nr, volatile unsigned long *addr)
+{
+       kasan_check_write(addr + BIT_WORD(nr), sizeof(long));
+       return arch___test_and_change_bit(nr, addr);
+}
+
+/**
+ * test_bit - Determine whether a bit is set
+ * @nr: bit number to test
+ * @addr: Address to start counting from
+ */
+static inline bool test_bit(long nr, const volatile unsigned long *addr)
+{
+       kasan_check_read(addr + BIT_WORD(nr), sizeof(long));
+       return arch_test_bit(nr, addr);
+}
+
+#if defined(arch_clear_bit_unlock_is_negative_byte)
+/**
+ * clear_bit_unlock_is_negative_byte - Clear a bit in memory and test if bottom
+ *                                     byte is negative, for unlock.
+ * @nr: the bit to clear
+ * @addr: the address to start counting from
+ *
+ * This operation is atomic and provides release barrier semantics.
+ *
+ * This is a bit of a one-trick-pony for the filemap code, which clears
+ * PG_locked and tests PG_waiters,
+ */
+static inline bool
+clear_bit_unlock_is_negative_byte(long nr, volatile unsigned long *addr)
+{
+       kasan_check_write(addr + BIT_WORD(nr), sizeof(long));
+       return arch_clear_bit_unlock_is_negative_byte(nr, addr);
+}
+/* Let everybody know we have it. */
+#define clear_bit_unlock_is_negative_byte clear_bit_unlock_is_negative_byte
+#endif
+
+#endif /* _ASM_GENERIC_BITOPS_INSTRUMENTED_H */
diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h
new file mode 100644 (file)
index 0000000..0becb7d
--- /dev/null
@@ -0,0 +1,180 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Linux-specific definitions for managing interactions with Microsoft's
+ * Hyper-V hypervisor. The definitions in this file are architecture
+ * independent. See arch/<arch>/include/asm/mshyperv.h for definitions
+ * that are specific to architecture <arch>.
+ *
+ * Definitions that are specified in the Hyper-V Top Level Functional
+ * Spec (TLFS) should not go in this file, but should instead go in
+ * hyperv-tlfs.h.
+ *
+ * Copyright (C) 2019, Microsoft, Inc.
+ *
+ * Author : Michael Kelley <mikelley@microsoft.com>
+ */
+
+#ifndef _ASM_GENERIC_MSHYPERV_H
+#define _ASM_GENERIC_MSHYPERV_H
+
+#include <linux/types.h>
+#include <linux/atomic.h>
+#include <linux/bitops.h>
+#include <linux/cpumask.h>
+#include <asm/ptrace.h>
+#include <asm/hyperv-tlfs.h>
+
+struct ms_hyperv_info {
+       u32 features;
+       u32 misc_features;
+       u32 hints;
+       u32 nested_features;
+       u32 max_vp_index;
+       u32 max_lp_index;
+};
+extern struct ms_hyperv_info ms_hyperv;
+
+extern u64 hv_do_hypercall(u64 control, void *inputaddr, void *outputaddr);
+extern u64 hv_do_fast_hypercall8(u16 control, u64 input8);
+
+
+/* Generate the guest OS identifier as described in the Hyper-V TLFS */
+static inline  __u64 generate_guest_id(__u64 d_info1, __u64 kernel_version,
+                                      __u64 d_info2)
+{
+       __u64 guest_id = 0;
+
+       guest_id = (((__u64)HV_LINUX_VENDOR_ID) << 48);
+       guest_id |= (d_info1 << 48);
+       guest_id |= (kernel_version << 16);
+       guest_id |= d_info2;
+
+       return guest_id;
+}
+
+
+/* Free the message slot and signal end-of-message if required */
+static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type)
+{
+       /*
+        * On crash we're reading some other CPU's message page and we need
+        * to be careful: this other CPU may already had cleared the header
+        * and the host may already had delivered some other message there.
+        * In case we blindly write msg->header.message_type we're going
+        * to lose it. We can still lose a message of the same type but
+        * we count on the fact that there can only be one
+        * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages
+        * on crash.
+        */
+       if (cmpxchg(&msg->header.message_type, old_msg_type,
+                   HVMSG_NONE) != old_msg_type)
+               return;
+
+       /*
+        * The cmxchg() above does an implicit memory barrier to
+        * ensure the write to MessageType (ie set to
+        * HVMSG_NONE) happens before we read the
+        * MessagePending and EOMing. Otherwise, the EOMing
+        * will not deliver any more messages since there is
+        * no empty slot
+        */
+       if (msg->header.message_flags.msg_pending) {
+               /*
+                * This will cause message queue rescan to
+                * possibly deliver another msg from the
+                * hypervisor
+                */
+               hv_signal_eom();
+       }
+}
+
+void hv_setup_vmbus_irq(void (*handler)(void));
+void hv_remove_vmbus_irq(void);
+void hv_enable_vmbus_irq(void);
+void hv_disable_vmbus_irq(void);
+
+void hv_setup_kexec_handler(void (*handler)(void));
+void hv_remove_kexec_handler(void);
+void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs));
+void hv_remove_crash_handler(void);
+
+#if IS_ENABLED(CONFIG_HYPERV)
+/*
+ * Hypervisor's notion of virtual processor ID is different from
+ * Linux' notion of CPU ID. This information can only be retrieved
+ * in the context of the calling CPU. Setup a map for easy access
+ * to this information.
+ */
+extern u32 *hv_vp_index;
+extern u32 hv_max_vp_index;
+
+/* Sentinel value for an uninitialized entry in hv_vp_index array */
+#define VP_INVAL       U32_MAX
+
+/**
+ * hv_cpu_number_to_vp_number() - Map CPU to VP.
+ * @cpu_number: CPU number in Linux terms
+ *
+ * This function returns the mapping between the Linux processor
+ * number and the hypervisor's virtual processor number, useful
+ * in making hypercalls and such that talk about specific
+ * processors.
+ *
+ * Return: Virtual processor number in Hyper-V terms
+ */
+static inline int hv_cpu_number_to_vp_number(int cpu_number)
+{
+       return hv_vp_index[cpu_number];
+}
+
+static inline int cpumask_to_vpset(struct hv_vpset *vpset,
+                                   const struct cpumask *cpus)
+{
+       int cpu, vcpu, vcpu_bank, vcpu_offset, nr_bank = 1;
+
+       /* valid_bank_mask can represent up to 64 banks */
+       if (hv_max_vp_index / 64 >= 64)
+               return 0;
+
+       /*
+        * Clear all banks up to the maximum possible bank as hv_tlb_flush_ex
+        * structs are not cleared between calls, we risk flushing unneeded
+        * vCPUs otherwise.
+        */
+       for (vcpu_bank = 0; vcpu_bank <= hv_max_vp_index / 64; vcpu_bank++)
+               vpset->bank_contents[vcpu_bank] = 0;
+
+       /*
+        * Some banks may end up being empty but this is acceptable.
+        */
+       for_each_cpu(cpu, cpus) {
+               vcpu = hv_cpu_number_to_vp_number(cpu);
+               if (vcpu == VP_INVAL)
+                       return -1;
+               vcpu_bank = vcpu / 64;
+               vcpu_offset = vcpu % 64;
+               __set_bit(vcpu_offset, (unsigned long *)
+                         &vpset->bank_contents[vcpu_bank]);
+               if (vcpu_bank >= nr_bank)
+                       nr_bank = vcpu_bank + 1;
+       }
+       vpset->valid_bank_mask = GENMASK_ULL(nr_bank - 1, 0);
+       return nr_bank;
+}
+
+void hyperv_report_panic(struct pt_regs *regs, long err);
+void hyperv_report_panic_msg(phys_addr_t pa, size_t size);
+bool hv_is_hyperv_initialized(void);
+void hyperv_cleanup(void);
+#else /* CONFIG_HYPERV */
+static inline bool hv_is_hyperv_initialized(void) { return false; }
+static inline void hyperv_cleanup(void) {}
+#endif /* CONFIG_HYPERV */
+
+#if IS_ENABLED(CONFIG_HYPERV)
+extern int hv_setup_stimer0_irq(int *irq, int *vector, void (*handler)(void));
+extern void hv_remove_stimer0_irq(int irq);
+#endif
+
+#endif
index 948714c..8476175 100644 (file)
 /* SPDX-License-Identifier: GPL-2.0 */
 #ifndef __ASM_GENERIC_PGALLOC_H
 #define __ASM_GENERIC_PGALLOC_H
-/*
- * an empty file is enough for a nommu architecture
- */
+
 #ifdef CONFIG_MMU
-#error need to implement an architecture specific asm/pgalloc.h
+
+#define GFP_PGTABLE_KERNEL     (GFP_KERNEL | __GFP_ZERO)
+#define GFP_PGTABLE_USER       (GFP_PGTABLE_KERNEL | __GFP_ACCOUNT)
+
+/**
+ * __pte_alloc_one_kernel - allocate a page for PTE-level kernel page table
+ * @mm: the mm_struct of the current context
+ *
+ * This function is intended for architectures that need
+ * anything beyond simple page allocation.
+ *
+ * Return: pointer to the allocated memory or %NULL on error
+ */
+static inline pte_t *__pte_alloc_one_kernel(struct mm_struct *mm)
+{
+       return (pte_t *)__get_free_page(GFP_PGTABLE_KERNEL);
+}
+
+#ifndef __HAVE_ARCH_PTE_ALLOC_ONE_KERNEL
+/**
+ * pte_alloc_one_kernel - allocate a page for PTE-level kernel page table
+ * @mm: the mm_struct of the current context
+ *
+ * Return: pointer to the allocated memory or %NULL on error
+ */
+static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm)
+{
+       return __pte_alloc_one_kernel(mm);
+}
+#endif
+
+/**
+ * pte_free_kernel - free PTE-level kernel page table page
+ * @mm: the mm_struct of the current context
+ * @pte: pointer to the memory containing the page table
+ */
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
+{
+       free_page((unsigned long)pte);
+}
+
+/**
+ * __pte_alloc_one - allocate a page for PTE-level user page table
+ * @mm: the mm_struct of the current context
+ * @gfp: GFP flags to use for the allocation
+ *
+ * Allocates a page and runs the pgtable_page_ctor().
+ *
+ * This function is intended for architectures that need
+ * anything beyond simple page allocation or must have custom GFP flags.
+ *
+ * Return: `struct page` initialized as page table or %NULL on error
+ */
+static inline pgtable_t __pte_alloc_one(struct mm_struct *mm, gfp_t gfp)
+{
+       struct page *pte;
+
+       pte = alloc_page(gfp);
+       if (!pte)
+               return NULL;
+       if (!pgtable_page_ctor(pte)) {
+               __free_page(pte);
+               return NULL;
+       }
+
+       return pte;
+}
+
+#ifndef __HAVE_ARCH_PTE_ALLOC_ONE
+/**
+ * pte_alloc_one - allocate a page for PTE-level user page table
+ * @mm: the mm_struct of the current context
+ *
+ * Allocates a page and runs the pgtable_page_ctor().
+ *
+ * Return: `struct page` initialized as page table or %NULL on error
+ */
+static inline pgtable_t pte_alloc_one(struct mm_struct *mm)
+{
+       return __pte_alloc_one(mm, GFP_PGTABLE_USER);
+}
 #endif
 
+/*
+ * Should really implement gc for free page table pages. This could be
+ * done with a reference count in struct page.
+ */
+
+/**
+ * pte_free - free PTE-level user page table page
+ * @mm: the mm_struct of the current context
+ * @pte_page: the `struct page` representing the page table
+ */
+static inline void pte_free(struct mm_struct *mm, struct page *pte_page)
+{
+       pgtable_page_dtor(pte_page);
+       __free_page(pte_page);
+}
+
+#else /* CONFIG_MMU */
+
+/* This is enough for a nommu architecture */
 #define check_pgt_cache()          do { } while (0)
 
+#endif /* CONFIG_MMU */
+
 #endif /* __ASM_GENERIC_PGALLOC_H */
diff --git a/include/asm-generic/ptrace.h b/include/asm-generic/ptrace.h
deleted file mode 100644 (file)
index ab16b6c..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Common low level (register) ptrace helpers
- *
- * Copyright 2004-2011 Analog Devices Inc.
- */
-
-#ifndef __ASM_GENERIC_PTRACE_H__
-#define __ASM_GENERIC_PTRACE_H__
-
-#ifndef __ASSEMBLY__
-
-/* Helpers for working with the instruction pointer */
-#ifndef GET_IP
-#define GET_IP(regs) ((regs)->pc)
-#endif
-#ifndef SET_IP
-#define SET_IP(regs, val) (GET_IP(regs) = (val))
-#endif
-
-static inline unsigned long instruction_pointer(struct pt_regs *regs)
-{
-       return GET_IP(regs);
-}
-static inline void instruction_pointer_set(struct pt_regs *regs,
-                                           unsigned long val)
-{
-       SET_IP(regs, val);
-}
-
-#ifndef profile_pc
-#define profile_pc(regs) instruction_pointer(regs)
-#endif
-
-/* Helpers for working with the user stack pointer */
-#ifndef GET_USP
-#define GET_USP(regs) ((regs)->usp)
-#endif
-#ifndef SET_USP
-#define SET_USP(regs, val) (GET_USP(regs) = (val))
-#endif
-
-static inline unsigned long user_stack_pointer(struct pt_regs *regs)
-{
-       return GET_USP(regs);
-}
-static inline void user_stack_pointer_set(struct pt_regs *regs,
-                                          unsigned long val)
-{
-       SET_USP(regs, val);
-}
-
-/* Helpers for working with the frame pointer */
-#ifndef GET_FP
-#define GET_FP(regs) ((regs)->fp)
-#endif
-#ifndef SET_FP
-#define SET_FP(regs, val) (GET_FP(regs) = (val))
-#endif
-
-static inline unsigned long frame_pointer(struct pt_regs *regs)
-{
-       return GET_FP(regs);
-}
-static inline void frame_pointer_set(struct pt_regs *regs,
-                                     unsigned long val)
-{
-       SET_FP(regs, val);
-}
-
-#endif /* __ASSEMBLY__ */
-
-#endif
index 84a9db1..16c769a 100644 (file)
 #include <asm/perf_event.h>
 
 #define ARMV8_PMU_CYCLE_IDX            (ARMV8_PMU_MAX_COUNTERS - 1)
+#define ARMV8_PMU_MAX_COUNTER_PAIRS    ((ARMV8_PMU_MAX_COUNTERS + 1) >> 1)
 
 #ifdef CONFIG_KVM_ARM_PMU
 
 struct kvm_pmc {
        u8 idx; /* index into the pmu->pmc array */
        struct perf_event *perf_event;
-       u64 bitmask;
 };
 
 struct kvm_pmu {
        int irq_num;
        struct kvm_pmc pmc[ARMV8_PMU_MAX_COUNTERS];
+       DECLARE_BITMAP(chained, ARMV8_PMU_MAX_COUNTER_PAIRS);
        bool ready;
        bool created;
        bool irq_level;
@@ -35,8 +36,8 @@ void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val);
 u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu);
 void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu);
 void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu);
-void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
-void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
+void kvm_pmu_disable_counter_mask(struct kvm_vcpu *vcpu, u64 val);
+void kvm_pmu_enable_counter_mask(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu);
 void kvm_pmu_sync_hwstate(struct kvm_vcpu *vcpu);
 bool kvm_pmu_should_notify_user(struct kvm_vcpu *vcpu);
@@ -72,8 +73,8 @@ static inline u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
 }
 static inline void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu) {}
 static inline void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu) {}
-static inline void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
-static inline void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
+static inline void kvm_pmu_disable_counter_mask(struct kvm_vcpu *vcpu, u64 val) {}
+static inline void kvm_pmu_enable_counter_mask(struct kvm_vcpu *vcpu, u64 val) {}
 static inline void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu) {}
 static inline void kvm_pmu_sync_hwstate(struct kvm_vcpu *vcpu) {}
 static inline bool kvm_pmu_should_notify_user(struct kvm_vcpu *vcpu)
index 07e02d6..6a1a8a3 100644 (file)
@@ -203,7 +203,6 @@ struct backing_dev_info {
 
 #ifdef CONFIG_DEBUG_FS
        struct dentry *debug_dir;
-       struct dentry *debug_stats;
 #endif
 };
 
index f31521d..338aa27 100644 (file)
@@ -64,6 +64,10 @@ extern struct page *balloon_page_alloc(void);
 extern void balloon_page_enqueue(struct balloon_dev_info *b_dev_info,
                                 struct page *page);
 extern struct page *balloon_page_dequeue(struct balloon_dev_info *b_dev_info);
+extern size_t balloon_page_list_enqueue(struct balloon_dev_info *b_dev_info,
+                                     struct list_head *pages);
+extern size_t balloon_page_list_dequeue(struct balloon_dev_info *b_dev_info,
+                                    struct list_head *pages, size_t n_req_pages);
 
 static inline void balloon_devinfo_init(struct balloon_dev_info *balloon)
 {
index fa5f9b7..cf5e840 100644 (file)
@@ -19,9 +19,9 @@ static const struct file_operations name##_fops = {                   \
 };
 
 /* debugfs.c */
-extern int ceph_debugfs_init(void);
+extern void ceph_debugfs_init(void);
 extern void ceph_debugfs_cleanup(void);
-extern int ceph_debugfs_client_init(struct ceph_client *client);
+extern void ceph_debugfs_client_init(struct ceph_client *client);
 extern void ceph_debugfs_client_cleanup(struct ceph_client *client);
 
 #endif
index 62a520d..a2b6882 100644 (file)
@@ -91,15 +91,11 @@ union coresight_dev_subtype {
 
 /**
  * struct coresight_platform_data - data harvested from the DT specification
- * @cpu:       the CPU a source belongs to. Only applicable for ETM/PTMs.
- * @name:      name of the component as shown under sysfs.
  * @nr_inport: number of input ports for this component.
  * @nr_outport:        number of output ports for this component.
  * @conns:     Array of nr_outport connections from this component
  */
 struct coresight_platform_data {
-       int cpu;
-       const char *name;
        int nr_inport;
        int nr_outport;
        struct coresight_connection *conns;
@@ -110,11 +106,12 @@ struct coresight_platform_data {
  * @type:      as defined by @coresight_dev_type.
  * @subtype:   as defined by @coresight_dev_subtype.
  * @ops:       generic operations for this component, as defined
              by @coresight_ops.
*             by @coresight_ops.
  * @pdata:     platform data collected from DT.
  * @dev:       The device entity associated to this component.
  * @groups:    operations specific to this component. These will end up
-               in the component's sysfs sub-directory.
+ *             in the component's sysfs sub-directory.
+ * @name:      name for the coresight device, also shown under sysfs.
  */
 struct coresight_desc {
        enum coresight_dev_type type;
@@ -123,28 +120,27 @@ struct coresight_desc {
        struct coresight_platform_data *pdata;
        struct device *dev;
        const struct attribute_group **groups;
+       const char *name;
 };
 
 /**
  * struct coresight_connection - representation of a single connection
  * @outport:   a connection's output port number.
- * @chid_name: remote component's name.
  * @child_port:        remote component's port number @output is connected to.
+ * @chid_fwnode: remote component's fwnode handle.
  * @child_dev: a @coresight_device representation of the component
                connected to @outport.
  */
 struct coresight_connection {
        int outport;
-       const char *child_name;
        int child_port;
+       struct fwnode_handle *child_fwnode;
        struct coresight_device *child_dev;
 };
 
 /**
  * struct coresight_device - representation of a device as used by the framework
- * @conns:     array of coresight_connections associated to this component.
- * @nr_inport: number of input port associated to this component.
- * @nr_outport:        number of output port associated to this component.
+ * @pdata:     Platform data with device connections associated to this device.
  * @type:      as defined by @coresight_dev_type.
  * @subtype:   as defined by @coresight_dev_subtype.
  * @ops:       generic operations for this component, as defined
@@ -159,9 +155,7 @@ struct coresight_connection {
  * @ea:                Device attribute for sink representation under PMU directory.
  */
 struct coresight_device {
-       struct coresight_connection *conns;
-       int nr_inport;
-       int nr_outport;
+       struct coresight_platform_data *pdata;
        enum coresight_dev_type type;
        union coresight_dev_subtype subtype;
        const struct coresight_ops *ops;
@@ -174,6 +168,28 @@ struct coresight_device {
        struct dev_ext_attribute *ea;
 };
 
+/*
+ * coresight_dev_list - Mapping for devices to "name" index for device
+ * names.
+ *
+ * @nr_idx:            Number of entries already allocated.
+ * @pfx:               Prefix pattern for device name.
+ * @fwnode_list:       Array of fwnode_handles associated with each allocated
+ *                     index, upto nr_idx entries.
+ */
+struct coresight_dev_list {
+       int                     nr_idx;
+       const char              *pfx;
+       struct fwnode_handle    **fwnode_list;
+};
+
+#define DEFINE_CORESIGHT_DEVLIST(var, dev_pfx)                         \
+static struct coresight_dev_list (var) = {                             \
+                                               .pfx = dev_pfx,         \
+                                               .nr_idx = 0,            \
+                                               .fwnode_list = NULL,    \
+}
+
 #define to_coresight_device(d) container_of(d, struct coresight_device, dev)
 
 #define source_ops(csdev)      csdev->ops->source_ops
@@ -267,7 +283,8 @@ extern int coresight_claim_device_unlocked(void __iomem *base);
 
 extern void coresight_disclaim_device(void __iomem *base);
 extern void coresight_disclaim_device_unlocked(void __iomem *base);
-
+extern char *coresight_alloc_device_name(struct coresight_dev_list *devs,
+                                        struct device *dev);
 #else
 static inline struct coresight_device *
 coresight_register(struct coresight_desc *desc) { return NULL; }
@@ -292,16 +309,8 @@ static inline void coresight_disclaim_device_unlocked(void __iomem *base) {}
 
 #endif
 
-#ifdef CONFIG_OF
-extern int of_coresight_get_cpu(const struct device_node *node);
-extern struct coresight_platform_data *
-of_get_coresight_platform_data(struct device *dev,
-                              const struct device_node *node);
-#else
-static inline int of_coresight_get_cpu(const struct device_node *node)
-{ return 0; }
-static inline struct coresight_platform_data *of_get_coresight_platform_data(
-       struct device *dev, const struct device_node *node) { return NULL; }
-#endif
+extern int coresight_get_cpu(struct device *dev);
+
+struct coresight_platform_data *coresight_get_platform_data(struct device *dev);
 
 #endif
index 87c211a..068793a 100644 (file)
@@ -176,6 +176,7 @@ enum cpuhp_state {
        CPUHP_AP_WATCHDOG_ONLINE,
        CPUHP_AP_WORKQUEUE_ONLINE,
        CPUHP_AP_RCUTREE_ONLINE,
+       CPUHP_AP_BASE_CACHEINFO_ONLINE,
        CPUHP_AP_ONLINE_DYN,
        CPUHP_AP_ONLINE_DYN_END         = CPUHP_AP_ONLINE_DYN + 30,
        CPUHP_AP_X86_HPET_ONLINE,
index 3b0ba54..58424eb 100644 (file)
@@ -133,9 +133,8 @@ struct dentry *debugfs_create_regset32(const char *name, umode_t mode,
 void debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs,
                          int nregs, void __iomem *base, char *prefix);
 
-struct dentry *debugfs_create_u32_array(const char *name, umode_t mode,
-                                       struct dentry *parent,
-                                       u32 *array, u32 elements);
+void debugfs_create_u32_array(const char *name, umode_t mode,
+                             struct dentry *parent, u32 *array, u32 elements);
 
 struct dentry *debugfs_create_devm_seqfile(struct device *dev, const char *name,
                                           struct dentry *parent,
@@ -353,11 +352,10 @@ static inline bool debugfs_initialized(void)
        return false;
 }
 
-static inline struct dentry *debugfs_create_u32_array(const char *name, umode_t mode,
-                                       struct dentry *parent,
-                                       u32 *array, u32 elements)
+static inline void debugfs_create_u32_array(const char *name, umode_t mode,
+                                           struct dentry *parent, u32 *array,
+                                           u32 elements)
 {
-       return ERR_PTR(-ENODEV);
 }
 
 static inline struct dentry *debugfs_create_devm_seqfile(struct device *dev,
index adfcabc..5eabfa0 100644 (file)
@@ -164,11 +164,13 @@ void subsys_dev_iter_init(struct subsys_dev_iter *iter,
 struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter);
 void subsys_dev_iter_exit(struct subsys_dev_iter *iter);
 
+int device_match_of_node(struct device *dev, const void *np);
+
 int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data,
                     int (*fn)(struct device *dev, void *data));
 struct device *bus_find_device(struct bus_type *bus, struct device *start,
-                              void *data,
-                              int (*match)(struct device *dev, void *data));
+                              const void *data,
+                              int (*match)(struct device *dev, const void *data));
 struct device *bus_find_device_by_name(struct bus_type *bus,
                                       struct device *start,
                                       const char *name);
@@ -337,11 +339,12 @@ extern int __must_check driver_for_each_device(struct device_driver *drv,
                                               int (*fn)(struct device *dev,
                                                         void *));
 struct device *driver_find_device(struct device_driver *drv,
-                                 struct device *start, void *data,
-                                 int (*match)(struct device *dev, void *data));
+                                 struct device *start, const void *data,
+                                 int (*match)(struct device *dev, const void *data));
 
 void driver_deferred_probe_add(struct device *dev);
 int driver_deferred_probe_check_state(struct device *dev);
+int driver_deferred_probe_check_state_continue(struct device *dev);
 
 /**
  * struct subsys_interface - interfaces to device functions
index 6665fa0..c05d4e6 100644 (file)
@@ -50,6 +50,7 @@
 #ifdef __KERNEL__
 
 #include <linux/device.h>
+#include <linux/mm.h>
 
 struct cma;
 struct page;
@@ -111,6 +112,8 @@ struct page *dma_alloc_from_contiguous(struct device *dev, size_t count,
                                       unsigned int order, bool no_warn);
 bool dma_release_from_contiguous(struct device *dev, struct page *pages,
                                 int count);
+struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp);
+void dma_free_contiguous(struct device *dev, struct page *page, size_t size);
 
 #else
 
@@ -153,6 +156,22 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages,
        return false;
 }
 
+/* Use fallback alloc() and free() when CONFIG_DMA_CMA=n */
+static inline struct page *dma_alloc_contiguous(struct device *dev, size_t size,
+               gfp_t gfp)
+{
+       int node = dev ? dev_to_node(dev) : NUMA_NO_NODE;
+       size_t align = get_order(PAGE_ALIGN(size));
+
+       return alloc_pages_node(node, gfp, align);
+}
+
+static inline void dma_free_contiguous(struct device *dev, struct page *page,
+               size_t size)
+{
+       __free_pages(page, get_order(size));
+}
+
 #endif
 
 #endif
index 6309a72..8d13e28 100644 (file)
@@ -729,13 +729,6 @@ static inline int dma_set_seg_boundary(struct device *dev, unsigned long mask)
        return -EIO;
 }
 
-#ifndef dma_max_pfn
-static inline unsigned long dma_max_pfn(struct device *dev)
-{
-       return (*dev->dma_mask >> PAGE_SHIFT) + dev->dma_pfn_offset;
-}
-#endif
-
 static inline int dma_get_cache_alignment(void)
 {
 #ifdef ARCH_DMA_MINALIGN
index 9741767..3813211 100644 (file)
@@ -20,6 +20,22 @@ static inline bool dev_is_dma_coherent(struct device *dev)
 }
 #endif /* CONFIG_ARCH_HAS_DMA_COHERENCE_H */
 
+/*
+ * Check if an allocation needs to be marked uncached to be coherent.
+ */
+static __always_inline bool dma_alloc_need_uncached(struct device *dev,
+               unsigned long attrs)
+{
+       if (dev_is_dma_coherent(dev))
+               return false;
+       if (attrs & DMA_ATTR_NO_KERNEL_MAPPING)
+               return false;
+       if (IS_ENABLED(CONFIG_DMA_NONCOHERENT_CACHE_SYNC) &&
+           (attrs & DMA_ATTR_NON_CONSISTENT))
+               return false;
+       return true;
+}
+
 void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
                gfp_t gfp, unsigned long attrs);
 void arch_dma_free(struct device *dev, size_t size, void *cpu_addr,
@@ -80,4 +96,7 @@ static inline void arch_dma_prep_coherent(struct page *page, size_t size)
 }
 #endif /* CONFIG_ARCH_HAS_DMA_PREP_COHERENT */
 
+void *uncached_kernel_address(void *addr);
+void *cached_kernel_address(void *addr);
+
 #endif /* _LINUX_DMA_NONCOHERENT_H */
diff --git a/include/linux/dma/mxs-dma.h b/include/linux/dma/mxs-dma.h
new file mode 100644 (file)
index 0000000..069d9f5
--- /dev/null
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _MXS_DMA_H_
+#define _MXS_DMA_H_
+
+#include <linux/dmaengine.h>
+
+#define MXS_DMA_CTRL_WAIT4END  BIT(31)
+#define MXS_DMA_CTRL_WAIT4RDY  BIT(30)
+
+/*
+ * The mxs dmaengine can do PIO transfers. We pass a pointer to the PIO words
+ * in the second argument to dmaengine_prep_slave_sg when the direction is
+ * set to DMA_TRANS_NONE. To make this clear and to prevent users from doing
+ * the error prone casting we have this wrapper function
+ */
+static inline struct dma_async_tx_descriptor *mxs_dmaengine_prep_pio(
+        struct dma_chan *chan, u32 *pio, unsigned int npio,
+        enum dma_transfer_direction dir, unsigned long flags)
+{
+       return dmaengine_prep_slave_sg(chan, (struct scatterlist *)pio, npio,
+                                      dir, flags);
+}
+
+#endif /* _MXS_DMA_H_ */
index 28813c6..a7cf359 100644 (file)
@@ -92,12 +92,14 @@ static inline bool dmar_rcu_check(void)
 
 #define        dmar_rcu_dereference(p) rcu_dereference_check((p), dmar_rcu_check())
 
-#define        for_each_dev_scope(a, c, p, d)  \
-       for ((p) = 0; ((d) = (p) < (c) ? dmar_rcu_dereference((a)[(p)].dev) : \
-                       NULL, (p) < (c)); (p)++)
-
-#define        for_each_active_dev_scope(a, c, p, d)   \
-       for_each_dev_scope((a), (c), (p), (d))  if (!(d)) { continue; } else
+#define for_each_dev_scope(devs, cnt, i, tmp)                          \
+       for ((i) = 0; ((tmp) = (i) < (cnt) ?                            \
+           dmar_rcu_dereference((devs)[(i)].dev) : NULL, (i) < (cnt)); \
+           (i)++)
+
+#define for_each_active_dev_scope(devs, cnt, i, tmp)                   \
+       for_each_dev_scope((devs), (cnt), (i), (tmp))                   \
+               if (!(tmp)) { continue; } else
 
 extern int dmar_table_init(void);
 extern int dmar_dev_scope_init(void);
index 1262ea6..778abbb 100644 (file)
@@ -46,7 +46,6 @@
 #define        ZYNQMP_PM_CAPABILITY_ACCESS     0x1U
 #define        ZYNQMP_PM_CAPABILITY_CONTEXT    0x2U
 #define        ZYNQMP_PM_CAPABILITY_WAKEUP     0x4U
-#define        ZYNQMP_PM_CAPABILITY_POWER      0x8U
 
 /*
  * Firmware FPGA Manager flags
index 9193f5f..75f2ed2 100644 (file)
@@ -3556,4 +3556,16 @@ static inline struct sock *io_uring_get_socket(struct file *file)
 }
 #endif
 
+int vfs_ioc_setflags_prepare(struct inode *inode, unsigned int oldflags,
+                            unsigned int flags);
+
+int vfs_ioc_fssetxattr_check(struct inode *inode, const struct fsxattr *old_fa,
+                            struct fsxattr *fa);
+
+static inline void simple_fill_fsxattr(struct fsxattr *fa, __u32 xflags)
+{
+       memset(fa, 0, sizeof(*fa));
+       fa->fsx_xflags = xflags;
+}
+
 #endif /* _LINUX_FS_H */
index cb2b46f..5d231ce 100644 (file)
@@ -98,6 +98,7 @@ struct fsl_usb2_platform_data {
        unsigned        has_fsl_erratum_14:1;
        unsigned        has_fsl_erratum_a005275:1;
        unsigned        has_fsl_erratum_a005697:1;
+       unsigned        has_fsl_erratum_a006918:1;
        unsigned        check_phy_clk_valid:1;
 
        /* register save area for suspend/resume */
index 205f62b..4bd583b 100644 (file)
@@ -155,6 +155,15 @@ static inline unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)
 
 extern void *gen_pool_dma_alloc(struct gen_pool *pool, size_t size,
                dma_addr_t *dma);
+extern void *gen_pool_dma_alloc_algo(struct gen_pool *pool, size_t size,
+               dma_addr_t *dma, genpool_algo_t algo, void *data);
+extern void *gen_pool_dma_alloc_align(struct gen_pool *pool, size_t size,
+               dma_addr_t *dma, int align);
+extern void *gen_pool_dma_zalloc(struct gen_pool *pool, size_t size, dma_addr_t *dma);
+extern void *gen_pool_dma_zalloc_algo(struct gen_pool *pool, size_t size,
+               dma_addr_t *dma, genpool_algo_t algo, void *data);
+extern void *gen_pool_dma_zalloc_align(struct gen_pool *pool, size_t size,
+               dma_addr_t *dma, int align);
 extern void gen_pool_free_owner(struct gen_pool *pool, unsigned long addr,
                size_t size, void **owner);
 static inline void gen_pool_free(struct gen_pool *pool, unsigned long addr,
index 39745b8..40915b4 100644 (file)
@@ -106,6 +106,7 @@ void devm_gpio_free(struct device *dev, unsigned int gpio);
 
 struct device;
 struct gpio_chip;
+struct pinctrl_dev;
 
 static inline bool gpio_is_valid(int number)
 {
index 8d58386..6a0e420 100644 (file)
@@ -586,6 +586,8 @@ void gpiochip_remove_pin_ranges(struct gpio_chip *chip);
 
 #else /* ! CONFIG_PINCTRL */
 
+struct pinctrl_dev;
+
 static inline int
 gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
                       unsigned int gpio_offset, unsigned int pin_offset,
index edf476c..edfca42 100644 (file)
@@ -16,29 +16,11 @@ struct user_struct;
 struct mmu_gather;
 
 #ifndef is_hugepd
-/*
- * Some architectures requires a hugepage directory format that is
- * required to support multiple hugepage sizes. For example
- * a4fe3ce76 "powerpc/mm: Allow more flexible layouts for hugepage pagetables"
- * introduced the same on powerpc. This allows for a more flexible hugepage
- * pagetable layout.
- */
 typedef struct { unsigned long pd; } hugepd_t;
 #define is_hugepd(hugepd) (0)
 #define __hugepd(x) ((hugepd_t) { (x) })
-static inline int gup_huge_pd(hugepd_t hugepd, unsigned long addr,
-                             unsigned pdshift, unsigned long end,
-                             int write, struct page **pages, int *nr)
-{
-       return 0;
-}
-#else
-extern int gup_huge_pd(hugepd_t hugepd, unsigned long addr,
-                      unsigned pdshift, unsigned long end,
-                      int write, struct page **pages, int *nr);
 #endif
 
-
 #ifdef CONFIG_HUGETLB_PAGE
 
 #include <linux/mempolicy.h>
@@ -608,22 +590,92 @@ static inline void huge_ptep_modify_prot_commit(struct vm_area_struct *vma,
 
 #else  /* CONFIG_HUGETLB_PAGE */
 struct hstate {};
-#define alloc_huge_page(v, a, r) NULL
-#define alloc_huge_page_node(h, nid) NULL
-#define alloc_huge_page_nodemask(h, preferred_nid, nmask) NULL
-#define alloc_huge_page_vma(h, vma, address) NULL
-#define alloc_bootmem_huge_page(h) NULL
-#define hstate_file(f) NULL
-#define hstate_sizelog(s) NULL
-#define hstate_vma(v) NULL
-#define hstate_inode(i) NULL
-#define page_hstate(page) NULL
-#define huge_page_size(h) PAGE_SIZE
-#define huge_page_mask(h) PAGE_MASK
-#define vma_kernel_pagesize(v) PAGE_SIZE
-#define vma_mmu_pagesize(v) PAGE_SIZE
-#define huge_page_order(h) 0
-#define huge_page_shift(h) PAGE_SHIFT
+
+static inline struct page *alloc_huge_page(struct vm_area_struct *vma,
+                                          unsigned long addr,
+                                          int avoid_reserve)
+{
+       return NULL;
+}
+
+static inline struct page *alloc_huge_page_node(struct hstate *h, int nid)
+{
+       return NULL;
+}
+
+static inline struct page *
+alloc_huge_page_nodemask(struct hstate *h, int preferred_nid, nodemask_t *nmask)
+{
+       return NULL;
+}
+
+static inline struct page *alloc_huge_page_vma(struct hstate *h,
+                                              struct vm_area_struct *vma,
+                                              unsigned long address)
+{
+       return NULL;
+}
+
+static inline int __alloc_bootmem_huge_page(struct hstate *h)
+{
+       return 0;
+}
+
+static inline struct hstate *hstate_file(struct file *f)
+{
+       return NULL;
+}
+
+static inline struct hstate *hstate_sizelog(int page_size_log)
+{
+       return NULL;
+}
+
+static inline struct hstate *hstate_vma(struct vm_area_struct *vma)
+{
+       return NULL;
+}
+
+static inline struct hstate *hstate_inode(struct inode *i)
+{
+       return NULL;
+}
+
+static inline struct hstate *page_hstate(struct page *page)
+{
+       return NULL;
+}
+
+static inline unsigned long huge_page_size(struct hstate *h)
+{
+       return PAGE_SIZE;
+}
+
+static inline unsigned long huge_page_mask(struct hstate *h)
+{
+       return PAGE_MASK;
+}
+
+static inline unsigned long vma_kernel_pagesize(struct vm_area_struct *vma)
+{
+       return PAGE_SIZE;
+}
+
+static inline unsigned long vma_mmu_pagesize(struct vm_area_struct *vma)
+{
+       return PAGE_SIZE;
+}
+
+static inline unsigned int huge_page_order(struct hstate *h)
+{
+       return 0;
+}
+
+static inline unsigned int huge_page_shift(struct hstate *h)
+{
+       return PAGE_SHIFT;
+}
+
 static inline bool hstate_is_gigantic(struct hstate *h)
 {
        return false;
index 971cf76..46b771d 100644 (file)
@@ -253,9 +253,9 @@ static inline void ide_std_init_ports(struct ide_hw *hw,
  * Special Driver Flags
  */
 enum {
-       IDE_SFLAG_SET_GEOMETRY          = (1 << 0),
-       IDE_SFLAG_RECALIBRATE           = (1 << 1),
-       IDE_SFLAG_SET_MULTMODE          = (1 << 2),
+       IDE_SFLAG_SET_GEOMETRY          = BIT(0),
+       IDE_SFLAG_RECALIBRATE           = BIT(1),
+       IDE_SFLAG_SET_MULTMODE          = BIT(2),
 };
 
 /*
@@ -267,13 +267,13 @@ typedef enum {
 } ide_startstop_t;
 
 enum {
-       IDE_VALID_ERROR                 = (1 << 1),
+       IDE_VALID_ERROR                 = BIT(1),
        IDE_VALID_FEATURE               = IDE_VALID_ERROR,
-       IDE_VALID_NSECT                 = (1 << 2),
-       IDE_VALID_LBAL                  = (1 << 3),
-       IDE_VALID_LBAM                  = (1 << 4),
-       IDE_VALID_LBAH                  = (1 << 5),
-       IDE_VALID_DEVICE                = (1 << 6),
+       IDE_VALID_NSECT                 = BIT(2),
+       IDE_VALID_LBAL                  = BIT(3),
+       IDE_VALID_LBAM                  = BIT(4),
+       IDE_VALID_LBAH                  = BIT(5),
+       IDE_VALID_DEVICE                = BIT(6),
        IDE_VALID_LBA                   = IDE_VALID_LBAL |
                                          IDE_VALID_LBAM |
                                          IDE_VALID_LBAH,
@@ -289,24 +289,24 @@ enum {
 };
 
 enum {
-       IDE_TFLAG_LBA48                 = (1 << 0),
-       IDE_TFLAG_WRITE                 = (1 << 1),
-       IDE_TFLAG_CUSTOM_HANDLER        = (1 << 2),
-       IDE_TFLAG_DMA_PIO_FALLBACK      = (1 << 3),
+       IDE_TFLAG_LBA48                 = BIT(0),
+       IDE_TFLAG_WRITE                 = BIT(1),
+       IDE_TFLAG_CUSTOM_HANDLER        = BIT(2),
+       IDE_TFLAG_DMA_PIO_FALLBACK      = BIT(3),
        /* force 16-bit I/O operations */
-       IDE_TFLAG_IO_16BIT              = (1 << 4),
+       IDE_TFLAG_IO_16BIT              = BIT(4),
        /* struct ide_cmd was allocated using kmalloc() */
-       IDE_TFLAG_DYN                   = (1 << 5),
-       IDE_TFLAG_FS                    = (1 << 6),
-       IDE_TFLAG_MULTI_PIO             = (1 << 7),
-       IDE_TFLAG_SET_XFER              = (1 << 8),
+       IDE_TFLAG_DYN                   = BIT(5),
+       IDE_TFLAG_FS                    = BIT(6),
+       IDE_TFLAG_MULTI_PIO             = BIT(7),
+       IDE_TFLAG_SET_XFER              = BIT(8),
 };
 
 enum {
-       IDE_FTFLAG_FLAGGED              = (1 << 0),
-       IDE_FTFLAG_SET_IN_FLAGS         = (1 << 1),
-       IDE_FTFLAG_OUT_DATA             = (1 << 2),
-       IDE_FTFLAG_IN_DATA              = (1 << 3),
+       IDE_FTFLAG_FLAGGED              = BIT(0),
+       IDE_FTFLAG_SET_IN_FLAGS         = BIT(1),
+       IDE_FTFLAG_OUT_DATA             = BIT(2),
+       IDE_FTFLAG_IN_DATA              = BIT(3),
 };
 
 struct ide_taskfile {
@@ -357,13 +357,13 @@ struct ide_cmd {
 /* ATAPI packet command flags */
 enum {
        /* set when an error is considered normal - no retry (ide-tape) */
-       PC_FLAG_ABORT                   = (1 << 0),
-       PC_FLAG_SUPPRESS_ERROR          = (1 << 1),
-       PC_FLAG_WAIT_FOR_DSC            = (1 << 2),
-       PC_FLAG_DMA_OK                  = (1 << 3),
-       PC_FLAG_DMA_IN_PROGRESS         = (1 << 4),
-       PC_FLAG_DMA_ERROR               = (1 << 5),
-       PC_FLAG_WRITING                 = (1 << 6),
+       PC_FLAG_ABORT                   = BIT(0),
+       PC_FLAG_SUPPRESS_ERROR          = BIT(1),
+       PC_FLAG_WAIT_FOR_DSC            = BIT(2),
+       PC_FLAG_DMA_OK                  = BIT(3),
+       PC_FLAG_DMA_IN_PROGRESS         = BIT(4),
+       PC_FLAG_DMA_ERROR               = BIT(5),
+       PC_FLAG_WRITING                 = BIT(6),
 };
 
 #define ATAPI_WAIT_PC          (60 * HZ)
@@ -417,111 +417,111 @@ struct ide_disk_ops {
 
 /* ATAPI device flags */
 enum {
-       IDE_AFLAG_DRQ_INTERRUPT         = (1 << 0),
+       IDE_AFLAG_DRQ_INTERRUPT         = BIT(0),
 
        /* ide-cd */
        /* Drive cannot eject the disc. */
-       IDE_AFLAG_NO_EJECT              = (1 << 1),
+       IDE_AFLAG_NO_EJECT              = BIT(1),
        /* Drive is a pre ATAPI 1.2 drive. */
-       IDE_AFLAG_PRE_ATAPI12           = (1 << 2),
+       IDE_AFLAG_PRE_ATAPI12           = BIT(2),
        /* TOC addresses are in BCD. */
-       IDE_AFLAG_TOCADDR_AS_BCD        = (1 << 3),
+       IDE_AFLAG_TOCADDR_AS_BCD        = BIT(3),
        /* TOC track numbers are in BCD. */
-       IDE_AFLAG_TOCTRACKS_AS_BCD      = (1 << 4),
+       IDE_AFLAG_TOCTRACKS_AS_BCD      = BIT(4),
        /* Saved TOC information is current. */
-       IDE_AFLAG_TOC_VALID             = (1 << 6),
+       IDE_AFLAG_TOC_VALID             = BIT(6),
        /* We think that the drive door is locked. */
-       IDE_AFLAG_DOOR_LOCKED           = (1 << 7),
+       IDE_AFLAG_DOOR_LOCKED           = BIT(7),
        /* SET_CD_SPEED command is unsupported. */
-       IDE_AFLAG_NO_SPEED_SELECT       = (1 << 8),
-       IDE_AFLAG_VERTOS_300_SSD        = (1 << 9),
-       IDE_AFLAG_VERTOS_600_ESD        = (1 << 10),
-       IDE_AFLAG_SANYO_3CD             = (1 << 11),
-       IDE_AFLAG_FULL_CAPS_PAGE        = (1 << 12),
-       IDE_AFLAG_PLAY_AUDIO_OK         = (1 << 13),
-       IDE_AFLAG_LE_SPEED_FIELDS       = (1 << 14),
+       IDE_AFLAG_NO_SPEED_SELECT       = BIT(8),
+       IDE_AFLAG_VERTOS_300_SSD        = BIT(9),
+       IDE_AFLAG_VERTOS_600_ESD        = BIT(10),
+       IDE_AFLAG_SANYO_3CD             = BIT(11),
+       IDE_AFLAG_FULL_CAPS_PAGE        = BIT(12),
+       IDE_AFLAG_PLAY_AUDIO_OK         = BIT(13),
+       IDE_AFLAG_LE_SPEED_FIELDS       = BIT(14),
 
        /* ide-floppy */
        /* Avoid commands not supported in Clik drive */
-       IDE_AFLAG_CLIK_DRIVE            = (1 << 15),
+       IDE_AFLAG_CLIK_DRIVE            = BIT(15),
        /* Requires BH algorithm for packets */
-       IDE_AFLAG_ZIP_DRIVE             = (1 << 16),
+       IDE_AFLAG_ZIP_DRIVE             = BIT(16),
        /* Supports format progress report */
-       IDE_AFLAG_SRFP                  = (1 << 17),
+       IDE_AFLAG_SRFP                  = BIT(17),
 
        /* ide-tape */
-       IDE_AFLAG_IGNORE_DSC            = (1 << 18),
+       IDE_AFLAG_IGNORE_DSC            = BIT(18),
        /* 0 When the tape position is unknown */
-       IDE_AFLAG_ADDRESS_VALID         = (1 << 19),
+       IDE_AFLAG_ADDRESS_VALID         = BIT(19),
        /* Device already opened */
-       IDE_AFLAG_BUSY                  = (1 << 20),
+       IDE_AFLAG_BUSY                  = BIT(20),
        /* Attempt to auto-detect the current user block size */
-       IDE_AFLAG_DETECT_BS             = (1 << 21),
+       IDE_AFLAG_DETECT_BS             = BIT(21),
        /* Currently on a filemark */
-       IDE_AFLAG_FILEMARK              = (1 << 22),
+       IDE_AFLAG_FILEMARK              = BIT(22),
        /* 0 = no tape is loaded, so we don't rewind after ejecting */
-       IDE_AFLAG_MEDIUM_PRESENT        = (1 << 23),
+       IDE_AFLAG_MEDIUM_PRESENT        = BIT(23),
 
-       IDE_AFLAG_NO_AUTOCLOSE          = (1 << 24),
+       IDE_AFLAG_NO_AUTOCLOSE          = BIT(24),
 };
 
 /* device flags */
 enum {
        /* restore settings after device reset */
-       IDE_DFLAG_KEEP_SETTINGS         = (1 << 0),
+       IDE_DFLAG_KEEP_SETTINGS         = BIT(0),
        /* device is using DMA for read/write */
-       IDE_DFLAG_USING_DMA             = (1 << 1),
+       IDE_DFLAG_USING_DMA             = BIT(1),
        /* okay to unmask other IRQs */
-       IDE_DFLAG_UNMASK                = (1 << 2),
+       IDE_DFLAG_UNMASK                = BIT(2),
        /* don't attempt flushes */
-       IDE_DFLAG_NOFLUSH               = (1 << 3),
+       IDE_DFLAG_NOFLUSH               = BIT(3),
        /* DSC overlap */
-       IDE_DFLAG_DSC_OVERLAP           = (1 << 4),
+       IDE_DFLAG_DSC_OVERLAP           = BIT(4),
        /* give potential excess bandwidth */
-       IDE_DFLAG_NICE1                 = (1 << 5),
+       IDE_DFLAG_NICE1                 = BIT(5),
        /* device is physically present */
-       IDE_DFLAG_PRESENT               = (1 << 6),
+       IDE_DFLAG_PRESENT               = BIT(6),
        /* disable Host Protected Area */
-       IDE_DFLAG_NOHPA                 = (1 << 7),
+       IDE_DFLAG_NOHPA                 = BIT(7),
        /* id read from device (synthetic if not set) */
-       IDE_DFLAG_ID_READ               = (1 << 8),
-       IDE_DFLAG_NOPROBE               = (1 << 9),
+       IDE_DFLAG_ID_READ               = BIT(8),
+       IDE_DFLAG_NOPROBE               = BIT(9),
        /* need to do check_media_change() */
-       IDE_DFLAG_REMOVABLE             = (1 << 10),
+       IDE_DFLAG_REMOVABLE             = BIT(10),
        /* needed for removable devices */
-       IDE_DFLAG_ATTACH                = (1 << 11),
-       IDE_DFLAG_FORCED_GEOM           = (1 << 12),
+       IDE_DFLAG_ATTACH                = BIT(11),
+       IDE_DFLAG_FORCED_GEOM           = BIT(12),
        /* disallow setting unmask bit */
-       IDE_DFLAG_NO_UNMASK             = (1 << 13),
+       IDE_DFLAG_NO_UNMASK             = BIT(13),
        /* disallow enabling 32-bit I/O */
-       IDE_DFLAG_NO_IO_32BIT           = (1 << 14),
+       IDE_DFLAG_NO_IO_32BIT           = BIT(14),
        /* for removable only: door lock/unlock works */
-       IDE_DFLAG_DOORLOCKING           = (1 << 15),
+       IDE_DFLAG_DOORLOCKING           = BIT(15),
        /* disallow DMA */
-       IDE_DFLAG_NODMA                 = (1 << 16),
+       IDE_DFLAG_NODMA                 = BIT(16),
        /* powermanagement told us not to do anything, so sleep nicely */
-       IDE_DFLAG_BLOCKED               = (1 << 17),
+       IDE_DFLAG_BLOCKED               = BIT(17),
        /* sleeping & sleep field valid */
-       IDE_DFLAG_SLEEPING              = (1 << 18),
-       IDE_DFLAG_POST_RESET            = (1 << 19),
-       IDE_DFLAG_UDMA33_WARNED         = (1 << 20),
-       IDE_DFLAG_LBA48                 = (1 << 21),
+       IDE_DFLAG_SLEEPING              = BIT(18),
+       IDE_DFLAG_POST_RESET            = BIT(19),
+       IDE_DFLAG_UDMA33_WARNED         = BIT(20),
+       IDE_DFLAG_LBA48                 = BIT(21),
        /* status of write cache */
-       IDE_DFLAG_WCACHE                = (1 << 22),
+       IDE_DFLAG_WCACHE                = BIT(22),
        /* used for ignoring ATA_DF */
-       IDE_DFLAG_NOWERR                = (1 << 23),
+       IDE_DFLAG_NOWERR                = BIT(23),
        /* retrying in PIO */
-       IDE_DFLAG_DMA_PIO_RETRY         = (1 << 24),
-       IDE_DFLAG_LBA                   = (1 << 25),
+       IDE_DFLAG_DMA_PIO_RETRY         = BIT(24),
+       IDE_DFLAG_LBA                   = BIT(25),
        /* don't unload heads */
-       IDE_DFLAG_NO_UNLOAD             = (1 << 26),
+       IDE_DFLAG_NO_UNLOAD             = BIT(26),
        /* heads unloaded, please don't reset port */
-       IDE_DFLAG_PARKED                = (1 << 27),
-       IDE_DFLAG_MEDIA_CHANGED         = (1 << 28),
+       IDE_DFLAG_PARKED                = BIT(27),
+       IDE_DFLAG_MEDIA_CHANGED         = BIT(28),
        /* write protect */
-       IDE_DFLAG_WP                    = (1 << 29),
-       IDE_DFLAG_FORMAT_IN_PROGRESS    = (1 << 30),
-       IDE_DFLAG_NIEN_QUIRK            = (1 << 31),
+       IDE_DFLAG_WP                    = BIT(29),
+       IDE_DFLAG_FORMAT_IN_PROGRESS    = BIT(30),
+       IDE_DFLAG_NIEN_QUIRK            = BIT(31),
 };
 
 struct ide_drive_s {
@@ -709,7 +709,7 @@ struct ide_dma_ops {
 };
 
 enum {
-       IDE_PFLAG_PROBING               = (1 << 0),
+       IDE_PFLAG_PROBING               = BIT(0),
 };
 
 struct ide_host;
@@ -862,7 +862,7 @@ extern struct mutex ide_setting_mtx;
  * configurable drive settings
  */
 
-#define DS_SYNC        (1 << 0)
+#define DS_SYNC        BIT(0)
 
 struct ide_devset {
        int             (*get)(ide_drive_t *);
@@ -1000,15 +1000,15 @@ static inline void ide_proc_unregister_driver(ide_drive_t *drive,
 
 enum {
        /* enter/exit functions */
-       IDE_DBG_FUNC =                  (1 << 0),
+       IDE_DBG_FUNC =                  BIT(0),
        /* sense key/asc handling */
-       IDE_DBG_SENSE =                 (1 << 1),
+       IDE_DBG_SENSE =                 BIT(1),
        /* packet commands handling */
-       IDE_DBG_PC =                    (1 << 2),
+       IDE_DBG_PC =                    BIT(2),
        /* request handling */
-       IDE_DBG_RQ =                    (1 << 3),
+       IDE_DBG_RQ =                    BIT(3),
        /* driver probing/setup */
-       IDE_DBG_PROBE =                 (1 << 4),
+       IDE_DBG_PROBE =                 BIT(4),
 };
 
 /* DRV_NAME has to be defined in the driver before using the macro below */
@@ -1171,10 +1171,10 @@ ssize_t ide_park_store(struct device *dev, struct device_attribute *attr,
  * the tail of our block device request queue and wait for their completion.
  */
 enum {
-       REQ_IDETAPE_PC1         = (1 << 0), /* packet command (first stage) */
-       REQ_IDETAPE_PC2         = (1 << 1), /* packet command (second stage) */
-       REQ_IDETAPE_READ        = (1 << 2),
-       REQ_IDETAPE_WRITE       = (1 << 3),
+       REQ_IDETAPE_PC1         = BIT(0), /* packet command (first stage) */
+       REQ_IDETAPE_PC2         = BIT(1), /* packet command (second stage) */
+       REQ_IDETAPE_READ        = BIT(2),
+       REQ_IDETAPE_WRITE       = BIT(3),
 };
 
 int ide_queue_pc_tail(ide_drive_t *, struct gendisk *, struct ide_atapi_pc *,
@@ -1264,71 +1264,71 @@ struct ide_pci_enablebit {
 
 enum {
        /* Uses ISA control ports not PCI ones. */
-       IDE_HFLAG_ISA_PORTS             = (1 << 0),
+       IDE_HFLAG_ISA_PORTS             = BIT(0),
        /* single port device */
-       IDE_HFLAG_SINGLE                = (1 << 1),
+       IDE_HFLAG_SINGLE                = BIT(1),
        /* don't use legacy PIO blacklist */
-       IDE_HFLAG_PIO_NO_BLACKLIST      = (1 << 2),
+       IDE_HFLAG_PIO_NO_BLACKLIST      = BIT(2),
        /* set for the second port of QD65xx */
-       IDE_HFLAG_QD_2ND_PORT           = (1 << 3),
+       IDE_HFLAG_QD_2ND_PORT           = BIT(3),
        /* use PIO8/9 for prefetch off/on */
-       IDE_HFLAG_ABUSE_PREFETCH        = (1 << 4),
+       IDE_HFLAG_ABUSE_PREFETCH        = BIT(4),
        /* use PIO6/7 for fast-devsel off/on */
-       IDE_HFLAG_ABUSE_FAST_DEVSEL     = (1 << 5),
+       IDE_HFLAG_ABUSE_FAST_DEVSEL     = BIT(5),
        /* use 100-102 and 200-202 PIO values to set DMA modes */
-       IDE_HFLAG_ABUSE_DMA_MODES       = (1 << 6),
+       IDE_HFLAG_ABUSE_DMA_MODES       = BIT(6),
        /*
         * keep DMA setting when programming PIO mode, may be used only
         * for hosts which have separate PIO and DMA timings (ie. PMAC)
         */
-       IDE_HFLAG_SET_PIO_MODE_KEEP_DMA = (1 << 7),
+       IDE_HFLAG_SET_PIO_MODE_KEEP_DMA = BIT(7),
        /* program host for the transfer mode after programming device */
-       IDE_HFLAG_POST_SET_MODE         = (1 << 8),
+       IDE_HFLAG_POST_SET_MODE         = BIT(8),
        /* don't program host/device for the transfer mode ("smart" hosts) */
-       IDE_HFLAG_NO_SET_MODE           = (1 << 9),
+       IDE_HFLAG_NO_SET_MODE           = BIT(9),
        /* trust BIOS for programming chipset/device for DMA */
-       IDE_HFLAG_TRUST_BIOS_FOR_DMA    = (1 << 10),
+       IDE_HFLAG_TRUST_BIOS_FOR_DMA    = BIT(10),
        /* host is CS5510/CS5520 */
-       IDE_HFLAG_CS5520                = (1 << 11),
+       IDE_HFLAG_CS5520                = BIT(11),
        /* ATAPI DMA is unsupported */
-       IDE_HFLAG_NO_ATAPI_DMA          = (1 << 12),
+       IDE_HFLAG_NO_ATAPI_DMA          = BIT(12),
        /* set if host is a "non-bootable" controller */
-       IDE_HFLAG_NON_BOOTABLE          = (1 << 13),
+       IDE_HFLAG_NON_BOOTABLE          = BIT(13),
        /* host doesn't support DMA */
-       IDE_HFLAG_NO_DMA                = (1 << 14),
+       IDE_HFLAG_NO_DMA                = BIT(14),
        /* check if host is PCI IDE device before allowing DMA */
-       IDE_HFLAG_NO_AUTODMA            = (1 << 15),
+       IDE_HFLAG_NO_AUTODMA            = BIT(15),
        /* host uses MMIO */
-       IDE_HFLAG_MMIO                  = (1 << 16),
+       IDE_HFLAG_MMIO                  = BIT(16),
        /* no LBA48 */
-       IDE_HFLAG_NO_LBA48              = (1 << 17),
+       IDE_HFLAG_NO_LBA48              = BIT(17),
        /* no LBA48 DMA */
-       IDE_HFLAG_NO_LBA48_DMA          = (1 << 18),
+       IDE_HFLAG_NO_LBA48_DMA          = BIT(18),
        /* data FIFO is cleared by an error */
-       IDE_HFLAG_ERROR_STOPS_FIFO      = (1 << 19),
+       IDE_HFLAG_ERROR_STOPS_FIFO      = BIT(19),
        /* serialize ports */
-       IDE_HFLAG_SERIALIZE             = (1 << 20),
+       IDE_HFLAG_SERIALIZE             = BIT(20),
        /* host is DTC2278 */
-       IDE_HFLAG_DTC2278               = (1 << 21),
+       IDE_HFLAG_DTC2278               = BIT(21),
        /* 4 devices on a single set of I/O ports */
-       IDE_HFLAG_4DRIVES               = (1 << 22),
+       IDE_HFLAG_4DRIVES               = BIT(22),
        /* host is TRM290 */
-       IDE_HFLAG_TRM290                = (1 << 23),
+       IDE_HFLAG_TRM290                = BIT(23),
        /* use 32-bit I/O ops */
-       IDE_HFLAG_IO_32BIT              = (1 << 24),
+       IDE_HFLAG_IO_32BIT              = BIT(24),
        /* unmask IRQs */
-       IDE_HFLAG_UNMASK_IRQS           = (1 << 25),
-       IDE_HFLAG_BROKEN_ALTSTATUS      = (1 << 26),
+       IDE_HFLAG_UNMASK_IRQS           = BIT(25),
+       IDE_HFLAG_BROKEN_ALTSTATUS      = BIT(26),
        /* serialize ports if DMA is possible (for sl82c105) */
-       IDE_HFLAG_SERIALIZE_DMA         = (1 << 27),
+       IDE_HFLAG_SERIALIZE_DMA         = BIT(27),
        /* force host out of "simplex" mode */
-       IDE_HFLAG_CLEAR_SIMPLEX         = (1 << 28),
+       IDE_HFLAG_CLEAR_SIMPLEX         = BIT(28),
        /* DSC overlap is unsupported */
-       IDE_HFLAG_NO_DSC                = (1 << 29),
+       IDE_HFLAG_NO_DSC                = BIT(29),
        /* never use 32-bit I/O ops */
-       IDE_HFLAG_NO_IO_32BIT           = (1 << 30),
+       IDE_HFLAG_NO_IO_32BIT           = BIT(30),
        /* never unmask IRQs */
-       IDE_HFLAG_NO_UNMASK_IRQS        = (1 << 31),
+       IDE_HFLAG_NO_UNMASK_IRQS        = BIT(31),
 };
 
 #ifdef CONFIG_BLK_DEV_OFFBOARD
@@ -1536,16 +1536,16 @@ struct ide_timing {
 };
 
 enum {
-       IDE_TIMING_SETUP        = (1 << 0),
-       IDE_TIMING_ACT8B        = (1 << 1),
-       IDE_TIMING_REC8B        = (1 << 2),
-       IDE_TIMING_CYC8B        = (1 << 3),
+       IDE_TIMING_SETUP        = BIT(0),
+       IDE_TIMING_ACT8B        = BIT(1),
+       IDE_TIMING_REC8B        = BIT(2),
+       IDE_TIMING_CYC8B        = BIT(3),
        IDE_TIMING_8BIT         = IDE_TIMING_ACT8B | IDE_TIMING_REC8B |
                                  IDE_TIMING_CYC8B,
-       IDE_TIMING_ACTIVE       = (1 << 4),
-       IDE_TIMING_RECOVER      = (1 << 5),
-       IDE_TIMING_CYCLE        = (1 << 6),
-       IDE_TIMING_UDMA         = (1 << 7),
+       IDE_TIMING_ACTIVE       = BIT(4),
+       IDE_TIMING_RECOVER      = BIT(5),
+       IDE_TIMING_CYCLE        = BIT(6),
+       IDE_TIMING_UDMA         = BIT(7),
        IDE_TIMING_ALL          = IDE_TIMING_SETUP | IDE_TIMING_8BIT |
                                  IDE_TIMING_ACTIVE | IDE_TIMING_RECOVER |
                                  IDE_TIMING_CYCLE | IDE_TIMING_UDMA,
diff --git a/include/linux/input/elan-i2c-ids.h b/include/linux/input/elan-i2c-ids.h
new file mode 100644 (file)
index 0000000..ceabb01
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Elan I2C/SMBus Touchpad device whitelist
+ *
+ * Copyright (c) 2013 ELAN Microelectronics Corp.
+ *
+ * Author: æ維 (Duson Lin) <dusonlin@emc.com.tw>
+ * Author: KT Liao <kt.liao@emc.com.tw>
+ * Version: 1.6.3
+ *
+ * Based on cyapa driver:
+ * copyright (c) 2011-2012 Cypress Semiconductor, Inc.
+ * copyright (c) 2011-2012 Google, 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.
+ *
+ * Trademarks are the property of their respective owners.
+ */
+
+#ifndef __ELAN_I2C_IDS_H
+#define __ELAN_I2C_IDS_H
+
+#include <linux/mod_devicetable.h>
+
+static const struct acpi_device_id elan_acpi_id[] = {
+       { "ELAN0000", 0 },
+       { "ELAN0100", 0 },
+       { "ELAN0600", 0 },
+       { "ELAN0601", 0 },
+       { "ELAN0602", 0 },
+       { "ELAN0603", 0 },
+       { "ELAN0604", 0 },
+       { "ELAN0605", 0 },
+       { "ELAN0606", 0 },
+       { "ELAN0607", 0 },
+       { "ELAN0608", 0 },
+       { "ELAN0609", 0 },
+       { "ELAN060B", 0 },
+       { "ELAN060C", 0 },
+       { "ELAN060F", 0 },
+       { "ELAN0610", 0 },
+       { "ELAN0611", 0 },
+       { "ELAN0612", 0 },
+       { "ELAN0615", 0 },
+       { "ELAN0616", 0 },
+       { "ELAN0617", 0 },
+       { "ELAN0618", 0 },
+       { "ELAN0619", 0 },
+       { "ELAN061A", 0 },
+       { "ELAN061B", 0 },
+       { "ELAN061C", 0 },
+       { "ELAN061D", 0 },
+       { "ELAN061E", 0 },
+       { "ELAN061F", 0 },
+       { "ELAN0620", 0 },
+       { "ELAN0621", 0 },
+       { "ELAN0622", 0 },
+       { "ELAN0623", 0 },
+       { "ELAN0624", 0 },
+       { "ELAN0625", 0 },
+       { "ELAN0626", 0 },
+       { "ELAN0627", 0 },
+       { "ELAN0628", 0 },
+       { "ELAN0629", 0 },
+       { "ELAN062A", 0 },
+       { "ELAN062B", 0 },
+       { "ELAN062C", 0 },
+       { "ELAN062D", 0 },
+       { "ELAN0631", 0 },
+       { "ELAN0632", 0 },
+       { "ELAN1000", 0 },
+       { }
+};
+
+#endif /* __ELAN_I2C_IDS_H */
index a61dc07..ac6aba6 100644 (file)
@@ -2,14 +2,43 @@
 #ifndef _LINUX_KASAN_CHECKS_H
 #define _LINUX_KASAN_CHECKS_H
 
-#if defined(__SANITIZE_ADDRESS__) || defined(__KASAN_INTERNAL)
-void kasan_check_read(const volatile void *p, unsigned int size);
-void kasan_check_write(const volatile void *p, unsigned int size);
+#include <linux/types.h>
+
+/*
+ * __kasan_check_*: Always available when KASAN is enabled. This may be used
+ * even in compilation units that selectively disable KASAN, but must use KASAN
+ * to validate access to an address.   Never use these in header files!
+ */
+#ifdef CONFIG_KASAN
+bool __kasan_check_read(const volatile void *p, unsigned int size);
+bool __kasan_check_write(const volatile void *p, unsigned int size);
+#else
+static inline bool __kasan_check_read(const volatile void *p, unsigned int size)
+{
+       return true;
+}
+static inline bool __kasan_check_write(const volatile void *p, unsigned int size)
+{
+       return true;
+}
+#endif
+
+/*
+ * kasan_check_*: Only available when the particular compilation unit has KASAN
+ * instrumentation enabled. May be used in header files.
+ */
+#ifdef __SANITIZE_ADDRESS__
+#define kasan_check_read __kasan_check_read
+#define kasan_check_write __kasan_check_write
 #else
-static inline void kasan_check_read(const volatile void *p, unsigned int size)
-{ }
-static inline void kasan_check_write(const volatile void *p, unsigned int size)
-{ }
+static inline bool kasan_check_read(const volatile void *p, unsigned int size)
+{
+       return true;
+}
+static inline bool kasan_check_write(const volatile void *p, unsigned int size)
+{
+       return true;
+}
 #endif
 
 #endif
index b40ea10..cc8a03c 100644 (file)
@@ -76,8 +76,11 @@ void kasan_free_shadow(const struct vm_struct *vm);
 int kasan_add_zero_shadow(void *start, unsigned long size);
 void kasan_remove_zero_shadow(void *start, unsigned long size);
 
-size_t ksize(const void *);
-static inline void kasan_unpoison_slab(const void *ptr) { ksize(ptr); }
+size_t __ksize(const void *);
+static inline void kasan_unpoison_slab(const void *ptr)
+{
+       kasan_unpoison_shadow(ptr, __ksize(ptr));
+}
 size_t kasan_metadata_size(struct kmem_cache *cache);
 
 bool kasan_save_enable_multi_shot(void);
index d1ad38a..c5da875 100644 (file)
@@ -159,7 +159,7 @@ static inline bool is_error_page(struct page *page)
 
 extern struct kmem_cache *kvm_vcpu_cache;
 
-extern spinlock_t kvm_lock;
+extern struct mutex kvm_lock;
 extern struct list_head vm_list;
 
 struct kvm_io_range {
@@ -867,7 +867,7 @@ int kvm_arch_hardware_enable(void);
 void kvm_arch_hardware_disable(void);
 int kvm_arch_hardware_setup(void);
 void kvm_arch_hardware_unsetup(void);
-void kvm_arch_check_processor_compat(void *rtn);
+int kvm_arch_check_processor_compat(void);
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu);
 bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu);
 int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu);
@@ -990,6 +990,7 @@ void kvm_unregister_irq_ack_notifier(struct kvm *kvm,
                                   struct kvm_irq_ack_notifier *kian);
 int kvm_request_irq_source_id(struct kvm *kvm);
 void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id);
+bool kvm_arch_irqfd_allowed(struct kvm *kvm, struct kvm_irqfd *args);
 
 /*
  * search_memslots() and __gfn_to_memslot() are here because they are
index eeba421..2734008 100644 (file)
@@ -35,7 +35,6 @@
  * @stack_node:        list node for klp_ops func_stack list
  * @old_size:  size of the old function
  * @new_size:  size of the new function
- * @kobj_added: @kobj has been added and needs freeing
  * @nop:        temporary patch to use the original code again; dyn. allocated
  * @patched:   the func has been added to the klp_ops list
  * @transition:        the func is currently being applied or reverted
@@ -113,7 +112,6 @@ struct klp_callbacks {
  * @node:      list node for klp_patch obj_list
  * @mod:       kernel module associated with the patched object
  *             (NULL for vmlinux)
- * @kobj_added: @kobj has been added and needs freeing
  * @dynamic:    temporary object for nop functions; dynamically allocated
  * @patched:   the object's funcs have been added to the klp_ops list
  */
@@ -140,7 +138,6 @@ struct klp_object {
  * @list:      list node for global list of actively used patches
  * @kobj:      kobject for sysfs resources
  * @obj_list:  dynamic list of the object entries
- * @kobj_added: @kobj has been added and needs freeing
  * @enabled:   the patch is enabled (but operation may be incomplete)
  * @forced:    was involved in a forced transition
  * @free_work: patch cleanup from workqueue-context
index 1dcb763..44c4146 100644 (file)
@@ -233,8 +233,9 @@ struct mem_cgroup {
        /* OOM-Killer disable */
        int             oom_kill_disable;
 
-       /* memory.events */
+       /* memory.events and memory.events.local */
        struct cgroup_file events_file;
+       struct cgroup_file events_local_file;
 
        /* handle for "memory.swap.events" */
        struct cgroup_file swap_events_file;
@@ -281,6 +282,7 @@ struct mem_cgroup {
 
        /* memory.events */
        atomic_long_t           memory_events[MEMCG_NR_MEMORY_EVENTS];
+       atomic_long_t           memory_events_local[MEMCG_NR_MEMORY_EVENTS];
 
        unsigned long           socket_pressure;
 
@@ -392,7 +394,6 @@ out:
 
 struct lruvec *mem_cgroup_page_lruvec(struct page *, struct pglist_data *);
 
-bool task_in_mem_cgroup(struct task_struct *task, struct mem_cgroup *memcg);
 struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p);
 
 struct mem_cgroup *get_mem_cgroup_from_mm(struct mm_struct *mm);
@@ -747,6 +748,9 @@ static inline void count_memcg_event_mm(struct mm_struct *mm,
 static inline void memcg_memory_event(struct mem_cgroup *memcg,
                                      enum memcg_memory_event event)
 {
+       atomic_long_inc(&memcg->memory_events_local[event]);
+       cgroup_file_notify(&memcg->events_local_file);
+
        do {
                atomic_long_inc(&memcg->memory_events[event]);
                cgroup_file_notify(&memcg->events_file);
@@ -870,12 +874,6 @@ static inline bool mm_match_cgroup(struct mm_struct *mm,
        return true;
 }
 
-static inline bool task_in_mem_cgroup(struct task_struct *task,
-                                     const struct mem_cgroup *memcg)
-{
-       return true;
-}
-
 static inline struct mem_cgroup *get_mem_cgroup_from_mm(struct mm_struct *mm)
 {
        return NULL;
@@ -1273,6 +1271,8 @@ int __memcg_kmem_charge(struct page *page, gfp_t gfp, int order);
 void __memcg_kmem_uncharge(struct page *page, int order);
 int __memcg_kmem_charge_memcg(struct page *page, gfp_t gfp, int order,
                              struct mem_cgroup *memcg);
+void __memcg_kmem_uncharge_memcg(struct mem_cgroup *memcg,
+                                unsigned int nr_pages);
 
 extern struct static_key_false memcg_kmem_enabled_key;
 extern struct workqueue_struct *memcg_kmem_cache_wq;
@@ -1314,6 +1314,14 @@ static inline int memcg_kmem_charge_memcg(struct page *page, gfp_t gfp,
                return __memcg_kmem_charge_memcg(page, gfp, order, memcg);
        return 0;
 }
+
+static inline void memcg_kmem_uncharge_memcg(struct page *page, int order,
+                                            struct mem_cgroup *memcg)
+{
+       if (memcg_kmem_enabled())
+               __memcg_kmem_uncharge_memcg(memcg, 1 << order);
+}
+
 /*
  * helper for accessing a memcg's index. It will be used as an index in the
  * child cache array in kmem_cache, and also to derive its name. This function
index 5ddca44..45aba26 100644 (file)
@@ -155,6 +155,7 @@ struct cros_ec_device {
        struct ec_response_get_next_event_v1 event_data;
        int event_size;
        u32 host_event_wake_mask;
+       u32 last_resume_result;
 };
 
 /**
index 114614e..7ccb875 100644 (file)
@@ -4,17 +4,20 @@
  *
  * Copyright (C) 2012 Google, Inc
  *
- * The ChromeOS EC multi function device is used to mux all the requests
- * to the EC device for its multiple features: keyboard controller,
- * battery charging and regulator control, firmware update.
- *
- * NOTE: This file is copied verbatim from the ChromeOS EC Open Source
- * project in an attempt to make future updates easy to make.
+ * NOTE: This file is auto-generated from ChromeOS EC Open Source code from
+ * https://chromium.googlesource.com/chromiumos/platform/ec/+/master/include/ec_commands.h
  */
 
+/* Host communication command constants for Chrome EC */
+
 #ifndef __CROS_EC_COMMANDS_H
 #define __CROS_EC_COMMANDS_H
 
+
+
+
+#define BUILD_ASSERT(_cond)
+
 /*
  * Current version of this protocol
  *
@@ -25,7 +28,7 @@
 #define EC_PROTO_VERSION          0x00000002
 
 /* Command version mask */
-#define EC_VER_MASK(version) (1UL << (version))
+#define EC_VER_MASK(version) BIT(version)
 
 /* I/O addresses for ACPI commands */
 #define EC_LPC_ADDR_ACPI_DATA  0x62
 /* Protocol version 2 */
 #define EC_LPC_ADDR_HOST_ARGS    0x800  /* And 0x801, 0x802, 0x803 */
 #define EC_LPC_ADDR_HOST_PARAM   0x804  /* For version 2 params; size is
-                                        * EC_PROTO2_MAX_PARAM_SIZE */
+                                        * EC_PROTO2_MAX_PARAM_SIZE
+                                        */
 /* Protocol version 3 */
 #define EC_LPC_ADDR_HOST_PACKET  0x800  /* Offset of version 3 packet */
 #define EC_LPC_HOST_PACKET_SIZE  0x100  /* Max size of version 3 packet */
 
-/* The actual block is 0x800-0x8ff, but some BIOSes think it's 0x880-0x8ff
- * and they tell the kernel that so we have to think of it as two parts. */
+/*
+ * The actual block is 0x800-0x8ff, but some BIOSes think it's 0x880-0x8ff
+ * and they tell the kernel that so we have to think of it as two parts.
+ */
 #define EC_HOST_CMD_REGION0    0x800
 #define EC_HOST_CMD_REGION1    0x880
 #define EC_HOST_CMD_REGION_SIZE 0x80
 
 /* EC command register bit functions */
-#define EC_LPC_CMDR_DATA       (1 << 0)  /* Data ready for host to read */
-#define EC_LPC_CMDR_PENDING    (1 << 1)  /* Write pending to EC */
-#define EC_LPC_CMDR_BUSY       (1 << 2)  /* EC is busy processing a command */
-#define EC_LPC_CMDR_CMD                (1 << 3)  /* Last host write was a command */
-#define EC_LPC_CMDR_ACPI_BRST  (1 << 4)  /* Burst mode (not used) */
-#define EC_LPC_CMDR_SCI                (1 << 5)  /* SCI event is pending */
-#define EC_LPC_CMDR_SMI                (1 << 6)  /* SMI event is pending */
+#define EC_LPC_CMDR_DATA       BIT(0)  /* Data ready for host to read */
+#define EC_LPC_CMDR_PENDING    BIT(1)  /* Write pending to EC */
+#define EC_LPC_CMDR_BUSY       BIT(2)  /* EC is busy processing a command */
+#define EC_LPC_CMDR_CMD                BIT(3)  /* Last host write was a command */
+#define EC_LPC_CMDR_ACPI_BRST  BIT(4)  /* Burst mode (not used) */
+#define EC_LPC_CMDR_SCI                BIT(5)  /* SCI event is pending */
+#define EC_LPC_CMDR_SMI                BIT(6)  /* SMI event is pending */
 
 #define EC_LPC_ADDR_MEMMAP       0x900
 #define EC_MEMMAP_SIZE         255 /* ACPI IO buffer max is 255 bytes */
 /* Unused 0x28 - 0x2f */
 #define EC_MEMMAP_SWITCHES         0x30        /* 8 bits */
 /* Unused 0x31 - 0x33 */
-#define EC_MEMMAP_HOST_EVENTS      0x34 /* 32 bits */
-/* Reserve 0x38 - 0x3f for additional host event-related stuff */
-/* Battery values are all 32 bits */
+#define EC_MEMMAP_HOST_EVENTS      0x34 /* 64 bits */
+/* Battery values are all 32 bits, unless otherwise noted. */
 #define EC_MEMMAP_BATT_VOLT        0x40 /* Battery Present Voltage */
 #define EC_MEMMAP_BATT_RATE        0x44 /* Battery Present Rate */
 #define EC_MEMMAP_BATT_CAP         0x48 /* Battery Remaining Capacity */
-#define EC_MEMMAP_BATT_FLAG        0x4c /* Battery State, defined below */
+#define EC_MEMMAP_BATT_FLAG        0x4c /* Battery State, see below (8-bit) */
+#define EC_MEMMAP_BATT_COUNT       0x4d /* Battery Count (8-bit) */
+#define EC_MEMMAP_BATT_INDEX       0x4e /* Current Battery Data Index (8-bit) */
+/* Unused 0x4f */
 #define EC_MEMMAP_BATT_DCAP        0x50 /* Battery Design Capacity */
 #define EC_MEMMAP_BATT_DVLT        0x54 /* Battery Design Voltage */
 #define EC_MEMMAP_BATT_LFCC        0x58 /* Battery Last Full Charge Capacity */
 /* Unused 0x84 - 0x8f */
 #define EC_MEMMAP_ACC_STATUS       0x90 /* Accelerometer status (8 bits )*/
 /* Unused 0x91 */
-#define EC_MEMMAP_ACC_DATA         0x92 /* Accelerometer data 0x92 - 0x9f */
+#define EC_MEMMAP_ACC_DATA         0x92 /* Accelerometers data 0x92 - 0x9f */
+/* 0x92: Lid Angle if available, LID_ANGLE_UNRELIABLE otherwise */
+/* 0x94 - 0x99: 1st Accelerometer */
+/* 0x9a - 0x9f: 2nd Accelerometer */
 #define EC_MEMMAP_GYRO_DATA        0xa0 /* Gyroscope data 0xa0 - 0xa5 */
-/* Unused 0xa6 - 0xfe (remember, 0xff is NOT part of the memmap region) */
+/* Unused 0xa6 - 0xdf */
 
+/*
+ * ACPI is unable to access memory mapped data at or above this offset due to
+ * limitations of the ACPI protocol. Do not place data in the range 0xe0 - 0xfe
+ * which might be needed by ACPI.
+ */
+#define EC_MEMMAP_NO_ACPI 0xe0
 
 /* Define the format of the accelerometer mapped memory status byte. */
 #define EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK  0x0f
-#define EC_MEMMAP_ACC_STATUS_BUSY_BIT        (1 << 4)
-#define EC_MEMMAP_ACC_STATUS_PRESENCE_BIT    (1 << 7)
+#define EC_MEMMAP_ACC_STATUS_BUSY_BIT        BIT(4)
+#define EC_MEMMAP_ACC_STATUS_PRESENCE_BIT    BIT(7)
 
 /* Number of temp sensors at EC_MEMMAP_TEMP_SENSOR */
 #define EC_TEMP_SENSOR_ENTRIES     16
 #define EC_BATT_FLAG_DISCHARGING  0x04
 #define EC_BATT_FLAG_CHARGING     0x08
 #define EC_BATT_FLAG_LEVEL_CRITICAL 0x10
+/* Set if some of the static/dynamic data is invalid (or outdated). */
+#define EC_BATT_FLAG_INVALID_DATA 0x20
 
 /* Switch flags at EC_MEMMAP_SWITCHES */
 #define EC_SWITCH_LID_OPEN               0x01
 #define EC_WIRELESS_SWITCH_WWAN       0x04  /* WWAN power */
 #define EC_WIRELESS_SWITCH_WLAN_POWER 0x08  /* WLAN power */
 
+/*****************************************************************************/
+/*
+ * ACPI commands
+ *
+ * These are valid ONLY on the ACPI command/data port.
+ */
+
+/*
+ * ACPI Read Embedded Controller
+ *
+ * This reads from ACPI memory space on the EC (EC_ACPI_MEM_*).
+ *
+ * Use the following sequence:
+ *
+ *    - Write EC_CMD_ACPI_READ to EC_LPC_ADDR_ACPI_CMD
+ *    - Wait for EC_LPC_CMDR_PENDING bit to clear
+ *    - Write address to EC_LPC_ADDR_ACPI_DATA
+ *    - Wait for EC_LPC_CMDR_DATA bit to set
+ *    - Read value from EC_LPC_ADDR_ACPI_DATA
+ */
+#define EC_CMD_ACPI_READ 0x0080
+
+/*
+ * ACPI Write Embedded Controller
+ *
+ * This reads from ACPI memory space on the EC (EC_ACPI_MEM_*).
+ *
+ * Use the following sequence:
+ *
+ *    - Write EC_CMD_ACPI_WRITE to EC_LPC_ADDR_ACPI_CMD
+ *    - Wait for EC_LPC_CMDR_PENDING bit to clear
+ *    - Write address to EC_LPC_ADDR_ACPI_DATA
+ *    - Wait for EC_LPC_CMDR_PENDING bit to clear
+ *    - Write value to EC_LPC_ADDR_ACPI_DATA
+ */
+#define EC_CMD_ACPI_WRITE 0x0081
+
+/*
+ * ACPI Burst Enable Embedded Controller
+ *
+ * This enables burst mode on the EC to allow the host to issue several
+ * commands back-to-back. While in this mode, writes to mapped multi-byte
+ * data are locked out to ensure data consistency.
+ */
+#define EC_CMD_ACPI_BURST_ENABLE 0x0082
+
+/*
+ * ACPI Burst Disable Embedded Controller
+ *
+ * This disables burst mode on the EC and stops preventing EC writes to mapped
+ * multi-byte data.
+ */
+#define EC_CMD_ACPI_BURST_DISABLE 0x0083
+
+/*
+ * ACPI Query Embedded Controller
+ *
+ * This clears the lowest-order bit in the currently pending host events, and
+ * sets the result code to the 1-based index of the bit (event 0x00000001 = 1,
+ * event 0x80000000 = 32), or 0 if no event was pending.
+ */
+#define EC_CMD_ACPI_QUERY_EVENT 0x0084
+
+/* Valid addresses in ACPI memory space, for read/write commands */
+
+/* Memory space version; set to EC_ACPI_MEM_VERSION_CURRENT */
+#define EC_ACPI_MEM_VERSION            0x00
+/*
+ * Test location; writing value here updates test compliment byte to (0xff -
+ * value).
+ */
+#define EC_ACPI_MEM_TEST               0x01
+/* Test compliment; writes here are ignored. */
+#define EC_ACPI_MEM_TEST_COMPLIMENT    0x02
+
+/* Keyboard backlight brightness percent (0 - 100) */
+#define EC_ACPI_MEM_KEYBOARD_BACKLIGHT 0x03
+/* DPTF Target Fan Duty (0-100, 0xff for auto/none) */
+#define EC_ACPI_MEM_FAN_DUTY           0x04
+
+/*
+ * DPTF temp thresholds. Any of the EC's temp sensors can have up to two
+ * independent thresholds attached to them. The current value of the ID
+ * register determines which sensor is affected by the THRESHOLD and COMMIT
+ * registers. The THRESHOLD register uses the same EC_TEMP_SENSOR_OFFSET scheme
+ * as the memory-mapped sensors. The COMMIT register applies those settings.
+ *
+ * The spec does not mandate any way to read back the threshold settings
+ * themselves, but when a threshold is crossed the AP needs a way to determine
+ * which sensor(s) are responsible. Each reading of the ID register clears and
+ * returns one sensor ID that has crossed one of its threshold (in either
+ * direction) since the last read. A value of 0xFF means "no new thresholds
+ * have tripped". Setting or enabling the thresholds for a sensor will clear
+ * the unread event count for that sensor.
+ */
+#define EC_ACPI_MEM_TEMP_ID            0x05
+#define EC_ACPI_MEM_TEMP_THRESHOLD     0x06
+#define EC_ACPI_MEM_TEMP_COMMIT        0x07
+/*
+ * Here are the bits for the COMMIT register:
+ *   bit 0 selects the threshold index for the chosen sensor (0/1)
+ *   bit 1 enables/disables the selected threshold (0 = off, 1 = on)
+ * Each write to the commit register affects one threshold.
+ */
+#define EC_ACPI_MEM_TEMP_COMMIT_SELECT_MASK BIT(0)
+#define EC_ACPI_MEM_TEMP_COMMIT_ENABLE_MASK BIT(1)
+/*
+ * Example:
+ *
+ * Set the thresholds for sensor 2 to 50 C and 60 C:
+ *   write 2 to [0x05]      --  select temp sensor 2
+ *   write 0x7b to [0x06]   --  C_TO_K(50) - EC_TEMP_SENSOR_OFFSET
+ *   write 0x2 to [0x07]    --  enable threshold 0 with this value
+ *   write 0x85 to [0x06]   --  C_TO_K(60) - EC_TEMP_SENSOR_OFFSET
+ *   write 0x3 to [0x07]    --  enable threshold 1 with this value
+ *
+ * Disable the 60 C threshold, leaving the 50 C threshold unchanged:
+ *   write 2 to [0x05]      --  select temp sensor 2
+ *   write 0x1 to [0x07]    --  disable threshold 1
+ */
+
+/* DPTF battery charging current limit */
+#define EC_ACPI_MEM_CHARGING_LIMIT     0x08
+
+/* Charging limit is specified in 64 mA steps */
+#define EC_ACPI_MEM_CHARGING_LIMIT_STEP_MA   64
+/* Value to disable DPTF battery charging limit */
+#define EC_ACPI_MEM_CHARGING_LIMIT_DISABLED  0xff
+
+/*
+ * Report device orientation
+ *  Bits       Definition
+ *  3:1        Device DPTF Profile Number (DDPN)
+ *               0   = Reserved for backward compatibility (indicates no valid
+ *                     profile number. Host should fall back to using TBMD).
+ *              1..7 = DPTF Profile number to indicate to host which table needs
+ *                     to be loaded.
+ *   0         Tablet Mode Device Indicator (TBMD)
+ */
+#define EC_ACPI_MEM_DEVICE_ORIENTATION 0x09
+#define EC_ACPI_MEM_TBMD_SHIFT         0
+#define EC_ACPI_MEM_TBMD_MASK          0x1
+#define EC_ACPI_MEM_DDPN_SHIFT         1
+#define EC_ACPI_MEM_DDPN_MASK          0x7
+
+/*
+ * Report device features. Uses the same format as the host command, except:
+ *
+ * bit 0 (EC_FEATURE_LIMITED) changes meaning from "EC code has a limited set
+ * of features", which is of limited interest when the system is already
+ * interpreting ACPI bytecode, to "EC_FEATURES[0-7] is not supported". Since
+ * these are supported, it defaults to 0.
+ * This allows detecting the presence of this field since older versions of
+ * the EC codebase would simply return 0xff to that unknown address. Check
+ * FEATURES0 != 0xff (or FEATURES0[0] == 0) to make sure that the other bits
+ * are valid.
+ */
+#define EC_ACPI_MEM_DEVICE_FEATURES0 0x0a
+#define EC_ACPI_MEM_DEVICE_FEATURES1 0x0b
+#define EC_ACPI_MEM_DEVICE_FEATURES2 0x0c
+#define EC_ACPI_MEM_DEVICE_FEATURES3 0x0d
+#define EC_ACPI_MEM_DEVICE_FEATURES4 0x0e
+#define EC_ACPI_MEM_DEVICE_FEATURES5 0x0f
+#define EC_ACPI_MEM_DEVICE_FEATURES6 0x10
+#define EC_ACPI_MEM_DEVICE_FEATURES7 0x11
+
+#define EC_ACPI_MEM_BATTERY_INDEX    0x12
+
+/*
+ * USB Port Power. Each bit indicates whether the corresponding USB ports' power
+ * is enabled (1) or disabled (0).
+ *   bit 0 USB port ID 0
+ *   ...
+ *   bit 7 USB port ID 7
+ */
+#define EC_ACPI_MEM_USB_PORT_POWER 0x13
+
+/*
+ * ACPI addresses 0x20 - 0xff map to EC_MEMMAP offset 0x00 - 0xdf.  This data
+ * is read-only from the AP.  Added in EC_ACPI_MEM_VERSION 2.
+ */
+#define EC_ACPI_MEM_MAPPED_BEGIN   0x20
+#define EC_ACPI_MEM_MAPPED_SIZE    0xe0
+
+/* Current version of ACPI memory address space */
+#define EC_ACPI_MEM_VERSION_CURRENT 2
+
+
 /*
  * This header file is used in coreboot both in C and ACPI code.  The ACPI code
  * is pre-processed to handle constants but the ASL compiler is unable to
  * handle actual C code so keep it separate.
  */
-#ifndef __ACPI__
+
+
+/*
+ * Attributes for EC request and response packets.  Just defining __packed
+ * results in inefficient assembly code on ARM, if the structure is actually
+ * 32-bit aligned, as it should be for all buffers.
+ *
+ * Be very careful when adding these to existing structures.  They will round
+ * up the structure size to the specified boundary.
+ *
+ * Also be very careful to make that if a structure is included in some other
+ * parent structure that the alignment will still be true given the packing of
+ * the parent structure.  This is particularly important if the sub-structure
+ * will be passed as a pointer to another function, since that function will
+ * not know about the misaligment caused by the parent structure's packing.
+ *
+ * Also be very careful using __packed - particularly when nesting non-packed
+ * structures inside packed ones.  In fact, DO NOT use __packed directly;
+ * always use one of these attributes.
+ *
+ * Once everything is annotated properly, the following search strings should
+ * not return ANY matches in this file other than right here:
+ *
+ * "__packed" - generates inefficient code; all sub-structs must also be packed
+ *
+ * "struct [^_]" - all structs should be annotated, except for structs that are
+ * members of other structs/unions (and their original declarations should be
+ * annotated).
+ */
 
 /*
- * Define __packed if someone hasn't beat us to it.  Linux kernel style
- * checking prefers __packed over __attribute__((packed)).
+ * Packed structures make no assumption about alignment, so they do inefficient
+ * byte-wise reads.
  */
-#ifndef __packed
-#define __packed __attribute__((packed))
-#endif
+#define __ec_align1 __packed
+#define __ec_align2 __packed
+#define __ec_align4 __packed
+#define __ec_align_size1 __packed
+#define __ec_align_offset1 __packed
+#define __ec_align_offset2 __packed
+#define __ec_todo_packed __packed
+#define __ec_todo_unpacked
+
 
 /* LPC command status byte masks */
 /* EC has written a byte in the data register and host hasn't read it yet */
 #define EC_LPC_STATUS_PROCESSING  0x04
 /* Last write to EC was a command, not data */
 #define EC_LPC_STATUS_LAST_CMD    0x08
-/* EC is in burst mode.  Unsupported by Chrome EC, so this bit is never set */
+/* EC is in burst mode */
 #define EC_LPC_STATUS_BURST_MODE  0x10
 /* SCI event is pending (requesting SCI query) */
 #define EC_LPC_STATUS_SCI_PENDING 0x20
 #define EC_LPC_STATUS_BUSY_MASK \
        (EC_LPC_STATUS_FROM_HOST | EC_LPC_STATUS_PROCESSING)
 
-/* Host command response codes */
+/*
+ * Host command response codes (16-bit).  Note that response codes should be
+ * stored in a uint16_t rather than directly in a value of this type.
+ */
 enum ec_status {
        EC_RES_SUCCESS = 0,
        EC_RES_INVALID_COMMAND = 1,
@@ -230,7 +474,13 @@ enum ec_status {
        EC_RES_OVERFLOW = 11,           /* Table / data overflow */
        EC_RES_INVALID_HEADER = 12,     /* Header contains invalid data */
        EC_RES_REQUEST_TRUNCATED = 13,  /* Didn't get the entire request */
-       EC_RES_RESPONSE_TOO_BIG = 14    /* Response was too big to handle */
+       EC_RES_RESPONSE_TOO_BIG = 14,   /* Response was too big to handle */
+       EC_RES_BUS_ERROR = 15,          /* Communications bus error */
+       EC_RES_BUSY = 16,               /* Up but too busy.  Should retry */
+       EC_RES_INVALID_HEADER_VERSION = 17,  /* Header version invalid */
+       EC_RES_INVALID_HEADER_CRC = 18,      /* Header CRC invalid */
+       EC_RES_INVALID_DATA_CRC = 19,        /* Data CRC invalid */
+       EC_RES_DUP_UNAVAILABLE = 20,         /* Can't resend response */
 };
 
 /*
@@ -250,7 +500,8 @@ enum host_event_code {
        EC_HOST_EVENT_BATTERY_CRITICAL = 7,
        EC_HOST_EVENT_BATTERY = 8,
        EC_HOST_EVENT_THERMAL_THRESHOLD = 9,
-       EC_HOST_EVENT_THERMAL_OVERLOAD = 10,
+       /* Event generated by a device attached to the EC */
+       EC_HOST_EVENT_DEVICE = 10,
        EC_HOST_EVENT_THERMAL = 11,
        EC_HOST_EVENT_USB_CHARGER = 12,
        EC_HOST_EVENT_KEY_PRESSED = 13,
@@ -277,15 +528,34 @@ enum host_event_code {
        EC_HOST_EVENT_HANG_DETECT = 20,
        /* Hang detect logic detected a hang and warm rebooted the AP */
        EC_HOST_EVENT_HANG_REBOOT = 21,
+
        /* PD MCU triggering host event */
        EC_HOST_EVENT_PD_MCU = 22,
 
-       /* EC desires to change state of host-controlled USB mux */
-       EC_HOST_EVENT_USB_MUX = 28,
+       /* Battery Status flags have changed */
+       EC_HOST_EVENT_BATTERY_STATUS = 23,
+
+       /* EC encountered a panic, triggering a reset */
+       EC_HOST_EVENT_PANIC = 24,
+
+       /* Keyboard fastboot combo has been pressed */
+       EC_HOST_EVENT_KEYBOARD_FASTBOOT = 25,
 
        /* EC RTC event occurred */
        EC_HOST_EVENT_RTC = 26,
 
+       /* Emulate MKBP event */
+       EC_HOST_EVENT_MKBP = 27,
+
+       /* EC desires to change state of host-controlled USB mux */
+       EC_HOST_EVENT_USB_MUX = 28,
+
+       /* TABLET/LAPTOP mode or detachable base attach/detach event */
+       EC_HOST_EVENT_MODE_CHANGE = 29,
+
+       /* Keyboard recovery combo with hardware reinitialization */
+       EC_HOST_EVENT_KEYBOARD_RECOVERY_HW_REINIT = 30,
+
        /*
         * The high bit of the event mask is not used as a host event code.  If
         * it reads back as set, then the entire event mask should be
@@ -296,7 +566,7 @@ enum host_event_code {
        EC_HOST_EVENT_INVALID = 32
 };
 /* Host event mask */
-#define EC_HOST_EVENT_MASK(event_code) (1UL << ((event_code) - 1))
+#define EC_HOST_EVENT_MASK(event_code) BIT_ULL((event_code) - 1)
 
 /**
  * struct ec_lpc_host_args - Arguments at EC_LPC_ADDR_HOST_ARGS
@@ -311,7 +581,7 @@ struct ec_lpc_host_args {
        uint8_t command_version;
        uint8_t data_size;
        uint8_t checksum;
-} __packed;
+} __ec_align4;
 
 /* Flags for ec_lpc_host_args.flags */
 /*
@@ -321,7 +591,7 @@ struct ec_lpc_host_args {
  * If EC gets a command and this flag is not set, this is an old-style command.
  * Command version is 0 and params from host are at EC_LPC_ADDR_OLD_PARAM with
  * unknown length.  EC must respond with an old-style response (that is,
- * withouth setting EC_HOST_ARGS_FLAG_TO_HOST).
+ * without setting EC_HOST_ARGS_FLAG_TO_HOST).
  */
 #define EC_HOST_ARGS_FLAG_FROM_HOST 0x01
 /*
@@ -482,7 +752,7 @@ struct ec_host_request {
        uint8_t command_version;
        uint8_t reserved;
        uint16_t data_len;
-} __packed;
+} __ec_align4;
 
 #define EC_HOST_RESPONSE_VERSION 3
 
@@ -501,18 +771,151 @@ struct ec_host_response {
        uint16_t result;
        uint16_t data_len;
        uint16_t reserved;
-} __packed;
+} __ec_align4;
+
+/*****************************************************************************/
+
+/*
+ * Host command protocol V4.
+ *
+ * Packets always start with a request or response header.  They are followed
+ * by data_len bytes of data.  If the data_crc_present flag is set, the data
+ * bytes are followed by a CRC-8 of that data, using using x^8 + x^2 + x + 1
+ * polynomial.
+ *
+ * Host algorithm when sending a request q:
+ *
+ * 101) tries_left=(some value, e.g. 3);
+ * 102) q.seq_num++
+ * 103) q.seq_dup=0
+ * 104) Calculate q.header_crc.
+ * 105) Send request q to EC.
+ * 106) Wait for response r.  Go to 201 if received or 301 if timeout.
+ *
+ * 201) If r.struct_version != 4, go to 301.
+ * 202) If r.header_crc mismatches calculated CRC for r header, go to 301.
+ * 203) If r.data_crc_present and r.data_crc mismatches, go to 301.
+ * 204) If r.seq_num != q.seq_num, go to 301.
+ * 205) If r.seq_dup == q.seq_dup, return success.
+ * 207) If r.seq_dup == 1, go to 301.
+ * 208) Return error.
+ *
+ * 301) If --tries_left <= 0, return error.
+ * 302) If q.seq_dup == 1, go to 105.
+ * 303) q.seq_dup = 1
+ * 304) Go to 104.
+ *
+ * EC algorithm when receiving a request q.
+ * EC has response buffer r, error buffer e.
+ *
+ * 101) If q.struct_version != 4, set e.result = EC_RES_INVALID_HEADER_VERSION
+ *      and go to 301
+ * 102) If q.header_crc mismatches calculated CRC, set e.result =
+ *      EC_RES_INVALID_HEADER_CRC and go to 301
+ * 103) If q.data_crc_present, calculate data CRC.  If that mismatches the CRC
+ *      byte at the end of the packet, set e.result = EC_RES_INVALID_DATA_CRC
+ *      and go to 301.
+ * 104) If q.seq_dup == 0, go to 201.
+ * 105) If q.seq_num != r.seq_num, go to 201.
+ * 106) If q.seq_dup == r.seq_dup, go to 205, else go to 203.
+ *
+ * 201) Process request q into response r.
+ * 202) r.seq_num = q.seq_num
+ * 203) r.seq_dup = q.seq_dup
+ * 204) Calculate r.header_crc
+ * 205) If r.data_len > 0 and data is no longer available, set e.result =
+ *      EC_RES_DUP_UNAVAILABLE and go to 301.
+ * 206) Send response r.
+ *
+ * 301) e.seq_num = q.seq_num
+ * 302) e.seq_dup = q.seq_dup
+ * 303) Calculate e.header_crc.
+ * 304) Send error response e.
+ */
+
+/* Version 4 request from host */
+struct ec_host_request4 {
+       /*
+        * bits 0-3: struct_version: Structure version (=4)
+        * bit    4: is_response: Is response (=0)
+        * bits 5-6: seq_num: Sequence number
+        * bit    7: seq_dup: Sequence duplicate flag
+        */
+       uint8_t fields0;
+
+       /*
+        * bits 0-4: command_version: Command version
+        * bits 5-6: Reserved (set 0, ignore on read)
+        * bit    7: data_crc_present: Is data CRC present after data
+        */
+       uint8_t fields1;
+
+       /* Command code (EC_CMD_*) */
+       uint16_t command;
+
+       /* Length of data which follows this header (not including data CRC) */
+       uint16_t data_len;
+
+       /* Reserved (set 0, ignore on read) */
+       uint8_t reserved;
+
+       /* CRC-8 of above fields, using x^8 + x^2 + x + 1 polynomial */
+       uint8_t header_crc;
+} __ec_align4;
+
+/* Version 4 response from EC */
+struct ec_host_response4 {
+       /*
+        * bits 0-3: struct_version: Structure version (=4)
+        * bit    4: is_response: Is response (=1)
+        * bits 5-6: seq_num: Sequence number
+        * bit    7: seq_dup: Sequence duplicate flag
+        */
+       uint8_t fields0;
+
+       /*
+        * bits 0-6: Reserved (set 0, ignore on read)
+        * bit    7: data_crc_present: Is data CRC present after data
+        */
+       uint8_t fields1;
+
+       /* Result code (EC_RES_*) */
+       uint16_t result;
+
+       /* Length of data which follows this header (not including data CRC) */
+       uint16_t data_len;
+
+       /* Reserved (set 0, ignore on read) */
+       uint8_t reserved;
+
+       /* CRC-8 of above fields, using x^8 + x^2 + x + 1 polynomial */
+       uint8_t header_crc;
+} __ec_align4;
+
+/* Fields in fields0 byte */
+#define EC_PACKET4_0_STRUCT_VERSION_MASK       0x0f
+#define EC_PACKET4_0_IS_RESPONSE_MASK          0x10
+#define EC_PACKET4_0_SEQ_NUM_SHIFT             5
+#define EC_PACKET4_0_SEQ_NUM_MASK              0x60
+#define EC_PACKET4_0_SEQ_DUP_MASK              0x80
+
+/* Fields in fields1 byte */
+#define EC_PACKET4_1_COMMAND_VERSION_MASK      0x1f  /* (request only) */
+#define EC_PACKET4_1_DATA_CRC_PRESENT_MASK     0x80
 
 /*****************************************************************************/
 /*
  * Notes on commands:
  *
  * Each command is an 16-bit command value.  Commands which take params or
- * return response data specify structs for that data.  If no struct is
+ * return response data specify structures for that data.  If no structure is
  * specified, the command does not input or output data, respectively.
  * Parameter/response length is implicit in the structs.  Some underlying
  * communication protocols (I2C, SPI) may add length or checksum headers, but
  * those are implementation-dependent and not defined here.
+ *
+ * All commands MUST be #defined to be 4-digit UPPER CASE hex values
+ * (e.g., 0x00AB, not 0xab) for CONFIG_HOSTCMD_SECTION_SORTED to work.
  */
 
 /*****************************************************************************/
@@ -522,7 +925,7 @@ struct ec_host_response {
  * Get protocol version, used to deal with non-backward compatible protocol
  * changes.
  */
-#define EC_CMD_PROTO_VERSION 0x00
+#define EC_CMD_PROTO_VERSION 0x0000
 
 /**
  * struct ec_response_proto_version - Response to the proto version command.
@@ -530,13 +933,13 @@ struct ec_host_response {
  */
 struct ec_response_proto_version {
        uint32_t version;
-} __packed;
+} __ec_align4;
 
 /*
  * Hello.  This is a simple command to test the EC is responsive to
  * commands.
  */
-#define EC_CMD_HELLO 0x01
+#define EC_CMD_HELLO 0x0001
 
 /**
  * struct ec_params_hello - Parameters to the hello command.
@@ -544,7 +947,7 @@ struct ec_response_proto_version {
  */
 struct ec_params_hello {
        uint32_t in_data;
-} __packed;
+} __ec_align4;
 
 /**
  * struct ec_response_hello - Response to the hello command.
@@ -552,10 +955,10 @@ struct ec_params_hello {
  */
 struct ec_response_hello {
        uint32_t out_data;
-} __packed;
+} __ec_align4;
 
 /* Get version number */
-#define EC_CMD_GET_VERSION 0x02
+#define EC_CMD_GET_VERSION 0x0002
 
 enum ec_current_image {
        EC_IMAGE_UNKNOWN = 0,
@@ -575,10 +978,10 @@ struct ec_response_get_version {
        char version_string_rw[32];
        char reserved[32];
        uint32_t current_image;
-} __packed;
+} __ec_align4;
 
 /* Read test */
-#define EC_CMD_READ_TEST 0x03
+#define EC_CMD_READ_TEST 0x0003
 
 /**
  * struct ec_params_read_test - Parameters for the read test command.
@@ -588,7 +991,7 @@ struct ec_response_get_version {
 struct ec_params_read_test {
        uint32_t offset;
        uint32_t size;
-} __packed;
+} __ec_align4;
 
 /**
  * struct ec_response_read_test - Response to the read test command.
@@ -596,17 +999,17 @@ struct ec_params_read_test {
  */
 struct ec_response_read_test {
        uint32_t data[32];
-} __packed;
+} __ec_align4;
 
 /*
  * Get build information
  *
  * Response is null-terminated string.
  */
-#define EC_CMD_GET_BUILD_INFO 0x04
+#define EC_CMD_GET_BUILD_INFO 0x0004
 
 /* Get chip info */
-#define EC_CMD_GET_CHIP_INFO 0x05
+#define EC_CMD_GET_CHIP_INFO 0x0005
 
 /**
  * struct ec_response_get_chip_info - Response to the get chip info command.
@@ -618,10 +1021,10 @@ struct ec_response_get_chip_info {
        char vendor[32];
        char name[32];
        char revision[32];
-} __packed;
+} __ec_align4;
 
 /* Get board HW version */
-#define EC_CMD_GET_BOARD_VERSION 0x06
+#define EC_CMD_GET_BOARD_VERSION 0x0006
 
 /**
  * struct ec_response_board_version - Response to the board version command.
@@ -629,7 +1032,7 @@ struct ec_response_get_chip_info {
  */
 struct ec_response_board_version {
        uint16_t board_version;
-} __packed;
+} __ec_align2;
 
 /*
  * Read memory-mapped data.
@@ -639,7 +1042,7 @@ struct ec_response_board_version {
  *
  * Response is params.size bytes of data.
  */
-#define EC_CMD_READ_MEMMAP 0x07
+#define EC_CMD_READ_MEMMAP 0x0007
 
 /**
  * struct ec_params_read_memmap - Parameters for the read memory map command.
@@ -649,10 +1052,10 @@ struct ec_response_board_version {
 struct ec_params_read_memmap {
        uint8_t offset;
        uint8_t size;
-} __packed;
+} __ec_align1;
 
 /* Read versions supported for a command */
-#define EC_CMD_GET_CMD_VERSIONS 0x08
+#define EC_CMD_GET_CMD_VERSIONS 0x0008
 
 /**
  * struct ec_params_get_cmd_versions - Parameters for the get command versions.
@@ -660,7 +1063,7 @@ struct ec_params_read_memmap {
  */
 struct ec_params_get_cmd_versions {
        uint8_t cmd;
-} __packed;
+} __ec_align1;
 
 /**
  * struct ec_params_get_cmd_versions_v1 - Parameters for the get command
@@ -669,7 +1072,7 @@ struct ec_params_get_cmd_versions {
  */
 struct ec_params_get_cmd_versions_v1 {
        uint16_t cmd;
-} __packed;
+} __ec_align2;
 
 /**
  * struct ec_response_get_cmd_version - Response to the get command versions.
@@ -678,20 +1081,20 @@ struct ec_params_get_cmd_versions_v1 {
  */
 struct ec_response_get_cmd_versions {
        uint32_t version_mask;
-} __packed;
+} __ec_align4;
 
 /*
- * Check EC communcations status (busy). This is needed on i2c/spi but not
+ * Check EC communications status (busy). This is needed on i2c/spi but not
  * on lpc since it has its own out-of-band busy indicator.
  *
  * lpc must read the status from the command register. Attempting this on
  * lpc will overwrite the args/parameter space and corrupt its data.
  */
-#define EC_CMD_GET_COMMS_STATUS                0x09
+#define EC_CMD_GET_COMMS_STATUS                0x0009
 
 /* Avoid using ec_status which is for return values */
 enum ec_comms_status {
-       EC_COMMS_STATUS_PROCESSING      = 1 << 0,       /* Processing cmd */
+       EC_COMMS_STATUS_PROCESSING      = BIT(0),       /* Processing cmd */
 };
 
 /**
@@ -701,29 +1104,29 @@ enum ec_comms_status {
  */
 struct ec_response_get_comms_status {
        uint32_t flags;         /* Mask of enum ec_comms_status */
-} __packed;
+} __ec_align4;
 
 /* Fake a variety of responses, purely for testing purposes. */
-#define EC_CMD_TEST_PROTOCOL           0x0a
+#define EC_CMD_TEST_PROTOCOL           0x000A
 
 /* Tell the EC what to send back to us. */
 struct ec_params_test_protocol {
        uint32_t ec_result;
        uint32_t ret_len;
        uint8_t buf[32];
-} __packed;
+} __ec_align4;
 
 /* Here it comes... */
 struct ec_response_test_protocol {
        uint8_t buf[32];
-} __packed;
+} __ec_align4;
 
-/* Get prococol information */
-#define EC_CMD_GET_PROTOCOL_INFO       0x0b
+/* Get protocol information */
+#define EC_CMD_GET_PROTOCOL_INFO       0x000B
 
 /* Flags for ec_response_get_protocol_info.flags */
 /* EC_RES_IN_PROGRESS may be returned if a command is slow */
-#define EC_PROTOCOL_INFO_IN_PROGRESS_SUPPORTED (1 << 0)
+#define EC_PROTOCOL_INFO_IN_PROGRESS_SUPPORTED BIT(0)
 
 /**
  * struct ec_response_get_protocol_info - Response to the get protocol info.
@@ -739,7 +1142,7 @@ struct ec_response_get_protocol_info {
        uint16_t max_request_packet_size;
        uint16_t max_response_packet_size;
        uint32_t flags;
-} __packed;
+} __ec_align4;
 
 
 /*****************************************************************************/
@@ -757,19 +1160,19 @@ struct ec_response_get_protocol_info {
 struct ec_params_get_set_value {
        uint32_t flags;
        uint32_t value;
-} __packed;
+} __ec_align4;
 
 struct ec_response_get_set_value {
        uint32_t flags;
        uint32_t value;
-} __packed;
+} __ec_align4;
 
-/* More than one command can use these structs to get/set paramters. */
-#define EC_CMD_GSV_PAUSE_IN_S5 0x0c
+/* More than one command can use these structs to get/set parameters. */
+#define EC_CMD_GSV_PAUSE_IN_S5 0x000C
 
 /*****************************************************************************/
 /* List the features supported by the firmware */
-#define EC_CMD_GET_FEATURES  0x0d
+#define EC_CMD_GET_FEATURES  0x000D
 
 /* Supported features */
 enum ec_feature_code {
@@ -876,24 +1279,36 @@ enum ec_feature_code {
        EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS = 37,
        /* EC supports audio codec. */
        EC_FEATURE_AUDIO_CODEC = 38,
-       /* EC Supports SCP. */
+       /* The MCU is a System Companion Processor (SCP). */
        EC_FEATURE_SCP = 39,
        /* The MCU is an Integrated Sensor Hub */
        EC_FEATURE_ISH = 40,
 };
 
-#define EC_FEATURE_MASK_0(event_code) (1UL << (event_code % 32))
-#define EC_FEATURE_MASK_1(event_code) (1UL << (event_code - 32))
+#define EC_FEATURE_MASK_0(event_code) BIT(event_code % 32)
+#define EC_FEATURE_MASK_1(event_code) BIT(event_code - 32)
 
 struct ec_response_get_features {
        uint32_t flags[2];
-} __packed;
+} __ec_align4;
+
+/*****************************************************************************/
+/* Get the board's SKU ID from EC */
+#define EC_CMD_GET_SKU_ID 0x000E
+
+/* Set SKU ID from AP */
+#define EC_CMD_SET_SKU_ID 0x000F
+
+struct ec_sku_id_info {
+       uint32_t sku_id;
+} __ec_align4;
 
 /*****************************************************************************/
 /* Flash commands */
 
 /* Get flash info */
-#define EC_CMD_FLASH_INFO 0x10
+#define EC_CMD_FLASH_INFO 0x0010
+#define EC_VER_FLASH_INFO 2
 
 /**
  * struct ec_response_flash_info - Response to the flash info command.
@@ -912,11 +1327,22 @@ struct ec_response_flash_info {
        uint32_t write_block_size;
        uint32_t erase_block_size;
        uint32_t protect_block_size;
-} __packed;
+} __ec_align4;
+
+/*
+ * Flags for version 1+ flash info command
+ * EC flash erases bits to 0 instead of 1.
+ */
+#define EC_FLASH_INFO_ERASE_TO_0 BIT(0)
 
-/* Flags for version 1+ flash info command */
-/* EC flash erases bits to 0 instead of 1 */
-#define EC_FLASH_INFO_ERASE_TO_0 (1 << 0)
+/*
+ * Flash must be selected for read/write/erase operations to succeed.  This may
+ * be necessary on a chip where write/erase can be corrupted by other board
+ * activity, or where the chip needs to enable some sort of programming voltage,
+ * or where the read/write/erase operations require cleanly suspending other
+ * chip functionality.
+ */
+#define EC_FLASH_INFO_SELECT_REQUIRED BIT(1)
 
 /**
  * struct ec_response_flash_info_1 - Response to the flash info v1 command.
@@ -938,7 +1364,14 @@ struct ec_response_flash_info {
  * fields following.
  *
  * gcc anonymous structs don't seem to get along with the __packed directive;
- * if they did we'd define the version 0 struct as a sub-struct of this one.
+ * if they did we'd define the version 0 structure as a sub-structure of this
+ * one.
+ *
+ * Version 2 supports flash banks of different sizes:
+ * The caller specified the number of banks it has preallocated
+ * (num_banks_desc)
+ * The EC returns the number of banks describing the flash memory.
+ * It adds banks descriptions up to num_banks_desc.
  */
 struct ec_response_flash_info_1 {
        /* Version 0 fields; see above for description */
@@ -950,14 +1383,50 @@ struct ec_response_flash_info_1 {
        /* Version 1 adds these fields: */
        uint32_t write_ideal_size;
        uint32_t flags;
-} __packed;
+} __ec_align4;
+
+struct ec_params_flash_info_2 {
+       /* Number of banks to describe */
+       uint16_t num_banks_desc;
+       /* Reserved; set 0; ignore on read */
+       uint8_t reserved[2];
+} __ec_align4;
+
+struct ec_flash_bank {
+       /* Number of sector is in this bank. */
+       uint16_t count;
+       /* Size in power of 2 of each sector (8 --> 256 bytes) */
+       uint8_t size_exp;
+       /* Minimal write size for the sectors in this bank */
+       uint8_t write_size_exp;
+       /* Erase size for the sectors in this bank */
+       uint8_t erase_size_exp;
+       /* Size for write protection, usually identical to erase size. */
+       uint8_t protect_size_exp;
+       /* Reserved; set 0; ignore on read */
+       uint8_t reserved[2];
+};
+
+struct ec_response_flash_info_2 {
+       /* Total flash in the EC. */
+       uint32_t flash_size;
+       /* Flags; see EC_FLASH_INFO_* */
+       uint32_t flags;
+       /* Maximum size to use to send data to write to the EC. */
+       uint32_t write_ideal_size;
+       /* Number of banks present in the EC. */
+       uint16_t num_banks_total;
+       /* Number of banks described in banks array. */
+       uint16_t num_banks_desc;
+       struct ec_flash_bank banks[0];
+} __ec_align4;
 
 /*
  * Read flash
  *
  * Response is params.size bytes of data.
  */
-#define EC_CMD_FLASH_READ 0x11
+#define EC_CMD_FLASH_READ 0x0011
 
 /**
  * struct ec_params_flash_read - Parameters for the flash read command.
@@ -967,10 +1436,10 @@ struct ec_response_flash_info_1 {
 struct ec_params_flash_read {
        uint32_t offset;
        uint32_t size;
-} __packed;
+} __ec_align4;
 
 /* Write flash */
-#define EC_CMD_FLASH_WRITE 0x12
+#define EC_CMD_FLASH_WRITE 0x0012
 #define EC_VER_FLASH_WRITE 1
 
 /* Version 0 of the flash command supported only 64 bytes of data */
@@ -985,20 +1454,57 @@ struct ec_params_flash_write {
        uint32_t offset;
        uint32_t size;
        /* Followed by data to write */
-} __packed;
+} __ec_align4;
 
 /* Erase flash */
-#define EC_CMD_FLASH_ERASE 0x13
+#define EC_CMD_FLASH_ERASE 0x0013
 
 /**
- * struct ec_params_flash_erase - Parameters for the flash erase command.
+ * struct ec_params_flash_erase - Parameters for the flash erase command, v0.
  * @offset: Byte offset to erase.
  * @size: Size to erase in bytes.
  */
 struct ec_params_flash_erase {
        uint32_t offset;
        uint32_t size;
-} __packed;
+} __ec_align4;
+
+/*
+ * v1 add async erase:
+ * subcommands can returns:
+ * EC_RES_SUCCESS : erased (see ERASE_SECTOR_ASYNC case below).
+ * EC_RES_INVALID_PARAM : offset/size are not aligned on a erase boundary.
+ * EC_RES_ERROR : other errors.
+ * EC_RES_BUSY : an existing erase operation is in progress.
+ * EC_RES_ACCESS_DENIED: Trying to erase running image.
+ *
+ * When ERASE_SECTOR_ASYNC returns EC_RES_SUCCESS, the operation is just
+ * properly queued. The user must call ERASE_GET_RESULT subcommand to get
+ * the proper result.
+ * When ERASE_GET_RESULT returns EC_RES_BUSY, the caller must wait and send
+ * ERASE_GET_RESULT again to get the result of ERASE_SECTOR_ASYNC.
+ * ERASE_GET_RESULT command may timeout on EC where flash access is not
+ * permitted while erasing. (For instance, STM32F4).
+ */
+enum ec_flash_erase_cmd {
+       FLASH_ERASE_SECTOR,     /* Erase and wait for result */
+       FLASH_ERASE_SECTOR_ASYNC,  /* Erase and return immediately. */
+       FLASH_ERASE_GET_RESULT,  /* Ask for last erase result */
+};
+
+/**
+ * struct ec_params_flash_erase_v1 - Parameters for the flash erase command, v1.
+ * @cmd: One of ec_flash_erase_cmd.
+ * @reserved: Pad byte; currently always contains 0.
+ * @flag: No flags defined yet; set to 0.
+ * @params: Same as v0 parameters.
+ */
+struct ec_params_flash_erase_v1 {
+       uint8_t  cmd;
+       uint8_t  reserved;
+       uint16_t flag;
+       struct ec_params_flash_erase params;
+} __ec_align4;
 
 /*
  * Get/set flash protection.
@@ -1010,31 +1516,40 @@ struct ec_params_flash_erase {
  *
  * If mask=0, simply returns the current flags state.
  */
-#define EC_CMD_FLASH_PROTECT 0x15
+#define EC_CMD_FLASH_PROTECT 0x0015
 #define EC_VER_FLASH_PROTECT 1  /* Command version 1 */
 
 /* Flags for flash protection */
 /* RO flash code protected when the EC boots */
-#define EC_FLASH_PROTECT_RO_AT_BOOT         (1 << 0)
+#define EC_FLASH_PROTECT_RO_AT_BOOT         BIT(0)
 /*
  * RO flash code protected now.  If this bit is set, at-boot status cannot
  * be changed.
  */
-#define EC_FLASH_PROTECT_RO_NOW             (1 << 1)
+#define EC_FLASH_PROTECT_RO_NOW             BIT(1)
 /* Entire flash code protected now, until reboot. */
-#define EC_FLASH_PROTECT_ALL_NOW            (1 << 2)
+#define EC_FLASH_PROTECT_ALL_NOW            BIT(2)
 /* Flash write protect GPIO is asserted now */
-#define EC_FLASH_PROTECT_GPIO_ASSERTED      (1 << 3)
+#define EC_FLASH_PROTECT_GPIO_ASSERTED      BIT(3)
 /* Error - at least one bank of flash is stuck locked, and cannot be unlocked */
-#define EC_FLASH_PROTECT_ERROR_STUCK        (1 << 4)
+#define EC_FLASH_PROTECT_ERROR_STUCK        BIT(4)
 /*
  * Error - flash protection is in inconsistent state.  At least one bank of
  * flash which should be protected is not protected.  Usually fixed by
  * re-requesting the desired flags, or by a hard reset if that fails.
  */
-#define EC_FLASH_PROTECT_ERROR_INCONSISTENT (1 << 5)
-/* Entile flash code protected when the EC boots */
-#define EC_FLASH_PROTECT_ALL_AT_BOOT        (1 << 6)
+#define EC_FLASH_PROTECT_ERROR_INCONSISTENT BIT(5)
+/* Entire flash code protected when the EC boots */
+#define EC_FLASH_PROTECT_ALL_AT_BOOT        BIT(6)
+/* RW flash code protected when the EC boots */
+#define EC_FLASH_PROTECT_RW_AT_BOOT         BIT(7)
+/* RW flash code protected now. */
+#define EC_FLASH_PROTECT_RW_NOW             BIT(8)
+/* Rollback information flash region protected when the EC boots */
+#define EC_FLASH_PROTECT_ROLLBACK_AT_BOOT   BIT(9)
+/* Rollback information flash region protected now */
+#define EC_FLASH_PROTECT_ROLLBACK_NOW       BIT(10)
+
 
 /**
  * struct ec_params_flash_protect - Parameters for the flash protect command.
@@ -1044,7 +1559,7 @@ struct ec_params_flash_erase {
 struct ec_params_flash_protect {
        uint32_t mask;
        uint32_t flags;
-} __packed;
+} __ec_align4;
 
 /**
  * struct ec_response_flash_protect - Response to the flash protect command.
@@ -1059,7 +1574,7 @@ struct ec_response_flash_protect {
        uint32_t flags;
        uint32_t valid_flags;
        uint32_t writable_flags;
-} __packed;
+} __ec_align4;
 
 /*
  * Note: commands 0x14 - 0x19 version 0 were old commands to get/set flash
@@ -1067,22 +1582,37 @@ struct ec_response_flash_protect {
  */
 
 /* Get the region offset/size */
-#define EC_CMD_FLASH_REGION_INFO 0x16
+#define EC_CMD_FLASH_REGION_INFO 0x0016
 #define EC_VER_FLASH_REGION_INFO 1
 
 enum ec_flash_region {
        /* Region which holds read-only EC image */
        EC_FLASH_REGION_RO = 0,
-       /* Region which holds rewritable EC image */
-       EC_FLASH_REGION_RW,
+       /*
+        * Region which holds active RW image. 'Active' is different from
+        * 'running'. Active means 'scheduled-to-run'. Since RO image always
+        * scheduled to run, active/non-active applies only to RW images (for
+        * the same reason 'update' applies only to RW images. It's a state of
+        * an image on a flash. Running image can be RO, RW_A, RW_B but active
+        * image can only be RW_A or RW_B. In recovery mode, an active RW image
+        * doesn't enter 'running' state but it's still active on a flash.
+        */
+       EC_FLASH_REGION_ACTIVE,
        /*
         * Region which should be write-protected in the factory (a superset of
         * EC_FLASH_REGION_RO)
         */
        EC_FLASH_REGION_WP_RO,
+       /* Region which holds updatable (non-active) RW image */
+       EC_FLASH_REGION_UPDATE,
        /* Number of regions */
        EC_FLASH_REGION_COUNT,
 };
+/*
+ * 'RW' is vague if there are multiple RW images; we mean the active one,
+ * so the old constant is deprecated.
+ */
+#define EC_FLASH_REGION_RW EC_FLASH_REGION_ACTIVE
 
 /**
  * struct ec_params_flash_region_info - Parameters for the flash region info
@@ -1091,15 +1621,15 @@ enum ec_flash_region {
  */
 struct ec_params_flash_region_info {
        uint32_t region;
-} __packed;
+} __ec_align4;
 
 struct ec_response_flash_region_info {
        uint32_t offset;
        uint32_t size;
-} __packed;
+} __ec_align4;
 
 /* Read/write VbNvContext */
-#define EC_CMD_VBNV_CONTEXT 0x17
+#define EC_CMD_VBNV_CONTEXT 0x0017
 #define EC_VER_VBNV_CONTEXT 1
 #define EC_VBNV_BLOCK_SIZE 16
 
@@ -1111,52 +1641,99 @@ enum ec_vbnvcontext_op {
 struct ec_params_vbnvcontext {
        uint32_t op;
        uint8_t block[EC_VBNV_BLOCK_SIZE];
-} __packed;
+} __ec_align4;
 
 struct ec_response_vbnvcontext {
        uint8_t block[EC_VBNV_BLOCK_SIZE];
-} __packed;
+} __ec_align4;
+
+
+/* Get SPI flash information */
+#define EC_CMD_FLASH_SPI_INFO 0x0018
+
+struct ec_response_flash_spi_info {
+       /* JEDEC info from command 0x9F (manufacturer, memory type, size) */
+       uint8_t jedec[3];
+
+       /* Pad byte; currently always contains 0 */
+       uint8_t reserved0;
+
+       /* Manufacturer / device ID from command 0x90 */
+       uint8_t mfr_dev_id[2];
+
+       /* Status registers from command 0x05 and 0x35 */
+       uint8_t sr1, sr2;
+} __ec_align1;
+
+
+/* Select flash during flash operations */
+#define EC_CMD_FLASH_SELECT 0x0019
+
+/**
+ * struct ec_params_flash_select - Parameters for the flash select command.
+ * @select: 1 to select flash, 0 to deselect flash
+ */
+struct ec_params_flash_select {
+       uint8_t select;
+} __ec_align4;
+
 
 /*****************************************************************************/
 /* PWM commands */
 
 /* Get fan target RPM */
-#define EC_CMD_PWM_GET_FAN_TARGET_RPM 0x20
+#define EC_CMD_PWM_GET_FAN_TARGET_RPM 0x0020
 
 struct ec_response_pwm_get_fan_rpm {
        uint32_t rpm;
-} __packed;
+} __ec_align4;
 
 /* Set target fan RPM */
-#define EC_CMD_PWM_SET_FAN_TARGET_RPM 0x21
+#define EC_CMD_PWM_SET_FAN_TARGET_RPM 0x0021
+
+/* Version 0 of input params */
+struct ec_params_pwm_set_fan_target_rpm_v0 {
+       uint32_t rpm;
+} __ec_align4;
 
-struct ec_params_pwm_set_fan_target_rpm {
+/* Version 1 of input params */
+struct ec_params_pwm_set_fan_target_rpm_v1 {
        uint32_t rpm;
-} __packed;
+       uint8_t fan_idx;
+} __ec_align_size1;
 
 /* Get keyboard backlight */
-#define EC_CMD_PWM_GET_KEYBOARD_BACKLIGHT 0x22
+/* OBSOLETE - Use EC_CMD_PWM_SET_DUTY */
+#define EC_CMD_PWM_GET_KEYBOARD_BACKLIGHT 0x0022
 
 struct ec_response_pwm_get_keyboard_backlight {
        uint8_t percent;
        uint8_t enabled;
-} __packed;
+} __ec_align1;
 
 /* Set keyboard backlight */
-#define EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT 0x23
+/* OBSOLETE - Use EC_CMD_PWM_SET_DUTY */
+#define EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT 0x0023
 
 struct ec_params_pwm_set_keyboard_backlight {
        uint8_t percent;
-} __packed;
+} __ec_align1;
 
 /* Set target fan PWM duty cycle */
-#define EC_CMD_PWM_SET_FAN_DUTY 0x24
+#define EC_CMD_PWM_SET_FAN_DUTY 0x0024
+
+/* Version 0 of input params */
+struct ec_params_pwm_set_fan_duty_v0 {
+       uint32_t percent;
+} __ec_align4;
 
-struct ec_params_pwm_set_fan_duty {
+/* Version 1 of input params */
+struct ec_params_pwm_set_fan_duty_v1 {
        uint32_t percent;
-} __packed;
+       uint8_t fan_idx;
+} __ec_align_size1;
 
-#define EC_CMD_PWM_SET_DUTY 0x25
+#define EC_CMD_PWM_SET_DUTY 0x0025
 /* 16 bit duty cycle, 0xffff = 100% */
 #define EC_PWM_MAX_DUTY 0xffff
 
@@ -1174,18 +1751,18 @@ struct ec_params_pwm_set_duty {
        uint16_t duty;     /* Duty cycle, EC_PWM_MAX_DUTY = 100% */
        uint8_t pwm_type;  /* ec_pwm_type */
        uint8_t index;     /* Type-specific index, or 0 if unique */
-} __packed;
+} __ec_align4;
 
-#define EC_CMD_PWM_GET_DUTY 0x26
+#define EC_CMD_PWM_GET_DUTY 0x0026
 
 struct ec_params_pwm_get_duty {
        uint8_t pwm_type;  /* ec_pwm_type */
        uint8_t index;     /* Type-specific index, or 0 if unique */
-} __packed;
+} __ec_align1;
 
 struct ec_response_pwm_get_duty {
        uint16_t duty;     /* Duty cycle, EC_PWM_MAX_DUTY = 100% */
-} __packed;
+} __ec_align2;
 
 /*****************************************************************************/
 /*
@@ -1194,11 +1771,11 @@ struct ec_response_pwm_get_duty {
  * into a subcommand. We'll make separate structs for subcommands with
  * different input args, so that we know how much to expect.
  */
-#define EC_CMD_LIGHTBAR_CMD 0x28
+#define EC_CMD_LIGHTBAR_CMD 0x0028
 
 struct rgb_s {
        uint8_t r, g, b;
-};
+} __ec_todo_unpacked;
 
 #define LB_BATTERY_LEVELS 4
 
@@ -1238,7 +1815,7 @@ struct lightbar_params_v0 {
 
        /* Color palette */
        struct rgb_s color[8];                  /* 0-3 are Google colors */
-} __packed;
+} __ec_todo_packed;
 
 struct lightbar_params_v1 {
        /* Timing */
@@ -1251,7 +1828,10 @@ struct lightbar_params_v1 {
        int32_t s3_sleep_for;
        int32_t s3_ramp_up;
        int32_t s3_ramp_down;
+       int32_t s5_ramp_up;
+       int32_t s5_ramp_down;
        int32_t tap_tick_delay;
+       int32_t tap_gate_delay;
        int32_t tap_display_time;
 
        /* Tap-for-battery params */
@@ -1279,84 +1859,182 @@ struct lightbar_params_v1 {
        uint8_t s0_idx[2][LB_BATTERY_LEVELS];   /* AP is running */
        uint8_t s3_idx[2][LB_BATTERY_LEVELS];   /* AP is sleeping */
 
+       /* s5: single color pulse on inhibited power-up */
+       uint8_t s5_idx;
+
        /* Color palette */
        struct rgb_s color[8];                  /* 0-3 are Google colors */
-} __packed;
+} __ec_todo_packed;
 
-/* Lightbar program */
-#define EC_LB_PROG_LEN 192
+/* Lightbar command params v2
+ * crbug.com/467716
+ *
+ * lightbar_parms_v1 was too big for i2c, therefore in v2, we split them up by
+ * logical groups to make it more manageable ( < 120 bytes).
+ *
+ * NOTE: Each of these groups must be less than 120 bytes.
+ */
+
+struct lightbar_params_v2_timing {
+       /* Timing */
+       int32_t google_ramp_up;
+       int32_t google_ramp_down;
+       int32_t s3s0_ramp_up;
+       int32_t s0_tick_delay[2];               /* AC=0/1 */
+       int32_t s0a_tick_delay[2];              /* AC=0/1 */
+       int32_t s0s3_ramp_down;
+       int32_t s3_sleep_for;
+       int32_t s3_ramp_up;
+       int32_t s3_ramp_down;
+       int32_t s5_ramp_up;
+       int32_t s5_ramp_down;
+       int32_t tap_tick_delay;
+       int32_t tap_gate_delay;
+       int32_t tap_display_time;
+} __ec_todo_packed;
+
+struct lightbar_params_v2_tap {
+       /* Tap-for-battery params */
+       uint8_t tap_pct_red;
+       uint8_t tap_pct_green;
+       uint8_t tap_seg_min_on;
+       uint8_t tap_seg_max_on;
+       uint8_t tap_seg_osc;
+       uint8_t tap_idx[3];
+} __ec_todo_packed;
+
+struct lightbar_params_v2_oscillation {
+       /* Oscillation */
+       uint8_t osc_min[2];                     /* AC=0/1 */
+       uint8_t osc_max[2];                     /* AC=0/1 */
+       uint8_t w_ofs[2];                       /* AC=0/1 */
+} __ec_todo_packed;
+
+struct lightbar_params_v2_brightness {
+       /* Brightness limits based on the backlight and AC. */
+       uint8_t bright_bl_off_fixed[2];         /* AC=0/1 */
+       uint8_t bright_bl_on_min[2];            /* AC=0/1 */
+       uint8_t bright_bl_on_max[2];            /* AC=0/1 */
+} __ec_todo_packed;
+
+struct lightbar_params_v2_thresholds {
+       /* Battery level thresholds */
+       uint8_t battery_threshold[LB_BATTERY_LEVELS - 1];
+} __ec_todo_packed;
+
+struct lightbar_params_v2_colors {
+       /* Map [AC][battery_level] to color index */
+       uint8_t s0_idx[2][LB_BATTERY_LEVELS];   /* AP is running */
+       uint8_t s3_idx[2][LB_BATTERY_LEVELS];   /* AP is sleeping */
+
+       /* s5: single color pulse on inhibited power-up */
+       uint8_t s5_idx;
+
+       /* Color palette */
+       struct rgb_s color[8];                  /* 0-3 are Google colors */
+} __ec_todo_packed;
+
+/* Lightbar program. */
+#define EC_LB_PROG_LEN 192
 struct lightbar_program {
        uint8_t size;
        uint8_t data[EC_LB_PROG_LEN];
-};
+} __ec_todo_unpacked;
 
 struct ec_params_lightbar {
        uint8_t cmd;                  /* Command (see enum lightbar_command) */
        union {
-               struct {
-                       /* no args */
-               } dump, off, on, init, get_seq, get_params_v0, get_params_v1,
-                       version, get_brightness, get_demo, suspend, resume;
+               /*
+                * The following commands have no args:
+                *
+                * dump, off, on, init, get_seq, get_params_v0, get_params_v1,
+                * version, get_brightness, get_demo, suspend, resume,
+                * get_params_v2_timing, get_params_v2_tap, get_params_v2_osc,
+                * get_params_v2_bright, get_params_v2_thlds,
+                * get_params_v2_colors
+                *
+                * Don't use an empty struct, because C++ hates that.
+                */
 
-               struct {
+               struct __ec_todo_unpacked {
                        uint8_t num;
                } set_brightness, seq, demo;
 
-               struct {
+               struct __ec_todo_unpacked {
                        uint8_t ctrl, reg, value;
                } reg;
 
-               struct {
+               struct __ec_todo_unpacked {
                        uint8_t led, red, green, blue;
                } set_rgb;
 
-               struct {
+               struct __ec_todo_unpacked {
                        uint8_t led;
                } get_rgb;
 
-               struct {
+               struct __ec_todo_unpacked {
                        uint8_t enable;
                } manual_suspend_ctrl;
 
                struct lightbar_params_v0 set_params_v0;
                struct lightbar_params_v1 set_params_v1;
+
+               struct lightbar_params_v2_timing set_v2par_timing;
+               struct lightbar_params_v2_tap set_v2par_tap;
+               struct lightbar_params_v2_oscillation set_v2par_osc;
+               struct lightbar_params_v2_brightness set_v2par_bright;
+               struct lightbar_params_v2_thresholds set_v2par_thlds;
+               struct lightbar_params_v2_colors set_v2par_colors;
+
                struct lightbar_program set_program;
        };
-} __packed;
+} __ec_todo_packed;
 
 struct ec_response_lightbar {
        union {
-               struct {
-                       struct {
+               struct __ec_todo_unpacked {
+                       struct __ec_todo_unpacked {
                                uint8_t reg;
                                uint8_t ic0;
                                uint8_t ic1;
                        } vals[23];
                } dump;
 
-               struct  {
+               struct __ec_todo_unpacked {
                        uint8_t num;
                } get_seq, get_brightness, get_demo;
 
                struct lightbar_params_v0 get_params_v0;
                struct lightbar_params_v1 get_params_v1;
 
-               struct {
+
+               struct lightbar_params_v2_timing get_params_v2_timing;
+               struct lightbar_params_v2_tap get_params_v2_tap;
+               struct lightbar_params_v2_oscillation get_params_v2_osc;
+               struct lightbar_params_v2_brightness get_params_v2_bright;
+               struct lightbar_params_v2_thresholds get_params_v2_thlds;
+               struct lightbar_params_v2_colors get_params_v2_colors;
+
+               struct __ec_todo_unpacked {
                        uint32_t num;
                        uint32_t flags;
                } version;
 
-               struct {
+               struct __ec_todo_unpacked {
                        uint8_t red, green, blue;
                } get_rgb;
 
-               struct {
-                       /* no return params */
-               } off, on, init, set_brightness, seq, reg, set_rgb,
-                       demo, set_params_v0, set_params_v1,
-                       set_program, manual_suspend_ctrl, suspend, resume;
+               /*
+                * The following commands have no response:
+                *
+                * off, on, init, set_brightness, seq, reg, set_rgb, demo,
+                * set_params_v0, set_params_v1, set_program,
+                * manual_suspend_ctrl, suspend, resume, set_v2par_timing,
+                * set_v2par_tap, set_v2par_osc, set_v2par_bright,
+                * set_v2par_thlds, set_v2par_colors
+                */
        };
-} __packed;
+} __ec_todo_packed;
 
 /* Lightbar commands */
 enum lightbar_command {
@@ -1382,13 +2060,25 @@ enum lightbar_command {
        LIGHTBAR_CMD_MANUAL_SUSPEND_CTRL = 19,
        LIGHTBAR_CMD_SUSPEND = 20,
        LIGHTBAR_CMD_RESUME = 21,
+       LIGHTBAR_CMD_GET_PARAMS_V2_TIMING = 22,
+       LIGHTBAR_CMD_SET_PARAMS_V2_TIMING = 23,
+       LIGHTBAR_CMD_GET_PARAMS_V2_TAP = 24,
+       LIGHTBAR_CMD_SET_PARAMS_V2_TAP = 25,
+       LIGHTBAR_CMD_GET_PARAMS_V2_OSCILLATION = 26,
+       LIGHTBAR_CMD_SET_PARAMS_V2_OSCILLATION = 27,
+       LIGHTBAR_CMD_GET_PARAMS_V2_BRIGHTNESS = 28,
+       LIGHTBAR_CMD_SET_PARAMS_V2_BRIGHTNESS = 29,
+       LIGHTBAR_CMD_GET_PARAMS_V2_THRESHOLDS = 30,
+       LIGHTBAR_CMD_SET_PARAMS_V2_THRESHOLDS = 31,
+       LIGHTBAR_CMD_GET_PARAMS_V2_COLORS = 32,
+       LIGHTBAR_CMD_SET_PARAMS_V2_COLORS = 33,
        LIGHTBAR_NUM_CMDS
 };
 
 /*****************************************************************************/
 /* LED control commands */
 
-#define EC_CMD_LED_CONTROL 0x29
+#define EC_CMD_LED_CONTROL 0x0029
 
 enum ec_led_id {
        /* LED to indicate battery state of charge */
@@ -1400,13 +2090,21 @@ enum ec_led_id {
        EC_LED_ID_POWER_LED,
        /* LED on power adapter or its plug */
        EC_LED_ID_ADAPTER_LED,
+       /* LED to indicate left side */
+       EC_LED_ID_LEFT_LED,
+       /* LED to indicate right side */
+       EC_LED_ID_RIGHT_LED,
+       /* LED to indicate recovery mode with HW_REINIT */
+       EC_LED_ID_RECOVERY_HW_REINIT_LED,
+       /* LED to indicate sysrq debug mode. */
+       EC_LED_ID_SYSRQ_DEBUG_LED,
 
        EC_LED_ID_COUNT
 };
 
 /* LED control flags */
-#define EC_LED_FLAGS_QUERY (1 << 0) /* Query LED capability only */
-#define EC_LED_FLAGS_AUTO  (1 << 1) /* Switch LED back to automatic control */
+#define EC_LED_FLAGS_QUERY BIT(0) /* Query LED capability only */
+#define EC_LED_FLAGS_AUTO  BIT(1) /* Switch LED back to automatic control */
 
 enum ec_led_colors {
        EC_LED_COLOR_RED = 0,
@@ -1414,6 +2112,7 @@ enum ec_led_colors {
        EC_LED_COLOR_BLUE,
        EC_LED_COLOR_YELLOW,
        EC_LED_COLOR_WHITE,
+       EC_LED_COLOR_AMBER,
 
        EC_LED_COLOR_COUNT
 };
@@ -1423,7 +2122,7 @@ struct ec_params_led_control {
        uint8_t flags;      /* Control flags */
 
        uint8_t brightness[EC_LED_COLOR_COUNT];
-} __packed;
+} __ec_align1;
 
 struct ec_response_led_control {
        /*
@@ -1434,7 +2133,7 @@ struct ec_response_led_control {
         * Other values means the LED is control by PWM.
         */
        uint8_t brightness_range[EC_LED_COLOR_COUNT];
-} __packed;
+} __ec_align1;
 
 /*****************************************************************************/
 /* Verified boot commands */
@@ -1445,7 +2144,7 @@ struct ec_response_led_control {
  */
 
 /* Verified boot hash command */
-#define EC_CMD_VBOOT_HASH 0x2A
+#define EC_CMD_VBOOT_HASH 0x002A
 
 struct ec_params_vboot_hash {
        uint8_t cmd;             /* enum ec_vboot_hash_cmd */
@@ -1455,7 +2154,7 @@ struct ec_params_vboot_hash {
        uint32_t offset;         /* Offset in flash to hash */
        uint32_t size;           /* Number of bytes to hash */
        uint8_t nonce_data[64];  /* Nonce data; ignored if nonce_size=0 */
-} __packed;
+} __ec_align4;
 
 struct ec_response_vboot_hash {
        uint8_t status;          /* enum ec_vboot_hash_status */
@@ -1465,7 +2164,7 @@ struct ec_response_vboot_hash {
        uint32_t offset;         /* Offset in flash which was hashed */
        uint32_t size;           /* Number of bytes hashed */
        uint8_t hash_digest[64]; /* Hash digest data */
-} __packed;
+} __ec_align4;
 
 enum ec_vboot_hash_cmd {
        EC_VBOOT_HASH_GET = 0,       /* Get current hash status */
@@ -1489,15 +2188,22 @@ enum ec_vboot_hash_status {
  * If one of these is specified, the EC will automatically update offset and
  * size to the correct values for the specified image (RO or RW).
  */
-#define EC_VBOOT_HASH_OFFSET_RO 0xfffffffe
-#define EC_VBOOT_HASH_OFFSET_RW 0xfffffffd
+#define EC_VBOOT_HASH_OFFSET_RO                0xfffffffe
+#define EC_VBOOT_HASH_OFFSET_ACTIVE    0xfffffffd
+#define EC_VBOOT_HASH_OFFSET_UPDATE    0xfffffffc
+
+/*
+ * 'RW' is vague if there are multiple RW images; we mean the active one,
+ * so the old constant is deprecated.
+ */
+#define EC_VBOOT_HASH_OFFSET_RW EC_VBOOT_HASH_OFFSET_ACTIVE
 
 /*****************************************************************************/
 /*
  * Motion sense commands. We'll make separate structs for sub-commands with
  * different input args, so that we know how much to expect.
  */
-#define EC_CMD_MOTION_SENSE_CMD 0x2B
+#define EC_CMD_MOTION_SENSE_CMD 0x002B
 
 /* Motion sense commands */
 enum motionsense_command {
@@ -1516,7 +2222,13 @@ enum motionsense_command {
 
        /*
         * EC Rate command is a setter/getter command for the EC sampling rate
-        * of all motion sensors in milliseconds.
+        * in milliseconds.
+        * It is per sensor, the EC run sample task  at the minimum of all
+        * sensors EC_RATE.
+        * For sensors without hardware FIFO, EC_RATE should be equals to 1/ODR
+        * to collect all the sensor samples.
+        * For sensor with hardware FIFO, EC_RATE is used as the maximal delay
+        * to process of all motion sensors in milliseconds.
         */
        MOTIONSENSE_CMD_EC_RATE = 2,
 
@@ -1547,32 +2259,76 @@ enum motionsense_command {
        MOTIONSENSE_CMD_DATA = 6,
 
        /*
-        * Perform low level calibration.. On sensors that support it, ask to
-        * do offset calibration.
+        * Return sensor fifo info.
+        */
+       MOTIONSENSE_CMD_FIFO_INFO = 7,
+
+       /*
+        * Insert a flush element in the fifo and return sensor fifo info.
+        * The host can use that element to synchronize its operation.
+        */
+       MOTIONSENSE_CMD_FIFO_FLUSH = 8,
+
+       /*
+        * Return a portion of the fifo.
+        */
+       MOTIONSENSE_CMD_FIFO_READ = 9,
+
+       /*
+        * Perform low level calibration.
+        * On sensors that support it, ask to do offset calibration.
         */
        MOTIONSENSE_CMD_PERFORM_CALIB = 10,
 
        /*
-        * Sensor Offset command is a setter/getter command for the offset used
-        * for calibration. The offsets can be calculated by the host, or via
+        * Sensor Offset command is a setter/getter command for the offset
+        * used for calibration.
+        * The offsets can be calculated by the host, or via
         * PERFORM_CALIB command.
         */
        MOTIONSENSE_CMD_SENSOR_OFFSET = 11,
 
-       /* Number of motionsense sub-commands. */
-       MOTIONSENSE_NUM_CMDS
-};
+       /*
+        * List available activities for a MOTION sensor.
+        * Indicates if they are enabled or disabled.
+        */
+       MOTIONSENSE_CMD_LIST_ACTIVITIES = 12,
+
+       /*
+        * Activity management
+        * Enable/Disable activity recognition.
+        */
+       MOTIONSENSE_CMD_SET_ACTIVITY = 13,
+
+       /*
+        * Lid Angle
+        */
+       MOTIONSENSE_CMD_LID_ANGLE = 14,
+
+       /*
+        * Allow the FIFO to trigger interrupt via MKBP events.
+        * By default the FIFO does not send interrupt to process the FIFO
+        * until the AP is ready or it is coming from a wakeup sensor.
+        */
+       MOTIONSENSE_CMD_FIFO_INT_ENABLE = 15,
 
-enum motionsensor_id {
-       EC_MOTION_SENSOR_ACCEL_BASE = 0,
-       EC_MOTION_SENSOR_ACCEL_LID = 1,
-       EC_MOTION_SENSOR_GYRO = 2,
+       /*
+        * Spoof the readings of the sensors.  The spoofed readings can be set
+        * to arbitrary values, or will lock to the last read actual values.
+        */
+       MOTIONSENSE_CMD_SPOOF = 16,
+
+       /* Set lid angle for tablet mode detection. */
+       MOTIONSENSE_CMD_TABLET_MODE_LID_ANGLE = 17,
 
        /*
-        * Note, if more sensors are added and this count changes, the padding
-        * in ec_response_motion_sense dump command must be modified.
+        * Sensor Scale command is a setter/getter command for the calibration
+        * scale.
         */
-       EC_MOTION_SENSOR_COUNT = 3
+       MOTIONSENSE_CMD_SENSOR_SCALE = 18,
+
+       /* Number of motionsense sub-commands. */
+       MOTIONSENSE_NUM_CMDS
 };
 
 /* List of motion sensor types. */
@@ -1584,6 +2340,7 @@ enum motionsensor_type {
        MOTIONSENSE_TYPE_LIGHT = 4,
        MOTIONSENSE_TYPE_ACTIVITY = 5,
        MOTIONSENSE_TYPE_BARO = 6,
+       MOTIONSENSE_TYPE_SYNC = 7,
        MOTIONSENSE_TYPE_MAX,
 };
 
@@ -1591,19 +2348,116 @@ enum motionsensor_type {
 enum motionsensor_location {
        MOTIONSENSE_LOC_BASE = 0,
        MOTIONSENSE_LOC_LID = 1,
+       MOTIONSENSE_LOC_CAMERA = 2,
        MOTIONSENSE_LOC_MAX,
 };
 
 /* List of motion sensor chips. */
 enum motionsensor_chip {
        MOTIONSENSE_CHIP_KXCJ9 = 0,
+       MOTIONSENSE_CHIP_LSM6DS0 = 1,
+       MOTIONSENSE_CHIP_BMI160 = 2,
+       MOTIONSENSE_CHIP_SI1141 = 3,
+       MOTIONSENSE_CHIP_SI1142 = 4,
+       MOTIONSENSE_CHIP_SI1143 = 5,
+       MOTIONSENSE_CHIP_KX022 = 6,
+       MOTIONSENSE_CHIP_L3GD20H = 7,
+       MOTIONSENSE_CHIP_BMA255 = 8,
+       MOTIONSENSE_CHIP_BMP280 = 9,
+       MOTIONSENSE_CHIP_OPT3001 = 10,
+       MOTIONSENSE_CHIP_BH1730 = 11,
+       MOTIONSENSE_CHIP_GPIO = 12,
+       MOTIONSENSE_CHIP_LIS2DH = 13,
+       MOTIONSENSE_CHIP_LSM6DSM = 14,
+       MOTIONSENSE_CHIP_LIS2DE = 15,
+       MOTIONSENSE_CHIP_LIS2MDL = 16,
+       MOTIONSENSE_CHIP_LSM6DS3 = 17,
+       MOTIONSENSE_CHIP_LSM6DSO = 18,
+       MOTIONSENSE_CHIP_LNG2DM = 19,
+       MOTIONSENSE_CHIP_MAX,
+};
+
+/* List of orientation positions */
+enum motionsensor_orientation {
+       MOTIONSENSE_ORIENTATION_LANDSCAPE = 0,
+       MOTIONSENSE_ORIENTATION_PORTRAIT = 1,
+       MOTIONSENSE_ORIENTATION_UPSIDE_DOWN_PORTRAIT = 2,
+       MOTIONSENSE_ORIENTATION_UPSIDE_DOWN_LANDSCAPE = 3,
+       MOTIONSENSE_ORIENTATION_UNKNOWN = 4,
+};
+
+struct ec_response_motion_sensor_data {
+       /* Flags for each sensor. */
+       uint8_t flags;
+       /* Sensor number the data comes from. */
+       uint8_t sensor_num;
+       /* Each sensor is up to 3-axis. */
+       union {
+               int16_t             data[3];
+               struct __ec_todo_packed {
+                       uint16_t    reserved;
+                       uint32_t    timestamp;
+               };
+               struct __ec_todo_unpacked {
+                       uint8_t     activity; /* motionsensor_activity */
+                       uint8_t     state;
+                       int16_t     add_info[2];
+               };
+       };
+} __ec_todo_packed;
+
+/* Note: used in ec_response_get_next_data */
+struct ec_response_motion_sense_fifo_info {
+       /* Size of the fifo */
+       uint16_t size;
+       /* Amount of space used in the fifo */
+       uint16_t count;
+       /* Timestamp recorded in us.
+        * aka accurate timestamp when host event was triggered.
+        */
+       uint32_t timestamp;
+       /* Total amount of vector lost */
+       uint16_t total_lost;
+       /* Lost events since the last fifo_info, per sensors */
+       uint16_t lost[0];
+} __ec_todo_packed;
+
+struct ec_response_motion_sense_fifo_data {
+       uint32_t number_data;
+       struct ec_response_motion_sensor_data data[0];
+} __ec_todo_packed;
+
+/* List supported activity recognition */
+enum motionsensor_activity {
+       MOTIONSENSE_ACTIVITY_RESERVED = 0,
+       MOTIONSENSE_ACTIVITY_SIG_MOTION = 1,
+       MOTIONSENSE_ACTIVITY_DOUBLE_TAP = 2,
+       MOTIONSENSE_ACTIVITY_ORIENTATION = 3,
 };
 
+struct ec_motion_sense_activity {
+       uint8_t sensor_num;
+       uint8_t activity; /* one of enum motionsensor_activity */
+       uint8_t enable;   /* 1: enable, 0: disable */
+       uint8_t reserved;
+       uint16_t parameters[3]; /* activity dependent parameters */
+} __ec_todo_unpacked;
+
 /* Module flag masks used for the dump sub-command. */
-#define MOTIONSENSE_MODULE_FLAG_ACTIVE (1<<0)
+#define MOTIONSENSE_MODULE_FLAG_ACTIVE BIT(0)
 
 /* Sensor flag masks used for the dump sub-command. */
-#define MOTIONSENSE_SENSOR_FLAG_PRESENT (1<<0)
+#define MOTIONSENSE_SENSOR_FLAG_PRESENT BIT(0)
+
+/*
+ * Flush entry for synchronization.
+ * data contains time stamp
+ */
+#define MOTIONSENSE_SENSOR_FLAG_FLUSH BIT(0)
+#define MOTIONSENSE_SENSOR_FLAG_TIMESTAMP BIT(1)
+#define MOTIONSENSE_SENSOR_FLAG_WAKEUP BIT(2)
+#define MOTIONSENSE_SENSOR_FLAG_TABLET_MODE BIT(3)
+#define MOTIONSENSE_SENSOR_FLAG_ODR BIT(4)
 
 /*
  * Send this value for the data element to only perform a read. If you
@@ -1614,48 +2468,79 @@ enum motionsensor_chip {
 
 #define EC_MOTION_SENSE_INVALID_CALIB_TEMP 0x8000
 
+/* MOTIONSENSE_CMD_SENSOR_OFFSET subcommand flag */
 /* Set Calibration information */
-#define MOTION_SENSE_SET_OFFSET        1
+#define MOTION_SENSE_SET_OFFSET BIT(0)
 
-struct ec_response_motion_sensor_data {
-       /* Flags for each sensor. */
-       uint8_t flags;
-       /* Sensor number the data comes from */
-       uint8_t sensor_num;
-       /* Each sensor is up to 3-axis. */
-       union {
-               int16_t             data[3];
-               struct {
-                       uint16_t    rsvd;
-                       uint32_t    timestamp;
-               } __packed;
-               struct {
-                       uint8_t     activity; /* motionsensor_activity */
-                       uint8_t     state;
-                       int16_t     add_info[2];
-               };
-       };
-} __packed;
+/* Default Scale value, factor 1. */
+#define MOTION_SENSE_DEFAULT_SCALE BIT(15)
+
+#define LID_ANGLE_UNRELIABLE 500
+
+enum motionsense_spoof_mode {
+       /* Disable spoof mode. */
+       MOTIONSENSE_SPOOF_MODE_DISABLE = 0,
+
+       /* Enable spoof mode, but use provided component values. */
+       MOTIONSENSE_SPOOF_MODE_CUSTOM,
+
+       /* Enable spoof mode, but use the current sensor values. */
+       MOTIONSENSE_SPOOF_MODE_LOCK_CURRENT,
+
+       /* Query the current spoof mode status for the sensor. */
+       MOTIONSENSE_SPOOF_MODE_QUERY,
+};
 
 struct ec_params_motion_sense {
        uint8_t cmd;
        union {
                /* Used for MOTIONSENSE_CMD_DUMP. */
-               struct {
-                       /* no args */
+               struct __ec_todo_unpacked {
+                       /*
+                        * Maximal number of sensor the host is expecting.
+                        * 0 means the host is only interested in the number
+                        * of sensors controlled by the EC.
+                        */
+                       uint8_t max_sensor_count;
                } dump;
 
                /*
-                * Used for MOTIONSENSE_CMD_EC_RATE and
-                * MOTIONSENSE_CMD_KB_WAKE_ANGLE.
+                * Used for MOTIONSENSE_CMD_KB_WAKE_ANGLE.
                 */
-               struct {
-                       /* Data to set or EC_MOTION_SENSE_NO_VALUE to read. */
+               struct __ec_todo_unpacked {
+                       /* Data to set or EC_MOTION_SENSE_NO_VALUE to read.
+                        * kb_wake_angle: angle to wakup AP.
+                        */
                        int16_t data;
-               } ec_rate, kb_wake_angle;
+               } kb_wake_angle;
+
+               /*
+                * Used for MOTIONSENSE_CMD_INFO, MOTIONSENSE_CMD_DATA
+                * and MOTIONSENSE_CMD_PERFORM_CALIB.
+                */
+               struct __ec_todo_unpacked {
+                       uint8_t sensor_num;
+               } info, info_3, data, fifo_flush, perform_calib,
+                               list_activities;
+
+               /*
+                * Used for MOTIONSENSE_CMD_EC_RATE, MOTIONSENSE_CMD_SENSOR_ODR
+                * and MOTIONSENSE_CMD_SENSOR_RANGE.
+                */
+               struct __ec_todo_unpacked {
+                       uint8_t sensor_num;
+
+                       /* Rounding flag, true for round-up, false for down. */
+                       uint8_t roundup;
+
+                       uint16_t reserved;
+
+                       /* Data to set or EC_MOTION_SENSE_NO_VALUE to read. */
+                       int32_t data;
+               } ec_rate, sensor_odr, sensor_range;
 
                /* Used for MOTIONSENSE_CMD_SENSOR_OFFSET */
-               struct {
+               struct __ec_todo_packed {
                        uint8_t sensor_num;
 
                        /*
@@ -1681,36 +2566,102 @@ struct ec_params_motion_sense {
                         * Compass:       1/16 uT
                         */
                        int16_t offset[3];
-               } __packed sensor_offset;
+               } sensor_offset;
 
-               /* Used for MOTIONSENSE_CMD_INFO. */
-               struct {
+               /* Used for MOTIONSENSE_CMD_SENSOR_SCALE */
+               struct __ec_todo_packed {
                        uint8_t sensor_num;
-               } info;
 
-               /*
-                * Used for MOTIONSENSE_CMD_SENSOR_ODR and
-                * MOTIONSENSE_CMD_SENSOR_RANGE.
-                */
-               struct {
-                       /* Should be element of enum motionsensor_id. */
-                       uint8_t sensor_num;
+                       /*
+                        * bit 0: If set (MOTION_SENSE_SET_OFFSET), set
+                        * the calibration information in the EC.
+                        * If unset, just retrieve calibration information.
+                        */
+                       uint16_t flags;
 
-                       /* Rounding flag, true for round-up, false for down. */
-                       uint8_t roundup;
+                       /*
+                        * Temperature at calibration, in units of 0.01 C
+                        * 0x8000: invalid / unknown.
+                        * 0x0: 0C
+                        * 0x7fff: +327.67C
+                        */
+                       int16_t temp;
 
-                       uint16_t reserved;
+                       /*
+                        * Scale for calibration:
+                        * By default scale is 1, it is encoded on 16bits:
+                        * 1 = BIT(15)
+                        * ~2 = 0xFFFF
+                        * ~0 = 0.
+                        */
+                       uint16_t scale[3];
+               } sensor_scale;
 
-                       /* Data to set or EC_MOTION_SENSE_NO_VALUE to read. */
-                       int32_t data;
-               } sensor_odr, sensor_range;
+
+               /* Used for MOTIONSENSE_CMD_FIFO_INFO */
+               /* (no params) */
+
+               /* Used for MOTIONSENSE_CMD_FIFO_READ */
+               struct __ec_todo_unpacked {
+                       /*
+                        * Number of expected vector to return.
+                        * EC may return less or 0 if none available.
+                        */
+                       uint32_t max_data_vector;
+               } fifo_read;
+
+               struct ec_motion_sense_activity set_activity;
+
+               /* Used for MOTIONSENSE_CMD_LID_ANGLE */
+               /* (no params) */
+
+               /* Used for MOTIONSENSE_CMD_FIFO_INT_ENABLE */
+               struct __ec_todo_unpacked {
+                       /*
+                        * 1: enable, 0 disable fifo,
+                        * EC_MOTION_SENSE_NO_VALUE return value.
+                        */
+                       int8_t enable;
+               } fifo_int_enable;
+
+               /* Used for MOTIONSENSE_CMD_SPOOF */
+               struct __ec_todo_packed {
+                       uint8_t sensor_id;
+
+                       /* See enum motionsense_spoof_mode. */
+                       uint8_t spoof_enable;
+
+                       /* Ignored, used for alignment. */
+                       uint8_t reserved;
+
+                       /* Individual component values to spoof. */
+                       int16_t components[3];
+               } spoof;
+
+               /* Used for MOTIONSENSE_CMD_TABLET_MODE_LID_ANGLE. */
+               struct __ec_todo_unpacked {
+                       /*
+                        * Lid angle threshold for switching between tablet and
+                        * clamshell mode.
+                        */
+                       int16_t lid_angle;
+
+                       /*
+                        * Hysteresis degree to prevent fluctuations between
+                        * clamshell and tablet mode if lid angle keeps
+                        * changing around the threshold. Lid motion driver will
+                        * use lid_angle + hys_degree to trigger tablet mode and
+                        * lid_angle - hys_degree to trigger clamshell mode.
+                        */
+                       int16_t hys_degree;
+               } tablet_mode_threshold;
        };
-} __packed;
+} __ec_todo_packed;
 
 struct ec_response_motion_sense {
        union {
-               /* Used for MOTIONSENSE_CMD_DUMP. */
-               struct {
+               /* Used for MOTIONSENSE_CMD_DUMP */
+               struct __ec_todo_unpacked {
                        /* Flags representing the motion sensor module. */
                        uint8_t module_flags;
 
@@ -1725,7 +2676,7 @@ struct ec_response_motion_sense {
                } dump;
 
                /* Used for MOTIONSENSE_CMD_INFO. */
-               struct {
+               struct __ec_todo_unpacked {
                        /* Should be element of enum motionsensor_type. */
                        uint8_t type;
 
@@ -1736,74 +2687,166 @@ struct ec_response_motion_sense {
                        uint8_t chip;
                } info;
 
+               /* Used for MOTIONSENSE_CMD_INFO version 3 */
+               struct __ec_todo_unpacked {
+                       /* Should be element of enum motionsensor_type. */
+                       uint8_t type;
+
+                       /* Should be element of enum motionsensor_location. */
+                       uint8_t location;
+
+                       /* Should be element of enum motionsensor_chip. */
+                       uint8_t chip;
+
+                       /* Minimum sensor sampling frequency */
+                       uint32_t min_frequency;
+
+                       /* Maximum sensor sampling frequency */
+                       uint32_t max_frequency;
+
+                       /* Max number of sensor events that could be in fifo */
+                       uint32_t fifo_max_event_count;
+               } info_3;
+
                /* Used for MOTIONSENSE_CMD_DATA */
                struct ec_response_motion_sensor_data data;
 
                /*
                 * Used for MOTIONSENSE_CMD_EC_RATE, MOTIONSENSE_CMD_SENSOR_ODR,
-                * MOTIONSENSE_CMD_SENSOR_RANGE, and
-                * MOTIONSENSE_CMD_KB_WAKE_ANGLE.
+                * MOTIONSENSE_CMD_SENSOR_RANGE,
+                * MOTIONSENSE_CMD_KB_WAKE_ANGLE,
+                * MOTIONSENSE_CMD_FIFO_INT_ENABLE and
+                * MOTIONSENSE_CMD_SPOOF.
                 */
-               struct {
+               struct __ec_todo_unpacked {
                        /* Current value of the parameter queried. */
                        int32_t ret;
-               } ec_rate, sensor_odr, sensor_range, kb_wake_angle;
+               } ec_rate, sensor_odr, sensor_range, kb_wake_angle,
+                 fifo_int_enable, spoof;
 
-               /* Used for MOTIONSENSE_CMD_SENSOR_OFFSET */
-               struct {
+               /*
+                * Used for MOTIONSENSE_CMD_SENSOR_OFFSET,
+                * PERFORM_CALIB.
+                */
+               struct __ec_todo_unpacked  {
                        int16_t temp;
                        int16_t offset[3];
                } sensor_offset, perform_calib;
-       };
-} __packed;
 
-/*****************************************************************************/
-/* USB charging control commands */
+               /* Used for MOTIONSENSE_CMD_SENSOR_SCALE */
+               struct __ec_todo_unpacked  {
+                       int16_t temp;
+                       uint16_t scale[3];
+               } sensor_scale;
 
-/* Set USB port charging mode */
-#define EC_CMD_USB_CHARGE_SET_MODE 0x30
+               struct ec_response_motion_sense_fifo_info fifo_info, fifo_flush;
 
-struct ec_params_usb_charge_set_mode {
-       uint8_t usb_port_id;
-       uint8_t mode;
-} __packed;
+               struct ec_response_motion_sense_fifo_data fifo_read;
 
-/*****************************************************************************/
-/* Persistent storage for host */
+               struct __ec_todo_packed {
+                       uint16_t reserved;
+                       uint32_t enabled;
+                       uint32_t disabled;
+               } list_activities;
 
-/* Maximum bytes that can be read/written in a single command */
-#define EC_PSTORE_SIZE_MAX 64
+               /* No params for set activity */
 
-/* Get persistent storage info */
-#define EC_CMD_PSTORE_INFO 0x40
+               /* Used for MOTIONSENSE_CMD_LID_ANGLE */
+               struct __ec_todo_unpacked {
+                       /*
+                        * Angle between 0 and 360 degree if available,
+                        * LID_ANGLE_UNRELIABLE otherwise.
+                        */
+                       uint16_t value;
+               } lid_angle;
 
-struct ec_response_pstore_info {
-       /* Persistent storage size, in bytes */
-       uint32_t pstore_size;
-       /* Access size; read/write offset and size must be a multiple of this */
-       uint32_t access_size;
-} __packed;
+               /* Used for MOTIONSENSE_CMD_TABLET_MODE_LID_ANGLE. */
+               struct __ec_todo_unpacked {
+                       /*
+                        * Lid angle threshold for switching between tablet and
+                        * clamshell mode.
+                        */
+                       uint16_t lid_angle;
+
+                       /* Hysteresis degree. */
+                       uint16_t hys_degree;
+               } tablet_mode_threshold;
+
+       };
+} __ec_todo_packed;
+
+/*****************************************************************************/
+/* Force lid open command */
+
+/* Make lid event always open */
+#define EC_CMD_FORCE_LID_OPEN 0x002C
+
+struct ec_params_force_lid_open {
+       uint8_t enabled;
+} __ec_align1;
+
+/*****************************************************************************/
+/* Configure the behavior of the power button */
+#define EC_CMD_CONFIG_POWER_BUTTON 0x002D
+
+enum ec_config_power_button_flags {
+       /* Enable/Disable power button pulses for x86 devices */
+       EC_POWER_BUTTON_ENABLE_PULSE = BIT(0),
+};
+
+struct ec_params_config_power_button {
+       /* See enum ec_config_power_button_flags */
+       uint8_t flags;
+} __ec_align1;
+
+/*****************************************************************************/
+/* USB charging control commands */
+
+/* Set USB port charging mode */
+#define EC_CMD_USB_CHARGE_SET_MODE 0x0030
+
+struct ec_params_usb_charge_set_mode {
+       uint8_t usb_port_id;
+       uint8_t mode:7;
+       uint8_t inhibit_charge:1;
+} __ec_align1;
+
+/*****************************************************************************/
+/* Persistent storage for host */
+
+/* Maximum bytes that can be read/written in a single command */
+#define EC_PSTORE_SIZE_MAX 64
+
+/* Get persistent storage info */
+#define EC_CMD_PSTORE_INFO 0x0040
+
+struct ec_response_pstore_info {
+       /* Persistent storage size, in bytes */
+       uint32_t pstore_size;
+       /* Access size; read/write offset and size must be a multiple of this */
+       uint32_t access_size;
+} __ec_align4;
 
 /*
  * Read persistent storage
  *
  * Response is params.size bytes of data.
  */
-#define EC_CMD_PSTORE_READ 0x41
+#define EC_CMD_PSTORE_READ 0x0041
 
 struct ec_params_pstore_read {
        uint32_t offset;   /* Byte offset to read */
        uint32_t size;     /* Size to read in bytes */
-} __packed;
+} __ec_align4;
 
 /* Write persistent storage */
-#define EC_CMD_PSTORE_WRITE 0x42
+#define EC_CMD_PSTORE_WRITE 0x0042
 
 struct ec_params_pstore_write {
        uint32_t offset;   /* Byte offset to write */
        uint32_t size;     /* Size to write in bytes */
        uint8_t data[EC_PSTORE_SIZE_MAX];
-} __packed;
+} __ec_align4;
 
 /*****************************************************************************/
 /* Real-time clock */
@@ -1811,21 +2854,21 @@ struct ec_params_pstore_write {
 /* RTC params and response structures */
 struct ec_params_rtc {
        uint32_t time;
-} __packed;
+} __ec_align4;
 
 struct ec_response_rtc {
        uint32_t time;
-} __packed;
+} __ec_align4;
 
 /* These use ec_response_rtc */
-#define EC_CMD_RTC_GET_VALUE 0x44
-#define EC_CMD_RTC_GET_ALARM 0x45
+#define EC_CMD_RTC_GET_VALUE 0x0044
+#define EC_CMD_RTC_GET_ALARM 0x0045
 
 /* These all use ec_params_rtc */
-#define EC_CMD_RTC_SET_VALUE 0x46
-#define EC_CMD_RTC_SET_ALARM 0x47
+#define EC_CMD_RTC_SET_VALUE 0x0046
+#define EC_CMD_RTC_SET_ALARM 0x0047
 
-/* Pass as param to SET_ALARM to clear the current alarm */
+/* Pass as time param to SET_ALARM to clear the current alarm */
 #define EC_RTC_ALARM_CLEAR 0
 
 /*****************************************************************************/
@@ -1835,8 +2878,8 @@ struct ec_response_rtc {
 #define EC_PORT80_SIZE_MAX 32
 
 /* Get last port80 code from previous boot */
-#define EC_CMD_PORT80_LAST_BOOT 0x48
-#define EC_CMD_PORT80_READ 0x48
+#define EC_CMD_PORT80_LAST_BOOT 0x0048
+#define EC_CMD_PORT80_READ 0x0048
 
 enum ec_port80_subcmd {
        EC_PORT80_GET_INFO = 0,
@@ -1846,29 +2889,72 @@ enum ec_port80_subcmd {
 struct ec_params_port80_read {
        uint16_t subcmd;
        union {
-               struct {
+               struct __ec_todo_unpacked {
                        uint32_t offset;
                        uint32_t num_entries;
                } read_buffer;
        };
-} __packed;
+} __ec_todo_packed;
 
 struct ec_response_port80_read {
        union {
-               struct {
+               struct __ec_todo_unpacked {
                        uint32_t writes;
                        uint32_t history_size;
                        uint32_t last_boot;
                } get_info;
-               struct {
+               struct __ec_todo_unpacked {
                        uint16_t codes[EC_PORT80_SIZE_MAX];
                } data;
        };
-} __packed;
+} __ec_todo_packed;
 
 struct ec_response_port80_last_boot {
        uint16_t code;
-} __packed;
+} __ec_align2;
+
+/*****************************************************************************/
+/* Temporary secure storage for host verified boot use */
+
+/* Number of bytes in a vstore slot */
+#define EC_VSTORE_SLOT_SIZE 64
+
+/* Maximum number of vstore slots */
+#define EC_VSTORE_SLOT_MAX 32
+
+/* Get persistent storage info */
+#define EC_CMD_VSTORE_INFO 0x0049
+struct ec_response_vstore_info {
+       /* Indicates which slots are locked */
+       uint32_t slot_locked;
+       /* Total number of slots available */
+       uint8_t slot_count;
+} __ec_align_size1;
+
+/*
+ * Read temporary secure storage
+ *
+ * Response is EC_VSTORE_SLOT_SIZE bytes of data.
+ */
+#define EC_CMD_VSTORE_READ 0x004A
+
+struct ec_params_vstore_read {
+       uint8_t slot; /* Slot to read from */
+} __ec_align1;
+
+struct ec_response_vstore_read {
+       uint8_t data[EC_VSTORE_SLOT_SIZE];
+} __ec_align1;
+
+/*
+ * Write temporary secure storage and lock it.
+ */
+#define EC_CMD_VSTORE_WRITE 0x004B
+
+struct ec_params_vstore_write {
+       uint8_t slot; /* Slot to write to */
+       uint8_t data[EC_VSTORE_SLOT_SIZE];
+} __ec_align1;
 
 /*****************************************************************************/
 /* Thermal engine commands. Note that there are two implementations. We'll
@@ -1877,8 +2963,8 @@ struct ec_response_port80_last_boot {
  * Version 1 separates the CPU thermal limits from the fan control.
  */
 
-#define EC_CMD_THERMAL_SET_THRESHOLD 0x50
-#define EC_CMD_THERMAL_GET_THRESHOLD 0x51
+#define EC_CMD_THERMAL_SET_THRESHOLD 0x0050
+#define EC_CMD_THERMAL_GET_THRESHOLD 0x0051
 
 /* The version 0 structs are opaque. You have to know what they are for
  * the get/set commands to make any sense.
@@ -1889,17 +2975,17 @@ struct ec_params_thermal_set_threshold {
        uint8_t sensor_type;
        uint8_t threshold_id;
        uint16_t value;
-} __packed;
+} __ec_align2;
 
 /* Version 0 - get */
 struct ec_params_thermal_get_threshold {
        uint8_t sensor_type;
        uint8_t threshold_id;
-} __packed;
+} __ec_align1;
 
 struct ec_response_thermal_get_threshold {
        uint16_t value;
-} __packed;
+} __ec_align2;
 
 
 /* The version 1 structs are visible. */
@@ -1911,71 +2997,124 @@ enum ec_temp_thresholds {
        EC_TEMP_THRESH_COUNT
 };
 
-/* Thermal configuration for one temperature sensor. Temps are in degrees K.
+/*
+ * Thermal configuration for one temperature sensor. Temps are in degrees K.
  * Zero values will be silently ignored by the thermal task.
+ *
+ * Set 'temp_host' value allows thermal task to trigger some event with 1 degree
+ * hysteresis.
+ * For example,
+ *     temp_host[EC_TEMP_THRESH_HIGH] = 300 K
+ *     temp_host_release[EC_TEMP_THRESH_HIGH] = 0 K
+ * EC will throttle ap when temperature >= 301 K, and release throttling when
+ * temperature <= 299 K.
+ *
+ * Set 'temp_host_release' value allows thermal task has a custom hysteresis.
+ * For example,
+ *     temp_host[EC_TEMP_THRESH_HIGH] = 300 K
+ *     temp_host_release[EC_TEMP_THRESH_HIGH] = 295 K
+ * EC will throttle ap when temperature >= 301 K, and release throttling when
+ * temperature <= 294 K.
+ *
+ * Note that this structure is a sub-structure of
+ * ec_params_thermal_set_threshold_v1, but maintains its alignment there.
  */
 struct ec_thermal_config {
        uint32_t temp_host[EC_TEMP_THRESH_COUNT]; /* levels of hotness */
+       uint32_t temp_host_release[EC_TEMP_THRESH_COUNT]; /* release levels */
        uint32_t temp_fan_off;          /* no active cooling needed */
        uint32_t temp_fan_max;          /* max active cooling needed */
-} __packed;
+} __ec_align4;
 
 /* Version 1 - get config for one sensor. */
 struct ec_params_thermal_get_threshold_v1 {
        uint32_t sensor_num;
-} __packed;
+} __ec_align4;
 /* This returns a struct ec_thermal_config */
 
-/* Version 1 - set config for one sensor.
- * Use read-modify-write for best results! */
+/*
+ * Version 1 - set config for one sensor.
+ * Use read-modify-write for best results!
+ */
 struct ec_params_thermal_set_threshold_v1 {
        uint32_t sensor_num;
        struct ec_thermal_config cfg;
-} __packed;
+} __ec_align4;
 /* This returns no data */
 
 /****************************************************************************/
 
 /* Toggle automatic fan control */
-#define EC_CMD_THERMAL_AUTO_FAN_CTRL 0x52
+#define EC_CMD_THERMAL_AUTO_FAN_CTRL 0x0052
+
+/* Version 1 of input params */
+struct ec_params_auto_fan_ctrl_v1 {
+       uint8_t fan_idx;
+} __ec_align1;
 
-/* Get TMP006 calibration data */
-#define EC_CMD_TMP006_GET_CALIBRATION 0x53
+/* Get/Set TMP006 calibration data */
+#define EC_CMD_TMP006_GET_CALIBRATION 0x0053
+#define EC_CMD_TMP006_SET_CALIBRATION 0x0054
+
+/*
+ * The original TMP006 calibration only needed four params, but now we need
+ * more. Since the algorithm is nothing but magic numbers anyway, we'll leave
+ * the params opaque. The v1 "get" response will include the algorithm number
+ * and how many params it requires. That way we can change the EC code without
+ * needing to update this file. We can also use a different algorithm on each
+ * sensor.
+ */
 
+/* This is the same struct for both v0 and v1. */
 struct ec_params_tmp006_get_calibration {
        uint8_t index;
-} __packed;
+} __ec_align1;
 
-struct ec_response_tmp006_get_calibration {
+/* Version 0 */
+struct ec_response_tmp006_get_calibration_v0 {
        float s0;
        float b0;
        float b1;
        float b2;
-} __packed;
-
-/* Set TMP006 calibration data */
-#define EC_CMD_TMP006_SET_CALIBRATION 0x54
+} __ec_align4;
 
-struct ec_params_tmp006_set_calibration {
+struct ec_params_tmp006_set_calibration_v0 {
        uint8_t index;
-       uint8_t reserved[3];  /* Reserved; set 0 */
+       uint8_t reserved[3];
        float s0;
        float b0;
        float b1;
        float b2;
-} __packed;
+} __ec_align4;
+
+/* Version 1 */
+struct ec_response_tmp006_get_calibration_v1 {
+       uint8_t algorithm;
+       uint8_t num_params;
+       uint8_t reserved[2];
+       float val[0];
+} __ec_align4;
+
+struct ec_params_tmp006_set_calibration_v1 {
+       uint8_t index;
+       uint8_t algorithm;
+       uint8_t num_params;
+       uint8_t reserved;
+       float val[0];
+} __ec_align4;
+
 
 /* Read raw TMP006 data */
-#define EC_CMD_TMP006_GET_RAW 0x55
+#define EC_CMD_TMP006_GET_RAW 0x0055
 
 struct ec_params_tmp006_get_raw {
        uint8_t index;
-} __packed;
+} __ec_align1;
 
 struct ec_response_tmp006_get_raw {
        int32_t t;  /* In 1/100 K */
        int32_t v;  /* In nV */
-};
+} __ec_align4;
 
 /*****************************************************************************/
 /* MKBP - Matrix KeyBoard Protocol */
@@ -1990,24 +3129,24 @@ struct ec_response_tmp006_get_raw {
  * to obtain the instantaneous state, use EC_CMD_MKBP_INFO with the type
  * EC_MKBP_INFO_CURRENT and event EC_MKBP_EVENT_KEY_MATRIX.
  */
-#define EC_CMD_MKBP_STATE 0x60
+#define EC_CMD_MKBP_STATE 0x0060
 
 /*
  * Provide information about various MKBP things.  See enum ec_mkbp_info_type.
  */
-#define EC_CMD_MKBP_INFO 0x61
+#define EC_CMD_MKBP_INFO 0x0061
 
 struct ec_response_mkbp_info {
        uint32_t rows;
        uint32_t cols;
        /* Formerly "switches", which was 0. */
        uint8_t reserved;
-} __packed;
+} __ec_align_size1;
 
 struct ec_params_mkbp_info {
        uint8_t info_type;
        uint8_t event_type;
-} __packed;
+} __ec_align1;
 
 enum ec_mkbp_info_type {
        /*
@@ -2049,17 +3188,28 @@ enum ec_mkbp_info_type {
 };
 
 /* Simulate key press */
-#define EC_CMD_MKBP_SIMULATE_KEY 0x62
+#define EC_CMD_MKBP_SIMULATE_KEY 0x0062
 
 struct ec_params_mkbp_simulate_key {
        uint8_t col;
        uint8_t row;
        uint8_t pressed;
-} __packed;
+} __ec_align1;
+
+#define EC_CMD_GET_KEYBOARD_ID 0x0063
+
+struct ec_response_keyboard_id {
+       uint32_t keyboard_id;
+} __ec_align4;
+
+enum keyboard_id {
+       KEYBOARD_ID_UNSUPPORTED = 0,
+       KEYBOARD_ID_UNREADABLE = 0xffffffff,
+};
 
 /* Configure keyboard scanning */
-#define EC_CMD_MKBP_SET_CONFIG 0x64
-#define EC_CMD_MKBP_GET_CONFIG 0x65
+#define EC_CMD_MKBP_SET_CONFIG 0x0064
+#define EC_CMD_MKBP_GET_CONFIG 0x0065
 
 /* flags */
 enum mkbp_config_flags {
@@ -2067,16 +3217,21 @@ enum mkbp_config_flags {
 };
 
 enum mkbp_config_valid {
-       EC_MKBP_VALID_SCAN_PERIOD               = 1 << 0,
-       EC_MKBP_VALID_POLL_TIMEOUT              = 1 << 1,
-       EC_MKBP_VALID_MIN_POST_SCAN_DELAY       = 1 << 3,
-       EC_MKBP_VALID_OUTPUT_SETTLE             = 1 << 4,
-       EC_MKBP_VALID_DEBOUNCE_DOWN             = 1 << 5,
-       EC_MKBP_VALID_DEBOUNCE_UP               = 1 << 6,
-       EC_MKBP_VALID_FIFO_MAX_DEPTH            = 1 << 7,
+       EC_MKBP_VALID_SCAN_PERIOD               = BIT(0),
+       EC_MKBP_VALID_POLL_TIMEOUT              = BIT(1),
+       EC_MKBP_VALID_MIN_POST_SCAN_DELAY       = BIT(3),
+       EC_MKBP_VALID_OUTPUT_SETTLE             = BIT(4),
+       EC_MKBP_VALID_DEBOUNCE_DOWN             = BIT(5),
+       EC_MKBP_VALID_DEBOUNCE_UP               = BIT(6),
+       EC_MKBP_VALID_FIFO_MAX_DEPTH            = BIT(7),
 };
 
-/* Configuration for our key scanning algorithm */
+/*
+ * Configuration for our key scanning algorithm.
+ *
+ * Note that this is used as a sub-structure of
+ * ec_{params/response}_mkbp_get_config.
+ */
 struct ec_mkbp_config {
        uint32_t valid_mask;            /* valid fields */
        uint8_t flags;          /* some flags (enum mkbp_config_flags) */
@@ -2096,18 +3251,18 @@ struct ec_mkbp_config {
        uint16_t debounce_up_us;        /* time for debounce on key up */
        /* maximum depth to allow for fifo (0 = no keyscan output) */
        uint8_t fifo_max_depth;
-} __packed;
+} __ec_align_size1;
 
 struct ec_params_mkbp_set_config {
        struct ec_mkbp_config config;
-} __packed;
+} __ec_align_size1;
 
 struct ec_response_mkbp_get_config {
        struct ec_mkbp_config config;
-} __packed;
+} __ec_align_size1;
 
 /* Run the key scan emulation */
-#define EC_CMD_KEYSCAN_SEQ_CTRL 0x66
+#define EC_CMD_KEYSCAN_SEQ_CTRL 0x0066
 
 enum ec_keyscan_seq_cmd {
        EC_KEYSCAN_SEQ_STATUS = 0,      /* Get status information */
@@ -2122,23 +3277,23 @@ enum ec_collect_flags {
         * Indicates this scan was processed by the EC. Due to timing, some
         * scans may be skipped.
         */
-       EC_KEYSCAN_SEQ_FLAG_DONE        = 1 << 0,
+       EC_KEYSCAN_SEQ_FLAG_DONE        = BIT(0),
 };
 
 struct ec_collect_item {
        uint8_t flags;          /* some flags (enum ec_collect_flags) */
-};
+} __ec_align1;
 
 struct ec_params_keyscan_seq_ctrl {
        uint8_t cmd;    /* Command to send (enum ec_keyscan_seq_cmd) */
        union {
-               struct {
+               struct __ec_align1 {
                        uint8_t active;         /* still active */
                        uint8_t num_items;      /* number of items */
                        /* Current item being presented */
                        uint8_t cur_item;
                } status;
-               struct {
+               struct __ec_todo_unpacked {
                        /*
                         * Absolute time for this scan, measured from the
                         * start of the sequence.
@@ -2146,29 +3301,40 @@ struct ec_params_keyscan_seq_ctrl {
                        uint32_t time_us;
                        uint8_t scan[0];        /* keyscan data */
                } add;
-               struct {
+               struct __ec_align1 {
                        uint8_t start_item;     /* First item to return */
                        uint8_t num_items;      /* Number of items to return */
                } collect;
        };
-} __packed;
+} __ec_todo_packed;
 
 struct ec_result_keyscan_seq_ctrl {
        union {
-               struct {
+               struct __ec_todo_unpacked {
                        uint8_t num_items;      /* Number of items */
                        /* Data for each item */
                        struct ec_collect_item item[0];
                } collect;
        };
-} __packed;
+} __ec_todo_packed;
 
 /*
- * Command for retrieving the next pending MKBP event from the EC device
+ * Get the next pending MKBP event.
  *
- * The device replies with UNAVAILABLE if there aren't any pending events.
+ * Returns EC_RES_UNAVAILABLE if there is no event pending.
+ */
+#define EC_CMD_GET_NEXT_EVENT 0x0067
+
+#define EC_MKBP_HAS_MORE_EVENTS_SHIFT 7
+
+/*
+ * We use the most significant bit of the event type to indicate to the host
+ * that the EC has more MKBP events available to provide.
  */
-#define EC_CMD_GET_NEXT_EVENT 0x67
+#define EC_MKBP_HAS_MORE_EVENTS BIT(EC_MKBP_HAS_MORE_EVENTS_SHIFT)
+
+/* The mask to apply to get the raw event type */
+#define EC_MKBP_EVENT_TYPE_MASK (BIT(EC_MKBP_HAS_MORE_EVENTS_SHIFT) - 1)
 
 enum ec_mkbp_event {
        /* Keyboard matrix changed. The event data is the new matrix state. */
@@ -2186,9 +3352,21 @@ enum ec_mkbp_event {
        /* The state of the switches have changed. */
        EC_MKBP_EVENT_SWITCH = 4,
 
-       /* EC sent a sysrq command */
+       /* New Fingerprint sensor event, the event data is fp_events bitmap. */
+       EC_MKBP_EVENT_FINGERPRINT = 5,
+
+       /*
+        * Sysrq event: send emulated sysrq. The event data is sysrq,
+        * corresponding to the key to be pressed.
+        */
        EC_MKBP_EVENT_SYSRQ = 6,
 
+       /*
+        * New 64-bit host event.
+        * The event data is 8 bytes of host event flags.
+        */
+       EC_MKBP_EVENT_HOST_EVENT64 = 7,
+
        /* Notify the AP that something happened on CEC */
        EC_MKBP_EVENT_CEC_EVENT = 8,
 
@@ -2198,65 +3376,140 @@ enum ec_mkbp_event {
        /* Number of MKBP events */
        EC_MKBP_EVENT_COUNT,
 };
+BUILD_ASSERT(EC_MKBP_EVENT_COUNT <= EC_MKBP_EVENT_TYPE_MASK);
 
-union ec_response_get_next_data {
-       uint8_t   key_matrix[13];
+union __ec_align_offset1 ec_response_get_next_data {
+       uint8_t key_matrix[13];
 
        /* Unaligned */
-       uint32_t  host_event;
+       uint32_t host_event;
+       uint64_t host_event64;
 
-       uint32_t   buttons;
-       uint32_t   switches;
-       uint32_t   sysrq;
-} __packed;
+       struct __ec_todo_unpacked {
+               /* For aligning the fifo_info */
+               uint8_t reserved[3];
+               struct ec_response_motion_sense_fifo_info info;
+       } sensor_fifo;
 
-union ec_response_get_next_data_v1 {
+       uint32_t buttons;
+
+       uint32_t switches;
+
+       uint32_t fp_events;
+
+       uint32_t sysrq;
+
+       /* CEC events from enum mkbp_cec_event */
+       uint32_t cec_events;
+};
+
+union __ec_align_offset1 ec_response_get_next_data_v1 {
        uint8_t key_matrix[16];
+
+       /* Unaligned */
        uint32_t host_event;
+       uint64_t host_event64;
+
+       struct __ec_todo_unpacked {
+               /* For aligning the fifo_info */
+               uint8_t reserved[3];
+               struct ec_response_motion_sense_fifo_info info;
+       } sensor_fifo;
+
        uint32_t buttons;
+
        uint32_t switches;
+
+       uint32_t fp_events;
+
        uint32_t sysrq;
+
+       /* CEC events from enum mkbp_cec_event */
        uint32_t cec_events;
+
        uint8_t cec_message[16];
-} __packed;
+};
+BUILD_ASSERT(sizeof(union ec_response_get_next_data_v1) == 16);
 
 struct ec_response_get_next_event {
        uint8_t event_type;
        /* Followed by event data if any */
        union ec_response_get_next_data data;
-} __packed;
+} __ec_align1;
 
 struct ec_response_get_next_event_v1 {
        uint8_t event_type;
        /* Followed by event data if any */
        union ec_response_get_next_data_v1 data;
-} __packed;
+} __ec_align1;
 
 /* Bit indices for buttons and switches.*/
 /* Buttons */
 #define EC_MKBP_POWER_BUTTON   0
 #define EC_MKBP_VOL_UP         1
 #define EC_MKBP_VOL_DOWN       2
+#define EC_MKBP_RECOVERY       3
 
 /* Switches */
 #define EC_MKBP_LID_OPEN       0
 #define EC_MKBP_TABLET_MODE    1
 #define EC_MKBP_BASE_ATTACHED  2
 
+/* Run keyboard factory test scanning */
+#define EC_CMD_KEYBOARD_FACTORY_TEST 0x0068
+
+struct ec_response_keyboard_factory_test {
+       uint16_t shorted;       /* Keyboard pins are shorted */
+} __ec_align2;
+
+/* Fingerprint events in 'fp_events' for EC_MKBP_EVENT_FINGERPRINT */
+#define EC_MKBP_FP_RAW_EVENT(fp_events) ((fp_events) & 0x00FFFFFF)
+#define EC_MKBP_FP_ERRCODE(fp_events)   ((fp_events) & 0x0000000F)
+#define EC_MKBP_FP_ENROLL_PROGRESS_OFFSET 4
+#define EC_MKBP_FP_ENROLL_PROGRESS(fpe) (((fpe) & 0x00000FF0) \
+                                        >> EC_MKBP_FP_ENROLL_PROGRESS_OFFSET)
+#define EC_MKBP_FP_MATCH_IDX_OFFSET 12
+#define EC_MKBP_FP_MATCH_IDX_MASK 0x0000F000
+#define EC_MKBP_FP_MATCH_IDX(fpe) (((fpe) & EC_MKBP_FP_MATCH_IDX_MASK) \
+                                        >> EC_MKBP_FP_MATCH_IDX_OFFSET)
+#define EC_MKBP_FP_ENROLL               BIT(27)
+#define EC_MKBP_FP_MATCH                BIT(28)
+#define EC_MKBP_FP_FINGER_DOWN          BIT(29)
+#define EC_MKBP_FP_FINGER_UP            BIT(30)
+#define EC_MKBP_FP_IMAGE_READY          BIT(31)
+/* code given by EC_MKBP_FP_ERRCODE() when EC_MKBP_FP_ENROLL is set */
+#define EC_MKBP_FP_ERR_ENROLL_OK               0
+#define EC_MKBP_FP_ERR_ENROLL_LOW_QUALITY      1
+#define EC_MKBP_FP_ERR_ENROLL_IMMOBILE         2
+#define EC_MKBP_FP_ERR_ENROLL_LOW_COVERAGE     3
+#define EC_MKBP_FP_ERR_ENROLL_INTERNAL         5
+/* Can be used to detect if image was usable for enrollment or not. */
+#define EC_MKBP_FP_ERR_ENROLL_PROBLEM_MASK     1
+/* code given by EC_MKBP_FP_ERRCODE() when EC_MKBP_FP_MATCH is set */
+#define EC_MKBP_FP_ERR_MATCH_NO                0
+#define EC_MKBP_FP_ERR_MATCH_NO_INTERNAL       6
+#define EC_MKBP_FP_ERR_MATCH_NO_TEMPLATES      7
+#define EC_MKBP_FP_ERR_MATCH_NO_LOW_QUALITY    2
+#define EC_MKBP_FP_ERR_MATCH_NO_LOW_COVERAGE   4
+#define EC_MKBP_FP_ERR_MATCH_YES               1
+#define EC_MKBP_FP_ERR_MATCH_YES_UPDATED       3
+#define EC_MKBP_FP_ERR_MATCH_YES_UPDATE_FAILED 5
+
+
 /*****************************************************************************/
 /* Temperature sensor commands */
 
 /* Read temperature sensor info */
-#define EC_CMD_TEMP_SENSOR_GET_INFO 0x70
+#define EC_CMD_TEMP_SENSOR_GET_INFO 0x0070
 
 struct ec_params_temp_sensor_get_info {
        uint8_t id;
-} __packed;
+} __ec_align1;
 
 struct ec_response_temp_sensor_get_info {
        char sensor_name[32];
        uint8_t sensor_type;
-} __packed;
+} __ec_align1;
 
 /*****************************************************************************/
 
@@ -2269,49 +3522,131 @@ struct ec_response_temp_sensor_get_info {
 /*****************************************************************************/
 /* Host event commands */
 
+
+/* Obsolete. New implementation should use EC_CMD_HOST_EVENT instead */
 /*
  * Host event mask params and response structures, shared by all of the host
  * event commands below.
  */
 struct ec_params_host_event_mask {
        uint32_t mask;
-} __packed;
+} __ec_align4;
 
 struct ec_response_host_event_mask {
        uint32_t mask;
-} __packed;
+} __ec_align4;
 
 /* These all use ec_response_host_event_mask */
-#define EC_CMD_HOST_EVENT_GET_B         0x87
-#define EC_CMD_HOST_EVENT_GET_SMI_MASK  0x88
-#define EC_CMD_HOST_EVENT_GET_SCI_MASK  0x89
-#define EC_CMD_HOST_EVENT_GET_WAKE_MASK 0x8d
+#define EC_CMD_HOST_EVENT_GET_B         0x0087
+#define EC_CMD_HOST_EVENT_GET_SMI_MASK  0x0088
+#define EC_CMD_HOST_EVENT_GET_SCI_MASK  0x0089
+#define EC_CMD_HOST_EVENT_GET_WAKE_MASK 0x008D
 
 /* These all use ec_params_host_event_mask */
-#define EC_CMD_HOST_EVENT_SET_SMI_MASK  0x8a
-#define EC_CMD_HOST_EVENT_SET_SCI_MASK  0x8b
-#define EC_CMD_HOST_EVENT_CLEAR         0x8c
-#define EC_CMD_HOST_EVENT_SET_WAKE_MASK 0x8e
-#define EC_CMD_HOST_EVENT_CLEAR_B       0x8f
+#define EC_CMD_HOST_EVENT_SET_SMI_MASK  0x008A
+#define EC_CMD_HOST_EVENT_SET_SCI_MASK  0x008B
+#define EC_CMD_HOST_EVENT_CLEAR         0x008C
+#define EC_CMD_HOST_EVENT_SET_WAKE_MASK 0x008E
+#define EC_CMD_HOST_EVENT_CLEAR_B       0x008F
+
+/*
+ * Unified host event programming interface - Should be used by newer versions
+ * of BIOS/OS to program host events and masks
+ */
+
+struct ec_params_host_event {
+
+       /* Action requested by host - one of enum ec_host_event_action. */
+       uint8_t action;
+
+       /*
+        * Mask type that the host requested the action on - one of
+        * enum ec_host_event_mask_type.
+        */
+       uint8_t mask_type;
+
+       /* Set to 0, ignore on read */
+       uint16_t reserved;
+
+       /* Value to be used in case of set operations. */
+       uint64_t value;
+} __ec_align4;
+
+/*
+ * Response structure returned by EC_CMD_HOST_EVENT.
+ * Update the value on a GET request. Set to 0 on GET/CLEAR
+ */
+
+struct ec_response_host_event {
+
+       /* Mask value in case of get operation */
+       uint64_t value;
+} __ec_align4;
+
+enum ec_host_event_action {
+       /*
+        * params.value is ignored. Value of mask_type populated
+        * in response.value
+        */
+       EC_HOST_EVENT_GET,
+
+       /* Bits in params.value are set */
+       EC_HOST_EVENT_SET,
+
+       /* Bits in params.value are cleared */
+       EC_HOST_EVENT_CLEAR,
+};
+
+enum ec_host_event_mask_type {
+
+       /* Main host event copy */
+       EC_HOST_EVENT_MAIN,
+
+       /* Copy B of host events */
+       EC_HOST_EVENT_B,
+
+       /* SCI Mask */
+       EC_HOST_EVENT_SCI_MASK,
+
+       /* SMI Mask */
+       EC_HOST_EVENT_SMI_MASK,
+
+       /* Mask of events that should be always reported in hostevents */
+       EC_HOST_EVENT_ALWAYS_REPORT_MASK,
+
+       /* Active wake mask */
+       EC_HOST_EVENT_ACTIVE_WAKE_MASK,
+
+       /* Lazy wake mask for S0ix */
+       EC_HOST_EVENT_LAZY_WAKE_MASK_S0IX,
+
+       /* Lazy wake mask for S3 */
+       EC_HOST_EVENT_LAZY_WAKE_MASK_S3,
+
+       /* Lazy wake mask for S5 */
+       EC_HOST_EVENT_LAZY_WAKE_MASK_S5,
+};
+
+#define EC_CMD_HOST_EVENT       0x00A4
 
 /*****************************************************************************/
 /* Switch commands */
 
 /* Enable/disable LCD backlight */
-#define EC_CMD_SWITCH_ENABLE_BKLIGHT 0x90
+#define EC_CMD_SWITCH_ENABLE_BKLIGHT 0x0090
 
 struct ec_params_switch_enable_backlight {
        uint8_t enabled;
-} __packed;
+} __ec_align1;
 
 /* Enable/disable WLAN/Bluetooth */
-#define EC_CMD_SWITCH_ENABLE_WIRELESS 0x91
+#define EC_CMD_SWITCH_ENABLE_WIRELESS 0x0091
 #define EC_VER_SWITCH_ENABLE_WIRELESS 1
 
 /* Version 0 params; no response */
 struct ec_params_switch_enable_wireless_v0 {
        uint8_t enabled;
-} __packed;
+} __ec_align1;
 
 /* Version 1 params */
 struct ec_params_switch_enable_wireless_v1 {
@@ -2330,7 +3665,7 @@ struct ec_params_switch_enable_wireless_v1 {
 
        /* Which flags to copy from suspend_flags */
        uint8_t suspend_mask;
-} __packed;
+} __ec_align1;
 
 /* Version 1 response */
 struct ec_response_switch_enable_wireless_v1 {
@@ -2339,55 +3674,56 @@ struct ec_response_switch_enable_wireless_v1 {
 
        /* Flags to leave enabled in S3 */
        uint8_t suspend_flags;
-} __packed;
+} __ec_align1;
 
 /*****************************************************************************/
 /* GPIO commands. Only available on EC if write protect has been disabled. */
 
 /* Set GPIO output value */
-#define EC_CMD_GPIO_SET 0x92
+#define EC_CMD_GPIO_SET 0x0092
 
 struct ec_params_gpio_set {
        char name[32];
        uint8_t val;
-} __packed;
+} __ec_align1;
 
 /* Get GPIO value */
-#define EC_CMD_GPIO_GET 0x93
+#define EC_CMD_GPIO_GET 0x0093
 
 /* Version 0 of input params and response */
 struct ec_params_gpio_get {
        char name[32];
-} __packed;
+} __ec_align1;
+
 struct ec_response_gpio_get {
        uint8_t val;
-} __packed;
+} __ec_align1;
 
 /* Version 1 of input params and response */
 struct ec_params_gpio_get_v1 {
        uint8_t subcmd;
        union {
-               struct {
+               struct __ec_align1 {
                        char name[32];
                } get_value_by_name;
-               struct {
+               struct __ec_align1 {
                        uint8_t index;
                } get_info;
        };
-} __packed;
+} __ec_align1;
 
 struct ec_response_gpio_get_v1 {
        union {
-               struct {
+               struct __ec_align1 {
                        uint8_t val;
                } get_value_by_name, get_count;
-               struct {
+               struct __ec_todo_unpacked {
                        uint8_t val;
                        char name[32];
                        uint32_t flags;
                } get_info;
        };
-} __packed;
+} __ec_todo_packed;
 
 enum gpio_get_subcmd {
        EC_GPIO_GET_BY_NAME = 0,
@@ -2399,25 +3735,28 @@ enum gpio_get_subcmd {
 /* I2C commands. Only available when flash write protect is unlocked. */
 
 /*
- * TODO(crosbug.com/p/23570): These commands are deprecated, and will be
- * removed soon.  Use EC_CMD_I2C_XFER instead.
+ * CAUTION: These commands are deprecated, and are not supported anymore in EC
+ * builds >= 8398.0.0 (see crosbug.com/p/23570).
+ *
+ * Use EC_CMD_I2C_PASSTHRU instead.
  */
 
 /* Read I2C bus */
-#define EC_CMD_I2C_READ 0x94
+#define EC_CMD_I2C_READ 0x0094
 
 struct ec_params_i2c_read {
        uint16_t addr; /* 8-bit address (7-bit shifted << 1) */
        uint8_t read_size; /* Either 8 or 16. */
        uint8_t port;
        uint8_t offset;
-} __packed;
+} __ec_align_size1;
+
 struct ec_response_i2c_read {
        uint16_t data;
-} __packed;
+} __ec_align2;
 
 /* Write I2C bus */
-#define EC_CMD_I2C_WRITE 0x95
+#define EC_CMD_I2C_WRITE 0x0095
 
 struct ec_params_i2c_write {
        uint16_t data;
@@ -2425,7 +3764,7 @@ struct ec_params_i2c_write {
        uint8_t write_size; /* Either 8 or 16. */
        uint8_t port;
        uint8_t offset;
-} __packed;
+} __ec_align_size1;
 
 /*****************************************************************************/
 /* Charge state commands. Only available when flash write protect unlocked. */
@@ -2433,7 +3772,7 @@ struct ec_params_i2c_write {
 /* Force charge state machine to stop charging the battery or force it to
  * discharge the battery.
  */
-#define EC_CMD_CHARGE_CONTROL 0x96
+#define EC_CMD_CHARGE_CONTROL 0x0096
 #define EC_VER_CHARGE_CONTROL 1
 
 enum ec_charge_control_mode {
@@ -2444,13 +3783,12 @@ enum ec_charge_control_mode {
 
 struct ec_params_charge_control {
        uint32_t mode;  /* enum charge_control_mode */
-} __packed;
+} __ec_align4;
 
 /*****************************************************************************/
-/* Console commands. Only available when flash write protect is unlocked. */
 
 /* Snapshot console output buffer for use by EC_CMD_CONSOLE_READ. */
-#define EC_CMD_CONSOLE_SNAPSHOT 0x97
+#define EC_CMD_CONSOLE_SNAPSHOT 0x0097
 
 /*
  * Read data from the saved snapshot. If the subcmd parameter is
@@ -2464,7 +3802,7 @@ struct ec_params_charge_control {
  * Response is null-terminated string.  Empty string, if there is no more
  * remaining output.
  */
-#define EC_CMD_CONSOLE_READ 0x98
+#define EC_CMD_CONSOLE_READ 0x0098
 
 enum ec_console_read_subcmd {
        CONSOLE_READ_NEXT = 0,
@@ -2473,7 +3811,7 @@ enum ec_console_read_subcmd {
 
 struct ec_params_console_read_v1 {
        uint8_t subcmd; /* enum ec_console_read_subcmd */
-} __packed;
+} __ec_align1;
 
 /*****************************************************************************/
 
@@ -2484,14 +3822,13 @@ struct ec_params_console_read_v1 {
  *       EC_RES_SUCCESS if the command was successful.
  *       EC_RES_ERROR if the cut off command failed.
  */
+#define EC_CMD_BATTERY_CUT_OFF 0x0099
 
-#define EC_CMD_BATTERY_CUT_OFF 0x99
-
-#define EC_BATTERY_CUTOFF_FLAG_AT_SHUTDOWN     (1 << 0)
+#define EC_BATTERY_CUTOFF_FLAG_AT_SHUTDOWN     BIT(0)
 
 struct ec_params_battery_cutoff {
        uint8_t flags;
-} __packed;
+} __ec_align1;
 
 /*****************************************************************************/
 /* USB port mux control. */
@@ -2499,11 +3836,11 @@ struct ec_params_battery_cutoff {
 /*
  * Switch USB mux or return to automatic switching.
  */
-#define EC_CMD_USB_MUX 0x9a
+#define EC_CMD_USB_MUX 0x009A
 
 struct ec_params_usb_mux {
        uint8_t mux;
-} __packed;
+} __ec_align1;
 
 /*****************************************************************************/
 /* LDOs / FETs control. */
@@ -2516,25 +3853,25 @@ enum ec_ldo_state {
 /*
  * Switch on/off a LDO.
  */
-#define EC_CMD_LDO_SET 0x9b
+#define EC_CMD_LDO_SET 0x009B
 
 struct ec_params_ldo_set {
        uint8_t index;
        uint8_t state;
-} __packed;
+} __ec_align1;
 
 /*
  * Get LDO state.
  */
-#define EC_CMD_LDO_GET 0x9c
+#define EC_CMD_LDO_GET 0x009C
 
 struct ec_params_ldo_get {
        uint8_t index;
-} __packed;
+} __ec_align1;
 
 struct ec_response_ldo_get {
        uint8_t state;
-} __packed;
+} __ec_align1;
 
 /*****************************************************************************/
 /* Power info. */
@@ -2542,7 +3879,7 @@ struct ec_response_ldo_get {
 /*
  * Get power info.
  */
-#define EC_CMD_POWER_INFO 0x9d
+#define EC_CMD_POWER_INFO 0x009D
 
 struct ec_response_power_info {
        uint32_t usb_dev_type;
@@ -2550,21 +3887,21 @@ struct ec_response_power_info {
        uint16_t voltage_system;
        uint16_t current_system;
        uint16_t usb_current_limit;
-} __packed;
+} __ec_align4;
 
 /*****************************************************************************/
 /* I2C passthru command */
 
-#define EC_CMD_I2C_PASSTHRU 0x9e
+#define EC_CMD_I2C_PASSTHRU 0x009E
 
 /* Read data; if not present, message is a write */
-#define EC_I2C_FLAG_READ       (1 << 15)
+#define EC_I2C_FLAG_READ       BIT(15)
 
 /* Mask for address */
 #define EC_I2C_ADDR_MASK       0x3ff
 
-#define EC_I2C_STATUS_NAK      (1 << 0) /* Transfer was not acknowledged */
-#define EC_I2C_STATUS_TIMEOUT  (1 << 1) /* Timeout during transfer */
+#define EC_I2C_STATUS_NAK      BIT(0) /* Transfer was not acknowledged */
+#define EC_I2C_STATUS_TIMEOUT  BIT(1) /* Timeout during transfer */
 
 /* Any error */
 #define EC_I2C_STATUS_ERROR    (EC_I2C_STATUS_NAK | EC_I2C_STATUS_TIMEOUT)
@@ -2572,49 +3909,49 @@ struct ec_response_power_info {
 struct ec_params_i2c_passthru_msg {
        uint16_t addr_flags;    /* I2C slave address (7 or 10 bits) and flags */
        uint16_t len;           /* Number of bytes to read or write */
-} __packed;
+} __ec_align2;
 
 struct ec_params_i2c_passthru {
        uint8_t port;           /* I2C port number */
        uint8_t num_msgs;       /* Number of messages */
        struct ec_params_i2c_passthru_msg msg[];
        /* Data to write for all messages is concatenated here */
-} __packed;
+} __ec_align2;
 
 struct ec_response_i2c_passthru {
        uint8_t i2c_status;     /* Status flags (EC_I2C_STATUS_...) */
        uint8_t num_msgs;       /* Number of messages processed */
        uint8_t data[];         /* Data read by messages concatenated here */
-} __packed;
+} __ec_align1;
 
 /*****************************************************************************/
 /* Power button hang detect */
 
-#define EC_CMD_HANG_DETECT 0x9f
+#define EC_CMD_HANG_DETECT 0x009F
 
 /* Reasons to start hang detection timer */
 /* Power button pressed */
-#define EC_HANG_START_ON_POWER_PRESS  (1 << 0)
+#define EC_HANG_START_ON_POWER_PRESS  BIT(0)
 
 /* Lid closed */
-#define EC_HANG_START_ON_LID_CLOSE    (1 << 1)
+#define EC_HANG_START_ON_LID_CLOSE    BIT(1)
 
  /* Lid opened */
-#define EC_HANG_START_ON_LID_OPEN     (1 << 2)
+#define EC_HANG_START_ON_LID_OPEN     BIT(2)
 
 /* Start of AP S3->S0 transition (booting or resuming from suspend) */
-#define EC_HANG_START_ON_RESUME       (1 << 3)
+#define EC_HANG_START_ON_RESUME       BIT(3)
 
 /* Reasons to cancel hang detection */
 
 /* Power button released */
-#define EC_HANG_STOP_ON_POWER_RELEASE (1 << 8)
+#define EC_HANG_STOP_ON_POWER_RELEASE BIT(8)
 
 /* Any host command from AP received */
-#define EC_HANG_STOP_ON_HOST_COMMAND  (1 << 9)
+#define EC_HANG_STOP_ON_HOST_COMMAND  BIT(9)
 
 /* Stop on end of AP S0->S3 transition (suspending or shutting down) */
-#define EC_HANG_STOP_ON_SUSPEND       (1 << 10)
+#define EC_HANG_STOP_ON_SUSPEND       BIT(10)
 
 /*
  * If this flag is set, all the other fields are ignored, and the hang detect
@@ -2622,14 +3959,14 @@ struct ec_response_i2c_passthru {
  * without reconfiguring any of the other hang detect settings.  Note that
  * you must previously have configured the timeouts.
  */
-#define EC_HANG_START_NOW             (1 << 30)
+#define EC_HANG_START_NOW             BIT(30)
 
 /*
  * If this flag is set, all the other fields are ignored (including
  * EC_HANG_START_NOW).  This provides the AP a way to stop the hang timer
  * without reconfiguring any of the other hang detect settings.
  */
-#define EC_HANG_STOP_NOW              (1 << 31)
+#define EC_HANG_STOP_NOW              BIT(31)
 
 struct ec_params_hang_detect {
        /* Flags; see EC_HANG_* */
@@ -2640,7 +3977,7 @@ struct ec_params_hang_detect {
 
        /* Timeout in msec before generating warm reboot, if enabled */
        uint16_t warm_reboot_timeout_msec;
-} __packed;
+} __ec_align4;
 
 /*****************************************************************************/
 /* Commands for battery charging */
@@ -2649,7 +3986,7 @@ struct ec_params_hang_detect {
  * This is the single catch-all host command to exchange data regarding the
  * charge state machine (v2 and up).
  */
-#define EC_CMD_CHARGE_STATE 0xa0
+#define EC_CMD_CHARGE_STATE 0x00A0
 
 /* Subcommands for this host command */
 enum charge_state_command {
@@ -2669,6 +4006,11 @@ enum charge_state_params {
        CS_PARAM_CHG_INPUT_CURRENT,   /* charger input current limit */
        CS_PARAM_CHG_STATUS,          /* charger-specific status */
        CS_PARAM_CHG_OPTION,          /* charger-specific options */
+       CS_PARAM_LIMIT_POWER,         /*
+                                      * Check if power is limited due to
+                                      * low battery and / or a weak external
+                                      * charger. READ ONLY.
+                                      */
        /* How many so far? */
        CS_NUM_BASE_PARAMS,
 
@@ -2676,30 +4018,39 @@ enum charge_state_params {
        CS_PARAM_CUSTOM_PROFILE_MIN = 0x10000,
        CS_PARAM_CUSTOM_PROFILE_MAX = 0x1ffff,
 
+       /* Range for CONFIG_CHARGE_STATE_DEBUG params */
+       CS_PARAM_DEBUG_MIN = 0x20000,
+       CS_PARAM_DEBUG_CTL_MODE = 0x20000,
+       CS_PARAM_DEBUG_MANUAL_MODE,
+       CS_PARAM_DEBUG_SEEMS_DEAD,
+       CS_PARAM_DEBUG_SEEMS_DISCONNECTED,
+       CS_PARAM_DEBUG_BATT_REMOVED,
+       CS_PARAM_DEBUG_MANUAL_CURRENT,
+       CS_PARAM_DEBUG_MANUAL_VOLTAGE,
+       CS_PARAM_DEBUG_MAX = 0x2ffff,
+
        /* Other custom param ranges go here... */
 };
 
 struct ec_params_charge_state {
        uint8_t cmd;                            /* enum charge_state_command */
        union {
-               struct {
-                       /* no args */
-               } get_state;
+               /* get_state has no args */
 
-               struct {
+               struct __ec_todo_unpacked {
                        uint32_t param;         /* enum charge_state_param */
                } get_param;
 
-               struct {
+               struct __ec_todo_unpacked {
                        uint32_t param;         /* param to set */
                        uint32_t value;         /* value to set */
                } set_param;
        };
-} __packed;
+} __ec_todo_packed;
 
 struct ec_response_charge_state {
        union {
-               struct {
+               struct __ec_align4 {
                        int ac;
                        int chg_voltage;
                        int chg_current;
@@ -2707,24 +4058,23 @@ struct ec_response_charge_state {
                        int batt_state_of_charge;
                } get_state;
 
-               struct {
+               struct __ec_align4 {
                        uint32_t value;
                } get_param;
-               struct {
-                       /* no return values */
-               } set_param;
+
+               /* set_param returns no args */
        };
-} __packed;
+} __ec_align4;
 
 
 /*
  * Set maximum battery charging current.
  */
-#define EC_CMD_CHARGE_CURRENT_LIMIT 0xa1
+#define EC_CMD_CHARGE_CURRENT_LIMIT 0x00A1
 
 struct ec_params_current_limit {
        uint32_t limit; /* in mA */
-} __packed;
+} __ec_align4;
 
 /*
  * Set maximum external voltage / current.
@@ -2735,23 +4085,69 @@ struct ec_params_current_limit {
 struct ec_params_external_power_limit_v1 {
        uint16_t current_lim; /* in mA, or EC_POWER_LIMIT_NONE to clear limit */
        uint16_t voltage_lim; /* in mV, or EC_POWER_LIMIT_NONE to clear limit */
-} __packed;
+} __ec_align2;
 
 #define EC_POWER_LIMIT_NONE 0xffff
 
+/*
+ * Set maximum voltage & current of a dedicated charge port
+ */
+#define EC_CMD_OVERRIDE_DEDICATED_CHARGER_LIMIT 0x00A3
+
+struct ec_params_dedicated_charger_limit {
+       uint16_t current_lim; /* in mA */
+       uint16_t voltage_lim; /* in mV */
+} __ec_align2;
+
+/*****************************************************************************/
+/* Hibernate/Deep Sleep Commands */
+
+/* Set the delay before going into hibernation. */
+#define EC_CMD_HIBERNATION_DELAY 0x00A8
+
+struct ec_params_hibernation_delay {
+       /*
+        * Seconds to wait in G3 before hibernate.  Pass in 0 to read the
+        * current settings without changing them.
+        */
+       uint32_t seconds;
+} __ec_align4;
+
+struct ec_response_hibernation_delay {
+       /*
+        * The current time in seconds in which the system has been in the G3
+        * state.  This value is reset if the EC transitions out of G3.
+        */
+       uint32_t time_g3;
+
+       /*
+        * The current time remaining in seconds until the EC should hibernate.
+        * This value is also reset if the EC transitions out of G3.
+        */
+       uint32_t time_remaining;
+
+       /*
+        * The current time in seconds that the EC should wait in G3 before
+        * hibernating.
+        */
+       uint32_t hibernate_delay;
+} __ec_align4;
+
 /* Inform the EC when entering a sleep state */
-#define EC_CMD_HOST_SLEEP_EVENT 0xa9
+#define EC_CMD_HOST_SLEEP_EVENT 0x00A9
 
 enum host_sleep_event {
        HOST_SLEEP_EVENT_S3_SUSPEND   = 1,
        HOST_SLEEP_EVENT_S3_RESUME    = 2,
        HOST_SLEEP_EVENT_S0IX_SUSPEND = 3,
-       HOST_SLEEP_EVENT_S0IX_RESUME  = 4
+       HOST_SLEEP_EVENT_S0IX_RESUME  = 4,
+       /* S3 suspend with additional enabled wake sources */
+       HOST_SLEEP_EVENT_S3_WAKEABLE_SUSPEND = 5,
 };
 
 struct ec_params_host_sleep_event {
        uint8_t sleep_event;
-} __packed;
+} __ec_align1;
 
 /*
  * Use a default timeout value (CONFIG_SLEEP_TIMEOUT_MS) for detecting sleep
@@ -2782,7 +4178,7 @@ struct ec_params_host_sleep_event_v1 {
 
                /* No parameters for non-suspend messages. */
        };
-} __packed;
+} __ec_align2;
 
 /* A timeout occurred when this bit is set */
 #define EC_HOST_RESUME_SLEEP_TIMEOUT 0x80000000
@@ -2808,42 +4204,72 @@ struct ec_response_host_sleep_event_v1 {
 
                /* No response fields for non-resume messages. */
        };
-} __packed;
+} __ec_align4;
+
+/*****************************************************************************/
+/* Device events */
+#define EC_CMD_DEVICE_EVENT 0x00AA
+
+enum ec_device_event {
+       EC_DEVICE_EVENT_TRACKPAD,
+       EC_DEVICE_EVENT_DSP,
+       EC_DEVICE_EVENT_WIFI,
+};
+
+enum ec_device_event_param {
+       /* Get and clear pending device events */
+       EC_DEVICE_EVENT_PARAM_GET_CURRENT_EVENTS,
+       /* Get device event mask */
+       EC_DEVICE_EVENT_PARAM_GET_ENABLED_EVENTS,
+       /* Set device event mask */
+       EC_DEVICE_EVENT_PARAM_SET_ENABLED_EVENTS,
+};
+
+#define EC_DEVICE_EVENT_MASK(event_code) BIT(event_code % 32)
+
+struct ec_params_device_event {
+       uint32_t event_mask;
+       uint8_t param;
+} __ec_align_size1;
+
+struct ec_response_device_event {
+       uint32_t event_mask;
+} __ec_align4;
 
 /*****************************************************************************/
 /* Smart battery pass-through */
 
 /* Get / Set 16-bit smart battery registers */
-#define EC_CMD_SB_READ_WORD   0xb0
-#define EC_CMD_SB_WRITE_WORD  0xb1
+#define EC_CMD_SB_READ_WORD   0x00B0
+#define EC_CMD_SB_WRITE_WORD  0x00B1
 
 /* Get / Set string smart battery parameters
  * formatted as SMBUS "block".
  */
-#define EC_CMD_SB_READ_BLOCK  0xb2
-#define EC_CMD_SB_WRITE_BLOCK 0xb3
+#define EC_CMD_SB_READ_BLOCK  0x00B2
+#define EC_CMD_SB_WRITE_BLOCK 0x00B3
 
 struct ec_params_sb_rd {
        uint8_t reg;
-} __packed;
+} __ec_align1;
 
 struct ec_response_sb_rd_word {
        uint16_t value;
-} __packed;
+} __ec_align2;
 
 struct ec_params_sb_wr_word {
        uint8_t reg;
        uint16_t value;
-} __packed;
+} __ec_align1;
 
 struct ec_response_sb_rd_block {
        uint8_t data[32];
-} __packed;
+} __ec_align1;
 
 struct ec_params_sb_wr_block {
        uint8_t reg;
        uint16_t data[32];
-} __packed;
+} __ec_align1;
 
 /*****************************************************************************/
 /* Battery vendor parameters
@@ -2854,7 +4280,7 @@ struct ec_params_sb_wr_block {
  * requested value.
  */
 
-#define EC_CMD_BATTERY_VENDOR_PARAM 0xb4
+#define EC_CMD_BATTERY_VENDOR_PARAM 0x00B4
 
 enum ec_battery_vendor_param_mode {
        BATTERY_VENDOR_PARAM_MODE_GET = 0,
@@ -2865,257 +4291,105 @@ struct ec_params_battery_vendor_param {
        uint32_t param;
        uint32_t value;
        uint8_t mode;
-} __packed;
+} __ec_align_size1;
 
 struct ec_response_battery_vendor_param {
        uint32_t value;
-} __packed;
+} __ec_align4;
 
 /*****************************************************************************/
-/* Commands for I2S recording on audio codec. */
-
-#define EC_CMD_CODEC_I2S 0x00BC
-
-enum ec_codec_i2s_subcmd {
-       EC_CODEC_SET_SAMPLE_DEPTH = 0x0,
-       EC_CODEC_SET_GAIN = 0x1,
-       EC_CODEC_GET_GAIN = 0x2,
-       EC_CODEC_I2S_ENABLE = 0x3,
-       EC_CODEC_I2S_SET_CONFIG = 0x4,
-       EC_CODEC_I2S_SET_TDM_CONFIG = 0x5,
-       EC_CODEC_I2S_SET_BCLK = 0x6,
+/*
+ * Smart Battery Firmware Update Commands
+ */
+#define EC_CMD_SB_FW_UPDATE 0x00B5
+
+enum ec_sb_fw_update_subcmd {
+       EC_SB_FW_UPDATE_PREPARE  = 0x0,
+       EC_SB_FW_UPDATE_INFO     = 0x1, /*query sb info */
+       EC_SB_FW_UPDATE_BEGIN    = 0x2, /*check if protected */
+       EC_SB_FW_UPDATE_WRITE    = 0x3, /*check if protected */
+       EC_SB_FW_UPDATE_END      = 0x4,
+       EC_SB_FW_UPDATE_STATUS   = 0x5,
+       EC_SB_FW_UPDATE_PROTECT  = 0x6,
+       EC_SB_FW_UPDATE_MAX      = 0x7,
 };
 
-enum ec_sample_depth_value {
-       EC_CODEC_SAMPLE_DEPTH_16 = 0,
-       EC_CODEC_SAMPLE_DEPTH_24 = 1,
-};
+#define SB_FW_UPDATE_CMD_WRITE_BLOCK_SIZE 32
+#define SB_FW_UPDATE_CMD_STATUS_SIZE 2
+#define SB_FW_UPDATE_CMD_INFO_SIZE 8
 
-enum ec_i2s_config {
-       EC_DAI_FMT_I2S = 0,
-       EC_DAI_FMT_RIGHT_J = 1,
-       EC_DAI_FMT_LEFT_J = 2,
-       EC_DAI_FMT_PCM_A = 3,
-       EC_DAI_FMT_PCM_B = 4,
-       EC_DAI_FMT_PCM_TDM = 5,
-};
+struct ec_sb_fw_update_header {
+       uint16_t subcmd;  /* enum ec_sb_fw_update_subcmd */
+       uint16_t fw_id;   /* firmware id */
+} __ec_align4;
 
-struct ec_param_codec_i2s {
-       /*
-        * enum ec_codec_i2s_subcmd
-        */
-       uint8_t cmd;
+struct ec_params_sb_fw_update {
+       struct ec_sb_fw_update_header hdr;
        union {
-               /*
-                * EC_CODEC_SET_SAMPLE_DEPTH
-                * Value should be one of ec_sample_depth_value.
-                */
-               uint8_t depth;
+               /* EC_SB_FW_UPDATE_PREPARE  = 0x0 */
+               /* EC_SB_FW_UPDATE_INFO     = 0x1 */
+               /* EC_SB_FW_UPDATE_BEGIN    = 0x2 */
+               /* EC_SB_FW_UPDATE_END      = 0x4 */
+               /* EC_SB_FW_UPDATE_STATUS   = 0x5 */
+               /* EC_SB_FW_UPDATE_PROTECT  = 0x6 */
+               /* Those have no args */
+
+               /* EC_SB_FW_UPDATE_WRITE    = 0x3 */
+               struct __ec_align4 {
+                       uint8_t  data[SB_FW_UPDATE_CMD_WRITE_BLOCK_SIZE];
+               } write;
+       };
+} __ec_align4;
 
-               /*
-                * EC_CODEC_SET_GAIN
-                * Value should be 0~43 for both channels.
-                */
-               struct ec_param_codec_i2s_set_gain {
-                       uint8_t left;
-                       uint8_t right;
-               } __packed gain;
+struct ec_response_sb_fw_update {
+       union {
+               /* EC_SB_FW_UPDATE_INFO     = 0x1 */
+               struct __ec_align1 {
+                       uint8_t data[SB_FW_UPDATE_CMD_INFO_SIZE];
+               } info;
 
-               /*
-                * EC_CODEC_I2S_ENABLE
-                * 1 to enable, 0 to disable.
-                */
-               uint8_t i2s_enable;
+               /* EC_SB_FW_UPDATE_STATUS   = 0x5 */
+               struct __ec_align1 {
+                       uint8_t data[SB_FW_UPDATE_CMD_STATUS_SIZE];
+               } status;
+       };
+} __ec_align1;
 
-               /*
-                * EC_CODEC_I2S_SET_COFNIG
-                * Value should be one of ec_i2s_config.
-                */
-               uint8_t i2s_config;
+/*
+ * Entering Verified Boot Mode Command
+ * Default mode is VBOOT_MODE_NORMAL if EC did not receive this command.
+ * Valid Modes are: normal, developer, and recovery.
+ */
+#define EC_CMD_ENTERING_MODE 0x00B6
 
-               /*
-                * EC_CODEC_I2S_SET_TDM_CONFIG
-                * Value should be one of ec_i2s_config.
-                */
-               struct ec_param_codec_i2s_tdm {
-                       /*
-                        * 0 to 496
-                        */
-                       int16_t ch0_delay;
-                       /*
-                        * -1 to 496
-                        */
-                       int16_t ch1_delay;
-                       uint8_t adjacent_to_ch0;
-                       uint8_t adjacent_to_ch1;
-               } __packed tdm_param;
+struct ec_params_entering_mode {
+       int vboot_mode;
+} __ec_align4;
 
-               /*
-                * EC_CODEC_I2S_SET_BCLK
-                */
-               uint32_t bclk;
-       };
-} __packed;
-
-/*
- * For subcommand EC_CODEC_GET_GAIN.
- */
-struct ec_response_codec_gain {
-       uint8_t left;
-       uint8_t right;
-} __packed;
+#define VBOOT_MODE_NORMAL    0
+#define VBOOT_MODE_DEVELOPER 1
+#define VBOOT_MODE_RECOVERY  2
 
 /*****************************************************************************/
-/* System commands */
-
 /*
- * TODO(crosbug.com/p/23747): This is a confusing name, since it doesn't
- * necessarily reboot the EC.  Rename to "image" or something similar?
+ * I2C passthru protection command: Protects I2C tunnels against access on
+ * certain addresses (board-specific).
  */
-#define EC_CMD_REBOOT_EC 0xd2
+#define EC_CMD_I2C_PASSTHRU_PROTECT 0x00B7
 
-/* Command */
-enum ec_reboot_cmd {
-       EC_REBOOT_CANCEL = 0,        /* Cancel a pending reboot */
-       EC_REBOOT_JUMP_RO = 1,       /* Jump to RO without rebooting */
-       EC_REBOOT_JUMP_RW = 2,       /* Jump to RW without rebooting */
-       /* (command 3 was jump to RW-B) */
-       EC_REBOOT_COLD = 4,          /* Cold-reboot */
-       EC_REBOOT_DISABLE_JUMP = 5,  /* Disable jump until next reboot */
-       EC_REBOOT_HIBERNATE = 6      /* Hibernate EC */
+enum ec_i2c_passthru_protect_subcmd {
+       EC_CMD_I2C_PASSTHRU_PROTECT_STATUS = 0x0,
+       EC_CMD_I2C_PASSTHRU_PROTECT_ENABLE = 0x1,
 };
 
-/* Flags for ec_params_reboot_ec.reboot_flags */
-#define EC_REBOOT_FLAG_RESERVED0      (1 << 0)  /* Was recovery request */
-#define EC_REBOOT_FLAG_ON_AP_SHUTDOWN (1 << 1)  /* Reboot after AP shutdown */
-
-struct ec_params_reboot_ec {
-       uint8_t cmd;           /* enum ec_reboot_cmd */
-       uint8_t flags;         /* See EC_REBOOT_FLAG_* */
-} __packed;
-
-/*
- * Get information on last EC panic.
- *
- * Returns variable-length platform-dependent panic information.  See panic.h
- * for details.
- */
-#define EC_CMD_GET_PANIC_INFO 0xd3
-
-/*****************************************************************************/
-/*
- * ACPI commands
- *
- * These are valid ONLY on the ACPI command/data port.
- */
-
-/*
- * ACPI Read Embedded Controller
- *
- * This reads from ACPI memory space on the EC (EC_ACPI_MEM_*).
- *
- * Use the following sequence:
- *
- *    - Write EC_CMD_ACPI_READ to EC_LPC_ADDR_ACPI_CMD
- *    - Wait for EC_LPC_CMDR_PENDING bit to clear
- *    - Write address to EC_LPC_ADDR_ACPI_DATA
- *    - Wait for EC_LPC_CMDR_DATA bit to set
- *    - Read value from EC_LPC_ADDR_ACPI_DATA
- */
-#define EC_CMD_ACPI_READ 0x80
-
-/*
- * ACPI Write Embedded Controller
- *
- * This reads from ACPI memory space on the EC (EC_ACPI_MEM_*).
- *
- * Use the following sequence:
- *
- *    - Write EC_CMD_ACPI_WRITE to EC_LPC_ADDR_ACPI_CMD
- *    - Wait for EC_LPC_CMDR_PENDING bit to clear
- *    - Write address to EC_LPC_ADDR_ACPI_DATA
- *    - Wait for EC_LPC_CMDR_PENDING bit to clear
- *    - Write value to EC_LPC_ADDR_ACPI_DATA
- */
-#define EC_CMD_ACPI_WRITE 0x81
-
-/*
- * ACPI Query Embedded Controller
- *
- * This clears the lowest-order bit in the currently pending host events, and
- * sets the result code to the 1-based index of the bit (event 0x00000001 = 1,
- * event 0x80000000 = 32), or 0 if no event was pending.
- */
-#define EC_CMD_ACPI_QUERY_EVENT 0x84
-
-/* Valid addresses in ACPI memory space, for read/write commands */
-
-/* Memory space version; set to EC_ACPI_MEM_VERSION_CURRENT */
-#define EC_ACPI_MEM_VERSION            0x00
-/*
- * Test location; writing value here updates test compliment byte to (0xff -
- * value).
- */
-#define EC_ACPI_MEM_TEST               0x01
-/* Test compliment; writes here are ignored. */
-#define EC_ACPI_MEM_TEST_COMPLIMENT    0x02
-
-/* Keyboard backlight brightness percent (0 - 100) */
-#define EC_ACPI_MEM_KEYBOARD_BACKLIGHT 0x03
-/* DPTF Target Fan Duty (0-100, 0xff for auto/none) */
-#define EC_ACPI_MEM_FAN_DUTY           0x04
-
-/*
- * DPTF temp thresholds. Any of the EC's temp sensors can have up to two
- * independent thresholds attached to them. The current value of the ID
- * register determines which sensor is affected by the THRESHOLD and COMMIT
- * registers. The THRESHOLD register uses the same EC_TEMP_SENSOR_OFFSET scheme
- * as the memory-mapped sensors. The COMMIT register applies those settings.
- *
- * The spec does not mandate any way to read back the threshold settings
- * themselves, but when a threshold is crossed the AP needs a way to determine
- * which sensor(s) are responsible. Each reading of the ID register clears and
- * returns one sensor ID that has crossed one of its threshold (in either
- * direction) since the last read. A value of 0xFF means "no new thresholds
- * have tripped". Setting or enabling the thresholds for a sensor will clear
- * the unread event count for that sensor.
- */
-#define EC_ACPI_MEM_TEMP_ID            0x05
-#define EC_ACPI_MEM_TEMP_THRESHOLD     0x06
-#define EC_ACPI_MEM_TEMP_COMMIT        0x07
-/*
- * Here are the bits for the COMMIT register:
- *   bit 0 selects the threshold index for the chosen sensor (0/1)
- *   bit 1 enables/disables the selected threshold (0 = off, 1 = on)
- * Each write to the commit register affects one threshold.
- */
-#define EC_ACPI_MEM_TEMP_COMMIT_SELECT_MASK (1 << 0)
-#define EC_ACPI_MEM_TEMP_COMMIT_ENABLE_MASK (1 << 1)
-/*
- * Example:
- *
- * Set the thresholds for sensor 2 to 50 C and 60 C:
- *   write 2 to [0x05]      --  select temp sensor 2
- *   write 0x7b to [0x06]   --  C_TO_K(50) - EC_TEMP_SENSOR_OFFSET
- *   write 0x2 to [0x07]    --  enable threshold 0 with this value
- *   write 0x85 to [0x06]   --  C_TO_K(60) - EC_TEMP_SENSOR_OFFSET
- *   write 0x3 to [0x07]    --  enable threshold 1 with this value
- *
- * Disable the 60 C threshold, leaving the 50 C threshold unchanged:
- *   write 2 to [0x05]      --  select temp sensor 2
- *   write 0x1 to [0x07]    --  disable threshold 1
- */
-
-/* DPTF battery charging current limit */
-#define EC_ACPI_MEM_CHARGING_LIMIT     0x08
-
-/* Charging limit is specified in 64 mA steps */
-#define EC_ACPI_MEM_CHARGING_LIMIT_STEP_MA   64
-/* Value to disable DPTF battery charging limit */
-#define EC_ACPI_MEM_CHARGING_LIMIT_DISABLED  0xff
+struct ec_params_i2c_passthru_protect {
+       uint8_t subcmd;
+       uint8_t port;           /* I2C port number */
+} __ec_align1;
 
-/* Current version of ACPI memory address space */
-#define EC_ACPI_MEM_VERSION_CURRENT 1
+struct ec_response_i2c_passthru_protect {
+       uint8_t status;         /* Status flags (0: unlocked, 1: locked) */
+} __ec_align1;
 
 
 /*****************************************************************************/
@@ -3124,7 +4398,8 @@ struct ec_params_reboot_ec {
  *
  * These commands are for sending and receiving message via HDMI CEC
  */
-#define EC_MAX_CEC_MSG_LEN 16
+
+#define MAX_CEC_MSG_LEN 16
 
 /* CEC message from the AP to be written on the CEC bus */
 #define EC_CMD_CEC_WRITE_MSG 0x00B8
@@ -3134,8 +4409,8 @@ struct ec_params_reboot_ec {
  * @msg: message content to write to the CEC bus
  */
 struct ec_params_cec_write {
-       uint8_t msg[EC_MAX_CEC_MSG_LEN];
-} __packed;
+       uint8_t msg[MAX_CEC_MSG_LEN];
+} __ec_align1;
 
 /* Set various CEC parameters */
 #define EC_CMD_CEC_SET 0x00BA
@@ -3144,14 +4419,14 @@ struct ec_params_cec_write {
  * struct ec_params_cec_set - CEC parameters set
  * @cmd: parameter type, can be CEC_CMD_ENABLE or CEC_CMD_LOGICAL_ADDRESS
  * @val: in case cmd is CEC_CMD_ENABLE, this field can be 0 to disable CEC
- *     or 1 to enable CEC functionality, in case cmd is CEC_CMD_LOGICAL_ADDRESS,
- *     this field encodes the requested logical address between 0 and 15
- *     or 0xff to unregister
+ *     or 1 to enable CEC functionality, in case cmd is
+ *     CEC_CMD_LOGICAL_ADDRESS, this field encodes the requested logical
+ *     address between 0 and 15 or 0xff to unregister
  */
 struct ec_params_cec_set {
        uint8_t cmd; /* enum cec_command */
        uint8_t val;
-} __packed;
+} __ec_align1;
 
 /* Read various CEC parameters */
 #define EC_CMD_CEC_GET 0x00BB
@@ -3162,7 +4437,7 @@ struct ec_params_cec_set {
  */
 struct ec_params_cec_get {
        uint8_t cmd; /* enum cec_command */
-} __packed;
+} __ec_align1;
 
 /**
  * struct ec_response_cec_get - CEC parameters get response
@@ -3173,10 +4448,10 @@ struct ec_params_cec_get {
  */
 struct ec_response_cec_get {
        uint8_t val;
-} __packed;
+} __ec_align1;
 
 /* CEC parameters command */
-enum ec_cec_command {
+enum cec_command {
        /* CEC reading, writing and events enable */
        CEC_CMD_ENABLE,
        /* CEC logical address  */
@@ -3191,6 +4466,134 @@ enum mkbp_cec_event {
        EC_MKBP_CEC_SEND_FAILED                 = BIT(1),
 };
 
+/*****************************************************************************/
+
+/* Commands for I2S recording on audio codec. */
+
+#define EC_CMD_CODEC_I2S 0x00BC
+#define EC_WOV_I2S_SAMPLE_RATE 48000
+
+enum ec_codec_i2s_subcmd {
+       EC_CODEC_SET_SAMPLE_DEPTH = 0x0,
+       EC_CODEC_SET_GAIN = 0x1,
+       EC_CODEC_GET_GAIN = 0x2,
+       EC_CODEC_I2S_ENABLE = 0x3,
+       EC_CODEC_I2S_SET_CONFIG = 0x4,
+       EC_CODEC_I2S_SET_TDM_CONFIG = 0x5,
+       EC_CODEC_I2S_SET_BCLK = 0x6,
+       EC_CODEC_I2S_SUBCMD_COUNT = 0x7,
+};
+
+enum ec_sample_depth_value {
+       EC_CODEC_SAMPLE_DEPTH_16 = 0,
+       EC_CODEC_SAMPLE_DEPTH_24 = 1,
+};
+
+enum ec_i2s_config {
+       EC_DAI_FMT_I2S = 0,
+       EC_DAI_FMT_RIGHT_J = 1,
+       EC_DAI_FMT_LEFT_J = 2,
+       EC_DAI_FMT_PCM_A = 3,
+       EC_DAI_FMT_PCM_B = 4,
+       EC_DAI_FMT_PCM_TDM = 5,
+};
+
+/*
+ * For subcommand EC_CODEC_GET_GAIN.
+ */
+struct __ec_align1 ec_codec_i2s_gain {
+       uint8_t left;
+       uint8_t right;
+};
+
+struct __ec_todo_unpacked ec_param_codec_i2s_tdm {
+       int16_t ch0_delay; /* 0 to 496 */
+       int16_t ch1_delay; /* -1 to 496 */
+       uint8_t adjacent_to_ch0;
+       uint8_t adjacent_to_ch1;
+};
+
+struct __ec_todo_packed ec_param_codec_i2s {
+       /* enum ec_codec_i2s_subcmd */
+       uint8_t cmd;
+       union {
+               /*
+                * EC_CODEC_SET_SAMPLE_DEPTH
+                * Value should be one of ec_sample_depth_value.
+                */
+               uint8_t depth;
+
+               /*
+                * EC_CODEC_SET_GAIN
+                * Value should be 0~43 for both channels.
+                */
+               struct ec_codec_i2s_gain gain;
+
+               /*
+                * EC_CODEC_I2S_ENABLE
+                * 1 to enable, 0 to disable.
+                */
+               uint8_t i2s_enable;
+
+               /*
+                * EC_CODEC_I2S_SET_CONFIG
+                * Value should be one of ec_i2s_config.
+                */
+               uint8_t i2s_config;
+
+               /*
+                * EC_CODEC_I2S_SET_TDM_CONFIG
+                * Value should be one of ec_i2s_config.
+                */
+               struct ec_param_codec_i2s_tdm tdm_param;
+
+               /*
+                * EC_CODEC_I2S_SET_BCLK
+                */
+               uint32_t bclk;
+       };
+};
+
+
+/*****************************************************************************/
+/* System commands */
+
+/*
+ * TODO(crosbug.com/p/23747): This is a confusing name, since it doesn't
+ * necessarily reboot the EC.  Rename to "image" or something similar?
+ */
+#define EC_CMD_REBOOT_EC 0x00D2
+
+/* Command */
+enum ec_reboot_cmd {
+       EC_REBOOT_CANCEL = 0,        /* Cancel a pending reboot */
+       EC_REBOOT_JUMP_RO = 1,       /* Jump to RO without rebooting */
+       EC_REBOOT_JUMP_RW = 2,       /* Jump to active RW without rebooting */
+       /* (command 3 was jump to RW-B) */
+       EC_REBOOT_COLD = 4,          /* Cold-reboot */
+       EC_REBOOT_DISABLE_JUMP = 5,  /* Disable jump until next reboot */
+       EC_REBOOT_HIBERNATE = 6,     /* Hibernate EC */
+       EC_REBOOT_HIBERNATE_CLEAR_AP_OFF = 7, /* and clears AP_OFF flag */
+};
+
+/* Flags for ec_params_reboot_ec.reboot_flags */
+#define EC_REBOOT_FLAG_RESERVED0      BIT(0)  /* Was recovery request */
+#define EC_REBOOT_FLAG_ON_AP_SHUTDOWN BIT(1)  /* Reboot after AP shutdown */
+#define EC_REBOOT_FLAG_SWITCH_RW_SLOT BIT(2)  /* Switch RW slot */
+
+struct ec_params_reboot_ec {
+       uint8_t cmd;           /* enum ec_reboot_cmd */
+       uint8_t flags;         /* See EC_REBOOT_FLAG_* */
+} __ec_align1;
+
+/*
+ * Get information on last EC panic.
+ *
+ * Returns variable-length platform-dependent panic information.  See panic.h
+ * for details.
+ */
+#define EC_CMD_GET_PANIC_INFO 0x00D3
+
 /*****************************************************************************/
 /*
  * Special commands
@@ -3208,7 +4611,7 @@ enum mkbp_cec_event {
  *
  * Use EC_CMD_REBOOT_EC to reboot the EC more politely.
  */
-#define EC_CMD_REBOOT 0xd1  /* Think "die" */
+#define EC_CMD_REBOOT 0x00D1  /* Think "die" */
 
 /*
  * Resend last response (not supported on LPC).
@@ -3217,7 +4620,7 @@ enum mkbp_cec_event {
  * there was no previous command, or the previous command's response was too
  * big to save.
  */
-#define EC_CMD_RESEND_RESPONSE 0xdb
+#define EC_CMD_RESEND_RESPONSE 0x00DB
 
 /*
  * This header byte on a command indicate version 0. Any header byte less
@@ -3229,9 +4632,7 @@ enum mkbp_cec_event {
  *
  * The old EC interface must not use commands 0xdc or higher.
  */
-#define EC_CMD_VERSION0 0xdc
-
-#endif  /* !__ACPI__ */
+#define EC_CMD_VERSION0 0x00DC
 
 /*****************************************************************************/
 /*
@@ -3241,21 +4642,56 @@ enum mkbp_cec_event {
  */
 
 /* EC to PD MCU exchange status command */
-#define EC_CMD_PD_EXCHANGE_STATUS 0x100
+#define EC_CMD_PD_EXCHANGE_STATUS 0x0100
+#define EC_VER_PD_EXCHANGE_STATUS 2
+
+enum pd_charge_state {
+       PD_CHARGE_NO_CHANGE = 0, /* Don't change charge state */
+       PD_CHARGE_NONE,          /* No charging allowed */
+       PD_CHARGE_5V,            /* 5V charging only */
+       PD_CHARGE_MAX            /* Charge at max voltage */
+};
 
 /* Status of EC being sent to PD */
+#define EC_STATUS_HIBERNATING  BIT(0)
+
 struct ec_params_pd_status {
-       int8_t batt_soc; /* battery state of charge */
-} __packed;
+       uint8_t status;       /* EC status */
+       int8_t batt_soc;      /* battery state of charge */
+       uint8_t charge_state; /* charging state (from enum pd_charge_state) */
+} __ec_align1;
 
 /* Status of PD being sent back to EC */
+#define PD_STATUS_HOST_EVENT      BIT(0) /* Forward host event to AP */
+#define PD_STATUS_IN_RW           BIT(1) /* Running RW image */
+#define PD_STATUS_JUMPED_TO_IMAGE BIT(2) /* Current image was jumped to */
+#define PD_STATUS_TCPC_ALERT_0    BIT(3) /* Alert active in port 0 TCPC */
+#define PD_STATUS_TCPC_ALERT_1    BIT(4) /* Alert active in port 1 TCPC */
+#define PD_STATUS_TCPC_ALERT_2    BIT(5) /* Alert active in port 2 TCPC */
+#define PD_STATUS_TCPC_ALERT_3    BIT(6) /* Alert active in port 3 TCPC */
+#define PD_STATUS_EC_INT_ACTIVE  (PD_STATUS_TCPC_ALERT_0 | \
+                                     PD_STATUS_TCPC_ALERT_1 | \
+                                     PD_STATUS_HOST_EVENT)
 struct ec_response_pd_status {
-       int8_t status;        /* PD MCU status */
-       uint32_t curr_lim_ma; /* input current limit */
-} __packed;
+       uint32_t curr_lim_ma;       /* input current limit */
+       uint16_t status;            /* PD MCU status */
+       int8_t active_charge_port;  /* active charging port */
+} __ec_align_size1;
+
+/* AP to PD MCU host event status command, cleared on read */
+#define EC_CMD_PD_HOST_EVENT_STATUS 0x0104
+
+/* PD MCU host event status bits */
+#define PD_EVENT_UPDATE_DEVICE     BIT(0)
+#define PD_EVENT_POWER_CHANGE      BIT(1)
+#define PD_EVENT_IDENTITY_RECEIVED BIT(2)
+#define PD_EVENT_DATA_SWAP         BIT(3)
+struct ec_response_host_event_status {
+       uint32_t status;      /* PD MCU host event status */
+} __ec_align4;
 
 /* Set USB type-C port role and muxes */
-#define EC_CMD_USB_PD_CONTROL 0x101
+#define EC_CMD_USB_PD_CONTROL 0x0101
 
 enum usb_pd_control_role {
        USB_PD_CTRL_ROLE_NO_CHANGE = 0,
@@ -3263,6 +4699,8 @@ enum usb_pd_control_role {
        USB_PD_CTRL_ROLE_TOGGLE_OFF = 2,
        USB_PD_CTRL_ROLE_FORCE_SINK = 3,
        USB_PD_CTRL_ROLE_FORCE_SOURCE = 4,
+       USB_PD_CTRL_ROLE_FREEZE = 5,
+       USB_PD_CTRL_ROLE_COUNT
 };
 
 enum usb_pd_control_mux {
@@ -3272,6 +4710,7 @@ enum usb_pd_control_mux {
        USB_PD_CTRL_MUX_DP = 3,
        USB_PD_CTRL_MUX_DOCK = 4,
        USB_PD_CTRL_MUX_AUTO = 5,
+       USB_PD_CTRL_MUX_COUNT
 };
 
 enum usb_pd_control_swap {
@@ -3287,11 +4726,11 @@ struct ec_params_usb_pd_control {
        uint8_t role;
        uint8_t mux;
        uint8_t swap;
-} __packed;
+} __ec_align1;
 
-#define PD_CTRL_RESP_ENABLED_COMMS      (1 << 0) /* Communication enabled */
-#define PD_CTRL_RESP_ENABLED_CONNECTED  (1 << 1) /* Device connected */
-#define PD_CTRL_RESP_ENABLED_PD_CAPABLE (1 << 2) /* Partner is PD capable */
+#define PD_CTRL_RESP_ENABLED_COMMS      BIT(0) /* Communication enabled */
+#define PD_CTRL_RESP_ENABLED_CONNECTED  BIT(1) /* Device connected */
+#define PD_CTRL_RESP_ENABLED_PD_CAPABLE BIT(2) /* Partner is PD capable */
 
 #define PD_CTRL_RESP_ROLE_POWER         BIT(0) /* 0=SNK/1=SRC */
 #define PD_CTRL_RESP_ROLE_DATA          BIT(1) /* 0=UFP/1=DFP */
@@ -3301,28 +4740,54 @@ struct ec_params_usb_pd_control {
 #define PD_CTRL_RESP_ROLE_USB_COMM      BIT(5) /* Partner USB comm capable */
 #define PD_CTRL_RESP_ROLE_EXT_POWERED   BIT(6) /* Partner externally powerd */
 
+struct ec_response_usb_pd_control {
+       uint8_t enabled;
+       uint8_t role;
+       uint8_t polarity;
+       uint8_t state;
+} __ec_align1;
+
 struct ec_response_usb_pd_control_v1 {
        uint8_t enabled;
        uint8_t role;
        uint8_t polarity;
        char state[32];
-} __packed;
+} __ec_align1;
+
+/* Values representing usbc PD CC state */
+#define USBC_PD_CC_NONE                0 /* No accessory connected */
+#define USBC_PD_CC_NO_UFP      1 /* No UFP accessory connected */
+#define USBC_PD_CC_AUDIO_ACC   2 /* Audio accessory connected */
+#define USBC_PD_CC_DEBUG_ACC   3 /* Debug accessory connected */
+#define USBC_PD_CC_UFP_ATTACHED        4 /* UFP attached to usbc */
+#define USBC_PD_CC_DFP_ATTACHED        5 /* DPF attached to usbc */
+
+struct ec_response_usb_pd_control_v2 {
+       uint8_t enabled;
+       uint8_t role;
+       uint8_t polarity;
+       char state[32];
+       uint8_t cc_state; /* USBC_PD_CC_*Encoded cc state */
+       uint8_t dp_mode;  /* Current DP pin mode (MODE_DP_PIN_[A-E]) */
+       /* CL:1500994 Current cable type */
+       uint8_t reserved_cable_type;
+} __ec_align1;
 
-#define EC_CMD_USB_PD_PORTS 0x102
+#define EC_CMD_USB_PD_PORTS 0x0102
 
 /* Maximum number of PD ports on a device, num_ports will be <= this */
 #define EC_USB_PD_MAX_PORTS 8
 
 struct ec_response_usb_pd_ports {
        uint8_t num_ports;
-} __packed;
+} __ec_align1;
 
-#define EC_CMD_USB_PD_POWER_INFO 0x103
+#define EC_CMD_USB_PD_POWER_INFO 0x0103
 
 #define PD_POWER_CHARGING_PORT 0xff
 struct ec_params_usb_pd_power_info {
        uint8_t port;
-} __packed;
+} __ec_align1;
 
 enum usb_chg_type {
        USB_CHG_TYPE_NONE,
@@ -3335,6 +4800,7 @@ enum usb_chg_type {
        USB_CHG_TYPE_OTHER,
        USB_CHG_TYPE_VBUS,
        USB_CHG_TYPE_UNKNOWN,
+       USB_CHG_TYPE_DEDICATED,
 };
 enum usb_power_roles {
        USB_PD_PORT_POWER_DISCONNECTED,
@@ -3348,7 +4814,7 @@ struct usb_chg_measures {
        uint16_t voltage_now;
        uint16_t current_max;
        uint16_t current_lim;
-} __packed;
+} __ec_align2;
 
 struct ec_response_usb_pd_power_info {
        uint8_t role;
@@ -3357,11 +4823,8 @@ struct ec_response_usb_pd_power_info {
        uint8_t reserved1;
        struct usb_chg_measures meas;
        uint32_t max_power;
-} __packed;
+} __ec_align4;
 
-struct ec_params_usb_pd_info_request {
-       uint8_t port;
-} __packed;
 
 /*
  * This command will return the number of USB PD charge port + the number
@@ -3371,7 +4834,47 @@ struct ec_params_usb_pd_info_request {
 #define EC_CMD_CHARGE_PORT_COUNT 0x0105
 struct ec_response_charge_port_count {
        uint8_t port_count;
-} __packed;
+} __ec_align1;
+
+/* Write USB-PD device FW */
+#define EC_CMD_USB_PD_FW_UPDATE 0x0110
+
+enum usb_pd_fw_update_cmds {
+       USB_PD_FW_REBOOT,
+       USB_PD_FW_FLASH_ERASE,
+       USB_PD_FW_FLASH_WRITE,
+       USB_PD_FW_ERASE_SIG,
+};
+
+struct ec_params_usb_pd_fw_update {
+       uint16_t dev_id;
+       uint8_t cmd;
+       uint8_t port;
+       uint32_t size;     /* Size to write in bytes */
+       /* Followed by data to write */
+} __ec_align4;
+
+/* Write USB-PD Accessory RW_HASH table entry */
+#define EC_CMD_USB_PD_RW_HASH_ENTRY 0x0111
+/* RW hash is first 20 bytes of SHA-256 of RW section */
+#define PD_RW_HASH_SIZE 20
+struct ec_params_usb_pd_rw_hash_entry {
+       uint16_t dev_id;
+       uint8_t dev_rw_hash[PD_RW_HASH_SIZE];
+       uint8_t reserved;        /*
+                                 * For alignment of current_image
+                                 * TODO(rspangler) but it's not aligned!
+                                 * Should have been reserved[2].
+                                 */
+       uint32_t current_image;  /* One of ec_current_image */
+} __ec_align1;
+
+/* Read USB-PD Accessory info */
+#define EC_CMD_USB_PD_DEV_INFO 0x0112
+
+struct ec_params_usb_pd_info_request {
+       uint8_t port;
+} __ec_align1;
 
 /* Read USB-PD Device discovery info */
 #define EC_CMD_USB_PD_DISCOVERY 0x0113
@@ -3379,7 +4882,7 @@ struct ec_params_usb_pd_discovery_entry {
        uint16_t vid;  /* USB-IF VID */
        uint16_t pid;  /* USB-IF PID */
        uint8_t ptype; /* product type (hub,periph,cable,ama) */
-} __packed;
+} __ec_align_size1;
 
 /* Override default charge behavior */
 #define EC_CMD_PD_CHARGE_PORT_OVERRIDE 0x0114
@@ -3393,9 +4896,13 @@ enum usb_pd_override_ports {
 
 struct ec_params_charge_port_override {
        int16_t override_port; /* Override port# */
-} __packed;
+} __ec_align2;
 
-/* Read (and delete) one entry of PD event log */
+/*
+ * Read (and delete) one entry of PD event log.
+ * TODO(crbug.com/751742): Make this host command more generic to accommodate
+ * future non-PD logs that use the same internal EC event_log.
+ */
 #define EC_CMD_PD_GET_LOG_ENTRY 0x0115
 
 struct ec_response_pd_log {
@@ -3404,7 +4911,7 @@ struct ec_response_pd_log {
        uint8_t size_port;  /* [7:5] port number [4:0] payload size in bytes */
        uint16_t data;      /* type-defined data payload */
        uint8_t payload[0]; /* optional additional data payload: 0..16 bytes */
-} __packed;
+} __ec_align4;
 
 /* The timestamp is the microsecond counter shifted to get about a ms. */
 #define PD_LOG_TIMESTAMP_SHIFT 10 /* 1 LSB = 1024us */
@@ -3470,35 +4977,698 @@ struct mcdp_version {
        uint8_t major;
        uint8_t minor;
        uint16_t build;
-} __packed;
+} __ec_align4;
 
 struct mcdp_info {
        uint8_t family[2];
        uint8_t chipid[2];
        struct mcdp_version irom;
        struct mcdp_version fw;
-} __packed;
+} __ec_align4;
 
 /* struct mcdp_info field decoding */
 #define MCDP_CHIPID(chipid) ((chipid[0] << 8) | chipid[1])
 #define MCDP_FAMILY(family) ((family[0] << 8) | family[1])
 
+/* Get/Set USB-PD Alternate mode info */
+#define EC_CMD_USB_PD_GET_AMODE 0x0116
+struct ec_params_usb_pd_get_mode_request {
+       uint16_t svid_idx; /* SVID index to get */
+       uint8_t port;      /* port */
+} __ec_align_size1;
+
+struct ec_params_usb_pd_get_mode_response {
+       uint16_t svid;   /* SVID */
+       uint16_t opos;    /* Object Position */
+       uint32_t vdo[6]; /* Mode VDOs */
+} __ec_align4;
+
+#define EC_CMD_USB_PD_SET_AMODE 0x0117
+
+enum pd_mode_cmd {
+       PD_EXIT_MODE = 0,
+       PD_ENTER_MODE = 1,
+       /* Not a command.  Do NOT remove. */
+       PD_MODE_CMD_COUNT,
+};
+
+struct ec_params_usb_pd_set_mode_request {
+       uint32_t cmd;  /* enum pd_mode_cmd */
+       uint16_t svid; /* SVID to set */
+       uint8_t opos;  /* Object Position */
+       uint8_t port;  /* port */
+} __ec_align4;
+
+/* Ask the PD MCU to record a log of a requested type */
+#define EC_CMD_PD_WRITE_LOG_ENTRY 0x0118
+
+struct ec_params_pd_write_log_entry {
+       uint8_t type; /* event type : see PD_EVENT_xx above */
+       uint8_t port; /* port#, or 0 for events unrelated to a given port */
+} __ec_align1;
+
+
+/* Control USB-PD chip */
+#define EC_CMD_PD_CONTROL 0x0119
+
+enum ec_pd_control_cmd {
+       PD_SUSPEND = 0,      /* Suspend the PD chip (EC: stop talking to PD) */
+       PD_RESUME,           /* Resume the PD chip (EC: start talking to PD) */
+       PD_RESET,            /* Force reset the PD chip */
+       PD_CONTROL_DISABLE,  /* Disable further calls to this command */
+       PD_CHIP_ON,          /* Power on the PD chip */
+};
+
+struct ec_params_pd_control {
+       uint8_t chip;         /* chip id */
+       uint8_t subcmd;
+} __ec_align1;
+
 /* Get info about USB-C SS muxes */
-#define EC_CMD_USB_PD_MUX_INFO 0x11a
+#define EC_CMD_USB_PD_MUX_INFO 0x011A
 
 struct ec_params_usb_pd_mux_info {
        uint8_t port; /* USB-C port number */
-} __packed;
+} __ec_align1;
 
 /* Flags representing mux state */
-#define USB_PD_MUX_USB_ENABLED       (1 << 0)
-#define USB_PD_MUX_DP_ENABLED        (1 << 1)
-#define USB_PD_MUX_POLARITY_INVERTED (1 << 2)
-#define USB_PD_MUX_HPD_IRQ           (1 << 3)
+#define USB_PD_MUX_USB_ENABLED       BIT(0) /* USB connected */
+#define USB_PD_MUX_DP_ENABLED        BIT(1) /* DP connected */
+#define USB_PD_MUX_POLARITY_INVERTED BIT(2) /* CC line Polarity inverted */
+#define USB_PD_MUX_HPD_IRQ           BIT(3) /* HPD IRQ is asserted */
+#define USB_PD_MUX_HPD_LVL           BIT(4) /* HPD level is asserted */
 
 struct ec_response_usb_pd_mux_info {
        uint8_t flags; /* USB_PD_MUX_*-encoded USB mux state */
-} __packed;
+} __ec_align1;
+
+#define EC_CMD_PD_CHIP_INFO            0x011B
+
+struct ec_params_pd_chip_info {
+       uint8_t port;   /* USB-C port number */
+       uint8_t renew;  /* Force renewal */
+} __ec_align1;
+
+struct ec_response_pd_chip_info {
+       uint16_t vendor_id;
+       uint16_t product_id;
+       uint16_t device_id;
+       union {
+               uint8_t fw_version_string[8];
+               uint64_t fw_version_number;
+       };
+} __ec_align2;
+
+struct ec_response_pd_chip_info_v1 {
+       uint16_t vendor_id;
+       uint16_t product_id;
+       uint16_t device_id;
+       union {
+               uint8_t fw_version_string[8];
+               uint64_t fw_version_number;
+       };
+       union {
+               uint8_t min_req_fw_version_string[8];
+               uint64_t min_req_fw_version_number;
+       };
+} __ec_align2;
+
+/* Run RW signature verification and get status */
+#define EC_CMD_RWSIG_CHECK_STATUS      0x011C
+
+struct ec_response_rwsig_check_status {
+       uint32_t status;
+} __ec_align4;
+
+/* For controlling RWSIG task */
+#define EC_CMD_RWSIG_ACTION    0x011D
+
+enum rwsig_action {
+       RWSIG_ACTION_ABORT = 0,         /* Abort RWSIG and prevent jumping */
+       RWSIG_ACTION_CONTINUE = 1,      /* Jump to RW immediately */
+};
+
+struct ec_params_rwsig_action {
+       uint32_t action;
+} __ec_align4;
+
+/* Run verification on a slot */
+#define EC_CMD_EFS_VERIFY      0x011E
+
+struct ec_params_efs_verify {
+       uint8_t region;         /* enum ec_flash_region */
+} __ec_align1;
+
+/*
+ * Retrieve info from Cros Board Info store. Response is based on the data
+ * type. Integers return a uint32. Strings return a string, using the response
+ * size to determine how big it is.
+ */
+#define EC_CMD_GET_CROS_BOARD_INFO     0x011F
+/*
+ * Write info into Cros Board Info on EEPROM. Write fails if the board has
+ * hardware write-protect enabled.
+ */
+#define EC_CMD_SET_CROS_BOARD_INFO     0x0120
+
+enum cbi_data_tag {
+       CBI_TAG_BOARD_VERSION = 0, /* uint32_t or smaller */
+       CBI_TAG_OEM_ID = 1,        /* uint32_t or smaller */
+       CBI_TAG_SKU_ID = 2,        /* uint32_t or smaller */
+       CBI_TAG_DRAM_PART_NUM = 3, /* variable length ascii, nul terminated. */
+       CBI_TAG_OEM_NAME = 4,      /* variable length ascii, nul terminated. */
+       CBI_TAG_MODEL_ID = 5,      /* uint32_t or smaller */
+       CBI_TAG_COUNT,
+};
+
+/*
+ * Flags to control read operation
+ *
+ * RELOAD:  Invalidate cache and read data from EEPROM. Useful to verify
+ *          write was successful without reboot.
+ */
+#define CBI_GET_RELOAD         BIT(0)
+
+struct ec_params_get_cbi {
+       uint32_t tag;           /* enum cbi_data_tag */
+       uint32_t flag;          /* CBI_GET_* */
+} __ec_align4;
+
+/*
+ * Flags to control write behavior.
+ *
+ * NO_SYNC: Makes EC update data in RAM but skip writing to EEPROM. It's
+ *          useful when writing multiple fields in a row.
+ * INIT:    Need to be set when creating a new CBI from scratch. All fields
+ *          will be initialized to zero first.
+ */
+#define CBI_SET_NO_SYNC                BIT(0)
+#define CBI_SET_INIT           BIT(1)
+
+struct ec_params_set_cbi {
+       uint32_t tag;           /* enum cbi_data_tag */
+       uint32_t flag;          /* CBI_SET_* */
+       uint32_t size;          /* Data size */
+       uint8_t data[];         /* For string and raw data */
+} __ec_align1;
+
+/*
+ * Information about resets of the AP by the EC and the EC's own uptime.
+ */
+#define EC_CMD_GET_UPTIME_INFO 0x0121
+
+struct ec_response_uptime_info {
+       /*
+        * Number of milliseconds since the last EC boot. Sysjump resets
+        * typically do not restart the EC's time_since_boot epoch.
+        *
+        * WARNING: The EC's sense of time is much less accurate than the AP's
+        * sense of time, in both phase and frequency.  This timebase is similar
+        * to CLOCK_MONOTONIC_RAW, but with 1% or more frequency error.
+        */
+       uint32_t time_since_ec_boot_ms;
+
+       /*
+        * Number of times the AP was reset by the EC since the last EC boot.
+        * Note that the AP may be held in reset by the EC during the initial
+        * boot sequence, such that the very first AP boot may count as more
+        * than one here.
+        */
+       uint32_t ap_resets_since_ec_boot;
+
+       /*
+        * The set of flags which describe the EC's most recent reset.  See
+        * include/system.h RESET_FLAG_* for details.
+        */
+       uint32_t ec_reset_flags;
+
+       /* Empty log entries have both the cause and timestamp set to zero. */
+       struct ap_reset_log_entry {
+               /*
+                * See include/chipset.h: enum chipset_{reset,shutdown}_reason
+                * for details.
+                */
+               uint16_t reset_cause;
+
+               /* Reserved for protocol growth. */
+               uint16_t reserved;
+
+               /*
+                * The time of the reset's assertion, in milliseconds since the
+                * last EC boot, in the same epoch as time_since_ec_boot_ms.
+                * Set to zero if the log entry is empty.
+                */
+               uint32_t reset_time_ms;
+       } recent_ap_reset[4];
+} __ec_align4;
+
+/*
+ * Add entropy to the device secret (stored in the rollback region).
+ *
+ * Depending on the chip, the operation may take a long time (e.g. to erase
+ * flash), so the commands are asynchronous.
+ */
+#define EC_CMD_ADD_ENTROPY     0x0122
+
+enum add_entropy_action {
+       /* Add entropy to the current secret. */
+       ADD_ENTROPY_ASYNC = 0,
+       /*
+        * Add entropy, and also make sure that the previous secret is erased.
+        * (this can be implemented by adding entropy multiple times until
+        * all rolback blocks have been overwritten).
+        */
+       ADD_ENTROPY_RESET_ASYNC = 1,
+       /* Read back result from the previous operation. */
+       ADD_ENTROPY_GET_RESULT = 2,
+};
+
+struct ec_params_rollback_add_entropy {
+       uint8_t action;
+} __ec_align1;
+
+/*
+ * Perform a single read of a given ADC channel.
+ */
+#define EC_CMD_ADC_READ                0x0123
+
+struct ec_params_adc_read {
+       uint8_t adc_channel;
+} __ec_align1;
+
+struct ec_response_adc_read {
+       int32_t adc_value;
+} __ec_align4;
+
+/*
+ * Read back rollback info
+ */
+#define EC_CMD_ROLLBACK_INFO           0x0124
+
+struct ec_response_rollback_info {
+       int32_t id; /* Incrementing number to indicate which region to use. */
+       int32_t rollback_min_version;
+       int32_t rw_rollback_version;
+} __ec_align4;
+
+
+/* Issue AP reset */
+#define EC_CMD_AP_RESET 0x0125
+
+/*****************************************************************************/
+/* The command range 0x200-0x2FF is reserved for Rotor. */
+
+/*****************************************************************************/
+/*
+ * Reserve a range of host commands for the CR51 firmware.
+ */
+#define EC_CMD_CR51_BASE 0x0300
+#define EC_CMD_CR51_LAST 0x03FF
+
+/*****************************************************************************/
+/* Fingerprint MCU commands: range 0x0400-0x040x */
+
+/* Fingerprint SPI sensor passthru command: prototyping ONLY */
+#define EC_CMD_FP_PASSTHRU 0x0400
+
+#define EC_FP_FLAG_NOT_COMPLETE 0x1
+
+struct ec_params_fp_passthru {
+       uint16_t len;           /* Number of bytes to write then read */
+       uint16_t flags;         /* EC_FP_FLAG_xxx */
+       uint8_t data[];         /* Data to send */
+} __ec_align2;
+
+/* Configure the Fingerprint MCU behavior */
+#define EC_CMD_FP_MODE 0x0402
+
+/* Put the sensor in its lowest power mode */
+#define FP_MODE_DEEPSLEEP      BIT(0)
+/* Wait to see a finger on the sensor */
+#define FP_MODE_FINGER_DOWN    BIT(1)
+/* Poll until the finger has left the sensor */
+#define FP_MODE_FINGER_UP      BIT(2)
+/* Capture the current finger image */
+#define FP_MODE_CAPTURE        BIT(3)
+/* Finger enrollment session on-going */
+#define FP_MODE_ENROLL_SESSION BIT(4)
+/* Enroll the current finger image */
+#define FP_MODE_ENROLL_IMAGE   BIT(5)
+/* Try to match the current finger image */
+#define FP_MODE_MATCH          BIT(6)
+/* Reset and re-initialize the sensor. */
+#define FP_MODE_RESET_SENSOR   BIT(7)
+/* special value: don't change anything just read back current mode */
+#define FP_MODE_DONT_CHANGE    BIT(31)
+
+#define FP_VALID_MODES (FP_MODE_DEEPSLEEP      | \
+                       FP_MODE_FINGER_DOWN    | \
+                       FP_MODE_FINGER_UP      | \
+                       FP_MODE_CAPTURE        | \
+                       FP_MODE_ENROLL_SESSION | \
+                       FP_MODE_ENROLL_IMAGE   | \
+                       FP_MODE_MATCH          | \
+                       FP_MODE_RESET_SENSOR   | \
+                       FP_MODE_DONT_CHANGE)
+
+/* Capture types defined in bits [30..28] */
+#define FP_MODE_CAPTURE_TYPE_SHIFT 28
+#define FP_MODE_CAPTURE_TYPE_MASK  (0x7 << FP_MODE_CAPTURE_TYPE_SHIFT)
+/*
+ * This enum must remain ordered, if you add new values you must ensure that
+ * FP_CAPTURE_TYPE_MAX is still the last one.
+ */
+enum fp_capture_type {
+       /* Full blown vendor-defined capture (produces 'frame_size' bytes) */
+       FP_CAPTURE_VENDOR_FORMAT = 0,
+       /* Simple raw image capture (produces width x height x bpp bits) */
+       FP_CAPTURE_SIMPLE_IMAGE = 1,
+       /* Self test pattern (e.g. checkerboard) */
+       FP_CAPTURE_PATTERN0 = 2,
+       /* Self test pattern (e.g. inverted checkerboard) */
+       FP_CAPTURE_PATTERN1 = 3,
+       /* Capture for Quality test with fixed contrast */
+       FP_CAPTURE_QUALITY_TEST = 4,
+       /* Capture for pixel reset value test */
+       FP_CAPTURE_RESET_TEST = 5,
+       FP_CAPTURE_TYPE_MAX,
+};
+/* Extracts the capture type from the sensor 'mode' word */
+#define FP_CAPTURE_TYPE(mode) (((mode) & FP_MODE_CAPTURE_TYPE_MASK) \
+                                      >> FP_MODE_CAPTURE_TYPE_SHIFT)
+
+struct ec_params_fp_mode {
+       uint32_t mode; /* as defined by FP_MODE_ constants */
+} __ec_align4;
+
+struct ec_response_fp_mode {
+       uint32_t mode; /* as defined by FP_MODE_ constants */
+} __ec_align4;
+
+/* Retrieve Fingerprint sensor information */
+#define EC_CMD_FP_INFO 0x0403
+
+/* Number of dead pixels detected on the last maintenance */
+#define FP_ERROR_DEAD_PIXELS(errors) ((errors) & 0x3FF)
+/* Unknown number of dead pixels detected on the last maintenance */
+#define FP_ERROR_DEAD_PIXELS_UNKNOWN (0x3FF)
+/* No interrupt from the sensor */
+#define FP_ERROR_NO_IRQ    BIT(12)
+/* SPI communication error */
+#define FP_ERROR_SPI_COMM  BIT(13)
+/* Invalid sensor Hardware ID */
+#define FP_ERROR_BAD_HWID  BIT(14)
+/* Sensor initialization failed */
+#define FP_ERROR_INIT_FAIL BIT(15)
+
+struct ec_response_fp_info_v0 {
+       /* Sensor identification */
+       uint32_t vendor_id;
+       uint32_t product_id;
+       uint32_t model_id;
+       uint32_t version;
+       /* Image frame characteristics */
+       uint32_t frame_size;
+       uint32_t pixel_format; /* using V4L2_PIX_FMT_ */
+       uint16_t width;
+       uint16_t height;
+       uint16_t bpp;
+       uint16_t errors; /* see FP_ERROR_ flags above */
+} __ec_align4;
+
+struct ec_response_fp_info {
+       /* Sensor identification */
+       uint32_t vendor_id;
+       uint32_t product_id;
+       uint32_t model_id;
+       uint32_t version;
+       /* Image frame characteristics */
+       uint32_t frame_size;
+       uint32_t pixel_format; /* using V4L2_PIX_FMT_ */
+       uint16_t width;
+       uint16_t height;
+       uint16_t bpp;
+       uint16_t errors; /* see FP_ERROR_ flags above */
+       /* Template/finger current information */
+       uint32_t template_size;  /* max template size in bytes */
+       uint16_t template_max;   /* maximum number of fingers/templates */
+       uint16_t template_valid; /* number of valid fingers/templates */
+       uint32_t template_dirty; /* bitmap of templates with MCU side changes */
+       uint32_t template_version; /* version of the template format */
+} __ec_align4;
+
+/* Get the last captured finger frame or a template content */
+#define EC_CMD_FP_FRAME 0x0404
+
+/* constants defining the 'offset' field which also contains the frame index */
+#define FP_FRAME_INDEX_SHIFT       28
+/* Frame buffer where the captured image is stored */
+#define FP_FRAME_INDEX_RAW_IMAGE    0
+/* First frame buffer holding a template */
+#define FP_FRAME_INDEX_TEMPLATE     1
+#define FP_FRAME_GET_BUFFER_INDEX(offset) ((offset) >> FP_FRAME_INDEX_SHIFT)
+#define FP_FRAME_OFFSET_MASK       0x0FFFFFFF
+
+/* Version of the format of the encrypted templates. */
+#define FP_TEMPLATE_FORMAT_VERSION 3
+
+/* Constants for encryption parameters */
+#define FP_CONTEXT_NONCE_BYTES 12
+#define FP_CONTEXT_USERID_WORDS (32 / sizeof(uint32_t))
+#define FP_CONTEXT_TAG_BYTES 16
+#define FP_CONTEXT_SALT_BYTES 16
+#define FP_CONTEXT_TPM_BYTES 32
+
+struct ec_fp_template_encryption_metadata {
+       /*
+        * Version of the structure format (N=3).
+        */
+       uint16_t struct_version;
+       /* Reserved bytes, set to 0. */
+       uint16_t reserved;
+       /*
+        * The salt is *only* ever used for key derivation. The nonce is unique,
+        * a different one is used for every message.
+        */
+       uint8_t nonce[FP_CONTEXT_NONCE_BYTES];
+       uint8_t salt[FP_CONTEXT_SALT_BYTES];
+       uint8_t tag[FP_CONTEXT_TAG_BYTES];
+};
+
+struct ec_params_fp_frame {
+       /*
+        * The offset contains the template index or FP_FRAME_INDEX_RAW_IMAGE
+        * in the high nibble, and the real offset within the frame in
+        * FP_FRAME_OFFSET_MASK.
+        */
+       uint32_t offset;
+       uint32_t size;
+} __ec_align4;
+
+/* Load a template into the MCU */
+#define EC_CMD_FP_TEMPLATE 0x0405
+
+/* Flag in the 'size' field indicating that the full template has been sent */
+#define FP_TEMPLATE_COMMIT 0x80000000
+
+struct ec_params_fp_template {
+       uint32_t offset;
+       uint32_t size;
+       uint8_t data[];
+} __ec_align4;
+
+/* Clear the current fingerprint user context and set a new one */
+#define EC_CMD_FP_CONTEXT 0x0406
+
+struct ec_params_fp_context {
+       uint32_t userid[FP_CONTEXT_USERID_WORDS];
+} __ec_align4;
+
+#define EC_CMD_FP_STATS 0x0407
+
+#define FPSTATS_CAPTURE_INV  BIT(0)
+#define FPSTATS_MATCHING_INV BIT(1)
+
+struct ec_response_fp_stats {
+       uint32_t capture_time_us;
+       uint32_t matching_time_us;
+       uint32_t overall_time_us;
+       struct {
+               uint32_t lo;
+               uint32_t hi;
+       } overall_t0;
+       uint8_t timestamps_invalid;
+       int8_t template_matched;
+} __ec_align2;
+
+#define EC_CMD_FP_SEED 0x0408
+struct ec_params_fp_seed {
+       /*
+        * Version of the structure format (N=3).
+        */
+       uint16_t struct_version;
+       /* Reserved bytes, set to 0. */
+       uint16_t reserved;
+       /* Seed from the TPM. */
+       uint8_t seed[FP_CONTEXT_TPM_BYTES];
+} __ec_align4;
+
+/*****************************************************************************/
+/* Touchpad MCU commands: range 0x0500-0x05FF */
+
+/* Perform touchpad self test */
+#define EC_CMD_TP_SELF_TEST 0x0500
+
+/* Get number of frame types, and the size of each type */
+#define EC_CMD_TP_FRAME_INFO 0x0501
+
+struct ec_response_tp_frame_info {
+       uint32_t n_frames;
+       uint32_t frame_sizes[0];
+} __ec_align4;
+
+/* Create a snapshot of current frame readings */
+#define EC_CMD_TP_FRAME_SNAPSHOT 0x0502
+
+/* Read the frame */
+#define EC_CMD_TP_FRAME_GET 0x0503
+
+struct ec_params_tp_frame_get {
+       uint32_t frame_index;
+       uint32_t offset;
+       uint32_t size;
+} __ec_align4;
+
+/*****************************************************************************/
+/* EC-EC communication commands: range 0x0600-0x06FF */
+
+#define EC_COMM_TEXT_MAX 8
+
+/*
+ * Get battery static information, i.e. information that never changes, or
+ * very infrequently.
+ */
+#define EC_CMD_BATTERY_GET_STATIC 0x0600
+
+/**
+ * struct ec_params_battery_static_info - Battery static info parameters
+ * @index: Battery index.
+ */
+struct ec_params_battery_static_info {
+       uint8_t index;
+} __ec_align_size1;
+
+/**
+ * struct ec_response_battery_static_info - Battery static info response
+ * @design_capacity: Battery Design Capacity (mAh)
+ * @design_voltage: Battery Design Voltage (mV)
+ * @manufacturer: Battery Manufacturer String
+ * @model: Battery Model Number String
+ * @serial: Battery Serial Number String
+ * @type: Battery Type String
+ * @cycle_count: Battery Cycle Count
+ */
+struct ec_response_battery_static_info {
+       uint16_t design_capacity;
+       uint16_t design_voltage;
+       char manufacturer[EC_COMM_TEXT_MAX];
+       char model[EC_COMM_TEXT_MAX];
+       char serial[EC_COMM_TEXT_MAX];
+       char type[EC_COMM_TEXT_MAX];
+       /* TODO(crbug.com/795991): Consider moving to dynamic structure. */
+       uint32_t cycle_count;
+} __ec_align4;
+
+/*
+ * Get battery dynamic information, i.e. information that is likely to change
+ * every time it is read.
+ */
+#define EC_CMD_BATTERY_GET_DYNAMIC 0x0601
+
+/**
+ * struct ec_params_battery_dynamic_info - Battery dynamic info parameters
+ * @index: Battery index.
+ */
+struct ec_params_battery_dynamic_info {
+       uint8_t index;
+} __ec_align_size1;
+
+/**
+ * struct ec_response_battery_dynamic_info - Battery dynamic info response
+ * @actual_voltage: Battery voltage (mV)
+ * @actual_current: Battery current (mA); negative=discharging
+ * @remaining_capacity: Remaining capacity (mAh)
+ * @full_capacity: Capacity (mAh, might change occasionally)
+ * @flags: Flags, see EC_BATT_FLAG_*
+ * @desired_voltage: Charging voltage desired by battery (mV)
+ * @desired_current: Charging current desired by battery (mA)
+ */
+struct ec_response_battery_dynamic_info {
+       int16_t actual_voltage;
+       int16_t actual_current;
+       int16_t remaining_capacity;
+       int16_t full_capacity;
+       int16_t flags;
+       int16_t desired_voltage;
+       int16_t desired_current;
+} __ec_align2;
+
+/*
+ * Control charger chip. Used to control charger chip on the slave.
+ */
+#define EC_CMD_CHARGER_CONTROL 0x0602
+
+/**
+ * struct ec_params_charger_control - Charger control parameters
+ * @max_current: Charger current (mA). Positive to allow base to draw up to
+ *     max_current and (possibly) charge battery, negative to request current
+ *     from base (OTG).
+ * @otg_voltage: Voltage (mV) to use in OTG mode, ignored if max_current is
+ *     >= 0.
+ * @allow_charging: Allow base battery charging (only makes sense if
+ *     max_current > 0).
+ */
+struct ec_params_charger_control {
+       int16_t max_current;
+       uint16_t otg_voltage;
+       uint8_t allow_charging;
+} __ec_align_size1;
+
+/*****************************************************************************/
+/*
+ * Reserve a range of host commands for board-specific, experimental, or
+ * special purpose features. These can be (re)used without updating this file.
+ *
+ * CAUTION: Don't go nuts with this. Shipping products should document ALL
+ * their EC commands for easier development, testing, debugging, and support.
+ *
+ * All commands MUST be #defined to be 4-digit UPPER CASE hex values
+ * (e.g., 0x00AB, not 0xab) for CONFIG_HOSTCMD_SECTION_SORTED to work.
+ *
+ * In your experimental code, you may want to do something like this:
+ *
+ *   #define EC_CMD_MAGIC_FOO 0x0000
+ *   #define EC_CMD_MAGIC_BAR 0x0001
+ *   #define EC_CMD_MAGIC_HEY 0x0002
+ *
+ *   DECLARE_PRIVATE_HOST_COMMAND(EC_CMD_MAGIC_FOO, magic_foo_handler,
+ *      EC_VER_MASK(0);
+ *
+ *   DECLARE_PRIVATE_HOST_COMMAND(EC_CMD_MAGIC_BAR, magic_bar_handler,
+ *      EC_VER_MASK(0);
+ *
+ *   DECLARE_PRIVATE_HOST_COMMAND(EC_CMD_MAGIC_HEY, magic_hey_handler,
+ *      EC_VER_MASK(0);
+ */
+#define EC_CMD_BOARD_SPECIFIC_BASE 0x3E00
+#define EC_CMD_BOARD_SPECIFIC_LAST 0x3FFF
+
+/*
+ * Given the private host command offset, calculate the true private host
+ * command value.
+ */
+#define EC_PRIVATE_HOST_COMMAND_VALUE(command) \
+       (EC_CMD_BOARD_SPECIFIC_BASE + (command))
 
 /*****************************************************************************/
 /*
@@ -3538,4 +5708,6 @@ struct ec_response_usb_pd_mux_info {
 #define EC_LPC_ADDR_OLD_PARAM   EC_HOST_CMD_REGION1
 #define EC_OLD_PARAM_SIZE       EC_HOST_CMD_REGION_SIZE
 
+
+
 #endif  /* __CROS_EC_COMMANDS_H */
index f0273c9..8cfda05 100644 (file)
@@ -19,7 +19,6 @@ struct device_node;
 #ifdef CONFIG_MFD_SYSCON
 extern struct regmap *syscon_node_to_regmap(struct device_node *np);
 extern struct regmap *syscon_regmap_lookup_by_compatible(const char *s);
-extern struct regmap *syscon_regmap_lookup_by_pdevname(const char *s);
 extern struct regmap *syscon_regmap_lookup_by_phandle(
                                        struct device_node *np,
                                        const char *property);
@@ -34,11 +33,6 @@ static inline struct regmap *syscon_regmap_lookup_by_compatible(const char *s)
        return ERR_PTR(-ENOTSUPP);
 }
 
-static inline struct regmap *syscon_regmap_lookup_by_pdevname(const char *s)
-{
-       return ERR_PTR(-ENOTSUPP);
-}
-
 static inline struct regmap *syscon_regmap_lookup_by_phandle(
                                        struct device_node *np,
                                        const char *property)
index dd0b5f4..f88f0ea 100644 (file)
@@ -633,6 +633,11 @@ static inline bool is_vmalloc_addr(const void *x)
        return false;
 #endif
 }
+
+#ifndef is_ioremap_addr
+#define is_ioremap_addr(x) is_vmalloc_addr(x)
+#endif
+
 #ifdef CONFIG_MMU
 extern int is_vmalloc_or_module_addr(const void *x);
 #else
@@ -2681,8 +2686,7 @@ static inline int vm_fault_to_errno(vm_fault_t vm_fault, int foll_flags)
        return 0;
 }
 
-typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr,
-                       void *data);
+typedef int (*pte_fn_t)(pte_t *pte, unsigned long addr, void *data);
 extern int apply_to_page_range(struct mm_struct *mm, unsigned long address,
                               unsigned long size, pte_fn_t fn, void *data);
 
@@ -2696,11 +2700,42 @@ static inline void kernel_poison_pages(struct page *page, int numpages,
                                        int enable) { }
 #endif
 
-extern bool _debug_pagealloc_enabled;
+#ifdef CONFIG_INIT_ON_ALLOC_DEFAULT_ON
+DECLARE_STATIC_KEY_TRUE(init_on_alloc);
+#else
+DECLARE_STATIC_KEY_FALSE(init_on_alloc);
+#endif
+static inline bool want_init_on_alloc(gfp_t flags)
+{
+       if (static_branch_unlikely(&init_on_alloc) &&
+           !page_poisoning_enabled())
+               return true;
+       return flags & __GFP_ZERO;
+}
+
+#ifdef CONFIG_INIT_ON_FREE_DEFAULT_ON
+DECLARE_STATIC_KEY_TRUE(init_on_free);
+#else
+DECLARE_STATIC_KEY_FALSE(init_on_free);
+#endif
+static inline bool want_init_on_free(void)
+{
+       return static_branch_unlikely(&init_on_free) &&
+              !page_poisoning_enabled();
+}
+
+#ifdef CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT
+DECLARE_STATIC_KEY_TRUE(_debug_pagealloc_enabled);
+#else
+DECLARE_STATIC_KEY_FALSE(_debug_pagealloc_enabled);
+#endif
 
 static inline bool debug_pagealloc_enabled(void)
 {
-       return IS_ENABLED(CONFIG_DEBUG_PAGEALLOC) && _debug_pagealloc_enabled;
+       if (!IS_ENABLED(CONFIG_DEBUG_PAGEALLOC))
+               return false;
+
+       return static_branch_unlikely(&_debug_pagealloc_enabled);
 }
 
 #if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_ARCH_HAS_SET_DIRECT_MAP)
@@ -2850,11 +2885,9 @@ extern long copy_huge_page_from_user(struct page *dst_page,
                                bool allow_pagefault);
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_HUGETLBFS */
 
-extern struct page_ext_operations debug_guardpage_ops;
-
 #ifdef CONFIG_DEBUG_PAGEALLOC
 extern unsigned int _debug_guardpage_minorder;
-extern bool _debug_guardpage_enabled;
+DECLARE_STATIC_KEY_FALSE(_debug_guardpage_enabled);
 
 static inline unsigned int debug_guardpage_minorder(void)
 {
@@ -2863,21 +2896,15 @@ static inline unsigned int debug_guardpage_minorder(void)
 
 static inline bool debug_guardpage_enabled(void)
 {
-       return _debug_guardpage_enabled;
+       return static_branch_unlikely(&_debug_guardpage_enabled);
 }
 
 static inline bool page_is_guard(struct page *page)
 {
-       struct page_ext *page_ext;
-
        if (!debug_guardpage_enabled())
                return false;
 
-       page_ext = lookup_page_ext(page);
-       if (unlikely(!page_ext))
-               return false;
-
-       return test_bit(PAGE_EXT_DEBUG_GUARD, &page_ext->flags);
+       return PageGuard(page);
 }
 #else
 static inline unsigned int debug_guardpage_minorder(void) { return 0; }
index 8ec38b1..1d10934 100644 (file)
@@ -329,7 +329,9 @@ struct vm_area_struct {
        struct file * vm_file;          /* File we map to (can be NULL). */
        void * vm_private_data;         /* was vm_pte (shared mem) */
 
+#ifdef CONFIG_SWAP
        atomic_long_t swap_readahead_info;
+#endif
 #ifndef CONFIG_MMU
        struct vm_region *vm_region;    /* NOMMU mapping region */
 #endif
index 7ac3755..4a351cb 100644 (file)
@@ -501,7 +501,6 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
                wake_up_process(host->sdio_irq_thread);
 }
 
-void sdio_run_irqs(struct mmc_host *host);
 void sdio_signal_irq(struct mmc_host *host);
 
 #ifdef CONFIG_REGULATOR
index 208c87c..c98a211 100644 (file)
@@ -219,6 +219,13 @@ struct cfi_pri_amdstd {
        uint8_t  VppMin;
        uint8_t  VppMax;
        uint8_t  TopBottom;
+       /* Below field are added from version 1.5 */
+       uint8_t  ProgramSuspend;
+       uint8_t  UnlockBypass;
+       uint8_t  SecureSiliconSector;
+       uint8_t  SoftwareFeatures;
+#define CFI_POLL_STATUS_REG    BIT(0)
+#define CFI_POLL_DQ            BIT(1)
 } __packed;
 
 /* Vendor-Specific PRI for Atmel chips (command set 0x0002) */
diff --git a/include/linux/mtd/hyperbus.h b/include/linux/mtd/hyperbus.h
new file mode 100644 (file)
index 0000000..2dfe659
--- /dev/null
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+#ifndef __LINUX_MTD_HYPERBUS_H__
+#define __LINUX_MTD_HYPERBUS_H__
+
+#include <linux/mtd/map.h>
+
+enum hyperbus_memtype {
+       HYPERFLASH,
+       HYPERRAM,
+};
+
+/**
+ * struct hyperbus_device - struct representing HyperBus slave device
+ * @map: map_info struct for accessing MMIO HyperBus flash memory
+ * @np: pointer to HyperBus slave device node
+ * @mtd: pointer to MTD struct
+ * @ctlr: pointer to HyperBus controller struct
+ * @memtype: type of memory device: HyperFlash or HyperRAM
+ */
+
+struct hyperbus_device {
+       struct map_info map;
+       struct device_node *np;
+       struct mtd_info *mtd;
+       struct hyperbus_ctlr *ctlr;
+       enum hyperbus_memtype memtype;
+};
+
+/**
+ * struct hyperbus_ops - struct representing custom HyperBus operations
+ * @read16: read 16 bit of data from flash in a single burst. Used to read
+ *          from non default address space, such as ID/CFI space
+ * @write16: write 16 bit of data to flash in a single burst. Used to
+ *           send cmd to flash or write single 16 bit word at a time.
+ * @copy_from: copy data from flash memory
+ * @copy_to: copy data to flash memory
+ * @calibrate: calibrate HyperBus controller
+ */
+
+struct hyperbus_ops {
+       u16 (*read16)(struct hyperbus_device *hbdev, unsigned long addr);
+       void (*write16)(struct hyperbus_device *hbdev,
+                       unsigned long addr, u16 val);
+       void (*copy_from)(struct hyperbus_device *hbdev, void *to,
+                         unsigned long from, ssize_t len);
+       void (*copy_to)(struct hyperbus_device *dev, unsigned long to,
+                       const void *from, ssize_t len);
+       int (*calibrate)(struct hyperbus_device *dev);
+};
+
+/**
+ * struct hyperbus_ctlr - struct representing HyperBus controller
+ * @dev: pointer to HyperBus controller device
+ * @calibrated: flag to indicate ctlr calibration sequence is complete
+ * @ops: HyperBus controller ops
+ */
+struct hyperbus_ctlr {
+       struct device *dev;
+       bool calibrated;
+
+       const struct hyperbus_ops *ops;
+};
+
+/**
+ * hyperbus_register_device - probe and register a HyperBus slave memory device
+ * @hbdev: hyperbus_device struct with dev, np and ctlr field populated
+ *
+ * Return: 0 for success, others for failure.
+ */
+int hyperbus_register_device(struct hyperbus_device *hbdev);
+
+/**
+ * hyperbus_unregister_device - deregister HyperBus slave memory device
+ * @hbdev: hyperbus_device to be unregistered
+ *
+ * Return: 0 for success, others for failure.
+ */
+int hyperbus_unregister_device(struct hyperbus_device *hbdev);
+
+#endif /* __LINUX_MTD_HYPERBUS_H__ */
index 936a3fd..4ca8c1c 100644 (file)
@@ -316,6 +316,12 @@ struct mtd_info {
        int (*_get_device) (struct mtd_info *mtd);
        void (*_put_device) (struct mtd_info *mtd);
 
+       /*
+        * flag indicates a panic write, low level drivers can take appropriate
+        * action if required to ensure writes go through
+        */
+       bool oops_panic_write;
+
        struct notifier_block reboot_notifier;  /* default mode before reboot */
 
        /* ECC status information */
index 2d12a1b..5f72840 100644 (file)
@@ -77,6 +77,7 @@
 #define ONENAND_DEVICE_DENSITY_1Gb     (0x003)
 #define ONENAND_DEVICE_DENSITY_2Gb     (0x004)
 #define ONENAND_DEVICE_DENSITY_4Gb     (0x005)
+#define ONENAND_DEVICE_DENSITY_8Gb     (0x006)
 
 /*
  * Version ID Register F002h (R)
index ac3884a..4ab9bcc 100644 (file)
@@ -874,6 +874,42 @@ int nand_op_parser_exec_op(struct nand_chip *chip,
                           const struct nand_op_parser *parser,
                           const struct nand_operation *op, bool check_only);
 
+static inline void nand_op_trace(const char *prefix,
+                                const struct nand_op_instr *instr)
+{
+#if IS_ENABLED(CONFIG_DYNAMIC_DEBUG) || defined(DEBUG)
+       switch (instr->type) {
+       case NAND_OP_CMD_INSTR:
+               pr_debug("%sCMD      [0x%02x]\n", prefix,
+                        instr->ctx.cmd.opcode);
+               break;
+       case NAND_OP_ADDR_INSTR:
+               pr_debug("%sADDR     [%d cyc: %*ph]\n", prefix,
+                        instr->ctx.addr.naddrs,
+                        instr->ctx.addr.naddrs < 64 ?
+                        instr->ctx.addr.naddrs : 64,
+                        instr->ctx.addr.addrs);
+               break;
+       case NAND_OP_DATA_IN_INSTR:
+               pr_debug("%sDATA_IN  [%d B%s]\n", prefix,
+                        instr->ctx.data.len,
+                        instr->ctx.data.force_8bit ?
+                        ", force 8-bit" : "");
+               break;
+       case NAND_OP_DATA_OUT_INSTR:
+               pr_debug("%sDATA_OUT [%d B%s]\n", prefix,
+                        instr->ctx.data.len,
+                        instr->ctx.data.force_8bit ?
+                        ", force 8-bit" : "");
+               break;
+       case NAND_OP_WAITRDY_INSTR:
+               pr_debug("%sWAITRDY  [max %d ms]\n", prefix,
+                        instr->ctx.waitrdy.timeout_ms);
+               break;
+       }
+#endif
+}
+
 /**
  * struct nand_controller_ops - Controller operations
  *
index 507f7e2..4ea558b 100644 (file)
                   SPI_MEM_OP_DUMMY(ndummy, 1),                         \
                   SPI_MEM_OP_DATA_IN(len, buf, 1))
 
+#define SPINAND_PAGE_READ_FROM_CACHE_OP_3A(fast, addr, ndummy, buf, len) \
+       SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1),               \
+                  SPI_MEM_OP_ADDR(3, addr, 1),                         \
+                  SPI_MEM_OP_DUMMY(ndummy, 1),                         \
+                  SPI_MEM_OP_DATA_IN(len, buf, 1))
+
 #define SPINAND_PAGE_READ_FROM_CACHE_X2_OP(addr, ndummy, buf, len)     \
        SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1),                             \
                   SPI_MEM_OP_ADDR(2, addr, 1),                         \
                   SPI_MEM_OP_DUMMY(ndummy, 1),                         \
                   SPI_MEM_OP_DATA_IN(len, buf, 2))
 
+#define SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(addr, ndummy, buf, len)  \
+       SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1),                             \
+                  SPI_MEM_OP_ADDR(3, addr, 1),                         \
+                  SPI_MEM_OP_DUMMY(ndummy, 1),                         \
+                  SPI_MEM_OP_DATA_IN(len, buf, 2))
+
 #define SPINAND_PAGE_READ_FROM_CACHE_X4_OP(addr, ndummy, buf, len)     \
        SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1),                             \
                   SPI_MEM_OP_ADDR(2, addr, 1),                         \
                   SPI_MEM_OP_DUMMY(ndummy, 1),                         \
                   SPI_MEM_OP_DATA_IN(len, buf, 4))
 
+#define SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(addr, ndummy, buf, len)  \
+       SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1),                             \
+                  SPI_MEM_OP_ADDR(3, addr, 1),                         \
+                  SPI_MEM_OP_DUMMY(ndummy, 1),                         \
+                  SPI_MEM_OP_DATA_IN(len, buf, 4))
+
 #define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(addr, ndummy, buf, len) \
        SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1),                             \
                   SPI_MEM_OP_ADDR(2, addr, 2),                         \
                   SPI_MEM_OP_DUMMY(ndummy, 2),                         \
                   SPI_MEM_OP_DATA_IN(len, buf, 2))
 
+#define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP_3A(addr, ndummy, buf, len) \
+       SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1),                             \
+                  SPI_MEM_OP_ADDR(3, addr, 2),                         \
+                  SPI_MEM_OP_DUMMY(ndummy, 2),                         \
+                  SPI_MEM_OP_DATA_IN(len, buf, 2))
+
 #define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(addr, ndummy, buf, len) \
        SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1),                             \
                   SPI_MEM_OP_ADDR(2, addr, 4),                         \
                   SPI_MEM_OP_DUMMY(ndummy, 4),                         \
                   SPI_MEM_OP_DATA_IN(len, buf, 4))
 
+#define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP_3A(addr, ndummy, buf, len) \
+       SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1),                             \
+                  SPI_MEM_OP_ADDR(3, addr, 4),                         \
+                  SPI_MEM_OP_DUMMY(ndummy, 4),                         \
+                  SPI_MEM_OP_DATA_IN(len, buf, 4))
+
 #define SPINAND_PROG_EXEC_OP(addr)                                     \
        SPI_MEM_OP(SPI_MEM_OP_CMD(0x10, 1),                             \
                   SPI_MEM_OP_ADDR(3, addr, 1),                         \
@@ -197,6 +227,7 @@ struct spinand_manufacturer {
 extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
 extern const struct spinand_manufacturer macronix_spinand_manufacturer;
 extern const struct spinand_manufacturer micron_spinand_manufacturer;
+extern const struct spinand_manufacturer paragon_spinand_manufacturer;
 extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
 extern const struct spinand_manufacturer winbond_spinand_manufacturer;
 
@@ -260,7 +291,7 @@ struct spinand_ecc_info {
  */
 struct spinand_info {
        const char *model;
-       u8 devid;
+       u16 devid;
        u32 flags;
        struct nand_memory_organization memorg;
        struct nand_ecc_req eccreq;
@@ -422,7 +453,7 @@ static inline void spinand_set_of_node(struct spinand_device *spinand,
 
 int spinand_match_and_init(struct spinand_device *dev,
                           const struct spinand_info *table,
-                          unsigned int table_size, u8 devid);
+                          unsigned int table_size, u16 devid);
 
 int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val);
 int spinand_select_target(struct spinand_device *spinand, unsigned int target);
index 4471cf9..47e5679 100644 (file)
 
 extern void mv64340_irq_init(unsigned int base);
 
-/* MPSC Platform Device, Driver Data (Shared register regions) */
-#define        MPSC_SHARED_NAME                "mpsc_shared"
-
-#define        MPSC_ROUTING_BASE_ORDER         0
-#define        MPSC_SDMA_INTR_BASE_ORDER       1
-
-#define MPSC_ROUTING_REG_BLOCK_SIZE    0x000c
-#define MPSC_SDMA_INTR_REG_BLOCK_SIZE  0x0084
-
-struct mpsc_shared_pdata {
-       u32     mrr_val;
-       u32     rcrr_val;
-       u32     tcrr_val;
-       u32     intr_cause_val;
-       u32     intr_mask_val;
-};
-
-/* MPSC Platform Device, Driver Data */
-#define        MPSC_CTLR_NAME                  "mpsc"
-
-#define        MPSC_BASE_ORDER                 0
-#define        MPSC_SDMA_BASE_ORDER            1
-#define        MPSC_BRG_BASE_ORDER             2
-
-#define MPSC_REG_BLOCK_SIZE            0x0038
-#define MPSC_SDMA_REG_BLOCK_SIZE       0x0c18
-#define MPSC_BRG_REG_BLOCK_SIZE                0x0008
-
-struct mpsc_pdata {
-       u8      mirror_regs;
-       u8      cache_mgmt;
-       u8      max_idle;
-       int     default_baud;
-       int     default_bits;
-       int     default_parity;
-       int     default_flow;
-       u32     chr_1_val;
-       u32     chr_2_val;
-       u32     chr_10_val;
-       u32     mpcr_val;
-       u32     bcr_val;
-       u8      brg_can_tune;
-       u8      brg_clk_src;
-       u32     brg_clk_freq;
-};
-
 /* Watchdog Platform Device, Driver Data */
 #define        MV64x60_WDT_NAME                        "mv64x60_wdt"
 
index a713e5d..acf820e 100644 (file)
 struct device_node;
 
 /* For scanning an arbitrary device-tree at any time */
-extern char *of_fdt_get_string(const void *blob, u32 offset);
-extern void *of_fdt_get_property(const void *blob,
-                                unsigned long node,
-                                const char *name,
-                                int *size);
-extern bool of_fdt_is_big_endian(const void *blob,
-                                unsigned long node);
-extern int of_fdt_match(const void *blob, unsigned long node,
-                       const char *const *compat);
 extern void *of_fdt_unflatten_tree(const unsigned long *blob,
                                   struct device_node *dad,
                                   struct device_node **mynodes);
@@ -64,9 +55,7 @@ extern int of_get_flat_dt_subnode_by_name(unsigned long node,
 extern const void *of_get_flat_dt_prop(unsigned long node, const char *name,
                                       int *size);
 extern int of_flat_dt_is_compatible(unsigned long node, const char *name);
-extern int of_flat_dt_match(unsigned long node, const char *const *matches);
 extern unsigned long of_get_flat_dt_root(void);
-extern int of_get_flat_dt_size(void);
 extern uint32_t of_get_flat_dt_phandle(unsigned long node);
 
 extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
index d079920..c696c26 100644 (file)
@@ -108,7 +108,6 @@ static inline vm_fault_t check_stable_address_space(struct mm_struct *mm)
 bool __oom_reap_task_mm(struct mm_struct *mm);
 
 extern unsigned long oom_badness(struct task_struct *p,
-               struct mem_cgroup *memcg, const nodemask_t *nodemask,
                unsigned long totalpages);
 
 extern bool out_of_memory(struct oom_control *oc);
index 9f8712a..b848517 100644 (file)
@@ -703,6 +703,7 @@ PAGEFLAG_FALSE(DoubleMap)
 #define PG_offline     0x00000100
 #define PG_kmemcg      0x00000200
 #define PG_table       0x00000400
+#define PG_guard       0x00000800
 
 #define PageType(page, flag)                                           \
        ((page->page_type & (PAGE_TYPE_BASE | flag)) == PAGE_TYPE_BASE)
@@ -754,6 +755,11 @@ PAGE_TYPE_OPS(Kmemcg, kmemcg)
  */
 PAGE_TYPE_OPS(Table, table)
 
+/*
+ * Marks guardpages used with debug_pagealloc.
+ */
+PAGE_TYPE_OPS(Guard, guard)
+
 extern bool is_free_buddy_page(struct page *page);
 
 __PAGEFLAG(Isolated, isolated, PF_ANY);
index 280ae96..1099c2f 100644 (file)
@@ -50,7 +50,7 @@ start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
  * Changes MIGRATE_ISOLATE to MIGRATE_MOVABLE.
  * target range is [start_pfn, end_pfn)
  */
-int
+void
 undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
                        unsigned migratetype);
 
index f84f167..0959295 100644 (file)
@@ -17,7 +17,6 @@ struct page_ext_operations {
 #ifdef CONFIG_PAGE_EXTENSION
 
 enum page_ext_flags {
-       PAGE_EXT_DEBUG_GUARD,
        PAGE_EXT_OWNER,
 #if defined(CONFIG_IDLE_PAGE_TRACKING) && !defined(CONFIG_64BIT)
        PAGE_EXT_YOUNG,
index fe0b29b..c755245 100644 (file)
@@ -383,8 +383,7 @@ extern int read_cache_pages(struct address_space *mapping,
 static inline struct page *read_mapping_page(struct address_space *mapping,
                                pgoff_t index, void *data)
 {
-       filler_t *filler = (filler_t *)mapping->a_ops->readpage;
-       return read_cache_page(mapping, index, filler, data);
+       return read_cache_page(mapping, index, NULL, data);
 }
 
 /*
@@ -452,6 +451,9 @@ extern int __lock_page_or_retry(struct page *page, struct mm_struct *mm,
                                unsigned int flags);
 extern void unlock_page(struct page *page);
 
+/*
+ * Return true if the page was successfully locked
+ */
 static inline int trylock_page(struct page *page)
 {
        page = compound_head(page);
index 3c202a1..01e8037 100644 (file)
@@ -66,13 +66,6 @@ static inline phys_addr_t pfn_t_to_phys(pfn_t pfn)
        return PFN_PHYS(pfn_t_to_pfn(pfn));
 }
 
-static inline void *pfn_t_to_virt(pfn_t pfn)
-{
-       if (pfn_t_has_page(pfn) && !is_device_private_page(pfn_t_to_page(pfn)))
-               return __va(pfn_t_to_phys(pfn));
-       return NULL;
-}
-
 static inline pfn_t page_to_pfn_t(struct page *page)
 {
        return pfn_to_pfn_t(page_to_pfn(page));
index 6f260c1..6aeb711 100644 (file)
 #ifndef __LINUX_PINCTRL_PINCONF_GENERIC_H
 #define __LINUX_PINCTRL_PINCONF_GENERIC_H
 
+#include <linux/device.h>
+#include <linux/pinctrl/machine.h>
+
+struct pinctrl_dev;
+struct pinctrl_map;
+
 /**
  * enum pin_config_param - possible pin configuration parameters
  * @PIN_CONFIG_BIAS_BUS_HOLD: the pin will be set to weakly latch so that it
@@ -54,6 +60,8 @@
  *     push-pull mode, the argument is ignored.
  * @PIN_CONFIG_DRIVE_STRENGTH: the pin will sink or source at most the current
  *     passed as argument. The argument is in mA.
+ * @PIN_CONFIG_DRIVE_STRENGTH_UA: the pin will sink or source at most the current
+ *     passed as argument. The argument is in uA.
  * @PIN_CONFIG_INPUT_DEBOUNCE: this will configure the pin to debounce mode,
  *     which means it will wait for signals to settle when reading inputs. The
  *     argument gives the debounce time in usecs. Setting the
@@ -111,6 +119,7 @@ enum pin_config_param {
        PIN_CONFIG_DRIVE_OPEN_SOURCE,
        PIN_CONFIG_DRIVE_PUSH_PULL,
        PIN_CONFIG_DRIVE_STRENGTH,
+       PIN_CONFIG_DRIVE_STRENGTH_UA,
        PIN_CONFIG_INPUT_DEBOUNCE,
        PIN_CONFIG_INPUT_ENABLE,
        PIN_CONFIG_INPUT_SCHMITT,
@@ -155,9 +164,6 @@ static inline unsigned long pinconf_to_config_packed(enum pin_config_param param
        return PIN_CONF_PACKED(param, argument);
 }
 
-#ifdef CONFIG_GENERIC_PINCONF
-
-#ifdef CONFIG_DEBUG_FS
 #define PCONFDUMP(a, b, c, d) {                                        \
        .param = a, .display = b, .format = c, .has_arg = d     \
        }
@@ -168,14 +174,6 @@ struct pin_config_item {
        const char * const format;
        bool has_arg;
 };
-#endif /* CONFIG_DEBUG_FS */
-
-#ifdef CONFIG_OF
-
-#include <linux/device.h>
-#include <linux/pinctrl/machine.h>
-struct pinctrl_dev;
-struct pinctrl_map;
 
 struct pinconf_generic_params {
        const char * const property;
@@ -220,8 +218,5 @@ static inline int pinconf_generic_dt_node_to_map_all(
        return pinconf_generic_dt_node_to_map(pctldev, np_config, map, num_maps,
                        PIN_MAP_TYPE_INVALID);
 }
-#endif
-
-#endif /* CONFIG_GENERIC_PINCONF */
 
 #endif /* __LINUX_PINCTRL_PINCONF_GENERIC_H */
index 514414a..f8a8215 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef __LINUX_PINCTRL_PINCONF_H
 #define __LINUX_PINCTRL_PINCONF_H
 
-#ifdef CONFIG_PINCONF
+#include <linux/types.h>
 
 struct pinctrl_dev;
 struct seq_file;
@@ -64,6 +64,4 @@ struct pinconf_ops {
                                            unsigned long config);
 };
 
-#endif
-
 #endif /* __LINUX_PINCTRL_PINCONF_H */
index a0e7858..635d97e 100644 (file)
@@ -3,6 +3,9 @@
  * Standard pin control state definitions
  */
 
+#ifndef __LINUX_PINCTRL_PINCTRL_STATE_H
+#define __LINUX_PINCTRL_PINCTRL_STATE_H
+
 /**
  * @PINCTRL_STATE_DEFAULT: the state the pinctrl handle shall be put
  *     into as default, usually this means the pins are up and ready to
@@ -31,3 +34,5 @@
 #define PINCTRL_STATE_INIT "init"
 #define PINCTRL_STATE_IDLE "idle"
 #define PINCTRL_STATE_SLEEP "sleep"
+
+#endif /* __LINUX_PINCTRL_PINCTRL_STATE_H */
index e429e5d..7ce2345 100644 (file)
@@ -11,8 +11,6 @@
 #ifndef __LINUX_PINCTRL_PINCTRL_H
 #define __LINUX_PINCTRL_PINCTRL_H
 
-#ifdef CONFIG_PINCTRL
-
 #include <linux/radix-tree.h>
 #include <linux/list.h>
 #include <linux/seq_file.h>
@@ -124,6 +122,10 @@ struct pinctrl_ops {
  *     the hardware description
  * @custom_conf_items: Information how to print @params in debugfs, must be
  *     the same size as the @custom_params, i.e. @num_custom_params
+ * @link_consumers: If true create a device link between pinctrl and its
+ *     consumers (i.e. the devices requesting pin control states). This is
+ *     sometimes necessary to ascertain the right suspend/resume order for
+ *     example.
  */
 struct pinctrl_desc {
        const char *name;
@@ -138,6 +140,7 @@ struct pinctrl_desc {
        const struct pinconf_generic_params *custom_params;
        const struct pin_config_item *custom_conf_items;
 #endif
+       bool link_consumers;
 };
 
 /* External interface to pin controller */
@@ -166,7 +169,6 @@ extern struct pinctrl_dev *devm_pinctrl_register(struct device *dev,
 extern void devm_pinctrl_unregister(struct device *dev,
                                struct pinctrl_dev *pctldev);
 
-extern bool pin_is_valid(struct pinctrl_dev *pctldev, int pin);
 extern void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
                                struct pinctrl_gpio_range *range);
 extern void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev,
@@ -197,16 +199,5 @@ struct pinctrl_dev *of_pinctrl_get(struct device_node *np)
 extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev);
 extern const char *pinctrl_dev_get_devname(struct pinctrl_dev *pctldev);
 extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev);
-#else
-
-struct pinctrl_dev;
-
-/* Sufficiently stupid default functions when pinctrl is not in use */
-static inline bool pin_is_valid(struct pinctrl_dev *pctldev, int pin)
-{
-       return pin >= 0;
-}
-
-#endif /* !CONFIG_PINCTRL */
 
 #endif /* __LINUX_PINCTRL_PINCTRL_H */
index e873ed9..9a647fa 100644 (file)
@@ -15,8 +15,6 @@
 #include <linux/seq_file.h>
 #include <linux/pinctrl/pinctrl.h>
 
-#ifdef CONFIG_PINMUX
-
 struct pinctrl_dev;
 
 /**
@@ -84,6 +82,4 @@ struct pinmux_ops {
        bool strict;
 };
 
-#endif /* CONFIG_PINMUX */
-
 #endif /* __LINUX_PINCTRL_PINMUX_H */
diff --git a/include/linux/platform_data/fsa9480.h b/include/linux/platform_data/fsa9480.h
deleted file mode 100644 (file)
index dea8d84..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2010 Samsung Electronics
- * Minkyu Kang <mk7.kang@samsung.com>
- */
-
-#ifndef _FSA9480_H_
-#define _FSA9480_H_
-
-#define FSA9480_ATTACHED       1
-#define FSA9480_DETACHED       0
-
-struct fsa9480_platform_data {
-       void (*cfg_gpio) (void);
-       void (*usb_cb) (u8 attached);
-       void (*uart_cb) (u8 attached);
-       void (*charger_cb) (u8 attached);
-       void (*jig_cb) (u8 attached);
-       void (*reset_cb) (void);
-       void (*usb_power) (u8 on);
-       int wakeup;
-};
-
-#endif /* _FSA9480_H_ */
index 1ff2247..ad03b58 100644 (file)
 
 /* Message flags for using the mailbox() interface */
 #define WILCO_EC_FLAG_NO_RESPONSE      BIT(0) /* EC does not respond */
-#define WILCO_EC_FLAG_EXTENDED_DATA    BIT(1) /* EC returns 256 data bytes */
 
 /* Normal commands have a maximum 32 bytes of data */
 #define EC_MAILBOX_DATA_SIZE           32
-/* Extended commands have 256 bytes of response data */
-#define EC_MAILBOX_DATA_SIZE_EXTENDED  256
 
 /**
  * struct wilco_ec_device - Wilco Embedded Controller handle.
@@ -32,6 +29,7 @@
  * @data_size: Size of the data buffer used for EC communication.
  * @debugfs_pdev: The child platform_device used by the debugfs sub-driver.
  * @rtc_pdev: The child platform_device used by the RTC sub-driver.
+ * @telem_pdev: The child platform_device used by the telemetry sub-driver.
  */
 struct wilco_ec_device {
        struct device *dev;
@@ -43,6 +41,7 @@ struct wilco_ec_device {
        size_t data_size;
        struct platform_device *debugfs_pdev;
        struct platform_device *rtc_pdev;
+       struct platform_device *telem_pdev;
 };
 
 /**
@@ -85,14 +84,12 @@ struct wilco_ec_response {
  * enum wilco_ec_msg_type - Message type to select a set of command codes.
  * @WILCO_EC_MSG_LEGACY: Legacy EC messages for standard EC behavior.
  * @WILCO_EC_MSG_PROPERTY: Get/Set/Sync EC controlled NVRAM property.
- * @WILCO_EC_MSG_TELEMETRY_SHORT: 32 bytes of telemetry data provided by the EC.
- * @WILCO_EC_MSG_TELEMETRY_LONG: 256 bytes of telemetry data provided by the EC.
+ * @WILCO_EC_MSG_TELEMETRY: Request telemetry data from the EC.
  */
 enum wilco_ec_msg_type {
        WILCO_EC_MSG_LEGACY = 0x00f0,
        WILCO_EC_MSG_PROPERTY = 0x00f2,
-       WILCO_EC_MSG_TELEMETRY_SHORT = 0x00f5,
-       WILCO_EC_MSG_TELEMETRY_LONG = 0x00f6,
+       WILCO_EC_MSG_TELEMETRY = 0x00f5,
 };
 
 /**
@@ -123,4 +120,87 @@ struct wilco_ec_message {
  */
 int wilco_ec_mailbox(struct wilco_ec_device *ec, struct wilco_ec_message *msg);
 
+/*
+ * A Property is typically a data item that is stored to NVRAM
+ * by the EC. Each of these data items has an index associated
+ * with it, known as the Property ID (PID). Properties may have
+ * variable lengths, up to a max of WILCO_EC_PROPERTY_MAX_SIZE
+ * bytes. Properties can be simple integers, or they may be more
+ * complex binary data.
+ */
+
+#define WILCO_EC_PROPERTY_MAX_SIZE     4
+
+/**
+ * struct ec_property_set_msg - Message to get or set a property.
+ * @property_id: Which property to get or set.
+ * @length: Number of bytes of |data| that are used.
+ * @data: Actual property data.
+ */
+struct wilco_ec_property_msg {
+       u32 property_id;
+       int length;
+       u8 data[WILCO_EC_PROPERTY_MAX_SIZE];
+};
+
+/**
+ * wilco_ec_get_property() - Retrieve a property from the EC.
+ * @ec: Embedded Controller device.
+ * @prop_msg: Message for request and response.
+ *
+ * The property_id field of |prop_msg| should be filled before calling this
+ * function. The result will be stored in the data and length fields.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int wilco_ec_get_property(struct wilco_ec_device *ec,
+                         struct wilco_ec_property_msg *prop_msg);
+
+/**
+ * wilco_ec_set_property() - Store a property on the EC.
+ * @ec: Embedded Controller device.
+ * @prop_msg: Message for request and response.
+ *
+ * The property_id, length, and data fields of |prop_msg| should be
+ * filled before calling this function.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int wilco_ec_set_property(struct wilco_ec_device *ec,
+                         struct wilco_ec_property_msg *prop_msg);
+
+/**
+ * wilco_ec_get_byte_property() - Retrieve a byte-size property from the EC.
+ * @ec: Embedded Controller device.
+ * @property_id: Which property to retrieve.
+ * @val: The result value, will be filled by this function.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int wilco_ec_get_byte_property(struct wilco_ec_device *ec, u32 property_id,
+                              u8 *val);
+
+/**
+ * wilco_ec_get_byte_property() - Store a byte-size property on the EC.
+ * @ec: Embedded Controller device.
+ * @property_id: Which property to store.
+ * @val: Value to store.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int wilco_ec_set_byte_property(struct wilco_ec_device *ec, u32 property_id,
+                              u8 val);
+
+/**
+ * wilco_ec_add_sysfs() - Create sysfs entries
+ * @ec: Wilco EC device
+ *
+ * wilco_ec_remove_sysfs() needs to be called afterwards
+ * to perform the necessary cleanup.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int wilco_ec_add_sysfs(struct wilco_ec_device *ec);
+void wilco_ec_remove_sysfs(struct wilco_ec_device *ec);
+
 #endif /* WILCO_EC_H */
index 30a9a55..6eec50f 100644 (file)
@@ -266,10 +266,11 @@ int sg_split(struct scatterlist *in, const int in_mapped_nents,
 typedef struct scatterlist *(sg_alloc_fn)(unsigned int, gfp_t);
 typedef void (sg_free_fn)(struct scatterlist *, unsigned int);
 
-void __sg_free_table(struct sg_table *, unsigned int, bool, sg_free_fn *);
+void __sg_free_table(struct sg_table *, unsigned int, unsigned int,
+                    sg_free_fn *);
 void sg_free_table(struct sg_table *);
 int __sg_alloc_table(struct sg_table *, unsigned int, unsigned int,
-                    struct scatterlist *, gfp_t, sg_alloc_fn *);
+                    struct scatterlist *, unsigned int, gfp_t, sg_alloc_fn *);
 int sg_alloc_table(struct sg_table *, unsigned int, gfp_t);
 int __sg_alloc_table_from_pages(struct sg_table *sgt, struct page **pages,
                                unsigned int n_pages, unsigned int offset,
@@ -331,9 +332,11 @@ size_t sg_zero_buffer(struct scatterlist *sgl, unsigned int nents,
 #endif
 
 #ifdef CONFIG_SG_POOL
-void sg_free_table_chained(struct sg_table *table, bool first_chunk);
+void sg_free_table_chained(struct sg_table *table,
+                          unsigned nents_first_chunk);
 int sg_alloc_table_chained(struct sg_table *table, int nents,
-                          struct scatterlist *first_chunk);
+                          struct scatterlist *first_chunk,
+                          unsigned nents_first_chunk);
 #endif
 
 /*
index 5e0b594..bb2bc99 100644 (file)
@@ -110,6 +110,7 @@ struct uart_8250_port {
                                                 *   if no_console_suspend
                                                 */
        unsigned char           probe;
+       struct mctrl_gpios      *gpios;
 #define UART_PROBE_RSA (1 << 0)
 
        /*
index 9449b19..56c9c7e 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/overflow.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
+#include <linux/percpu-refcount.h>
 
 
 /*
 /* Objects are reclaimable */
 #define SLAB_RECLAIM_ACCOUNT   ((slab_flags_t __force)0x00020000U)
 #define SLAB_TEMPORARY         SLAB_RECLAIM_ACCOUNT    /* Objects are short-lived */
+
+/* Slab deactivation flag */
+#define SLAB_DEACTIVATED       ((slab_flags_t __force)0x10000000U)
+
 /*
  * ZERO_SIZE_PTR will be returned for zero sized kmalloc requests.
  *
@@ -151,8 +156,7 @@ void kmem_cache_destroy(struct kmem_cache *);
 int kmem_cache_shrink(struct kmem_cache *);
 
 void memcg_create_kmem_cache(struct mem_cgroup *, struct kmem_cache *);
-void memcg_deactivate_kmem_caches(struct mem_cgroup *);
-void memcg_destroy_kmem_caches(struct mem_cgroup *);
+void memcg_deactivate_kmem_caches(struct mem_cgroup *, struct mem_cgroup *);
 
 /*
  * Please use this macro to create slab caches. Simply specify the
@@ -184,6 +188,7 @@ void * __must_check __krealloc(const void *, size_t, gfp_t);
 void * __must_check krealloc(const void *, size_t, gfp_t);
 void kfree(const void *);
 void kzfree(const void *);
+size_t __ksize(const void *);
 size_t ksize(const void *);
 
 #ifdef CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR
@@ -641,11 +646,12 @@ struct memcg_cache_params {
                        struct mem_cgroup *memcg;
                        struct list_head children_node;
                        struct list_head kmem_caches_node;
+                       struct percpu_ref refcnt;
 
-                       void (*deact_fn)(struct kmem_cache *);
+                       void (*work_fn)(struct kmem_cache *);
                        union {
-                               struct rcu_head deact_rcu_head;
-                               struct work_struct deact_work;
+                               struct rcu_head rcu_head;
+                               struct work_struct work;
                        };
                };
        };
index b57cd8b..9752381 100644 (file)
@@ -12,6 +12,7 @@
 
 struct pid;
 struct cred;
+struct socket;
 
 #define __sockaddr_check_size(size)    \
        BUILD_BUG_ON(((size) > sizeof(struct __kernel_sockaddr_storage)))
@@ -374,6 +375,12 @@ extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg,
 extern int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg,
                          unsigned int vlen, unsigned int flags,
                          bool forbid_cmsg_compat);
+extern long __sys_sendmsg_sock(struct socket *sock,
+                              struct user_msghdr __user *msg,
+                              unsigned int flags);
+extern long __sys_recvmsg_sock(struct socket *sock,
+                              struct user_msghdr __user *msg,
+                              unsigned int flags);
 
 /* helpers which do the actual work for syscalls */
 extern int __sys_recvfrom(int fd, void __user *ubuf, size_t size,
index 35662d9..bea46bd 100644 (file)
@@ -41,6 +41,31 @@ struct sdw_slave;
 #define SDW_DAI_ID_RANGE_START         100
 #define SDW_DAI_ID_RANGE_END           200
 
+enum {
+       SDW_PORT_DIRN_SINK = 0,
+       SDW_PORT_DIRN_SOURCE,
+       SDW_PORT_DIRN_MAX,
+};
+
+/*
+ * constants for flow control, ports and transport
+ *
+ * these are bit masks as devices can have multiple capabilities
+ */
+
+/*
+ * flow modes for SDW port. These can be isochronous, tx controlled,
+ * rx controlled or async
+ */
+#define SDW_PORT_FLOW_MODE_ISOCH       0
+#define SDW_PORT_FLOW_MODE_TX_CNTRL    BIT(0)
+#define SDW_PORT_FLOW_MODE_RX_CNTRL    BIT(1)
+#define SDW_PORT_FLOW_MODE_ASYNC       GENMASK(1, 0)
+
+/* sample packaging for block. It can be per port or per channel */
+#define SDW_BLOCK_PACKG_PER_PORT       BIT(0)
+#define SDW_BLOCK_PACKG_PER_CH         BIT(1)
+
 /**
  * enum sdw_slave_status - Slave status
  * @SDW_SLAVE_UNATTACHED: Slave is not attached with the bus.
@@ -76,6 +101,14 @@ enum sdw_command_response {
        SDW_CMD_FAIL_OTHER = 4,
 };
 
+/* block group count enum */
+enum sdw_dpn_grouping {
+       SDW_BLK_GRP_CNT_1 = 0,
+       SDW_BLK_GRP_CNT_2 = 1,
+       SDW_BLK_GRP_CNT_3 = 2,
+       SDW_BLK_GRP_CNT_4 = 3,
+};
+
 /**
  * enum sdw_stream_type: data stream type
  *
@@ -100,6 +133,26 @@ enum sdw_data_direction {
        SDW_DATA_DIR_TX = 1,
 };
 
+/**
+ * enum sdw_port_data_mode: Data Port mode
+ *
+ * @SDW_PORT_DATA_MODE_NORMAL: Normal data mode where audio data is received
+ * and transmitted.
+ * @SDW_PORT_DATA_MODE_STATIC_1: Simple test mode which uses static value of
+ * logic 1. The encoding will result in signal transitions at every bitslot
+ * owned by this Port
+ * @SDW_PORT_DATA_MODE_STATIC_0: Simple test mode which uses static value of
+ * logic 0. The encoding will result in no signal transitions
+ * @SDW_PORT_DATA_MODE_PRBS: Test mode which uses a PRBS generator to produce
+ * a pseudo random data pattern that is transferred
+ */
+enum sdw_port_data_mode {
+       SDW_PORT_DATA_MODE_NORMAL = 0,
+       SDW_PORT_DATA_MODE_STATIC_1 = 1,
+       SDW_PORT_DATA_MODE_STATIC_0 = 2,
+       SDW_PORT_DATA_MODE_PRBS = 3,
+};
+
 /*
  * SDW properties, defined in MIPI DisCo spec v1.0
  */
@@ -153,10 +206,11 @@ enum sdw_clk_stop_mode {
  * (inclusive)
  * @num_words: number of wordlengths supported
  * @words: wordlengths supported
- * @flow_controlled: Slave implementation results in an OK_NotReady
+ * @BRA_flow_controlled: Slave implementation results in an OK_NotReady
  * response
  * @simple_ch_prep_sm: If channel prepare sequence is required
- * @device_interrupts: If implementation-defined interrupts are supported
+ * @imp_def_interrupts: If set, each bit corresponds to support for
+ * implementation-defined interrupts
  *
  * The wordlengths are specified by Spec as max, min AND number of
  * discrete values, implementation can define based on the wordlengths they
@@ -167,9 +221,9 @@ struct sdw_dp0_prop {
        u32 min_word;
        u32 num_words;
        u32 *words;
-       bool flow_controlled;
+       bool BRA_flow_controlled;
        bool simple_ch_prep_sm;
-       bool device_interrupts;
+       bool imp_def_interrupts;
 };
 
 /**
@@ -219,7 +273,7 @@ struct sdw_dpn_audio_mode {
  * @simple_ch_prep_sm: If the port supports simplified channel prepare state
  * machine
  * @ch_prep_timeout: Port-specific timeout value, in milliseconds
- * @device_interrupts: If set, each bit corresponds to support for
+ * @imp_def_interrupts: If set, each bit corresponds to support for
  * implementation-defined interrupts
  * @max_ch: Maximum channels supported
  * @min_ch: Minimum channels supported
@@ -244,7 +298,7 @@ struct sdw_dpn_prop {
        u32 max_grouping;
        bool simple_ch_prep_sm;
        u32 ch_prep_timeout;
-       u32 device_interrupts;
+       u32 imp_def_interrupts;
        u32 max_ch;
        u32 min_ch;
        u32 num_ch;
@@ -311,36 +365,32 @@ struct sdw_slave_prop {
 /**
  * struct sdw_master_prop - Master properties
  * @revision: MIPI spec version of the implementation
- * @master_count: Number of masters
- * @clk_stop_mode: Bitmap for Clock Stop modes supported
- * @max_freq: Maximum Bus clock frequency, in Hz
+ * @clk_stop_modes: Bitmap, bit N set when clock-stop-modeN supported
+ * @max_clk_freq: Maximum Bus clock frequency, in Hz
  * @num_clk_gears: Number of clock gears supported
  * @clk_gears: Clock gears supported
- * @num_freq: Number of clock frequencies supported, in Hz
- * @freq: Clock frequencies supported, in Hz
+ * @num_clk_freq: Number of clock frequencies supported, in Hz
+ * @clk_freq: Clock frequencies supported, in Hz
  * @default_frame_rate: Controller default Frame rate, in Hz
  * @default_row: Number of rows
  * @default_col: Number of columns
- * @dynamic_frame: Dynamic frame supported
+ * @dynamic_frame: Dynamic frame shape supported
  * @err_threshold: Number of times that software may retry sending a single
  * command
- * @dpn_prop: Data Port N properties
  */
 struct sdw_master_prop {
        u32 revision;
-       u32 master_count;
-       enum sdw_clk_stop_mode clk_stop_mode;
-       u32 max_freq;
+       u32 clk_stop_modes;
+       u32 max_clk_freq;
        u32 num_clk_gears;
        u32 *clk_gears;
-       u32 num_freq;
-       u32 *freq;
+       u32 num_clk_freq;
+       u32 *clk_freq;
        u32 default_frame_rate;
        u32 default_row;
        u32 default_col;
        bool dynamic_frame;
        u32 err_threshold;
-       struct sdw_dpn_prop *dpn_prop;
 };
 
 int sdw_master_read_prop(struct sdw_bus *bus);
index 9c756b5..aaa7f42 100644 (file)
@@ -16,4 +16,15 @@ void sdw_unregister_driver(struct sdw_driver *drv);
 
 int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size);
 
+/**
+ * module_sdw_driver() - Helper macro for registering a Soundwire driver
+ * @__sdw_driver: soundwire slave driver struct
+ *
+ * Helper macro for Soundwire drivers which do not do anything special in
+ * module init/exit. This eliminates a lot of boilerplate. Each module may only
+ * use this macro once, and calling it replaces module_init() and module_exit()
+ */
+#define module_sdw_driver(__sdw_driver) \
+       module_driver(__sdw_driver, sdw_register_driver, \
+                       sdw_unregister_driver)
 #endif /* __SOUNDWIRE_TYPES_H */
index 4bfb5c4..de2c67a 100644 (file)
@@ -148,7 +148,7 @@ struct zone;
  * We always assume that blocks are of size PAGE_SIZE.
  */
 struct swap_extent {
-       struct list_head list;
+       struct rb_node rb_node;
        pgoff_t start_page;
        pgoff_t nr_pages;
        sector_t start_block;
@@ -175,8 +175,9 @@ enum {
        SWP_PAGE_DISCARD = (1 << 10),   /* freed swap page-cluster discards */
        SWP_STABLE_WRITES = (1 << 11),  /* no overwrite PG_writeback pages */
        SWP_SYNCHRONOUS_IO = (1 << 12), /* synchronous IO is efficient */
+       SWP_VALID       = (1 << 13),    /* swap is valid to be operated on? */
                                        /* add others here before... */
-       SWP_SCANNING    = (1 << 13),    /* refcount in scan_swap_map */
+       SWP_SCANNING    = (1 << 14),    /* refcount in scan_swap_map */
 };
 
 #define SWAP_CLUSTER_MAX 32UL
@@ -247,8 +248,7 @@ struct swap_info_struct {
        unsigned int cluster_next;      /* likely index for next allocation */
        unsigned int cluster_nr;        /* countdown to next cluster search */
        struct percpu_cluster __percpu *percpu_cluster; /* per cpu's swap location */
-       struct swap_extent *curr_swap_extent;
-       struct swap_extent first_swap_extent;
+       struct rb_root swap_extent_root;/* root of the swap extent rbtree */
        struct block_device *bdev;      /* swap device or bdev of swap file */
        struct file *swap_file;         /* seldom referenced */
        unsigned int old_block_size;    /* seldom referenced */
@@ -460,7 +460,7 @@ extern unsigned int count_swap_pages(int, int);
 extern sector_t map_swap_page(struct page *, struct block_device **);
 extern sector_t swapdev_block(int, pgoff_t);
 extern int page_swapcount(struct page *);
-extern int __swap_count(struct swap_info_struct *si, swp_entry_t entry);
+extern int __swap_count(swp_entry_t entry);
 extern int __swp_swapcount(swp_entry_t entry);
 extern int swp_swapcount(swp_entry_t entry);
 extern struct swap_info_struct *page_swap_info(struct page *);
@@ -470,6 +470,12 @@ extern int try_to_free_swap(struct page *);
 struct backing_dev_info;
 extern int init_swap_address_space(unsigned int type, unsigned long nr_pages);
 extern void exit_swap_address_space(unsigned int type);
+extern struct swap_info_struct *get_swap_device(swp_entry_t entry);
+
+static inline void put_swap_device(struct swap_info_struct *si)
+{
+       rcu_read_unlock();
+}
 
 #else /* CONFIG_SWAP */
 
@@ -576,7 +582,7 @@ static inline int page_swapcount(struct page *page)
        return 0;
 }
 
-static inline int __swap_count(struct swap_info_struct *si, swp_entry_t entry)
+static inline int __swap_count(swp_entry_t entry)
 {
        return 0;
 }
index cea1761..ab5f523 100644 (file)
@@ -267,13 +267,13 @@ bool csum_and_copy_from_iter_full(void *addr, size_t bytes, __wsum *csum, struct
 size_t hash_and_copy_to_iter(const void *addr, size_t bytes, void *hashp,
                struct iov_iter *i);
 
-int import_iovec(int type, const struct iovec __user * uvector,
+ssize_t import_iovec(int type, const struct iovec __user * uvector,
                 unsigned nr_segs, unsigned fast_segs,
                 struct iovec **iov, struct iov_iter *i);
 
 #ifdef CONFIG_COMPAT
 struct compat_iovec;
-int compat_import_iovec(int type, const struct compat_iovec __user * uvector,
+ssize_t compat_import_iovec(int type, const struct compat_iovec __user * uvector,
                 unsigned nr_segs, unsigned fast_segs,
                 struct iovec **iov, struct iov_iter *i);
 #endif
index ae82d9d..83d35d9 100644 (file)
@@ -578,6 +578,7 @@ struct usb3_lpm_parameters {
  * @bus_mA: Current available from the bus
  * @portnum: parent port number (origin 1)
  * @level: number of USB hub ancestors
+ * @devaddr: device address, XHCI: assigned by HW, others: same as devnum
  * @can_submit: URBs may be submitted
  * @persist_enabled:  USB_PERSIST enabled for this device
  * @have_langid: whether string_langid is valid
@@ -661,6 +662,7 @@ struct usb_device {
        unsigned short bus_mA;
        u8 portnum;
        u8 level;
+       u8 devaddr;
 
        unsigned can_submit:1;
        unsigned persist_enabled:1;
index 911e05a..edd89b7 100644 (file)
@@ -61,6 +61,7 @@ struct ci_hdrc_platform_data {
 #define CI_HDRC_OVERRIDE_PHY_CONTROL   BIT(12) /* Glue layer manages phy */
 #define CI_HDRC_REQUIRES_ALIGNED_DMA   BIT(13)
 #define CI_HDRC_IMX_IS_HSIC            BIT(14)
+#define CI_HDRC_PMQOS                  BIT(15)
        enum usb_dr_mode        dr_mode;
 #define CI_HDRC_CONTROLLER_RESET_EVENT         0
 #define CI_HDRC_CONTROLLER_STOPPED_EVENT       1
index 7595056..fb19141 100644 (file)
@@ -310,7 +310,8 @@ struct usb_gadget_ops {
        int     (*pullup) (struct usb_gadget *, int is_on);
        int     (*ioctl)(struct usb_gadget *,
                                unsigned code, unsigned long param);
-       void    (*get_config_params)(struct usb_dcd_config_params *);
+       void    (*get_config_params)(struct usb_gadget *,
+                                    struct usb_dcd_config_params *);
        int     (*udc_start)(struct usb_gadget *,
                        struct usb_gadget_driver *);
        int     (*udc_stop)(struct usb_gadget *);
index bb57b5a..bab27cc 100644 (file)
@@ -216,6 +216,9 @@ struct usb_hcd {
 #define        HC_IS_RUNNING(state) ((state) & __ACTIVE)
 #define        HC_IS_SUSPENDED(state) ((state) & __SUSPEND)
 
+       /* memory pool for HCs having local memory, or %NULL */
+       struct gen_pool         *localmem_pool;
+
        /* more shared queuing code would be good; it should support
         * smarter scheduling, handle transaction translators, etc;
         * input size of periodic table to an interrupt scheduler.
@@ -253,7 +256,6 @@ struct hc_driver {
 
        int     flags;
 #define        HCD_MEMORY      0x0001          /* HC regs use memory (else I/O) */
-#define        HCD_LOCAL_MEM   0x0002          /* HC needs local memory */
 #define        HCD_SHARED      0x0004          /* Two (or more) usb_hcds share HW */
 #define        HCD_USB11       0x0010          /* USB 1.1 */
 #define        HCD_USB2        0x0020          /* USB 2.0 */
@@ -461,6 +463,8 @@ extern int usb_add_hcd(struct usb_hcd *hcd,
                unsigned int irqnum, unsigned long irqflags);
 extern void usb_remove_hcd(struct usb_hcd *hcd);
 extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1);
+int usb_hcd_setup_local_mem(struct usb_hcd *hcd, phys_addr_t phys_addr,
+                           dma_addr_t dma, size_t size);
 
 struct platform_device;
 extern void usb_hcd_platform_shutdown(struct platform_device *dev);
index 53924f8..6914475 100644 (file)
@@ -3,6 +3,7 @@
  * Renesas USB
  *
  * Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2019 Renesas Electronics Corporation
  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
  *
  * This program is distributed in the hope that it will be useful,
@@ -32,17 +33,6 @@ enum {
        USBHS_MAX,
 };
 
-/*
- * callback functions table for driver
- *
- * These functions are called from platform for driver.
- * Callback function's pointer will be set before
- * renesas_usbhs_platform_callback :: hardware_init was called
- */
-struct renesas_usbhs_driver_callback {
-       int (*notify_hotplug)(struct platform_device *pdev);
-};
-
 /*
  * callback functions for platform
  *
@@ -180,23 +170,20 @@ struct renesas_usbhs_driver_param {
         */
        int pio_dma_border; /* default is 64byte */
 
-       uintptr_t type;
        u32 enable_gpio;
 
        /*
         * option:
         */
-       u32 has_otg:1; /* for controlling PWEN/EXTLP */
-       u32 has_sudmac:1; /* for SUDMAC */
        u32 has_usb_dmac:1; /* for USB-DMAC */
+       u32 runtime_pwctrl:1;
+       u32 has_cnen:1;
+       u32 cfifo_byte_addr:1; /* CFIFO is byte addressable */
 #define USBHS_USB_DMAC_XFER_SIZE       32      /* hardcode the xfer size */
+       u32 multi_clks:1;
+       u32 has_new_pipe_configs:1;
 };
 
-#define USBHS_TYPE_RCAR_GEN2           1
-#define USBHS_TYPE_RCAR_GEN3           2
-#define USBHS_TYPE_RCAR_GEN3_WITH_PLL  3
-#define USBHS_TYPE_RZA1                        4
-
 /*
  * option:
  *
@@ -211,12 +198,6 @@ struct renesas_usbhs_platform_info {
         */
        struct renesas_usbhs_platform_callback  platform_callback;
 
-       /*
-        * driver set these callback functions pointer.
-        * platform can use it on callback functions
-        */
-       struct renesas_usbhs_driver_callback    driver_callback;
-
        /*
         * option:
         *
@@ -230,12 +211,4 @@ struct renesas_usbhs_platform_info {
  */
 #define renesas_usbhs_get_info(pdev)\
        ((struct renesas_usbhs_platform_info *)(pdev)->dev.platform_data)
-
-#define renesas_usbhs_call_notify_hotplug(pdev)                                \
-       ({                                                              \
-               struct renesas_usbhs_driver_callback *dc;               \
-               dc = &(renesas_usbhs_get_info(pdev)->driver_callback);  \
-               if (dc && dc->notify_hotplug)                           \
-                       dc->notify_hotplug(pdev);                       \
-       })
 #endif /* RENESAS_USB_H */
index 51e1312..9b21d00 100644 (file)
@@ -72,10 +72,12 @@ extern void vm_unmap_aliases(void);
 
 #ifdef CONFIG_MMU
 extern void __init vmalloc_init(void);
+extern unsigned long vmalloc_nr_pages(void);
 #else
 static inline void vmalloc_init(void)
 {
 }
+static inline unsigned long vmalloc_nr_pages(void) { return 0; }
 #endif
 
 extern void *vmalloc(unsigned long size);
index 61e6fdd..6d28bc4 100644 (file)
@@ -17,7 +17,7 @@ struct vmpressure {
        unsigned long tree_scanned;
        unsigned long tree_reclaimed;
        /* The lock is used to keep the scanned/reclaimed above in sync. */
-       struct spinlock sr_lock;
+       spinlock_t sr_lock;
 
        /* The list of vmpressure_event structs. */
        struct list_head events;
index 77ac9c7..fefb529 100644 (file)
@@ -62,9 +62,18 @@ enum {
 
 /*
  * A single VMCI device has an upper limit of 128MB on the amount of
- * memory that can be used for queue pairs.
+ * memory that can be used for queue pairs. Since each queue pair
+ * consists of at least two pages, the memory limit also dictates the
+ * number of queue pairs a guest can create.
  */
 #define VMCI_MAX_GUEST_QP_MEMORY (128 * 1024 * 1024)
+#define VMCI_MAX_GUEST_QP_COUNT  (VMCI_MAX_GUEST_QP_MEMORY / PAGE_SIZE / 2)
+
+/*
+ * There can be at most PAGE_SIZE doorbells since there is one doorbell
+ * per byte in the doorbell bitmap page.
+ */
+#define VMCI_MAX_GUEST_DOORBELL_COUNT PAGE_SIZE
 
 /*
  * Queues with pre-mapped data pages must be small, so that we don't pin
@@ -430,8 +439,8 @@ enum {
 struct vmci_queue_header {
        /* All fields are 64bit and aligned. */
        struct vmci_handle handle;      /* Identifier. */
-       atomic64_t producer_tail;       /* Offset in this queue. */
-       atomic64_t consumer_head;       /* Offset in peer queue. */
+       u64 producer_tail;      /* Offset in this queue. */
+       u64 consumer_head;      /* Offset in peer queue. */
 };
 
 /*
@@ -732,13 +741,9 @@ static inline void *vmci_event_data_payload(struct vmci_event_data *ev_data)
  * prefix will be used, so correctness isn't an issue, but using a
  * 64bit operation still adds unnecessary overhead.
  */
-static inline u64 vmci_q_read_pointer(atomic64_t *var)
+static inline u64 vmci_q_read_pointer(u64 *var)
 {
-#if defined(CONFIG_X86_32)
-       return atomic_read((atomic_t *)var);
-#else
-       return atomic64_read(var);
-#endif
+       return READ_ONCE(*(unsigned long *)var);
 }
 
 /*
@@ -747,23 +752,17 @@ static inline u64 vmci_q_read_pointer(atomic64_t *var)
  * never exceeds a 32bit value in this case. On 32bit SMP, using a
  * locked cmpxchg8b adds unnecessary overhead.
  */
-static inline void vmci_q_set_pointer(atomic64_t *var,
-                                     u64 new_val)
+static inline void vmci_q_set_pointer(u64 *var, u64 new_val)
 {
-#if defined(CONFIG_X86_32)
-       return atomic_set((atomic_t *)var, (u32)new_val);
-#else
-       return atomic64_set(var, new_val);
-#endif
+       /* XXX buggered on big-endian */
+       WRITE_ONCE(*(unsigned long *)var, (unsigned long)new_val);
 }
 
 /*
  * Helper to add a given offset to a head or tail pointer. Wraps the
  * value of the pointer around the max size of the queue.
  */
-static inline void vmci_qp_add_pointer(atomic64_t *var,
-                                      size_t add,
-                                      u64 size)
+static inline void vmci_qp_add_pointer(u64 *var, size_t add, u64 size)
 {
        u64 new_val = vmci_q_read_pointer(var);
 
@@ -840,8 +839,8 @@ static inline void vmci_q_header_init(struct vmci_queue_header *q_header,
                                      const struct vmci_handle handle)
 {
        q_header->handle = handle;
-       atomic64_set(&q_header->producer_tail, 0);
-       atomic64_set(&q_header->consumer_head, 0);
+       q_header->producer_tail = 0;
+       q_header->consumer_head = 0;
 }
 
 /*
index 9710254..e0a3423 100644 (file)
@@ -1,18 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 #ifndef _FC_FIP_H_
 #define _FC_FIP_H_
index b1424dc..800d53d 100644 (file)
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
-/* * Copyright(c) 2011 Intel Corporation. All rights reserved.
+/*
+ * Copyright(c) 2011 Intel Corporation. All rights reserved.
  *
  * Maintained at www.Open-FCoE.org
  */
index 8b31588..92b11c7 100644 (file)
@@ -5,8 +5,6 @@
  * Copyright (C) 2005 Dmitry Yusupov
  * Copyright (C) 2005 Alex Aizman
  * maintained by open-iscsi@googlegroups.com
- *
- * See the file COPYING included with this distribution for more details.
  */
 
 #ifndef ISCSI_IF_H
index aeb4980..b71b5c4 100644 (file)
@@ -5,8 +5,6 @@
  * Copyright (C) 2005 Dmitry Yusupov
  * Copyright (C) 2005 Alex Aizman
  * maintained by open-iscsi@googlegroups.com
- *
- * See the file COPYING included with this distribution for more details.
  */
 
 #ifndef ISCSI_PROTO_H
index 172f15e..7c8ba9d 100644 (file)
@@ -5,8 +5,6 @@
  * Copyright (C) 2008 Mike Christie
  * Copyright (C) 2008 Red Hat, Inc.  All rights reserved.
  * maintained by open-iscsi@googlegroups.com
- *
- * See the file COPYING included with this distribution for more details.
  */
 
 #ifndef LIBISCSI_TCP_H
index e9664bb..4e2d61e 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * SAS host prototypes and structures header file
  *
@@ -207,8 +207,7 @@ struct sas_work {
        struct work_struct work;
 };
 
-/* Lots of code duplicates this in the SCSI tree, which can be factored out */
-static inline bool sas_dev_type_is_expander(enum sas_device_type type)
+static inline bool dev_is_expander(enum sas_device_type type)
 {
        return type == SAS_EDGE_EXPANDER_DEVICE ||
               type == SAS_FANOUT_EXPANDER_DEVICE;
index 97a0f6b..a5d8ae4 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * SAS structures and definitions header file
  *
index 0580dce..a0458bd 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /* 
  *  Transport specific attributes.
  *
index 43f09c7..7db2dd7 100644 (file)
@@ -3,9 +3,6 @@
  *  FiberChannel transport specific attributes exported to sysfs.
  *
  *  Copyright (c) 2003 Silicon Graphics, Inc.  All rights reserved.
- *
- *  ========
- *
  *  Copyright (C) 2004-2007   James Smart, Emulex Corporation
  *    Rewrite for host, target, device, and remote port attributes,
  *    statistics, and service functions...
index e3dc031..1796ff9 100644 (file)
@@ -1019,8 +1019,8 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,
        ),
 
        TP_fast_assign(
-               __entry->dev            = page->mapping->host->i_sb->s_dev;
-               __entry->ino            = page->mapping->host->i_ino;
+               __entry->dev            = page_file_mapping(page)->host->i_sb->s_dev;
+               __entry->ino            = page_file_mapping(page)->host->i_ino;
                __entry->index          = page->index;
                __entry->old_blkaddr    = fio->old_blkaddr;
                __entry->new_blkaddr    = fio->new_blkaddr;
@@ -1207,10 +1207,11 @@ DECLARE_EVENT_CLASS(f2fs__page,
        ),
 
        TP_fast_assign(
-               __entry->dev    = page->mapping->host->i_sb->s_dev;
-               __entry->ino    = page->mapping->host->i_ino;
+               __entry->dev    = page_file_mapping(page)->host->i_sb->s_dev;
+               __entry->ino    = page_file_mapping(page)->host->i_ino;
                __entry->type   = type;
-               __entry->dir    = S_ISDIR(page->mapping->host->i_mode);
+               __entry->dir    =
+                       S_ISDIR(page_file_mapping(page)->host->i_mode);
                __entry->index  = page->index;
                __entry->dirty  = PageDirty(page);
                __entry->uptodate = PageUptodate(page);
diff --git a/include/uapi/Kbuild b/include/uapi/Kbuild
new file mode 100644 (file)
index 0000000..61ee6e5
--- /dev/null
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0
+ifeq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/uapi/asm/a.out.h),)
+no-export-headers += linux/a.out.h
+endif
+
+ifeq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/uapi/asm/kvm.h),)
+no-export-headers += linux/kvm.h
+endif
+
+ifeq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/uapi/asm/kvm_para.h),)
+ifeq ($(wildcard $(objtree)/arch/$(SRCARCH)/include/generated/uapi/asm/kvm_para.h),)
+no-export-headers += linux/kvm_para.h
+endif
+endif
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
deleted file mode 100644 (file)
index 34711c5..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-ifeq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/uapi/asm/a.out.h),)
-no-export-headers += a.out.h
-endif
-
-ifeq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/uapi/asm/kvm.h),)
-no-export-headers += kvm.h
-endif
-
-ifeq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/uapi/asm/kvm_para.h),)
-ifeq ($(wildcard $(objtree)/arch/$(SRCARCH)/include/generated/uapi/asm/kvm_para.h),)
-no-export-headers += kvm_para.h
-endif
-endif
index a0c4600..1e1652f 100644 (file)
@@ -27,6 +27,7 @@ struct io_uring_sqe {
                __u32           fsync_flags;
                __u16           poll_events;
                __u32           sync_range_flags;
+               __u32           msg_flags;
        };
        __u64   user_data;      /* data to be passed back at completion time */
        union {
@@ -40,6 +41,7 @@ struct io_uring_sqe {
  */
 #define IOSQE_FIXED_FILE       (1U << 0)       /* use fixed fileset */
 #define IOSQE_IO_DRAIN         (1U << 1)       /* issue after inflight IO */
+#define IOSQE_IO_LINK          (1U << 2)       /* links next sqe */
 
 /*
  * io_uring_setup() flags
@@ -57,6 +59,8 @@ struct io_uring_sqe {
 #define IORING_OP_POLL_ADD     6
 #define IORING_OP_POLL_REMOVE  7
 #define IORING_OP_SYNC_FILE_RANGE      8
+#define IORING_OP_SENDMSG      9
+#define IORING_OP_RECVMSG      10
 
 /*
  * sqe->fsync_flags
index 2fe12b4..a7c1954 100644 (file)
@@ -696,9 +696,11 @@ struct kvm_ioeventfd {
 #define KVM_X86_DISABLE_EXITS_MWAIT          (1 << 0)
 #define KVM_X86_DISABLE_EXITS_HLT            (1 << 1)
 #define KVM_X86_DISABLE_EXITS_PAUSE          (1 << 2)
+#define KVM_X86_DISABLE_EXITS_CSTATE         (1 << 3)
 #define KVM_X86_DISABLE_VALID_EXITS          (KVM_X86_DISABLE_EXITS_MWAIT | \
                                               KVM_X86_DISABLE_EXITS_HLT | \
-                                              KVM_X86_DISABLE_EXITS_PAUSE)
+                                              KVM_X86_DISABLE_EXITS_PAUSE | \
+                                              KVM_X86_DISABLE_EXITS_CSTATE)
 
 /* for KVM_ENABLE_CAP */
 struct kvm_enable_cap {
@@ -993,6 +995,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_ARM_SVE 170
 #define KVM_CAP_ARM_PTRAUTH_ADDRESS 171
 #define KVM_CAP_ARM_PTRAUTH_GENERIC 172
+#define KVM_CAP_PMU_EVENT_FILTER 173
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -1327,6 +1330,8 @@ struct kvm_s390_ucas_mapping {
 #define KVM_PPC_GET_RMMU_INFO    _IOW(KVMIO,  0xb0, struct kvm_ppc_rmmu_info)
 /* Available with KVM_CAP_PPC_GET_CPU_CHAR */
 #define KVM_PPC_GET_CPU_CHAR     _IOR(KVMIO,  0xb1, struct kvm_ppc_cpu_char)
+/* Available with KVM_CAP_PMU_EVENT_FILTER */
+#define KVM_SET_PMU_EVENT_FILTER  _IOW(KVMIO,  0xb2, struct kvm_pmu_event_filter)
 
 /* ioctl for vm fd */
 #define KVM_CREATE_DEVICE        _IOWR(KVMIO,  0xe0, struct kvm_create_device)
index 6c0ce49..8b86609 100644 (file)
@@ -28,6 +28,7 @@
 #define KVM_HC_MIPS_CONSOLE_OUTPUT     8
 #define KVM_HC_CLOCK_PAIRING           9
 #define KVM_HC_SEND_IPI                10
+#define KVM_HC_SCHED_YIELD             11
 
 /*
  * hypercalls use architecture specific
index a7e66ab..c23f91a 100644 (file)
@@ -29,7 +29,7 @@
 
 #include <linux/types.h>
 #include <linux/magic.h>
-
+#include <asm/byteorder.h>
 
 #define NILFS_INODE_BMAP_SIZE  7
 
@@ -533,19 +533,19 @@ enum {
 static inline void                                                     \
 nilfs_checkpoint_set_##name(struct nilfs_checkpoint *cp)               \
 {                                                                      \
-       cp->cp_flags = cpu_to_le32(le32_to_cpu(cp->cp_flags) |          \
-                                  (1UL << NILFS_CHECKPOINT_##flag));   \
+       cp->cp_flags = __cpu_to_le32(__le32_to_cpu(cp->cp_flags) |      \
+                                    (1UL << NILFS_CHECKPOINT_##flag)); \
 }                                                                      \
 static inline void                                                     \
 nilfs_checkpoint_clear_##name(struct nilfs_checkpoint *cp)             \
 {                                                                      \
-       cp->cp_flags = cpu_to_le32(le32_to_cpu(cp->cp_flags) &          \
+       cp->cp_flags = __cpu_to_le32(__le32_to_cpu(cp->cp_flags) &      \
                                   ~(1UL << NILFS_CHECKPOINT_##flag));  \
 }                                                                      \
 static inline int                                                      \
 nilfs_checkpoint_##name(const struct nilfs_checkpoint *cp)             \
 {                                                                      \
-       return !!(le32_to_cpu(cp->cp_flags) &                           \
+       return !!(__le32_to_cpu(cp->cp_flags) &                         \
                  (1UL << NILFS_CHECKPOINT_##flag));                    \
 }
 
@@ -595,20 +595,20 @@ enum {
 static inline void                                                     \
 nilfs_segment_usage_set_##name(struct nilfs_segment_usage *su)         \
 {                                                                      \
-       su->su_flags = cpu_to_le32(le32_to_cpu(su->su_flags) |          \
+       su->su_flags = __cpu_to_le32(__le32_to_cpu(su->su_flags) |      \
                                   (1UL << NILFS_SEGMENT_USAGE_##flag));\
 }                                                                      \
 static inline void                                                     \
 nilfs_segment_usage_clear_##name(struct nilfs_segment_usage *su)       \
 {                                                                      \
        su->su_flags =                                                  \
-               cpu_to_le32(le32_to_cpu(su->su_flags) &                 \
+               __cpu_to_le32(__le32_to_cpu(su->su_flags) &             \
                            ~(1UL << NILFS_SEGMENT_USAGE_##flag));      \
 }                                                                      \
 static inline int                                                      \
 nilfs_segment_usage_##name(const struct nilfs_segment_usage *su)       \
 {                                                                      \
-       return !!(le32_to_cpu(su->su_flags) &                           \
+       return !!(__le32_to_cpu(su->su_flags) &                         \
                  (1UL << NILFS_SEGMENT_USAGE_##flag));                 \
 }
 
@@ -619,15 +619,15 @@ NILFS_SEGMENT_USAGE_FNS(ERROR, error)
 static inline void
 nilfs_segment_usage_set_clean(struct nilfs_segment_usage *su)
 {
-       su->su_lastmod = cpu_to_le64(0);
-       su->su_nblocks = cpu_to_le32(0);
-       su->su_flags = cpu_to_le32(0);
+       su->su_lastmod = __cpu_to_le64(0);
+       su->su_nblocks = __cpu_to_le32(0);
+       su->su_flags = __cpu_to_le32(0);
 }
 
 static inline int
 nilfs_segment_usage_clean(const struct nilfs_segment_usage *su)
 {
-       return !le32_to_cpu(su->su_flags);
+       return !__le32_to_cpu(su->su_flags);
 }
 
 /**
index 67c4aaa..5642c05 100644 (file)
 /* Motorola i.MX SoC */
 #define PORT_IMX       62
 
-/* Marvell MPSC */
+/* Marvell MPSC (obsolete unused) */
 #define PORT_MPSC      63
 
 /* TXX9 type number */
index 964e872..78efe87 100644 (file)
@@ -76,6 +76,26 @@ struct usbdevfs_connectinfo {
        unsigned char slow;
 };
 
+struct usbdevfs_conninfo_ex {
+       __u32 size;             /* Size of the structure from the kernel's */
+                               /* point of view. Can be used by userspace */
+                               /* to determine how much data can be       */
+                               /* used/trusted.                           */
+       __u32 busnum;           /* USB bus number, as enumerated by the    */
+                               /* kernel, the device is connected to.     */
+       __u32 devnum;           /* Device address on the bus.              */
+       __u32 speed;            /* USB_SPEED_* constants from ch9.h        */
+       __u8 num_ports;         /* Number of ports the device is connected */
+                               /* to on the way to the root hub. It may   */
+                               /* be bigger than size of 'ports' array so */
+                               /* userspace can detect overflows.         */
+       __u8 ports[7];          /* List of ports on the way from the root  */
+                               /* hub to the device. Current limit in     */
+                               /* USB specification is 7 tiers (root hub, */
+                               /* 5 intermediate hubs, device), which     */
+                               /* gives at most 6 port entries.           */
+};
+
 #define USBDEVFS_URB_SHORT_NOT_OK      0x01
 #define USBDEVFS_URB_ISO_ASAP          0x02
 #define USBDEVFS_URB_BULK_CONTINUATION 0x04
@@ -137,6 +157,7 @@ struct usbdevfs_hub_portinfo {
 #define USBDEVFS_CAP_REAP_AFTER_DISCONNECT     0x10
 #define USBDEVFS_CAP_MMAP                      0x20
 #define USBDEVFS_CAP_DROP_PRIVILEGES           0x40
+#define USBDEVFS_CAP_CONNINFO_EX               0x80
 
 /* USBDEVFS_DISCONNECT_CLAIM flags & struct */
 
@@ -197,5 +218,10 @@ struct usbdevfs_streams {
 #define USBDEVFS_FREE_STREAMS      _IOR('U', 29, struct usbdevfs_streams)
 #define USBDEVFS_DROP_PRIVILEGES   _IOW('U', 30, __u32)
 #define USBDEVFS_GET_SPEED         _IO('U', 31)
+/*
+ * Returns struct usbdevfs_conninfo_ex; length is variable to allow
+ * extending size of the data returned.
+ */
+#define USBDEVFS_CONNINFO_EX(len)  _IOC(_IOC_READ, 'U', 32, len)
 
 #endif /* _UAPI_LINUX_USBDEVICE_FS_H */
index 204ab9b..3956c22 100644 (file)
@@ -45,6 +45,30 @@ enum goya_queue_id {
        GOYA_QUEUE_ID_SIZE
 };
 
+/*
+ * Engine Numbering
+ *
+ * Used in the "busy_engines_mask" field in `struct hl_info_hw_idle'
+ */
+
+enum goya_engine_id {
+       GOYA_ENGINE_ID_DMA_0 = 0,
+       GOYA_ENGINE_ID_DMA_1,
+       GOYA_ENGINE_ID_DMA_2,
+       GOYA_ENGINE_ID_DMA_3,
+       GOYA_ENGINE_ID_DMA_4,
+       GOYA_ENGINE_ID_MME_0,
+       GOYA_ENGINE_ID_TPC_0,
+       GOYA_ENGINE_ID_TPC_1,
+       GOYA_ENGINE_ID_TPC_2,
+       GOYA_ENGINE_ID_TPC_3,
+       GOYA_ENGINE_ID_TPC_4,
+       GOYA_ENGINE_ID_TPC_5,
+       GOYA_ENGINE_ID_TPC_6,
+       GOYA_ENGINE_ID_TPC_7,
+       GOYA_ENGINE_ID_SIZE
+};
+
 enum hl_device_status {
        HL_DEVICE_STATUS_OPERATIONAL,
        HL_DEVICE_STATUS_IN_RESET,
@@ -86,7 +110,11 @@ struct hl_info_dram_usage {
 
 struct hl_info_hw_idle {
        __u32 is_idle;
-       __u32 pad;
+       /*
+        * Bitmask of busy engines.
+        * Bits definition is according to `enum <chip>_enging_id'.
+        */
+       __u32 busy_engines_mask;
 };
 
 struct hl_info_device_status {
index aff5b5e..47ffe32 100644 (file)
@@ -113,11 +113,11 @@ struct mtd_write_req {
 #define MTD_CAP_NVRAM          (MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE)
 
 /* Obsolete ECC byte placement modes (used with obsolete MEMGETOOBSEL) */
-#define MTD_NANDECC_OFF                0       // Switch off ECC (Not recommended)
-#define MTD_NANDECC_PLACE      1       // Use the given placement in the structure (YAFFS1 legacy mode)
-#define MTD_NANDECC_AUTOPLACE  2       // Use the default placement scheme
-#define MTD_NANDECC_PLACEONLY  3       // Use the given placement in the structure (Do not store ecc result on read)
-#define MTD_NANDECC_AUTOPL_USR         4       // Use the given autoplacement scheme rather than using the default
+#define MTD_NANDECC_OFF                0       /* Switch off ECC (Not recommended) */
+#define MTD_NANDECC_PLACE      1       /* Use the given placement in the structure (YAFFS1 legacy mode) */
+#define MTD_NANDECC_AUTOPLACE  2       /* Use the default placement scheme */
+#define MTD_NANDECC_PLACEONLY  3       /* Use the given placement in the structure (Do not store ecc result on read) */
+#define MTD_NANDECC_AUTOPL_USR         4       /* Use the given autoplacement scheme rather than using the default */
 
 /* OTP mode selection */
 #define MTD_OTP_OFF            0
index a81c535..76f627f 100644 (file)
@@ -2,19 +2,6 @@
 /*
  * Copyright(c) 2007 Intel 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.
- *
- * 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.
- *
  * Maintained at www.Open-FCoE.org
  */
 
index 8c0a292..0dab49d 100644 (file)
@@ -2,19 +2,6 @@
 /*
  * Copyright(c) 2007 Intel 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.
- *
- * 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.
- *
  * Maintained at www.Open-FCoE.org
  */
 
index 2153f35..effb4c6 100644 (file)
@@ -2,19 +2,6 @@
 /*
  * Copyright(c) 2007 Intel 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.
- *
- * 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.
- *
  * Maintained at www.Open-FCoE.org
  */
 
index 015e5e1..4cf0a40 100644 (file)
@@ -2,19 +2,6 @@
 /*
  * Copyright(c) 2007 Intel 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.
- *
- * 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.
- *
  * Maintained at www.Open-FCoE.org
  */
 
index 62597d8..52f32a6 100644 (file)
@@ -3,21 +3,6 @@
  *  FC Transport BSG Interface
  *
  *  Copyright (C) 2008   James Smart, Emulex 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.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General 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 SCSI_BSG_FC_H
index 5ccc233..5dd3820 100644 (file)
@@ -4,21 +4,6 @@
  *    Used for the posting of outbound SCSI transport events
  *
  *  Copyright (C) 2006   James Smart, Emulex 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.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General 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 SCSI_NETLINK_H
 #define SCSI_NETLINK_H
index 060f563..a390235 100644 (file)
@@ -3,21 +3,6 @@
  *  FC Transport Netlink Interface
  *
  *  Copyright (C) 2006   James Smart, Emulex 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.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General 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 SCSI_NETLINK_FC_H
 #define SCSI_NETLINK_FC_H
index d3ad482..9697c6b 100644 (file)
@@ -24,6 +24,9 @@ config CLANG_VERSION
        int
        default $(shell,$(srctree)/scripts/clang-version.sh $(CC))
 
+config CC_CAN_LINK
+       def_bool $(success,$(srctree)/scripts/cc-can-link.sh $(CC))
+
 config CC_HAS_ASM_GOTO
        def_bool $(success,$(srctree)/scripts/gcc-goto.sh $(CC))
 
@@ -96,6 +99,36 @@ config COMPILE_TEST
          here. If you are a user/distributor, say N here to exclude useless
          drivers to be distributed.
 
+config HEADER_TEST
+       bool "Compile test headers that should be standalone compilable"
+       help
+         Compile test headers listed in header-test-y target to ensure they are
+         self-contained, i.e. compilable as standalone units.
+
+         If you are a developer or tester and want to ensure the requested
+         headers are self-contained, say Y here. Otherwise, choose N.
+
+config KERNEL_HEADER_TEST
+       bool "Compile test kernel headers"
+       depends on HEADER_TEST
+       help
+         Headers in include/ are used to build external moduls.
+         Compile test them to ensure they are self-contained, i.e.
+         compilable as standalone units.
+
+         If you are a developer or tester and want to ensure the headers
+         in include/ are self-contained, say Y here. Otherwise, choose N.
+
+config UAPI_HEADER_TEST
+       bool "Compile test UAPI headers"
+       depends on HEADER_TEST && HEADERS_INSTALL && CC_CAN_LINK
+       help
+         Compile test headers exported to user-space to ensure they are
+         self-contained, i.e. compilable as standalone units.
+
+         If you are a developer or tester and want to ensure the exported
+         headers are self-contained, say Y here. Otherwise, choose N.
+
 config LOCALVERSION
        string "Local version - append to kernel release"
        help
index 66a196c..ff5803b 100644 (file)
@@ -520,6 +520,29 @@ static inline void initcall_debug_enable(void)
 }
 #endif
 
+/* Report memory auto-initialization states for this boot. */
+static void __init report_meminit(void)
+{
+       const char *stack;
+
+       if (IS_ENABLED(CONFIG_INIT_STACK_ALL))
+               stack = "all";
+       else if (IS_ENABLED(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL))
+               stack = "byref_all";
+       else if (IS_ENABLED(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF))
+               stack = "byref";
+       else if (IS_ENABLED(CONFIG_GCC_PLUGIN_STRUCTLEAK_USER))
+               stack = "__user";
+       else
+               stack = "off";
+
+       pr_info("mem auto-init: stack:%s, heap alloc:%s, heap free:%s\n",
+               stack, want_init_on_alloc(GFP_KERNEL) ? "on" : "off",
+               want_init_on_free() ? "on" : "off");
+       if (want_init_on_free())
+               pr_info("mem auto-init: clearing system memory may take some time...\n");
+}
+
 /*
  * Set up kernel memory allocators
  */
@@ -530,6 +553,7 @@ static void __init mm_init(void)
         * bigger than MAX_ORDER unless SPARSEMEM.
         */
        page_ext_init_flatmem();
+       report_meminit();
        mem_init();
        kmem_cache_init();
        pgtable_init();
index b2a8790..bfc0c17 100644 (file)
@@ -214,6 +214,62 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages,
        return cma_release(dev_get_cma_area(dev), pages, count);
 }
 
+/**
+ * dma_alloc_contiguous() - allocate contiguous pages
+ * @dev:   Pointer to device for which the allocation is performed.
+ * @size:  Requested allocation size.
+ * @gfp:   Allocation flags.
+ *
+ * This function allocates contiguous memory buffer for specified device. It
+ * first tries to use device specific contiguous memory area if available or
+ * the default global one, then tries a fallback allocation of normal pages.
+ *
+ * Note that it byapss one-page size of allocations from the global area as
+ * the addresses within one page are always contiguous, so there is no need
+ * to waste CMA pages for that kind; it also helps reduce fragmentations.
+ */
+struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp)
+{
+       int node = dev ? dev_to_node(dev) : NUMA_NO_NODE;
+       size_t count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+       size_t align = get_order(PAGE_ALIGN(size));
+       struct page *page = NULL;
+       struct cma *cma = NULL;
+
+       if (dev && dev->cma_area)
+               cma = dev->cma_area;
+       else if (count > 1)
+               cma = dma_contiguous_default_area;
+
+       /* CMA can be used only in the context which permits sleeping */
+       if (cma && gfpflags_allow_blocking(gfp)) {
+               align = min_t(size_t, align, CONFIG_CMA_ALIGNMENT);
+               page = cma_alloc(cma, count, align, gfp & __GFP_NOWARN);
+       }
+
+       /* Fallback allocation of normal pages */
+       if (!page)
+               page = alloc_pages_node(node, gfp, align);
+       return page;
+}
+
+/**
+ * dma_free_contiguous() - release allocated pages
+ * @dev:   Pointer to device for which the pages were allocated.
+ * @page:  Pointer to the allocated pages.
+ * @size:  Size of allocated pages.
+ *
+ * This function releases memory allocated by dma_alloc_contiguous(). As the
+ * cma_release returns false when provided pages do not belong to contiguous
+ * area and true otherwise, this function then does a fallback __free_pages()
+ * upon a false-return.
+ */
+void dma_free_contiguous(struct device *dev, struct page *page, size_t size)
+{
+       if (!cma_release(dev_get_cma_area(dev), page, size >> PAGE_SHIFT))
+               __free_pages(page, get_order(size));
+}
+
 /*
  * Support for reserved memory regions defined in device tree
  */
index 2c2772e..b90e1ae 100644 (file)
@@ -96,8 +96,6 @@ static bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size)
 struct page *__dma_direct_alloc_pages(struct device *dev, size_t size,
                dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
 {
-       unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
-       int page_order = get_order(size);
        struct page *page = NULL;
        u64 phys_mask;
 
@@ -109,20 +107,9 @@ struct page *__dma_direct_alloc_pages(struct device *dev, size_t size,
        gfp |= __dma_direct_optimal_gfp_mask(dev, dev->coherent_dma_mask,
                        &phys_mask);
 again:
-       /* CMA can be used only in the context which permits sleeping */
-       if (gfpflags_allow_blocking(gfp)) {
-               page = dma_alloc_from_contiguous(dev, count, page_order,
-                                                gfp & __GFP_NOWARN);
-               if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) {
-                       dma_release_from_contiguous(dev, page, count);
-                       page = NULL;
-               }
-       }
-       if (!page)
-               page = alloc_pages_node(dev_to_node(dev), gfp, page_order);
-
+       page = dma_alloc_contiguous(dev, size, gfp);
        if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) {
-               __free_pages(page, page_order);
+               dma_free_contiguous(dev, page, size);
                page = NULL;
 
                if (IS_ENABLED(CONFIG_ZONE_DMA32) &&
@@ -151,10 +138,18 @@ void *dma_direct_alloc_pages(struct device *dev, size_t size,
        if (!page)
                return NULL;
 
+       if (attrs & DMA_ATTR_NO_KERNEL_MAPPING) {
+               /* remove any dirty cache lines on the kernel alias */
+               if (!PageHighMem(page))
+                       arch_dma_prep_coherent(page, size);
+               /* return the page pointer as the opaque cookie */
+               return page;
+       }
+
        if (PageHighMem(page)) {
                /*
                 * Depending on the cma= arguments and per-arch setup
-                * dma_alloc_from_contiguous could return highmem pages.
+                * dma_alloc_contiguous could return highmem pages.
                 * Without remapping there is no way to return them here,
                 * so log an error and fail.
                 */
@@ -171,15 +166,19 @@ void *dma_direct_alloc_pages(struct device *dev, size_t size,
                *dma_handle = phys_to_dma(dev, page_to_phys(page));
        }
        memset(ret, 0, size);
+
+       if (IS_ENABLED(CONFIG_ARCH_HAS_UNCACHED_SEGMENT) &&
+           dma_alloc_need_uncached(dev, attrs)) {
+               arch_dma_prep_coherent(page, size);
+               ret = uncached_kernel_address(ret);
+       }
+
        return ret;
 }
 
 void __dma_direct_free_pages(struct device *dev, size_t size, struct page *page)
 {
-       unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
-
-       if (!dma_release_from_contiguous(dev, page, count))
-               __free_pages(page, get_order(size));
+       dma_free_contiguous(dev, page, size);
 }
 
 void dma_direct_free_pages(struct device *dev, size_t size, void *cpu_addr,
@@ -187,15 +186,26 @@ void dma_direct_free_pages(struct device *dev, size_t size, void *cpu_addr,
 {
        unsigned int page_order = get_order(size);
 
+       if (attrs & DMA_ATTR_NO_KERNEL_MAPPING) {
+               /* cpu_addr is a struct page cookie, not a kernel address */
+               __dma_direct_free_pages(dev, size, cpu_addr);
+               return;
+       }
+
        if (force_dma_unencrypted())
                set_memory_encrypted((unsigned long)cpu_addr, 1 << page_order);
+
+       if (IS_ENABLED(CONFIG_ARCH_HAS_UNCACHED_SEGMENT) &&
+           dma_alloc_need_uncached(dev, attrs))
+               cpu_addr = cached_kernel_address(cpu_addr);
        __dma_direct_free_pages(dev, size, virt_to_page(cpu_addr));
 }
 
 void *dma_direct_alloc(struct device *dev, size_t size,
                dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
 {
-       if (!dev_is_dma_coherent(dev))
+       if (!IS_ENABLED(CONFIG_ARCH_HAS_UNCACHED_SEGMENT) &&
+           dma_alloc_need_uncached(dev, attrs))
                return arch_dma_alloc(dev, size, dma_handle, gfp, attrs);
        return dma_direct_alloc_pages(dev, size, dma_handle, gfp, attrs);
 }
@@ -203,7 +213,8 @@ void *dma_direct_alloc(struct device *dev, size_t size,
 void dma_direct_free(struct device *dev, size_t size,
                void *cpu_addr, dma_addr_t dma_addr, unsigned long attrs)
 {
-       if (!dev_is_dma_coherent(dev))
+       if (!IS_ENABLED(CONFIG_ARCH_HAS_UNCACHED_SEGMENT) &&
+           dma_alloc_need_uncached(dev, attrs))
                arch_dma_free(dev, size, cpu_addr, dma_addr, attrs);
        else
                dma_direct_free_pages(dev, size, cpu_addr, dma_addr, attrs);
index f7afdad..1f628e7 100644 (file)
@@ -317,6 +317,12 @@ void arch_dma_set_mask(struct device *dev, u64 mask);
 
 int dma_set_mask(struct device *dev, u64 mask)
 {
+       /*
+        * Truncate the mask to the actually supported dma_addr_t width to
+        * avoid generating unsupportable addresses.
+        */
+       mask = (dma_addr_t)mask;
+
        if (!dev->dma_mask || !dma_supported(dev, mask))
                return -EIO;
 
@@ -330,6 +336,12 @@ EXPORT_SYMBOL(dma_set_mask);
 #ifndef CONFIG_ARCH_HAS_DMA_SET_COHERENT_MASK
 int dma_set_coherent_mask(struct device *dev, u64 mask)
 {
+       /*
+        * Truncate the mask to the actually supported dma_addr_t width to
+        * avoid generating unsupportable addresses.
+        */
+       mask = (dma_addr_t)mask;
+
        if (!dma_supported(dev, mask))
                return -EIO;
 
index 7a72319..a594aec 100644 (file)
@@ -158,6 +158,9 @@ out:
 
 bool dma_in_atomic_pool(void *start, size_t size)
 {
+       if (unlikely(!atomic_pool))
+               return false;
+
        return addr_in_gen_pool(atomic_pool, (unsigned long)start, size);
 }
 
@@ -199,8 +202,7 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
 
        size = PAGE_ALIGN(size);
 
-       if (!gfpflags_allow_blocking(flags) &&
-           !(attrs & DMA_ATTR_NO_KERNEL_MAPPING)) {
+       if (!gfpflags_allow_blocking(flags)) {
                ret = dma_alloc_from_pool(size, &page, flags);
                if (!ret)
                        return NULL;
@@ -214,11 +216,6 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
        /* remove any dirty cache lines on the kernel alias */
        arch_dma_prep_coherent(page, size);
 
-       if (attrs & DMA_ATTR_NO_KERNEL_MAPPING) {
-               ret = page; /* opaque cookie */
-               goto done;
-       }
-
        /* create a coherent mapping */
        ret = dma_common_contiguous_remap(page, size, VM_USERMAP,
                        arch_dma_mmap_pgprot(dev, PAGE_KERNEL, attrs),
@@ -237,10 +234,7 @@ done:
 void arch_dma_free(struct device *dev, size_t size, void *vaddr,
                dma_addr_t dma_handle, unsigned long attrs)
 {
-       if (attrs & DMA_ATTR_NO_KERNEL_MAPPING) {
-               /* vaddr is a struct page cookie, not a kernel address */
-               __dma_direct_free_pages(dev, size, vaddr);
-       } else if (!dma_free_from_pool(vaddr, PAGE_ALIGN(size))) {
+       if (!dma_free_from_pool(vaddr, PAGE_ALIGN(size))) {
                phys_addr_t phys = dma_to_phys(dev, dma_handle);
                struct page *page = pfn_to_page(__phys_to_pfn(phys));
 
index 13f0cb0..62fa5a8 100644 (file)
@@ -696,29 +696,12 @@ bool is_swiotlb_active(void)
 
 static int __init swiotlb_create_debugfs(void)
 {
-       struct dentry *d_swiotlb_usage;
-       struct dentry *ent;
-
-       d_swiotlb_usage = debugfs_create_dir("swiotlb", NULL);
-
-       if (!d_swiotlb_usage)
-               return -ENOMEM;
-
-       ent = debugfs_create_ulong("io_tlb_nslabs", 0400,
-                                  d_swiotlb_usage, &io_tlb_nslabs);
-       if (!ent)
-               goto fail;
-
-       ent = debugfs_create_ulong("io_tlb_used", 0400,
-                                  d_swiotlb_usage, &io_tlb_used);
-       if (!ent)
-               goto fail;
+       struct dentry *root;
 
+       root = debugfs_create_dir("swiotlb", NULL);
+       debugfs_create_ulong("io_tlb_nslabs", 0400, root, &io_tlb_nslabs);
+       debugfs_create_ulong("io_tlb_used", 0400, root, &io_tlb_used);
        return 0;
-
-fail:
-       debugfs_remove_recursive(d_swiotlb_usage);
-       return -ENOMEM;
 }
 
 late_initcall(swiotlb_create_debugfs);
index feb8071..63b3491 100644 (file)
@@ -152,20 +152,13 @@ static int fei_retval_get(void *data, u64 *val)
 DEFINE_DEBUGFS_ATTRIBUTE(fei_retval_ops, fei_retval_get, fei_retval_set,
                         "%llx\n");
 
-static int fei_debugfs_add_attr(struct fei_attr *attr)
+static void fei_debugfs_add_attr(struct fei_attr *attr)
 {
        struct dentry *dir;
 
        dir = debugfs_create_dir(attr->kp.symbol_name, fei_debugfs_dir);
-       if (!dir)
-               return -ENOMEM;
-
-       if (!debugfs_create_file("retval", 0600, dir, attr, &fei_retval_ops)) {
-               debugfs_remove_recursive(dir);
-               return -ENOMEM;
-       }
 
-       return 0;
+       debugfs_create_file("retval", 0600, dir, attr, &fei_retval_ops);
 }
 
 static void fei_debugfs_remove_attr(struct fei_attr *attr)
@@ -306,7 +299,7 @@ static ssize_t fei_write(struct file *file, const char __user *buffer,
 
        ret = register_kprobe(&attr->kp);
        if (!ret)
-               ret = fei_debugfs_add_attr(attr);
+               fei_debugfs_add_attr(attr);
        if (ret < 0)
                fei_attr_remove(attr);
        else {
@@ -337,19 +330,13 @@ static int __init fei_debugfs_init(void)
                return PTR_ERR(dir);
 
        /* injectable attribute is just a symlink of error_inject/list */
-       if (!debugfs_create_symlink("injectable", dir,
-                                   "../error_injection/list"))
-               goto error;
+       debugfs_create_symlink("injectable", dir, "../error_injection/list");
 
-       if (!debugfs_create_file("inject", 0600, dir, NULL, &fei_ops))
-               goto error;
+       debugfs_create_file("inject", 0600, dir, NULL, &fei_ops);
 
        fei_debugfs_dir = dir;
 
        return 0;
-error:
-       debugfs_remove_recursive(dir);
-       return -ENOMEM;
 }
 
 late_initcall(fei_debugfs_init);
index 6e40ff6..e5eb5ea 100644 (file)
@@ -64,7 +64,6 @@ struct gcov_node {
 static const char objtree[] = OBJTREE;
 static const char srctree[] = SRCTREE;
 static struct gcov_node root_node;
-static struct dentry *reset_dentry;
 static LIST_HEAD(all_head);
 static DEFINE_MUTEX(node_lock);
 
@@ -387,8 +386,6 @@ static void add_links(struct gcov_node *node, struct dentry *parent)
                        goto out_err;
                node->links[i] = debugfs_create_symlink(deskew(basename),
                                                        parent, target);
-               if (!node->links[i])
-                       goto out_err;
                kfree(target);
        }
 
@@ -450,11 +447,6 @@ static struct gcov_node *new_node(struct gcov_node *parent,
                                        parent->dentry, node, &gcov_data_fops);
        } else
                node->dentry = debugfs_create_dir(node->name, parent->dentry);
-       if (!node->dentry) {
-               pr_warn("could not create file\n");
-               kfree(node);
-               return NULL;
-       }
        if (info)
                add_links(node, parent->dentry);
        list_add(&node->list, &parent->children);
@@ -761,32 +753,20 @@ void gcov_event(enum gcov_action action, struct gcov_info *info)
 /* Create debugfs entries. */
 static __init int gcov_fs_init(void)
 {
-       int rc = -EIO;
-
        init_node(&root_node, NULL, NULL, NULL);
        /*
         * /sys/kernel/debug/gcov will be parent for the reset control file
         * and all profiling files.
         */
        root_node.dentry = debugfs_create_dir("gcov", NULL);
-       if (!root_node.dentry)
-               goto err_remove;
        /*
         * Create reset file which resets all profiling counts when written
         * to.
         */
-       reset_dentry = debugfs_create_file("reset", 0600, root_node.dentry,
-                                          NULL, &gcov_reset_fops);
-       if (!reset_dentry)
-               goto err_remove;
+       debugfs_create_file("reset", 0600, root_node.dentry, NULL,
+                           &gcov_reset_fops);
        /* Replay previous events to get our fs hierarchy up-to-date. */
        gcov_enable_events();
        return 0;
-
-err_remove:
-       pr_err("init failed\n");
-       debugfs_remove(root_node.dentry);
-
-       return rc;
 }
 device_initcall(gcov_fs_init);
index 9a34e1d..9ff4498 100755 (executable)
@@ -4,24 +4,12 @@
 # This script generates an archive consisting of kernel headers
 # for CONFIG_IKHEADERS.
 set -e
-spath="$(dirname "$(readlink -f "$0")")"
-kroot="$spath/.."
+sfile="$(readlink -f "$0")"
 outdir="$(pwd)"
 tarfile=$1
 cpio_dir=$outdir/$tarfile.tmp
 
-# Script filename relative to the kernel source root
-# We add it to the archive because it is small and any changes
-# to this script will also cause a rebuild of the archive.
-sfile="$(realpath --relative-to $kroot "$(readlink -f "$0")")"
-
-src_file_list="
-include/
-arch/$SRCARCH/include/
-$sfile
-"
-
-obj_file_list="
+dir_list="
 include/
 arch/$SRCARCH/include/
 "
@@ -33,33 +21,29 @@ arch/$SRCARCH/include/
 # Uncomment it for debugging.
 # if [ ! -f /tmp/iter ]; then iter=1; echo 1 > /tmp/iter;
 # else iter=$(($(cat /tmp/iter) + 1)); echo $iter > /tmp/iter; fi
-# find $src_file_list -type f | xargs ls -lR > /tmp/src-ls-$iter
-# find $obj_file_list -type f | xargs ls -lR > /tmp/obj-ls-$iter
+# find $src_file_list -name "*.h" | xargs ls -l > /tmp/src-ls-$iter
+# find $obj_file_list -name "*.h" | xargs ls -l > /tmp/obj-ls-$iter
 
 # include/generated/compile.h is ignored because it is touched even when none
 # of the source files changed. This causes pointless regeneration, so let us
 # ignore them for md5 calculation.
-pushd $kroot > /dev/null
-src_files_md5="$(find $src_file_list -type f                       |
+pushd $srctree > /dev/null
+src_files_md5="$(find $dir_list -name "*.h"                       |
                grep -v "include/generated/compile.h"              |
                grep -v "include/generated/autoconf.h"             |
-               grep -v "include/config/auto.conf"                 |
-               grep -v "include/config/auto.conf.cmd"             |
-               grep -v "include/config/tristate.conf"             |
-               xargs ls -lR | md5sum | cut -d ' ' -f1)"
+               xargs ls -l | md5sum | cut -d ' ' -f1)"
 popd > /dev/null
-obj_files_md5="$(find $obj_file_list -type f                       |
+obj_files_md5="$(find $dir_list -name "*.h"                       |
                grep -v "include/generated/compile.h"              |
                grep -v "include/generated/autoconf.h"             |
-               grep -v "include/config/auto.conf"                 |
-               grep -v "include/config/auto.conf.cmd"             |
-               grep -v "include/config/tristate.conf"             |
-               xargs ls -lR | md5sum | cut -d ' ' -f1)"
-
+               xargs ls -l | md5sum | cut -d ' ' -f1)"
+# Any changes to this script will also cause a rebuild of the archive.
+this_file_md5="$(ls -l $sfile | md5sum | cut -d ' ' -f1)"
 if [ -f $tarfile ]; then tarfile_md5="$(md5sum $tarfile | cut -d ' ' -f1)"; fi
 if [ -f kernel/kheaders.md5 ] &&
        [ "$(cat kernel/kheaders.md5|head -1)" == "$src_files_md5" ] &&
        [ "$(cat kernel/kheaders.md5|head -2|tail -1)" == "$obj_files_md5" ] &&
+       [ "$(cat kernel/kheaders.md5|head -3|tail -1)" == "$this_file_md5" ] &&
        [ "$(cat kernel/kheaders.md5|tail -1)" == "$tarfile_md5" ]; then
                exit
 fi
@@ -71,16 +55,16 @@ fi
 rm -rf $cpio_dir
 mkdir $cpio_dir
 
-pushd $kroot > /dev/null
-for f in $src_file_list;
-       do find "$f" ! -name "*.cmd" ! -name ".*";
+pushd $srctree > /dev/null
+for f in $dir_list;
+       do find "$f" -name "*.h";
 done | cpio --quiet -pd $cpio_dir
 popd > /dev/null
 
 # The second CPIO can complain if files already exist which can
 # happen with out of tree builds. Just silence CPIO for now.
-for f in $obj_file_list;
-       do find "$f" ! -name "*.cmd" ! -name ".*";
+for f in $dir_list;
+       do find "$f" -name "*.h";
 done | cpio --quiet -pd $cpio_dir >/dev/null 2>&1
 
 # Remove comments except SDPX lines
@@ -91,6 +75,7 @@ tar -Jcf $tarfile -C $cpio_dir/ . > /dev/null
 
 echo "$src_files_md5" >  kernel/kheaders.md5
 echo "$obj_files_md5" >> kernel/kheaders.md5
+echo "$this_file_md5" >> kernel/kheaders.md5
 echo "$(md5sum $tarfile | cut -d ' ' -f1)" >> kernel/kheaders.md5
 
 rm -rf $cpio_dir
index 93c2644..62c92e4 100644 (file)
@@ -121,7 +121,7 @@ EXPORT_SYMBOL(memremap);
 
 void memunmap(void *addr)
 {
-       if (is_vmalloc_addr(addr))
+       if (is_ioremap_addr(addr))
                iounmap((void __iomem *) addr);
 }
 EXPORT_SYMBOL(memunmap);
index 445337c..9f5433a 100644 (file)
@@ -2570,33 +2570,20 @@ static const struct file_operations fops_kp = {
 
 static int __init debugfs_kprobe_init(void)
 {
-       struct dentry *dir, *file;
+       struct dentry *dir;
        unsigned int value = 1;
 
        dir = debugfs_create_dir("kprobes", NULL);
-       if (!dir)
-               return -ENOMEM;
 
-       file = debugfs_create_file("list", 0400, dir, NULL,
-                               &debugfs_kprobes_operations);
-       if (!file)
-               goto error;
+       debugfs_create_file("list", 0400, dir, NULL,
+                           &debugfs_kprobes_operations);
 
-       file = debugfs_create_file("enabled", 0600, dir,
-                                       &value, &fops_kp);
-       if (!file)
-               goto error;
+       debugfs_create_file("enabled", 0600, dir, &value, &fops_kp);
 
-       file = debugfs_create_file("blacklist", 0400, dir, NULL,
-                               &debugfs_kprobe_blacklist_ops);
-       if (!file)
-               goto error;
+       debugfs_create_file("blacklist", 0400, dir, NULL,
+                           &debugfs_kprobe_blacklist_ops);
 
        return 0;
-
-error:
-       debugfs_remove(dir);
-       return -ENOMEM;
 }
 
 late_initcall(debugfs_kprobe_init);
index abb2a4a..cdf318d 100644 (file)
@@ -247,7 +247,6 @@ static int klp_check_stack(struct task_struct *task, char *err_buf)
        int ret, nr_entries;
 
        ret = stack_trace_save_tsk_reliable(task, entries, ARRAY_SIZE(entries));
-       WARN_ON_ONCE(ret == -ENOSYS);
        if (ret < 0) {
                snprintf(err_buf, STACK_ERR_BUF_SIZE,
                         "%s: %s:%d has an unreliable stack\n",
@@ -281,11 +280,11 @@ static int klp_check_stack(struct task_struct *task, char *err_buf)
  */
 static bool klp_try_switch_task(struct task_struct *task)
 {
+       static char err_buf[STACK_ERR_BUF_SIZE];
        struct rq *rq;
        struct rq_flags flags;
        int ret;
        bool success = false;
-       char err_buf[STACK_ERR_BUF_SIZE];
 
        err_buf[0] = '\0';
 
@@ -293,6 +292,13 @@ static bool klp_try_switch_task(struct task_struct *task)
        if (task->patch_state == klp_target_state)
                return true;
 
+       /*
+        * For arches which don't have reliable stack traces, we have to rely
+        * on other methods (e.g., switching tasks at kernel exit).
+        */
+       if (!klp_have_reliable_stack())
+               return false;
+
        /*
         * Now try to check the stack for any to-be-patched or to-be-unpatched
         * functions.  If all goes well, switch the task to the target patch
@@ -328,7 +334,6 @@ done:
                pr_debug("%s", err_buf);
 
        return success;
-
 }
 
 /*
index 36139de..e6a02b2 100644 (file)
@@ -228,7 +228,7 @@ unsigned int stack_trace_save_user(unsigned long *store, unsigned int size)
        };
 
        /* Trace user stack if not a kernel thread */
-       if (!current->mm)
+       if (current->flags & PF_KTHREAD)
                return 0;
 
        arch_stack_walk_user(consume_entry, &c, task_pt_regs(current));
@@ -255,14 +255,6 @@ save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace)
        WARN_ONCE(1, KERN_INFO "save_stack_trace_regs() not implemented yet.\n");
 }
 
-__weak int
-save_stack_trace_tsk_reliable(struct task_struct *tsk,
-                             struct stack_trace *trace)
-{
-       WARN_ONCE(1, KERN_INFO "save_stack_tsk_reliable() not implemented yet.\n");
-       return -ENOSYS;
-}
-
 /**
  * stack_trace_save - Save a stack trace into a storage array
  * @store:     Pointer to storage array
index a808931..8cf3596 100644 (file)
@@ -104,11 +104,7 @@ void update_vsyscall(struct timekeeper *tk)
        vdso_ts->sec    = tk->xtime_sec + tk->wall_to_monotonic.tv_sec;
        nsec            = tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift;
        nsec            = nsec + tk->wall_to_monotonic.tv_nsec;
-       while (nsec >= NSEC_PER_SEC) {
-               nsec = nsec - NSEC_PER_SEC;
-               vdso_ts->sec++;
-       }
-       vdso_ts->nsec   = nsec;
+       vdso_ts->sec    += __iter_div_u64_rem(nsec, NSEC_PER_SEC, &vdso_ts->nsec);
 
        if (__arch_use_vsyscall(vdata))
                update_vdso_data(vdata, tk);
index e1c6d79..2d6e93a 100644 (file)
@@ -512,8 +512,6 @@ static int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
        dir = debugfs_lookup(buts->name, blk_debugfs_root);
        if (!dir)
                bt->dir = dir = debugfs_create_dir(buts->name, blk_debugfs_root);
-       if (!dir)
-               goto err;
 
        bt->dev = dev;
        atomic_set(&bt->dropped, 0);
@@ -522,12 +520,8 @@ static int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
        ret = -EIO;
        bt->dropped_file = debugfs_create_file("dropped", 0444, dir, bt,
                                               &blk_dropped_fops);
-       if (!bt->dropped_file)
-               goto err;
 
        bt->msg_file = debugfs_create_file("msg", 0222, dir, bt, &blk_msg_fops);
-       if (!bt->msg_file)
-               goto err;
 
        bt->rchan = relay_open("trace", dir, buts->buf_size,
                                buts->buf_nr, &blk_relay_callbacks, bt);
index c3aabb5..c90c687 100644 (file)
@@ -8618,10 +8618,6 @@ struct dentry *tracing_init_dentry(void)
         */
        tr->dir = debugfs_create_automount("tracing", NULL,
                                           trace_automount, NULL);
-       if (!tr->dir) {
-               pr_warn_once("Could not create debugfs directory 'tracing'\n");
-               return ERR_PTR(-ENOMEM);
-       }
 
        return NULL;
 }
index 277e403..4469407 100644 (file)
@@ -22,8 +22,6 @@ static int __init sw842_debugfs_create(void)
                return -ENODEV;
 
        sw842_debugfs_root = debugfs_create_dir(MODULE_NAME, NULL);
-       if (IS_ERR(sw842_debugfs_root))
-               return PTR_ERR(sw842_debugfs_root);
 
        for (i = 0; i < ARRAY_SIZE(template_count); i++) {
                char name[32];
@@ -46,8 +44,7 @@ static int __init sw842_debugfs_create(void)
 
 static void __exit sw842_debugfs_remove(void)
 {
-       if (sw842_debugfs_root && !IS_ERR(sw842_debugfs_root))
-               debugfs_remove_recursive(sw842_debugfs_root);
+       debugfs_remove_recursive(sw842_debugfs_root);
 }
 
 #endif
index d4c8c93..4ac4ca2 100644 (file)
@@ -305,19 +305,26 @@ config DEBUG_FS
 
          If unsure, say N.
 
-config HEADERS_CHECK
-       bool "Run 'make headers_check' when building vmlinux"
+config HEADERS_INSTALL
+       bool "Install uapi headers to usr/include"
        depends on !UML
        help
-         This option will extract the user-visible kernel headers whenever
-         building the kernel, and will run basic sanity checks on them to
-         ensure that exported files do not attempt to include files which
-         were not exported, etc.
+         This option will install uapi headers (headers exported to user-space)
+         into the usr/include directory for use during the kernel build.
+         This is unneeded for building the kernel itself, but needed for some
+         user-space program samples. It is also needed by some features such
+         as uapi header sanity checks.
+
+config HEADERS_CHECK
+       bool "Run sanity checks on uapi headers when building 'all'"
+       depends on HEADERS_INSTALL
+       help
+         This option will run basic sanity checks on uapi headers when
+         building the 'all' target, for example, ensure that they do not
+         attempt to include files which were not exported, etc.
 
          If you're making modifications to header files which are
-         relevant for userspace, say 'Y', and check the headers
-         exported to $(INSTALL_HDR_PATH) (usually 'usr/include' in
-         your build tree), to make sure they're suitable.
+         relevant for userspace, say 'Y'.
 
 config OPTIMIZE_INLINING
        bool "Allow compiler to uninline functions marked 'inline'"
index 8a16c2d..c604091 100644 (file)
@@ -993,20 +993,14 @@ static __initdata int ddebug_init_success;
 
 static int __init dynamic_debug_init_debugfs(void)
 {
-       struct dentry *dir, *file;
+       struct dentry *dir;
 
        if (!ddebug_init_success)
                return -ENODEV;
 
        dir = debugfs_create_dir("dynamic_debug", NULL);
-       if (!dir)
-               return -ENOMEM;
-       file = debugfs_create_file("control", 0644, dir, NULL,
-                                       &ddebug_proc_fops);
-       if (!file) {
-               debugfs_remove(dir);
-               return -ENOMEM;
-       }
+       debugfs_create_file("control", 0644, dir, NULL, &ddebug_proc_fops);
+
        return 0;
 }
 
index 3cb21b2..8186ca8 100644 (file)
@@ -166,10 +166,10 @@ static int debugfs_ul_get(void *data, u64 *val)
 
 DEFINE_SIMPLE_ATTRIBUTE(fops_ul, debugfs_ul_get, debugfs_ul_set, "%llu\n");
 
-static struct dentry *debugfs_create_ul(const char *name, umode_t mode,
-                               struct dentry *parent, unsigned long *value)
+static void debugfs_create_ul(const char *name, umode_t mode,
+                             struct dentry *parent, unsigned long *value)
 {
-       return debugfs_create_file(name, mode, parent, value, &fops_ul);
+       debugfs_create_file(name, mode, parent, value, &fops_ul);
 }
 
 #ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
@@ -185,12 +185,11 @@ static int debugfs_stacktrace_depth_set(void *data, u64 val)
 DEFINE_SIMPLE_ATTRIBUTE(fops_stacktrace_depth, debugfs_ul_get,
                        debugfs_stacktrace_depth_set, "%llu\n");
 
-static struct dentry *debugfs_create_stacktrace_depth(
-       const char *name, umode_t mode,
-       struct dentry *parent, unsigned long *value)
+static void debugfs_create_stacktrace_depth(const char *name, umode_t mode,
+                                           struct dentry *parent,
+                                           unsigned long *value)
 {
-       return debugfs_create_file(name, mode, parent, value,
-                                  &fops_stacktrace_depth);
+       debugfs_create_file(name, mode, parent, value, &fops_stacktrace_depth);
 }
 
 #endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
@@ -202,51 +201,31 @@ struct dentry *fault_create_debugfs_attr(const char *name,
        struct dentry *dir;
 
        dir = debugfs_create_dir(name, parent);
-       if (!dir)
-               return ERR_PTR(-ENOMEM);
-
-       if (!debugfs_create_ul("probability", mode, dir, &attr->probability))
-               goto fail;
-       if (!debugfs_create_ul("interval", mode, dir, &attr->interval))
-               goto fail;
-       if (!debugfs_create_atomic_t("times", mode, dir, &attr->times))
-               goto fail;
-       if (!debugfs_create_atomic_t("space", mode, dir, &attr->space))
-               goto fail;
-       if (!debugfs_create_ul("verbose", mode, dir, &attr->verbose))
-               goto fail;
-       if (!debugfs_create_u32("verbose_ratelimit_interval_ms", mode, dir,
-                               &attr->ratelimit_state.interval))
-               goto fail;
-       if (!debugfs_create_u32("verbose_ratelimit_burst", mode, dir,
-                               &attr->ratelimit_state.burst))
-               goto fail;
-       if (!debugfs_create_bool("task-filter", mode, dir, &attr->task_filter))
-               goto fail;
+       if (IS_ERR(dir))
+               return dir;
+
+       debugfs_create_ul("probability", mode, dir, &attr->probability);
+       debugfs_create_ul("interval", mode, dir, &attr->interval);
+       debugfs_create_atomic_t("times", mode, dir, &attr->times);
+       debugfs_create_atomic_t("space", mode, dir, &attr->space);
+       debugfs_create_ul("verbose", mode, dir, &attr->verbose);
+       debugfs_create_u32("verbose_ratelimit_interval_ms", mode, dir,
+                          &attr->ratelimit_state.interval);
+       debugfs_create_u32("verbose_ratelimit_burst", mode, dir,
+                          &attr->ratelimit_state.burst);
+       debugfs_create_bool("task-filter", mode, dir, &attr->task_filter);
 
 #ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
-
-       if (!debugfs_create_stacktrace_depth("stacktrace-depth", mode, dir,
-                               &attr->stacktrace_depth))
-               goto fail;
-       if (!debugfs_create_ul("require-start", mode, dir,
-                               &attr->require_start))
-               goto fail;
-       if (!debugfs_create_ul("require-end", mode, dir, &attr->require_end))
-               goto fail;
-       if (!debugfs_create_ul("reject-start", mode, dir, &attr->reject_start))
-               goto fail;
-       if (!debugfs_create_ul("reject-end", mode, dir, &attr->reject_end))
-               goto fail;
-
+       debugfs_create_stacktrace_depth("stacktrace-depth", mode, dir,
+                                       &attr->stacktrace_depth);
+       debugfs_create_ul("require-start", mode, dir, &attr->require_start);
+       debugfs_create_ul("require-end", mode, dir, &attr->require_end);
+       debugfs_create_ul("reject-start", mode, dir, &attr->reject_start);
+       debugfs_create_ul("reject-end", mode, dir, &attr->reject_end);
 #endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
 
        attr->dname = dget(dir);
        return dir;
-fail:
-       debugfs_remove_recursive(dir);
-
-       return ERR_PTR(-ENOMEM);
 }
 EXPORT_SYMBOL_GPL(fault_create_debugfs_attr);
 
index 9969358..e7258d8 100644 (file)
 #endif
 #include <linux/font.h>
 
-#define NO_FONTS
-
 static const struct font_desc *fonts[] = {
 #ifdef CONFIG_FONT_8x8
-#undef NO_FONTS
-    &font_vga_8x8,
+       &font_vga_8x8,
 #endif
 #ifdef CONFIG_FONT_8x16
-#undef NO_FONTS
-    &font_vga_8x16,
+       &font_vga_8x16,
 #endif
 #ifdef CONFIG_FONT_6x11
-#undef NO_FONTS
-    &font_vga_6x11,
+       &font_vga_6x11,
 #endif
 #ifdef CONFIG_FONT_7x14
-#undef NO_FONTS
-    &font_7x14,
+       &font_7x14,
 #endif
 #ifdef CONFIG_FONT_SUN8x16
-#undef NO_FONTS
-    &font_sun_8x16,
+       &font_sun_8x16,
 #endif
 #ifdef CONFIG_FONT_SUN12x22
-#undef NO_FONTS
-    &font_sun_12x22,
+       &font_sun_12x22,
 #endif
 #ifdef CONFIG_FONT_10x18
-#undef NO_FONTS
-    &font_10x18,
+       &font_10x18,
 #endif
 #ifdef CONFIG_FONT_ACORN_8x8
-#undef NO_FONTS
-    &font_acorn_8x8,
+       &font_acorn_8x8,
 #endif
 #ifdef CONFIG_FONT_PEARL_8x8
-#undef NO_FONTS
-    &font_pearl_8x8,
+       &font_pearl_8x8,
 #endif
 #ifdef CONFIG_FONT_MINI_4x6
-#undef NO_FONTS
-    &font_mini_4x6,
+       &font_mini_4x6,
 #endif
 #ifdef CONFIG_FONT_6x10
-#undef NO_FONTS
-    &font_6x10,
+       &font_6x10,
 #endif
 #ifdef CONFIG_FONT_TER16x32
-#undef NO_FONTS
-    &font_ter_16x32,
+       &font_ter_16x32,
 #endif
 };
 
@@ -90,16 +76,17 @@ static const struct font_desc *fonts[] = {
  *     specified font.
  *
  */
-
 const struct font_desc *find_font(const char *name)
 {
-   unsigned int i;
+       unsigned int i;
 
-   for (i = 0; i < num_fonts; i++)
-      if (!strcmp(fonts[i]->name, name))
-         return fonts[i];
-   return NULL;
+       BUILD_BUG_ON(!num_fonts);
+       for (i = 0; i < num_fonts; i++)
+               if (!strcmp(fonts[i]->name, name))
+                       return fonts[i];
+       return NULL;
 }
+EXPORT_SYMBOL(find_font);
 
 
 /**
@@ -116,44 +103,46 @@ const struct font_desc *find_font(const char *name)
  *     chosen font.
  *
  */
-
 const struct font_desc *get_default_font(int xres, int yres, u32 font_w,
                                         u32 font_h)
 {
-    int i, c, cc;
-    const struct font_desc *f, *g;
-
-    g = NULL;
-    cc = -10000;
-    for(i=0; i<num_fonts; i++) {
-       f = fonts[i];
-       c = f->pref;
+       int i, c, cc, res;
+       const struct font_desc *f, *g;
+
+       g = NULL;
+       cc = -10000;
+       for (i = 0; i < num_fonts; i++) {
+               f = fonts[i];
+               c = f->pref;
 #if defined(__mc68000__)
 #ifdef CONFIG_FONT_PEARL_8x8
-       if (MACH_IS_AMIGA && f->idx == PEARL8x8_IDX)
-           c = 100;
+               if (MACH_IS_AMIGA && f->idx == PEARL8x8_IDX)
+                       c = 100;
 #endif
 #ifdef CONFIG_FONT_6x11
-       if (MACH_IS_MAC && xres < 640 && f->idx == VGA6x11_IDX)
-           c = 100;
+               if (MACH_IS_MAC && xres < 640 && f->idx == VGA6x11_IDX)
+                       c = 100;
 #endif
 #endif
-       if ((yres < 400) == (f->height <= 8))
-           c += 1000;
+               if ((yres < 400) == (f->height <= 8))
+                       c += 1000;
+
+               /* prefer a bigger font for high resolution */
+               res = (xres / f->width) * (yres / f->height) / 1000;
+               if (res > 20)
+                       c += 20 - res;
 
-       if ((font_w & (1 << (f->width - 1))) &&
-           (font_h & (1 << (f->height - 1))))
-           c += 1000;
+               if ((font_w & (1 << (f->width - 1))) &&
+                   (font_h & (1 << (f->height - 1))))
+                       c += 1000;
 
-       if (c > cc) {
-           cc = c;
-           g = f;
+               if (c > cc) {
+                       cc = c;
+                       g = f;
+               }
        }
-    }
-    return g;
+       return g;
 }
-
-EXPORT_SYMBOL(find_font);
 EXPORT_SYMBOL(get_default_font);
 
 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
index 5257f74..9fc3129 100644 (file)
@@ -327,21 +327,45 @@ EXPORT_SYMBOL(gen_pool_alloc_algo_owner);
  * gen_pool_dma_alloc - allocate special memory from the pool for DMA usage
  * @pool: pool to allocate from
  * @size: number of bytes to allocate from the pool
- * @dma: dma-view physical address return value.  Use NULL if unneeded.
+ * @dma: dma-view physical address return value.  Use %NULL if unneeded.
  *
  * Allocate the requested number of bytes from the specified pool.
  * Uses the pool allocation function (with first-fit algorithm by default).
  * Can not be used in NMI handler on architectures without
  * NMI-safe cmpxchg implementation.
+ *
+ * Return: virtual address of the allocated memory, or %NULL on failure
  */
 void *gen_pool_dma_alloc(struct gen_pool *pool, size_t size, dma_addr_t *dma)
+{
+       return gen_pool_dma_alloc_algo(pool, size, dma, pool->algo, pool->data);
+}
+EXPORT_SYMBOL(gen_pool_dma_alloc);
+
+/**
+ * gen_pool_dma_alloc_algo - allocate special memory from the pool for DMA
+ * usage with the given pool algorithm
+ * @pool: pool to allocate from
+ * @size: number of bytes to allocate from the pool
+ * @dma: DMA-view physical address return value. Use %NULL if unneeded.
+ * @algo: algorithm passed from caller
+ * @data: data passed to algorithm
+ *
+ * Allocate the requested number of bytes from the specified pool. Uses the
+ * given pool allocation function. Can not be used in NMI handler on
+ * architectures without NMI-safe cmpxchg implementation.
+ *
+ * Return: virtual address of the allocated memory, or %NULL on failure
+ */
+void *gen_pool_dma_alloc_algo(struct gen_pool *pool, size_t size,
+               dma_addr_t *dma, genpool_algo_t algo, void *data)
 {
        unsigned long vaddr;
 
        if (!pool)
                return NULL;
 
-       vaddr = gen_pool_alloc(pool, size);
+       vaddr = gen_pool_alloc_algo(pool, size, algo, data);
        if (!vaddr)
                return NULL;
 
@@ -350,7 +374,102 @@ void *gen_pool_dma_alloc(struct gen_pool *pool, size_t size, dma_addr_t *dma)
 
        return (void *)vaddr;
 }
-EXPORT_SYMBOL(gen_pool_dma_alloc);
+EXPORT_SYMBOL(gen_pool_dma_alloc_algo);
+
+/**
+ * gen_pool_dma_alloc_align - allocate special memory from the pool for DMA
+ * usage with the given alignment
+ * @pool: pool to allocate from
+ * @size: number of bytes to allocate from the pool
+ * @dma: DMA-view physical address return value. Use %NULL if unneeded.
+ * @align: alignment in bytes for starting address
+ *
+ * Allocate the requested number bytes from the specified pool, with the given
+ * alignment restriction. Can not be used in NMI handler on architectures
+ * without NMI-safe cmpxchg implementation.
+ *
+ * Return: virtual address of the allocated memory, or %NULL on failure
+ */
+void *gen_pool_dma_alloc_align(struct gen_pool *pool, size_t size,
+               dma_addr_t *dma, int align)
+{
+       struct genpool_data_align data = { .align = align };
+
+       return gen_pool_dma_alloc_algo(pool, size, dma,
+                       gen_pool_first_fit_align, &data);
+}
+EXPORT_SYMBOL(gen_pool_dma_alloc_align);
+
+/**
+ * gen_pool_dma_zalloc - allocate special zeroed memory from the pool for
+ * DMA usage
+ * @pool: pool to allocate from
+ * @size: number of bytes to allocate from the pool
+ * @dma: dma-view physical address return value.  Use %NULL if unneeded.
+ *
+ * Allocate the requested number of zeroed bytes from the specified pool.
+ * Uses the pool allocation function (with first-fit algorithm by default).
+ * Can not be used in NMI handler on architectures without
+ * NMI-safe cmpxchg implementation.
+ *
+ * Return: virtual address of the allocated zeroed memory, or %NULL on failure
+ */
+void *gen_pool_dma_zalloc(struct gen_pool *pool, size_t size, dma_addr_t *dma)
+{
+       return gen_pool_dma_zalloc_algo(pool, size, dma, pool->algo, pool->data);
+}
+EXPORT_SYMBOL(gen_pool_dma_zalloc);
+
+/**
+ * gen_pool_dma_zalloc_algo - allocate special zeroed memory from the pool for
+ * DMA usage with the given pool algorithm
+ * @pool: pool to allocate from
+ * @size: number of bytes to allocate from the pool
+ * @dma: DMA-view physical address return value. Use %NULL if unneeded.
+ * @algo: algorithm passed from caller
+ * @data: data passed to algorithm
+ *
+ * Allocate the requested number of zeroed bytes from the specified pool. Uses
+ * the given pool allocation function. Can not be used in NMI handler on
+ * architectures without NMI-safe cmpxchg implementation.
+ *
+ * Return: virtual address of the allocated zeroed memory, or %NULL on failure
+ */
+void *gen_pool_dma_zalloc_algo(struct gen_pool *pool, size_t size,
+               dma_addr_t *dma, genpool_algo_t algo, void *data)
+{
+       void *vaddr = gen_pool_dma_alloc_algo(pool, size, dma, algo, data);
+
+       if (vaddr)
+               memset(vaddr, 0, size);
+
+       return vaddr;
+}
+EXPORT_SYMBOL(gen_pool_dma_zalloc_algo);
+
+/**
+ * gen_pool_dma_zalloc_align - allocate special zeroed memory from the pool for
+ * DMA usage with the given alignment
+ * @pool: pool to allocate from
+ * @size: number of bytes to allocate from the pool
+ * @dma: DMA-view physical address return value. Use %NULL if unneeded.
+ * @align: alignment in bytes for starting address
+ *
+ * Allocate the requested number of zeroed bytes from the specified pool,
+ * with the given alignment restriction. Can not be used in NMI handler on
+ * architectures without NMI-safe cmpxchg implementation.
+ *
+ * Return: virtual address of the allocated zeroed memory, or %NULL on failure
+ */
+void *gen_pool_dma_zalloc_align(struct gen_pool *pool, size_t size,
+               dma_addr_t *dma, int align)
+{
+       struct genpool_data_align data = { .align = align };
+
+       return gen_pool_dma_zalloc_algo(pool, size, dma,
+                       gen_pool_first_fit_align, &data);
+}
+EXPORT_SYMBOL(gen_pool_dma_zalloc_align);
 
 /**
  * gen_pool_free - free allocated special memory back to the pool
index f99c41d..f1e0569 100644 (file)
@@ -1634,9 +1634,9 @@ EXPORT_SYMBOL(dup_iter);
  * on-stack array was used or not (and regardless of whether this function
  * returns an error or not).
  *
- * Return: 0 on success or negative error code on error.
+ * Return: Negative error code on error, bytes imported on success
  */
-int import_iovec(int type, const struct iovec __user * uvector,
+ssize_t import_iovec(int type, const struct iovec __user * uvector,
                 unsigned nr_segs, unsigned fast_segs,
                 struct iovec **iov, struct iov_iter *i)
 {
@@ -1652,16 +1652,17 @@ int import_iovec(int type, const struct iovec __user * uvector,
        }
        iov_iter_init(i, type, p, nr_segs, n);
        *iov = p == *iov ? NULL : p;
-       return 0;
+       return n;
 }
 EXPORT_SYMBOL(import_iovec);
 
 #ifdef CONFIG_COMPAT
 #include <linux/compat.h>
 
-int compat_import_iovec(int type, const struct compat_iovec __user * uvector,
-                unsigned nr_segs, unsigned fast_segs,
-                struct iovec **iov, struct iov_iter *i)
+ssize_t compat_import_iovec(int type,
+               const struct compat_iovec __user * uvector,
+               unsigned nr_segs, unsigned fast_segs,
+               struct iovec **iov, struct iov_iter *i)
 {
        ssize_t n;
        struct iovec *p;
@@ -1675,7 +1676,7 @@ int compat_import_iovec(int type, const struct compat_iovec __user * uvector,
        }
        iov_iter_init(i, type, p, nr_segs, n);
        *iov = p == *iov ? NULL : p;
-       return 0;
+       return n;
 }
 #endif
 
index f2ccdba..83198cb 100644 (file)
@@ -498,8 +498,10 @@ int kobject_rename(struct kobject *kobj, const char *new_name)
        kobj = kobject_get(kobj);
        if (!kobj)
                return -EINVAL;
-       if (!kobj->parent)
+       if (!kobj->parent) {
+               kobject_put(kobj);
                return -EINVAL;
+       }
 
        devpath = kobject_get_path(kobj, GFP_KERNEL);
        if (!devpath) {
index 3d2ba7c..21016b3 100644 (file)
@@ -59,33 +59,22 @@ struct dentry *notifier_err_inject_init(const char *name, struct dentry *parent,
        err_inject->nb.priority = priority;
 
        dir = debugfs_create_dir(name, parent);
-       if (!dir)
-               return ERR_PTR(-ENOMEM);
 
        actions_dir = debugfs_create_dir("actions", dir);
-       if (!actions_dir)
-               goto fail;
 
        for (action = err_inject->actions; action->name; action++) {
                struct dentry *action_dir;
 
                action_dir = debugfs_create_dir(action->name, actions_dir);
-               if (!action_dir)
-                       goto fail;
 
                /*
                 * Create debugfs r/w file containing action->error. If
                 * notifier call chain is called with action->val, it will
                 * fail with the error code
                 */
-               if (!debugfs_create_errno("error", mode, action_dir,
-                                       &action->error))
-                       goto fail;
+               debugfs_create_errno("error", mode, action_dir, &action->error);
        }
        return dir;
-fail:
-       debugfs_remove_recursive(dir);
-       return ERR_PTR(-ENOMEM);
 }
 EXPORT_SYMBOL_GPL(notifier_err_inject_init);
 
index e723eac..42695bc 100644 (file)
@@ -12,9 +12,6 @@ raid6_pq-$(CONFIG_S390) += s390vx8.o recov_s390xc.o
 
 hostprogs-y    += mktables
 
-quiet_cmd_unroll = UNROLL  $@
-      cmd_unroll = $(AWK) -f$(srctree)/$(src)/unroll.awk -vN=$(UNROLL) < $< > $@
-
 ifeq ($(CONFIG_ALTIVEC),y)
 altivec_flags := -maltivec $(call cc-option,-mabi=altivec)
 
@@ -26,7 +23,6 @@ CFLAGS_REMOVE_altivec1.o  += -msoft-float
 CFLAGS_REMOVE_altivec2.o  += -msoft-float
 CFLAGS_REMOVE_altivec4.o  += -msoft-float
 CFLAGS_REMOVE_altivec8.o  += -msoft-float
-CFLAGS_REMOVE_altivec8.o  += -msoft-float
 CFLAGS_REMOVE_vpermxor1.o += -msoft-float
 CFLAGS_REMOVE_vpermxor2.o += -msoft-float
 CFLAGS_REMOVE_vpermxor4.o += -msoft-float
@@ -51,111 +47,39 @@ CFLAGS_REMOVE_neon8.o += -mgeneral-regs-only
 endif
 endif
 
-targets += int1.c
-$(obj)/int1.c:   UNROLL := 1
-$(obj)/int1.c:   $(src)/int.uc $(src)/unroll.awk FORCE
-       $(call if_changed,unroll)
-
-targets += int2.c
-$(obj)/int2.c:   UNROLL := 2
-$(obj)/int2.c:   $(src)/int.uc $(src)/unroll.awk FORCE
-       $(call if_changed,unroll)
-
-targets += int4.c
-$(obj)/int4.c:   UNROLL := 4
-$(obj)/int4.c:   $(src)/int.uc $(src)/unroll.awk FORCE
-       $(call if_changed,unroll)
-
-targets += int8.c
-$(obj)/int8.c:   UNROLL := 8
-$(obj)/int8.c:   $(src)/int.uc $(src)/unroll.awk FORCE
-       $(call if_changed,unroll)
-
-targets += int16.c
-$(obj)/int16.c:  UNROLL := 16
-$(obj)/int16.c:  $(src)/int.uc $(src)/unroll.awk FORCE
-       $(call if_changed,unroll)
+quiet_cmd_unroll = UNROLL  $@
+      cmd_unroll = $(AWK) -f$(srctree)/$(src)/unroll.awk -vN=$* < $< > $@
 
-targets += int32.c
-$(obj)/int32.c:  UNROLL := 32
-$(obj)/int32.c:  $(src)/int.uc $(src)/unroll.awk FORCE
+targets += int1.c int2.c int4.c int8.c int16.c int32.c
+$(obj)/int%.c: $(src)/int.uc $(src)/unroll.awk FORCE
        $(call if_changed,unroll)
 
 CFLAGS_altivec1.o += $(altivec_flags)
-targets += altivec1.c
-$(obj)/altivec1.c:   UNROLL := 1
-$(obj)/altivec1.c:   $(src)/altivec.uc $(src)/unroll.awk FORCE
-       $(call if_changed,unroll)
-
 CFLAGS_altivec2.o += $(altivec_flags)
-targets += altivec2.c
-$(obj)/altivec2.c:   UNROLL := 2
-$(obj)/altivec2.c:   $(src)/altivec.uc $(src)/unroll.awk FORCE
-       $(call if_changed,unroll)
-
 CFLAGS_altivec4.o += $(altivec_flags)
-targets += altivec4.c
-$(obj)/altivec4.c:   UNROLL := 4
-$(obj)/altivec4.c:   $(src)/altivec.uc $(src)/unroll.awk FORCE
-       $(call if_changed,unroll)
-
 CFLAGS_altivec8.o += $(altivec_flags)
-targets += altivec8.c
-$(obj)/altivec8.c:   UNROLL := 8
-$(obj)/altivec8.c:   $(src)/altivec.uc $(src)/unroll.awk FORCE
+targets += altivec1.c altivec2.c altivec4.c altivec8.c
+$(obj)/altivec%.c: $(src)/altivec.uc $(src)/unroll.awk FORCE
        $(call if_changed,unroll)
 
 CFLAGS_vpermxor1.o += $(altivec_flags)
-targets += vpermxor1.c
-$(obj)/vpermxor1.c: UNROLL := 1
-$(obj)/vpermxor1.c: $(src)/vpermxor.uc $(src)/unroll.awk FORCE
-       $(call if_changed,unroll)
-
 CFLAGS_vpermxor2.o += $(altivec_flags)
-targets += vpermxor2.c
-$(obj)/vpermxor2.c: UNROLL := 2
-$(obj)/vpermxor2.c: $(src)/vpermxor.uc $(src)/unroll.awk FORCE
-       $(call if_changed,unroll)
-
 CFLAGS_vpermxor4.o += $(altivec_flags)
-targets += vpermxor4.c
-$(obj)/vpermxor4.c: UNROLL := 4
-$(obj)/vpermxor4.c: $(src)/vpermxor.uc $(src)/unroll.awk FORCE
-       $(call if_changed,unroll)
-
 CFLAGS_vpermxor8.o += $(altivec_flags)
-targets += vpermxor8.c
-$(obj)/vpermxor8.c: UNROLL := 8
-$(obj)/vpermxor8.c: $(src)/vpermxor.uc $(src)/unroll.awk FORCE
+targets += vpermxor1.o vpermxor2.o vpermxor4.o vpermxor8.o
+$(obj)/vpermxor%.c: $(src)/vpermxor.uc $(src)/unroll.awk FORCE
        $(call if_changed,unroll)
 
 CFLAGS_neon1.o += $(NEON_FLAGS)
-targets += neon1.c
-$(obj)/neon1.c:   UNROLL := 1
-$(obj)/neon1.c:   $(src)/neon.uc $(src)/unroll.awk FORCE
-       $(call if_changed,unroll)
-
 CFLAGS_neon2.o += $(NEON_FLAGS)
-targets += neon2.c
-$(obj)/neon2.c:   UNROLL := 2
-$(obj)/neon2.c:   $(src)/neon.uc $(src)/unroll.awk FORCE
-       $(call if_changed,unroll)
-
 CFLAGS_neon4.o += $(NEON_FLAGS)
-targets += neon4.c
-$(obj)/neon4.c:   UNROLL := 4
-$(obj)/neon4.c:   $(src)/neon.uc $(src)/unroll.awk FORCE
-       $(call if_changed,unroll)
-
 CFLAGS_neon8.o += $(NEON_FLAGS)
-targets += neon8.c
-$(obj)/neon8.c:   UNROLL := 8
-$(obj)/neon8.c:   $(src)/neon.uc $(src)/unroll.awk FORCE
+targets += neon1.c neon2.c neon4.c neon8.c
+$(obj)/neon%.c: $(src)/neon.uc $(src)/unroll.awk FORCE
        $(call if_changed,unroll)
 
 targets += s390vx8.c
-$(obj)/s390vx8.c:   UNROLL := 8
-$(obj)/s390vx8.c:   $(src)/s390vx.uc $(src)/unroll.awk FORCE
+$(obj)/s390vx%.c: $(src)/s390vx.uc $(src)/unroll.awk FORCE
        $(call if_changed,unroll)
 
 quiet_cmd_mktable = TABLE   $@
index eacb824..c2cf2c3 100644 (file)
@@ -179,7 +179,8 @@ static void sg_kfree(struct scatterlist *sg, unsigned int nents)
  * __sg_free_table - Free a previously mapped sg table
  * @table:     The sg table header to use
  * @max_ents:  The maximum number of entries per single scatterlist
- * @skip_first_chunk: don't free the (preallocated) first scatterlist chunk
+ * @nents_first_chunk: Number of entries int the (preallocated) first
+ *     scatterlist chunk, 0 means no such preallocated first chunk
  * @free_fn:   Free function
  *
  *  Description:
@@ -189,9 +190,10 @@ static void sg_kfree(struct scatterlist *sg, unsigned int nents)
  *
  **/
 void __sg_free_table(struct sg_table *table, unsigned int max_ents,
-                    bool skip_first_chunk, sg_free_fn *free_fn)
+                    unsigned int nents_first_chunk, sg_free_fn *free_fn)
 {
        struct scatterlist *sgl, *next;
+       unsigned curr_max_ents = nents_first_chunk ?: max_ents;
 
        if (unlikely(!table->sgl))
                return;
@@ -207,9 +209,9 @@ void __sg_free_table(struct sg_table *table, unsigned int max_ents,
                 * sg_size is then one less than alloc size, since the last
                 * element is the chain pointer.
                 */
-               if (alloc_size > max_ents) {
-                       next = sg_chain_ptr(&sgl[max_ents - 1]);
-                       alloc_size = max_ents;
+               if (alloc_size > curr_max_ents) {
+                       next = sg_chain_ptr(&sgl[curr_max_ents - 1]);
+                       alloc_size = curr_max_ents;
                        sg_size = alloc_size - 1;
                } else {
                        sg_size = alloc_size;
@@ -217,11 +219,12 @@ void __sg_free_table(struct sg_table *table, unsigned int max_ents,
                }
 
                table->orig_nents -= sg_size;
-               if (skip_first_chunk)
-                       skip_first_chunk = false;
+               if (nents_first_chunk)
+                       nents_first_chunk = 0;
                else
                        free_fn(sgl, alloc_size);
                sgl = next;
+               curr_max_ents = max_ents;
        }
 
        table->sgl = NULL;
@@ -244,6 +247,8 @@ EXPORT_SYMBOL(sg_free_table);
  * @table:     The sg table header to use
  * @nents:     Number of entries in sg list
  * @max_ents:  The maximum number of entries the allocator returns per call
+ * @nents_first_chunk: Number of entries int the (preallocated) first
+ *     scatterlist chunk, 0 means no such preallocated chunk provided by user
  * @gfp_mask:  GFP allocation mask
  * @alloc_fn:  Allocator to use
  *
@@ -260,10 +265,13 @@ EXPORT_SYMBOL(sg_free_table);
  **/
 int __sg_alloc_table(struct sg_table *table, unsigned int nents,
                     unsigned int max_ents, struct scatterlist *first_chunk,
-                    gfp_t gfp_mask, sg_alloc_fn *alloc_fn)
+                    unsigned int nents_first_chunk, gfp_t gfp_mask,
+                    sg_alloc_fn *alloc_fn)
 {
        struct scatterlist *sg, *prv;
        unsigned int left;
+       unsigned curr_max_ents = nents_first_chunk ?: max_ents;
+       unsigned prv_max_ents;
 
        memset(table, 0, sizeof(*table));
 
@@ -279,8 +287,8 @@ int __sg_alloc_table(struct sg_table *table, unsigned int nents,
        do {
                unsigned int sg_size, alloc_size = left;
 
-               if (alloc_size > max_ents) {
-                       alloc_size = max_ents;
+               if (alloc_size > curr_max_ents) {
+                       alloc_size = curr_max_ents;
                        sg_size = alloc_size - 1;
                } else
                        sg_size = alloc_size;
@@ -314,7 +322,7 @@ int __sg_alloc_table(struct sg_table *table, unsigned int nents,
                 * If this is not the first mapping, chain previous part.
                 */
                if (prv)
-                       sg_chain(prv, max_ents, sg);
+                       sg_chain(prv, prv_max_ents, sg);
                else
                        table->sgl = sg;
 
@@ -325,6 +333,8 @@ int __sg_alloc_table(struct sg_table *table, unsigned int nents,
                        sg_mark_end(&sg[sg_size - 1]);
 
                prv = sg;
+               prv_max_ents = curr_max_ents;
+               curr_max_ents = max_ents;
        } while (left);
 
        return 0;
@@ -347,9 +357,9 @@ int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
        int ret;
 
        ret = __sg_alloc_table(table, nents, SG_MAX_SINGLE_ALLOC,
-                              NULL, gfp_mask, sg_kmalloc);
+                              NULL, 0, gfp_mask, sg_kmalloc);
        if (unlikely(ret))
-               __sg_free_table(table, SG_MAX_SINGLE_ALLOC, false, sg_kfree);
+               __sg_free_table(table, SG_MAX_SINGLE_ALLOC, 0, sg_kfree);
 
        return ret;
 }
index cff20df..db29e5c 100644 (file)
@@ -70,18 +70,27 @@ static struct scatterlist *sg_pool_alloc(unsigned int nents, gfp_t gfp_mask)
 /**
  * sg_free_table_chained - Free a previously mapped sg table
  * @table:     The sg table header to use
- * @first_chunk: was first_chunk not NULL in sg_alloc_table_chained?
+ * @nents_first_chunk: size of the first_chunk SGL passed to
+ *             sg_alloc_table_chained
  *
  *  Description:
  *    Free an sg table previously allocated and setup with
  *    sg_alloc_table_chained().
  *
+ *    @nents_first_chunk has to be same with that same parameter passed
+ *    to sg_alloc_table_chained().
+ *
  **/
-void sg_free_table_chained(struct sg_table *table, bool first_chunk)
+void sg_free_table_chained(struct sg_table *table,
+               unsigned nents_first_chunk)
 {
-       if (first_chunk && table->orig_nents <= SG_CHUNK_SIZE)
+       if (table->orig_nents <= nents_first_chunk)
                return;
-       __sg_free_table(table, SG_CHUNK_SIZE, first_chunk, sg_pool_free);
+
+       if (nents_first_chunk == 1)
+               nents_first_chunk = 0;
+
+       __sg_free_table(table, SG_CHUNK_SIZE, nents_first_chunk, sg_pool_free);
 }
 EXPORT_SYMBOL_GPL(sg_free_table_chained);
 
@@ -90,31 +99,41 @@ EXPORT_SYMBOL_GPL(sg_free_table_chained);
  * @table:     The sg table header to use
  * @nents:     Number of entries in sg list
  * @first_chunk: first SGL
+ * @nents_first_chunk: number of the SGL of @first_chunk
  *
  *  Description:
  *    Allocate and chain SGLs in an sg table. If @nents@ is larger than
- *    SG_CHUNK_SIZE a chained sg table will be setup.
+ *    @nents_first_chunk a chained sg table will be setup. @first_chunk is
+ *    ignored if nents_first_chunk <= 1 because user expects the SGL points
+ *    non-chain SGL.
  *
  **/
 int sg_alloc_table_chained(struct sg_table *table, int nents,
-               struct scatterlist *first_chunk)
+               struct scatterlist *first_chunk, unsigned nents_first_chunk)
 {
        int ret;
 
        BUG_ON(!nents);
 
-       if (first_chunk) {
-               if (nents <= SG_CHUNK_SIZE) {
+       if (first_chunk && nents_first_chunk) {
+               if (nents <= nents_first_chunk) {
                        table->nents = table->orig_nents = nents;
                        sg_init_table(table->sgl, nents);
                        return 0;
                }
        }
 
+       /* User supposes that the 1st SGL includes real entry */
+       if (nents_first_chunk <= 1) {
+               first_chunk = NULL;
+               nents_first_chunk = 0;
+       }
+
        ret = __sg_alloc_table(table, nents, SG_CHUNK_SIZE,
-                              first_chunk, GFP_ATOMIC, sg_pool_alloc);
+                              first_chunk, nents_first_chunk,
+                              GFP_ATOMIC, sg_pool_alloc);
        if (unlikely(ret))
-               sg_free_table_chained(table, (bool)first_chunk);
+               sg_free_table_chained(table, nents_first_chunk);
        return ret;
 }
 EXPORT_SYMBOL_GPL(sg_alloc_table_chained);
index e3c593c..b63b367 100644 (file)
@@ -7,16 +7,17 @@
 
 #define pr_fmt(fmt) "kasan test: %s " fmt, __func__
 
+#include <linux/bitops.h>
 #include <linux/delay.h>
+#include <linux/kasan.h>
 #include <linux/kernel.h>
-#include <linux/mman.h>
 #include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/module.h>
 #include <linux/printk.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/uaccess.h>
-#include <linux/module.h>
-#include <linux/kasan.h>
 
 /*
  * Note: test functions are marked noinline so that their names appear in
@@ -619,6 +620,95 @@ static noinline void __init kasan_strings(void)
        strnlen(ptr, 1);
 }
 
+static noinline void __init kasan_bitops(void)
+{
+       /*
+        * Allocate 1 more byte, which causes kzalloc to round up to 16-bytes;
+        * this way we do not actually corrupt other memory.
+        */
+       long *bits = kzalloc(sizeof(*bits) + 1, GFP_KERNEL);
+       if (!bits)
+               return;
+
+       /*
+        * Below calls try to access bit within allocated memory; however, the
+        * below accesses are still out-of-bounds, since bitops are defined to
+        * operate on the whole long the bit is in.
+        */
+       pr_info("out-of-bounds in set_bit\n");
+       set_bit(BITS_PER_LONG, bits);
+
+       pr_info("out-of-bounds in __set_bit\n");
+       __set_bit(BITS_PER_LONG, bits);
+
+       pr_info("out-of-bounds in clear_bit\n");
+       clear_bit(BITS_PER_LONG, bits);
+
+       pr_info("out-of-bounds in __clear_bit\n");
+       __clear_bit(BITS_PER_LONG, bits);
+
+       pr_info("out-of-bounds in clear_bit_unlock\n");
+       clear_bit_unlock(BITS_PER_LONG, bits);
+
+       pr_info("out-of-bounds in __clear_bit_unlock\n");
+       __clear_bit_unlock(BITS_PER_LONG, bits);
+
+       pr_info("out-of-bounds in change_bit\n");
+       change_bit(BITS_PER_LONG, bits);
+
+       pr_info("out-of-bounds in __change_bit\n");
+       __change_bit(BITS_PER_LONG, bits);
+
+       /*
+        * Below calls try to access bit beyond allocated memory.
+        */
+       pr_info("out-of-bounds in test_and_set_bit\n");
+       test_and_set_bit(BITS_PER_LONG + BITS_PER_BYTE, bits);
+
+       pr_info("out-of-bounds in __test_and_set_bit\n");
+       __test_and_set_bit(BITS_PER_LONG + BITS_PER_BYTE, bits);
+
+       pr_info("out-of-bounds in test_and_set_bit_lock\n");
+       test_and_set_bit_lock(BITS_PER_LONG + BITS_PER_BYTE, bits);
+
+       pr_info("out-of-bounds in test_and_clear_bit\n");
+       test_and_clear_bit(BITS_PER_LONG + BITS_PER_BYTE, bits);
+
+       pr_info("out-of-bounds in __test_and_clear_bit\n");
+       __test_and_clear_bit(BITS_PER_LONG + BITS_PER_BYTE, bits);
+
+       pr_info("out-of-bounds in test_and_change_bit\n");
+       test_and_change_bit(BITS_PER_LONG + BITS_PER_BYTE, bits);
+
+       pr_info("out-of-bounds in __test_and_change_bit\n");
+       __test_and_change_bit(BITS_PER_LONG + BITS_PER_BYTE, bits);
+
+       pr_info("out-of-bounds in test_bit\n");
+       (void)test_bit(BITS_PER_LONG + BITS_PER_BYTE, bits);
+
+#if defined(clear_bit_unlock_is_negative_byte)
+       pr_info("out-of-bounds in clear_bit_unlock_is_negative_byte\n");
+       clear_bit_unlock_is_negative_byte(BITS_PER_LONG + BITS_PER_BYTE, bits);
+#endif
+       kfree(bits);
+}
+
+static noinline void __init kmalloc_double_kzfree(void)
+{
+       char *ptr;
+       size_t size = 16;
+
+       pr_info("double-free (kzfree)\n");
+       ptr = kmalloc(size, GFP_KERNEL);
+       if (!ptr) {
+               pr_err("Allocation failed\n");
+               return;
+       }
+
+       kzfree(ptr);
+       kzfree(ptr);
+}
+
 static int __init kmalloc_tests_init(void)
 {
        /*
@@ -660,6 +750,8 @@ static int __init kmalloc_tests_init(void)
        kasan_memchr();
        kasan_memcmp();
        kasan_strings();
+       kasan_bitops();
+       kmalloc_double_kzfree();
 
        kasan_restore_multi_shot(multishot);
 
index ef6efed..0b43525 100644 (file)
@@ -132,7 +132,8 @@ config HAVE_MEMBLOCK_NODE_MAP
 config HAVE_MEMBLOCK_PHYS_MAP
        bool
 
-config HAVE_GENERIC_GUP
+config HAVE_FAST_GUP
+       depends on MMU
        bool
 
 config ARCH_KEEP_MEMBLOCK
@@ -762,7 +763,20 @@ config GUP_BENCHMARK
 
          See tools/testing/selftests/vm/gup_benchmark.c
 
+config GUP_GET_PTE_LOW_HIGH
+       bool
+
 config ARCH_HAS_PTE_SPECIAL
        bool
 
+#
+# Some architectures require a special hugepage directory format that is
+# required to support multiple hugepage sizes. For example a4fe3ce76
+# "powerpc/mm: Allow more flexible layouts for hugepage pagetables"
+# introduced it on powerpc.  This allows for a more flexible hugepage
+# pagetable layouts.
+#
+config ARCH_HAS_HUGEPD
+       bool
+
 endmenu
index fa6d792..82b6a20 100644 (file)
@@ -12,19 +12,23 @@ config DEBUG_PAGEALLOC
        bool "Debug page memory allocations"
        depends on DEBUG_KERNEL
        depends on !HIBERNATION || ARCH_SUPPORTS_DEBUG_PAGEALLOC && !PPC && !SPARC
-       select PAGE_EXTENSION
        select PAGE_POISONING if !ARCH_SUPPORTS_DEBUG_PAGEALLOC
        ---help---
          Unmap pages from the kernel linear mapping after free_pages().
          Depending on runtime enablement, this results in a small or large
          slowdown, but helps to find certain types of memory corruption.
 
+         Also, the state of page tracking structures is checked more often as
+         pages are being allocated and freed, as unexpected state changes
+         often happen for same reasons as memory corruption (e.g. double free,
+         use-after-free).
+
          For architectures which don't enable ARCH_SUPPORTS_DEBUG_PAGEALLOC,
          fill the pages with poison patterns after free_pages() and verify
-         the patterns before alloc_pages().  Additionally,
-         this option cannot be enabled in combination with hibernation as
-         that would result in incorrect warnings of memory corruption after
-         a resume because free pages are not saved to the suspend image.
+         the patterns before alloc_pages(). Additionally, this option cannot
+         be enabled in combination with hibernation as that would result in
+         incorrect warnings of memory corruption after a resume because free
+         pages are not saved to the suspend image.
 
          By default this option will have a small overhead, e.g. by not
          allowing the kernel mapping to be backed by large pages on some
index ac5e5ba..dc0746c 100644 (file)
@@ -22,7 +22,7 @@ KCOV_INSTRUMENT_mmzone.o := n
 KCOV_INSTRUMENT_vmstat.o := n
 
 mmu-y                  := nommu.o
-mmu-$(CONFIG_MMU)      := gup.o highmem.o memory.o mincore.o \
+mmu-$(CONFIG_MMU)      := highmem.o memory.o mincore.o \
                           mlock.o mmap.o mmu_gather.o mprotect.o mremap.o \
                           msync.o page_vma_mapped.o pagewalk.o \
                           pgtable-generic.o rmap.o vmalloc.o
@@ -39,7 +39,7 @@ obj-y                 := filemap.o mempool.o oom_kill.o fadvise.o \
                           mm_init.o mmu_context.o percpu.o slab_common.o \
                           compaction.o vmacache.o \
                           interval_tree.o list_lru.o workingset.o \
-                          debug.o $(mmu-y)
+                          debug.o gup.o $(mmu-y)
 
 # Give 'page_alloc' its own module-parameter namespace
 page-alloc-y := page_alloc.o
index 909dae4..e8e8915 100644 (file)
@@ -103,39 +103,25 @@ static int bdi_debug_stats_show(struct seq_file *m, void *v)
 }
 DEFINE_SHOW_ATTRIBUTE(bdi_debug_stats);
 
-static int bdi_debug_register(struct backing_dev_info *bdi, const char *name)
+static void bdi_debug_register(struct backing_dev_info *bdi, const char *name)
 {
-       if (!bdi_debug_root)
-               return -ENOMEM;
-
        bdi->debug_dir = debugfs_create_dir(name, bdi_debug_root);
-       if (!bdi->debug_dir)
-               return -ENOMEM;
-
-       bdi->debug_stats = debugfs_create_file("stats", 0444, bdi->debug_dir,
-                                              bdi, &bdi_debug_stats_fops);
-       if (!bdi->debug_stats) {
-               debugfs_remove(bdi->debug_dir);
-               bdi->debug_dir = NULL;
-               return -ENOMEM;
-       }
 
-       return 0;
+       debugfs_create_file("stats", 0444, bdi->debug_dir, bdi,
+                           &bdi_debug_stats_fops);
 }
 
 static void bdi_debug_unregister(struct backing_dev_info *bdi)
 {
-       debugfs_remove(bdi->debug_stats);
-       debugfs_remove(bdi->debug_dir);
+       debugfs_remove_recursive(bdi->debug_dir);
 }
 #else
 static inline void bdi_debug_init(void)
 {
 }
-static inline int bdi_debug_register(struct backing_dev_info *bdi,
+static inline void bdi_debug_register(struct backing_dev_info *bdi,
                                      const char *name)
 {
-       return 0;
 }
 static inline void bdi_debug_unregister(struct backing_dev_info *bdi)
 {
index ba739b7..83a7b61 100644 (file)
 #include <linux/export.h>
 #include <linux/balloon_compaction.h>
 
+static void balloon_page_enqueue_one(struct balloon_dev_info *b_dev_info,
+                                    struct page *page)
+{
+       /*
+        * Block others from accessing the 'page' when we get around to
+        * establishing additional references. We should be the only one
+        * holding a reference to the 'page' at this point. If we are not, then
+        * memory corruption is possible and we should stop execution.
+        */
+       BUG_ON(!trylock_page(page));
+       list_del(&page->lru);
+       balloon_page_insert(b_dev_info, page);
+       unlock_page(page);
+       __count_vm_event(BALLOON_INFLATE);
+}
+
+/**
+ * balloon_page_list_enqueue() - inserts a list of pages into the balloon page
+ *                              list.
+ * @b_dev_info: balloon device descriptor where we will insert a new page to
+ * @pages: pages to enqueue - allocated using balloon_page_alloc.
+ *
+ * Driver must call it to properly enqueue a balloon pages before definitively
+ * removing it from the guest system.
+ *
+ * Return: number of pages that were enqueued.
+ */
+size_t balloon_page_list_enqueue(struct balloon_dev_info *b_dev_info,
+                                struct list_head *pages)
+{
+       struct page *page, *tmp;
+       unsigned long flags;
+       size_t n_pages = 0;
+
+       spin_lock_irqsave(&b_dev_info->pages_lock, flags);
+       list_for_each_entry_safe(page, tmp, pages, lru) {
+               balloon_page_enqueue_one(b_dev_info, page);
+               n_pages++;
+       }
+       spin_unlock_irqrestore(&b_dev_info->pages_lock, flags);
+       return n_pages;
+}
+EXPORT_SYMBOL_GPL(balloon_page_list_enqueue);
+
+/**
+ * balloon_page_list_dequeue() - removes pages from balloon's page list and
+ *                              returns a list of the pages.
+ * @b_dev_info: balloon device decriptor where we will grab a page from.
+ * @pages: pointer to the list of pages that would be returned to the caller.
+ * @n_req_pages: number of requested pages.
+ *
+ * Driver must call this function to properly de-allocate a previous enlisted
+ * balloon pages before definetively releasing it back to the guest system.
+ * This function tries to remove @n_req_pages from the ballooned pages and
+ * return them to the caller in the @pages list.
+ *
+ * Note that this function may fail to dequeue some pages temporarily empty due
+ * to compaction isolated pages.
+ *
+ * Return: number of pages that were added to the @pages list.
+ */
+size_t balloon_page_list_dequeue(struct balloon_dev_info *b_dev_info,
+                                struct list_head *pages, size_t n_req_pages)
+{
+       struct page *page, *tmp;
+       unsigned long flags;
+       size_t n_pages = 0;
+
+       spin_lock_irqsave(&b_dev_info->pages_lock, flags);
+       list_for_each_entry_safe(page, tmp, &b_dev_info->pages, lru) {
+               if (n_pages == n_req_pages)
+                       break;
+
+               /*
+                * Block others from accessing the 'page' while we get around to
+                * establishing additional references and preparing the 'page'
+                * to be released by the balloon driver.
+                */
+               if (!trylock_page(page))
+                       continue;
+
+               if (IS_ENABLED(CONFIG_BALLOON_COMPACTION) &&
+                   PageIsolated(page)) {
+                       /* raced with isolation */
+                       unlock_page(page);
+                       continue;
+               }
+               balloon_page_delete(page);
+               __count_vm_event(BALLOON_DEFLATE);
+               list_add(&page->lru, pages);
+               unlock_page(page);
+               n_pages++;
+       }
+       spin_unlock_irqrestore(&b_dev_info->pages_lock, flags);
+
+       return n_pages;
+}
+EXPORT_SYMBOL_GPL(balloon_page_list_dequeue);
+
 /*
  * balloon_page_alloc - allocates a new page for insertion into the balloon
  *                       page list.
@@ -44,17 +143,9 @@ void balloon_page_enqueue(struct balloon_dev_info *b_dev_info,
 {
        unsigned long flags;
 
-       /*
-        * Block others from accessing the 'page' when we get around to
-        * establishing additional references. We should be the only one
-        * holding a reference to the 'page' at this point.
-        */
-       BUG_ON(!trylock_page(page));
        spin_lock_irqsave(&b_dev_info->pages_lock, flags);
-       balloon_page_insert(b_dev_info, page);
-       __count_vm_event(BALLOON_INFLATE);
+       balloon_page_enqueue_one(b_dev_info, page);
        spin_unlock_irqrestore(&b_dev_info->pages_lock, flags);
-       unlock_page(page);
 }
 EXPORT_SYMBOL_GPL(balloon_page_enqueue);
 
@@ -71,36 +162,13 @@ EXPORT_SYMBOL_GPL(balloon_page_enqueue);
  */
 struct page *balloon_page_dequeue(struct balloon_dev_info *b_dev_info)
 {
-       struct page *page, *tmp;
        unsigned long flags;
-       bool dequeued_page;
+       LIST_HEAD(pages);
+       int n_pages;
 
-       dequeued_page = false;
-       spin_lock_irqsave(&b_dev_info->pages_lock, flags);
-       list_for_each_entry_safe(page, tmp, &b_dev_info->pages, lru) {
-               /*
-                * Block others from accessing the 'page' while we get around
-                * establishing additional references and preparing the 'page'
-                * to be released by the balloon driver.
-                */
-               if (trylock_page(page)) {
-#ifdef CONFIG_BALLOON_COMPACTION
-                       if (PageIsolated(page)) {
-                               /* raced with isolation */
-                               unlock_page(page);
-                               continue;
-                       }
-#endif
-                       balloon_page_delete(page);
-                       __count_vm_event(BALLOON_DEFLATE);
-                       unlock_page(page);
-                       dequeued_page = true;
-                       break;
-               }
-       }
-       spin_unlock_irqrestore(&b_dev_info->pages_lock, flags);
+       n_pages = balloon_page_list_dequeue(b_dev_info, &pages, 1);
 
-       if (!dequeued_page) {
+       if (n_pages != 1) {
                /*
                 * If we are unable to dequeue a balloon page because the page
                 * list is empty and there is no isolated pages, then something
@@ -113,9 +181,9 @@ struct page *balloon_page_dequeue(struct balloon_dev_info *b_dev_info)
                             !b_dev_info->isolated_pages))
                        BUG();
                spin_unlock_irqrestore(&b_dev_info->pages_lock, flags);
-               page = NULL;
+               return NULL;
        }
-       return page;
+       return list_first_entry(&pages, struct page, lru);
 }
 EXPORT_SYMBOL_GPL(balloon_page_dequeue);
 
index 2397f7c..db7eee9 100644 (file)
@@ -304,8 +304,7 @@ static int __init init_cleancache(void)
 {
 #ifdef CONFIG_DEBUG_FS
        struct dentry *root = debugfs_create_dir("cleancache", NULL);
-       if (root == NULL)
-               return -ENXIO;
+
        debugfs_create_u64("succ_gets", 0444, root, &cleancache_succ_gets);
        debugfs_create_u64("failed_gets", 0444, root, &cleancache_failed_gets);
        debugfs_create_u64("puts", 0444, root, &cleancache_puts);
index 8c94c89..fe5d330 100644 (file)
@@ -378,7 +378,7 @@ void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags,
 #endif
        spin_unlock_irqrestore(&pool->lock, flags);
 
-       if (mem_flags & __GFP_ZERO)
+       if (want_init_on_alloc(mem_flags))
                memset(retval, 0, pool->size);
 
        return retval;
@@ -428,6 +428,8 @@ void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma)
        }
 
        offset = vaddr - page->vaddr;
+       if (want_init_on_free())
+               memset(vaddr, 0, pool->size);
 #ifdef DMAPOOL_DEBUG
        if ((dma - page->dma) != offset) {
                spin_unlock_irqrestore(&pool->lock, flags);
index ec5aad2..f92fed9 100644 (file)
@@ -23,7 +23,8 @@ bool __should_failslab(struct kmem_cache *s, gfp_t gfpflags)
        if (gfpflags & __GFP_NOFAIL)
                return false;
 
-       if (failslab.ignore_gfp_reclaim && (gfpflags & __GFP_RECLAIM))
+       if (failslab.ignore_gfp_reclaim &&
+                       (gfpflags & __GFP_DIRECT_RECLAIM))
                return false;
 
        if (failslab.cache_filter && !(s->flags & SLAB_FAILSLAB))
index f1aa20a..d0cf700 100644 (file)
@@ -2504,10 +2504,8 @@ static struct file *do_async_mmap_readahead(struct vm_fault *vmf,
  *
  * vma->vm_mm->mmap_sem must be held on entry.
  *
- * If our return value has VM_FAULT_RETRY set, it's because
- * lock_page_or_retry() returned 0.
- * The mmap_sem has usually been released in this case.
- * See __lock_page_or_retry() for the exception.
+ * If our return value has VM_FAULT_RETRY set, it's because the mmap_sem
+ * may be dropped before doing I/O or by lock_page_maybe_drop_mmap().
  *
  * If our return value does not have VM_FAULT_RETRY set, the mmap_sem
  * has not been released.
@@ -2825,7 +2823,11 @@ repeat:
                }
 
 filler:
-               err = filler(data, page);
+               if (filler)
+                       err = filler(data, page);
+               else
+                       err = mapping->a_ops->readpage(data, page);
+
                if (err < 0) {
                        put_page(page);
                        return ERR_PTR(err);
@@ -2915,7 +2917,8 @@ struct page *read_cache_page(struct address_space *mapping,
                                int (*filler)(void *, struct page *),
                                void *data)
 {
-       return do_read_cache_page(mapping, index, filler, data, mapping_gfp_mask(mapping));
+       return do_read_cache_page(mapping, index, filler, data,
+                       mapping_gfp_mask(mapping));
 }
 EXPORT_SYMBOL(read_cache_page);
 
@@ -2936,9 +2939,7 @@ struct page *read_cache_page_gfp(struct address_space *mapping,
                                pgoff_t index,
                                gfp_t gfp)
 {
-       filler_t *filler = (filler_t *)mapping->a_ops->readpage;
-
-       return do_read_cache_page(mapping, index, filler, NULL, gfp);
+       return do_read_cache_page(mapping, index, NULL, NULL, gfp);
 }
 EXPORT_SYMBOL(read_cache_page_gfp);
 
index ddde097..43b7d87 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -134,6 +134,7 @@ void put_user_pages(struct page **pages, unsigned long npages)
 }
 EXPORT_SYMBOL(put_user_pages);
 
+#ifdef CONFIG_MMU
 static struct page *no_page_table(struct vm_area_struct *vma,
                unsigned int flags)
 {
@@ -515,7 +516,7 @@ static struct page *follow_p4d_mask(struct vm_area_struct *vma,
  * an error pointer if there is a mapping to something not represented
  * by a page descriptor (see also vm_normal_page()).
  */
-struct page *follow_page_mask(struct vm_area_struct *vma,
+static struct page *follow_page_mask(struct vm_area_struct *vma,
                              unsigned long address, unsigned int flags,
                              struct follow_page_context *ctx)
 {
@@ -585,11 +586,14 @@ static int get_gate_page(struct mm_struct *mm, unsigned long address,
                pgd = pgd_offset_k(address);
        else
                pgd = pgd_offset_gate(mm, address);
-       BUG_ON(pgd_none(*pgd));
+       if (pgd_none(*pgd))
+               return -EFAULT;
        p4d = p4d_offset(pgd, address);
-       BUG_ON(p4d_none(*p4d));
+       if (p4d_none(*p4d))
+               return -EFAULT;
        pud = pud_offset(p4d, address);
-       BUG_ON(pud_none(*pud));
+       if (pud_none(*pud))
+               return -EFAULT;
        pmd = pmd_offset(pud, address);
        if (!pmd_present(*pmd))
                return -EFAULT;
@@ -1100,86 +1104,6 @@ static __always_inline long __get_user_pages_locked(struct task_struct *tsk,
        return pages_done;
 }
 
-/*
- * We can leverage the VM_FAULT_RETRY functionality in the page fault
- * paths better by using either get_user_pages_locked() or
- * get_user_pages_unlocked().
- *
- * get_user_pages_locked() is suitable to replace the form:
- *
- *      down_read(&mm->mmap_sem);
- *      do_something()
- *      get_user_pages(tsk, mm, ..., pages, NULL);
- *      up_read(&mm->mmap_sem);
- *
- *  to:
- *
- *      int locked = 1;
- *      down_read(&mm->mmap_sem);
- *      do_something()
- *      get_user_pages_locked(tsk, mm, ..., pages, &locked);
- *      if (locked)
- *          up_read(&mm->mmap_sem);
- */
-long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
-                          unsigned int gup_flags, struct page **pages,
-                          int *locked)
-{
-       /*
-        * FIXME: Current FOLL_LONGTERM behavior is incompatible with
-        * FAULT_FLAG_ALLOW_RETRY because of the FS DAX check requirement on
-        * vmas.  As there are no users of this flag in this call we simply
-        * disallow this option for now.
-        */
-       if (WARN_ON_ONCE(gup_flags & FOLL_LONGTERM))
-               return -EINVAL;
-
-       return __get_user_pages_locked(current, current->mm, start, nr_pages,
-                                      pages, NULL, locked,
-                                      gup_flags | FOLL_TOUCH);
-}
-EXPORT_SYMBOL(get_user_pages_locked);
-
-/*
- * get_user_pages_unlocked() is suitable to replace the form:
- *
- *      down_read(&mm->mmap_sem);
- *      get_user_pages(tsk, mm, ..., pages, NULL);
- *      up_read(&mm->mmap_sem);
- *
- *  with:
- *
- *      get_user_pages_unlocked(tsk, mm, ..., pages);
- *
- * It is functionally equivalent to get_user_pages_fast so
- * get_user_pages_fast should be used instead if specific gup_flags
- * (e.g. FOLL_FORCE) are not required.
- */
-long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages,
-                            struct page **pages, unsigned int gup_flags)
-{
-       struct mm_struct *mm = current->mm;
-       int locked = 1;
-       long ret;
-
-       /*
-        * FIXME: Current FOLL_LONGTERM behavior is incompatible with
-        * FAULT_FLAG_ALLOW_RETRY because of the FS DAX check requirement on
-        * vmas.  As there are no users of this flag in this call we simply
-        * disallow this option for now.
-        */
-       if (WARN_ON_ONCE(gup_flags & FOLL_LONGTERM))
-               return -EINVAL;
-
-       down_read(&mm->mmap_sem);
-       ret = __get_user_pages_locked(current, mm, start, nr_pages, pages, NULL,
-                                     &locked, gup_flags | FOLL_TOUCH);
-       if (locked)
-               up_read(&mm->mmap_sem);
-       return ret;
-}
-EXPORT_SYMBOL(get_user_pages_unlocked);
-
 /*
  * get_user_pages_remote() - pin user pages in memory
  * @tsk:       the task_struct to use for page fault accounting, or
@@ -1256,6 +1180,198 @@ long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
 }
 EXPORT_SYMBOL(get_user_pages_remote);
 
+/**
+ * populate_vma_page_range() -  populate a range of pages in the vma.
+ * @vma:   target vma
+ * @start: start address
+ * @end:   end address
+ * @nonblocking:
+ *
+ * This takes care of mlocking the pages too if VM_LOCKED is set.
+ *
+ * return 0 on success, negative error code on error.
+ *
+ * vma->vm_mm->mmap_sem must be held.
+ *
+ * If @nonblocking is NULL, it may be held for read or write and will
+ * be unperturbed.
+ *
+ * If @nonblocking is non-NULL, it must held for read only and may be
+ * released.  If it's released, *@nonblocking will be set to 0.
+ */
+long populate_vma_page_range(struct vm_area_struct *vma,
+               unsigned long start, unsigned long end, int *nonblocking)
+{
+       struct mm_struct *mm = vma->vm_mm;
+       unsigned long nr_pages = (end - start) / PAGE_SIZE;
+       int gup_flags;
+
+       VM_BUG_ON(start & ~PAGE_MASK);
+       VM_BUG_ON(end   & ~PAGE_MASK);
+       VM_BUG_ON_VMA(start < vma->vm_start, vma);
+       VM_BUG_ON_VMA(end   > vma->vm_end, vma);
+       VM_BUG_ON_MM(!rwsem_is_locked(&mm->mmap_sem), mm);
+
+       gup_flags = FOLL_TOUCH | FOLL_POPULATE | FOLL_MLOCK;
+       if (vma->vm_flags & VM_LOCKONFAULT)
+               gup_flags &= ~FOLL_POPULATE;
+       /*
+        * We want to touch writable mappings with a write fault in order
+        * to break COW, except for shared mappings because these don't COW
+        * and we would not want to dirty them for nothing.
+        */
+       if ((vma->vm_flags & (VM_WRITE | VM_SHARED)) == VM_WRITE)
+               gup_flags |= FOLL_WRITE;
+
+       /*
+        * We want mlock to succeed for regions that have any permissions
+        * other than PROT_NONE.
+        */
+       if (vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC))
+               gup_flags |= FOLL_FORCE;
+
+       /*
+        * We made sure addr is within a VMA, so the following will
+        * not result in a stack expansion that recurses back here.
+        */
+       return __get_user_pages(current, mm, start, nr_pages, gup_flags,
+                               NULL, NULL, nonblocking);
+}
+
+/*
+ * __mm_populate - populate and/or mlock pages within a range of address space.
+ *
+ * This is used to implement mlock() and the MAP_POPULATE / MAP_LOCKED mmap
+ * flags. VMAs must be already marked with the desired vm_flags, and
+ * mmap_sem must not be held.
+ */
+int __mm_populate(unsigned long start, unsigned long len, int ignore_errors)
+{
+       struct mm_struct *mm = current->mm;
+       unsigned long end, nstart, nend;
+       struct vm_area_struct *vma = NULL;
+       int locked = 0;
+       long ret = 0;
+
+       end = start + len;
+
+       for (nstart = start; nstart < end; nstart = nend) {
+               /*
+                * We want to fault in pages for [nstart; end) address range.
+                * Find first corresponding VMA.
+                */
+               if (!locked) {
+                       locked = 1;
+                       down_read(&mm->mmap_sem);
+                       vma = find_vma(mm, nstart);
+               } else if (nstart >= vma->vm_end)
+                       vma = vma->vm_next;
+               if (!vma || vma->vm_start >= end)
+                       break;
+               /*
+                * Set [nstart; nend) to intersection of desired address
+                * range with the first VMA. Also, skip undesirable VMA types.
+                */
+               nend = min(end, vma->vm_end);
+               if (vma->vm_flags & (VM_IO | VM_PFNMAP))
+                       continue;
+               if (nstart < vma->vm_start)
+                       nstart = vma->vm_start;
+               /*
+                * Now fault in a range of pages. populate_vma_page_range()
+                * double checks the vma flags, so that it won't mlock pages
+                * if the vma was already munlocked.
+                */
+               ret = populate_vma_page_range(vma, nstart, nend, &locked);
+               if (ret < 0) {
+                       if (ignore_errors) {
+                               ret = 0;
+                               continue;       /* continue at next VMA */
+                       }
+                       break;
+               }
+               nend = nstart + ret * PAGE_SIZE;
+               ret = 0;
+       }
+       if (locked)
+               up_read(&mm->mmap_sem);
+       return ret;     /* 0 or negative error code */
+}
+
+/**
+ * get_dump_page() - pin user page in memory while writing it to core dump
+ * @addr: user address
+ *
+ * Returns struct page pointer of user page pinned for dump,
+ * to be freed afterwards by put_page().
+ *
+ * Returns NULL on any kind of failure - a hole must then be inserted into
+ * the corefile, to preserve alignment with its headers; and also returns
+ * NULL wherever the ZERO_PAGE, or an anonymous pte_none, has been found -
+ * allowing a hole to be left in the corefile to save diskspace.
+ *
+ * Called without mmap_sem, but after all other threads have been killed.
+ */
+#ifdef CONFIG_ELF_CORE
+struct page *get_dump_page(unsigned long addr)
+{
+       struct vm_area_struct *vma;
+       struct page *page;
+
+       if (__get_user_pages(current, current->mm, addr, 1,
+                            FOLL_FORCE | FOLL_DUMP | FOLL_GET, &page, &vma,
+                            NULL) < 1)
+               return NULL;
+       flush_cache_page(vma, addr, page_to_pfn(page));
+       return page;
+}
+#endif /* CONFIG_ELF_CORE */
+#else /* CONFIG_MMU */
+static long __get_user_pages_locked(struct task_struct *tsk,
+               struct mm_struct *mm, unsigned long start,
+               unsigned long nr_pages, struct page **pages,
+               struct vm_area_struct **vmas, int *locked,
+               unsigned int foll_flags)
+{
+       struct vm_area_struct *vma;
+       unsigned long vm_flags;
+       int i;
+
+       /* calculate required read or write permissions.
+        * If FOLL_FORCE is set, we only require the "MAY" flags.
+        */
+       vm_flags  = (foll_flags & FOLL_WRITE) ?
+                       (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD);
+       vm_flags &= (foll_flags & FOLL_FORCE) ?
+                       (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE);
+
+       for (i = 0; i < nr_pages; i++) {
+               vma = find_vma(mm, start);
+               if (!vma)
+                       goto finish_or_fault;
+
+               /* protect what we can, including chardevs */
+               if ((vma->vm_flags & (VM_IO | VM_PFNMAP)) ||
+                   !(vm_flags & vma->vm_flags))
+                       goto finish_or_fault;
+
+               if (pages) {
+                       pages[i] = virt_to_page(start);
+                       if (pages[i])
+                               get_page(pages[i]);
+               }
+               if (vmas)
+                       vmas[i] = vma;
+               start = (start + PAGE_SIZE) & PAGE_MASK;
+       }
+
+       return i;
+
+finish_or_fault:
+       return i ? : -EFAULT;
+}
+#endif /* !CONFIG_MMU */
+
 #if defined(CONFIG_FS_DAX) || defined (CONFIG_CMA)
 static bool check_dax_vmas(struct vm_area_struct **vmas, long nr_pages)
 {
@@ -1336,25 +1452,31 @@ static long check_and_migrate_cma_pages(struct task_struct *tsk,
                                        struct vm_area_struct **vmas,
                                        unsigned int gup_flags)
 {
-       long i;
+       unsigned long i;
+       unsigned long step;
        bool drain_allow = true;
        bool migrate_allow = true;
        LIST_HEAD(cma_page_list);
 
 check_again:
-       for (i = 0; i < nr_pages; i++) {
+       for (i = 0; i < nr_pages;) {
+
+               struct page *head = compound_head(pages[i]);
+
+               /*
+                * gup may start from a tail page. Advance step by the left
+                * part.
+                */
+               step = (1 << compound_order(head)) - (pages[i] - head);
                /*
                 * If we get a page from the CMA zone, since we are going to
                 * be pinning these entries, we might as well move them out
                 * of the CMA zone if possible.
                 */
-               if (is_migrate_cma_page(pages[i])) {
-
-                       struct page *head = compound_head(pages[i]);
-
-                       if (PageHuge(head)) {
+               if (is_migrate_cma_page(head)) {
+                       if (PageHuge(head))
                                isolate_huge_page(head, &cma_page_list);
-                       else {
+                       else {
                                if (!PageLRU(head) && drain_allow) {
                                        lru_add_drain_all();
                                        drain_allow = false;
@@ -1369,6 +1491,8 @@ check_again:
                                }
                        }
                }
+
+               i += step;
        }
 
        if (!list_empty(&cma_page_list)) {
@@ -1417,7 +1541,7 @@ static long check_and_migrate_cma_pages(struct task_struct *tsk,
 {
        return nr_pages;
 }
-#endif
+#endif /* CONFIG_CMA */
 
 /*
  * __gup_longterm_locked() is a wrapper for __get_user_pages_locked which
@@ -1503,155 +1627,88 @@ long get_user_pages(unsigned long start, unsigned long nr_pages,
 }
 EXPORT_SYMBOL(get_user_pages);
 
-/**
- * populate_vma_page_range() -  populate a range of pages in the vma.
- * @vma:   target vma
- * @start: start address
- * @end:   end address
- * @nonblocking:
- *
- * This takes care of mlocking the pages too if VM_LOCKED is set.
+/*
+ * We can leverage the VM_FAULT_RETRY functionality in the page fault
+ * paths better by using either get_user_pages_locked() or
+ * get_user_pages_unlocked().
  *
- * return 0 on success, negative error code on error.
+ * get_user_pages_locked() is suitable to replace the form:
  *
- * vma->vm_mm->mmap_sem must be held.
+ *      down_read(&mm->mmap_sem);
+ *      do_something()
+ *      get_user_pages(tsk, mm, ..., pages, NULL);
+ *      up_read(&mm->mmap_sem);
  *
- * If @nonblocking is NULL, it may be held for read or write and will
- * be unperturbed.
+ *  to:
  *
- * If @nonblocking is non-NULL, it must held for read only and may be
- * released.  If it's released, *@nonblocking will be set to 0.
+ *      int locked = 1;
+ *      down_read(&mm->mmap_sem);
+ *      do_something()
+ *      get_user_pages_locked(tsk, mm, ..., pages, &locked);
+ *      if (locked)
+ *          up_read(&mm->mmap_sem);
  */
-long populate_vma_page_range(struct vm_area_struct *vma,
-               unsigned long start, unsigned long end, int *nonblocking)
+long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
+                          unsigned int gup_flags, struct page **pages,
+                          int *locked)
 {
-       struct mm_struct *mm = vma->vm_mm;
-       unsigned long nr_pages = (end - start) / PAGE_SIZE;
-       int gup_flags;
-
-       VM_BUG_ON(start & ~PAGE_MASK);
-       VM_BUG_ON(end   & ~PAGE_MASK);
-       VM_BUG_ON_VMA(start < vma->vm_start, vma);
-       VM_BUG_ON_VMA(end   > vma->vm_end, vma);
-       VM_BUG_ON_MM(!rwsem_is_locked(&mm->mmap_sem), mm);
-
-       gup_flags = FOLL_TOUCH | FOLL_POPULATE | FOLL_MLOCK;
-       if (vma->vm_flags & VM_LOCKONFAULT)
-               gup_flags &= ~FOLL_POPULATE;
-       /*
-        * We want to touch writable mappings with a write fault in order
-        * to break COW, except for shared mappings because these don't COW
-        * and we would not want to dirty them for nothing.
-        */
-       if ((vma->vm_flags & (VM_WRITE | VM_SHARED)) == VM_WRITE)
-               gup_flags |= FOLL_WRITE;
-
        /*
-        * We want mlock to succeed for regions that have any permissions
-        * other than PROT_NONE.
+        * FIXME: Current FOLL_LONGTERM behavior is incompatible with
+        * FAULT_FLAG_ALLOW_RETRY because of the FS DAX check requirement on
+        * vmas.  As there are no users of this flag in this call we simply
+        * disallow this option for now.
         */
-       if (vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC))
-               gup_flags |= FOLL_FORCE;
+       if (WARN_ON_ONCE(gup_flags & FOLL_LONGTERM))
+               return -EINVAL;
 
-       /*
-        * We made sure addr is within a VMA, so the following will
-        * not result in a stack expansion that recurses back here.
-        */
-       return __get_user_pages(current, mm, start, nr_pages, gup_flags,
-                               NULL, NULL, nonblocking);
+       return __get_user_pages_locked(current, current->mm, start, nr_pages,
+                                      pages, NULL, locked,
+                                      gup_flags | FOLL_TOUCH);
 }
+EXPORT_SYMBOL(get_user_pages_locked);
 
 /*
- * __mm_populate - populate and/or mlock pages within a range of address space.
+ * get_user_pages_unlocked() is suitable to replace the form:
  *
- * This is used to implement mlock() and the MAP_POPULATE / MAP_LOCKED mmap
- * flags. VMAs must be already marked with the desired vm_flags, and
- * mmap_sem must not be held.
+ *      down_read(&mm->mmap_sem);
+ *      get_user_pages(tsk, mm, ..., pages, NULL);
+ *      up_read(&mm->mmap_sem);
+ *
+ *  with:
+ *
+ *      get_user_pages_unlocked(tsk, mm, ..., pages);
+ *
+ * It is functionally equivalent to get_user_pages_fast so
+ * get_user_pages_fast should be used instead if specific gup_flags
+ * (e.g. FOLL_FORCE) are not required.
  */
-int __mm_populate(unsigned long start, unsigned long len, int ignore_errors)
+long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages,
+                            struct page **pages, unsigned int gup_flags)
 {
        struct mm_struct *mm = current->mm;
-       unsigned long end, nstart, nend;
-       struct vm_area_struct *vma = NULL;
-       int locked = 0;
-       long ret = 0;
+       int locked = 1;
+       long ret;
 
-       end = start + len;
+       /*
+        * FIXME: Current FOLL_LONGTERM behavior is incompatible with
+        * FAULT_FLAG_ALLOW_RETRY because of the FS DAX check requirement on
+        * vmas.  As there are no users of this flag in this call we simply
+        * disallow this option for now.
+        */
+       if (WARN_ON_ONCE(gup_flags & FOLL_LONGTERM))
+               return -EINVAL;
 
-       for (nstart = start; nstart < end; nstart = nend) {
-               /*
-                * We want to fault in pages for [nstart; end) address range.
-                * Find first corresponding VMA.
-                */
-               if (!locked) {
-                       locked = 1;
-                       down_read(&mm->mmap_sem);
-                       vma = find_vma(mm, nstart);
-               } else if (nstart >= vma->vm_end)
-                       vma = vma->vm_next;
-               if (!vma || vma->vm_start >= end)
-                       break;
-               /*
-                * Set [nstart; nend) to intersection of desired address
-                * range with the first VMA. Also, skip undesirable VMA types.
-                */
-               nend = min(end, vma->vm_end);
-               if (vma->vm_flags & (VM_IO | VM_PFNMAP))
-                       continue;
-               if (nstart < vma->vm_start)
-                       nstart = vma->vm_start;
-               /*
-                * Now fault in a range of pages. populate_vma_page_range()
-                * double checks the vma flags, so that it won't mlock pages
-                * if the vma was already munlocked.
-                */
-               ret = populate_vma_page_range(vma, nstart, nend, &locked);
-               if (ret < 0) {
-                       if (ignore_errors) {
-                               ret = 0;
-                               continue;       /* continue at next VMA */
-                       }
-                       break;
-               }
-               nend = nstart + ret * PAGE_SIZE;
-               ret = 0;
-       }
+       down_read(&mm->mmap_sem);
+       ret = __get_user_pages_locked(current, mm, start, nr_pages, pages, NULL,
+                                     &locked, gup_flags | FOLL_TOUCH);
        if (locked)
                up_read(&mm->mmap_sem);
-       return ret;     /* 0 or negative error code */
-}
-
-/**
- * get_dump_page() - pin user page in memory while writing it to core dump
- * @addr: user address
- *
- * Returns struct page pointer of user page pinned for dump,
- * to be freed afterwards by put_page().
- *
- * Returns NULL on any kind of failure - a hole must then be inserted into
- * the corefile, to preserve alignment with its headers; and also returns
- * NULL wherever the ZERO_PAGE, or an anonymous pte_none, has been found -
- * allowing a hole to be left in the corefile to save diskspace.
- *
- * Called without mmap_sem, but after all other threads have been killed.
- */
-#ifdef CONFIG_ELF_CORE
-struct page *get_dump_page(unsigned long addr)
-{
-       struct vm_area_struct *vma;
-       struct page *page;
-
-       if (__get_user_pages(current, current->mm, addr, 1,
-                            FOLL_FORCE | FOLL_DUMP | FOLL_GET, &page, &vma,
-                            NULL) < 1)
-               return NULL;
-       flush_cache_page(vma, addr, page_to_pfn(page));
-       return page;
+       return ret;
 }
-#endif /* CONFIG_ELF_CORE */
+EXPORT_SYMBOL(get_user_pages_unlocked);
 
 /*
- * Generic Fast GUP
+ * Fast GUP
  *
  * get_user_pages_fast attempts to pin user pages by walking the page
  * tables directly and avoids taking locks. Thus the walker needs to be
@@ -1683,20 +1740,64 @@ struct page *get_dump_page(unsigned long addr)
  *
  * This code is based heavily on the PowerPC implementation by Nick Piggin.
  */
-#ifdef CONFIG_HAVE_GENERIC_GUP
+#ifdef CONFIG_HAVE_FAST_GUP
+#ifdef CONFIG_GUP_GET_PTE_LOW_HIGH
+/*
+ * WARNING: only to be used in the get_user_pages_fast() implementation.
+ *
+ * With get_user_pages_fast(), we walk down the pagetables without taking any
+ * locks.  For this we would like to load the pointers atomically, but sometimes
+ * that is not possible (e.g. without expensive cmpxchg8b on x86_32 PAE).  What
+ * we do have is the guarantee that a PTE will only either go from not present
+ * to present, or present to not present or both -- it will not switch to a
+ * completely different present page without a TLB flush in between; something
+ * that we are blocking by holding interrupts off.
+ *
+ * Setting ptes from not present to present goes:
+ *
+ *   ptep->pte_high = h;
+ *   smp_wmb();
+ *   ptep->pte_low = l;
+ *
+ * And present to not present goes:
+ *
+ *   ptep->pte_low = 0;
+ *   smp_wmb();
+ *   ptep->pte_high = 0;
+ *
+ * We must ensure here that the load of pte_low sees 'l' IFF pte_high sees 'h'.
+ * We load pte_high *after* loading pte_low, which ensures we don't see an older
+ * value of pte_high.  *Then* we recheck pte_low, which ensures that we haven't
+ * picked up a changed pte high. We might have gotten rubbish values from
+ * pte_low and pte_high, but we are guaranteed that pte_low will not have the
+ * present bit set *unless* it is 'l'. Because get_user_pages_fast() only
+ * operates on present ptes we're safe.
+ */
+static inline pte_t gup_get_pte(pte_t *ptep)
+{
+       pte_t pte;
 
-#ifndef gup_get_pte
+       do {
+               pte.pte_low = ptep->pte_low;
+               smp_rmb();
+               pte.pte_high = ptep->pte_high;
+               smp_rmb();
+       } while (unlikely(pte.pte_low != ptep->pte_low));
+
+       return pte;
+}
+#else /* CONFIG_GUP_GET_PTE_LOW_HIGH */
 /*
- * We assume that the PTE can be read atomically. If this is not the case for
- * your architecture, please provide the helper.
+ * We require that the PTE can be read atomically.
  */
 static inline pte_t gup_get_pte(pte_t *ptep)
 {
        return READ_ONCE(*ptep);
 }
-#endif
+#endif /* CONFIG_GUP_GET_PTE_LOW_HIGH */
 
-static void undo_dev_pagemap(int *nr, int nr_start, struct page **pages)
+static void __maybe_unused undo_dev_pagemap(int *nr, int nr_start,
+                                           struct page **pages)
 {
        while ((*nr) - nr_start) {
                struct page *page = pages[--(*nr)];
@@ -1877,6 +1978,90 @@ static int __gup_device_huge_pud(pud_t pud, pud_t *pudp, unsigned long addr,
 }
 #endif
 
+#ifdef CONFIG_ARCH_HAS_HUGEPD
+static unsigned long hugepte_addr_end(unsigned long addr, unsigned long end,
+                                     unsigned long sz)
+{
+       unsigned long __boundary = (addr + sz) & ~(sz-1);
+       return (__boundary - 1 < end - 1) ? __boundary : end;
+}
+
+static int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,
+                      unsigned long end, int write, struct page **pages, int *nr)
+{
+       unsigned long pte_end;
+       struct page *head, *page;
+       pte_t pte;
+       int refs;
+
+       pte_end = (addr + sz) & ~(sz-1);
+       if (pte_end < end)
+               end = pte_end;
+
+       pte = READ_ONCE(*ptep);
+
+       if (!pte_access_permitted(pte, write))
+               return 0;
+
+       /* hugepages are never "special" */
+       VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
+
+       refs = 0;
+       head = pte_page(pte);
+
+       page = head + ((addr & (sz-1)) >> PAGE_SHIFT);
+       do {
+               VM_BUG_ON(compound_head(page) != head);
+               pages[*nr] = page;
+               (*nr)++;
+               page++;
+               refs++;
+       } while (addr += PAGE_SIZE, addr != end);
+
+       head = try_get_compound_head(head, refs);
+       if (!head) {
+               *nr -= refs;
+               return 0;
+       }
+
+       if (unlikely(pte_val(pte) != pte_val(*ptep))) {
+               /* Could be optimized better */
+               *nr -= refs;
+               while (refs--)
+                       put_page(head);
+               return 0;
+       }
+
+       SetPageReferenced(head);
+       return 1;
+}
+
+static int gup_huge_pd(hugepd_t hugepd, unsigned long addr,
+               unsigned int pdshift, unsigned long end, int write,
+               struct page **pages, int *nr)
+{
+       pte_t *ptep;
+       unsigned long sz = 1UL << hugepd_shift(hugepd);
+       unsigned long next;
+
+       ptep = hugepte_offset(hugepd, addr, pdshift);
+       do {
+               next = hugepte_addr_end(addr, end, sz);
+               if (!gup_hugepte(ptep, sz, addr, end, write, pages, nr))
+                       return 0;
+       } while (ptep++, addr = next, addr != end);
+
+       return 1;
+}
+#else
+static inline int gup_huge_pd(hugepd_t hugepd, unsigned long addr,
+               unsigned pdshift, unsigned long end, int write,
+               struct page **pages, int *nr)
+{
+       return 0;
+}
+#endif /* CONFIG_ARCH_HAS_HUGEPD */
+
 static int gup_huge_pmd(pmd_t orig, pmd_t *pmdp, unsigned long addr,
                unsigned long end, unsigned int flags, struct page **pages, int *nr)
 {
@@ -2117,19 +2302,21 @@ static void gup_pgd_range(unsigned long addr, unsigned long end,
                        return;
        } while (pgdp++, addr = next, addr != end);
 }
+#else
+static inline void gup_pgd_range(unsigned long addr, unsigned long end,
+               unsigned int flags, struct page **pages, int *nr)
+{
+}
+#endif /* CONFIG_HAVE_FAST_GUP */
 
 #ifndef gup_fast_permitted
 /*
  * Check if it's allowed to use __get_user_pages_fast() for the range, or
  * we need to fall back to the slow version:
  */
-bool gup_fast_permitted(unsigned long start, int nr_pages)
+static bool gup_fast_permitted(unsigned long start, unsigned long end)
 {
-       unsigned long len, end;
-
-       len = (unsigned long) nr_pages << PAGE_SHIFT;
-       end = start + len;
-       return end >= start;
+       return true;
 }
 #endif
 
@@ -2138,6 +2325,9 @@ bool gup_fast_permitted(unsigned long start, int nr_pages)
  * the regular GUP.
  * Note a difference with get_user_pages_fast: this always returns the
  * number of pages pinned, 0 if no pages were pinned.
+ *
+ * If the architecture does not support this function, simply return with no
+ * pages pinned.
  */
 int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
                          struct page **pages)
@@ -2146,10 +2336,12 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
        unsigned long flags;
        int nr = 0;
 
-       start &= PAGE_MASK;
+       start = untagged_addr(start) & PAGE_MASK;
        len = (unsigned long) nr_pages << PAGE_SHIFT;
        end = start + len;
 
+       if (end <= start)
+               return 0;
        if (unlikely(!access_ok((void __user *)start, len)))
                return 0;
 
@@ -2165,7 +2357,8 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
         * block IPIs that come from THPs splitting.
         */
 
-       if (gup_fast_permitted(start, nr_pages)) {
+       if (IS_ENABLED(CONFIG_HAVE_FAST_GUP) &&
+           gup_fast_permitted(start, end)) {
                local_irq_save(flags);
                gup_pgd_range(start, end, write ? FOLL_WRITE : 0, pages, &nr);
                local_irq_restore(flags);
@@ -2173,6 +2366,7 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
 
        return nr;
 }
+EXPORT_SYMBOL_GPL(__get_user_pages_fast);
 
 static int __gup_longterm_unlocked(unsigned long start, int nr_pages,
                                   unsigned int gup_flags, struct page **pages)
@@ -2219,18 +2413,21 @@ int get_user_pages_fast(unsigned long start, int nr_pages,
        unsigned long addr, len, end;
        int nr = 0, ret = 0;
 
-       start &= PAGE_MASK;
+       if (WARN_ON_ONCE(gup_flags & ~(FOLL_WRITE | FOLL_LONGTERM)))
+               return -EINVAL;
+
+       start = untagged_addr(start) & PAGE_MASK;
        addr = start;
        len = (unsigned long) nr_pages << PAGE_SHIFT;
        end = start + len;
 
-       if (nr_pages <= 0)
+       if (end <= start)
                return 0;
-
        if (unlikely(!access_ok((void __user *)start, len)))
                return -EFAULT;
 
-       if (gup_fast_permitted(start, nr_pages)) {
+       if (IS_ENABLED(CONFIG_HAVE_FAST_GUP) &&
+           gup_fast_permitted(start, end)) {
                local_irq_disable();
                gup_pgd_range(addr, end, gup_flags, pages, &nr);
                local_irq_enable();
@@ -2256,5 +2453,4 @@ int get_user_pages_fast(unsigned long start, int nr_pages,
 
        return ret;
 }
-
-#endif /* CONFIG_HAVE_GENERIC_GUP */
+EXPORT_SYMBOL_GPL(get_user_pages_fast);
index 1a7497d..5b7430b 100644 (file)
@@ -77,63 +77,40 @@ static void pfn_inject_exit(void)
 
 static int pfn_inject_init(void)
 {
-       struct dentry *dentry;
-
        hwpoison_dir = debugfs_create_dir("hwpoison", NULL);
-       if (hwpoison_dir == NULL)
-               return -ENOMEM;
 
        /*
         * Note that the below poison/unpoison interfaces do not involve
         * hardware status change, hence do not require hardware support.
         * They are mainly for testing hwpoison in software level.
         */
-       dentry = debugfs_create_file("corrupt-pfn", 0200, hwpoison_dir,
-                                         NULL, &hwpoison_fops);
-       if (!dentry)
-               goto fail;
-
-       dentry = debugfs_create_file("unpoison-pfn", 0200, hwpoison_dir,
-                                    NULL, &unpoison_fops);
-       if (!dentry)
-               goto fail;
-
-       dentry = debugfs_create_u32("corrupt-filter-enable", 0600,
-                                   hwpoison_dir, &hwpoison_filter_enable);
-       if (!dentry)
-               goto fail;
-
-       dentry = debugfs_create_u32("corrupt-filter-dev-major", 0600,
-                                   hwpoison_dir, &hwpoison_filter_dev_major);
-       if (!dentry)
-               goto fail;
-
-       dentry = debugfs_create_u32("corrupt-filter-dev-minor", 0600,
-                                   hwpoison_dir, &hwpoison_filter_dev_minor);
-       if (!dentry)
-               goto fail;
-
-       dentry = debugfs_create_u64("corrupt-filter-flags-mask", 0600,
-                                   hwpoison_dir, &hwpoison_filter_flags_mask);
-       if (!dentry)
-               goto fail;
-
-       dentry = debugfs_create_u64("corrupt-filter-flags-value", 0600,
-                                   hwpoison_dir, &hwpoison_filter_flags_value);
-       if (!dentry)
-               goto fail;
+       debugfs_create_file("corrupt-pfn", 0200, hwpoison_dir, NULL,
+                           &hwpoison_fops);
+
+       debugfs_create_file("unpoison-pfn", 0200, hwpoison_dir, NULL,
+                           &unpoison_fops);
+
+       debugfs_create_u32("corrupt-filter-enable", 0600, hwpoison_dir,
+                          &hwpoison_filter_enable);
+
+       debugfs_create_u32("corrupt-filter-dev-major", 0600, hwpoison_dir,
+                          &hwpoison_filter_dev_major);
+
+       debugfs_create_u32("corrupt-filter-dev-minor", 0600, hwpoison_dir,
+                          &hwpoison_filter_dev_minor);
+
+       debugfs_create_u64("corrupt-filter-flags-mask", 0600, hwpoison_dir,
+                          &hwpoison_filter_flags_mask);
+
+       debugfs_create_u64("corrupt-filter-flags-value", 0600, hwpoison_dir,
+                          &hwpoison_filter_flags_value);
 
 #ifdef CONFIG_MEMCG
-       dentry = debugfs_create_u64("corrupt-filter-memcg", 0600,
-                                   hwpoison_dir, &hwpoison_filter_memcg);
-       if (!dentry)
-               goto fail;
+       debugfs_create_u64("corrupt-filter-memcg", 0600, hwpoison_dir,
+                          &hwpoison_filter_memcg);
 #endif
 
        return 0;
-fail:
-       pfn_inject_exit();
-       return -ENOMEM;
 }
 
 module_init(pfn_inject_init);
index 242fdc0..2277b82 100644 (file)
@@ -14,8 +14,6 @@
  *
  */
 
-#define __KASAN_INTERNAL
-
 #include <linux/export.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -89,17 +87,17 @@ void kasan_disable_current(void)
        current->kasan_depth--;
 }
 
-void kasan_check_read(const volatile void *p, unsigned int size)
+bool __kasan_check_read(const volatile void *p, unsigned int size)
 {
-       check_memory_region((unsigned long)p, size, false, _RET_IP_);
+       return check_memory_region((unsigned long)p, size, false, _RET_IP_);
 }
-EXPORT_SYMBOL(kasan_check_read);
+EXPORT_SYMBOL(__kasan_check_read);
 
-void kasan_check_write(const volatile void *p, unsigned int size)
+bool __kasan_check_write(const volatile void *p, unsigned int size)
 {
-       check_memory_region((unsigned long)p, size, true, _RET_IP_);
+       return check_memory_region((unsigned long)p, size, true, _RET_IP_);
 }
-EXPORT_SYMBOL(kasan_check_write);
+EXPORT_SYMBOL(__kasan_check_write);
 
 #undef memset
 void *memset(void *addr, int c, size_t len)
index 504c793..616f9dd 100644 (file)
@@ -166,29 +166,30 @@ static __always_inline bool memory_is_poisoned(unsigned long addr, size_t size)
        return memory_is_poisoned_n(addr, size);
 }
 
-static __always_inline void check_memory_region_inline(unsigned long addr,
+static __always_inline bool check_memory_region_inline(unsigned long addr,
                                                size_t size, bool write,
                                                unsigned long ret_ip)
 {
        if (unlikely(size == 0))
-               return;
+               return true;
 
        if (unlikely((void *)addr <
                kasan_shadow_to_mem((void *)KASAN_SHADOW_START))) {
                kasan_report(addr, size, write, ret_ip);
-               return;
+               return false;
        }
 
        if (likely(!memory_is_poisoned(addr, size)))
-               return;
+               return true;
 
        kasan_report(addr, size, write, ret_ip);
+       return false;
 }
 
-void check_memory_region(unsigned long addr, size_t size, bool write,
+bool check_memory_region(unsigned long addr, size_t size, bool write,
                                unsigned long ret_ip)
 {
-       check_memory_region_inline(addr, size, write, ret_ip);
+       return check_memory_region_inline(addr, size, write, ret_ip);
 }
 
 void kasan_cache_shrink(struct kmem_cache *cache)
index 3ce956e..014f19e 100644 (file)
 
 #define KASAN_ALLOCA_REDZONE_SIZE      32
 
+/*
+ * Stack frame marker (compiler ABI).
+ */
+#define KASAN_CURRENT_STACK_FRAME_MAGIC 0x41B58AB3
+
 /* Don't break randconfig/all*config builds */
 #ifndef KASAN_ABI_VERSION
 #define KASAN_ABI_VERSION 1
@@ -123,7 +128,15 @@ static inline bool addr_has_shadow(const void *addr)
 
 void kasan_poison_shadow(const void *address, size_t size, u8 value);
 
-void check_memory_region(unsigned long addr, size_t size, bool write,
+/**
+ * check_memory_region - Check memory region, and report if invalid access.
+ * @addr: the accessed address
+ * @size: the accessed size
+ * @write: true if access is a write access
+ * @ret_ip: return address
+ * @return: true if access was valid, false if invalid
+ */
+bool check_memory_region(unsigned long addr, size_t size, bool write,
                                unsigned long ret_ip);
 
 void *find_first_bad_addr(void *addr, size_t size);
index 03a4435..0e5f965 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/types.h>
 #include <linux/kasan.h>
 #include <linux/module.h>
+#include <linux/sched/task_stack.h>
 
 #include <asm/sections.h>
 
@@ -181,6 +182,168 @@ static inline bool init_task_stack_addr(const void *addr)
                        sizeof(init_thread_union.stack));
 }
 
+static bool __must_check tokenize_frame_descr(const char **frame_descr,
+                                             char *token, size_t max_tok_len,
+                                             unsigned long *value)
+{
+       const char *sep = strchr(*frame_descr, ' ');
+
+       if (sep == NULL)
+               sep = *frame_descr + strlen(*frame_descr);
+
+       if (token != NULL) {
+               const size_t tok_len = sep - *frame_descr;
+
+               if (tok_len + 1 > max_tok_len) {
+                       pr_err("KASAN internal error: frame description too long: %s\n",
+                              *frame_descr);
+                       return false;
+               }
+
+               /* Copy token (+ 1 byte for '\0'). */
+               strlcpy(token, *frame_descr, tok_len + 1);
+       }
+
+       /* Advance frame_descr past separator. */
+       *frame_descr = sep + 1;
+
+       if (value != NULL && kstrtoul(token, 10, value)) {
+               pr_err("KASAN internal error: not a valid number: %s\n", token);
+               return false;
+       }
+
+       return true;
+}
+
+static void print_decoded_frame_descr(const char *frame_descr)
+{
+       /*
+        * We need to parse the following string:
+        *    "n alloc_1 alloc_2 ... alloc_n"
+        * where alloc_i looks like
+        *    "offset size len name"
+        * or "offset size len name:line".
+        */
+
+       char token[64];
+       unsigned long num_objects;
+
+       if (!tokenize_frame_descr(&frame_descr, token, sizeof(token),
+                                 &num_objects))
+               return;
+
+       pr_err("\n");
+       pr_err("this frame has %lu %s:\n", num_objects,
+              num_objects == 1 ? "object" : "objects");
+
+       while (num_objects--) {
+               unsigned long offset;
+               unsigned long size;
+
+               /* access offset */
+               if (!tokenize_frame_descr(&frame_descr, token, sizeof(token),
+                                         &offset))
+                       return;
+               /* access size */
+               if (!tokenize_frame_descr(&frame_descr, token, sizeof(token),
+                                         &size))
+                       return;
+               /* name length (unused) */
+               if (!tokenize_frame_descr(&frame_descr, NULL, 0, NULL))
+                       return;
+               /* object name */
+               if (!tokenize_frame_descr(&frame_descr, token, sizeof(token),
+                                         NULL))
+                       return;
+
+               /* Strip line number; without filename it's not very helpful. */
+               strreplace(token, ':', '\0');
+
+               /* Finally, print object information. */
+               pr_err(" [%lu, %lu) '%s'", offset, offset + size, token);
+       }
+}
+
+static bool __must_check get_address_stack_frame_info(const void *addr,
+                                                     unsigned long *offset,
+                                                     const char **frame_descr,
+                                                     const void **frame_pc)
+{
+       unsigned long aligned_addr;
+       unsigned long mem_ptr;
+       const u8 *shadow_bottom;
+       const u8 *shadow_ptr;
+       const unsigned long *frame;
+
+       BUILD_BUG_ON(IS_ENABLED(CONFIG_STACK_GROWSUP));
+
+       /*
+        * NOTE: We currently only support printing frame information for
+        * accesses to the task's own stack.
+        */
+       if (!object_is_on_stack(addr))
+               return false;
+
+       aligned_addr = round_down((unsigned long)addr, sizeof(long));
+       mem_ptr = round_down(aligned_addr, KASAN_SHADOW_SCALE_SIZE);
+       shadow_ptr = kasan_mem_to_shadow((void *)aligned_addr);
+       shadow_bottom = kasan_mem_to_shadow(end_of_stack(current));
+
+       while (shadow_ptr >= shadow_bottom && *shadow_ptr != KASAN_STACK_LEFT) {
+               shadow_ptr--;
+               mem_ptr -= KASAN_SHADOW_SCALE_SIZE;
+       }
+
+       while (shadow_ptr >= shadow_bottom && *shadow_ptr == KASAN_STACK_LEFT) {
+               shadow_ptr--;
+               mem_ptr -= KASAN_SHADOW_SCALE_SIZE;
+       }
+
+       if (shadow_ptr < shadow_bottom)
+               return false;
+
+       frame = (const unsigned long *)(mem_ptr + KASAN_SHADOW_SCALE_SIZE);
+       if (frame[0] != KASAN_CURRENT_STACK_FRAME_MAGIC) {
+               pr_err("KASAN internal error: frame info validation failed; invalid marker: %lu\n",
+                      frame[0]);
+               return false;
+       }
+
+       *offset = (unsigned long)addr - (unsigned long)frame;
+       *frame_descr = (const char *)frame[1];
+       *frame_pc = (void *)frame[2];
+
+       return true;
+}
+
+static void print_address_stack_frame(const void *addr)
+{
+       unsigned long offset;
+       const char *frame_descr;
+       const void *frame_pc;
+
+       if (IS_ENABLED(CONFIG_KASAN_SW_TAGS))
+               return;
+
+       if (!get_address_stack_frame_info(addr, &offset, &frame_descr,
+                                         &frame_pc))
+               return;
+
+       /*
+        * get_address_stack_frame_info only returns true if the given addr is
+        * on the current task's stack.
+        */
+       pr_err("\n");
+       pr_err("addr %px is located in stack of task %s/%d at offset %lu in frame:\n",
+              addr, current->comm, task_pid_nr(current), offset);
+       pr_err(" %pS\n", frame_pc);
+
+       if (!frame_descr)
+               return;
+
+       print_decoded_frame_descr(frame_descr);
+}
+
 static void print_address_description(void *addr)
 {
        struct page *page = addr_to_page(addr);
@@ -204,6 +367,8 @@ static void print_address_description(void *addr)
                pr_err("The buggy address belongs to the page:\n");
                dump_page(page, "kasan: bad access detected");
        }
+
+       print_address_stack_frame(addr);
 }
 
 static bool row_is_guilty(const void *row, const void *guilty)
index 63fca31..0e987c9 100644 (file)
@@ -76,7 +76,7 @@ void *kasan_reset_tag(const void *addr)
        return reset_tag(addr);
 }
 
-void check_memory_region(unsigned long addr, size_t size, bool write,
+bool check_memory_region(unsigned long addr, size_t size, bool write,
                                unsigned long ret_ip)
 {
        u8 tag;
@@ -84,7 +84,7 @@ void check_memory_region(unsigned long addr, size_t size, bool write,
        void *untagged_addr;
 
        if (unlikely(size == 0))
-               return;
+               return true;
 
        tag = get_tag((const void *)addr);
 
@@ -106,22 +106,24 @@ void check_memory_region(unsigned long addr, size_t size, bool write,
         * set to KASAN_TAG_KERNEL (0xFF)).
         */
        if (tag == KASAN_TAG_KERNEL)
-               return;
+               return true;
 
        untagged_addr = reset_tag((const void *)addr);
        if (unlikely(untagged_addr <
                        kasan_shadow_to_mem((void *)KASAN_SHADOW_START))) {
                kasan_report(addr, size, write, ret_ip);
-               return;
+               return false;
        }
        shadow_first = kasan_mem_to_shadow(untagged_addr);
        shadow_last = kasan_mem_to_shadow(untagged_addr + size - 1);
        for (shadow = shadow_first; shadow <= shadow_last; shadow++) {
                if (*shadow != tag) {
                        kasan_report(addr, size, write, ret_ip);
-                       return;
+                       return false;
                }
        }
+
+       return true;
 }
 
 #define DEFINE_HWASAN_LOAD_STORE(size)                                 \
index 9dd581d..dbbd518 100644 (file)
@@ -575,7 +575,7 @@ static struct kmemleak_object *create_object(unsigned long ptr, size_t size,
        if (in_irq()) {
                object->pid = 0;
                strncpy(object->comm, "hardirq", sizeof(object->comm));
-       } else if (in_softirq()) {
+       } else if (in_serving_softirq()) {
                object->pid = 0;
                strncpy(object->comm, "softirq", sizeof(object->comm));
        } else {
@@ -1866,7 +1866,7 @@ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
        }
 
        if (!kmemleak_enabled) {
-               ret = -EBUSY;
+               ret = -EPERM;
                goto out;
        }
 
@@ -2105,14 +2105,9 @@ void __init kmemleak_init(void)
  */
 static int __init kmemleak_late_init(void)
 {
-       struct dentry *dentry;
-
        kmemleak_initialized = 1;
 
-       dentry = debugfs_create_file("kmemleak", 0644, NULL, NULL,
-                                    &kmemleak_fops);
-       if (!dentry)
-               pr_warn("Failed to create the debugfs kmemleak file\n");
+       debugfs_create_file("kmemleak", 0644, NULL, NULL, &kmemleak_fops);
 
        if (kmemleak_error) {
                /*
index 927d85b..0f1f6b0 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/memcontrol.h>
+#include "slab.h"
 
 #ifdef CONFIG_MEMCG_KMEM
 static LIST_HEAD(list_lrus);
@@ -63,7 +64,7 @@ static __always_inline struct mem_cgroup *mem_cgroup_from_kmem(void *ptr)
        if (!memcg_kmem_enabled())
                return NULL;
        page = virt_to_head_page(ptr);
-       return page->mem_cgroup;
+       return memcg_from_slab_page(page);
 }
 
 static inline struct list_lru_one *
index ba9138a..4f05735 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/lockdep.h>
 #include <linux/file.h>
 #include <linux/tracehook.h>
+#include <linux/seq_buf.h>
 #include "internal.h"
 #include <net/sock.h>
 #include <net/ip.h>
@@ -485,7 +486,10 @@ ino_t page_cgroup_ino(struct page *page)
        unsigned long ino = 0;
 
        rcu_read_lock();
-       memcg = READ_ONCE(page->mem_cgroup);
+       if (PageHead(page) && PageSlab(page))
+               memcg = memcg_from_slab_page(page);
+       else
+               memcg = READ_ONCE(page->mem_cgroup);
        while (memcg && !(memcg->css.flags & CSS_ONLINE))
                memcg = parent_mem_cgroup(memcg);
        if (memcg)
@@ -1163,7 +1167,7 @@ int mem_cgroup_scan_tasks(struct mem_cgroup *memcg,
                struct css_task_iter it;
                struct task_struct *task;
 
-               css_task_iter_start(&iter->css, 0, &it);
+               css_task_iter_start(&iter->css, CSS_TASK_ITER_PROCS, &it);
                while (!ret && (task = css_task_iter_next(&it)))
                        ret = fn(task, arg);
                css_task_iter_end(&it);
@@ -1255,32 +1259,6 @@ void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru,
                *lru_size += nr_pages;
 }
 
-bool task_in_mem_cgroup(struct task_struct *task, struct mem_cgroup *memcg)
-{
-       struct mem_cgroup *task_memcg;
-       struct task_struct *p;
-       bool ret;
-
-       p = find_lock_task_mm(task);
-       if (p) {
-               task_memcg = get_mem_cgroup_from_mm(p->mm);
-               task_unlock(p);
-       } else {
-               /*
-                * All threads may have already detached their mm's, but the oom
-                * killer still needs to detect if they have already been oom
-                * killed to prevent needlessly killing additional tasks.
-                */
-               rcu_read_lock();
-               task_memcg = mem_cgroup_from_task(task);
-               css_get(&task_memcg->css);
-               rcu_read_unlock();
-       }
-       ret = mem_cgroup_is_descendant(task_memcg, memcg);
-       css_put(&task_memcg->css);
-       return ret;
-}
-
 /**
  * mem_cgroup_margin - calculate chargeable space of a memory cgroup
  * @memcg: the memory cgroup
@@ -1356,27 +1334,114 @@ static bool mem_cgroup_wait_acct_move(struct mem_cgroup *memcg)
        return false;
 }
 
-static const unsigned int memcg1_stats[] = {
-       MEMCG_CACHE,
-       MEMCG_RSS,
-       MEMCG_RSS_HUGE,
-       NR_SHMEM,
-       NR_FILE_MAPPED,
-       NR_FILE_DIRTY,
-       NR_WRITEBACK,
-       MEMCG_SWAP,
-};
+static char *memory_stat_format(struct mem_cgroup *memcg)
+{
+       struct seq_buf s;
+       int i;
 
-static const char *const memcg1_stat_names[] = {
-       "cache",
-       "rss",
-       "rss_huge",
-       "shmem",
-       "mapped_file",
-       "dirty",
-       "writeback",
-       "swap",
-};
+       seq_buf_init(&s, kmalloc(PAGE_SIZE, GFP_KERNEL), PAGE_SIZE);
+       if (!s.buffer)
+               return NULL;
+
+       /*
+        * Provide statistics on the state of the memory subsystem as
+        * well as cumulative event counters that show past behavior.
+        *
+        * This list is ordered following a combination of these gradients:
+        * 1) generic big picture -> specifics and details
+        * 2) reflecting userspace activity -> reflecting kernel heuristics
+        *
+        * Current memory state:
+        */
+
+       seq_buf_printf(&s, "anon %llu\n",
+                      (u64)memcg_page_state(memcg, MEMCG_RSS) *
+                      PAGE_SIZE);
+       seq_buf_printf(&s, "file %llu\n",
+                      (u64)memcg_page_state(memcg, MEMCG_CACHE) *
+                      PAGE_SIZE);
+       seq_buf_printf(&s, "kernel_stack %llu\n",
+                      (u64)memcg_page_state(memcg, MEMCG_KERNEL_STACK_KB) *
+                      1024);
+       seq_buf_printf(&s, "slab %llu\n",
+                      (u64)(memcg_page_state(memcg, NR_SLAB_RECLAIMABLE) +
+                            memcg_page_state(memcg, NR_SLAB_UNRECLAIMABLE)) *
+                      PAGE_SIZE);
+       seq_buf_printf(&s, "sock %llu\n",
+                      (u64)memcg_page_state(memcg, MEMCG_SOCK) *
+                      PAGE_SIZE);
+
+       seq_buf_printf(&s, "shmem %llu\n",
+                      (u64)memcg_page_state(memcg, NR_SHMEM) *
+                      PAGE_SIZE);
+       seq_buf_printf(&s, "file_mapped %llu\n",
+                      (u64)memcg_page_state(memcg, NR_FILE_MAPPED) *
+                      PAGE_SIZE);
+       seq_buf_printf(&s, "file_dirty %llu\n",
+                      (u64)memcg_page_state(memcg, NR_FILE_DIRTY) *
+                      PAGE_SIZE);
+       seq_buf_printf(&s, "file_writeback %llu\n",
+                      (u64)memcg_page_state(memcg, NR_WRITEBACK) *
+                      PAGE_SIZE);
+
+       /*
+        * TODO: We should eventually replace our own MEMCG_RSS_HUGE counter
+        * with the NR_ANON_THP vm counter, but right now it's a pain in the
+        * arse because it requires migrating the work out of rmap to a place
+        * where the page->mem_cgroup is set up and stable.
+        */
+       seq_buf_printf(&s, "anon_thp %llu\n",
+                      (u64)memcg_page_state(memcg, MEMCG_RSS_HUGE) *
+                      PAGE_SIZE);
+
+       for (i = 0; i < NR_LRU_LISTS; i++)
+               seq_buf_printf(&s, "%s %llu\n", mem_cgroup_lru_names[i],
+                              (u64)memcg_page_state(memcg, NR_LRU_BASE + i) *
+                              PAGE_SIZE);
+
+       seq_buf_printf(&s, "slab_reclaimable %llu\n",
+                      (u64)memcg_page_state(memcg, NR_SLAB_RECLAIMABLE) *
+                      PAGE_SIZE);
+       seq_buf_printf(&s, "slab_unreclaimable %llu\n",
+                      (u64)memcg_page_state(memcg, NR_SLAB_UNRECLAIMABLE) *
+                      PAGE_SIZE);
+
+       /* Accumulated memory events */
+
+       seq_buf_printf(&s, "pgfault %lu\n", memcg_events(memcg, PGFAULT));
+       seq_buf_printf(&s, "pgmajfault %lu\n", memcg_events(memcg, PGMAJFAULT));
+
+       seq_buf_printf(&s, "workingset_refault %lu\n",
+                      memcg_page_state(memcg, WORKINGSET_REFAULT));
+       seq_buf_printf(&s, "workingset_activate %lu\n",
+                      memcg_page_state(memcg, WORKINGSET_ACTIVATE));
+       seq_buf_printf(&s, "workingset_nodereclaim %lu\n",
+                      memcg_page_state(memcg, WORKINGSET_NODERECLAIM));
+
+       seq_buf_printf(&s, "pgrefill %lu\n", memcg_events(memcg, PGREFILL));
+       seq_buf_printf(&s, "pgscan %lu\n",
+                      memcg_events(memcg, PGSCAN_KSWAPD) +
+                      memcg_events(memcg, PGSCAN_DIRECT));
+       seq_buf_printf(&s, "pgsteal %lu\n",
+                      memcg_events(memcg, PGSTEAL_KSWAPD) +
+                      memcg_events(memcg, PGSTEAL_DIRECT));
+       seq_buf_printf(&s, "pgactivate %lu\n", memcg_events(memcg, PGACTIVATE));
+       seq_buf_printf(&s, "pgdeactivate %lu\n", memcg_events(memcg, PGDEACTIVATE));
+       seq_buf_printf(&s, "pglazyfree %lu\n", memcg_events(memcg, PGLAZYFREE));
+       seq_buf_printf(&s, "pglazyfreed %lu\n", memcg_events(memcg, PGLAZYFREED));
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+       seq_buf_printf(&s, "thp_fault_alloc %lu\n",
+                      memcg_events(memcg, THP_FAULT_ALLOC));
+       seq_buf_printf(&s, "thp_collapse_alloc %lu\n",
+                      memcg_events(memcg, THP_COLLAPSE_ALLOC));
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+
+       /* The above should easily fit into one page */
+       WARN_ON_ONCE(seq_buf_has_overflowed(&s));
+
+       return s.buffer;
+}
 
 #define K(x) ((x) << (PAGE_SHIFT-10))
 /**
@@ -1411,39 +1476,32 @@ void mem_cgroup_print_oom_context(struct mem_cgroup *memcg, struct task_struct *
  */
 void mem_cgroup_print_oom_meminfo(struct mem_cgroup *memcg)
 {
-       struct mem_cgroup *iter;
-       unsigned int i;
+       char *buf;
 
        pr_info("memory: usage %llukB, limit %llukB, failcnt %lu\n",
                K((u64)page_counter_read(&memcg->memory)),
                K((u64)memcg->memory.max), memcg->memory.failcnt);
-       pr_info("memory+swap: usage %llukB, limit %llukB, failcnt %lu\n",
-               K((u64)page_counter_read(&memcg->memsw)),
-               K((u64)memcg->memsw.max), memcg->memsw.failcnt);
-       pr_info("kmem: usage %llukB, limit %llukB, failcnt %lu\n",
-               K((u64)page_counter_read(&memcg->kmem)),
-               K((u64)memcg->kmem.max), memcg->kmem.failcnt);
-
-       for_each_mem_cgroup_tree(iter, memcg) {
-               pr_info("Memory cgroup stats for ");
-               pr_cont_cgroup_path(iter->css.cgroup);
-               pr_cont(":");
-
-               for (i = 0; i < ARRAY_SIZE(memcg1_stats); i++) {
-                       if (memcg1_stats[i] == MEMCG_SWAP && !do_swap_account)
-                               continue;
-                       pr_cont(" %s:%luKB", memcg1_stat_names[i],
-                               K(memcg_page_state_local(iter,
-                                                        memcg1_stats[i])));
-               }
-
-               for (i = 0; i < NR_LRU_LISTS; i++)
-                       pr_cont(" %s:%luKB", mem_cgroup_lru_names[i],
-                               K(memcg_page_state_local(iter,
-                                                        NR_LRU_BASE + i)));
-
-               pr_cont("\n");
+       if (cgroup_subsys_on_dfl(memory_cgrp_subsys))
+               pr_info("swap: usage %llukB, limit %llukB, failcnt %lu\n",
+                       K((u64)page_counter_read(&memcg->swap)),
+                       K((u64)memcg->swap.max), memcg->swap.failcnt);
+       else {
+               pr_info("memory+swap: usage %llukB, limit %llukB, failcnt %lu\n",
+                       K((u64)page_counter_read(&memcg->memsw)),
+                       K((u64)memcg->memsw.max), memcg->memsw.failcnt);
+               pr_info("kmem: usage %llukB, limit %llukB, failcnt %lu\n",
+                       K((u64)page_counter_read(&memcg->kmem)),
+                       K((u64)memcg->kmem.max), memcg->kmem.failcnt);
        }
+
+       pr_info("Memory cgroup stats for ");
+       pr_cont_cgroup_path(memcg->css.cgroup);
+       pr_cont(":");
+       buf = memory_stat_format(memcg);
+       if (!buf)
+               return;
+       pr_info("%s", buf);
+       kfree(buf);
 }
 
 /*
@@ -2279,7 +2337,6 @@ static int try_charge(struct mem_cgroup *memcg, gfp_t gfp_mask,
        unsigned long nr_reclaimed;
        bool may_swap = true;
        bool drained = false;
-       bool oomed = false;
        enum oom_status oom_status;
 
        if (mem_cgroup_is_root(memcg))
@@ -2366,7 +2423,7 @@ retry:
        if (nr_retries--)
                goto retry;
 
-       if (gfp_mask & __GFP_RETRY_MAYFAIL && oomed)
+       if (gfp_mask & __GFP_RETRY_MAYFAIL)
                goto nomem;
 
        if (gfp_mask & __GFP_NOFAIL)
@@ -2385,7 +2442,6 @@ retry:
        switch (oom_status) {
        case OOM_SUCCESS:
                nr_retries = MEM_CGROUP_RECLAIM_RETRIES;
-               oomed = true;
                goto retry;
        case OOM_FAILED:
                goto force;
@@ -2588,12 +2644,13 @@ static void memcg_schedule_kmem_cache_create(struct mem_cgroup *memcg,
 {
        struct memcg_kmem_cache_create_work *cw;
 
+       if (!css_tryget_online(&memcg->css))
+               return;
+
        cw = kmalloc(sizeof(*cw), GFP_NOWAIT | __GFP_NOWARN);
        if (!cw)
                return;
 
-       css_get(&memcg->css);
-
        cw->memcg = memcg;
        cw->cachep = cachep;
        INIT_WORK(&cw->work, memcg_kmem_cache_create_func);
@@ -2628,6 +2685,7 @@ struct kmem_cache *memcg_kmem_get_cache(struct kmem_cache *cachep)
 {
        struct mem_cgroup *memcg;
        struct kmem_cache *memcg_cachep;
+       struct memcg_cache_array *arr;
        int kmemcg_id;
 
        VM_BUG_ON(!is_root_cache(cachep));
@@ -2635,14 +2693,28 @@ struct kmem_cache *memcg_kmem_get_cache(struct kmem_cache *cachep)
        if (memcg_kmem_bypass())
                return cachep;
 
-       memcg = get_mem_cgroup_from_current();
+       rcu_read_lock();
+
+       if (unlikely(current->active_memcg))
+               memcg = current->active_memcg;
+       else
+               memcg = mem_cgroup_from_task(current);
+
+       if (!memcg || memcg == root_mem_cgroup)
+               goto out_unlock;
+
        kmemcg_id = READ_ONCE(memcg->kmemcg_id);
        if (kmemcg_id < 0)
-               goto out;
+               goto out_unlock;
 
-       memcg_cachep = cache_from_memcg_idx(cachep, kmemcg_id);
-       if (likely(memcg_cachep))
-               return memcg_cachep;
+       arr = rcu_dereference(cachep->memcg_params.memcg_caches);
+
+       /*
+        * Make sure we will access the up-to-date value. The code updating
+        * memcg_caches issues a write barrier to match the data dependency
+        * barrier inside READ_ONCE() (see memcg_create_kmem_cache()).
+        */
+       memcg_cachep = READ_ONCE(arr->entries[kmemcg_id]);
 
        /*
         * If we are in a safe context (can wait, and not in interrupt
@@ -2655,10 +2727,20 @@ struct kmem_cache *memcg_kmem_get_cache(struct kmem_cache *cachep)
         * memcg_create_kmem_cache, this means no further allocation
         * could happen with the slab_mutex held. So it's better to
         * defer everything.
+        *
+        * If the memcg is dying or memcg_cache is about to be released,
+        * don't bother creating new kmem_caches. Because memcg_cachep
+        * is ZEROed as the fist step of kmem offlining, we don't need
+        * percpu_ref_tryget_live() here. css_tryget_online() check in
+        * memcg_schedule_kmem_cache_create() will prevent us from
+        * creation of a new kmem_cache.
         */
-       memcg_schedule_kmem_cache_create(memcg, cachep);
-out:
-       css_put(&memcg->css);
+       if (unlikely(!memcg_cachep))
+               memcg_schedule_kmem_cache_create(memcg, cachep);
+       else if (percpu_ref_tryget(&memcg_cachep->memcg_params.refcnt))
+               cachep = memcg_cachep;
+out_unlock:
+       rcu_read_unlock();
        return cachep;
 }
 
@@ -2669,7 +2751,7 @@ out:
 void memcg_kmem_put_cache(struct kmem_cache *cachep)
 {
        if (!is_root_cache(cachep))
-               css_put(&cachep->memcg_params.memcg->css);
+               percpu_ref_put(&cachep->memcg_params.refcnt);
 }
 
 /**
@@ -2697,9 +2779,6 @@ int __memcg_kmem_charge_memcg(struct page *page, gfp_t gfp, int order,
                cancel_charge(memcg, nr_pages);
                return -ENOMEM;
        }
-
-       page->mem_cgroup = memcg;
-
        return 0;
 }
 
@@ -2722,12 +2801,30 @@ int __memcg_kmem_charge(struct page *page, gfp_t gfp, int order)
        memcg = get_mem_cgroup_from_current();
        if (!mem_cgroup_is_root(memcg)) {
                ret = __memcg_kmem_charge_memcg(page, gfp, order, memcg);
-               if (!ret)
+               if (!ret) {
+                       page->mem_cgroup = memcg;
                        __SetPageKmemcg(page);
+               }
        }
        css_put(&memcg->css);
        return ret;
 }
+
+/**
+ * __memcg_kmem_uncharge_memcg: uncharge a kmem page
+ * @memcg: memcg to uncharge
+ * @nr_pages: number of pages to uncharge
+ */
+void __memcg_kmem_uncharge_memcg(struct mem_cgroup *memcg,
+                                unsigned int nr_pages)
+{
+       if (!cgroup_subsys_on_dfl(memory_cgrp_subsys))
+               page_counter_uncharge(&memcg->kmem, nr_pages);
+
+       page_counter_uncharge(&memcg->memory, nr_pages);
+       if (do_memsw_account())
+               page_counter_uncharge(&memcg->memsw, nr_pages);
+}
 /**
  * __memcg_kmem_uncharge: uncharge a kmem page
  * @page: page to uncharge
@@ -2742,14 +2839,7 @@ void __memcg_kmem_uncharge(struct page *page, int order)
                return;
 
        VM_BUG_ON_PAGE(mem_cgroup_is_root(memcg), page);
-
-       if (!cgroup_subsys_on_dfl(memory_cgrp_subsys))
-               page_counter_uncharge(&memcg->kmem, nr_pages);
-
-       page_counter_uncharge(&memcg->memory, nr_pages);
-       if (do_memsw_account())
-               page_counter_uncharge(&memcg->memsw, nr_pages);
-
+       __memcg_kmem_uncharge_memcg(memcg, nr_pages);
        page->mem_cgroup = NULL;
 
        /* slab pages do not have PageKmemcg flag set */
@@ -3168,15 +3258,15 @@ static void memcg_offline_kmem(struct mem_cgroup *memcg)
         */
        memcg->kmem_state = KMEM_ALLOCATED;
 
-       memcg_deactivate_kmem_caches(memcg);
-
-       kmemcg_id = memcg->kmemcg_id;
-       BUG_ON(kmemcg_id < 0);
-
        parent = parent_mem_cgroup(memcg);
        if (!parent)
                parent = root_mem_cgroup;
 
+       memcg_deactivate_kmem_caches(memcg, parent);
+
+       kmemcg_id = memcg->kmemcg_id;
+       BUG_ON(kmemcg_id < 0);
+
        /*
         * Change kmemcg_id of this cgroup and all its descendants to the
         * parent's id, and then move all entries from this cgroup's list_lrus
@@ -3207,9 +3297,8 @@ static void memcg_free_kmem(struct mem_cgroup *memcg)
                memcg_offline_kmem(memcg);
 
        if (memcg->kmem_state == KMEM_ALLOCATED) {
-               memcg_destroy_kmem_caches(memcg);
+               WARN_ON(!list_empty(&memcg->kmem_caches));
                static_branch_dec(&memcg_kmem_enabled_key);
-               WARN_ON(page_counter_read(&memcg->kmem));
        }
 }
 #else
@@ -3472,6 +3561,28 @@ static int memcg_numa_stat_show(struct seq_file *m, void *v)
 }
 #endif /* CONFIG_NUMA */
 
+static const unsigned int memcg1_stats[] = {
+       MEMCG_CACHE,
+       MEMCG_RSS,
+       MEMCG_RSS_HUGE,
+       NR_SHMEM,
+       NR_FILE_MAPPED,
+       NR_FILE_DIRTY,
+       NR_WRITEBACK,
+       MEMCG_SWAP,
+};
+
+static const char *const memcg1_stat_names[] = {
+       "cache",
+       "rss",
+       "rss_huge",
+       "shmem",
+       "mapped_file",
+       "dirty",
+       "writeback",
+       "swap",
+};
+
 /* Universal VM events cgroup1 shows, original sort order */
 static const unsigned int memcg1_events[] = {
        PGPGIN,
@@ -3530,12 +3641,13 @@ static int memcg_stat_show(struct seq_file *m, void *v)
                if (memcg1_stats[i] == MEMCG_SWAP && !do_memsw_account())
                        continue;
                seq_printf(m, "total_%s %llu\n", memcg1_stat_names[i],
-                          (u64)memcg_page_state(memcg, i) * PAGE_SIZE);
+                          (u64)memcg_page_state(memcg, memcg1_stats[i]) *
+                          PAGE_SIZE);
        }
 
        for (i = 0; i < ARRAY_SIZE(memcg1_events); i++)
                seq_printf(m, "total_%s %llu\n", memcg1_event_names[i],
-                          (u64)memcg_events(memcg, i));
+                          (u64)memcg_events(memcg, memcg1_events[i]));
 
        for (i = 0; i < NR_LRU_LISTS; i++)
                seq_printf(m, "total_%s %llu\n", mem_cgroup_lru_names[i],
@@ -4634,6 +4746,9 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
 
        /* The following stuff does not apply to the root */
        if (!parent) {
+#ifdef CONFIG_MEMCG_KMEM
+               INIT_LIST_HEAD(&memcg->kmem_caches);
+#endif
                root_mem_cgroup = memcg;
                return &memcg->css;
        }
@@ -5625,112 +5740,42 @@ static ssize_t memory_max_write(struct kernfs_open_file *of,
        return nbytes;
 }
 
+static void __memory_events_show(struct seq_file *m, atomic_long_t *events)
+{
+       seq_printf(m, "low %lu\n", atomic_long_read(&events[MEMCG_LOW]));
+       seq_printf(m, "high %lu\n", atomic_long_read(&events[MEMCG_HIGH]));
+       seq_printf(m, "max %lu\n", atomic_long_read(&events[MEMCG_MAX]));
+       seq_printf(m, "oom %lu\n", atomic_long_read(&events[MEMCG_OOM]));
+       seq_printf(m, "oom_kill %lu\n",
+                  atomic_long_read(&events[MEMCG_OOM_KILL]));
+}
+
 static int memory_events_show(struct seq_file *m, void *v)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_seq(m);
 
-       seq_printf(m, "low %lu\n",
-                  atomic_long_read(&memcg->memory_events[MEMCG_LOW]));
-       seq_printf(m, "high %lu\n",
-                  atomic_long_read(&memcg->memory_events[MEMCG_HIGH]));
-       seq_printf(m, "max %lu\n",
-                  atomic_long_read(&memcg->memory_events[MEMCG_MAX]));
-       seq_printf(m, "oom %lu\n",
-                  atomic_long_read(&memcg->memory_events[MEMCG_OOM]));
-       seq_printf(m, "oom_kill %lu\n",
-                  atomic_long_read(&memcg->memory_events[MEMCG_OOM_KILL]));
-
+       __memory_events_show(m, memcg->memory_events);
        return 0;
 }
 
-static int memory_stat_show(struct seq_file *m, void *v)
+static int memory_events_local_show(struct seq_file *m, void *v)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_seq(m);
-       int i;
-
-       /*
-        * Provide statistics on the state of the memory subsystem as
-        * well as cumulative event counters that show past behavior.
-        *
-        * This list is ordered following a combination of these gradients:
-        * 1) generic big picture -> specifics and details
-        * 2) reflecting userspace activity -> reflecting kernel heuristics
-        *
-        * Current memory state:
-        */
-
-       seq_printf(m, "anon %llu\n",
-                  (u64)memcg_page_state(memcg, MEMCG_RSS) * PAGE_SIZE);
-       seq_printf(m, "file %llu\n",
-                  (u64)memcg_page_state(memcg, MEMCG_CACHE) * PAGE_SIZE);
-       seq_printf(m, "kernel_stack %llu\n",
-                  (u64)memcg_page_state(memcg, MEMCG_KERNEL_STACK_KB) * 1024);
-       seq_printf(m, "slab %llu\n",
-                  (u64)(memcg_page_state(memcg, NR_SLAB_RECLAIMABLE) +
-                        memcg_page_state(memcg, NR_SLAB_UNRECLAIMABLE)) *
-                  PAGE_SIZE);
-       seq_printf(m, "sock %llu\n",
-                  (u64)memcg_page_state(memcg, MEMCG_SOCK) * PAGE_SIZE);
-
-       seq_printf(m, "shmem %llu\n",
-                  (u64)memcg_page_state(memcg, NR_SHMEM) * PAGE_SIZE);
-       seq_printf(m, "file_mapped %llu\n",
-                  (u64)memcg_page_state(memcg, NR_FILE_MAPPED) * PAGE_SIZE);
-       seq_printf(m, "file_dirty %llu\n",
-                  (u64)memcg_page_state(memcg, NR_FILE_DIRTY) * PAGE_SIZE);
-       seq_printf(m, "file_writeback %llu\n",
-                  (u64)memcg_page_state(memcg, NR_WRITEBACK) * PAGE_SIZE);
 
-       /*
-        * TODO: We should eventually replace our own MEMCG_RSS_HUGE counter
-        * with the NR_ANON_THP vm counter, but right now it's a pain in the
-        * arse because it requires migrating the work out of rmap to a place
-        * where the page->mem_cgroup is set up and stable.
-        */
-       seq_printf(m, "anon_thp %llu\n",
-                  (u64)memcg_page_state(memcg, MEMCG_RSS_HUGE) * PAGE_SIZE);
-
-       for (i = 0; i < NR_LRU_LISTS; i++)
-               seq_printf(m, "%s %llu\n", mem_cgroup_lru_names[i],
-                          (u64)memcg_page_state(memcg, NR_LRU_BASE + i) *
-                          PAGE_SIZE);
-
-       seq_printf(m, "slab_reclaimable %llu\n",
-                  (u64)memcg_page_state(memcg, NR_SLAB_RECLAIMABLE) *
-                  PAGE_SIZE);
-       seq_printf(m, "slab_unreclaimable %llu\n",
-                  (u64)memcg_page_state(memcg, NR_SLAB_UNRECLAIMABLE) *
-                  PAGE_SIZE);
-
-       /* Accumulated memory events */
-
-       seq_printf(m, "pgfault %lu\n", memcg_events(memcg, PGFAULT));
-       seq_printf(m, "pgmajfault %lu\n", memcg_events(memcg, PGMAJFAULT));
-
-       seq_printf(m, "workingset_refault %lu\n",
-                  memcg_page_state(memcg, WORKINGSET_REFAULT));
-       seq_printf(m, "workingset_activate %lu\n",
-                  memcg_page_state(memcg, WORKINGSET_ACTIVATE));
-       seq_printf(m, "workingset_nodereclaim %lu\n",
-                  memcg_page_state(memcg, WORKINGSET_NODERECLAIM));
-
-       seq_printf(m, "pgrefill %lu\n", memcg_events(memcg, PGREFILL));
-       seq_printf(m, "pgscan %lu\n", memcg_events(memcg, PGSCAN_KSWAPD) +
-                  memcg_events(memcg, PGSCAN_DIRECT));
-       seq_printf(m, "pgsteal %lu\n", memcg_events(memcg, PGSTEAL_KSWAPD) +
-                  memcg_events(memcg, PGSTEAL_DIRECT));
-       seq_printf(m, "pgactivate %lu\n", memcg_events(memcg, PGACTIVATE));
-       seq_printf(m, "pgdeactivate %lu\n", memcg_events(memcg, PGDEACTIVATE));
-       seq_printf(m, "pglazyfree %lu\n", memcg_events(memcg, PGLAZYFREE));
-       seq_printf(m, "pglazyfreed %lu\n", memcg_events(memcg, PGLAZYFREED));
+       __memory_events_show(m, memcg->memory_events_local);
+       return 0;
+}
 
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-       seq_printf(m, "thp_fault_alloc %lu\n",
-                  memcg_events(memcg, THP_FAULT_ALLOC));
-       seq_printf(m, "thp_collapse_alloc %lu\n",
-                  memcg_events(memcg, THP_COLLAPSE_ALLOC));
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+static int memory_stat_show(struct seq_file *m, void *v)
+{
+       struct mem_cgroup *memcg = mem_cgroup_from_seq(m);
+       char *buf;
 
+       buf = memory_stat_format(memcg);
+       if (!buf)
+               return -ENOMEM;
+       seq_puts(m, buf);
+       kfree(buf);
        return 0;
 }
 
@@ -5801,6 +5846,12 @@ static struct cftype memory_files[] = {
                .file_offset = offsetof(struct mem_cgroup, events_file),
                .seq_show = memory_events_show,
        },
+       {
+               .name = "events.local",
+               .flags = CFTYPE_NOT_ON_ROOT,
+               .file_offset = offsetof(struct mem_cgroup, events_local_file),
+               .seq_show = memory_events_local_show,
+       },
        {
                .name = "stat",
                .flags = CFTYPE_NOT_ON_ROOT,
index f045514..7e08cbf 100644 (file)
@@ -213,7 +213,7 @@ static int kill_proc(struct to_kill *tk, unsigned long pfn, int flags)
        short addr_lsb = tk->size_shift;
        int ret;
 
-       pr_err("Memory failure: %#lx: Killing %s:%d due to hardware memory corruption\n",
+       pr_err("Memory failure: %#lx: Sending SIGBUS to %s:%d due to hardware memory corruption\n",
                pfn, t->comm, t->pid);
 
        if ((flags & MF_ACTION_REQUIRED) && t->mm == current->mm) {
index ddf20bd..53bd595 100644 (file)
@@ -1475,8 +1475,6 @@ static int insert_page(struct vm_area_struct *vma, unsigned long addr,
        set_pte_at(mm, addr, pte, mk_pte(page, prot));
 
        retval = 0;
-       pte_unmap_unlock(pte, ptl);
-       return retval;
 out_unlock:
        pte_unmap_unlock(pte, ptl);
 out:
@@ -1547,7 +1545,7 @@ static int __vm_map_pages(struct vm_area_struct *vma, struct page **pages,
        int ret, i;
 
        /* Fail if the user requested offset is beyond the end of the object */
-       if (offset > num)
+       if (offset >= num)
                return -ENXIO;
 
        /* Fail if the user requested size exceeds available object size */
@@ -2038,7 +2036,6 @@ static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd,
 {
        pte_t *pte;
        int err;
-       pgtable_t token;
        spinlock_t *uninitialized_var(ptl);
 
        pte = (mm == &init_mm) ?
@@ -2051,10 +2048,8 @@ static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd,
 
        arch_enter_lazy_mmu_mode();
 
-       token = pmd_pgtable(*pmd);
-
        do {
-               err = fn(pte++, token, addr, data);
+               err = fn(pte++, addr, data);
                if (err)
                        break;
        } while (addr += PAGE_SIZE, addr != end);
@@ -2807,7 +2802,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
                struct swap_info_struct *si = swp_swap_info(entry);
 
                if (si->flags & SWP_SYNCHRONOUS_IO &&
-                               __swap_count(si, entry) == 1) {
+                               __swap_count(entry) == 1) {
                        /* skip swapcache */
                        page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma,
                                                        vmf->address);
@@ -4349,7 +4344,9 @@ int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
        void *old_buf = buf;
        int write = gup_flags & FOLL_WRITE;
 
-       down_read(&mm->mmap_sem);
+       if (down_read_killable(&mm->mmap_sem))
+               return 0;
+
        /* ignore errors, just check how much was successfully transferred */
        while (len) {
                int bytes, ret, offset;
index c3f058b..4fe91d4 100644 (file)
@@ -68,8 +68,16 @@ static unsigned char mincore_page(struct address_space *mapping, pgoff_t pgoff)
                 */
                if (xa_is_value(page)) {
                        swp_entry_t swp = radix_to_swp_entry(page);
-                       page = find_get_page(swap_address_space(swp),
-                                            swp_offset(swp));
+                       struct swap_info_struct *si;
+
+                       /* Prevent swap device to being swapoff under us */
+                       si = get_swap_device(swp);
+                       if (si) {
+                               page = find_get_page(swap_address_space(swp),
+                                                    swp_offset(swp));
+                               put_swap_device(si);
+                       } else
+                               page = NULL;
                }
        } else
                page = find_get_page(mapping, pgoff);
index 513b960..b567062 100644 (file)
@@ -274,7 +274,7 @@ static int do_mmu_notifier_register(struct mmu_notifier *mn,
         * thanks to mm_take_all_locks().
         */
        spin_lock(&mm->mmu_notifier_mm->lock);
-       hlist_add_head(&mn->hlist, &mm->mmu_notifier_mm->list);
+       hlist_add_head_rcu(&mn->hlist, &mm->mmu_notifier_mm->list);
        spin_unlock(&mm->mmu_notifier_mm->lock);
 
        mm_drop_all_locks(mm);
index d8c02fb..eb3e2e5 100644 (file)
@@ -111,94 +111,6 @@ unsigned int kobjsize(const void *objp)
        return PAGE_SIZE << compound_order(page);
 }
 
-static long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
-                     unsigned long start, unsigned long nr_pages,
-                     unsigned int foll_flags, struct page **pages,
-                     struct vm_area_struct **vmas, int *nonblocking)
-{
-       struct vm_area_struct *vma;
-       unsigned long vm_flags;
-       int i;
-
-       /* calculate required read or write permissions.
-        * If FOLL_FORCE is set, we only require the "MAY" flags.
-        */
-       vm_flags  = (foll_flags & FOLL_WRITE) ?
-                       (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD);
-       vm_flags &= (foll_flags & FOLL_FORCE) ?
-                       (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE);
-
-       for (i = 0; i < nr_pages; i++) {
-               vma = find_vma(mm, start);
-               if (!vma)
-                       goto finish_or_fault;
-
-               /* protect what we can, including chardevs */
-               if ((vma->vm_flags & (VM_IO | VM_PFNMAP)) ||
-                   !(vm_flags & vma->vm_flags))
-                       goto finish_or_fault;
-
-               if (pages) {
-                       pages[i] = virt_to_page(start);
-                       if (pages[i])
-                               get_page(pages[i]);
-               }
-               if (vmas)
-                       vmas[i] = vma;
-               start = (start + PAGE_SIZE) & PAGE_MASK;
-       }
-
-       return i;
-
-finish_or_fault:
-       return i ? : -EFAULT;
-}
-
-/*
- * get a list of pages in an address range belonging to the specified process
- * and indicate the VMA that covers each page
- * - this is potentially dodgy as we may end incrementing the page count of a
- *   slab page or a secondary page from a compound page
- * - don't permit access to VMAs that don't support it, such as I/O mappings
- */
-long get_user_pages(unsigned long start, unsigned long nr_pages,
-                   unsigned int gup_flags, struct page **pages,
-                   struct vm_area_struct **vmas)
-{
-       return __get_user_pages(current, current->mm, start, nr_pages,
-                               gup_flags, pages, vmas, NULL);
-}
-EXPORT_SYMBOL(get_user_pages);
-
-long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
-                           unsigned int gup_flags, struct page **pages,
-                           int *locked)
-{
-       return get_user_pages(start, nr_pages, gup_flags, pages, NULL);
-}
-EXPORT_SYMBOL(get_user_pages_locked);
-
-static long __get_user_pages_unlocked(struct task_struct *tsk,
-                       struct mm_struct *mm, unsigned long start,
-                       unsigned long nr_pages, struct page **pages,
-                       unsigned int gup_flags)
-{
-       long ret;
-       down_read(&mm->mmap_sem);
-       ret = __get_user_pages(tsk, mm, start, nr_pages, gup_flags, pages,
-                               NULL, NULL);
-       up_read(&mm->mmap_sem);
-       return ret;
-}
-
-long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages,
-                            struct page **pages, unsigned int gup_flags)
-{
-       return __get_user_pages_unlocked(current, current->mm, start, nr_pages,
-                                        pages, gup_flags);
-}
-EXPORT_SYMBOL(get_user_pages_unlocked);
-
 /**
  * follow_pfn - look up PFN at a user virtual address
  * @vma: memory mapping
@@ -1792,7 +1704,8 @@ int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
        struct vm_area_struct *vma;
        int write = gup_flags & FOLL_WRITE;
 
-       down_read(&mm->mmap_sem);
+       if (down_read_killable(&mm->mmap_sem))
+               return 0;
 
        /* the access must start within one of the target process's mappings */
        vma = find_vma(mm, addr);
index f719b64..eda2e2a 100644 (file)
@@ -64,21 +64,33 @@ int sysctl_oom_dump_tasks = 1;
  */
 DEFINE_MUTEX(oom_lock);
 
+static inline bool is_memcg_oom(struct oom_control *oc)
+{
+       return oc->memcg != NULL;
+}
+
 #ifdef CONFIG_NUMA
 /**
- * has_intersects_mems_allowed() - check task eligiblity for kill
+ * oom_cpuset_eligible() - check task eligiblity for kill
  * @start: task struct of which task to consider
  * @mask: nodemask passed to page allocator for mempolicy ooms
  *
  * Task eligibility is determined by whether or not a candidate task, @tsk,
  * shares the same mempolicy nodes as current if it is bound by such a policy
  * and whether or not it has the same set of allowed cpuset nodes.
+ *
+ * This function is assuming oom-killer context and 'current' has triggered
+ * the oom-killer.
  */
-static bool has_intersects_mems_allowed(struct task_struct *start,
-                                       const nodemask_t *mask)
+static bool oom_cpuset_eligible(struct task_struct *start,
+                               struct oom_control *oc)
 {
        struct task_struct *tsk;
        bool ret = false;
+       const nodemask_t *mask = oc->nodemask;
+
+       if (is_memcg_oom(oc))
+               return true;
 
        rcu_read_lock();
        for_each_thread(start, tsk) {
@@ -105,8 +117,7 @@ static bool has_intersects_mems_allowed(struct task_struct *start,
        return ret;
 }
 #else
-static bool has_intersects_mems_allowed(struct task_struct *tsk,
-                                       const nodemask_t *mask)
+static bool oom_cpuset_eligible(struct task_struct *tsk, struct oom_control *oc)
 {
        return true;
 }
@@ -146,28 +157,13 @@ static inline bool is_sysrq_oom(struct oom_control *oc)
        return oc->order == -1;
 }
 
-static inline bool is_memcg_oom(struct oom_control *oc)
-{
-       return oc->memcg != NULL;
-}
-
 /* return true if the task is not adequate as candidate victim task. */
-static bool oom_unkillable_task(struct task_struct *p,
-               struct mem_cgroup *memcg, const nodemask_t *nodemask)
+static bool oom_unkillable_task(struct task_struct *p)
 {
        if (is_global_init(p))
                return true;
        if (p->flags & PF_KTHREAD)
                return true;
-
-       /* When mem_cgroup_out_of_memory() and p is not member of the group */
-       if (memcg && !task_in_mem_cgroup(p, memcg))
-               return true;
-
-       /* p may not have freeable memory in nodemask */
-       if (!has_intersects_mems_allowed(p, nodemask))
-               return true;
-
        return false;
 }
 
@@ -194,20 +190,17 @@ static bool is_dump_unreclaim_slabs(void)
  * oom_badness - heuristic function to determine which candidate task to kill
  * @p: task struct of which task we should calculate
  * @totalpages: total present RAM allowed for page allocation
- * @memcg: task's memory controller, if constrained
- * @nodemask: nodemask passed to page allocator for mempolicy ooms
  *
  * The heuristic for determining which task to kill is made to be as simple and
  * predictable as possible.  The goal is to return the highest value for the
  * task consuming the most memory to avoid subsequent oom failures.
  */
-unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg,
-                         const nodemask_t *nodemask, unsigned long totalpages)
+unsigned long oom_badness(struct task_struct *p, unsigned long totalpages)
 {
        long points;
        long adj;
 
-       if (oom_unkillable_task(p, memcg, nodemask))
+       if (oom_unkillable_task(p))
                return 0;
 
        p = find_lock_task_mm(p);
@@ -318,7 +311,11 @@ static int oom_evaluate_task(struct task_struct *task, void *arg)
        struct oom_control *oc = arg;
        unsigned long points;
 
-       if (oom_unkillable_task(task, NULL, oc->nodemask))
+       if (oom_unkillable_task(task))
+               goto next;
+
+       /* p may not have freeable memory in nodemask */
+       if (!is_memcg_oom(oc) && !oom_cpuset_eligible(task, oc))
                goto next;
 
        /*
@@ -342,13 +339,10 @@ static int oom_evaluate_task(struct task_struct *task, void *arg)
                goto select;
        }
 
-       points = oom_badness(task, NULL, oc->nodemask, oc->totalpages);
+       points = oom_badness(task, oc->totalpages);
        if (!points || points < oc->chosen_points)
                goto next;
 
-       /* Prefer thread group leaders for display purposes */
-       if (points == oc->chosen_points && thread_group_leader(oc->chosen))
-               goto next;
 select:
        if (oc->chosen)
                put_task_struct(oc->chosen);
@@ -381,14 +375,44 @@ static void select_bad_process(struct oom_control *oc)
                                break;
                rcu_read_unlock();
        }
+}
 
-       oc->chosen_points = oc->chosen_points * 1000 / oc->totalpages;
+static int dump_task(struct task_struct *p, void *arg)
+{
+       struct oom_control *oc = arg;
+       struct task_struct *task;
+
+       if (oom_unkillable_task(p))
+               return 0;
+
+       /* p may not have freeable memory in nodemask */
+       if (!is_memcg_oom(oc) && !oom_cpuset_eligible(p, oc))
+               return 0;
+
+       task = find_lock_task_mm(p);
+       if (!task) {
+               /*
+                * This is a kthread or all of p's threads have already
+                * detached their mm's.  There's no need to report
+                * them; they can't be oom killed anyway.
+                */
+               return 0;
+       }
+
+       pr_info("[%7d] %5d %5d %8lu %8lu %8ld %8lu         %5hd %s\n",
+               task->pid, from_kuid(&init_user_ns, task_uid(task)),
+               task->tgid, task->mm->total_vm, get_mm_rss(task->mm),
+               mm_pgtables_bytes(task->mm),
+               get_mm_counter(task->mm, MM_SWAPENTS),
+               task->signal->oom_score_adj, task->comm);
+       task_unlock(task);
+
+       return 0;
 }
 
 /**
  * dump_tasks - dump current memory state of all system tasks
- * @memcg: current's memory controller, if constrained
- * @nodemask: nodemask passed to page allocator for mempolicy ooms
+ * @oc: pointer to struct oom_control
  *
  * Dumps the current memory state of all eligible tasks.  Tasks not in the same
  * memcg, not in the same cpuset, or bound to a disjoint set of mempolicy nodes
@@ -396,37 +420,21 @@ static void select_bad_process(struct oom_control *oc)
  * State information includes task's pid, uid, tgid, vm size, rss,
  * pgtables_bytes, swapents, oom_score_adj value, and name.
  */
-static void dump_tasks(struct mem_cgroup *memcg, const nodemask_t *nodemask)
+static void dump_tasks(struct oom_control *oc)
 {
-       struct task_struct *p;
-       struct task_struct *task;
-
        pr_info("Tasks state (memory values in pages):\n");
        pr_info("[  pid  ]   uid  tgid total_vm      rss pgtables_bytes swapents oom_score_adj name\n");
-       rcu_read_lock();
-       for_each_process(p) {
-               if (oom_unkillable_task(p, memcg, nodemask))
-                       continue;
 
-               task = find_lock_task_mm(p);
-               if (!task) {
-                       /*
-                        * This is a kthread or all of p's threads have already
-                        * detached their mm's.  There's no need to report
-                        * them; they can't be oom killed anyway.
-                        */
-                       continue;
-               }
+       if (is_memcg_oom(oc))
+               mem_cgroup_scan_tasks(oc->memcg, dump_task, oc);
+       else {
+               struct task_struct *p;
 
-               pr_info("[%7d] %5d %5d %8lu %8lu %8ld %8lu         %5hd %s\n",
-                       task->pid, from_kuid(&init_user_ns, task_uid(task)),
-                       task->tgid, task->mm->total_vm, get_mm_rss(task->mm),
-                       mm_pgtables_bytes(task->mm),
-                       get_mm_counter(task->mm, MM_SWAPENTS),
-                       task->signal->oom_score_adj, task->comm);
-               task_unlock(task);
+               rcu_read_lock();
+               for_each_process(p)
+                       dump_task(p, oc);
+               rcu_read_unlock();
        }
-       rcu_read_unlock();
 }
 
 static void dump_oom_summary(struct oom_control *oc, struct task_struct *victim)
@@ -458,7 +466,7 @@ static void dump_header(struct oom_control *oc, struct task_struct *p)
                        dump_unreclaimable_slab();
        }
        if (sysctl_oom_dump_tasks)
-               dump_tasks(oc->memcg, oc->nodemask);
+               dump_tasks(oc);
        if (p)
                dump_oom_summary(oc, p);
 }
@@ -1075,7 +1083,8 @@ bool out_of_memory(struct oom_control *oc)
        check_panic_on_oom(oc);
 
        if (!is_memcg_oom(oc) && sysctl_oom_kill_allocating_task &&
-           current->mm && !oom_unkillable_task(current, NULL, oc->nodemask) &&
+           current->mm && !oom_unkillable_task(current) &&
+           oom_cpuset_eligible(current, oc) &&
            current->signal->oom_score_adj != OOM_SCORE_ADJ_MIN) {
                get_task_struct(current);
                oc->chosen = current;
index bdbe8b6..1804f64 100644 (file)
@@ -2429,7 +2429,6 @@ void account_page_dirtied(struct page *page, struct address_space *mapping)
                this_cpu_inc(bdp_ratelimits);
        }
 }
-EXPORT_SYMBOL(account_page_dirtied);
 
 /*
  * Helper function for deaccounting dirty page without writeback.
index 8e3bc94..dbd0d5c 100644 (file)
@@ -50,7 +50,6 @@
 #include <linux/backing-dev.h>
 #include <linux/fault-inject.h>
 #include <linux/page-isolation.h>
-#include <linux/page_ext.h>
 #include <linux/debugobjects.h>
 #include <linux/kmemleak.h>
 #include <linux/compaction.h>
@@ -136,6 +135,55 @@ unsigned long totalcma_pages __read_mostly;
 
 int percpu_pagelist_fraction;
 gfp_t gfp_allowed_mask __read_mostly = GFP_BOOT_MASK;
+#ifdef CONFIG_INIT_ON_ALLOC_DEFAULT_ON
+DEFINE_STATIC_KEY_TRUE(init_on_alloc);
+#else
+DEFINE_STATIC_KEY_FALSE(init_on_alloc);
+#endif
+EXPORT_SYMBOL(init_on_alloc);
+
+#ifdef CONFIG_INIT_ON_FREE_DEFAULT_ON
+DEFINE_STATIC_KEY_TRUE(init_on_free);
+#else
+DEFINE_STATIC_KEY_FALSE(init_on_free);
+#endif
+EXPORT_SYMBOL(init_on_free);
+
+static int __init early_init_on_alloc(char *buf)
+{
+       int ret;
+       bool bool_result;
+
+       if (!buf)
+               return -EINVAL;
+       ret = kstrtobool(buf, &bool_result);
+       if (bool_result && page_poisoning_enabled())
+               pr_info("mem auto-init: CONFIG_PAGE_POISONING is on, will take precedence over init_on_alloc\n");
+       if (bool_result)
+               static_branch_enable(&init_on_alloc);
+       else
+               static_branch_disable(&init_on_alloc);
+       return ret;
+}
+early_param("init_on_alloc", early_init_on_alloc);
+
+static int __init early_init_on_free(char *buf)
+{
+       int ret;
+       bool bool_result;
+
+       if (!buf)
+               return -EINVAL;
+       ret = kstrtobool(buf, &bool_result);
+       if (bool_result && page_poisoning_enabled())
+               pr_info("mem auto-init: CONFIG_PAGE_POISONING is on, will take precedence over init_on_free\n");
+       if (bool_result)
+               static_branch_enable(&init_on_free);
+       else
+               static_branch_disable(&init_on_free);
+       return ret;
+}
+early_param("init_on_free", early_init_on_free);
 
 /*
  * A cached value of the page's pageblock's migratetype, used when the page is
@@ -224,8 +272,6 @@ int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES] = {
        [ZONE_MOVABLE] = 0,
 };
 
-EXPORT_SYMBOL(totalram_pages);
-
 static char * const zone_names[MAX_NR_ZONES] = {
 #ifdef CONFIG_ZONE_DMA
         "DMA",
@@ -646,30 +692,29 @@ void prep_compound_page(struct page *page, unsigned int order)
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
 unsigned int _debug_guardpage_minorder;
-bool _debug_pagealloc_enabled __read_mostly
-                       = IS_ENABLED(CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT);
+
+#ifdef CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT
+DEFINE_STATIC_KEY_TRUE(_debug_pagealloc_enabled);
+#else
+DEFINE_STATIC_KEY_FALSE(_debug_pagealloc_enabled);
+#endif
 EXPORT_SYMBOL(_debug_pagealloc_enabled);
-bool _debug_guardpage_enabled __read_mostly;
+
+DEFINE_STATIC_KEY_FALSE(_debug_guardpage_enabled);
 
 static int __init early_debug_pagealloc(char *buf)
 {
-       if (!buf)
+       bool enable = false;
+
+       if (kstrtobool(buf, &enable))
                return -EINVAL;
-       return kstrtobool(buf, &_debug_pagealloc_enabled);
-}
-early_param("debug_pagealloc", early_debug_pagealloc);
 
-static bool need_debug_guardpage(void)
-{
-       /* If we don't use debug_pagealloc, we don't need guard page */
-       if (!debug_pagealloc_enabled())
-               return false;
+       if (enable)
+               static_branch_enable(&_debug_pagealloc_enabled);
 
-       if (!debug_guardpage_minorder())
-               return false;
-
-       return true;
+       return 0;
 }
+early_param("debug_pagealloc", early_debug_pagealloc);
 
 static void init_debug_guardpage(void)
 {
@@ -679,14 +724,9 @@ static void init_debug_guardpage(void)
        if (!debug_guardpage_minorder())
                return;
 
-       _debug_guardpage_enabled = true;
+       static_branch_enable(&_debug_guardpage_enabled);
 }
 
-struct page_ext_operations debug_guardpage_ops = {
-       .need = need_debug_guardpage,
-       .init = init_debug_guardpage,
-};
-
 static int __init debug_guardpage_minorder_setup(char *buf)
 {
        unsigned long res;
@@ -704,20 +744,13 @@ early_param("debug_guardpage_minorder", debug_guardpage_minorder_setup);
 static inline bool set_page_guard(struct zone *zone, struct page *page,
                                unsigned int order, int migratetype)
 {
-       struct page_ext *page_ext;
-
        if (!debug_guardpage_enabled())
                return false;
 
        if (order >= debug_guardpage_minorder())
                return false;
 
-       page_ext = lookup_page_ext(page);
-       if (unlikely(!page_ext))
-               return false;
-
-       __set_bit(PAGE_EXT_DEBUG_GUARD, &page_ext->flags);
-
+       __SetPageGuard(page);
        INIT_LIST_HEAD(&page->lru);
        set_page_private(page, order);
        /* Guard pages are not available for any usage */
@@ -729,23 +762,16 @@ static inline bool set_page_guard(struct zone *zone, struct page *page,
 static inline void clear_page_guard(struct zone *zone, struct page *page,
                                unsigned int order, int migratetype)
 {
-       struct page_ext *page_ext;
-
        if (!debug_guardpage_enabled())
                return;
 
-       page_ext = lookup_page_ext(page);
-       if (unlikely(!page_ext))
-               return;
-
-       __clear_bit(PAGE_EXT_DEBUG_GUARD, &page_ext->flags);
+       __ClearPageGuard(page);
 
        set_page_private(page, 0);
        if (!is_migrate_isolate(migratetype))
                __mod_zone_freepage_state(zone, (1 << order), migratetype);
 }
 #else
-struct page_ext_operations debug_guardpage_ops;
 static inline bool set_page_guard(struct zone *zone, struct page *page,
                        unsigned int order, int migratetype) { return false; }
 static inline void clear_page_guard(struct zone *zone, struct page *page,
@@ -1090,6 +1116,14 @@ out:
        return ret;
 }
 
+static void kernel_init_free_pages(struct page *page, int numpages)
+{
+       int i;
+
+       for (i = 0; i < numpages; i++)
+               clear_highpage(page + i);
+}
+
 static __always_inline bool free_pages_prepare(struct page *page,
                                        unsigned int order, bool check_free)
 {
@@ -1141,6 +1175,9 @@ static __always_inline bool free_pages_prepare(struct page *page,
                                           PAGE_SIZE << order);
        }
        arch_free_page(page, order);
+       if (want_init_on_free())
+               kernel_init_free_pages(page, 1 << order);
+
        kernel_poison_pages(page, 1 << order, 0);
        if (debug_pagealloc_enabled())
                kernel_map_pages(page, 1 << order, 0);
@@ -1151,19 +1188,36 @@ static __always_inline bool free_pages_prepare(struct page *page,
 }
 
 #ifdef CONFIG_DEBUG_VM
-static inline bool free_pcp_prepare(struct page *page)
+/*
+ * With DEBUG_VM enabled, order-0 pages are checked immediately when being freed
+ * to pcp lists. With debug_pagealloc also enabled, they are also rechecked when
+ * moved from pcp lists to free lists.
+ */
+static bool free_pcp_prepare(struct page *page)
 {
        return free_pages_prepare(page, 0, true);
 }
 
-static inline bool bulkfree_pcp_prepare(struct page *page)
+static bool bulkfree_pcp_prepare(struct page *page)
 {
-       return false;
+       if (debug_pagealloc_enabled())
+               return free_pages_check(page);
+       else
+               return false;
 }
 #else
+/*
+ * With DEBUG_VM disabled, order-0 pages being freed are checked only when
+ * moving from pcp lists to free list in order to reduce overhead. With
+ * debug_pagealloc enabled, they are checked also immediately when being freed
+ * to the pcp lists.
+ */
 static bool free_pcp_prepare(struct page *page)
 {
-       return free_pages_prepare(page, 0, false);
+       if (debug_pagealloc_enabled())
+               return free_pages_prepare(page, 0, true);
+       else
+               return free_pages_prepare(page, 0, false);
 }
 
 static bool bulkfree_pcp_prepare(struct page *page)
@@ -1904,6 +1958,10 @@ void __init page_alloc_init_late(void)
 
        for_each_populated_zone(zone)
                set_zone_contiguous(zone);
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+       init_debug_guardpage();
+#endif
 }
 
 #ifdef CONFIG_CMA
@@ -2021,28 +2079,44 @@ static inline int check_new_page(struct page *page)
 
 static inline bool free_pages_prezeroed(void)
 {
-       return IS_ENABLED(CONFIG_PAGE_POISONING_ZERO) &&
-               page_poisoning_enabled();
+       return (IS_ENABLED(CONFIG_PAGE_POISONING_ZERO) &&
+               page_poisoning_enabled()) || want_init_on_free();
 }
 
 #ifdef CONFIG_DEBUG_VM
-static bool check_pcp_refill(struct page *page)
+/*
+ * With DEBUG_VM enabled, order-0 pages are checked for expected state when
+ * being allocated from pcp lists. With debug_pagealloc also enabled, they are
+ * also checked when pcp lists are refilled from the free lists.
+ */
+static inline bool check_pcp_refill(struct page *page)
 {
-       return false;
+       if (debug_pagealloc_enabled())
+               return check_new_page(page);
+       else
+               return false;
 }
 
-static bool check_new_pcp(struct page *page)
+static inline bool check_new_pcp(struct page *page)
 {
        return check_new_page(page);
 }
 #else
-static bool check_pcp_refill(struct page *page)
+/*
+ * With DEBUG_VM disabled, free order-0 pages are checked for expected state
+ * when pcp lists are being refilled from the free lists. With debug_pagealloc
+ * enabled, they are also checked when being allocated from the pcp lists.
+ */
+static inline bool check_pcp_refill(struct page *page)
 {
        return check_new_page(page);
 }
-static bool check_new_pcp(struct page *page)
+static inline bool check_new_pcp(struct page *page)
 {
-       return false;
+       if (debug_pagealloc_enabled())
+               return check_new_page(page);
+       else
+               return false;
 }
 #endif /* CONFIG_DEBUG_VM */
 
@@ -2076,13 +2150,10 @@ inline void post_alloc_hook(struct page *page, unsigned int order,
 static void prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
                                                        unsigned int alloc_flags)
 {
-       int i;
-
        post_alloc_hook(page, order, gfp_flags);
 
-       if (!free_pages_prezeroed() && (gfp_flags & __GFP_ZERO))
-               for (i = 0; i < (1 << order); i++)
-                       clear_highpage(page + i);
+       if (!free_pages_prezeroed() && want_init_on_alloc(gfp_flags))
+               kernel_init_free_pages(page, 1 << order);
 
        if (order && (gfp_flags & __GFP_COMP))
                prep_compound_page(page, order);
@@ -7520,10 +7591,28 @@ static int page_alloc_cpu_dead(unsigned int cpu)
        return 0;
 }
 
+#ifdef CONFIG_NUMA
+int hashdist = HASHDIST_DEFAULT;
+
+static int __init set_hashdist(char *str)
+{
+       if (!str)
+               return 0;
+       hashdist = simple_strtoul(str, &str, 0);
+       return 1;
+}
+__setup("hashdist=", set_hashdist);
+#endif
+
 void __init page_alloc_init(void)
 {
        int ret;
 
+#ifdef CONFIG_NUMA
+       if (num_node_state(N_MEMORY) == 1)
+               hashdist = 0;
+#endif
+
        ret = cpuhp_setup_state_nocalls(CPUHP_PAGE_ALLOC_DEAD,
                                        "mm/page_alloc:dead", NULL,
                                        page_alloc_cpu_dead);
@@ -7908,19 +7997,6 @@ out:
        return ret;
 }
 
-#ifdef CONFIG_NUMA
-int hashdist = HASHDIST_DEFAULT;
-
-static int __init set_hashdist(char *str)
-{
-       if (!str)
-               return 0;
-       hashdist = simple_strtoul(str, &str, 0);
-       return 1;
-}
-__setup("hashdist=", set_hashdist);
-#endif
-
 #ifndef __HAVE_ARCH_RESERVED_KERNEL_PAGES
 /*
  * Returns the number of pages that arch has reserved but
@@ -7967,6 +8043,7 @@ void *__init alloc_large_system_hash(const char *tablename,
        unsigned long log2qty, size;
        void *table = NULL;
        gfp_t gfp_flags;
+       bool virt;
 
        /* allow the kernel cmdline to have a say */
        if (!numentries) {
@@ -8023,6 +8100,7 @@ void *__init alloc_large_system_hash(const char *tablename,
 
        gfp_flags = (flags & HASH_ZERO) ? GFP_ATOMIC | __GFP_ZERO : GFP_ATOMIC;
        do {
+               virt = false;
                size = bucketsize << log2qty;
                if (flags & HASH_EARLY) {
                        if (flags & HASH_ZERO)
@@ -8030,26 +8108,26 @@ void *__init alloc_large_system_hash(const char *tablename,
                        else
                                table = memblock_alloc_raw(size,
                                                           SMP_CACHE_BYTES);
-               } else if (hashdist) {
+               } else if (get_order(size) >= MAX_ORDER || hashdist) {
                        table = __vmalloc(size, gfp_flags, PAGE_KERNEL);
+                       virt = true;
                } else {
                        /*
                         * If bucketsize is not a power-of-two, we may free
                         * some pages at the end of hash table which
                         * alloc_pages_exact() automatically does
                         */
-                       if (get_order(size) < MAX_ORDER) {
-                               table = alloc_pages_exact(size, gfp_flags);
-                               kmemleak_alloc(table, size, 1, gfp_flags);
-                       }
+                       table = alloc_pages_exact(size, gfp_flags);
+                       kmemleak_alloc(table, size, 1, gfp_flags);
                }
        } while (!table && size > PAGE_SIZE && --log2qty);
 
        if (!table)
                panic("Failed to allocate %s hash table\n", tablename);
 
-       pr_info("%s hash table entries: %ld (order: %d, %lu bytes)\n",
-               tablename, 1UL << log2qty, ilog2(size) - PAGE_SHIFT, size);
+       pr_info("%s hash table entries: %ld (order: %d, %lu bytes, %s)\n",
+               tablename, 1UL << log2qty, ilog2(size) - PAGE_SHIFT, size,
+               virt ? "vmalloc" : "linear");
 
        if (_hash_shift)
                *_hash_shift = log2qty;
index d8f1aca..5f5769c 100644 (file)
@@ -59,9 +59,6 @@
  */
 
 static struct page_ext_operations *page_ext_ops[] = {
-#ifdef CONFIG_DEBUG_PAGEALLOC
-       &debug_guardpage_ops,
-#endif
 #ifdef CONFIG_PAGE_OWNER
        &page_owner_ops,
 #endif
index a39aac2..24ee600 100644 (file)
@@ -163,7 +163,7 @@ int generic_swapfile_activate(struct swap_info_struct *sis,
        blocks_per_page = PAGE_SIZE >> blkbits;
 
        /*
-        * Map all the blocks into the extent list.  This code doesn't try
+        * Map all the blocks into the extent tree.  This code doesn't try
         * to be very smart.
         */
        probe_block = 0;
index e3638a5..89c19c0 100644 (file)
@@ -230,7 +230,7 @@ undo:
 /*
  * Make isolated pages available again.
  */
-int undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
+void undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
                            unsigned migratetype)
 {
        unsigned long pfn;
@@ -247,7 +247,6 @@ int undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
                        continue;
                unset_migratetype_isolate(page, migratetype);
        }
-       return 0;
 }
 /*
  * Test all pages in the range is free(means isolated) or not.
index f7117ad..9df3705 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -371,12 +371,6 @@ static void **dbg_userword(struct kmem_cache *cachep, void *objp)
 static int slab_max_order = SLAB_MAX_ORDER_LO;
 static bool slab_max_order_set __initdata;
 
-static inline struct kmem_cache *virt_to_cache(const void *obj)
-{
-       struct page *page = virt_to_head_page(obj);
-       return page->slab_cache;
-}
-
 static inline void *index_to_obj(struct kmem_cache *cache, struct page *page,
                                 unsigned int idx)
 {
@@ -1245,7 +1239,7 @@ void __init kmem_cache_init(void)
                                  nr_node_ids * sizeof(struct kmem_cache_node *),
                                  SLAB_HWCACHE_ALIGN, 0, 0);
        list_add(&kmem_cache->list, &slab_caches);
-       memcg_link_cache(kmem_cache);
+       memcg_link_cache(kmem_cache, NULL);
        slab_state = PARTIAL;
 
        /*
@@ -1366,7 +1360,6 @@ static struct page *kmem_getpages(struct kmem_cache *cachep, gfp_t flags,
                                                                int nodeid)
 {
        struct page *page;
-       int nr_pages;
 
        flags |= cachep->allocflags;
 
@@ -1376,17 +1369,11 @@ static struct page *kmem_getpages(struct kmem_cache *cachep, gfp_t flags,
                return NULL;
        }
 
-       if (memcg_charge_slab(page, flags, cachep->gfporder, cachep)) {
+       if (charge_slab_page(page, flags, cachep->gfporder, cachep)) {
                __free_pages(page, cachep->gfporder);
                return NULL;
        }
 
-       nr_pages = (1 << cachep->gfporder);
-       if (cachep->flags & SLAB_RECLAIM_ACCOUNT)
-               mod_lruvec_page_state(page, NR_SLAB_RECLAIMABLE, nr_pages);
-       else
-               mod_lruvec_page_state(page, NR_SLAB_UNRECLAIMABLE, nr_pages);
-
        __SetPageSlab(page);
        /* Record if ALLOC_NO_WATERMARKS was set when allocating the slab */
        if (sk_memalloc_socks() && page_is_pfmemalloc(page))
@@ -1401,12 +1388,6 @@ static struct page *kmem_getpages(struct kmem_cache *cachep, gfp_t flags,
 static void kmem_freepages(struct kmem_cache *cachep, struct page *page)
 {
        int order = cachep->gfporder;
-       unsigned long nr_freed = (1 << order);
-
-       if (cachep->flags & SLAB_RECLAIM_ACCOUNT)
-               mod_lruvec_page_state(page, NR_SLAB_RECLAIMABLE, -nr_freed);
-       else
-               mod_lruvec_page_state(page, NR_SLAB_UNRECLAIMABLE, -nr_freed);
 
        BUG_ON(!PageSlab(page));
        __ClearPageSlabPfmemalloc(page);
@@ -1415,8 +1396,8 @@ static void kmem_freepages(struct kmem_cache *cachep, struct page *page)
        page->mapping = NULL;
 
        if (current->reclaim_state)
-               current->reclaim_state->reclaimed_slab += nr_freed;
-       memcg_uncharge_slab(page, order, cachep);
+               current->reclaim_state->reclaimed_slab += 1 << order;
+       uncharge_slab_page(page, order, cachep);
        __free_pages(page, order);
 }
 
@@ -1830,6 +1811,14 @@ static bool set_objfreelist_slab_cache(struct kmem_cache *cachep,
 
        cachep->num = 0;
 
+       /*
+        * If slab auto-initialization on free is enabled, store the freelist
+        * off-slab, so that its contents don't end up in one of the allocated
+        * objects.
+        */
+       if (unlikely(slab_want_init_on_free(cachep)))
+               return false;
+
        if (cachep->ctor || flags & SLAB_TYPESAFE_BY_RCU)
                return false;
 
@@ -2258,6 +2247,10 @@ void __kmemcg_cache_deactivate(struct kmem_cache *cachep)
 {
        __kmem_cache_shrink(cachep);
 }
+
+void __kmemcg_cache_deactivate_after_rcu(struct kmem_cache *s)
+{
+}
 #endif
 
 int __kmem_cache_shutdown(struct kmem_cache *cachep)
@@ -3263,7 +3256,7 @@ slab_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
        local_irq_restore(save_flags);
        ptr = cache_alloc_debugcheck_after(cachep, flags, ptr, caller);
 
-       if (unlikely(flags & __GFP_ZERO) && ptr)
+       if (unlikely(slab_want_init_on_alloc(flags, cachep)) && ptr)
                memset(ptr, 0, cachep->object_size);
 
        slab_post_alloc_hook(cachep, flags, 1, &ptr);
@@ -3320,7 +3313,7 @@ slab_alloc(struct kmem_cache *cachep, gfp_t flags, unsigned long caller)
        objp = cache_alloc_debugcheck_after(cachep, flags, objp, caller);
        prefetchw(objp);
 
-       if (unlikely(flags & __GFP_ZERO) && objp)
+       if (unlikely(slab_want_init_on_alloc(flags, cachep)) && objp)
                memset(objp, 0, cachep->object_size);
 
        slab_post_alloc_hook(cachep, flags, 1, &objp);
@@ -3441,6 +3434,8 @@ void ___cache_free(struct kmem_cache *cachep, void *objp,
        struct array_cache *ac = cpu_cache_get(cachep);
 
        check_irq_off();
+       if (unlikely(slab_want_init_on_free(cachep)))
+               memset(objp, 0, cachep->object_size);
        kmemleak_free_recursive(objp, cachep->flags);
        objp = cache_free_debugcheck(cachep, objp, caller);
 
@@ -3528,7 +3523,7 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
        cache_alloc_debugcheck_after_bulk(s, flags, size, p, _RET_IP_);
 
        /* Clear memory outside IRQ disabled section */
-       if (unlikely(flags & __GFP_ZERO))
+       if (unlikely(slab_want_init_on_alloc(flags, s)))
                for (i = 0; i < size; i++)
                        memset(p[i], 0, s->object_size);
 
@@ -3715,6 +3710,8 @@ void kmem_cache_free_bulk(struct kmem_cache *orig_s, size_t size, void **p)
                        s = virt_to_cache(objp);
                else
                        s = cache_from_obj(orig_s, objp);
+               if (!s)
+                       continue;
 
                debug_check_no_locks_freed(objp, s->object_size);
                if (!(s->flags & SLAB_DEBUG_OBJECTS))
@@ -3749,6 +3746,10 @@ void kfree(const void *objp)
        local_irq_save(flags);
        kfree_debugcheck(objp);
        c = virt_to_cache(objp);
+       if (!c) {
+               local_irq_restore(flags);
+               return;
+       }
        debug_check_no_locks_freed(objp, c->object_size);
 
        debug_check_no_obj_freed(objp, c->object_size);
@@ -4204,33 +4205,23 @@ void __check_heap_object(const void *ptr, unsigned long n, struct page *page,
 #endif /* CONFIG_HARDENED_USERCOPY */
 
 /**
- * ksize - get the actual amount of memory allocated for a given object
- * @objp: Pointer to the object
- *
- * kmalloc may internally round up allocations and return more memory
- * than requested. ksize() can be used to determine the actual amount of
- * memory allocated. The caller may use this additional memory, even though
- * a smaller amount of memory was initially specified with the kmalloc call.
- * The caller must guarantee that objp points to a valid object previously
- * allocated with either kmalloc() or kmem_cache_alloc(). The object
- * must not be freed during the duration of the call.
+ * __ksize -- Uninstrumented ksize.
  *
- * Return: size of the actual memory used by @objp in bytes
+ * Unlike ksize(), __ksize() is uninstrumented, and does not provide the same
+ * safety checks as ksize() with KASAN instrumentation enabled.
  */
-size_t ksize(const void *objp)
+size_t __ksize(const void *objp)
 {
+       struct kmem_cache *c;
        size_t size;
 
        BUG_ON(!objp);
        if (unlikely(objp == ZERO_SIZE_PTR))
                return 0;
 
-       size = virt_to_cache(objp)->object_size;
-       /* We assume that ksize callers could use the whole allocated area,
-        * so we need to unpoison this area.
-        */
-       kasan_unpoison_shadow(objp, size);
+       c = virt_to_cache(objp);
+       size = c ? c->object_size : 0;
 
        return size;
 }
-EXPORT_SYMBOL(ksize);
+EXPORT_SYMBOL(__ksize);
index 43ac818..9057b80 100644 (file)
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -172,6 +172,7 @@ int __kmem_cache_shutdown(struct kmem_cache *);
 void __kmem_cache_release(struct kmem_cache *);
 int __kmem_cache_shrink(struct kmem_cache *);
 void __kmemcg_cache_deactivate(struct kmem_cache *s);
+void __kmemcg_cache_deactivate_after_rcu(struct kmem_cache *s);
 void slab_kmem_cache_release(struct kmem_cache *);
 
 struct seq_file;
@@ -204,6 +205,12 @@ ssize_t slabinfo_write(struct file *file, const char __user *buffer,
 void __kmem_cache_free_bulk(struct kmem_cache *, size_t, void **);
 int __kmem_cache_alloc_bulk(struct kmem_cache *, gfp_t, size_t, void **);
 
+static inline int cache_vmstat_idx(struct kmem_cache *s)
+{
+       return (s->flags & SLAB_RECLAIM_ACCOUNT) ?
+               NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE;
+}
+
 #ifdef CONFIG_MEMCG_KMEM
 
 /* List of all root caches. */
@@ -241,31 +248,6 @@ static inline const char *cache_name(struct kmem_cache *s)
        return s->name;
 }
 
-/*
- * Note, we protect with RCU only the memcg_caches array, not per-memcg caches.
- * That said the caller must assure the memcg's cache won't go away by either
- * taking a css reference to the owner cgroup, or holding the slab_mutex.
- */
-static inline struct kmem_cache *
-cache_from_memcg_idx(struct kmem_cache *s, int idx)
-{
-       struct kmem_cache *cachep;
-       struct memcg_cache_array *arr;
-
-       rcu_read_lock();
-       arr = rcu_dereference(s->memcg_params.memcg_caches);
-
-       /*
-        * Make sure we will access the up-to-date value. The code updating
-        * memcg_caches issues a write barrier to match this (see
-        * memcg_create_kmem_cache()).
-        */
-       cachep = READ_ONCE(arr->entries[idx]);
-       rcu_read_unlock();
-
-       return cachep;
-}
-
 static inline struct kmem_cache *memcg_root_cache(struct kmem_cache *s)
 {
        if (is_root_cache(s))
@@ -273,25 +255,94 @@ static inline struct kmem_cache *memcg_root_cache(struct kmem_cache *s)
        return s->memcg_params.root_cache;
 }
 
+/*
+ * Expects a pointer to a slab page. Please note, that PageSlab() check
+ * isn't sufficient, as it returns true also for tail compound slab pages,
+ * which do not have slab_cache pointer set.
+ * So this function assumes that the page can pass PageHead() and PageSlab()
+ * checks.
+ *
+ * The kmem_cache can be reparented asynchronously. The caller must ensure
+ * the memcg lifetime, e.g. by taking rcu_read_lock() or cgroup_mutex.
+ */
+static inline struct mem_cgroup *memcg_from_slab_page(struct page *page)
+{
+       struct kmem_cache *s;
+
+       s = READ_ONCE(page->slab_cache);
+       if (s && !is_root_cache(s))
+               return READ_ONCE(s->memcg_params.memcg);
+
+       return NULL;
+}
+
+/*
+ * Charge the slab page belonging to the non-root kmem_cache.
+ * Can be called for non-root kmem_caches only.
+ */
 static __always_inline int memcg_charge_slab(struct page *page,
                                             gfp_t gfp, int order,
                                             struct kmem_cache *s)
 {
-       if (is_root_cache(s))
+       struct mem_cgroup *memcg;
+       struct lruvec *lruvec;
+       int ret;
+
+       rcu_read_lock();
+       memcg = READ_ONCE(s->memcg_params.memcg);
+       while (memcg && !css_tryget_online(&memcg->css))
+               memcg = parent_mem_cgroup(memcg);
+       rcu_read_unlock();
+
+       if (unlikely(!memcg || mem_cgroup_is_root(memcg))) {
+               mod_node_page_state(page_pgdat(page), cache_vmstat_idx(s),
+                                   (1 << order));
+               percpu_ref_get_many(&s->memcg_params.refcnt, 1 << order);
                return 0;
-       return memcg_kmem_charge_memcg(page, gfp, order, s->memcg_params.memcg);
+       }
+
+       ret = memcg_kmem_charge_memcg(page, gfp, order, memcg);
+       if (ret)
+               goto out;
+
+       lruvec = mem_cgroup_lruvec(page_pgdat(page), memcg);
+       mod_lruvec_state(lruvec, cache_vmstat_idx(s), 1 << order);
+
+       /* transer try_charge() page references to kmem_cache */
+       percpu_ref_get_many(&s->memcg_params.refcnt, 1 << order);
+       css_put_many(&memcg->css, 1 << order);
+out:
+       css_put(&memcg->css);
+       return ret;
 }
 
+/*
+ * Uncharge a slab page belonging to a non-root kmem_cache.
+ * Can be called for non-root kmem_caches only.
+ */
 static __always_inline void memcg_uncharge_slab(struct page *page, int order,
                                                struct kmem_cache *s)
 {
-       memcg_kmem_uncharge(page, order);
+       struct mem_cgroup *memcg;
+       struct lruvec *lruvec;
+
+       rcu_read_lock();
+       memcg = READ_ONCE(s->memcg_params.memcg);
+       if (likely(!mem_cgroup_is_root(memcg))) {
+               lruvec = mem_cgroup_lruvec(page_pgdat(page), memcg);
+               mod_lruvec_state(lruvec, cache_vmstat_idx(s), -(1 << order));
+               memcg_kmem_uncharge_memcg(page, order, memcg);
+       } else {
+               mod_node_page_state(page_pgdat(page), cache_vmstat_idx(s),
+                                   -(1 << order));
+       }
+       rcu_read_unlock();
+
+       percpu_ref_put_many(&s->memcg_params.refcnt, 1 << order);
 }
 
 extern void slab_init_memcg_params(struct kmem_cache *);
-extern void memcg_link_cache(struct kmem_cache *s);
-extern void slab_deactivate_memcg_cache_rcu_sched(struct kmem_cache *s,
-                               void (*deact_fn)(struct kmem_cache *));
+extern void memcg_link_cache(struct kmem_cache *s, struct mem_cgroup *memcg);
 
 #else /* CONFIG_MEMCG_KMEM */
 
@@ -310,7 +361,7 @@ static inline bool is_root_cache(struct kmem_cache *s)
 static inline bool slab_equal_or_root(struct kmem_cache *s,
                                      struct kmem_cache *p)
 {
-       return true;
+       return s == p;
 }
 
 static inline const char *cache_name(struct kmem_cache *s)
@@ -318,15 +369,14 @@ static inline const char *cache_name(struct kmem_cache *s)
        return s->name;
 }
 
-static inline struct kmem_cache *
-cache_from_memcg_idx(struct kmem_cache *s, int idx)
+static inline struct kmem_cache *memcg_root_cache(struct kmem_cache *s)
 {
-       return NULL;
+       return s;
 }
 
-static inline struct kmem_cache *memcg_root_cache(struct kmem_cache *s)
+static inline struct mem_cgroup *memcg_from_slab_page(struct page *page)
 {
-       return s;
+       return NULL;
 }
 
 static inline int memcg_charge_slab(struct page *page, gfp_t gfp, int order,
@@ -344,16 +394,52 @@ static inline void slab_init_memcg_params(struct kmem_cache *s)
 {
 }
 
-static inline void memcg_link_cache(struct kmem_cache *s)
+static inline void memcg_link_cache(struct kmem_cache *s,
+                                   struct mem_cgroup *memcg)
 {
 }
 
 #endif /* CONFIG_MEMCG_KMEM */
 
+static inline struct kmem_cache *virt_to_cache(const void *obj)
+{
+       struct page *page;
+
+       page = virt_to_head_page(obj);
+       if (WARN_ONCE(!PageSlab(page), "%s: Object is not a Slab page!\n",
+                                       __func__))
+               return NULL;
+       return page->slab_cache;
+}
+
+static __always_inline int charge_slab_page(struct page *page,
+                                           gfp_t gfp, int order,
+                                           struct kmem_cache *s)
+{
+       if (is_root_cache(s)) {
+               mod_node_page_state(page_pgdat(page), cache_vmstat_idx(s),
+                                   1 << order);
+               return 0;
+       }
+
+       return memcg_charge_slab(page, gfp, order, s);
+}
+
+static __always_inline void uncharge_slab_page(struct page *page, int order,
+                                              struct kmem_cache *s)
+{
+       if (is_root_cache(s)) {
+               mod_node_page_state(page_pgdat(page), cache_vmstat_idx(s),
+                                   -(1 << order));
+               return;
+       }
+
+       memcg_uncharge_slab(page, order, s);
+}
+
 static inline struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x)
 {
        struct kmem_cache *cachep;
-       struct page *page;
 
        /*
         * When kmemcg is not being used, both assignments should return the
@@ -363,18 +449,15 @@ static inline struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x)
         * will also be a constant.
         */
        if (!memcg_kmem_enabled() &&
+           !IS_ENABLED(CONFIG_SLAB_FREELIST_HARDENED) &&
            !unlikely(s->flags & SLAB_CONSISTENCY_CHECKS))
                return s;
 
-       page = virt_to_head_page(x);
-       cachep = page->slab_cache;
-       if (slab_equal_or_root(cachep, s))
-               return cachep;
-
-       pr_err("%s: Wrong slab cache. %s but object is from %s\n",
-              __func__, s->name, cachep->name);
-       WARN_ON_ONCE(1);
-       return s;
+       cachep = virt_to_cache(x);
+       WARN_ONCE(cachep && !slab_equal_or_root(cachep, s),
+                 "%s: Wrong slab cache. %s but object is from %s\n",
+                 __func__, s->name, cachep->name);
+       return cachep;
 }
 
 static inline size_t slab_ksize(const struct kmem_cache *s)
@@ -524,4 +607,24 @@ static inline int cache_random_seq_create(struct kmem_cache *cachep,
 static inline void cache_random_seq_destroy(struct kmem_cache *cachep) { }
 #endif /* CONFIG_SLAB_FREELIST_RANDOM */
 
+static inline bool slab_want_init_on_alloc(gfp_t flags, struct kmem_cache *c)
+{
+       if (static_branch_unlikely(&init_on_alloc)) {
+               if (c->ctor)
+                       return false;
+               if (c->flags & (SLAB_TYPESAFE_BY_RCU | SLAB_POISON))
+                       return flags & __GFP_ZERO;
+               return true;
+       }
+       return flags & __GFP_ZERO;
+}
+
+static inline bool slab_want_init_on_free(struct kmem_cache *c)
+{
+       if (static_branch_unlikely(&init_on_free))
+               return !(c->ctor ||
+                        (c->flags & (SLAB_TYPESAFE_BY_RCU | SLAB_POISON)));
+       return false;
+}
+
 #endif /* MM_SLAB_H */
index 58251ba..6c49dbb 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/uaccess.h>
 #include <linux/seq_file.h>
 #include <linux/proc_fs.h>
+#include <linux/debugfs.h>
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 #include <asm/page.h>
@@ -130,6 +131,9 @@ int __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t nr,
 #ifdef CONFIG_MEMCG_KMEM
 
 LIST_HEAD(slab_root_caches);
+static DEFINE_SPINLOCK(memcg_kmem_wq_lock);
+
+static void kmemcg_cache_shutdown(struct percpu_ref *percpu_ref);
 
 void slab_init_memcg_params(struct kmem_cache *s)
 {
@@ -140,13 +144,18 @@ void slab_init_memcg_params(struct kmem_cache *s)
 }
 
 static int init_memcg_params(struct kmem_cache *s,
-               struct mem_cgroup *memcg, struct kmem_cache *root_cache)
+                            struct kmem_cache *root_cache)
 {
        struct memcg_cache_array *arr;
 
        if (root_cache) {
+               int ret = percpu_ref_init(&s->memcg_params.refcnt,
+                                         kmemcg_cache_shutdown,
+                                         0, GFP_KERNEL);
+               if (ret)
+                       return ret;
+
                s->memcg_params.root_cache = root_cache;
-               s->memcg_params.memcg = memcg;
                INIT_LIST_HEAD(&s->memcg_params.children_node);
                INIT_LIST_HEAD(&s->memcg_params.kmem_caches_node);
                return 0;
@@ -171,6 +180,8 @@ static void destroy_memcg_params(struct kmem_cache *s)
 {
        if (is_root_cache(s))
                kvfree(rcu_access_pointer(s->memcg_params.memcg_caches));
+       else
+               percpu_ref_exit(&s->memcg_params.refcnt);
 }
 
 static void free_memcg_params(struct rcu_head *rcu)
@@ -221,11 +232,13 @@ int memcg_update_all_caches(int num_memcgs)
        return ret;
 }
 
-void memcg_link_cache(struct kmem_cache *s)
+void memcg_link_cache(struct kmem_cache *s, struct mem_cgroup *memcg)
 {
        if (is_root_cache(s)) {
                list_add(&s->root_caches_node, &slab_root_caches);
        } else {
+               css_get(&memcg->css);
+               s->memcg_params.memcg = memcg;
                list_add(&s->memcg_params.children_node,
                         &s->memcg_params.root_cache->memcg_params.children);
                list_add(&s->memcg_params.kmem_caches_node,
@@ -240,11 +253,13 @@ static void memcg_unlink_cache(struct kmem_cache *s)
        } else {
                list_del(&s->memcg_params.children_node);
                list_del(&s->memcg_params.kmem_caches_node);
+               mem_cgroup_put(s->memcg_params.memcg);
+               WRITE_ONCE(s->memcg_params.memcg, NULL);
        }
 }
 #else
 static inline int init_memcg_params(struct kmem_cache *s,
-               struct mem_cgroup *memcg, struct kmem_cache *root_cache)
+                                   struct kmem_cache *root_cache)
 {
        return 0;
 }
@@ -384,7 +399,7 @@ static struct kmem_cache *create_cache(const char *name,
        s->useroffset = useroffset;
        s->usersize = usersize;
 
-       err = init_memcg_params(s, memcg, root_cache);
+       err = init_memcg_params(s, root_cache);
        if (err)
                goto out_free_cache;
 
@@ -394,7 +409,7 @@ static struct kmem_cache *create_cache(const char *name,
 
        s->refcount = 1;
        list_add(&s->list, &slab_caches);
-       memcg_link_cache(s);
+       memcg_link_cache(s, memcg);
 out:
        if (err)
                return ERR_PTR(err);
@@ -640,7 +655,7 @@ void memcg_create_kmem_cache(struct mem_cgroup *memcg,
         * The memory cgroup could have been offlined while the cache
         * creation work was pending.
         */
-       if (memcg->kmem_state != KMEM_ONLINE || root_cache->memcg_params.dying)
+       if (memcg->kmem_state != KMEM_ONLINE)
                goto out_unlock;
 
        idx = memcg_cache_id(memcg);
@@ -677,7 +692,7 @@ void memcg_create_kmem_cache(struct mem_cgroup *memcg,
        }
 
        /*
-        * Since readers won't lock (see cache_from_memcg_idx()), we need a
+        * Since readers won't lock (see memcg_kmem_get_cache()), we need a
         * barrier here to ensure nobody will see the kmem_cache partially
         * initialized.
         */
@@ -691,74 +706,95 @@ out_unlock:
        put_online_cpus();
 }
 
-static void kmemcg_deactivate_workfn(struct work_struct *work)
+static void kmemcg_workfn(struct work_struct *work)
 {
        struct kmem_cache *s = container_of(work, struct kmem_cache,
-                                           memcg_params.deact_work);
+                                           memcg_params.work);
 
        get_online_cpus();
        get_online_mems();
 
        mutex_lock(&slab_mutex);
-
-       s->memcg_params.deact_fn(s);
-
+       s->memcg_params.work_fn(s);
        mutex_unlock(&slab_mutex);
 
        put_online_mems();
        put_online_cpus();
-
-       /* done, put the ref from slab_deactivate_memcg_cache_rcu_sched() */
-       css_put(&s->memcg_params.memcg->css);
 }
 
-static void kmemcg_deactivate_rcufn(struct rcu_head *head)
+static void kmemcg_rcufn(struct rcu_head *head)
 {
        struct kmem_cache *s = container_of(head, struct kmem_cache,
-                                           memcg_params.deact_rcu_head);
+                                           memcg_params.rcu_head);
 
        /*
-        * We need to grab blocking locks.  Bounce to ->deact_work.  The
+        * We need to grab blocking locks.  Bounce to ->work.  The
         * work item shares the space with the RCU head and can't be
         * initialized eariler.
         */
-       INIT_WORK(&s->memcg_params.deact_work, kmemcg_deactivate_workfn);
-       queue_work(memcg_kmem_cache_wq, &s->memcg_params.deact_work);
+       INIT_WORK(&s->memcg_params.work, kmemcg_workfn);
+       queue_work(memcg_kmem_cache_wq, &s->memcg_params.work);
 }
 
-/**
- * slab_deactivate_memcg_cache_rcu_sched - schedule deactivation after a
- *                                        sched RCU grace period
- * @s: target kmem_cache
- * @deact_fn: deactivation function to call
- *
- * Schedule @deact_fn to be invoked with online cpus, mems and slab_mutex
- * held after a sched RCU grace period.  The slab is guaranteed to stay
- * alive until @deact_fn is finished.  This is to be used from
- * __kmemcg_cache_deactivate().
- */
-void slab_deactivate_memcg_cache_rcu_sched(struct kmem_cache *s,
-                                          void (*deact_fn)(struct kmem_cache *))
+static void kmemcg_cache_shutdown_fn(struct kmem_cache *s)
 {
-       if (WARN_ON_ONCE(is_root_cache(s)) ||
-           WARN_ON_ONCE(s->memcg_params.deact_fn))
-               return;
+       WARN_ON(shutdown_cache(s));
+}
+
+static void kmemcg_cache_shutdown(struct percpu_ref *percpu_ref)
+{
+       struct kmem_cache *s = container_of(percpu_ref, struct kmem_cache,
+                                           memcg_params.refcnt);
+       unsigned long flags;
 
+       spin_lock_irqsave(&memcg_kmem_wq_lock, flags);
        if (s->memcg_params.root_cache->memcg_params.dying)
+               goto unlock;
+
+       s->memcg_params.work_fn = kmemcg_cache_shutdown_fn;
+       INIT_WORK(&s->memcg_params.work, kmemcg_workfn);
+       queue_work(memcg_kmem_cache_wq, &s->memcg_params.work);
+
+unlock:
+       spin_unlock_irqrestore(&memcg_kmem_wq_lock, flags);
+}
+
+static void kmemcg_cache_deactivate_after_rcu(struct kmem_cache *s)
+{
+       __kmemcg_cache_deactivate_after_rcu(s);
+       percpu_ref_kill(&s->memcg_params.refcnt);
+}
+
+static void kmemcg_cache_deactivate(struct kmem_cache *s)
+{
+       if (WARN_ON_ONCE(is_root_cache(s)))
                return;
 
-       /* pin memcg so that @s doesn't get destroyed in the middle */
-       css_get(&s->memcg_params.memcg->css);
+       __kmemcg_cache_deactivate(s);
+       s->flags |= SLAB_DEACTIVATED;
+
+       /*
+        * memcg_kmem_wq_lock is used to synchronize memcg_params.dying
+        * flag and make sure that no new kmem_cache deactivation tasks
+        * are queued (see flush_memcg_workqueue() ).
+        */
+       spin_lock_irq(&memcg_kmem_wq_lock);
+       if (s->memcg_params.root_cache->memcg_params.dying)
+               goto unlock;
 
-       s->memcg_params.deact_fn = deact_fn;
-       call_rcu(&s->memcg_params.deact_rcu_head, kmemcg_deactivate_rcufn);
+       s->memcg_params.work_fn = kmemcg_cache_deactivate_after_rcu;
+       call_rcu(&s->memcg_params.rcu_head, kmemcg_rcufn);
+unlock:
+       spin_unlock_irq(&memcg_kmem_wq_lock);
 }
 
-void memcg_deactivate_kmem_caches(struct mem_cgroup *memcg)
+void memcg_deactivate_kmem_caches(struct mem_cgroup *memcg,
+                                 struct mem_cgroup *parent)
 {
        int idx;
        struct memcg_cache_array *arr;
        struct kmem_cache *s, *c;
+       unsigned int nr_reparented;
 
        idx = memcg_cache_id(memcg);
 
@@ -773,30 +809,20 @@ void memcg_deactivate_kmem_caches(struct mem_cgroup *memcg)
                if (!c)
                        continue;
 
-               __kmemcg_cache_deactivate(c);
+               kmemcg_cache_deactivate(c);
                arr->entries[idx] = NULL;
        }
-       mutex_unlock(&slab_mutex);
-
-       put_online_mems();
-       put_online_cpus();
-}
-
-void memcg_destroy_kmem_caches(struct mem_cgroup *memcg)
-{
-       struct kmem_cache *s, *s2;
-
-       get_online_cpus();
-       get_online_mems();
-
-       mutex_lock(&slab_mutex);
-       list_for_each_entry_safe(s, s2, &memcg->kmem_caches,
-                                memcg_params.kmem_caches_node) {
-               /*
-                * The cgroup is about to be freed and therefore has no charges
-                * left. Hence, all its caches must be empty by now.
-                */
-               BUG_ON(shutdown_cache(s));
+       nr_reparented = 0;
+       list_for_each_entry(s, &memcg->kmem_caches,
+                           memcg_params.kmem_caches_node) {
+               WRITE_ONCE(s->memcg_params.memcg, parent);
+               css_put(&memcg->css);
+               nr_reparented++;
+       }
+       if (nr_reparented) {
+               list_splice_init(&memcg->kmem_caches,
+                                &parent->kmem_caches);
+               css_get_many(&parent->css, nr_reparented);
        }
        mutex_unlock(&slab_mutex);
 
@@ -861,16 +887,15 @@ static int shutdown_memcg_caches(struct kmem_cache *s)
 
 static void flush_memcg_workqueue(struct kmem_cache *s)
 {
-       mutex_lock(&slab_mutex);
+       spin_lock_irq(&memcg_kmem_wq_lock);
        s->memcg_params.dying = true;
-       mutex_unlock(&slab_mutex);
+       spin_unlock_irq(&memcg_kmem_wq_lock);
 
        /*
-        * SLUB deactivates the kmem_caches through call_rcu. Make
+        * SLAB and SLUB deactivate the kmem_caches through call_rcu. Make
         * sure all registered rcu callbacks have been invoked.
         */
-       if (IS_ENABLED(CONFIG_SLUB))
-               rcu_barrier();
+       rcu_barrier();
 
        /*
         * SLAB and SLUB create memcg kmem_caches through workqueue and SLUB
@@ -997,7 +1022,7 @@ struct kmem_cache *__init create_kmalloc_cache(const char *name,
 
        create_boot_cache(s, name, size, flags, useroffset, usersize);
        list_add(&s->list, &slab_caches);
-       memcg_link_cache(s);
+       memcg_link_cache(s, NULL);
        s->refcount = 1;
        return s;
 }
@@ -1498,6 +1523,64 @@ static int __init slab_proc_init(void)
        return 0;
 }
 module_init(slab_proc_init);
+
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_MEMCG_KMEM)
+/*
+ * Display information about kmem caches that have child memcg caches.
+ */
+static int memcg_slabinfo_show(struct seq_file *m, void *unused)
+{
+       struct kmem_cache *s, *c;
+       struct slabinfo sinfo;
+
+       mutex_lock(&slab_mutex);
+       seq_puts(m, "# <name> <css_id[:dead|deact]> <active_objs> <num_objs>");
+       seq_puts(m, " <active_slabs> <num_slabs>\n");
+       list_for_each_entry(s, &slab_root_caches, root_caches_node) {
+               /*
+                * Skip kmem caches that don't have any memcg children.
+                */
+               if (list_empty(&s->memcg_params.children))
+                       continue;
+
+               memset(&sinfo, 0, sizeof(sinfo));
+               get_slabinfo(s, &sinfo);
+               seq_printf(m, "%-17s root       %6lu %6lu %6lu %6lu\n",
+                          cache_name(s), sinfo.active_objs, sinfo.num_objs,
+                          sinfo.active_slabs, sinfo.num_slabs);
+
+               for_each_memcg_cache(c, s) {
+                       struct cgroup_subsys_state *css;
+                       char *status = "";
+
+                       css = &c->memcg_params.memcg->css;
+                       if (!(css->flags & CSS_ONLINE))
+                               status = ":dead";
+                       else if (c->flags & SLAB_DEACTIVATED)
+                               status = ":deact";
+
+                       memset(&sinfo, 0, sizeof(sinfo));
+                       get_slabinfo(c, &sinfo);
+                       seq_printf(m, "%-17s %4d%-6s %6lu %6lu %6lu %6lu\n",
+                                  cache_name(c), css->id, status,
+                                  sinfo.active_objs, sinfo.num_objs,
+                                  sinfo.active_slabs, sinfo.num_slabs);
+               }
+       }
+       mutex_unlock(&slab_mutex);
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(memcg_slabinfo);
+
+static int __init memcg_slabinfo_init(void)
+{
+       debugfs_create_file("memcg_slabinfo", S_IFREG | S_IRUGO,
+                           NULL, NULL, &memcg_slabinfo_fops);
+       return 0;
+}
+
+late_initcall(memcg_slabinfo_init);
+#endif /* CONFIG_DEBUG_FS && CONFIG_MEMCG_KMEM */
 #endif /* CONFIG_SLAB || CONFIG_SLUB_DEBUG */
 
 static __always_inline void *__do_krealloc(const void *p, size_t new_size,
@@ -1597,6 +1680,52 @@ void kzfree(const void *p)
 }
 EXPORT_SYMBOL(kzfree);
 
+/**
+ * ksize - get the actual amount of memory allocated for a given object
+ * @objp: Pointer to the object
+ *
+ * kmalloc may internally round up allocations and return more memory
+ * than requested. ksize() can be used to determine the actual amount of
+ * memory allocated. The caller may use this additional memory, even though
+ * a smaller amount of memory was initially specified with the kmalloc call.
+ * The caller must guarantee that objp points to a valid object previously
+ * allocated with either kmalloc() or kmem_cache_alloc(). The object
+ * must not be freed during the duration of the call.
+ *
+ * Return: size of the actual memory used by @objp in bytes
+ */
+size_t ksize(const void *objp)
+{
+       size_t size;
+
+       if (WARN_ON_ONCE(!objp))
+               return 0;
+       /*
+        * We need to check that the pointed to object is valid, and only then
+        * unpoison the shadow memory below. We use __kasan_check_read(), to
+        * generate a more useful report at the time ksize() is called (rather
+        * than later where behaviour is undefined due to potential
+        * use-after-free or double-free).
+        *
+        * If the pointed to memory is invalid we return 0, to avoid users of
+        * ksize() writing to and potentially corrupting the memory region.
+        *
+        * We want to perform the check before __ksize(), to avoid potentially
+        * crashing in __ksize() due to accessing invalid metadata.
+        */
+       if (unlikely(objp == ZERO_SIZE_PTR) || !__kasan_check_read(objp, 1))
+               return 0;
+
+       size = __ksize(objp);
+       /*
+        * We assume that ksize callers could use whole allocated area,
+        * so we need to unpoison this area.
+        */
+       kasan_unpoison_shadow(objp, size);
+       return size;
+}
+EXPORT_SYMBOL(ksize);
+
 /* Tracepoints definitions. */
 EXPORT_TRACEPOINT_SYMBOL(kmalloc);
 EXPORT_TRACEPOINT_SYMBOL(kmem_cache_alloc);
index 84aefd9..7f421d0 100644 (file)
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -527,7 +527,7 @@ void kfree(const void *block)
 EXPORT_SYMBOL(kfree);
 
 /* can't use ksize for kmem_cache_alloc memory, only kmalloc */
-size_t ksize(const void *block)
+size_t __ksize(const void *block)
 {
        struct page *sp;
        int align;
@@ -545,7 +545,7 @@ size_t ksize(const void *block)
        m = (unsigned int *)(block - align);
        return SLOB_UNITS(*m) * SLOB_UNIT;
 }
-EXPORT_SYMBOL(ksize);
+EXPORT_SYMBOL(__ksize);
 
 int __kmem_cache_create(struct kmem_cache *c, slab_flags_t flags)
 {
index cd04dbd..e6c030e 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1279,6 +1279,10 @@ check_slabs:
        if (*str == ',')
                slub_debug_slabs = str + 1;
 out:
+       if ((static_branch_unlikely(&init_on_alloc) ||
+            static_branch_unlikely(&init_on_free)) &&
+           (slub_debug & SLAB_POISON))
+               pr_info("mem auto-init: SLAB_POISON will take precedence over init_on_alloc/init_on_free\n");
        return 1;
 }
 
@@ -1313,9 +1317,7 @@ slab_flags_t kmem_cache_flags(unsigned int object_size,
                char *end, *glob;
                size_t cmplen;
 
-               end = strchr(iter, ',');
-               if (!end)
-                       end = iter + strlen(iter);
+               end = strchrnul(iter, ',');
 
                glob = strnchr(iter, end - iter, '*');
                if (glob)
@@ -1424,6 +1426,28 @@ static __always_inline bool slab_free_hook(struct kmem_cache *s, void *x)
 static inline bool slab_free_freelist_hook(struct kmem_cache *s,
                                           void **head, void **tail)
 {
+
+       void *object;
+       void *next = *head;
+       void *old_tail = *tail ? *tail : *head;
+       int rsize;
+
+       if (slab_want_init_on_free(s))
+               do {
+                       object = next;
+                       next = get_freepointer(s, object);
+                       /*
+                        * Clear the object and the metadata, but don't touch
+                        * the redzone.
+                        */
+                       memset(object, 0, s->object_size);
+                       rsize = (s->flags & SLAB_RED_ZONE) ? s->red_left_pad
+                                                          : 0;
+                       memset((char *)object + s->inuse, 0,
+                              s->size - s->inuse - rsize);
+                       set_freepointer(s, object, next);
+               } while (object != old_tail);
+
 /*
  * Compiler cannot detect this function can be removed if slab_free_hook()
  * evaluates to nothing.  Thus, catch all relevant config debug options here.
@@ -1433,9 +1457,7 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s,
        defined(CONFIG_DEBUG_OBJECTS_FREE) ||   \
        defined(CONFIG_KASAN)
 
-       void *object;
-       void *next = *head;
-       void *old_tail = *tail ? *tail : *head;
+       next = *head;
 
        /* Head and tail of the reconstructed freelist */
        *head = NULL;
@@ -1490,7 +1512,7 @@ static inline struct page *alloc_slab_page(struct kmem_cache *s,
        else
                page = __alloc_pages_node(node, flags, order);
 
-       if (page && memcg_charge_slab(page, flags, order, s)) {
+       if (page && charge_slab_page(page, flags, order, s)) {
                __free_pages(page, order);
                page = NULL;
        }
@@ -1683,11 +1705,6 @@ out:
        if (!page)
                return NULL;
 
-       mod_lruvec_page_state(page,
-               (s->flags & SLAB_RECLAIM_ACCOUNT) ?
-               NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
-               1 << oo_order(oo));
-
        inc_slabs_node(s, page_to_nid(page), page->objects);
 
        return page;
@@ -1721,18 +1738,13 @@ static void __free_slab(struct kmem_cache *s, struct page *page)
                        check_object(s, page, p, SLUB_RED_INACTIVE);
        }
 
-       mod_lruvec_page_state(page,
-               (s->flags & SLAB_RECLAIM_ACCOUNT) ?
-               NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
-               -pages);
-
        __ClearPageSlabPfmemalloc(page);
        __ClearPageSlab(page);
 
        page->mapping = NULL;
        if (current->reclaim_state)
                current->reclaim_state->reclaimed_slab += pages;
-       memcg_uncharge_slab(page, order, s);
+       uncharge_slab_page(page, order, s);
        __free_pages(page, order);
 }
 
@@ -2741,8 +2753,14 @@ redo:
                prefetch_freepointer(s, next_object);
                stat(s, ALLOC_FASTPATH);
        }
+       /*
+        * If the object has been wiped upon free, make sure it's fully
+        * initialized by zeroing out freelist pointer.
+        */
+       if (unlikely(slab_want_init_on_free(s)) && object)
+               memset(object + s->offset, 0, sizeof(void *));
 
-       if (unlikely(gfpflags & __GFP_ZERO) && object)
+       if (unlikely(slab_want_init_on_alloc(gfpflags, s)) && object)
                memset(object, 0, s->object_size);
 
        slab_post_alloc_hook(s, gfpflags, 1, &object);
@@ -3163,7 +3181,7 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
        local_irq_enable();
 
        /* Clear memory outside IRQ disabled fastpath loop */
-       if (unlikely(flags & __GFP_ZERO)) {
+       if (unlikely(slab_want_init_on_alloc(flags, s))) {
                int j;
 
                for (j = 0; j < i; j++)
@@ -3652,10 +3670,6 @@ static int kmem_cache_open(struct kmem_cache *s, slab_flags_t flags)
 
        free_kmem_cache_nodes(s);
 error:
-       if (flags & SLAB_PANIC)
-               panic("Cannot create slab %s size=%u realsize=%u order=%u offset=%u flags=%lx\n",
-                     s->name, s->size, s->size,
-                     oo_order(s->oo), s->offset, (unsigned long)flags);
        return -EINVAL;
 }
 
@@ -3901,7 +3915,7 @@ void __check_heap_object(const void *ptr, unsigned long n, struct page *page,
 }
 #endif /* CONFIG_HARDENED_USERCOPY */
 
-static size_t __ksize(const void *object)
+size_t __ksize(const void *object)
 {
        struct page *page;
 
@@ -3917,17 +3931,7 @@ static size_t __ksize(const void *object)
 
        return slab_ksize(page->slab_cache);
 }
-
-size_t ksize(const void *object)
-{
-       size_t size = __ksize(object);
-       /* We assume that ksize callers could use whole allocated area,
-        * so we need to unpoison this area.
-        */
-       kasan_unpoison_shadow(object, size);
-       return size;
-}
-EXPORT_SYMBOL(ksize);
+EXPORT_SYMBOL(__ksize);
 
 void kfree(const void *x)
 {
@@ -4024,7 +4028,7 @@ int __kmem_cache_shrink(struct kmem_cache *s)
 }
 
 #ifdef CONFIG_MEMCG
-static void kmemcg_cache_deact_after_rcu(struct kmem_cache *s)
+void __kmemcg_cache_deactivate_after_rcu(struct kmem_cache *s)
 {
        /*
         * Called with all the locks held after a sched RCU grace period.
@@ -4050,12 +4054,6 @@ void __kmemcg_cache_deactivate(struct kmem_cache *s)
         */
        slub_set_cpu_partial(s, 0);
        s->min_partial = 0;
-
-       /*
-        * s->cpu_partial is checked locklessly (see put_cpu_partial), so
-        * we have to make sure the change is visible before shrinking.
-        */
-       slab_deactivate_memcg_cache_rcu_sched(s, kmemcg_cache_deact_after_rcu);
 }
 #endif /* CONFIG_MEMCG */
 
@@ -4215,7 +4213,7 @@ static struct kmem_cache * __init bootstrap(struct kmem_cache *static_cache)
        }
        slab_init_memcg_params(s);
        list_add(&s->list, &slab_caches);
-       memcg_link_cache(s);
+       memcg_link_cache(s, NULL);
        return s;
 }
 
index 85245fd..8368621 100644 (file)
@@ -73,23 +73,24 @@ unsigned long total_swapcache_pages(void)
        unsigned int i, j, nr;
        unsigned long ret = 0;
        struct address_space *spaces;
+       struct swap_info_struct *si;
 
-       rcu_read_lock();
        for (i = 0; i < MAX_SWAPFILES; i++) {
-               /*
-                * The corresponding entries in nr_swapper_spaces and
-                * swapper_spaces will be reused only after at least
-                * one grace period.  So it is impossible for them
-                * belongs to different usage.
-                */
-               nr = nr_swapper_spaces[i];
-               spaces = rcu_dereference(swapper_spaces[i]);
-               if (!nr || !spaces)
+               swp_entry_t entry = swp_entry(i, 1);
+
+               /* Avoid get_swap_device() to warn for bad swap entry */
+               if (!swp_swap_info(entry))
+                       continue;
+               /* Prevent swapoff to free swapper_spaces */
+               si = get_swap_device(entry);
+               if (!si)
                        continue;
+               nr = nr_swapper_spaces[i];
+               spaces = swapper_spaces[i];
                for (j = 0; j < nr; j++)
                        ret += spaces[j].nrpages;
+               put_swap_device(si);
        }
-       rcu_read_unlock();
        return ret;
 }
 
@@ -310,8 +311,13 @@ struct page *lookup_swap_cache(swp_entry_t entry, struct vm_area_struct *vma,
                               unsigned long addr)
 {
        struct page *page;
+       struct swap_info_struct *si;
 
+       si = get_swap_device(entry);
+       if (!si)
+               return NULL;
        page = find_get_page(swap_address_space(entry), swp_offset(entry));
+       put_swap_device(si);
 
        INC_CACHE_INFO(find_total);
        if (page) {
@@ -354,8 +360,8 @@ struct page *__read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
                        struct vm_area_struct *vma, unsigned long addr,
                        bool *new_page_allocated)
 {
-       struct page *found_page, *new_page = NULL;
-       struct address_space *swapper_space = swap_address_space(entry);
+       struct page *found_page = NULL, *new_page = NULL;
+       struct swap_info_struct *si;
        int err;
        *new_page_allocated = false;
 
@@ -365,7 +371,12 @@ struct page *__read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
                 * called after lookup_swap_cache() failed, re-calling
                 * that would confuse statistics.
                 */
-               found_page = find_get_page(swapper_space, swp_offset(entry));
+               si = get_swap_device(entry);
+               if (!si)
+                       break;
+               found_page = find_get_page(swap_address_space(entry),
+                                          swp_offset(entry));
+               put_swap_device(si);
                if (found_page)
                        break;
 
@@ -601,20 +612,16 @@ int init_swap_address_space(unsigned int type, unsigned long nr_pages)
                mapping_set_no_writeback_tags(space);
        }
        nr_swapper_spaces[type] = nr;
-       rcu_assign_pointer(swapper_spaces[type], spaces);
+       swapper_spaces[type] = spaces;
 
        return 0;
 }
 
 void exit_swap_address_space(unsigned int type)
 {
-       struct address_space *spaces;
-
-       spaces = swapper_spaces[type];
+       kvfree(swapper_spaces[type]);
        nr_swapper_spaces[type] = 0;
-       rcu_assign_pointer(swapper_spaces[type], NULL);
-       synchronize_rcu();
-       kvfree(spaces);
+       swapper_spaces[type] = NULL;
 }
 
 static inline void swap_ra_clamp_pfn(struct vm_area_struct *vma,
index 596ac98..0789a76 100644 (file)
@@ -152,6 +152,18 @@ static int __try_to_reclaim_swap(struct swap_info_struct *si,
        return ret;
 }
 
+static inline struct swap_extent *first_se(struct swap_info_struct *sis)
+{
+       struct rb_node *rb = rb_first(&sis->swap_extent_root);
+       return rb_entry(rb, struct swap_extent, rb_node);
+}
+
+static inline struct swap_extent *next_se(struct swap_extent *se)
+{
+       struct rb_node *rb = rb_next(&se->rb_node);
+       return rb ? rb_entry(rb, struct swap_extent, rb_node) : NULL;
+}
+
 /*
  * swapon tell device that all the old swap contents can be discarded,
  * to allow the swap device to optimize its wear-levelling.
@@ -164,7 +176,7 @@ static int discard_swap(struct swap_info_struct *si)
        int err = 0;
 
        /* Do not discard the swap header page! */
-       se = &si->first_swap_extent;
+       se = first_se(si);
        start_block = (se->start_block + 1) << (PAGE_SHIFT - 9);
        nr_blocks = ((sector_t)se->nr_pages - 1) << (PAGE_SHIFT - 9);
        if (nr_blocks) {
@@ -175,7 +187,7 @@ static int discard_swap(struct swap_info_struct *si)
                cond_resched();
        }
 
-       list_for_each_entry(se, &si->first_swap_extent.list, list) {
+       for (se = next_se(se); se; se = next_se(se)) {
                start_block = se->start_block << (PAGE_SHIFT - 9);
                nr_blocks = (sector_t)se->nr_pages << (PAGE_SHIFT - 9);
 
@@ -189,6 +201,26 @@ static int discard_swap(struct swap_info_struct *si)
        return err;             /* That will often be -EOPNOTSUPP */
 }
 
+static struct swap_extent *
+offset_to_swap_extent(struct swap_info_struct *sis, unsigned long offset)
+{
+       struct swap_extent *se;
+       struct rb_node *rb;
+
+       rb = sis->swap_extent_root.rb_node;
+       while (rb) {
+               se = rb_entry(rb, struct swap_extent, rb_node);
+               if (offset < se->start_page)
+                       rb = rb->rb_left;
+               else if (offset >= se->start_page + se->nr_pages)
+                       rb = rb->rb_right;
+               else
+                       return se;
+       }
+       /* It *must* be present */
+       BUG();
+}
+
 /*
  * swap allocation tell device that a cluster of swap can now be discarded,
  * to allow the swap device to optimize its wear-levelling.
@@ -196,32 +228,25 @@ static int discard_swap(struct swap_info_struct *si)
 static void discard_swap_cluster(struct swap_info_struct *si,
                                 pgoff_t start_page, pgoff_t nr_pages)
 {
-       struct swap_extent *se = si->curr_swap_extent;
-       int found_extent = 0;
+       struct swap_extent *se = offset_to_swap_extent(si, start_page);
 
        while (nr_pages) {
-               if (se->start_page <= start_page &&
-                   start_page < se->start_page + se->nr_pages) {
-                       pgoff_t offset = start_page - se->start_page;
-                       sector_t start_block = se->start_block + offset;
-                       sector_t nr_blocks = se->nr_pages - offset;
-
-                       if (nr_blocks > nr_pages)
-                               nr_blocks = nr_pages;
-                       start_page += nr_blocks;
-                       nr_pages -= nr_blocks;
-
-                       if (!found_extent++)
-                               si->curr_swap_extent = se;
-
-                       start_block <<= PAGE_SHIFT - 9;
-                       nr_blocks <<= PAGE_SHIFT - 9;
-                       if (blkdev_issue_discard(si->bdev, start_block,
-                                   nr_blocks, GFP_NOIO, 0))
-                               break;
-               }
+               pgoff_t offset = start_page - se->start_page;
+               sector_t start_block = se->start_block + offset;
+               sector_t nr_blocks = se->nr_pages - offset;
+
+               if (nr_blocks > nr_pages)
+                       nr_blocks = nr_pages;
+               start_page += nr_blocks;
+               nr_pages -= nr_blocks;
+
+               start_block <<= PAGE_SHIFT - 9;
+               nr_blocks <<= PAGE_SHIFT - 9;
+               if (blkdev_issue_discard(si->bdev, start_block,
+                                       nr_blocks, GFP_NOIO, 0))
+                       break;
 
-               se = list_next_entry(se, list);
+               se = next_se(se);
        }
 }
 
@@ -1079,12 +1104,11 @@ fail:
 static struct swap_info_struct *__swap_info_get(swp_entry_t entry)
 {
        struct swap_info_struct *p;
-       unsigned long offset, type;
+       unsigned long offset;
 
        if (!entry.val)
                goto out;
-       type = swp_type(entry);
-       p = swap_type_to_swap_info(type);
+       p = swp_swap_info(entry);
        if (!p)
                goto bad_nofile;
        if (!(p->flags & SWP_USED))
@@ -1187,6 +1211,69 @@ static unsigned char __swap_entry_free_locked(struct swap_info_struct *p,
        return usage;
 }
 
+/*
+ * Check whether swap entry is valid in the swap device.  If so,
+ * return pointer to swap_info_struct, and keep the swap entry valid
+ * via preventing the swap device from being swapoff, until
+ * put_swap_device() is called.  Otherwise return NULL.
+ *
+ * The entirety of the RCU read critical section must come before the
+ * return from or after the call to synchronize_rcu() in
+ * enable_swap_info() or swapoff().  So if "si->flags & SWP_VALID" is
+ * true, the si->map, si->cluster_info, etc. must be valid in the
+ * critical section.
+ *
+ * Notice that swapoff or swapoff+swapon can still happen before the
+ * rcu_read_lock() in get_swap_device() or after the rcu_read_unlock()
+ * in put_swap_device() if there isn't any other way to prevent
+ * swapoff, such as page lock, page table lock, etc.  The caller must
+ * be prepared for that.  For example, the following situation is
+ * possible.
+ *
+ *   CPU1                              CPU2
+ *   do_swap_page()
+ *     ...                             swapoff+swapon
+ *     __read_swap_cache_async()
+ *       swapcache_prepare()
+ *         __swap_duplicate()
+ *           // check swap_map
+ *     // verify PTE not changed
+ *
+ * In __swap_duplicate(), the swap_map need to be checked before
+ * changing partly because the specified swap entry may be for another
+ * swap device which has been swapoff.  And in do_swap_page(), after
+ * the page is read from the swap device, the PTE is verified not
+ * changed with the page table locked to check whether the swap device
+ * has been swapoff or swapoff+swapon.
+ */
+struct swap_info_struct *get_swap_device(swp_entry_t entry)
+{
+       struct swap_info_struct *si;
+       unsigned long offset;
+
+       if (!entry.val)
+               goto out;
+       si = swp_swap_info(entry);
+       if (!si)
+               goto bad_nofile;
+
+       rcu_read_lock();
+       if (!(si->flags & SWP_VALID))
+               goto unlock_out;
+       offset = swp_offset(entry);
+       if (offset >= si->max)
+               goto unlock_out;
+
+       return si;
+bad_nofile:
+       pr_err("%s: %s%08lx\n", __func__, Bad_file, entry.val);
+out:
+       return NULL;
+unlock_out:
+       rcu_read_unlock();
+       return NULL;
+}
+
 static unsigned char __swap_entry_free(struct swap_info_struct *p,
                                       swp_entry_t entry, unsigned char usage)
 {
@@ -1358,11 +1445,18 @@ int page_swapcount(struct page *page)
        return count;
 }
 
-int __swap_count(struct swap_info_struct *si, swp_entry_t entry)
+int __swap_count(swp_entry_t entry)
 {
+       struct swap_info_struct *si;
        pgoff_t offset = swp_offset(entry);
+       int count = 0;
 
-       return swap_count(si->swap_map[offset]);
+       si = get_swap_device(entry);
+       if (si) {
+               count = swap_count(si->swap_map[offset]);
+               put_swap_device(si);
+       }
+       return count;
 }
 
 static int swap_swapcount(struct swap_info_struct *si, swp_entry_t entry)
@@ -1387,9 +1481,11 @@ int __swp_swapcount(swp_entry_t entry)
        int count = 0;
        struct swap_info_struct *si;
 
-       si = __swap_info_get(entry);
-       if (si)
+       si = get_swap_device(entry);
+       if (si) {
                count = swap_swapcount(si, entry);
+               put_swap_device(si);
+       }
        return count;
 }
 
@@ -1684,7 +1780,7 @@ int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p)
                        return type;
                }
                if (bdev == sis->bdev) {
-                       struct swap_extent *se = &sis->first_swap_extent;
+                       struct swap_extent *se = first_se(sis);
 
                        if (se->start_block == offset) {
                                if (bdev_p)
@@ -2161,7 +2257,6 @@ static void drain_mmlist(void)
 static sector_t map_swap_entry(swp_entry_t entry, struct block_device **bdev)
 {
        struct swap_info_struct *sis;
-       struct swap_extent *start_se;
        struct swap_extent *se;
        pgoff_t offset;
 
@@ -2169,18 +2264,8 @@ static sector_t map_swap_entry(swp_entry_t entry, struct block_device **bdev)
        *bdev = sis->bdev;
 
        offset = swp_offset(entry);
-       start_se = sis->curr_swap_extent;
-       se = start_se;
-
-       for ( ; ; ) {
-               if (se->start_page <= offset &&
-                               offset < (se->start_page + se->nr_pages)) {
-                       return se->start_block + (offset - se->start_page);
-               }
-               se = list_next_entry(se, list);
-               sis->curr_swap_extent = se;
-               BUG_ON(se == start_se);         /* It *must* be present */
-       }
+       se = offset_to_swap_extent(sis, offset);
+       return se->start_block + (offset - se->start_page);
 }
 
 /*
@@ -2198,12 +2283,11 @@ sector_t map_swap_page(struct page *page, struct block_device **bdev)
  */
 static void destroy_swap_extents(struct swap_info_struct *sis)
 {
-       while (!list_empty(&sis->first_swap_extent.list)) {
-               struct swap_extent *se;
+       while (!RB_EMPTY_ROOT(&sis->swap_extent_root)) {
+               struct rb_node *rb = sis->swap_extent_root.rb_node;
+               struct swap_extent *se = rb_entry(rb, struct swap_extent, rb_node);
 
-               se = list_first_entry(&sis->first_swap_extent.list,
-                               struct swap_extent, list);
-               list_del(&se->list);
+               rb_erase(rb, &sis->swap_extent_root);
                kfree(se);
        }
 
@@ -2219,7 +2303,7 @@ static void destroy_swap_extents(struct swap_info_struct *sis)
 
 /*
  * Add a block range (and the corresponding page range) into this swapdev's
- * extent list.  The extent list is kept sorted in page order.
+ * extent tree.
  *
  * This function rather assumes that it is called in ascending page order.
  */
@@ -2227,20 +2311,21 @@ int
 add_swap_extent(struct swap_info_struct *sis, unsigned long start_page,
                unsigned long nr_pages, sector_t start_block)
 {
+       struct rb_node **link = &sis->swap_extent_root.rb_node, *parent = NULL;
        struct swap_extent *se;
        struct swap_extent *new_se;
-       struct list_head *lh;
-
-       if (start_page == 0) {
-               se = &sis->first_swap_extent;
-               sis->curr_swap_extent = se;
-               se->start_page = 0;
-               se->nr_pages = nr_pages;
-               se->start_block = start_block;
-               return 1;
-       } else {
-               lh = sis->first_swap_extent.list.prev;  /* Highest extent */
-               se = list_entry(lh, struct swap_extent, list);
+
+       /*
+        * place the new node at the right most since the
+        * function is called in ascending page order.
+        */
+       while (*link) {
+               parent = *link;
+               link = &parent->rb_right;
+       }
+
+       if (parent) {
+               se = rb_entry(parent, struct swap_extent, rb_node);
                BUG_ON(se->start_page + se->nr_pages != start_page);
                if (se->start_block + se->nr_pages == start_block) {
                        /* Merge it */
@@ -2249,9 +2334,7 @@ add_swap_extent(struct swap_info_struct *sis, unsigned long start_page,
                }
        }
 
-       /*
-        * No merge.  Insert a new extent, preserving ordering.
-        */
+       /* No merge, insert a new extent. */
        new_se = kmalloc(sizeof(*se), GFP_KERNEL);
        if (new_se == NULL)
                return -ENOMEM;
@@ -2259,7 +2342,8 @@ add_swap_extent(struct swap_info_struct *sis, unsigned long start_page,
        new_se->nr_pages = nr_pages;
        new_se->start_block = start_block;
 
-       list_add_tail(&new_se->list, &sis->first_swap_extent.list);
+       rb_link_node(&new_se->rb_node, parent, link);
+       rb_insert_color(&new_se->rb_node, &sis->swap_extent_root);
        return 1;
 }
 EXPORT_SYMBOL_GPL(add_swap_extent);
@@ -2335,9 +2419,9 @@ static int swap_node(struct swap_info_struct *p)
        return bdev ? bdev->bd_disk->node_id : NUMA_NO_NODE;
 }
 
-static void _enable_swap_info(struct swap_info_struct *p, int prio,
-                               unsigned char *swap_map,
-                               struct swap_cluster_info *cluster_info)
+static void setup_swap_info(struct swap_info_struct *p, int prio,
+                           unsigned char *swap_map,
+                           struct swap_cluster_info *cluster_info)
 {
        int i;
 
@@ -2362,7 +2446,11 @@ static void _enable_swap_info(struct swap_info_struct *p, int prio,
        }
        p->swap_map = swap_map;
        p->cluster_info = cluster_info;
-       p->flags |= SWP_WRITEOK;
+}
+
+static void _enable_swap_info(struct swap_info_struct *p)
+{
+       p->flags |= SWP_WRITEOK | SWP_VALID;
        atomic_long_add(p->pages, &nr_swap_pages);
        total_swap_pages += p->pages;
 
@@ -2389,7 +2477,17 @@ static void enable_swap_info(struct swap_info_struct *p, int prio,
        frontswap_init(p->type, frontswap_map);
        spin_lock(&swap_lock);
        spin_lock(&p->lock);
-        _enable_swap_info(p, prio, swap_map, cluster_info);
+       setup_swap_info(p, prio, swap_map, cluster_info);
+       spin_unlock(&p->lock);
+       spin_unlock(&swap_lock);
+       /*
+        * Guarantee swap_map, cluster_info, etc. fields are valid
+        * between get/put_swap_device() if SWP_VALID bit is set
+        */
+       synchronize_rcu();
+       spin_lock(&swap_lock);
+       spin_lock(&p->lock);
+       _enable_swap_info(p);
        spin_unlock(&p->lock);
        spin_unlock(&swap_lock);
 }
@@ -2398,7 +2496,8 @@ static void reinsert_swap_info(struct swap_info_struct *p)
 {
        spin_lock(&swap_lock);
        spin_lock(&p->lock);
-       _enable_swap_info(p, p->prio, p->swap_map, p->cluster_info);
+       setup_swap_info(p, p->prio, p->swap_map, p->cluster_info);
+       _enable_swap_info(p);
        spin_unlock(&p->lock);
        spin_unlock(&swap_lock);
 }
@@ -2501,6 +2600,17 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
 
        reenable_swap_slots_cache_unlock();
 
+       spin_lock(&swap_lock);
+       spin_lock(&p->lock);
+       p->flags &= ~SWP_VALID;         /* mark swap device as invalid */
+       spin_unlock(&p->lock);
+       spin_unlock(&swap_lock);
+       /*
+        * wait for swap operations protected by get/put_swap_device()
+        * to complete
+        */
+       synchronize_rcu();
+
        flush_work(&p->discard_work);
 
        destroy_swap_extents(p);
@@ -2749,7 +2859,7 @@ static struct swap_info_struct *alloc_swap_info(void)
                 * would be relying on p->type to remain valid.
                 */
        }
-       INIT_LIST_HEAD(&p->first_swap_extent.list);
+       p->swap_extent_root = RB_ROOT;
        plist_node_init(&p->list, 0);
        for_each_node(i)
                plist_node_init(&p->avail_lists[i], 0);
@@ -3265,17 +3375,11 @@ static int __swap_duplicate(swp_entry_t entry, unsigned char usage)
        unsigned char has_cache;
        int err = -EINVAL;
 
-       if (non_swap_entry(entry))
-               goto out;
-
-       p = swp_swap_info(entry);
+       p = get_swap_device(entry);
        if (!p)
-               goto bad_file;
-
-       offset = swp_offset(entry);
-       if (unlikely(offset >= p->max))
                goto out;
 
+       offset = swp_offset(entry);
        ci = lock_cluster_or_swap_info(p, offset);
 
        count = p->swap_map[offset];
@@ -3321,11 +3425,9 @@ static int __swap_duplicate(swp_entry_t entry, unsigned char usage)
 unlock_out:
        unlock_cluster_or_swap_info(p, ci);
 out:
+       if (p)
+               put_swap_device(p);
        return err;
-
-bad_file:
-       pr_err("swap_dup: %s%08lx\n", Bad_file, entry.val);
-       goto out;
 }
 
 /*
@@ -3417,6 +3519,7 @@ int add_swap_count_continuation(swp_entry_t entry, gfp_t gfp_mask)
        struct page *list_page;
        pgoff_t offset;
        unsigned char count;
+       int ret = 0;
 
        /*
         * When debugging, it's easier to use __GFP_ZERO here; but it's better
@@ -3424,15 +3527,15 @@ int add_swap_count_continuation(swp_entry_t entry, gfp_t gfp_mask)
         */
        page = alloc_page(gfp_mask | __GFP_HIGHMEM);
 
-       si = swap_info_get(entry);
+       si = get_swap_device(entry);
        if (!si) {
                /*
                 * An acceptable race has occurred since the failing
-                * __swap_duplicate(): the swap entry has been freed,
-                * perhaps even the whole swap_map cleared for swapoff.
+                * __swap_duplicate(): the swap device may be swapoff
                 */
                goto outer;
        }
+       spin_lock(&si->lock);
 
        offset = swp_offset(entry);
 
@@ -3450,9 +3553,8 @@ int add_swap_count_continuation(swp_entry_t entry, gfp_t gfp_mask)
        }
 
        if (!page) {
-               unlock_cluster(ci);
-               spin_unlock(&si->lock);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out;
        }
 
        /*
@@ -3504,10 +3606,11 @@ out_unlock_cont:
 out:
        unlock_cluster(ci);
        spin_unlock(&si->lock);
+       put_swap_device(si);
 outer:
        if (page)
                __free_page(page);
-       return 0;
+       return ret;
 }
 
 /*
index 9834c4a..68575a3 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -300,53 +300,6 @@ void arch_pick_mmap_layout(struct mm_struct *mm, struct rlimit *rlim_stack)
 }
 #endif
 
-/*
- * Like get_user_pages_fast() except its IRQ-safe in that it won't fall
- * back to the regular GUP.
- * Note a difference with get_user_pages_fast: this always returns the
- * number of pages pinned, 0 if no pages were pinned.
- * If the architecture does not support this function, simply return with no
- * pages pinned.
- */
-int __weak __get_user_pages_fast(unsigned long start,
-                                int nr_pages, int write, struct page **pages)
-{
-       return 0;
-}
-EXPORT_SYMBOL_GPL(__get_user_pages_fast);
-
-/**
- * get_user_pages_fast() - pin user pages in memory
- * @start:     starting user address
- * @nr_pages:  number of pages from start to pin
- * @gup_flags: flags modifying pin behaviour
- * @pages:     array that receives pointers to the pages pinned.
- *             Should be at least nr_pages long.
- *
- * get_user_pages_fast provides equivalent functionality to get_user_pages,
- * operating on current and current->mm, with force=0 and vma=NULL. However
- * unlike get_user_pages, it must be called without mmap_sem held.
- *
- * get_user_pages_fast may take mmap_sem and page table locks, so no
- * assumptions can be made about lack of locking. get_user_pages_fast is to be
- * implemented in a way that is advantageous (vs get_user_pages()) when the
- * user memory area is already faulted in and present in ptes. However if the
- * pages have to be faulted in, it may turn out to be slightly slower so
- * callers need to carefully consider what to use. On many architectures,
- * get_user_pages_fast simply falls back to get_user_pages.
- *
- * Return: number of pages pinned. This may be fewer than the number
- * requested. If nr_pages is 0 or negative, returns 0. If no pages
- * were pinned, returns -errno.
- */
-int __weak get_user_pages_fast(unsigned long start,
-                               int nr_pages, unsigned int gup_flags,
-                               struct page **pages)
-{
-       return get_user_pages_unlocked(start, nr_pages, pages, gup_flags);
-}
-EXPORT_SYMBOL_GPL(get_user_pages_fast);
-
 unsigned long vm_mmap_pgoff(struct file *file, unsigned long addr,
        unsigned long len, unsigned long prot,
        unsigned long flag, unsigned long pgoff)
index 030a544..4fa8d84 100644 (file)
@@ -365,6 +365,13 @@ static LIST_HEAD(free_vmap_area_list);
  */
 static struct rb_root free_vmap_area_root = RB_ROOT;
 
+/*
+ * Preload a CPU with one object for "no edge" split case. The
+ * aim is to get rid of allocations from the atomic context, thus
+ * to use more permissive allocation masks.
+ */
+static DEFINE_PER_CPU(struct vmap_area *, ne_fit_preload_node);
+
 static __always_inline unsigned long
 va_size(struct vmap_area *va)
 {
@@ -399,6 +406,13 @@ static void purge_vmap_area_lazy(void);
 static BLOCKING_NOTIFIER_HEAD(vmap_notify_list);
 static unsigned long lazy_max_pages(void);
 
+static atomic_long_t nr_vmalloc_pages;
+
+unsigned long vmalloc_nr_pages(void)
+{
+       return atomic_long_read(&nr_vmalloc_pages);
+}
+
 static struct vmap_area *__find_vmap_area(unsigned long addr)
 {
        struct rb_node *n = vmap_area_root.rb_node;
@@ -527,20 +541,17 @@ link_va(struct vmap_area *va, struct rb_root *root,
 static __always_inline void
 unlink_va(struct vmap_area *va, struct rb_root *root)
 {
-       /*
-        * During merging a VA node can be empty, therefore
-        * not linked with the tree nor list. Just check it.
-        */
-       if (!RB_EMPTY_NODE(&va->rb_node)) {
-               if (root == &free_vmap_area_root)
-                       rb_erase_augmented(&va->rb_node,
-                               root, &free_vmap_area_rb_augment_cb);
-               else
-                       rb_erase(&va->rb_node, root);
+       if (WARN_ON(RB_EMPTY_NODE(&va->rb_node)))
+               return;
 
-               list_del(&va->list);
-               RB_CLEAR_NODE(&va->rb_node);
-       }
+       if (root == &free_vmap_area_root)
+               rb_erase_augmented(&va->rb_node,
+                       root, &free_vmap_area_rb_augment_cb);
+       else
+               rb_erase(&va->rb_node, root);
+
+       list_del(&va->list);
+       RB_CLEAR_NODE(&va->rb_node);
 }
 
 #if DEBUG_AUGMENT_PROPAGATE_CHECK
@@ -712,9 +723,6 @@ merge_or_add_vmap_area(struct vmap_area *va,
                        /* Check and update the tree if needed. */
                        augment_tree_propagate_from(sibling);
 
-                       /* Remove this VA, it has been merged. */
-                       unlink_va(va, root);
-
                        /* Free vmap_area object. */
                        kmem_cache_free(vmap_area_cachep, va);
 
@@ -739,12 +747,11 @@ merge_or_add_vmap_area(struct vmap_area *va,
                        /* Check and update the tree if needed. */
                        augment_tree_propagate_from(sibling);
 
-                       /* Remove this VA, it has been merged. */
-                       unlink_va(va, root);
+                       if (merged)
+                               unlink_va(va, root);
 
                        /* Free vmap_area object. */
                        kmem_cache_free(vmap_area_cachep, va);
-
                        return;
                }
        }
@@ -951,9 +958,24 @@ adjust_va_to_fit_type(struct vmap_area *va,
                 *   L V  NVA  V R
                 * |---|-------|---|
                 */
-               lva = kmem_cache_alloc(vmap_area_cachep, GFP_NOWAIT);
-               if (unlikely(!lva))
-                       return -1;
+               lva = __this_cpu_xchg(ne_fit_preload_node, NULL);
+               if (unlikely(!lva)) {
+                       /*
+                        * For percpu allocator we do not do any pre-allocation
+                        * and leave it as it is. The reason is it most likely
+                        * never ends up with NE_FIT_TYPE splitting. In case of
+                        * percpu allocations offsets and sizes are aligned to
+                        * fixed align request, i.e. RE_FIT_TYPE and FL_FIT_TYPE
+                        * are its main fitting cases.
+                        *
+                        * There are a few exceptions though, as an example it is
+                        * a first allocation (early boot up) when we have "one"
+                        * big free space that has to be split.
+                        */
+                       lva = kmem_cache_alloc(vmap_area_cachep, GFP_NOWAIT);
+                       if (!lva)
+                               return -1;
+               }
 
                /*
                 * Build the remainder.
@@ -986,7 +1008,7 @@ adjust_va_to_fit_type(struct vmap_area *va,
  */
 static __always_inline unsigned long
 __alloc_vmap_area(unsigned long size, unsigned long align,
-       unsigned long vstart, unsigned long vend, int node)
+       unsigned long vstart, unsigned long vend)
 {
        unsigned long nva_start_addr;
        struct vmap_area *va;
@@ -1032,7 +1054,7 @@ static struct vmap_area *alloc_vmap_area(unsigned long size,
                                unsigned long vstart, unsigned long vend,
                                int node, gfp_t gfp_mask)
 {
-       struct vmap_area *va;
+       struct vmap_area *va, *pva;
        unsigned long addr;
        int purged = 0;
 
@@ -1057,13 +1079,38 @@ static struct vmap_area *alloc_vmap_area(unsigned long size,
        kmemleak_scan_area(&va->rb_node, SIZE_MAX, gfp_mask & GFP_RECLAIM_MASK);
 
 retry:
+       /*
+        * Preload this CPU with one extra vmap_area object to ensure
+        * that we have it available when fit type of free area is
+        * NE_FIT_TYPE.
+        *
+        * The preload is done in non-atomic context, thus it allows us
+        * to use more permissive allocation masks to be more stable under
+        * low memory condition and high memory pressure.
+        *
+        * Even if it fails we do not really care about that. Just proceed
+        * as it is. "overflow" path will refill the cache we allocate from.
+        */
+       preempt_disable();
+       if (!__this_cpu_read(ne_fit_preload_node)) {
+               preempt_enable();
+               pva = kmem_cache_alloc_node(vmap_area_cachep, GFP_KERNEL, node);
+               preempt_disable();
+
+               if (__this_cpu_cmpxchg(ne_fit_preload_node, NULL, pva)) {
+                       if (pva)
+                               kmem_cache_free(vmap_area_cachep, pva);
+               }
+       }
+
        spin_lock(&vmap_area_lock);
+       preempt_enable();
 
        /*
         * If an allocation fails, the "vend" address is
         * returned. Therefore trigger the overflow path.
         */
-       addr = __alloc_vmap_area(size, align, vstart, vend, node);
+       addr = __alloc_vmap_area(size, align, vstart, vend);
        if (unlikely(addr == vend))
                goto overflow;
 
@@ -1119,8 +1166,6 @@ EXPORT_SYMBOL_GPL(unregister_vmap_purge_notifier);
 
 static void __free_vmap_area(struct vmap_area *va)
 {
-       BUG_ON(RB_EMPTY_NODE(&va->rb_node));
-
        /*
         * Remove from the busy tree/list.
         */
@@ -2199,6 +2244,7 @@ static void __vunmap(const void *addr, int deallocate_pages)
                        BUG_ON(!page);
                        __free_pages(page, 0);
                }
+               atomic_long_sub(area->nr_pages, &nr_vmalloc_pages);
 
                kvfree(area->pages);
        }
@@ -2376,12 +2422,14 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
                if (unlikely(!page)) {
                        /* Successfully allocated i pages, free them in __vunmap() */
                        area->nr_pages = i;
+                       atomic_long_add(area->nr_pages, &nr_vmalloc_pages);
                        goto fail;
                }
                area->pages[i] = page;
                if (gfpflags_allow_blocking(gfp_mask|highmem_mask))
                        cond_resched();
        }
+       atomic_long_add(area->nr_pages, &nr_vmalloc_pages);
 
        if (map_vm_area(area, prot, pages))
                goto fail;
@@ -2774,7 +2822,7 @@ static int aligned_vwrite(char *buf, char *addr, unsigned long count)
  * Note: In usual ops, vread() is never necessary because the caller
  * should know vmalloc() area is valid and can use memcpy().
  * This is for routines which have to access vmalloc area without
- * any informaion, as /dev/kmem.
+ * any information, as /dev/kmem.
  *
  * Return: number of bytes for which addr and buf should be increased
  * (same number as @count) or %0 if [addr...addr+count) doesn't
@@ -2853,7 +2901,7 @@ finished:
  * Note: In usual ops, vwrite() is never necessary because the caller
  * should know vmalloc() area is valid and can use memcpy().
  * This is for routines which have to access vmalloc area without
- * any informaion, as /dev/kmem.
+ * any information, as /dev/kmem.
  *
  * Return: number of bytes for which addr and buf should be
  * increased (same number as @count) or %0 if [addr...addr+count)
@@ -2996,7 +3044,7 @@ void __weak vmalloc_sync_all(void)
 }
 
 
-static int f(pte_t *pte, pgtable_t table, unsigned long addr, void *data)
+static int f(pte_t *pte, unsigned long addr, void *data)
 {
        pte_t ***p = data;
 
index 910e02c..f8e3dcd 100644 (file)
@@ -1118,6 +1118,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                int may_enter_fs;
                enum page_references references = PAGEREF_RECLAIM_CLEAN;
                bool dirty, writeback;
+               unsigned int nr_pages;
 
                cond_resched();
 
@@ -1129,7 +1130,10 @@ static unsigned long shrink_page_list(struct list_head *page_list,
 
                VM_BUG_ON_PAGE(PageActive(page), page);
 
-               sc->nr_scanned++;
+               nr_pages = 1 << compound_order(page);
+
+               /* Account the number of base pages even though THP */
+               sc->nr_scanned += nr_pages;
 
                if (unlikely(!page_evictable(page)))
                        goto activate_locked;
@@ -1137,11 +1141,6 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                if (!sc->may_unmap && page_mapped(page))
                        goto keep_locked;
 
-               /* Double the slab pressure for mapped and swapcache pages */
-               if ((page_mapped(page) || PageSwapCache(page)) &&
-                   !(PageAnon(page) && !PageSwapBacked(page)))
-                       sc->nr_scanned++;
-
                may_enter_fs = (sc->gfp_mask & __GFP_FS) ||
                        (PageSwapCache(page) && (sc->gfp_mask & __GFP_IO));
 
@@ -1255,7 +1254,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                case PAGEREF_ACTIVATE:
                        goto activate_locked;
                case PAGEREF_KEEP:
-                       stat->nr_ref_keep++;
+                       stat->nr_ref_keep += nr_pages;
                        goto keep_locked;
                case PAGEREF_RECLAIM:
                case PAGEREF_RECLAIM_CLEAN:
@@ -1287,7 +1286,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                                }
                                if (!add_to_swap(page)) {
                                        if (!PageTransHuge(page))
-                                               goto activate_locked;
+                                               goto activate_locked_split;
                                        /* Fallback to swap normal pages */
                                        if (split_huge_page_to_list(page,
                                                                    page_list))
@@ -1296,7 +1295,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                                        count_vm_event(THP_SWPOUT_FALLBACK);
 #endif
                                        if (!add_to_swap(page))
-                                               goto activate_locked;
+                                               goto activate_locked_split;
                                }
 
                                may_enter_fs = 1;
@@ -1310,6 +1309,18 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                                goto keep_locked;
                }
 
+               /*
+                * THP may get split above, need minus tail pages and update
+                * nr_pages to avoid accounting tail pages twice.
+                *
+                * The tail pages that are added into swap cache successfully
+                * reach here.
+                */
+               if ((nr_pages > 1) && !PageTransHuge(page)) {
+                       sc->nr_scanned -= (nr_pages - 1);
+                       nr_pages = 1;
+               }
+
                /*
                 * The page is mapped into the page tables of one or more
                 * processes. Try to unmap it here.
@@ -1320,7 +1331,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                        if (unlikely(PageTransHuge(page)))
                                flags |= TTU_SPLIT_HUGE_PMD;
                        if (!try_to_unmap(page, flags)) {
-                               stat->nr_unmap_fail++;
+                               stat->nr_unmap_fail += nr_pages;
                                goto activate_locked;
                        }
                }
@@ -1447,7 +1458,11 @@ static unsigned long shrink_page_list(struct list_head *page_list,
 
                unlock_page(page);
 free_it:
-               nr_reclaimed++;
+               /*
+                * THP may get swapped out in a whole, need account
+                * all base pages.
+                */
+               nr_reclaimed += nr_pages;
 
                /*
                 * Is there need to periodically free_page_list? It would
@@ -1460,6 +1475,15 @@ free_it:
                        list_add(&page->lru, &free_pages);
                continue;
 
+activate_locked_split:
+               /*
+                * The tail pages that are failed to add into swap cache
+                * reach here.  Fixup nr_scanned and nr_pages.
+                */
+               if (nr_pages > 1) {
+                       sc->nr_scanned -= (nr_pages - 1);
+                       nr_pages = 1;
+               }
 activate_locked:
                /* Not a candidate for swapping, so reclaim swap space. */
                if (PageSwapCache(page) && (mem_cgroup_swap_full(page) ||
@@ -1469,8 +1493,7 @@ activate_locked:
                if (!PageMlocked(page)) {
                        int type = page_is_file_cache(page);
                        SetPageActive(page);
-                       pgactivate++;
-                       stat->nr_activate[type] += hpage_nr_pages(page);
+                       stat->nr_activate[type] += nr_pages;
                        count_memcg_page_event(page, PGACTIVATE);
                }
 keep_locked:
@@ -1480,6 +1503,8 @@ keep:
                VM_BUG_ON_PAGE(PageLRU(page) || PageUnevictable(page), page);
        }
 
+       pgactivate = stat->nr_activate[0] + stat->nr_activate[1];
+
        mem_cgroup_uncharge_list(&free_pages);
        try_to_unmap_flush();
        free_unref_page_list(&free_pages);
@@ -1651,10 +1676,9 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
        LIST_HEAD(pages_skipped);
        isolate_mode_t mode = (sc->may_unmap ? 0 : ISOLATE_UNMAPPED);
 
+       total_scan = 0;
        scan = 0;
-       for (total_scan = 0;
-            scan < nr_to_scan && nr_taken < nr_to_scan && !list_empty(src);
-            total_scan++) {
+       while (scan < nr_to_scan && !list_empty(src)) {
                struct page *page;
 
                page = lru_to_page(src);
@@ -1662,9 +1686,12 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
 
                VM_BUG_ON_PAGE(!PageLRU(page), page);
 
+               nr_pages = 1 << compound_order(page);
+               total_scan += nr_pages;
+
                if (page_zonenum(page) > sc->reclaim_idx) {
                        list_move(&page->lru, &pages_skipped);
-                       nr_skipped[page_zonenum(page)]++;
+                       nr_skipped[page_zonenum(page)] += nr_pages;
                        continue;
                }
 
@@ -1673,11 +1700,14 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
                 * return with no isolated pages if the LRU mostly contains
                 * ineligible pages.  This causes the VM to not reclaim any
                 * pages, triggering a premature OOM.
+                *
+                * Account all tail pages of THP.  This would not cause
+                * premature OOM since __isolate_lru_page() returns -EBUSY
+                * only when the page is being freed somewhere else.
                 */
-               scan++;
+               scan += nr_pages;
                switch (__isolate_lru_page(page, mode)) {
                case 0:
-                       nr_pages = hpage_nr_pages(page);
                        nr_taken += nr_pages;
                        nr_zone_taken[page_zonenum(page)] += nr_pages;
                        list_move(&page->lru, dst);
@@ -2125,7 +2155,7 @@ static void shrink_active_list(unsigned long nr_to_scan,
  *   10TB     320        32GB
  */
 static bool inactive_list_is_low(struct lruvec *lruvec, bool file,
-                                struct scan_control *sc, bool actual_reclaim)
+                                struct scan_control *sc, bool trace)
 {
        enum lru_list active_lru = file * LRU_FILE + LRU_ACTIVE;
        struct pglist_data *pgdat = lruvec_pgdat(lruvec);
@@ -2151,7 +2181,7 @@ static bool inactive_list_is_low(struct lruvec *lruvec, bool file,
         * rid of the stale workingset quickly.
         */
        refaults = lruvec_page_state_local(lruvec, WORKINGSET_ACTIVATE);
-       if (file && actual_reclaim && lruvec->refaults != refaults) {
+       if (file && lruvec->refaults != refaults) {
                inactive_ratio = 0;
        } else {
                gb = (inactive + active) >> (30 - PAGE_SHIFT);
@@ -2161,7 +2191,7 @@ static bool inactive_list_is_low(struct lruvec *lruvec, bool file,
                        inactive_ratio = 1;
        }
 
-       if (actual_reclaim)
+       if (trace)
                trace_mm_vmscan_inactive_list_is_low(pgdat->node_id, sc->reclaim_idx,
                        lruvec_lru_size(lruvec, inactive_lru, MAX_NR_ZONES), inactive,
                        lruvec_lru_size(lruvec, active_lru, MAX_NR_ZONES), active,
index 985732c..dfcd69d 100644 (file)
@@ -924,7 +924,16 @@ retry:
                set_bit(PAGE_HEADLESS, &page->private);
                goto headless;
        }
-       __SetPageMovable(page, pool->inode->i_mapping);
+       if (can_sleep) {
+               lock_page(page);
+               __SetPageMovable(page, pool->inode->i_mapping);
+               unlock_page(page);
+       } else {
+               if (trylock_page(page)) {
+                       __SetPageMovable(page, pool->inode->i_mapping);
+                       unlock_page(page);
+               }
+       }
        z3fold_page_lock(zhdr);
 
 found:
@@ -1331,6 +1340,7 @@ static int z3fold_page_migrate(struct address_space *mapping, struct page *newpa
 
        VM_BUG_ON_PAGE(!PageMovable(page), page);
        VM_BUG_ON_PAGE(!PageIsolated(page), page);
+       VM_BUG_ON_PAGE(!PageLocked(newpage), newpage);
 
        zhdr = page_address(page);
        pool = zhdr_to_pool(zhdr);
index 0787d33..db09eb3 100644 (file)
@@ -575,8 +575,6 @@ static void __init zs_stat_init(void)
        }
 
        zs_stat_root = debugfs_create_dir("zsmalloc", NULL);
-       if (!zs_stat_root)
-               pr_warn("debugfs 'zsmalloc' stat dir creation failed\n");
 }
 
 static void __exit zs_stat_exit(void)
@@ -647,29 +645,15 @@ DEFINE_SHOW_ATTRIBUTE(zs_stats_size);
 
 static void zs_pool_stat_create(struct zs_pool *pool, const char *name)
 {
-       struct dentry *entry;
-
        if (!zs_stat_root) {
                pr_warn("no root stat dir, not creating <%s> stat dir\n", name);
                return;
        }
 
-       entry = debugfs_create_dir(name, zs_stat_root);
-       if (!entry) {
-               pr_warn("debugfs dir <%s> creation failed\n", name);
-               return;
-       }
-       pool->stat_dentry = entry;
-
-       entry = debugfs_create_file("classes", S_IFREG | 0444,
-                                   pool->stat_dentry, pool,
-                                   &zs_stats_size_fops);
-       if (!entry) {
-               pr_warn("%s: debugfs file entry <%s> creation failed\n",
-                               name, "classes");
-               debugfs_remove_recursive(pool->stat_dentry);
-               pool->stat_dentry = NULL;
-       }
+       pool->stat_dentry = debugfs_create_dir(name, zs_stat_root);
+
+       debugfs_create_file("classes", S_IFREG | 0444, pool->stat_dentry, pool,
+                           &zs_stats_size_fops);
 }
 
 static void zs_pool_stat_destroy(struct zs_pool *pool)
index 2412042..0e22744 100644 (file)
@@ -1253,8 +1253,6 @@ static int __init zswap_debugfs_init(void)
                return -ENODEV;
 
        zswap_debugfs_root = debugfs_create_dir("zswap", NULL);
-       if (!zswap_debugfs_root)
-               return -ENOMEM;
 
        debugfs_create_u64("pool_limit_hit", 0444,
                           zswap_debugfs_root, &zswap_pool_limit_hit);
index 549938a..a3cd90a 100644 (file)
@@ -767,10 +767,16 @@ static struct p9_trans_module p9_virtio_trans = {
 /* The standard init function */
 static int __init p9_virtio_init(void)
 {
+       int rc;
+
        INIT_LIST_HEAD(&virtio_chan_list);
 
        v9fs_register_trans(&p9_virtio_trans);
-       return register_virtio_driver(&p9_virtio_drv);
+       rc = register_virtio_driver(&p9_virtio_drv);
+       if (rc)
+               v9fs_unregister_trans(&p9_virtio_trans);
+
+       return rc;
 }
 
 static void __exit p9_virtio_cleanup(void)
index 29420eb..3963eb1 100644 (file)
@@ -530,13 +530,19 @@ static struct xenbus_driver xen_9pfs_front_driver = {
 
 static int p9_trans_xen_init(void)
 {
+       int rc;
+
        if (!xen_domain())
                return -ENODEV;
 
        pr_info("Initialising Xen transport for 9pfs\n");
 
        v9fs_register_trans(&p9_xen_trans);
-       return xenbus_register_frontend(&xen_9pfs_front_driver);
+       rc = xenbus_register_frontend(&xen_9pfs_front_driver);
+       if (rc)
+               v9fs_unregister_trans(&p9_xen_trans);
+
+       return rc;
 }
 module_init(p9_trans_xen_init);
 
index 91f9d87..fed9290 100644 (file)
@@ -9,7 +9,7 @@ menuconfig BPFILTER
 if BPFILTER
 config BPFILTER_UMH
        tristate "bpfilter kernel module with user mode helper"
-       depends on $(success,$(srctree)/scripts/cc-can-link.sh $(CC))
+       depends on CC_CAN_LINK
        default m
        help
          This builds bpfilter kernel module with embedded user mode helper
index 1c811c7..4eeea4d 100644 (file)
@@ -776,9 +776,7 @@ static int __init init_ceph_lib(void)
 {
        int ret = 0;
 
-       ret = ceph_debugfs_init();
-       if (ret < 0)
-               goto out;
+       ceph_debugfs_init();
 
        ret = ceph_crypto_init();
        if (ret < 0)
@@ -803,7 +801,6 @@ out_crypto:
        ceph_crypto_shutdown();
 out_debugfs:
        ceph_debugfs_cleanup();
-out:
        return ret;
 }
 
index 63aef99..7cb992e 100644 (file)
@@ -389,12 +389,9 @@ CEPH_DEFINE_SHOW_FUNC(monc_show)
 CEPH_DEFINE_SHOW_FUNC(osdc_show)
 CEPH_DEFINE_SHOW_FUNC(client_options_show)
 
-int __init ceph_debugfs_init(void)
+void __init ceph_debugfs_init(void)
 {
        ceph_debugfs_dir = debugfs_create_dir("ceph", NULL);
-       if (!ceph_debugfs_dir)
-               return -ENOMEM;
-       return 0;
 }
 
 void ceph_debugfs_cleanup(void)
@@ -402,9 +399,8 @@ void ceph_debugfs_cleanup(void)
        debugfs_remove(ceph_debugfs_dir);
 }
 
-int ceph_debugfs_client_init(struct ceph_client *client)
+void ceph_debugfs_client_init(struct ceph_client *client)
 {
-       int ret = -ENOMEM;
        char name[80];
 
        snprintf(name, sizeof(name), "%pU.client%lld", &client->fsid,
@@ -412,56 +408,37 @@ int ceph_debugfs_client_init(struct ceph_client *client)
 
        dout("ceph_debugfs_client_init %p %s\n", client, name);
 
-       BUG_ON(client->debugfs_dir);
        client->debugfs_dir = debugfs_create_dir(name, ceph_debugfs_dir);
-       if (!client->debugfs_dir)
-               goto out;
 
        client->monc.debugfs_file = debugfs_create_file("monc",
                                                      0400,
                                                      client->debugfs_dir,
                                                      client,
                                                      &monc_show_fops);
-       if (!client->monc.debugfs_file)
-               goto out;
 
        client->osdc.debugfs_file = debugfs_create_file("osdc",
                                                      0400,
                                                      client->debugfs_dir,
                                                      client,
                                                      &osdc_show_fops);
-       if (!client->osdc.debugfs_file)
-               goto out;
 
        client->debugfs_monmap = debugfs_create_file("monmap",
                                        0400,
                                        client->debugfs_dir,
                                        client,
                                        &monmap_show_fops);
-       if (!client->debugfs_monmap)
-               goto out;
 
        client->debugfs_osdmap = debugfs_create_file("osdmap",
                                        0400,
                                        client->debugfs_dir,
                                        client,
                                        &osdmap_show_fops);
-       if (!client->debugfs_osdmap)
-               goto out;
 
        client->debugfs_options = debugfs_create_file("client_options",
                                        0400,
                                        client->debugfs_dir,
                                        client,
                                        &client_options_show_fops);
-       if (!client->debugfs_options)
-               goto out;
-
-       return 0;
-
-out:
-       ceph_debugfs_client_cleanup(client);
-       return ret;
 }
 
 void ceph_debugfs_client_cleanup(struct ceph_client *client)
@@ -477,18 +454,16 @@ void ceph_debugfs_client_cleanup(struct ceph_client *client)
 
 #else  /* CONFIG_DEBUG_FS */
 
-int __init ceph_debugfs_init(void)
+void __init ceph_debugfs_init(void)
 {
-       return 0;
 }
 
 void ceph_debugfs_cleanup(void)
 {
 }
 
-int ceph_debugfs_client_init(struct ceph_client *client)
+void ceph_debugfs_client_init(struct ceph_client *client)
 {
-       return 0;
 }
 
 void ceph_debugfs_client_cleanup(struct ceph_client *client)
index 3f9ce60..0f7ded2 100644 (file)
@@ -80,9 +80,10 @@ int get_compat_msghdr(struct msghdr *kmsg,
 
        kmsg->msg_iocb = NULL;
 
-       return compat_import_iovec(save_addr ? READ : WRITE,
+       err = compat_import_iovec(save_addr ? READ : WRITE,
                                   compat_ptr(msg.msg_iov), msg.msg_iovlen,
                                   UIO_FASTIOV, iov, &kmsg->msg_iter);
+       return err < 0 ? err : 0;
 }
 
 /* Bleech... */
index 3e073ca..d57b0cc 100644 (file)
@@ -1597,7 +1597,7 @@ static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority,
                sk = kmem_cache_alloc(slab, priority & ~__GFP_ZERO);
                if (!sk)
                        return sk;
-               if (priority & __GFP_ZERO)
+               if (want_init_on_alloc(priority))
                        sk_prot_clear_nulls(sk, prot->obj_size);
        } else
                sk = kmalloc(prot->obj_size, priority);
index 16449d6..293d568 100644 (file)
@@ -2222,9 +2222,10 @@ static int copy_msghdr_from_user(struct msghdr *kmsg,
 
        kmsg->msg_iocb = NULL;
 
-       return import_iovec(save_addr ? READ : WRITE,
+       err = import_iovec(save_addr ? READ : WRITE,
                            msg.msg_iov, msg.msg_iovlen,
                            UIO_FASTIOV, iov, &kmsg->msg_iter);
+       return err < 0 ? err : 0;
 }
 
 static int ___sys_sendmsg(struct socket *sock, struct user_msghdr __user *msg,
@@ -2326,6 +2327,13 @@ out_freeiov:
 /*
  *     BSD sendmsg interface
  */
+long __sys_sendmsg_sock(struct socket *sock, struct user_msghdr __user *msg,
+                       unsigned int flags)
+{
+       struct msghdr msg_sys;
+
+       return ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL, 0);
+}
 
 long __sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned int flags,
                   bool forbid_cmsg_compat)
@@ -2500,6 +2508,14 @@ out_freeiov:
  *     BSD recvmsg interface
  */
 
+long __sys_recvmsg_sock(struct socket *sock, struct user_msghdr __user *msg,
+                       unsigned int flags)
+{
+       struct msghdr msg_sys;
+
+       return ___sys_recvmsg(sock, msg, &msg_sys, flags, 0);
+}
+
 long __sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned int flags,
                   bool forbid_cmsg_compat)
 {
index 95ebd76..707d7aa 100644 (file)
@@ -11,7 +11,6 @@
 #include "netns.h"
 
 static struct dentry *topdir;
-static struct dentry *rpc_fault_dir;
 static struct dentry *rpc_clnt_dir;
 static struct dentry *rpc_xprt_dir;
 
@@ -125,23 +124,16 @@ rpc_clnt_debugfs_register(struct rpc_clnt *clnt)
        char name[24]; /* enough for "../../rpc_xprt/ + 8 hex digits + NULL */
        struct rpc_xprt *xprt;
 
-       /* Already registered? */
-       if (clnt->cl_debugfs || !rpc_clnt_dir)
-               return;
-
        len = snprintf(name, sizeof(name), "%x", clnt->cl_clid);
        if (len >= sizeof(name))
                return;
 
        /* make the per-client dir */
        clnt->cl_debugfs = debugfs_create_dir(name, rpc_clnt_dir);
-       if (!clnt->cl_debugfs)
-               return;
 
        /* make tasks file */
-       if (!debugfs_create_file("tasks", S_IFREG | 0400, clnt->cl_debugfs,
-                                clnt, &tasks_fops))
-               goto out_err;
+       debugfs_create_file("tasks", S_IFREG | 0400, clnt->cl_debugfs, clnt,
+                           &tasks_fops);
 
        rcu_read_lock();
        xprt = rcu_dereference(clnt->cl_xprt);
@@ -157,8 +149,7 @@ rpc_clnt_debugfs_register(struct rpc_clnt *clnt)
        if (len >= sizeof(name))
                goto out_err;
 
-       if (!debugfs_create_symlink("xprt", clnt->cl_debugfs, name))
-               goto out_err;
+       debugfs_create_symlink("xprt", clnt->cl_debugfs, name);
 
        return;
 out_err:
@@ -226,9 +217,6 @@ rpc_xprt_debugfs_register(struct rpc_xprt *xprt)
        static atomic_t cur_id;
        char            name[9]; /* 8 hex digits + NULL term */
 
-       if (!rpc_xprt_dir)
-               return;
-
        id = (unsigned int)atomic_inc_return(&cur_id);
 
        len = snprintf(name, sizeof(name), "%x", id);
@@ -237,15 +225,10 @@ rpc_xprt_debugfs_register(struct rpc_xprt *xprt)
 
        /* make the per-client dir */
        xprt->debugfs = debugfs_create_dir(name, rpc_xprt_dir);
-       if (!xprt->debugfs)
-               return;
 
        /* make tasks file */
-       if (!debugfs_create_file("info", S_IFREG | 0400, xprt->debugfs,
-                                xprt, &xprt_info_fops)) {
-               debugfs_remove_recursive(xprt->debugfs);
-               xprt->debugfs = NULL;
-       }
+       debugfs_create_file("info", S_IFREG | 0400, xprt->debugfs, xprt,
+                           &xprt_info_fops);
 
        atomic_set(&xprt->inject_disconnect, rpc_inject_disconnect);
 }
@@ -308,28 +291,11 @@ static const struct file_operations fault_disconnect_fops = {
        .release        = fault_release,
 };
 
-static struct dentry *
-inject_fault_dir(struct dentry *topdir)
-{
-       struct dentry *faultdir;
-
-       faultdir = debugfs_create_dir("inject_fault", topdir);
-       if (!faultdir)
-               return NULL;
-
-       if (!debugfs_create_file("disconnect", S_IFREG | 0400, faultdir,
-                                NULL, &fault_disconnect_fops))
-               return NULL;
-
-       return faultdir;
-}
-
 void __exit
 sunrpc_debugfs_exit(void)
 {
        debugfs_remove_recursive(topdir);
        topdir = NULL;
-       rpc_fault_dir = NULL;
        rpc_clnt_dir = NULL;
        rpc_xprt_dir = NULL;
 }
@@ -337,26 +303,16 @@ sunrpc_debugfs_exit(void)
 void __init
 sunrpc_debugfs_init(void)
 {
-       topdir = debugfs_create_dir("sunrpc", NULL);
-       if (!topdir)
-               return;
+       struct dentry *rpc_fault_dir;
 
-       rpc_fault_dir = inject_fault_dir(topdir);
-       if (!rpc_fault_dir)
-               goto out_remove;
+       topdir = debugfs_create_dir("sunrpc", NULL);
 
        rpc_clnt_dir = debugfs_create_dir("rpc_clnt", topdir);
-       if (!rpc_clnt_dir)
-               goto out_remove;
 
        rpc_xprt_dir = debugfs_create_dir("rpc_xprt", topdir);
-       if (!rpc_xprt_dir)
-               goto out_remove;
 
-       return;
-out_remove:
-       debugfs_remove_recursive(topdir);
-       topdir = NULL;
-       rpc_fault_dir = NULL;
-       rpc_clnt_dir = NULL;
+       rpc_fault_dir = debugfs_create_dir("inject_fault", topdir);
+
+       debugfs_create_file("disconnect", S_IFREG | 0400, rpc_fault_dir, NULL,
+                           &fault_disconnect_fops);
 }
index 2121c9b..48fe3b1 100644 (file)
@@ -73,7 +73,8 @@ svc_rdma_get_rw_ctxt(struct svcxprt_rdma *rdma, unsigned int sges)
 
        ctxt->rw_sg_table.sgl = ctxt->rw_first_sgl;
        if (sg_alloc_table_chained(&ctxt->rw_sg_table, sges,
-                                  ctxt->rw_sg_table.sgl)) {
+                                  ctxt->rw_sg_table.sgl,
+                                  SG_CHUNK_SIZE)) {
                kfree(ctxt);
                ctxt = NULL;
        }
@@ -84,7 +85,7 @@ out:
 static void svc_rdma_put_rw_ctxt(struct svcxprt_rdma *rdma,
                                 struct svc_rdma_rw_ctxt *ctxt)
 {
-       sg_free_table_chained(&ctxt->rw_sg_table, true);
+       sg_free_table_chained(&ctxt->rw_sg_table, SG_CHUNK_SIZE);
 
        spin_lock(&rdma->sc_rw_ctxt_lock);
        list_add(&ctxt->rw_list, &rdma->sc_rw_ctxts);
index d63cc8a..71b5e83 100644 (file)
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 menuconfig SAMPLES
        bool "Sample kernel code"
-       depends on !UML
        help
          You can build and test sample kernel code here.
 
@@ -95,16 +94,24 @@ config SAMPLE_CONFIGFS
 
 config SAMPLE_CONNECTOR
        tristate "Build connector sample -- loadable modules only"
-       depends on CONNECTOR && m
+       depends on CONNECTOR && HEADERS_INSTALL && m
        help
          When enabled, this builds both a sample kernel module for
          the connector interface and a user space tool to communicate
          with it.
          See also Documentation/connector/connector.txt
 
+config SAMPLE_HIDRAW
+       bool "hidraw sample"
+       depends on HEADERS_INSTALL
+
+config SAMPLE_PIDFD
+       bool "pidfd sample"
+       depends on HEADERS_INSTALL
+
 config SAMPLE_SECCOMP
        bool "Build seccomp sample code"
-       depends on SECCOMP_FILTER
+       depends on SECCOMP_FILTER && HEADERS_INSTALL
        help
          Build samples of seccomp filters using various methods of
          BPF filter construction.
@@ -156,6 +163,7 @@ config SAMPLE_ANDROID_BINDERFS
 
 config SAMPLE_VFS
        bool "Build example programs that use new VFS system calls"
+       depends on HEADERS_INSTALL
        help
          Build example userspace programs that use new VFS system calls such
          as mount API and statx().  Note that this is restricted to the x86
index debf892..7d6e4ca 100644 (file)
@@ -4,14 +4,14 @@
 obj-$(CONFIG_SAMPLE_ANDROID_BINDERFS)  += binderfs/
 obj-$(CONFIG_SAMPLE_CONFIGFS)          += configfs/
 obj-$(CONFIG_SAMPLE_CONNECTOR)         += connector/
-subdir-y                               += hidraw
+subdir-$(CONFIG_SAMPLE_HIDRAW)         += hidraw
 obj-$(CONFIG_SAMPLE_HW_BREAKPOINT)     += hw_breakpoint/
 obj-$(CONFIG_SAMPLE_KDB)               += kdb/
 obj-$(CONFIG_SAMPLE_KFIFO)             += kfifo/
 obj-$(CONFIG_SAMPLE_KOBJECT)           += kobject/
 obj-$(CONFIG_SAMPLE_KPROBES)           += kprobes/
 obj-$(CONFIG_SAMPLE_LIVEPATCH)         += livepatch/
-subdir-y                               += pidfd
+subdir-$(CONFIG_SAMPLE_PIDFD)          += pidfd
 obj-$(CONFIG_SAMPLE_QMI_CLIENT)                += qmi/
 obj-$(CONFIG_SAMPLE_RPMSG_CLIENT)      += rpmsg/
 subdir-$(CONFIG_SAMPLE_SECCOMP)                += seccomp
index ee58cde..73e80b9 100644 (file)
@@ -79,8 +79,8 @@ endef
 # would try to directly execute the shell builtin 'command'. This workaround
 # should be kept for a long time since this issue was fixed only after the
 # GNU Make 4.2.1 release.
-cc-cross-prefix = $(firstword $(foreach c, $(filter-out -%, $(1)), \
-                       $(if $(shell command -v $(c)gcc 2>/dev/null), $(c))))
+cc-cross-prefix = $(firstword $(foreach c, $(1), \
+                       $(if $(shell command -v -- $(c)gcc 2>/dev/null), $(c))))
 
 # output directory for tests below
 TMPOUT := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/)
@@ -187,12 +187,6 @@ dtbinst := -f $(srctree)/scripts/Makefile.dtbinst obj
 # $(Q)$(MAKE) $(clean)=dir
 clean := -f $(srctree)/scripts/Makefile.clean obj
 
-###
-# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.headersinst obj=
-# Usage:
-# $(Q)$(MAKE) $(hdr-inst)=dir
-hdr-inst := -f $(srctree)/scripts/Makefile.headersinst obj
-
 # echo command.
 # Short version is used, if $(quiet) equals `quiet_', otherwise full one.
 echo-cmd = $(if $($(quiet)cmd_$(1)),\
@@ -213,12 +207,12 @@ objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o)))
 # See Documentation/kbuild/makefiles.rst for more info
 
 ifneq ($(KBUILD_NOCMDDEP),1)
-# Check if both arguments are the same including their order. Result is empty
+# Check if both commands are the same including their order. Result is empty
 # string if equal. User may override this check using make KBUILD_NOCMDDEP=1
-arg-check = $(filter-out $(subst $(space),$(space_escape),$(strip $(cmd_$@))), \
+cmd-check = $(filter-out $(subst $(space),$(space_escape),$(strip $(cmd_$@))), \
                          $(subst $(space),$(space_escape),$(strip $(cmd_$1))))
 else
-arg-check = $(if $(strip $(cmd_$@)),,1)
+cmd-check = $(if $(strip $(cmd_$@)),,1)
 endif
 
 # Replace >$< with >$$< to preserve $ when reloading the .cmd file
@@ -231,15 +225,15 @@ make-cmd = $(call escsq,$(subst $(pound),$$(pound),$(subst $$,$$$$,$(cmd_$(1))))
 
 # Find any prerequisites that is newer than target or that does not exist.
 # PHONY targets skipped in both cases.
-any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
+any-prereq = $(filter-out $(PHONY),$?)$(filter-out $(PHONY) $(wildcard $^),$^)
 
 # Execute command if command has changed or prerequisite(s) are updated.
-if_changed = $(if $(strip $(any-prereq) $(arg-check)),                       \
+if_changed = $(if $(any-prereq)$(cmd-check),                                 \
        $(cmd);                                                              \
        printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)
 
 # Execute the command and also postprocess generated .d dependencies file.
-if_changed_dep = $(if $(strip $(any-prereq) $(arg-check)),$(cmd_and_fixdep),@:)
+if_changed_dep = $(if $(any-prereq)$(cmd-check),$(cmd_and_fixdep),@:)
 
 cmd_and_fixdep =                                                             \
        $(cmd);                                                              \
@@ -249,7 +243,7 @@ cmd_and_fixdep =                                                             \
 # Usage: $(call if_changed_rule,foo)
 # Will check if $(cmd_foo) or any of the prerequisites changed,
 # and if so will execute $(rule_foo).
-if_changed_rule = $(if $(strip $(any-prereq) $(arg-check)),$(rule_$(1)),@:)
+if_changed_rule = $(if $(any-prereq)$(cmd-check),$(rule_$(1)),@:)
 
 ###
 # why - tell why a target got built
@@ -274,8 +268,8 @@ ifeq ($(KBUILD_VERBOSE),2)
 why =                                                                        \
     $(if $(filter $@, $(PHONY)),- due to target is PHONY,                    \
         $(if $(wildcard $@),                                                 \
-            $(if $(strip $(any-prereq)),- due to: $(any-prereq),             \
-                $(if $(arg-check),                                           \
+            $(if $(any-prereq),- due to: $(any-prereq),                      \
+                $(if $(cmd-check),                                           \
                     $(if $(cmd_$@),- due to command line change,             \
                         $(if $(filter $@, $(targets)),                       \
                             - due to missing .cmd file,                      \
index 9d442ee..16bcb80 100644 (file)
@@ -31,11 +31,6 @@ always               := $(hostprogs-y) $(hostprogs-m)
 # The following hostprogs-y programs are only build on demand
 hostprogs-y += unifdef
 
-# These targets are used internally to avoid "is up to date" messages
-PHONY += build_unifdef
-build_unifdef: $(obj)/unifdef
-       @:
-
 subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins
 subdir-$(CONFIG_MODVERSIONS) += genksyms
 subdir-$(CONFIG_SECURITY_SELINUX) += selinux
index ae9cf74..be38198 100644 (file)
@@ -294,6 +294,15 @@ quiet_cmd_cc_lst_c = MKLST   $@
 $(obj)/%.lst: $(src)/%.c FORCE
        $(call if_changed_dep,cc_lst_c)
 
+# header test (header-test-y target)
+# ---------------------------------------------------------------------------
+
+quiet_cmd_cc_s_h = CC      $@
+      cmd_cc_s_h = $(CC) $(c_flags) -S -o $@ -x c /dev/null -include $<
+
+$(obj)/%.h.s: $(src)/%.h FORCE
+       $(call if_changed_dep,cc_s_h)
+
 # Compile assembler sources (.S)
 # ---------------------------------------------------------------------------
 
@@ -504,7 +513,7 @@ existing-targets := $(wildcard $(sort $(targets)))
 
 -include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd)
 
-ifneq ($(srctree),.)
+ifdef building_out_of_srctree
 # Create directories for object files if they do not exist
 obj-dirs := $(sort $(obj) $(patsubst %/,%, $(dir $(targets))))
 # If targets exist, their directories apparently exist. Skip mkdir.
index 3ab8d1a..a74ce2e 100644 (file)
@@ -34,7 +34,6 @@ warning-1 += $(call cc-option, -Wstringop-truncation)
 warning-1 += -Wno-missing-field-initializers
 warning-1 += -Wno-sign-compare
 
-warning-2 := -Waggregate-return
 warning-2 += -Wcast-align
 warning-2 += -Wdisabled-optimization
 warning-2 += -Wnested-externs
@@ -68,10 +67,8 @@ else
 
 ifdef CONFIG_CC_IS_CLANG
 KBUILD_CFLAGS += -Wno-initializer-overrides
-KBUILD_CFLAGS += -Wno-unused-value
 KBUILD_CFLAGS += -Wno-format
 KBUILD_CFLAGS += -Wno-sign-compare
 KBUILD_CFLAGS += -Wno-format-zero-length
-KBUILD_CFLAGS += -Wno-uninitialized
 endif
 endif
index 3d1ebaa..1b405a7 100644 (file)
@@ -14,109 +14,89 @@ __headers:
 
 include scripts/Kbuild.include
 
-srcdir        := $(srctree)/$(obj)
+src := $(srctree)/$(obj)
+gen := $(objtree)/$(subst include/,include/generated/,$(obj))
+dst := usr/include
 
-# When make is run under a fakechroot environment, the function
-# $(wildcard $(srcdir)/*/.) doesn't only return directories, but also regular
-# files. So, we are using a combination of sort/dir/wildcard which works
-# with fakechroot.
-subdirs       := $(patsubst $(srcdir)/%/,%,\
-                $(filter-out $(srcdir)/,\
-                $(sort $(dir $(wildcard $(srcdir)/*/)))))
+-include $(src)/Kbuild
 
-# Recursion
-__headers: $(subdirs)
+# $(filter %/, ...) is a workaround for GNU Make <= 4.2.1, where
+# $(wildcard $(src)/*/) contains not only directories but also regular files.
+src-subdirs := $(patsubst $(src)/%/,%,$(filter %/, $(wildcard $(src)/*/)))
+gen-subdirs := $(patsubst $(gen)/%/,%,$(filter %/, $(wildcard $(gen)/*/)))
+all-subdirs := $(sort $(src-subdirs) $(gen-subdirs))
 
-PHONY += $(subdirs)
-$(subdirs):
-       $(Q)$(MAKE) $(hdr-inst)=$(obj)/$@ dst=$(dst)/$@
+src-headers := $(if $(src-subdirs), $(shell cd $(src) && find $(src-subdirs) -name '*.h'))
+src-headers := $(filter-out $(no-export-headers), $(src-headers))
+gen-headers := $(if $(gen-subdirs), $(shell cd $(gen) && find $(gen-subdirs) -name '*.h'))
+gen-headers := $(filter-out $(no-export-headers), $(gen-headers))
 
-# Skip header install/check for include/uapi and arch/$(SRCARCH)/include/uapi.
-# We have only sub-directories there.
-skip-inst := $(if $(filter %/uapi,$(obj)),1)
+# If the same header is exported from source and generated directories,
+# the former takes precedence, but this should be warned.
+duplicated := $(filter $(gen-headers), $(src-headers))
+$(if $(duplicated), $(warning duplicated header export: $(duplicated)))
 
-ifeq ($(skip-inst),)
+gen-headers := $(filter-out $(duplicated), $(gen-headers))
 
-# Kbuild file is optional
-kbuild-file := $(srctree)/$(obj)/Kbuild
--include $(kbuild-file)
+# Add dst path prefix
+all-subdirs := $(addprefix $(dst)/, $(all-subdirs))
+src-headers := $(addprefix $(dst)/, $(src-headers))
+gen-headers := $(addprefix $(dst)/, $(gen-headers))
+all-headers := $(src-headers) $(gen-headers)
 
-installdir    := $(INSTALL_HDR_PATH)/$(dst)
-gendir        := $(objtree)/$(subst include/,include/generated/,$(obj))
-header-files  := $(notdir $(wildcard $(srcdir)/*.h))
-header-files  := $(filter-out $(no-export-headers), $(header-files))
-genhdr-files  := $(notdir $(wildcard $(gendir)/*.h))
-genhdr-files  := $(filter-out $(header-files), $(genhdr-files))
+# Work out what needs to be removed
+old-subdirs := $(wildcard $(all-subdirs))
+old-headers := $(if $(old-subdirs),$(shell find $(old-subdirs) -name '*.h'))
+unwanted    := $(filter-out $(all-headers), $(old-headers))
 
-# files used to track state of install/check
-install-file  := $(installdir)/.install
-check-file    := $(installdir)/.check
+# Create directories
+existing-dirs := $(sort $(dir $(old-headers)))
+wanted-dirs   := $(sort $(dir $(all-headers)))
+new-dirs      := $(filter-out $(existing-dirs), $(wanted-dirs))
+$(if $(new-dirs), $(shell mkdir -p $(new-dirs)))
 
-# all headers files for this dir
-all-files     := $(header-files) $(genhdr-files)
-output-files  := $(addprefix $(installdir)/, $(all-files))
+# Rules
 
-# Work out what needs to be removed
-oldheaders    := $(patsubst $(installdir)/%,%,$(wildcard $(installdir)/*.h))
-unwanted      := $(filter-out $(all-files),$(oldheaders))
+ifndef HDRCHECK
 
-# Prefix unwanted with full paths to $(INSTALL_HDR_PATH)
-unwanted-file := $(addprefix $(installdir)/, $(unwanted))
+quiet_cmd_install = HDRINST $@
+      cmd_install = $(CONFIG_SHELL) $(srctree)/scripts/headers_install.sh $< $@
 
-printdir = $(patsubst $(INSTALL_HDR_PATH)/%/,%,$(dir $@))
+$(src-headers): $(dst)/%.h: $(src)/%.h $(srctree)/scripts/headers_install.sh FORCE
+       $(call if_changed,install)
 
-quiet_cmd_install = INSTALL $(printdir) ($(words $(all-files))\
-                            file$(if $(word 2, $(all-files)),s))
-      cmd_install = \
-        $(CONFIG_SHELL) $< $(installdir) $(srcdir) $(header-files); \
-        $(CONFIG_SHELL) $< $(installdir) $(gendir) $(genhdr-files); \
-        touch $@
+$(gen-headers): $(dst)/%.h: $(gen)/%.h $(srctree)/scripts/headers_install.sh FORCE
+       $(call if_changed,install)
 
 quiet_cmd_remove = REMOVE  $(unwanted)
-      cmd_remove = rm -f $(unwanted-file)
-
-quiet_cmd_check = CHECK   $(printdir) ($(words $(all-files)) files)
-# Headers list can be pretty long, xargs helps to avoid
-# the "Argument list too long" error.
-      cmd_check = for f in $(all-files); do                          \
-                  echo "$(installdir)/$${f}"; done                      \
-                  | xargs                                            \
-                  $(PERL) $< $(INSTALL_HDR_PATH)/include $(SRCARCH); \
-                 touch $@
+      cmd_remove = rm -f $(unwanted)
 
-ifndef HDRCHECK
-# Rules for installing headers
-__headers: $(install-file)
+__headers: $(all-headers)
+ifneq ($(unwanted),)
+       $(call cmd,remove)
+endif
        @:
 
-targets += $(install-file)
-$(install-file): scripts/headers_install.sh \
-                $(addprefix $(srcdir)/,$(header-files)) \
-                $(addprefix $(gendir)/,$(genhdr-files)) FORCE
-       $(if $(unwanted),$(call cmd,remove),)
-       $(if $(wildcard $(dir $@)),,$(shell mkdir -p $(dir $@)))
-       $(call if_changed,install)
+existing-headers := $(filter $(old-headers), $(all-headers))
+
+-include $(foreach f,$(existing-headers),$(dir $(f)).$(notdir $(f)).cmd)
 
 else
-__headers: $(check-file)
-       @:
 
-targets += $(check-file)
-$(check-file): scripts/headers_check.pl $(output-files) FORCE
-       $(call if_changed,check)
+quiet_cmd_check = HDRCHK  $<
+      cmd_check = $(PERL) $(srctree)/scripts/headers_check.pl $(dst) $(SRCARCH) $<; touch $@
 
-endif
+check-files := $(addsuffix .chk, $(all-headers))
 
-cmd_files := $(wildcard \
-             $(foreach f,$(sort $(targets)),$(dir $(f)).$(notdir $(f)).cmd))
+$(check-files): $(dst)/%.chk : $(dst)/% $(srctree)/scripts/headers_check.pl
+       $(call cmd,check)
 
-ifneq ($(cmd_files),)
-       include $(cmd_files)
-endif
+__headers: $(check-files)
+       @:
 
-endif # skip-inst
+endif
 
 PHONY += FORCE
-FORCE: ;
+FORCE:
 
 .PHONY: $(PHONY)
index a316d36..2208ebb 100644 (file)
@@ -69,7 +69,7 @@ _hostcxx_flags = $(KBUILD_HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) \
 
 # $(objtree)/$(obj) for including generated headers from checkin source files
 ifeq ($(KBUILD_EXTMOD),)
-ifneq ($(srctree),.)
+ifdef building_out_of_srctree
 _hostc_flags   += -I $(objtree)/$(obj)
 _hostcxx_flags += -I $(objtree)/$(obj)
 endif
index f1f38c8..6cb3aa5 100644 (file)
@@ -66,6 +66,20 @@ extra-y += $(patsubst %.dtb,%.dt.yaml, $(dtb-y))
 extra-$(CONFIG_OF_ALL_DTBS) += $(patsubst %.dtb,%.dt.yaml, $(dtb-))
 endif
 
+# Test self-contained headers
+
+# Wildcard searches in $(srctree)/$(src)/, but not in $(objtree)/$(obj)/.
+# Stale generated headers are often left over, so pattern matching should
+# be avoided. Please notice $(srctree)/$(src)/ and $(objtree)/$(obj) point
+# to the same location for in-tree building. So, header-test-pattern-y should
+# be used with care.
+header-test-y  += $(filter-out $(header-test-), \
+               $(patsubst $(srctree)/$(src)/%, %, \
+               $(wildcard $(addprefix $(srctree)/$(src)/, \
+               $(header-test-pattern-y)))))
+
+extra-$(CONFIG_HEADER_TEST) += $(addsuffix .s, $(header-test-y))
+
 # Add subdir path
 
 extra-y                := $(addprefix $(obj)/,$(extra-y))
@@ -140,7 +154,7 @@ endif
 # $(srctree)/$(src) for including checkin headers from generated source files
 # $(objtree)/$(obj) for including generated headers from checkin source files
 ifeq ($(KBUILD_EXTMOD),)
-ifneq ($(srctree),.)
+ifdef building_out_of_srctree
 _c_flags   += -I $(srctree)/$(src) -I $(objtree)/$(obj)
 _a_flags   += -I $(srctree)/$(src) -I $(objtree)/$(obj)
 _cpp_flags += -I $(srctree)/$(src) -I $(objtree)/$(obj)
@@ -331,19 +345,19 @@ printf "%08x\n" $$dec_size |                                              \
 )
 
 quiet_cmd_bzip2 = BZIP2   $@
-      cmd_bzip2 = { cat $(real-prereqs) | bzip2 -9 && $(size_append); } > $@
+      cmd_bzip2 = { cat $(real-prereqs) | bzip2 -9; $(size_append); } > $@
 
 # Lzma
 # ---------------------------------------------------------------------------
 
 quiet_cmd_lzma = LZMA    $@
-      cmd_lzma = { cat $(real-prereqs) | lzma -9 && $(size_append); } > $@
+      cmd_lzma = { cat $(real-prereqs) | lzma -9; $(size_append); } > $@
 
 quiet_cmd_lzo = LZO     $@
-      cmd_lzo = { cat $(real-prereqs) | lzop -9 && $(size_append); } > $@
+      cmd_lzo = { cat $(real-prereqs) | lzop -9; $(size_append); } > $@
 
 quiet_cmd_lz4 = LZ4     $@
-      cmd_lz4 = { cat $(real-prereqs) | lz4c -l -c1 stdin stdout && \
+      cmd_lz4 = { cat $(real-prereqs) | lz4c -l -c1 stdin stdout; \
                   $(size_append); } > $@
 
 # U-Boot mkimage
@@ -386,7 +400,7 @@ quiet_cmd_uimage = UIMAGE  $@
 # big dictionary would increase the memory usage too much in the multi-call
 # decompression mode. A BCJ filter isn't used either.
 quiet_cmd_xzkern = XZKERN  $@
-      cmd_xzkern = { cat $(real-prereqs) | sh $(srctree)/scripts/xz_wrap.sh && \
+      cmd_xzkern = { cat $(real-prereqs) | sh $(srctree)/scripts/xz_wrap.sh; \
                      $(size_append); } > $@
 
 quiet_cmd_xzmisc = XZMISC  $@
index ea90a90..50a9990 100644 (file)
@@ -15,7 +15,7 @@ include include/config/tristate.conf
 
 include scripts/Kbuild.include
 
-ifneq ($(srctree),.)
+ifdef building_out_of_srctree
 # Create output directory if not already present
 _dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj))
 endif
index facbd60..9ba47b0 100644 (file)
@@ -99,6 +99,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <string.h>
+#include <stdarg.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <ctype.h>
@@ -109,6 +110,36 @@ static void usage(void)
        exit(1);
 }
 
+/*
+ * In the intended usage of this program, the stdout is redirected to .*.cmd
+ * files. The return value of printf() and putchar() must be checked to catch
+ * any error, e.g. "No space left on device".
+ */
+static void xprintf(const char *format, ...)
+{
+       va_list ap;
+       int ret;
+
+       va_start(ap, format);
+       ret = vprintf(format, ap);
+       if (ret < 0) {
+               perror("fixdep");
+               exit(1);
+       }
+       va_end(ap);
+}
+
+static void xputchar(int c)
+{
+       int ret;
+
+       ret = putchar(c);
+       if (ret == EOF) {
+               perror("fixdep");
+               exit(1);
+       }
+}
+
 /*
  * Print out a dependency path from a symbol name
  */
@@ -116,7 +147,7 @@ static void print_dep(const char *m, int slen, const char *dir)
 {
        int c, prev_c = '/', i;
 
-       printf("    $(wildcard %s/", dir);
+       xprintf("    $(wildcard %s/", dir);
        for (i = 0; i < slen; i++) {
                c = m[i];
                if (c == '_')
@@ -124,10 +155,10 @@ static void print_dep(const char *m, int slen, const char *dir)
                else
                        c = tolower(c);
                if (c != '/' || prev_c != '/')
-                       putchar(c);
+                       xputchar(c);
                prev_c = c;
        }
-       printf(".h) \\\n");
+       xprintf(".h) \\\n");
 }
 
 struct item {
@@ -324,13 +355,13 @@ static void parse_dep_file(char *m, const char *target)
                                 */
                                if (!saw_any_target) {
                                        saw_any_target = 1;
-                                       printf("source_%s := %s\n\n",
-                                              target, m);
-                                       printf("deps_%s := \\\n", target);
+                                       xprintf("source_%s := %s\n\n",
+                                               target, m);
+                                       xprintf("deps_%s := \\\n", target);
                                }
                                is_first_dep = 0;
                        } else {
-                               printf("  %s \\\n", m);
+                               xprintf("  %s \\\n", m);
                        }
 
                        buf = read_file(m);
@@ -353,8 +384,8 @@ static void parse_dep_file(char *m, const char *target)
                exit(1);
        }
 
-       printf("\n%s: $(deps_%s)\n\n", target, target);
-       printf("$(deps_%s):\n", target);
+       xprintf("\n%s: $(deps_%s)\n\n", target, target);
+       xprintf("$(deps_%s):\n", target);
 }
 
 int main(int argc, char *argv[])
@@ -369,7 +400,7 @@ int main(int argc, char *argv[])
        target = argv[2];
        cmdline = argv[3];
 
-       printf("cmd_%s := %s\n\n", target, cmdline);
+       xprintf("cmd_%s := %s\n\n", target, cmdline);
 
        buf = read_file(depfile);
        parse_dep_file(buf, target);
index 888bf43..19f2645 100644 (file)
@@ -77,7 +77,7 @@ p1 << r1.p1;
 p2 << r1.p2;
 @@
 
-cocci.print_main("WARNING opportunity for kstrdep",p1)
+cocci.print_main("WARNING opportunity for kstrdup",p1)
 cocci.print_secs("strcpy",p2)
 
 @script:python depends on org@
@@ -85,7 +85,7 @@ p1 << r2.p1;
 p2 << r2.p2;
 @@
 
-cocci.print_main("WARNING opportunity for kstrdep",p1)
+cocci.print_main("WARNING opportunity for kstrdup",p1)
 cocci.print_secs("memcpy",p2)
 
 @script:python depends on report@
@@ -93,7 +93,7 @@ p1 << r1.p1;
 p2 << r1.p2;
 @@
 
-msg = "WARNING opportunity for kstrdep (strcpy on line %s)" % (p2[0].line)
+msg = "WARNING opportunity for kstrdup (strcpy on line %s)" % (p2[0].line)
 coccilib.report.print_report(p1[0], msg)
 
 @script:python depends on report@
@@ -101,5 +101,5 @@ p1 << r2.p1;
 p2 << r2.p2;
 @@
 
-msg = "WARNING opportunity for kstrdep (memcpy on line %s)" % (p2[0].line)
+msg = "WARNING opportunity for kstrdup (memcpy on line %s)" % (p2[0].line)
 coccilib.report.print_report(p1[0], msg)
index 350145d..12ce18f 100644 (file)
@@ -35,11 +35,11 @@ type loff_t;
 // a function that blocks
 @ blocks @
 identifier block_f;
-identifier wait_event =~ "^wait_event_.*";
+identifier wait =~ "^wait_.*";
 @@
   block_f(...) {
     ... when exists
-    wait_event(...)
+    wait(...)
     ... when exists
   }
 
@@ -49,12 +49,12 @@ identifier wait_event =~ "^wait_event_.*";
 // XXX currently reader_blocks supports only direct and 1-level indirect cases.
 @ reader_blocks_direct @
 identifier stream_reader.readstream;
-identifier wait_event =~ "^wait_event_.*";
+identifier wait =~ "^wait_.*";
 @@
   readstream(...)
   {
     ... when exists
-    wait_event(...)
+    wait(...)
     ... when exists
   }
 
index a5af9e3..fefd033 100644 (file)
@@ -3,7 +3,7 @@
 /// functions.  Values allocated using the devm_functions are freed when
 /// the device is detached, and thus the use of the standard freeing
 /// function would cause a double free.
-/// See Documentation/driver-model/devres.txt for more information.
+/// See Documentation/driver-model/devres.rst for more information.
 ///
 /// A difficulty of detecting this problem is that the standard freeing
 /// function might be called from a different function than the one
index c9f071b..1209213 100644 (file)
@@ -24,7 +24,7 @@ if (id == NULL || ...) { ... return ...; }
     when != of_dev_put(id)
     when != if (id) { ... put_device(&id->dev) ... }
     when != e1 = (T)id
-    when != e1 = &id->dev
+    when != e1 = (T)(&id->dev)
     when != e1 = get_device(&id->dev)
     when != e1 = (T1)platform_get_drvdata(id)
 (
@@ -42,11 +42,10 @@ p1 << search.p1;
 p2 << search.p2;
 @@
 
-coccilib.report.print_report(p2[0], "ERROR: missing put_device; "
-                             + "call of_find_device_by_node on line "
-                             + p1[0].line
-                             + ", but without a corresponding object release "
-                             + "within this function.")
+coccilib.report.print_report(p2[0],
+                             "ERROR: missing put_device; call of_find_device_by_node on line "
+                             + p1[0].line
+                             + ", but without a corresponding object release within this function.")
 
 @script:python depends on org@
 p1 << search.p1;
index a7a3620..13e5fba 100755 (executable)
@@ -28,7 +28,7 @@ parse_symbol() {
                local objfile=${modcache[$module]}
        else
                [[ $modpath == "" ]] && return
-               local objfile=$(find "$modpath" -name $module.ko -print -quit)
+               local objfile=$(find "$modpath" -name "${module//_/[-_]}.ko*" -print -quit)
                [[ $objfile == "" ]] && return
                modcache[$module]=$objfile
        fi
@@ -85,7 +85,7 @@ parse_symbol() {
        fi
 
        # Strip out the base of the path
-       code=${code//^$basepath/""}
+       code=${code#$basepath/}
 
        # In the case of inlines, move everything to same line
        code=${code//$'\n'/' '}
index 6ce8b4a..9c467b0 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0-only
+# SPDX-License-Identifier: GPL-2.0-or-later
 # Makefile.dtc
 #
 # This is not a complete Makefile of itself.  Instead, it is designed to
index 1ae7a54..d7986ee 100644 (file)
@@ -645,6 +645,8 @@ ERROR(path_references, fixup_path_references, NULL, &duplicate_node_names);
 static void fixup_omit_unused_nodes(struct check *c, struct dt_info *dti,
                                    struct node *node)
 {
+       if (generate_symbols && node->labels)
+               return;
        if (node->omit_if_unused && !node->is_referenced)
                delete_node(node);
 }
@@ -1197,8 +1199,24 @@ static void check_avoid_unnecessary_addr_size(struct check *c, struct dt_info *d
 }
 WARNING(avoid_unnecessary_addr_size, check_avoid_unnecessary_addr_size, NULL, &avoid_default_addr_size);
 
-static void check_unique_unit_address(struct check *c, struct dt_info *dti,
-                                             struct node *node)
+static bool node_is_disabled(struct node *node)
+{
+       struct property *prop;
+
+       prop = get_property(node, "status");
+       if (prop) {
+               char *str = prop->val.val;
+               if (streq("disabled", str))
+                       return true;
+       }
+
+       return false;
+}
+
+static void check_unique_unit_address_common(struct check *c,
+                                               struct dt_info *dti,
+                                               struct node *node,
+                                               bool disable_check)
 {
        struct node *childa;
 
@@ -1215,18 +1233,38 @@ static void check_unique_unit_address(struct check *c, struct dt_info *dti,
                if (!strlen(addr_a))
                        continue;
 
+               if (disable_check && node_is_disabled(childa))
+                       continue;
+
                for_each_child(node, childb) {
                        const char *addr_b = get_unitname(childb);
                        if (childa == childb)
                                break;
 
+                       if (disable_check && node_is_disabled(childb))
+                               continue;
+
                        if (streq(addr_a, addr_b))
                                FAIL(c, dti, childb, "duplicate unit-address (also used in node %s)", childa->fullpath);
                }
        }
 }
+
+static void check_unique_unit_address(struct check *c, struct dt_info *dti,
+                                             struct node *node)
+{
+       check_unique_unit_address_common(c, dti, node, false);
+}
 WARNING(unique_unit_address, check_unique_unit_address, NULL, &avoid_default_addr_size);
 
+static void check_unique_unit_address_if_enabled(struct check *c, struct dt_info *dti,
+                                             struct node *node)
+{
+       check_unique_unit_address_common(c, dti, node, true);
+}
+CHECK_ENTRY(unique_unit_address_if_enabled, check_unique_unit_address_if_enabled,
+           NULL, false, false, &avoid_default_addr_size);
+
 static void check_obsolete_chosen_interrupt_controller(struct check *c,
                                                       struct dt_info *dti,
                                                       struct node *node)
@@ -1527,10 +1565,14 @@ static void check_interrupts_property(struct check *c,
                prop = get_property(parent, "interrupt-parent");
                if (prop) {
                        phandle = propval_cell(prop);
-                       /* Give up if this is an overlay with external references */
-                       if ((phandle == 0 || phandle == -1) &&
-                           (dti->dtsflags & DTSF_PLUGIN))
+                       if ((phandle == 0) || (phandle == -1)) {
+                               /* Give up if this is an overlay with
+                                * external references */
+                               if (dti->dtsflags & DTSF_PLUGIN)
                                        return;
+                               FAIL_PROP(c, dti, parent, prop, "Invalid phandle");
+                               continue;
+                       }
 
                        irq_node = get_node_by_phandle(root, phandle);
                        if (!irq_node) {
@@ -1699,7 +1741,7 @@ static void check_graph_endpoint(struct check *c, struct dt_info *dti,
                return;
 
        if (!strprefixeq(node->name, node->basenamelen, "endpoint"))
-               FAIL(c, dti, node, "graph endpont node name should be 'endpoint'");
+               FAIL(c, dti, node, "graph endpoint node name should be 'endpoint'");
 
        check_graph_reg(c, dti, node);
 
@@ -1754,6 +1796,7 @@ static struct check *check_table[] = {
        &avoid_default_addr_size,
        &avoid_unnecessary_addr_size,
        &unique_unit_address,
+       &unique_unit_address_if_enabled,
        &obsolete_chosen_interrupt_controller,
        &chosen_node_is_root, &chosen_node_bootargs, &chosen_node_stdout_path,
 
index 06c0409..5c6c3fd 100644 (file)
@@ -1,21 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the 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
  */
 
 %option noyywrap nounput noinput never-interactive
index 2ec981e..2ed4dc1 100644 (file)
@@ -1,21 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the 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 <stdio.h>
index 357b878..6e74ece 100644 (file)
@@ -216,7 +216,8 @@ void add_child(struct node *parent, struct node *child);
 void delete_node_by_name(struct node *parent, char *name);
 void delete_node(struct node *node);
 void append_to_property(struct node *node,
-                       char *name, const void *data, int len);
+                       char *name, const void *data, int len,
+                       enum markertype type);
 
 const char *get_unitname(struct node *node);
 struct property *get_property(struct node *node, const char *propname);
index 65705a3..bd6977e 100644 (file)
@@ -510,7 +510,7 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
        fprintf(f, "/* Memory reserve map from source file */\n");
 
        /*
-        * Use .long on high and low halfs of u64s to avoid .quad
+        * Use .long on high and low halves of u64s to avoid .quad
         * as it appears .quad isn't available in some assemblers.
         */
        for (re = dti->reservelist; re; re = re->next) {
index 1649c2c..e546397 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0-only
+# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 # Makefile.libfdt
 #
 # This is not a complete Makefile of itself.  Instead, it is designed to
@@ -10,7 +10,9 @@ LIBFDT_VERSION = version.lds
 LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \
        fdt_addresses.c fdt_overlay.c
 LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
+LIBFDT_LIB = libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT)
 
 libfdt_clean:
        @$(VECHO) CLEAN "(libfdt)"
        rm -f $(STD_CLEANFILES:%=$(LIBFDT_dir)/%)
+       rm -f $(LIBFDT_dir)/$(LIBFDT_soname)
index ae03b11..179168e 100644 (file)
@@ -1,52 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "libfdt_env.h"
 
index 74961f9..f2e6880 100644 (file)
@@ -1,55 +1,10 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
 #ifndef FDT_H
 #define FDT_H
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
  * Copyright 2012 Kim Phillips, Freescale Semiconductor.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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 __ASSEMBLY__
index f13a87d..d8ba8ec 100644 (file)
@@ -1,53 +1,8 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
  * Copyright (C) 2018 embedded brains GmbH
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "libfdt_env.h"
 
@@ -95,3 +50,50 @@ int fdt_size_cells(const void *fdt, int nodeoffset)
                return 1;
        return val;
 }
+
+/* This function assumes that [address|size]_cells is 1 or 2 */
+int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
+                            const char *name, uint64_t addr, uint64_t size)
+{
+       int addr_cells, size_cells, ret;
+       uint8_t data[sizeof(fdt64_t) * 2], *prop;
+
+       ret = fdt_address_cells(fdt, parent);
+       if (ret < 0)
+               return ret;
+       addr_cells = ret;
+
+       ret = fdt_size_cells(fdt, parent);
+       if (ret < 0)
+               return ret;
+       size_cells = ret;
+
+       /* check validity of address */
+       prop = data;
+       if (addr_cells == 1) {
+               if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size))
+                       return -FDT_ERR_BADVALUE;
+
+               fdt32_st(prop, (uint32_t)addr);
+       } else if (addr_cells == 2) {
+               fdt64_st(prop, addr);
+       } else {
+               return -FDT_ERR_BADNCELLS;
+       }
+
+       /* check validity of size */
+       prop += addr_cells * sizeof(fdt32_t);
+       if (size_cells == 1) {
+               if (size > UINT32_MAX)
+                       return -FDT_ERR_BADVALUE;
+
+               fdt32_st(prop, (uint32_t)size);
+       } else if (size_cells == 2) {
+               fdt64_st(prop, size);
+       } else {
+               return -FDT_ERR_BADNCELLS;
+       }
+
+       return fdt_appendprop(fdt, nodeoffset, name, data,
+                             (addr_cells + size_cells) * sizeof(fdt32_t));
+}
index f2ae9b7..49d54d4 100644 (file)
@@ -1,52 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2012 David Gibson, IBM Corporation.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "libfdt_env.h"
 
index 5fdab6c..e97f12b 100644 (file)
@@ -1,53 +1,8 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2016 Free Electrons
  * Copyright (C) 2016 NextThing Co.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "libfdt_env.h"
 
@@ -93,11 +48,11 @@ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
  * @pathp: pointer which receives the path of the target (or NULL)
  *
  * overlay_get_target() retrieves the target offset in the base
- * device tree of a fragment, no matter how the actual targetting is
+ * device tree of a fragment, no matter how the actual targeting is
  * done (through a phandle or a path)
  *
  * returns:
- *      the targetted node offset in the base device tree
+ *      the targeted node offset in the base device tree
  *      Negative error code on error
  */
 static int overlay_get_target(const void *fdt, const void *fdto,
@@ -863,12 +818,16 @@ static int overlay_symbol_update(void *fdt, void *fdto)
 
 int fdt_overlay_apply(void *fdt, void *fdto)
 {
-       uint32_t delta = fdt_get_max_phandle(fdt);
+       uint32_t delta;
        int ret;
 
        FDT_RO_PROBE(fdt);
        FDT_RO_PROBE(fdto);
 
+       ret = fdt_find_max_phandle(fdt, &delta);
+       if (ret)
+               goto err;
+
        ret = overlay_adjust_local_phandles(fdto, delta);
        if (ret)
                goto err;
index eafc142..6fd9ec1 100644 (file)
@@ -1,52 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "libfdt_env.h"
 
@@ -144,29 +99,49 @@ static int fdt_string_eq_(const void *fdt, int stroffset,
        return p && (slen == len) && (memcmp(p, s, len) == 0);
 }
 
-uint32_t fdt_get_max_phandle(const void *fdt)
+int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
 {
-       uint32_t max_phandle = 0;
-       int offset;
+       uint32_t max = 0;
+       int offset = -1;
 
-       for (offset = fdt_next_node(fdt, -1, NULL);;
-            offset = fdt_next_node(fdt, offset, NULL)) {
-               uint32_t phandle;
+       while (true) {
+               uint32_t value;
 
-               if (offset == -FDT_ERR_NOTFOUND)
-                       return max_phandle;
+               offset = fdt_next_node(fdt, offset, NULL);
+               if (offset < 0) {
+                       if (offset == -FDT_ERR_NOTFOUND)
+                               break;
 
-               if (offset < 0)
-                       return (uint32_t)-1;
+                       return offset;
+               }
 
-               phandle = fdt_get_phandle(fdt, offset);
-               if (phandle == (uint32_t)-1)
-                       continue;
+               value = fdt_get_phandle(fdt, offset);
 
-               if (phandle > max_phandle)
-                       max_phandle = phandle;
+               if (value > max)
+                       max = value;
        }
 
+       if (phandle)
+               *phandle = max;
+
+       return 0;
+}
+
+int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
+{
+       uint32_t max;
+       int err;
+
+       err = fdt_find_max_phandle(fdt, &max);
+       if (err < 0)
+               return err;
+
+       if (max == FDT_MAX_PHANDLE)
+               return -FDT_ERR_NOPHANDLES;
+
+       if (phandle)
+               *phandle = max + 1;
+
        return 0;
 }
 
index 2e49855..8795947 100644 (file)
@@ -1,52 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "libfdt_env.h"
 
@@ -136,6 +91,14 @@ static int fdt_splice_struct_(void *fdt, void *p,
        return 0;
 }
 
+/* Must only be used to roll back in case of error */
+static void fdt_del_last_string_(void *fdt, const char *s)
+{
+       int newlen = strlen(s) + 1;
+
+       fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) - newlen);
+}
+
 static int fdt_splice_string_(void *fdt, int newlen)
 {
        void *p = (char *)fdt
@@ -149,7 +112,7 @@ static int fdt_splice_string_(void *fdt, int newlen)
        return 0;
 }
 
-static int fdt_find_add_string_(void *fdt, const char *s)
+static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
 {
        char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
        const char *p;
@@ -157,6 +120,8 @@ static int fdt_find_add_string_(void *fdt, const char *s)
        int len = strlen(s) + 1;
        int err;
 
+       *allocated = 0;
+
        p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s);
        if (p)
                /* found it */
@@ -167,6 +132,8 @@ static int fdt_find_add_string_(void *fdt, const char *s)
        if (err)
                return err;
 
+       *allocated = 1;
+
        memcpy(new, s, len);
        return (new - strtab);
 }
@@ -225,11 +192,12 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
        int nextoffset;
        int namestroff;
        int err;
+       int allocated;
 
        if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
                return nextoffset;
 
-       namestroff = fdt_find_add_string_(fdt, name);
+       namestroff = fdt_find_add_string_(fdt, name, &allocated);
        if (namestroff < 0)
                return namestroff;
 
@@ -237,8 +205,11 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
        proplen = sizeof(**prop) + FDT_TAGALIGN(len);
 
        err = fdt_splice_struct_(fdt, *prop, 0, proplen);
-       if (err)
+       if (err) {
+               if (allocated)
+                       fdt_del_last_string_(fdt, name);
                return err;
+       }
 
        (*prop)->tag = cpu_to_fdt32(FDT_PROP);
        (*prop)->nameoff = cpu_to_fdt32(namestroff);
index 9677a18..768db66 100644 (file)
@@ -1,51 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "libfdt_env.h"
@@ -82,6 +38,7 @@ static struct fdt_errtabent fdt_errtable[] = {
        FDT_ERRTABENT(FDT_ERR_BADVALUE),
        FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
        FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
+       FDT_ERRTABENT(FDT_ERR_BADFLAGS),
 };
 #define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
 
index 9fa4a94..76bea22 100644 (file)
@@ -1,52 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "libfdt_env.h"
 
@@ -121,6 +76,12 @@ static int fdt_sw_probe_struct_(void *fdt)
                        return err; \
        }
 
+static inline uint32_t sw_flags(void *fdt)
+{
+       /* assert: (fdt_magic(fdt) == FDT_SW_MAGIC) */
+       return fdt_last_comp_version(fdt);
+}
+
 /* 'complete' state:   Enter this state after fdt_finish()
  *
  * Allowed functions: none
@@ -141,7 +102,7 @@ static void *fdt_grab_space_(void *fdt, size_t len)
        return fdt_offset_ptr_w_(fdt, offset);
 }
 
-int fdt_create(void *buf, int bufsize)
+int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags)
 {
        const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
                                         sizeof(struct fdt_reserve_entry));
@@ -150,11 +111,22 @@ int fdt_create(void *buf, int bufsize)
        if (bufsize < hdrsize)
                return -FDT_ERR_NOSPACE;
 
+       if (flags & ~FDT_CREATE_FLAGS_ALL)
+               return -FDT_ERR_BADFLAGS;
+
        memset(buf, 0, bufsize);
 
+       /*
+        * magic and last_comp_version keep intermediate state during the fdt
+        * creation process, which is replaced with the proper FDT format by
+        * fdt_finish().
+        *
+        * flags should be accessed with sw_flags().
+        */
        fdt_set_magic(fdt, FDT_SW_MAGIC);
        fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
-       fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
+       fdt_set_last_comp_version(fdt, flags);
+
        fdt_set_totalsize(fdt,  bufsize);
 
        fdt_set_off_mem_rsvmap(fdt, hdrsize);
@@ -164,6 +136,11 @@ int fdt_create(void *buf, int bufsize)
        return 0;
 }
 
+int fdt_create(void *buf, int bufsize)
+{
+       return fdt_create_with_flags(buf, bufsize, 0);
+}
+
 int fdt_resize(void *fdt, void *buf, int bufsize)
 {
        size_t headsize, tailsize;
@@ -262,19 +239,13 @@ int fdt_end_node(void *fdt)
        return 0;
 }
 
-static int fdt_find_add_string_(void *fdt, const char *s)
+static int fdt_add_string_(void *fdt, const char *s)
 {
        char *strtab = (char *)fdt + fdt_totalsize(fdt);
-       const char *p;
        int strtabsize = fdt_size_dt_strings(fdt);
        int len = strlen(s) + 1;
        int struct_top, offset;
 
-       p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
-       if (p)
-               return p - strtab;
-
-       /* Add it */
        offset = -strtabsize - len;
        struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
        if (fdt_totalsize(fdt) + offset < struct_top)
@@ -285,20 +256,56 @@ static int fdt_find_add_string_(void *fdt, const char *s)
        return offset;
 }
 
+/* Must only be used to roll back in case of error */
+static void fdt_del_last_string_(void *fdt, const char *s)
+{
+       int strtabsize = fdt_size_dt_strings(fdt);
+       int len = strlen(s) + 1;
+
+       fdt_set_size_dt_strings(fdt, strtabsize - len);
+}
+
+static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
+{
+       char *strtab = (char *)fdt + fdt_totalsize(fdt);
+       int strtabsize = fdt_size_dt_strings(fdt);
+       const char *p;
+
+       *allocated = 0;
+
+       p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
+       if (p)
+               return p - strtab;
+
+       *allocated = 1;
+
+       return fdt_add_string_(fdt, s);
+}
+
 int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
 {
        struct fdt_property *prop;
        int nameoff;
+       int allocated;
 
        FDT_SW_PROBE_STRUCT(fdt);
 
-       nameoff = fdt_find_add_string_(fdt, name);
+       /* String de-duplication can be slow, _NO_NAME_DEDUP skips it */
+       if (sw_flags(fdt) & FDT_CREATE_FLAG_NO_NAME_DEDUP) {
+               allocated = 1;
+               nameoff = fdt_add_string_(fdt, name);
+       } else {
+               nameoff = fdt_find_add_string_(fdt, name, &allocated);
+       }
        if (nameoff == 0)
                return -FDT_ERR_NOSPACE;
 
        prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
-       if (! prop)
+       if (! prop) {
+               if (allocated)
+                       fdt_del_last_string_(fdt, name);
                return -FDT_ERR_NOSPACE;
+       }
 
        prop->tag = cpu_to_fdt32(FDT_PROP);
        prop->nameoff = cpu_to_fdt32(nameoff);
@@ -360,6 +367,10 @@ int fdt_finish(void *fdt)
 
        /* Finally, adjust the header */
        fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
+
+       /* And fix up fields that were keeping intermediate state. */
+       fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
        fdt_set_magic(fdt, FDT_MAGIC);
+
        return 0;
 }
index 534c1cb..f64139e 100644 (file)
@@ -1,52 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "libfdt_env.h"
 
index 627da2e..7b5ffd1 100644 (file)
@@ -1,54 +1,9 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
 #ifndef LIBFDT_H
 #define LIBFDT_H
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include "libfdt_env.h"
        /* FDT_ERR_NOPHANDLES: The device tree doesn't have any
         * phandle available anymore without causing an overflow */
 
-#define FDT_ERR_MAX            17
+#define FDT_ERR_BADFLAGS       18
+       /* FDT_ERR_BADFLAGS: The function was passed a flags field that
+        * contains invalid flags or an invalid combination of flags. */
+
+#define FDT_ERR_MAX            18
+
+/* constants */
+#define FDT_MAX_PHANDLE 0xfffffffe
+       /* Valid values for phandles range from 1 to 2^32-2. */
 
 /**********************************************************************/
 /* Low-level functions (you probably don't need these)                */
@@ -171,6 +134,16 @@ static inline uint32_t fdt32_ld(const fdt32_t *p)
                | bp[3];
 }
 
+static inline void fdt32_st(void *property, uint32_t value)
+{
+       uint8_t *bp = property;
+
+       bp[0] = value >> 24;
+       bp[1] = (value >> 16) & 0xff;
+       bp[2] = (value >> 8) & 0xff;
+       bp[3] = value & 0xff;
+}
+
 static inline uint64_t fdt64_ld(const fdt64_t *p)
 {
        const uint8_t *bp = (const uint8_t *)p;
@@ -185,6 +158,20 @@ static inline uint64_t fdt64_ld(const fdt64_t *p)
                | bp[7];
 }
 
+static inline void fdt64_st(void *property, uint64_t value)
+{
+       uint8_t *bp = property;
+
+       bp[0] = value >> 56;
+       bp[1] = (value >> 48) & 0xff;
+       bp[2] = (value >> 40) & 0xff;
+       bp[3] = (value >> 32) & 0xff;
+       bp[4] = (value >> 24) & 0xff;
+       bp[5] = (value >> 16) & 0xff;
+       bp[6] = (value >> 8) & 0xff;
+       bp[7] = value & 0xff;
+}
+
 /**********************************************************************/
 /* Traversal functions                                                */
 /**********************************************************************/
@@ -227,7 +214,7 @@ int fdt_next_subnode(const void *fdt, int offset);
  *             ...
  *     }
  *
- *     if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) {
+ *     if ((node < 0) && (node != -FDT_ERR_NOTFOUND)) {
  *             Error handling
  *     }
  *
@@ -361,6 +348,20 @@ const char *fdt_get_string(const void *fdt, int stroffset, int *lenp);
  */
 const char *fdt_string(const void *fdt, int stroffset);
 
+/**
+ * fdt_find_max_phandle - find and return the highest phandle in a tree
+ * @fdt: pointer to the device tree blob
+ * @phandle: return location for the highest phandle value found in the tree
+ *
+ * fdt_find_max_phandle() finds the highest phandle value in the given device
+ * tree. The value returned in @phandle is only valid if the function returns
+ * success.
+ *
+ * returns:
+ *     0 on success or a negative error code on failure
+ */
+int fdt_find_max_phandle(const void *fdt, uint32_t *phandle);
+
 /**
  * fdt_get_max_phandle - retrieves the highest phandle in a tree
  * @fdt: pointer to the device tree blob
@@ -369,12 +370,39 @@ const char *fdt_string(const void *fdt, int stroffset);
  * device tree. This will ignore badly formatted phandles, or phandles
  * with a value of 0 or -1.
  *
+ * This function is deprecated in favour of fdt_find_max_phandle().
+ *
  * returns:
  *      the highest phandle on success
  *      0, if no phandle was found in the device tree
  *      -1, if an error occurred
  */
-uint32_t fdt_get_max_phandle(const void *fdt);
+static inline uint32_t fdt_get_max_phandle(const void *fdt)
+{
+       uint32_t phandle;
+       int err;
+
+       err = fdt_find_max_phandle(fdt, &phandle);
+       if (err < 0)
+               return (uint32_t)-1;
+
+       return phandle;
+}
+
+/**
+ * fdt_generate_phandle - return a new, unused phandle for a device tree blob
+ * @fdt: pointer to the device tree blob
+ * @phandle: return location for the new phandle
+ *
+ * Walks the device tree blob and looks for the highest phandle value. On
+ * success, the new, unused phandle value (one higher than the previously
+ * highest phandle value in the device tree blob) will be returned in the
+ * @phandle parameter.
+ *
+ * Returns:
+ *   0 on success or a negative error-code on failure
+ */
+int fdt_generate_phandle(const void *fdt, uint32_t *phandle);
 
 /**
  * fdt_num_mem_rsv - retrieve the number of memory reserve map entries
@@ -566,7 +594,7 @@ int fdt_next_property_offset(const void *fdt, int offset);
  *             ...
  *     }
  *
- *     if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) {
+ *     if ((property < 0) && (property != -FDT_ERR_NOTFOUND)) {
  *             Error handling
  *     }
  *
@@ -669,7 +697,7 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
 /**
  * fdt_getprop_by_offset - retrieve the value of a property at a given offset
  * @fdt: pointer to the device tree blob
- * @ffset: offset of the property to read
+ * @offset: offset of the property to read
  * @namep: pointer to a string variable (will be overwritten) or NULL
  * @lenp: pointer to an integer variable (will be overwritten) or NULL
  *
@@ -1360,7 +1388,45 @@ int fdt_nop_node(void *fdt, int nodeoffset);
 /* Sequential write functions                                         */
 /**********************************************************************/
 
+/* fdt_create_with_flags flags */
+#define FDT_CREATE_FLAG_NO_NAME_DEDUP 0x1
+       /* FDT_CREATE_FLAG_NO_NAME_DEDUP: Do not try to de-duplicate property
+        * names in the fdt. This can result in faster creation times, but
+        * a larger fdt. */
+
+#define FDT_CREATE_FLAGS_ALL   (FDT_CREATE_FLAG_NO_NAME_DEDUP)
+
+/**
+ * fdt_create_with_flags - begin creation of a new fdt
+ * @fdt: pointer to memory allocated where fdt will be created
+ * @bufsize: size of the memory space at fdt
+ * @flags: a valid combination of FDT_CREATE_FLAG_ flags, or 0.
+ *
+ * fdt_create_with_flags() begins the process of creating a new fdt with
+ * the sequential write interface.
+ *
+ * fdt creation process must end with fdt_finished() to produce a valid fdt.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt
+ *     -FDT_ERR_BADFLAGS, flags is not valid
+ */
+int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags);
+
+/**
+ * fdt_create - begin creation of a new fdt
+ * @fdt: pointer to memory allocated where fdt will be created
+ * @bufsize: size of the memory space at fdt
+ *
+ * fdt_create() is equivalent to fdt_create_with_flags() with flags=0.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt
+ */
 int fdt_create(void *buf, int bufsize);
+
 int fdt_resize(void *fdt, void *buf, int bufsize);
 int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
 int fdt_finish_reservemap(void *fdt);
@@ -1831,6 +1897,43 @@ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset,
 #define fdt_appendprop_string(fdt, nodeoffset, name, str) \
        fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
 
+/**
+ * fdt_appendprop_addrrange - append a address range property
+ * @fdt: pointer to the device tree blob
+ * @parent: offset of the parent node
+ * @nodeoffset: offset of the node to add a property at
+ * @name: name of property
+ * @addr: start address of a given range
+ * @size: size of a given range
+ *
+ * fdt_appendprop_addrrange() appends an address range value (start
+ * address and size) to the value of the named property in the given
+ * node, or creates a new property with that value if it does not
+ * already exist.
+ * If "name" is not specified, a default "reg" is used.
+ * Cell sizes are determined by parent's #address-cells and #size-cells.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ *             #address-cells property
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADVALUE, addr or size doesn't fit to respective cells size
+ *     -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *             contain a new property
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
+                            const char *name, uint64_t addr, uint64_t size);
+
 /**
  * fdt_delprop - delete a property
  * @fdt: pointer to the device tree blob
index eb20538..73b6d40 100644 (file)
@@ -1,57 +1,13 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
 #ifndef LIBFDT_ENV_H
 #define LIBFDT_ENV_H
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
  * Copyright 2012 Kim Phillips, Freescale Semiconductor.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <stdlib.h>
index 4109f89..7830e55 100644 (file)
@@ -1,54 +1,9 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
 #ifndef LIBFDT_INTERNAL_H
 #define LIBFDT_INTERNAL_H
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include <fdt.h>
 
index 3275231..0c03999 100644 (file)
@@ -234,6 +234,7 @@ struct node * add_orphan_node(struct node *dt, struct node *new_node, char *ref)
        char *name;
 
        if (ref[0] == '/') {
+               d = data_add_marker(d, TYPE_STRING, ref);
                d = data_append_data(d, ref, strlen(ref) + 1);
 
                p = build_property("target-path", d, NULL);
@@ -335,17 +336,20 @@ void delete_node(struct node *node)
 }
 
 void append_to_property(struct node *node,
-                                   char *name, const void *data, int len)
+                       char *name, const void *data, int len,
+                       enum markertype type)
 {
        struct data d;
        struct property *p;
 
        p = get_property(node, name);
        if (p) {
-               d = data_append_data(p->val, data, len);
+               d = data_add_marker(p->val, type, name);
+               d = data_append_data(d, data, len);
                p->val = d;
        } else {
-               d = data_append_data(empty_data, data, len);
+               d = data_add_marker(empty_data, type, name);
+               d = data_append_data(d, data, len);
                p = build_property(name, d, NULL);
                add_property(node, p);
        }
@@ -843,8 +847,8 @@ static void generate_label_tree_internal(struct dt_info *dti,
 
                        /* insert it */
                        p = build_property(l->label,
-                               data_copy_mem(node->fullpath,
-                                               strlen(node->fullpath) + 1),
+                               data_copy_escape_string(node->fullpath,
+                                               strlen(node->fullpath)),
                                NULL);
                        add_property(an, p);
                }
@@ -895,7 +899,7 @@ static void add_fixup_entry(struct dt_info *dti, struct node *fn,
 
        xasprintf(&entry, "%s:%s:%u",
                        node->fullpath, prop->name, m->offset);
-       append_to_property(fn, m->ref, entry, strlen(entry) + 1);
+       append_to_property(fn, m->ref, entry, strlen(entry) + 1, TYPE_STRING);
 
        free(entry);
 }
@@ -955,7 +959,7 @@ static void add_local_fixup_entry(struct dt_info *dti,
        char **compp;
        int i, depth;
 
-       /* walk back retreiving depth */
+       /* walk back retrieving depth */
        depth = 0;
        for (wn = node; wn; wn = wn->parent)
                depth++;
@@ -978,7 +982,7 @@ static void add_local_fixup_entry(struct dt_info *dti,
        free(compp);
 
        value_32 = cpu_to_fdt32(m->offset);
-       append_to_property(wn, prop->name, &value_32, sizeof(value_32));
+       append_to_property(wn, prop->name, &value_32, sizeof(value_32), TYPE_UINT32);
 }
 
 static void generate_local_fixups_tree_internal(struct dt_info *dti,
index 11a5614..ca5cb52 100644 (file)
@@ -108,7 +108,7 @@ int utilfdt_read_err(const char *filename, char **buffp, size_t *len);
  * stderr.
  *
  * @param filename     The filename to write, or - for stdout
- * @param blob         Poiner to buffer containing fdt
+ * @param blob         Pointer to buffer containing fdt
  * @return 0 if ok, -1 on error
  */
 int utilfdt_write(const char *filename, const void *blob);
@@ -119,7 +119,7 @@ int utilfdt_write(const char *filename, const void *blob);
  * an error message for the user.
  *
  * @param filename     The filename to write, or - for stdout
- * @param blob         Poiner to buffer containing fdt
+ * @param blob         Pointer to buffer containing fdt
  * @return 0 if ok, else an errno value representing the error
  */
 int utilfdt_write_err(const char *filename, const void *blob);
index 75f383c..f2761e2 100644 (file)
@@ -1 +1 @@
-#define DTC_VERSION "DTC 1.4.7-gf267e674"
+#define DTC_VERSION "DTC 1.5.0-g702c1b6c"
index 9fd3d8e..1247550 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 
-ifneq ($(srctree),.)
+ifdef building_out_of_srctree
 
 symlinks := $(patsubst $(srctree)/$(src)/%,%,$(wildcard $(srctree)/$(src)/*.py))
 
index e93336b..c586d32 100644 (file)
@@ -25,6 +25,10 @@ static struct resword {
        { "__volatile__", VOLATILE_KEYW },
        { "__builtin_va_list", VA_LIST_KEYW },
 
+       { "__int128", BUILTIN_INT_KEYW },
+       { "__int128_t", BUILTIN_INT_KEYW },
+       { "__uint128_t", BUILTIN_INT_KEYW },
+
        // According to rth, c99 defines "_Bool", __restrict", __restrict__", "restrict".  KAO
        { "_Bool", BOOL_KEYW },
        { "_restrict", RESTRICT_KEYW },
index 00a6d7e..1ebcf52 100644 (file)
@@ -76,6 +76,7 @@ static void record_compound(struct string_list **keyw,
 %token ATTRIBUTE_KEYW
 %token AUTO_KEYW
 %token BOOL_KEYW
+%token BUILTIN_INT_KEYW
 %token CHAR_KEYW
 %token CONST_KEYW
 %token DOUBLE_KEYW
@@ -263,6 +264,7 @@ simple_type_specifier:
        | VOID_KEYW
        | BOOL_KEYW
        | VA_LIST_KEYW
+       | BUILTIN_INT_KEYW
        | TYPE                  { (*$1)->tag = SYM_TYPEDEF; $$ = $1; }
        ;
 
diff --git a/scripts/get_abi.pl b/scripts/get_abi.pl
new file mode 100755 (executable)
index 0000000..c738cb7
--- /dev/null
@@ -0,0 +1,468 @@
+#!/usr/bin/perl
+# SPDX-License-Identifier: GPL-2.0
+
+use strict;
+use Pod::Usage;
+use Getopt::Long;
+use File::Find;
+use Fcntl ':mode';
+
+my $help;
+my $man;
+my $debug;
+my $prefix="Documentation/ABI";
+
+GetOptions(
+       "debug|d+" => \$debug,
+       "dir=s" => \$prefix,
+       'help|?' => \$help,
+       man => \$man
+) or pod2usage(2);
+
+pod2usage(1) if $help;
+pod2usage(-exitstatus => 0, -verbose => 2) if $man;
+
+pod2usage(2) if (scalar @ARGV < 1 || @ARGV > 2);
+
+my ($cmd, $arg) = @ARGV;
+
+pod2usage(2) if ($cmd ne "search" && $cmd ne "rest" && $cmd ne "validate");
+pod2usage(2) if ($cmd eq "search" && !$arg);
+
+require Data::Dumper if ($debug);
+
+my %data;
+
+#
+# Displays an error message, printing file name and line
+#
+sub parse_error($$$$) {
+       my ($file, $ln, $msg, $data) = @_;
+
+       print STDERR "file $file#$ln: $msg at\n\t$data";
+}
+
+#
+# Parse an ABI file, storing its contents at %data
+#
+sub parse_abi {
+       my $file = $File::Find::name;
+
+       my $mode = (stat($file))[2];
+       return if ($mode & S_IFDIR);
+       return if ($file =~ m,/README,);
+
+       my $name = $file;
+       $name =~ s,.*/,,;
+
+       my $nametag = "File $name";
+       $data{$nametag}->{what} = "File $name";
+       $data{$nametag}->{type} = "File";
+       $data{$nametag}->{file} = $name;
+       $data{$nametag}->{filepath} = $file;
+       $data{$nametag}->{is_file} = 1;
+
+       my $type = $file;
+       $type =~ s,.*/(.*)/.*,$1,;
+
+       my $what;
+       my $new_what;
+       my $tag;
+       my $ln;
+       my $xrefs;
+       my $space;
+       my @labels;
+       my $label;
+
+       print STDERR "Opening $file\n" if ($debug > 1);
+       open IN, $file;
+       while(<IN>) {
+               $ln++;
+               if (m/^(\S+)(:\s*)(.*)/i) {
+                       my $new_tag = lc($1);
+                       my $sep = $2;
+                       my $content = $3;
+
+                       if (!($new_tag =~ m/(what|where|date|kernelversion|contact|description|users)/)) {
+                               if ($tag eq "description") {
+                                       # New "tag" is actually part of
+                                       # description. Don't consider it a tag
+                                       $new_tag = "";
+                               } elsif ($tag ne "") {
+                                       parse_error($file, $ln, "tag '$tag' is invalid", $_);
+                               }
+                       }
+
+                       # Invalid, but it is a common mistake
+                       if ($new_tag eq "where") {
+                               parse_error($file, $ln, "tag 'Where' is invalid. Should be 'What:' instead", $_);
+                               $new_tag = "what";
+                       }
+
+                       if ($new_tag =~ m/what/) {
+                               $space = "";
+                               if ($tag =~ m/what/) {
+                                       $what .= ", " . $content;
+                               } else {
+                                       parse_error($file, $ln, "What '$what' doesn't have a description", "") if ($what && !$data{$what}->{description});
+
+                                       $what = $content;
+                                       $label = $content;
+                                       $new_what = 1;
+                               }
+                               push @labels, [($content, $label)];
+                               $tag = $new_tag;
+
+                               push @{$data{$nametag}->{xrefs}}, [($content, $label)] if ($data{$nametag}->{what});
+                               next;
+                       }
+
+                       if ($tag ne "" && $new_tag) {
+                               $tag = $new_tag;
+
+                               if ($new_what) {
+                                       @{$data{$what}->{label}} = @labels if ($data{$nametag}->{what});
+                                       @labels = ();
+                                       $label = "";
+                                       $new_what = 0;
+
+                                       $data{$what}->{type} = $type;
+                                       $data{$what}->{file} = $name;
+                                       $data{$what}->{filepath} = $file;
+                                       print STDERR "\twhat: $what\n" if ($debug > 1);
+                               }
+
+                               if (!$what) {
+                                       parse_error($file, $ln, "'What:' should come first:", $_);
+                                       next;
+                               }
+                               if ($tag eq "description") {
+                                       next if ($content =~ m/^\s*$/);
+                                       if ($content =~ m/^(\s*)(.*)/) {
+                                               my $new_content = $2;
+                                               $space = $new_tag . $sep . $1;
+                                               while ($space =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {}
+                                               $space =~ s/./ /g;
+                                               $data{$what}->{$tag} .= "$new_content\n";
+                                       }
+                               } else {
+                                       $data{$what}->{$tag} = $content;
+                               }
+                               next;
+                       }
+               }
+
+               # Store any contents before tags at the database
+               if (!$tag && $data{$nametag}->{what}) {
+                       $data{$nametag}->{description} .= $_;
+                       next;
+               }
+
+               if ($tag eq "description") {
+                       if (!$data{$what}->{description}) {
+                               next if (m/^\s*\n/);
+                               if (m/^(\s*)(.*)/) {
+                                       $space = $1;
+                                       while ($space =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {}
+                                       $data{$what}->{$tag} .= "$2\n";
+                               }
+                       } else {
+                               my $content = $_;
+                               if (m/^\s*\n/) {
+                                       $data{$what}->{$tag} .= $content;
+                                       next;
+                               }
+
+                               while ($content =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {}
+                               $space = "" if (!($content =~ s/^($space)//));
+
+                               # Compress spaces with tabs
+                               $content =~ s<^ {8}> <\t>;
+                               $content =~ s<^ {1,7}\t> <\t>;
+                               $content =~ s< {1,7}\t> <\t>;
+                               $data{$what}->{$tag} .= $content;
+                       }
+                       next;
+               }
+               if (m/^\s*(.*)/) {
+                       $data{$what}->{$tag} .= "\n$1";
+                       $data{$what}->{$tag} =~ s/\n+$//;
+                       next;
+               }
+
+               # Everything else is error
+               parse_error($file, $ln, "Unexpected line:", $_);
+       }
+       $data{$nametag}->{description} =~ s/^\n+//;
+       close IN;
+}
+
+#
+# Outputs the book on ReST format
+#
+
+my %labels;
+
+sub output_rest {
+       foreach my $what (sort {
+                               ($data{$a}->{type} eq "File") cmp ($data{$b}->{type} eq "File") ||
+                               $a cmp $b
+                              } keys %data) {
+               my $type = $data{$what}->{type};
+               my $file = $data{$what}->{file};
+               my $filepath = $data{$what}->{filepath};
+
+               my $w = $what;
+               $w =~ s/([\(\)\_\-\*\=\^\~\\])/\\$1/g;
+
+
+               foreach my $p (@{$data{$what}->{label}}) {
+                       my ($content, $label) = @{$p};
+                       $label = "abi_" . $label . " ";
+                       $label =~ tr/A-Z/a-z/;
+
+                       # Convert special chars to "_"
+                       $label =~s/([\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\xff])/_/g;
+                       $label =~ s,_+,_,g;
+                       $label =~ s,_$,,;
+
+                       # Avoid duplicated labels
+                       while (defined($labels{$label})) {
+                           my @chars = ("A".."Z", "a".."z");
+                           $label .= $chars[rand @chars];
+                       }
+                       $labels{$label} = 1;
+
+                       $data{$what}->{label} .= $label;
+
+                       printf ".. _%s:\n\n", $label;
+
+                       # only one label is enough
+                       last;
+               }
+
+
+               $filepath =~ s,.*/(.*/.*),\1,;;
+               $filepath =~ s,[/\-],_,g;;
+               my $fileref = "abi_file_".$filepath;
+
+               if ($type eq "File") {
+                       my $bar = $w;
+                       $bar =~ s/./-/g;
+
+                       print ".. _$fileref:\n\n";
+                       print "$w\n$bar\n\n";
+               } else {
+                       my @names = split /\s*,\s*/,$w;
+
+                       my $len = 0;
+
+                       foreach my $name (@names) {
+                               $len = length($name) if (length($name) > $len);
+                       }
+
+                       print "What:\n\n";
+
+                       print "+-" . "-" x $len . "-+\n";
+                       foreach my $name (@names) {
+                               printf "| %s", $name . " " x ($len - length($name)) . " |\n";
+                               print "+-" . "-" x $len . "-+\n";
+                       }
+                       print "\n";
+               }
+
+               print "Defined on file :ref:`$file <$fileref>`\n\n" if ($type ne "File");
+
+               my $desc = $data{$what}->{description};
+               $desc =~ s/^\s+//;
+
+               # Remove title markups from the description, as they won't work
+               $desc =~ s/\n[\-\*\=\^\~]+\n/\n/g;
+
+               if (!($desc =~ /^\s*$/)) {
+                       if ($desc =~ m/\:\n/ || $desc =~ m/\n[\t ]+/  || $desc =~ m/[\x00-\x08\x0b-\x1f\x7b-\xff]/) {
+                               # put everything inside a code block
+                               $desc =~ s/\n/\n /g;
+
+                               print "::\n\n";
+                               print " $desc\n\n";
+                       } else {
+                               # Escape any special chars from description
+                               $desc =~s/([\x00-\x08\x0b-\x1f\x21-\x2a\x2d\x2f\x3c-\x40\x5c\x5e-\x60\x7b-\xff])/\\$1/g;
+
+                               print "$desc\n\n";
+                       }
+               } else {
+                       print "DESCRIPTION MISSING for $what\n\n" if (!$data{$what}->{is_file});
+               }
+
+               if ($data{$what}->{xrefs}) {
+                       printf "Has the following ABI:\n\n";
+
+                       foreach my $p(@{$data{$what}->{xrefs}}) {
+                               my ($content, $label) = @{$p};
+                               $label = "abi_" . $label . " ";
+                               $label =~ tr/A-Z/a-z/;
+
+                               # Convert special chars to "_"
+                               $label =~s/([\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\xff])/_/g;
+                               $label =~ s,_+,_,g;
+                               $label =~ s,_$,,;
+
+                               # Escape special chars from content
+                               $content =~s/([\x00-\x1f\x21-\x2f\x3a-\x40\x7b-\xff])/\\$1/g;
+
+                               print "- :ref:`$content <$label>`\n\n";
+                       }
+               }
+       }
+}
+
+#
+# Searches for ABI symbols
+#
+sub search_symbols {
+       foreach my $what (sort keys %data) {
+               next if (!($what =~ m/($arg)/));
+
+               my $type = $data{$what}->{type};
+               next if ($type eq "File");
+
+               my $file = $data{$what}->{filepath};
+
+               my $bar = $what;
+               $bar =~ s/./-/g;
+
+               print "\n$what\n$bar\n\n";
+
+               my $kernelversion = $data{$what}->{kernelversion};
+               my $contact = $data{$what}->{contact};
+               my $users = $data{$what}->{users};
+               my $date = $data{$what}->{date};
+               my $desc = $data{$what}->{description};
+               $kernelversion =~ s/^\s+//;
+               $contact =~ s/^\s+//;
+               $users =~ s/^\s+//;
+               $users =~ s/\n//g;
+               $date =~ s/^\s+//;
+               $desc =~ s/^\s+//;
+
+               printf "Kernel version:\t\t%s\n", $kernelversion if ($kernelversion);
+               printf "Date:\t\t\t%s\n", $date if ($date);
+               printf "Contact:\t\t%s\n", $contact if ($contact);
+               printf "Users:\t\t\t%s\n", $users if ($users);
+               print "Defined on file:\t$file\n\n";
+               print "Description:\n\n$desc";
+       }
+}
+
+
+#
+# Parses all ABI files located at $prefix dir
+#
+find({wanted =>\&parse_abi, no_chdir => 1}, $prefix);
+
+print STDERR Data::Dumper->Dump([\%data], [qw(*data)]) if ($debug);
+
+#
+# Handles the command
+#
+if ($cmd eq "rest") {
+       output_rest;
+} elsif ($cmd eq "search") {
+       search_symbols;
+}
+
+
+__END__
+
+=head1 NAME
+
+abi_book.pl - parse the Linux ABI files and produce a ReST book.
+
+=head1 SYNOPSIS
+
+B<abi_book.pl> [--debug] [--man] [--help] [--dir=<dir>] <COMAND> [<ARGUMENT>]
+
+Where <COMMAND> can be:
+
+=over 8
+
+B<search> [SEARCH_REGEX] - search for [SEARCH_REGEX] inside ABI
+
+B<rest>                  - output the ABI in ReST markup language
+
+B<validate>              - validate the ABI contents
+
+=back
+
+=head1 OPTIONS
+
+=over 8
+
+=item B<--dir>
+
+Changes the location of the ABI search. By default, it uses
+the Documentation/ABI directory.
+
+=item B<--debug>
+
+Put the script in verbose mode, useful for debugging. Can be called multiple
+times, to increase verbosity.
+
+=item B<--help>
+
+Prints a brief help message and exits.
+
+=item B<--man>
+
+Prints the manual page and exits.
+
+=back
+
+=head1 DESCRIPTION
+
+Parse the Linux ABI files from ABI DIR (usually located at Documentation/ABI),
+allowing to search for ABI symbols or to produce a ReST book containing
+the Linux ABI documentation.
+
+=head1 EXAMPLES
+
+Search for all stable symbols with the word "usb":
+
+=over 8
+
+$ scripts/get_abi.pl search usb --dir Documentation/ABI/stable
+
+=back
+
+Search for all symbols that match the regex expression "usb.*cap":
+
+=over 8
+
+$ scripts/get_abi.pl search usb.*cap
+
+=back
+
+Output all obsoleted symbols in ReST format
+
+=over 8
+
+$ scripts/get_abi.pl rest --dir Documentation/ABI/obsolete
+
+=back
+
+=head1 BUGS
+
+Report bugs to Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
+
+=head1 COPYRIGHT
+
+Copyright (c) 2016-2019 by Mauro Carvalho Chehab <mchehab+samsung@kernel.org>.
+
+License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>.
+
+This is free software: you are free to change and redistribute it.
+There is NO WARRANTY, to the extent permitted by law.
+
+=cut
diff --git a/scripts/headers.sh b/scripts/headers.sh
deleted file mode 100755 (executable)
index e0f883e..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Run headers_$1 command for all suitable architectures
-
-# Stop on error
-set -e
-
-do_command()
-{
-       if [ -f ${srctree}/arch/$2/include/asm/Kbuild ]; then
-               make ARCH=$2 KBUILD_HEADERS=$1 headers_$1
-       else
-               printf "Ignoring arch: %s\n" ${arch}
-       fi
-}
-
-archs=${HDR_ARCH_LIST:-$(ls ${srctree}/arch)}
-
-for arch in ${archs}; do
-       case ${arch} in
-       um)        # no userspace export
-               ;;
-       *)
-               if [ -d ${srctree}/arch/${arch} ]; then
-                       do_command $1 ${arch}
-               fi
-               ;;
-       esac
-done
index 593f887..47f6f3e 100755 (executable)
@@ -1,47 +1,39 @@
 #!/bin/sh
 # SPDX-License-Identifier: GPL-2.0
 
-if [ $# -lt 2 ]
+if [ $# -ne 2 ]
 then
-       echo "Usage: headers_install.sh OUTDIR SRCDIR [FILES...]"
+       echo "Usage: headers_install.sh INFILE OUTFILE"
        echo
        echo "Prepares kernel header files for use by user space, by removing"
        echo "all compiler.h definitions and #includes, removing any"
        echo "#ifdef __KERNEL__ sections, and putting __underscores__ around"
        echo "asm/inline/volatile keywords."
        echo
-       echo "OUTDIR: directory to write each userspace header FILE to."
-       echo "SRCDIR: source directory where files are picked."
-       echo "FILES:  list of header files to operate on."
+       echo "INFILE: header file to operate on"
+       echo "OUTFILE: output file which the processed header is writen to"
 
        exit 1
 fi
 
 # Grab arguments
+INFILE=$1
+OUTFILE=$2
+TMPFILE=$OUTFILE.tmp
 
-OUTDIR="$1"
-shift
-SRCDIR="$1"
-shift
+trap 'rm -f $OUTFILE $TMPFILE' EXIT
 
-# Iterate through files listed on command line
+sed -E -e '
+       s/([[:space:](])(__user|__force|__iomem)[[:space:]]/\1/g
+       s/__attribute_const__([[:space:]]|$)/\1/g
+       s@^#include <linux/compiler(|_types).h>@@
+       s/(^|[^a-zA-Z0-9])__packed([^a-zA-Z0-9_]|$)/\1__attribute__((packed))\2/g
+       s/(^|[[:space:](])(inline|asm|volatile)([[:space:](]|$)/\1__\2__\3/g
+       s@#(ifndef|define|endif[[:space:]]*/[*])[[:space:]]*_UAPI@#\1 @
+' $INFILE > $TMPFILE || exit 1
 
-FILE=
-trap 'rm -f "$OUTDIR/$FILE" "$OUTDIR/$FILE.sed"' EXIT
-for i in "$@"
-do
-       FILE="$(basename "$i")"
-       sed -E \
-               -e 's/([[:space:](])(__user|__force|__iomem)[[:space:]]/\1/g' \
-               -e 's/__attribute_const__([[:space:]]|$)/\1/g' \
-               -e 's@^#include <linux/compiler(|_types).h>@@' \
-               -e 's/(^|[^a-zA-Z0-9])__packed([^a-zA-Z0-9_]|$)/\1__attribute__((packed))\2/g' \
-               -e 's/(^|[[:space:](])(inline|asm|volatile)([[:space:](]|$)/\1__\2__\3/g' \
-               -e 's@#(ifndef|define|endif[[:space:]]*/[*])[[:space:]]*_UAPI@#\1 @' \
-               "$SRCDIR/$i" > "$OUTDIR/$FILE.sed" || exit 1
-       scripts/unifdef -U__KERNEL__ -D__EXPORTED_HEADERS__ "$OUTDIR/$FILE.sed" \
-               > "$OUTDIR/$FILE"
-       [ $? -gt 1 ] && exit 1
-       rm -f "$OUTDIR/$FILE.sed"
-done
+scripts/unifdef -U__KERNEL__ -D__EXPORTED_HEADERS__ $TMPFILE > $OUTFILE
+[ $? -gt 1 ] && exit 1
+
+rm -f $TMPFILE
 trap - EXIT
index e17837f..ae6504d 100644 (file)
@@ -150,6 +150,9 @@ static int read_symbol(FILE *in, struct sym_entry *s)
        /* exclude debugging symbols */
        else if (stype == 'N' || stype == 'n')
                return -1;
+       /* exclude s390 kasan local symbols */
+       else if (!strncmp(sym, ".LASANPC", 8))
+               return -1;
 
        /* include the type field in the symbol name, so that it gets
         * compressed together */
index 3f327e2..ab30fe7 100644 (file)
@@ -12,6 +12,10 @@ else
 Kconfig := Kconfig
 endif
 
+ifndef KBUILD_DEFCONFIG
+KBUILD_DEFCONFIG := defconfig
+endif
+
 ifeq ($(quiet),silent_)
 silent := -s
 endif
@@ -74,9 +78,7 @@ savedefconfig: $(obj)/conf
        $< $(silent) --$@=defconfig $(Kconfig)
 
 defconfig: $(obj)/conf
-ifeq ($(KBUILD_DEFCONFIG),)
-       $< $(silent) --defconfig $(Kconfig)
-else ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG)),)
+ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG)),)
        @$(kecho) "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'"
        $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig)
 else
index ef3678c..40e16e8 100644 (file)
@@ -90,7 +90,7 @@ static int conf_askvalue(struct symbol *sym, const char *def)
        line[0] = '\n';
        line[1] = 0;
 
-       if (!sym_is_changable(sym)) {
+       if (!sym_is_changeable(sym)) {
                printf("%s\n", def);
                line[0] = '\n';
                line[1] = 0;
@@ -234,7 +234,7 @@ static int conf_choice(struct menu *menu)
 
        sym = menu->sym;
        is_new = !sym_has_value(sym);
-       if (sym_is_changable(sym)) {
+       if (sym_is_changeable(sym)) {
                conf_sym(menu);
                sym_calc_value(sym);
                switch (sym_get_tristate_value(sym)) {
@@ -418,7 +418,7 @@ static void check_conf(struct menu *menu)
 
        sym = menu->sym;
        if (sym && !sym_has_value(sym)) {
-               if (sym_is_changable(sym) ||
+               if (sym_is_changeable(sym) ||
                    (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
                        if (input_mode == listnewconfig) {
                                if (sym->name) {
@@ -451,7 +451,7 @@ static struct option long_opts[] = {
        {"oldaskconfig",    no_argument,       NULL, oldaskconfig},
        {"oldconfig",       no_argument,       NULL, oldconfig},
        {"syncconfig",      no_argument,       NULL, syncconfig},
-       {"defconfig",       optional_argument, NULL, defconfig},
+       {"defconfig",       required_argument, NULL, defconfig},
        {"savedefconfig",   required_argument, NULL, savedefconfig},
        {"allnoconfig",     no_argument,       NULL, allnoconfig},
        {"allyesconfig",    no_argument,       NULL, allyesconfig},
@@ -562,8 +562,6 @@ int main(int ac, char **av)
 
        switch (input_mode) {
        case defconfig:
-               if (!defconfig_file)
-                       defconfig_file = conf_get_default_confname();
                if (conf_read(defconfig_file)) {
                        fprintf(stderr,
                                "***\n"
index 6006154..501fdcc 100644 (file)
@@ -177,8 +177,6 @@ static void conf_message(const char *fmt, ...)
 static const char *conf_filename;
 static int conf_lineno, conf_warnings;
 
-const char conf_defname[] = "arch/$(ARCH)/defconfig";
-
 static void conf_warning(const char *fmt, ...)
 {
        va_list ap;
@@ -233,21 +231,6 @@ static const char *conf_get_autoconfig_name(void)
        return name ? name : "include/config/auto.conf";
 }
 
-char *conf_get_default_confname(void)
-{
-       static char fullname[PATH_MAX+1];
-       char *env, *name;
-
-       name = expand_string(conf_defname);
-       env = getenv(SRCTREE);
-       if (env) {
-               snprintf(fullname, sizeof(fullname), "%s/%s", env, name);
-               if (is_present(fullname))
-                       return fullname;
-       }
-       return name;
-}
-
 static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
 {
        char *p2;
@@ -551,11 +534,9 @@ int conf_read(const char *name)
                        switch (sym->type) {
                        case S_BOOLEAN:
                        case S_TRISTATE:
-                               if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))
-                                       break;
-                               if (!sym_is_choice(sym))
+                               if (sym->def[S_DEF_USER].tri == sym_get_tristate_value(sym))
                                        continue;
-                               /* fall through */
+                               break;
                        default:
                                if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
                                        continue;
@@ -813,7 +794,7 @@ int conf_write_defconfig(const char *filename)
                                goto next_menu;
                        sym->flags &= ~SYMBOL_WRITE;
                        /* If we cannot change the symbol - skip */
-                       if (!sym_is_changable(sym))
+                       if (!sym_is_changeable(sym))
                                goto next_menu;
                        /* If symbol equals to default value - skip */
                        if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0)
index cbc7658..4fb16f3 100644 (file)
@@ -49,7 +49,6 @@ const char *zconf_curname(void);
 
 /* confdata.c */
 const char *conf_get_configname(void);
-char *conf_get_default_confname(void);
 void sym_set_change_count(int count);
 void sym_add_change_count(int count);
 bool conf_set_all_new_symbols(enum conf_def_mode mode);
index 86c2675..f9ab982 100644 (file)
@@ -42,7 +42,7 @@ tristate sym_toggle_tristate_value(struct symbol *sym);
 bool sym_string_valid(struct symbol *sym, const char *newval);
 bool sym_string_within_range(struct symbol *sym, const char *str);
 bool sym_set_string_value(struct symbol *sym, const char *newval);
-bool sym_is_changable(struct symbol *sym);
+bool sym_is_changeable(struct symbol *sym);
 struct property * sym_get_choice_prop(struct symbol *sym);
 const char * sym_get_string_value(struct symbol *sym);
 
@@ -58,7 +58,6 @@ void env_write_dep(FILE *f, const char *auto_conf_name);
 void variable_add(const char *name, const char *value,
                  enum variable_flavor flavor);
 void variable_all_del(void);
-char *expand_string(const char *in);
 char *expand_dollar(const char **str);
 char *expand_one_token(const char **str);
 
index 694091f..49c26ea 100644 (file)
@@ -536,7 +536,7 @@ static void build_conf(struct menu *menu)
                }
 
                val = sym_get_tristate_value(sym);
-               if (sym_is_changable(sym)) {
+               if (sym_is_changeable(sym)) {
                        switch (type) {
                        case S_BOOLEAN:
                                item_make("[%c]", val == no ? ' ' : '*');
@@ -587,7 +587,7 @@ static void build_conf(struct menu *menu)
                } else {
                        switch (type) {
                        case S_BOOLEAN:
-                               if (sym_is_changable(sym))
+                               if (sym_is_changeable(sym))
                                        item_make("[%c]", val == no ? ' ' : '*');
                                else
                                        item_make("-%c-", val == no ? ' ' : '*');
@@ -600,7 +600,7 @@ static void build_conf(struct menu *menu)
                                case mod: ch = 'M'; break;
                                default:  ch = ' '; break;
                                }
-                               if (sym_is_changable(sym)) {
+                               if (sym_is_changeable(sym)) {
                                        if (sym->rev_dep.tri == mod)
                                                item_make("{%c}", ch);
                                        else
@@ -617,7 +617,7 @@ static void build_conf(struct menu *menu)
                                if (tmp < 0)
                                        tmp = 0;
                                item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
-                                            (sym_has_value(sym) || !sym_is_changable(sym)) ?
+                                            (sym_has_value(sym) || !sym_is_changeable(sym)) ?
                                             "" : " (NEW)");
                                item_set_tag('s');
                                item_set_data(menu);
@@ -625,7 +625,7 @@ static void build_conf(struct menu *menu)
                        }
                }
                item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
-                         (sym_has_value(sym) || !sym_is_changable(sym)) ?
+                         (sym_has_value(sym) || !sym_is_changeable(sym)) ?
                          "" : " (NEW)");
                if (menu->prompt->type == P_MENU) {
                        item_add_str("  %s", menu_is_empty(menu) ? "----" : "--->");
index cbafe3b..b7c1ef7 100644 (file)
@@ -803,7 +803,7 @@ static void build_conf(struct menu *menu)
                }
 
                val = sym_get_tristate_value(sym);
-               if (sym_is_changable(sym)) {
+               if (sym_is_changeable(sym)) {
                        switch (type) {
                        case S_BOOLEAN:
                                item_make(menu, 't', "[%c]",
@@ -857,7 +857,7 @@ static void build_conf(struct menu *menu)
                } else {
                        switch (type) {
                        case S_BOOLEAN:
-                               if (sym_is_changable(sym))
+                               if (sym_is_changeable(sym))
                                        item_make(menu, 't', "[%c]",
                                                val == no ? ' ' : '*');
                                else
@@ -876,7 +876,7 @@ static void build_conf(struct menu *menu)
                                        ch = ' ';
                                        break;
                                }
-                               if (sym_is_changable(sym)) {
+                               if (sym_is_changeable(sym)) {
                                        if (sym->rev_dep.tri == mod)
                                                item_make(menu,
                                                        't', "{%c}", ch);
@@ -896,14 +896,14 @@ static void build_conf(struct menu *menu)
                                item_add_str("%*c%s%s", tmp, ' ',
                                                menu_get_prompt(menu),
                                                (sym_has_value(sym) ||
-                                                !sym_is_changable(sym)) ? "" :
+                                                !sym_is_changeable(sym)) ? "" :
                                                " (NEW)");
                                goto conf_childs;
                        }
                }
                item_add_str("%*c%s%s", indent + 1, ' ',
                                menu_get_prompt(menu),
-                               (sym_has_value(sym) || !sym_is_changable(sym)) ?
+                               (sym_has_value(sym) || !sym_is_changeable(sym)) ?
                                "" : " (NEW)");
                if (menu->prompt && menu->prompt->type == P_MENU) {
                        item_add_str("  %s", menu_is_empty(menu) ? "----" : "--->");
index 592dfbf..0243086 100644 (file)
@@ -15,6 +15,7 @@
 #define ARRAY_SIZE(arr)                (sizeof(arr) / sizeof((arr)[0]))
 
 static char *expand_string_with_args(const char *in, int argc, char *argv[]);
+static char *expand_string(const char *in);
 
 static void __attribute__((noreturn)) pperror(const char *format, ...)
 {
@@ -550,7 +551,7 @@ static char *expand_string_with_args(const char *in, int argc, char *argv[])
        return __expand_string(&in, is_end_of_str, argc, argv);
 }
 
-char *expand_string(const char *in)
+static char *expand_string(const char *in)
 {
        return expand_string_with_args(in, 0, NULL);
 }
index ce7fc87..82773cc 100644 (file)
@@ -152,7 +152,7 @@ void ConfigItem::updateMenu(void)
        case S_TRISTATE:
                char ch;
 
-               if (!sym_is_changable(sym) && list->optMode == normalOpt) {
+               if (!sym_is_changeable(sym) && list->optMode == normalOpt) {
                        setPixmap(promptColIdx, QIcon());
                        setText(noColIdx, QString::null);
                        setText(modColIdx, QString::null);
index 09fd6fa..f56eec5 100644 (file)
@@ -785,7 +785,7 @@ const char *sym_get_string_value(struct symbol *sym)
        return (const char *)sym->curr.val;
 }
 
-bool sym_is_changable(struct symbol *sym)
+bool sym_is_changeable(struct symbol *sym)
 {
        return sym->visible > sym->rev_dep.tri;
 }
index b03dd56..e8ca6dc 100755 (executable)
@@ -130,7 +130,7 @@ if is_enabled CONFIG_MODULES; then
 fi
 
 if [ "$ARCH" != "um" ]; then
-       $MAKE -f $srctree/Makefile headers_check
+       $MAKE -f $srctree/Makefile headers
        $MAKE -f $srctree/Makefile headers_install INSTALL_HDR_PATH="$libc_headers_dir/usr"
 fi
 
index 009147d..2d29df4 100755 (executable)
@@ -31,7 +31,7 @@ PROVIDES="$PROVIDES kernel-$KERNELRELEASE"
 __KERNELRELEASE=$(echo $KERNELRELEASE | sed -e "s/-/_/g")
 EXCLUDES="$RCS_TAR_IGNORE --exclude=.tmp_versions --exclude=*vmlinux* \
 --exclude=*.o --exclude=*.ko --exclude=*.cmd --exclude=Documentation \
---exclude=.config.old --exclude=.missing-syscalls.d"
+--exclude=.config.old --exclude=.missing-syscalls.d --exclude=*.s"
 
 # We can label the here-doc lines for conditional output to the spec file
 #
index 86b8733..de75b9f 100644 (file)
@@ -41,6 +41,7 @@ accquired||acquired
 accross||across
 acessable||accessible
 acess||access
+acessing||accessing
 achitecture||architecture
 acient||ancient
 acitions||actions
@@ -54,6 +55,7 @@ activete||activate
 actived||activated
 actualy||actually
 acumulating||accumulating
+acumulative||accumulative
 acumulator||accumulator
 adapater||adapter
 addional||additional
@@ -103,6 +105,7 @@ alogrithm||algorithm
 alot||a lot
 alow||allow
 alows||allows
+alredy||already
 altough||although
 alue||value
 ambigious||ambiguous
@@ -223,6 +226,7 @@ boardcast||broadcast
 borad||board
 boundry||boundary
 brievely||briefly
+brigde||bridge
 broadcase||broadcast
 broadcat||broadcast
 bufufer||buffer
@@ -239,6 +243,7 @@ calulate||calculate
 cancelation||cancellation
 cancle||cancel
 capabilites||capabilities
+capabilties||capabilities
 capabilty||capability
 capabitilies||capabilities
 capablity||capability
@@ -325,6 +330,7 @@ conector||connector
 connecetd||connected
 configuartion||configuration
 configuation||configuration
+configued||configured
 configuratoin||configuration
 configuraton||configuration
 configuretion||configuration
@@ -407,6 +413,7 @@ depreacte||deprecate
 desactivate||deactivate
 desciptor||descriptor
 desciptors||descriptors
+descripto||descriptor
 descripton||description
 descrition||description
 descritptor||descriptor
@@ -432,6 +439,7 @@ deveolpment||development
 devided||divided
 deviece||device
 diable||disable
+dicline||decline
 dictionnary||dictionary
 didnt||didn't
 diferent||different
@@ -461,6 +469,7 @@ disharge||discharge
 disnabled||disabled
 dispertion||dispersion
 dissapears||disappears
+dissconect||disconnect
 distiction||distinction
 divisable||divisible
 divsiors||divisors
@@ -469,11 +478,14 @@ documantation||documentation
 documentaion||documentation
 documment||document
 doesnt||doesn't
+donwload||download
+donwloading||downloading
 dorp||drop
 dosen||doesn
 downlad||download
 downlads||downloads
 droped||dropped
+droput||dropout
 druing||during
 dynmaic||dynamic
 eanable||enable
@@ -482,6 +494,7 @@ ecspecially||especially
 edditable||editable
 editting||editing
 efective||effective
+effectivness||effectiveness
 efficently||efficiently
 ehther||ether
 eigth||eight
@@ -543,6 +556,7 @@ extensability||extensibility
 extention||extension
 extenstion||extension
 extracter||extractor
+faied||failed
 faield||failed
 falied||failed
 faild||failed
@@ -567,6 +581,7 @@ fetaures||features
 fileystem||filesystem
 fimware||firmware
 firmare||firmware
+firmaware||firmware
 firware||firmware
 finanize||finalize
 findn||find
@@ -601,6 +616,8 @@ funtions||functions
 furthur||further
 futhermore||furthermore
 futrue||future
+gatable||gateable
+gateing||gating
 gauage||gauge
 gaurenteed||guaranteed
 generiously||generously
@@ -641,9 +658,11 @@ iomaped||iomapped
 imblance||imbalance
 immeadiately||immediately
 immedaite||immediate
+immedate||immediate
 immediatelly||immediately
 immediatly||immediately
 immidiate||immediate
+immutible||immutable
 impelentation||implementation
 impementated||implemented
 implemantation||implementation
@@ -661,10 +680,12 @@ incative||inactive
 incomming||incoming
 incompatabilities||incompatibilities
 incompatable||incompatible
+incompatble||incompatible
 inconsistant||inconsistent
 increas||increase
 incremeted||incremented
 incrment||increment
+inculde||include
 indendation||indentation
 indended||intended
 independant||independent
@@ -778,6 +799,7 @@ libary||library
 librairies||libraries
 libraris||libraries
 licenceing||licencing
+logaritmic||logarithmic
 loggging||logging
 loggin||login
 logile||logfile
@@ -832,6 +854,7 @@ mispelled||misspelled
 mispelt||misspelt
 mising||missing
 mismactch||mismatch
+missign||missing
 missmanaged||mismanaged
 missmatch||mismatch
 miximum||maximum
@@ -848,6 +871,7 @@ mopdule||module
 mroe||more
 mulitplied||multiplied
 multidimensionnal||multidimensional
+multipe||multiple
 multple||multiple
 mumber||number
 muticast||multicast
@@ -870,7 +894,9 @@ nescessary||necessary
 nessessary||necessary
 noticable||noticeable
 notications||notifications
+notifcations||notifications
 notifed||notified
+notity||notify
 numebr||number
 numner||number
 obtaion||obtain
@@ -887,6 +913,7 @@ occuring||occurring
 offser||offset
 offet||offset
 offloded||offloaded
+offseting||offsetting
 omited||omitted
 omiting||omitting
 omitt||omit
@@ -1009,6 +1036,8 @@ programers||programmers
 programm||program
 programms||programs
 progresss||progress
+prohibitted||prohibited
+prohibitting||prohibiting
 promiscous||promiscuous
 promps||prompts
 pronnounced||pronounced
@@ -1023,6 +1052,7 @@ prosess||process
 protable||portable
 protcol||protocol
 protecion||protection
+protedcted||protected
 protocoll||protocol
 promixity||proximity
 psudo||pseudo
@@ -1037,6 +1067,7 @@ reasearcher||researcher
 reasearchers||researchers
 reasearch||research
 recepient||recipient
+recevied||received
 receving||receiving
 recieved||received
 recieve||receive
@@ -1110,6 +1141,7 @@ retreived||retrieved
 retreive||retrieve
 retreiving||retrieving
 retrive||retrieve
+retrived||retrieved
 retuned||returned
 reudce||reduce
 reuest||request
@@ -1145,7 +1177,6 @@ senarios||scenarios
 sentivite||sensitive
 separatly||separately
 sepcify||specify
-sepc||spec
 seperated||separated
 seperately||separately
 seperate||separate
@@ -1177,6 +1208,7 @@ singaled||signaled
 singal||signal
 singed||signed
 sleeped||slept
+sliped||slipped
 softwares||software
 speach||speech
 specfic||specific
@@ -1283,6 +1315,7 @@ threds||threads
 threshhold||threshold
 thresold||threshold
 throught||through
+trackling||tracking
 troughput||throughput
 thses||these
 tiggers||triggers
@@ -1409,5 +1442,6 @@ wnat||want
 workarould||workaround
 writeing||writing
 writting||writing
+wtih||with
 zombe||zombie
 zomebie||zombie
index d46be47..4e18ae5 100755 (executable)
@@ -6,7 +6,7 @@
 # mode may be any of: tags, TAGS, cscope
 #
 # Uses the following environment variables:
-# ARCH, SUBARCH, SRCARCH, srctree, src, obj
+# SUBARCH, SRCARCH, srctree
 
 if [ "$KBUILD_VERBOSE" = "1" ]; then
        set -x
@@ -17,8 +17,7 @@ ignore="$(echo "$RCS_FIND_IGNORE" | sed 's|\\||g' )"
 # tags and cscope files should also ignore MODVERSION *.mod.c files
 ignore="$ignore ( -name *.mod.c ) -prune -o"
 
-# Do not use full path if we do not use O=.. builds
-# Use make O=. {tags|cscope}
+# Use make KBUILD_ABS_SRCTREE=1 {tags|cscope}
 # to force full paths for a non-O= build
 if [ "${srctree}" = "." -o -z "${srctree}" ]; then
        tree=
@@ -36,21 +35,19 @@ elif [ "${ALLSOURCE_ARCHS}" = "all" ]; then
        ALLSOURCE_ARCHS=$(find ${tree}arch/ -mindepth 1 -maxdepth 1 -type d -printf '%f ')
 fi
 
-# find sources in arch/$ARCH
+# find sources in arch/$1
 find_arch_sources()
 {
        for i in $archincludedir; do
                prune="$prune -wholename $i -prune -o"
        done
-       find ${tree}arch/$1 $ignore $subarchprune $prune -name "$2" \
-               -not -type l -print;
+       find ${tree}arch/$1 $ignore $prune -name "$2" -not -type l -print;
 }
 
 # find sources in arch/$1/include
 find_arch_include_sources()
 {
-       include=$(find ${tree}arch/$1/ $subarchprune \
-                                       -name include -type d -print);
+       include=$(find ${tree}arch/$1/ -name include -type d -print);
        if [ -n "$include" ]; then
                archincludedir="$archincludedir $include"
                find $include $ignore -name "$2" -not -type l -print;
@@ -306,36 +303,6 @@ if [ "${ARCH}" = "um" ]; then
        else
                archinclude=${SUBARCH}
        fi
-elif [ "${SRCARCH}" = "arm" -a "${SUBARCH}" != "" ]; then
-       subarchdir=$(find ${tree}arch/$SRCARCH/ -name "mach-*" -type d -o \
-                                                       -name "plat-*" -type d);
-       mach_suffix=$SUBARCH
-       plat_suffix=$SUBARCH
-
-       # Special cases when $plat_suffix != $mach_suffix
-       case $mach_suffix in
-               "omap1" | "omap2")
-                       plat_suffix="omap"
-                       ;;
-       esac
-
-       if [ ! -d ${tree}arch/$SRCARCH/mach-$mach_suffix ]; then
-               echo "Warning: arch/arm/mach-$mach_suffix/ not found." >&2
-               echo "         Fix your \$SUBARCH appropriately" >&2
-       fi
-
-       for i in $subarchdir; do
-               case "$i" in
-                       *"mach-"${mach_suffix})
-                               ;;
-                       *"plat-"${plat_suffix})
-                               ;;
-                       *)
-                               subarchprune="$subarchprune \
-                                               -wholename $i -prune -o"
-                               ;;
-               esac
-       done
 fi
 
 remove_structs=
index c6cb2d9..a1ffe2e 100644 (file)
@@ -160,6 +160,35 @@ config STACKLEAK_RUNTIME_DISABLE
          runtime to control kernel stack erasing for kernels built with
          CONFIG_GCC_PLUGIN_STACKLEAK.
 
+config INIT_ON_ALLOC_DEFAULT_ON
+       bool "Enable heap memory zeroing on allocation by default"
+       help
+         This has the effect of setting "init_on_alloc=1" on the kernel
+         command line. This can be disabled with "init_on_alloc=0".
+         When "init_on_alloc" is enabled, all page allocator and slab
+         allocator memory will be zeroed when allocated, eliminating
+         many kinds of "uninitialized heap memory" flaws, especially
+         heap content exposures. The performance impact varies by
+         workload, but most cases see <1% impact. Some synthetic
+         workloads have measured as high as 7%.
+
+config INIT_ON_FREE_DEFAULT_ON
+       bool "Enable heap memory zeroing on free by default"
+       help
+         This has the effect of setting "init_on_free=1" on the kernel
+         command line. This can be disabled with "init_on_free=0".
+         Similar to "init_on_alloc", when "init_on_free" is enabled,
+         all page allocator and slab allocator memory will be zeroed
+         when freed, eliminating many kinds of "uninitialized heap memory"
+         flaws, especially heap content exposures. The primary difference
+         with "init_on_free" is that data lifetime in memory is reduced,
+         as anything freed is wiped immediately, making live forensics or
+         cold boot memory attacks unable to recover freed memory contents.
+         The performance impact varies by workload, but is more expensive
+         than "init_on_alloc" due to the negative cache effects of
+         touching "cold" memory areas. Most cases see 3-5% impact. Some
+         synthetic workloads have measured as high as 8%.
+
 endmenu
 
 endmenu
index 79131ef..81519c8 100644 (file)
@@ -37,6 +37,8 @@ static void report_load(const char *origin, struct file *file, char *operation)
 }
 
 static int enforce = IS_ENABLED(CONFIG_SECURITY_LOADPIN_ENFORCE);
+static char *exclude_read_files[READING_MAX_ID];
+static int ignore_read_file_id[READING_MAX_ID] __ro_after_init;
 static struct super_block *pinned_root;
 static DEFINE_SPINLOCK(pinned_root_spinlock);
 
@@ -121,6 +123,13 @@ static int loadpin_read_file(struct file *file, enum kernel_read_file_id id)
        struct super_block *load_root;
        const char *origin = kernel_read_file_id_str(id);
 
+       /* If the file id is excluded, ignore the pinning. */
+       if ((unsigned int)id < ARRAY_SIZE(ignore_read_file_id) &&
+           ignore_read_file_id[id]) {
+               report_load(origin, file, "pinning-excluded");
+               return 0;
+       }
+
        /* This handles the older init_module API that has a NULL file. */
        if (!file) {
                if (!enforce) {
@@ -179,10 +188,47 @@ static struct security_hook_list loadpin_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(kernel_load_data, loadpin_load_data),
 };
 
+static void __init parse_exclude(void)
+{
+       int i, j;
+       char *cur;
+
+       /*
+        * Make sure all the arrays stay within expected sizes. This
+        * is slightly weird because kernel_read_file_str[] includes
+        * READING_MAX_ID, which isn't actually meaningful here.
+        */
+       BUILD_BUG_ON(ARRAY_SIZE(exclude_read_files) !=
+                    ARRAY_SIZE(ignore_read_file_id));
+       BUILD_BUG_ON(ARRAY_SIZE(kernel_read_file_str) <
+                    ARRAY_SIZE(ignore_read_file_id));
+
+       for (i = 0; i < ARRAY_SIZE(exclude_read_files); i++) {
+               cur = exclude_read_files[i];
+               if (!cur)
+                       break;
+               if (*cur == '\0')
+                       continue;
+
+               for (j = 0; j < ARRAY_SIZE(ignore_read_file_id); j++) {
+                       if (strcmp(cur, kernel_read_file_str[j]) == 0) {
+                               pr_info("excluding: %s\n",
+                                       kernel_read_file_str[j]);
+                               ignore_read_file_id[j] = 1;
+                               /*
+                                * Can not break, because one read_file_str
+                                * may map to more than on read_file_id.
+                                */
+                       }
+               }
+       }
+}
+
 static int __init loadpin_init(void)
 {
        pr_info("ready to pin (currently %senforcing)\n",
                enforce ? "" : "not ");
+       parse_exclude();
        security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin");
        return 0;
 }
@@ -195,3 +241,5 @@ DEFINE_LSM(loadpin) = {
 /* Should not be mutable after boot, so not listed in sysfs (perm == 0). */
 module_param(enforce, int, 0);
 MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning");
+module_param_array_named(exclude, exclude_read_files, charp, NULL, 0);
+MODULE_PARM_DESC(exclude, "Exclude pinning specific read file types");
index 0ac3e52..85beef2 100644 (file)
@@ -38,21 +38,21 @@ static const DECLARE_TLV_DB_SCALE(ec_mic_gain_tlv, 0, 100, 0);
 
 static int ec_command_get_gain(struct snd_soc_component *component,
                               struct ec_param_codec_i2s *param,
-                              struct ec_response_codec_gain *resp)
+                              struct ec_codec_i2s_gain *resp)
 {
        struct cros_ec_codec_data *codec_data =
                snd_soc_component_get_drvdata(component);
        struct cros_ec_device *ec_device = codec_data->ec_device;
        u8 buffer[sizeof(struct cros_ec_command) +
                  max(sizeof(struct ec_param_codec_i2s),
-                     sizeof(struct ec_response_codec_gain))];
+                     sizeof(struct ec_codec_i2s_gain))];
        struct cros_ec_command *msg = (struct cros_ec_command *)&buffer;
        int ret;
 
        msg->version = 0;
        msg->command = EC_CMD_CODEC_I2S;
        msg->outsize = sizeof(struct ec_param_codec_i2s);
-       msg->insize = sizeof(struct ec_response_codec_gain);
+       msg->insize = sizeof(struct ec_codec_i2s_gain);
 
        memcpy(msg->data, param, msg->outsize);
 
@@ -226,7 +226,7 @@ static int get_ec_mic_gain(struct snd_soc_component *component,
                           u8 *left, u8 *right)
 {
        struct ec_param_codec_i2s param;
-       struct ec_response_codec_gain resp;
+       struct ec_codec_i2s_gain resp;
        int ret;
 
        param.cmd = EC_CODEC_GET_GAIN;
index 7a3e138..c16b0ff 100644 (file)
@@ -422,7 +422,7 @@ static const struct dailink_match_data dailink_match[] = {
        },
 };
 
-static int of_dev_node_match(struct device *dev, void *data)
+static int of_dev_node_match(struct device *dev, const void *data)
 {
        return dev->of_node == data;
 }
index d329825..cfb297e 100644 (file)
@@ -10,4 +10,4 @@ all: ihex2fw
 clean:
        $(RM) ihex2fw
 
-.PHONY: all clean
\ No newline at end of file
+.PHONY: all clean
index a22b6e8..7399eb7 100644 (file)
@@ -156,9 +156,9 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
                        *be = (endianchar == 'b');
                        *bytes = padint / 8;
                        if (*bits_used == 64)
-                               *mask = ~0;
+                               *mask = ~(0ULL);
                        else
-                               *mask = (1ULL << *bits_used) - 1;
+                               *mask = (1ULL << *bits_used) - 1ULL;
 
                        *is_signed = (signchar == 's');
                        if (fclose(sysfsfp)) {
index 2fe12b4..c2152f3 100644 (file)
@@ -696,9 +696,11 @@ struct kvm_ioeventfd {
 #define KVM_X86_DISABLE_EXITS_MWAIT          (1 << 0)
 #define KVM_X86_DISABLE_EXITS_HLT            (1 << 1)
 #define KVM_X86_DISABLE_EXITS_PAUSE          (1 << 2)
+#define KVM_X86_DISABLE_EXITS_CSTATE         (1 << 3)
 #define KVM_X86_DISABLE_VALID_EXITS          (KVM_X86_DISABLE_EXITS_MWAIT | \
                                               KVM_X86_DISABLE_EXITS_HLT | \
-                                              KVM_X86_DISABLE_EXITS_PAUSE)
+                                              KVM_X86_DISABLE_EXITS_PAUSE | \
+                                              KVM_X86_DISABLE_EXITS_CSTATE)
 
 /* for KVM_ENABLE_CAP */
 struct kvm_enable_cap {
index 9781ca7..25b43a8 100644 (file)
@@ -74,7 +74,7 @@ endif
 # Append kselftest to KBUILD_OUTPUT to avoid cluttering
 # KBUILD_OUTPUT with selftest objects and headers installed
 # by selftests Makefile or lib.mk.
-ifneq ($(KBUILD_SRC),)
+ifdef building_out_of_srctree
 override LDFLAGS =
 endif
 
index 2bfddb6..8219a30 100644 (file)
@@ -11,7 +11,6 @@
 #include <stdlib.h>
 #include <sys/inotify.h>
 #include <string.h>
-#include <sys/types.h>
 #include <sys/wait.h>
 
 #include "../kselftest.h"
diff --git a/tools/testing/selftests/drivers/dma-buf/config b/tools/testing/selftests/drivers/dma-buf/config
new file mode 100644 (file)
index 0000000..d708515
--- /dev/null
@@ -0,0 +1 @@
+CONFIG_UDMABUF=y
index a4320c4..f901076 100755 (executable)
@@ -153,13 +153,18 @@ config_set_read_fw_idx()
 
 read_firmwares()
 {
+       if [ "$1" = "xzonly" ]; then
+               fwfile="${FW}-orig"
+       else
+               fwfile="$FW"
+       fi
        for i in $(seq 0 3); do
                config_set_read_fw_idx $i
                # Verify the contents are what we expect.
                # -Z required for now -- check for yourself, md5sum
                # on $FW and DIR/read_firmware will yield the same. Even
                # cmp agrees, so something is off.
-               if ! diff -q -Z "$FW" $DIR/read_firmware 2>/dev/null ; then
+               if ! diff -q -Z "$fwfile" $DIR/read_firmware 2>/dev/null ; then
                        echo "request #$i: firmware was not loaded" >&2
                        exit 1
                fi
@@ -246,17 +251,17 @@ test_request_firmware_nowait_custom_nofile()
 
 test_batched_request_firmware()
 {
-       echo -n "Batched request_firmware() try #$1: "
+       echo -n "Batched request_firmware() $2 try #$1: "
        config_reset
        config_trigger_sync
-       read_firmwares
+       read_firmwares $2
        release_all_firmware
        echo "OK"
 }
 
 test_batched_request_firmware_direct()
 {
-       echo -n "Batched request_firmware_direct() try #$1: "
+       echo -n "Batched request_firmware_direct() $2 try #$1: "
        config_reset
        config_set_sync_direct
        config_trigger_sync
@@ -266,7 +271,7 @@ test_batched_request_firmware_direct()
 
 test_request_firmware_nowait_uevent()
 {
-       echo -n "Batched request_firmware_nowait(uevent=true) try #$1: "
+       echo -n "Batched request_firmware_nowait(uevent=true) $2 try #$1: "
        config_reset
        config_trigger_async
        release_all_firmware
@@ -275,11 +280,16 @@ test_request_firmware_nowait_uevent()
 
 test_request_firmware_nowait_custom()
 {
-       echo -n "Batched request_firmware_nowait(uevent=false) try #$1: "
+       echo -n "Batched request_firmware_nowait(uevent=false) $2 try #$1: "
        config_reset
        config_unset_uevent
        RANDOM_FILE_PATH=$(setup_random_file)
        RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"
+       if [ "$2" = "both" ]; then
+               xz -9 -C crc32 -k $RANDOM_FILE_PATH
+       elif [ "$2" = "xzonly" ]; then
+               xz -9 -C crc32 $RANDOM_FILE_PATH
+       fi
        config_set_name $RANDOM_FILE
        config_trigger_async
        release_all_firmware
@@ -294,19 +304,19 @@ test_config_present
 echo
 echo "Testing with the file present..."
 for i in $(seq 1 5); do
-       test_batched_request_firmware $i
+       test_batched_request_firmware $i normal
 done
 
 for i in $(seq 1 5); do
-       test_batched_request_firmware_direct $i
+       test_batched_request_firmware_direct $i normal
 done
 
 for i in $(seq 1 5); do
-       test_request_firmware_nowait_uevent $i
+       test_request_firmware_nowait_uevent $i normal
 done
 
 for i in $(seq 1 5); do
-       test_request_firmware_nowait_custom $i
+       test_request_firmware_nowait_custom $i normal
 done
 
 # Test for file not found, errors are expected, the failure would be
@@ -329,4 +339,47 @@ for i in $(seq 1 5); do
        test_request_firmware_nowait_custom_nofile $i
 done
 
+test "$HAS_FW_LOADER_COMPRESS" != "yes" && exit 0
+
+# test with both files present
+xz -9 -C crc32 -k $FW
+config_set_name $NAME
+echo
+echo "Testing with both plain and xz files present..."
+for i in $(seq 1 5); do
+       test_batched_request_firmware $i both
+done
+
+for i in $(seq 1 5); do
+       test_batched_request_firmware_direct $i both
+done
+
+for i in $(seq 1 5); do
+       test_request_firmware_nowait_uevent $i both
+done
+
+for i in $(seq 1 5); do
+       test_request_firmware_nowait_custom $i both
+done
+
+# test with only xz file present
+mv "$FW" "${FW}-orig"
+echo
+echo "Testing with only xz file present..."
+for i in $(seq 1 5); do
+       test_batched_request_firmware $i xzonly
+done
+
+for i in $(seq 1 5); do
+       test_batched_request_firmware_direct $i xzonly
+done
+
+for i in $(seq 1 5); do
+       test_request_firmware_nowait_uevent $i xzonly
+done
+
+for i in $(seq 1 5); do
+       test_request_firmware_nowait_custom $i xzonly
+done
+
 exit 0
index 1cbb12e..f236cc2 100755 (executable)
@@ -50,6 +50,7 @@ check_setup()
 {
        HAS_FW_LOADER_USER_HELPER="$(kconfig_has CONFIG_FW_LOADER_USER_HELPER=y)"
        HAS_FW_LOADER_USER_HELPER_FALLBACK="$(kconfig_has CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y)"
+       HAS_FW_LOADER_COMPRESS="$(kconfig_has CONFIG_FW_LOADER_COMPRESS=y)"
        PROC_FW_IGNORE_SYSFS_FALLBACK="0"
        PROC_FW_FORCE_SYSFS_FALLBACK="0"
 
@@ -84,6 +85,12 @@ check_setup()
        fi
 
        OLD_FWPATH="$(cat /sys/module/firmware_class/parameters/path)"
+
+       if [ "$HAS_FW_LOADER_COMPRESS" = "yes" ]; then
+               if ! which xz 2> /dev/null > /dev/null; then
+                       HAS_FW_LOADER_COMPRESS=""
+               fi
+       fi
 }
 
 verify_reqs()
index cffdd4e..8e14d55 100755 (executable)
@@ -11,6 +11,7 @@ source $TEST_DIR/fw_lib.sh
 
 export HAS_FW_LOADER_USER_HELPER=""
 export HAS_FW_LOADER_USER_HELPER_FALLBACK=""
+export HAS_FW_LOADER_COMPRESS=""
 
 run_tests()
 {
index fc27f89..ceb52b9 100644 (file)
@@ -121,7 +121,6 @@ static void *vcpu_worker(void *data)
        uint64_t *guest_array;
        uint64_t pages_count = 0;
        struct kvm_run *run;
-       struct ucall uc;
 
        run = vcpu_state(vm, VCPU_ID);
 
@@ -132,7 +131,7 @@ static void *vcpu_worker(void *data)
                /* Let the guest dirty the random pages */
                ret = _vcpu_run(vm, VCPU_ID);
                TEST_ASSERT(ret == 0, "vcpu_run failed: %d\n", ret);
-               if (get_ucall(vm, VCPU_ID, &uc) == UCALL_SYNC) {
+               if (get_ucall(vm, VCPU_ID, NULL) == UCALL_SYNC) {
                        pages_count += TEST_PAGES_PER_LOOP;
                        generate_random_array(guest_array, TEST_PAGES_PER_LOOP);
                } else {
index 9ef2ab1..b7fa0c8 100644 (file)
@@ -52,4 +52,8 @@ static inline void set_reg(struct kvm_vm *vm, uint32_t vcpuid, uint64_t id, uint
        vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, &reg);
 }
 
+void aarch64_vcpu_setup(struct kvm_vm *vm, int vcpuid, struct kvm_vcpu_init *init);
+void aarch64_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid,
+                             struct kvm_vcpu_init *init, void *guest_code);
+
 #endif /* SELFTEST_KVM_PROCESSOR_H */
index 7318fb0..00235f5 100644 (file)
@@ -86,8 +86,7 @@ int _vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long ioctl,
                void *arg);
 void vm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg);
 void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags);
-void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, int pgd_memslot,
-                int gdt_memslot);
+void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid);
 vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min,
                          uint32_t data_memslot, uint32_t pgd_memslot);
 void virt_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
index 19e6679..af2023d 100644 (file)
@@ -235,28 +235,21 @@ struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages,
        return vm;
 }
 
-void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code)
+void aarch64_vcpu_setup(struct kvm_vm *vm, int vcpuid, struct kvm_vcpu_init *init)
 {
-       size_t stack_size = vm->page_size == 4096 ?
-                                       DEFAULT_STACK_PGS * vm->page_size :
-                                       vm->page_size;
-       uint64_t stack_vaddr = vm_vaddr_alloc(vm, stack_size,
-                                       DEFAULT_ARM64_GUEST_STACK_VADDR_MIN, 0, 0);
+       struct kvm_vcpu_init default_init = { .target = -1, };
+       uint64_t sctlr_el1, tcr_el1;
 
-       vm_vcpu_add(vm, vcpuid, 0, 0);
+       if (!init)
+               init = &default_init;
 
-       set_reg(vm, vcpuid, ARM64_CORE_REG(sp_el1), stack_vaddr + stack_size);
-       set_reg(vm, vcpuid, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code);
-}
-
-void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, int gdt_memslot)
-{
-       struct kvm_vcpu_init init;
-       uint64_t sctlr_el1, tcr_el1;
+       if (init->target == -1) {
+               struct kvm_vcpu_init preferred;
+               vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &preferred);
+               init->target = preferred.target;
+       }
 
-       memset(&init, 0, sizeof(init));
-       init.target = KVM_ARM_TARGET_GENERIC_V8;
-       vcpu_ioctl(vm, vcpuid, KVM_ARM_VCPU_INIT, &init);
+       vcpu_ioctl(vm, vcpuid, KVM_ARM_VCPU_INIT, init);
 
        /*
         * Enable FP/ASIMD to avoid trapping when accessing Q0-Q15
@@ -316,3 +309,24 @@ void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent)
        fprintf(stream, "%*spstate: 0x%.16lx pc: 0x%.16lx\n",
                indent, "", pstate, pc);
 }
+
+void aarch64_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid,
+                             struct kvm_vcpu_init *init, void *guest_code)
+{
+       size_t stack_size = vm->page_size == 4096 ?
+                                       DEFAULT_STACK_PGS * vm->page_size :
+                                       vm->page_size;
+       uint64_t stack_vaddr = vm_vaddr_alloc(vm, stack_size,
+                                       DEFAULT_ARM64_GUEST_STACK_VADDR_MIN, 0, 0);
+
+       vm_vcpu_add(vm, vcpuid);
+       aarch64_vcpu_setup(vm, vcpuid, init);
+
+       set_reg(vm, vcpuid, ARM64_CORE_REG(sp_el1), stack_vaddr + stack_size);
+       set_reg(vm, vcpuid, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code);
+}
+
+void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code)
+{
+       aarch64_vcpu_add_default(vm, vcpuid, NULL, guest_code);
+}
index ee864fa..221e3fa 100644 (file)
@@ -763,11 +763,10 @@ static int vcpu_mmap_sz(void)
  *
  * Return: None
  *
- * Creates and adds to the VM specified by vm and virtual CPU with
- * the ID given by vcpuid.
+ * Adds a virtual CPU to the VM specified by vm with the ID given by vcpuid.
+ * No additional VCPU setup is done.
  */
-void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, int pgd_memslot,
-                int gdt_memslot)
+void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid)
 {
        struct vcpu *vcpu;
 
@@ -801,8 +800,6 @@ void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, int pgd_memslot,
                vm->vcpu_head->prev = vcpu;
        vcpu->next = vm->vcpu_head;
        vm->vcpu_head = vcpu;
-
-       vcpu_setup(vm, vcpuid, pgd_memslot, gdt_memslot);
 }
 
 /*
index 265b782..f36262e 100644 (file)
@@ -64,8 +64,6 @@ struct kvm_vm {
 };
 
 struct vcpu *vcpu_find(struct kvm_vm *vm, uint32_t vcpuid);
-void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot,
-               int gdt_memslot);
 void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent);
 void regs_dump(FILE *stream, struct kvm_regs *regs, uint8_t indent);
 void sregs_dump(FILE *stream, struct kvm_sregs *sregs, uint8_t indent);
index b701a01..dd9a667 100644 (file)
@@ -125,16 +125,16 @@ void ucall(uint64_t cmd, int nargs, ...)
 uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc)
 {
        struct kvm_run *run = vcpu_state(vm, vcpu_id);
-
-       memset(uc, 0, sizeof(*uc));
+       struct ucall ucall = {};
+       bool got_ucall = false;
 
 #ifdef __x86_64__
        if (ucall_type == UCALL_PIO && run->exit_reason == KVM_EXIT_IO &&
            run->io.port == UCALL_PIO_PORT) {
                struct kvm_regs regs;
                vcpu_regs_get(vm, vcpu_id, &regs);
-               memcpy(uc, addr_gva2hva(vm, (vm_vaddr_t)regs.rdi), sizeof(*uc));
-               return uc->cmd;
+               memcpy(&ucall, addr_gva2hva(vm, (vm_vaddr_t)regs.rdi), sizeof(ucall));
+               got_ucall = true;
        }
 #endif
        if (ucall_type == UCALL_MMIO && run->exit_reason == KVM_EXIT_MMIO &&
@@ -143,8 +143,15 @@ uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc)
                TEST_ASSERT(run->mmio.is_write && run->mmio.len == 8,
                            "Unexpected ucall exit mmio address access");
                memcpy(&gva, run->mmio.data, sizeof(gva));
-               memcpy(uc, addr_gva2hva(vm, gva), sizeof(*uc));
+               memcpy(&ucall, addr_gva2hva(vm, gva), sizeof(ucall));
+               got_ucall = true;
+       }
+
+       if (got_ucall) {
+               vcpu_run_complete_io(vm, vcpu_id);
+               if (uc)
+                       memcpy(uc, &ucall, sizeof(ucall));
        }
 
-       return uc->cmd;
+       return ucall.cmd;
 }
index d2ad85f..b430f96 100644 (file)
@@ -609,7 +609,7 @@ static void kvm_setup_tss_64bit(struct kvm_vm *vm, struct kvm_segment *segp,
        kvm_seg_fill_gdt_64bit(vm, segp);
 }
 
-void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, int gdt_memslot)
+static void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, int gdt_memslot)
 {
        struct kvm_sregs sregs;
 
@@ -655,7 +655,8 @@ void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code)
                                     DEFAULT_GUEST_STACK_VADDR_MIN, 0, 0);
 
        /* Create VCPU */
-       vm_vcpu_add(vm, vcpuid, 0, 0);
+       vm_vcpu_add(vm, vcpuid);
+       vcpu_setup(vm, vcpuid, 0, 0);
 
        /* Setup guest general purpose registers */
        vcpu_regs_get(vm, vcpuid, &regs);
index 241919e..f95c083 100644 (file)
@@ -144,7 +144,7 @@ int main(int argc, char *argv[])
 
                /* Restore state in a new VM.  */
                kvm_vm_restart(vm, O_RDWR);
-               vm_vcpu_add(vm, VCPU_ID, 0, 0);
+               vm_vcpu_add(vm, VCPU_ID);
                vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
                vcpu_ioctl(vm, VCPU_ID, KVM_ENABLE_CAP, &enable_evmcs_cap);
                vcpu_load_state(vm, VCPU_ID, state);
index 6a3eec8..429226b 100644 (file)
@@ -33,7 +33,7 @@ void test_vcpu_creation(int first_vcpu_id, int num_vcpus)
                int vcpu_id = first_vcpu_id + i;
 
                /* This asserts that the vCPU was created. */
-               vm_vcpu_add(vm, vcpu_id, 0, 0);
+               vm_vcpu_add(vm, vcpu_id);
        }
 
        kvm_vm_free(vm);
index 4daf520..8c06364 100644 (file)
@@ -144,7 +144,7 @@ int main(int argc, char *argv[])
                state = vcpu_save_state(vm, VCPU_ID);
                kvm_vm_release(vm);
                kvm_vm_restart(vm, O_RDWR);
-               vm_vcpu_add(vm, VCPU_ID, 0, 0);
+               vm_vcpu_add(vm, VCPU_ID);
                vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
                vcpu_load_state(vm, VCPU_ID, state);
                run = vcpu_state(vm, VCPU_ID);
index 1a23617..3ab5ec3 100644 (file)
@@ -176,7 +176,7 @@ int main(int argc, char *argv[])
 
                /* Restore state in a new VM.  */
                kvm_vm_restart(vm, O_RDWR);
-               vm_vcpu_add(vm, VCPU_ID, 0, 0);
+               vm_vcpu_add(vm, VCPU_ID);
                vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
                vcpu_load_state(vm, VCPU_ID, state);
                run = vcpu_state(vm, VCPU_ID);
index 0773371..1c8a196 100644 (file)
@@ -70,7 +70,7 @@ define RUN_TESTS
 endef
 
 run_tests: all
-ifneq ($(KBUILD_SRC),)
+ifdef building_out_of_srctree
        @if [ "X$(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES)" != "X" ]; then
                @rsync -aq $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) $(OUTPUT)
        fi
@@ -125,7 +125,7 @@ clean:
 # When make O= with kselftest target from main level
 # the following aren't defined.
 #
-ifneq ($(KBUILD_SRC),)
+ifdef building_out_of_srctree
 LINK.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
 COMPILE.S = $(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
 LINK.S = $(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
index 0fbed67..aca3491 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/types.h>
 #include <linux/net_tstamp.h>
 #include <linux/errqueue.h>
+#include <linux/sockios.h>
 
 #ifndef SO_TIMESTAMPING
 # define SO_TIMESTAMPING         37
 # define SO_TIMESTAMPNS 35
 #endif
 
-#ifndef SIOCGSTAMPNS
-# define SIOCGSTAMPNS 0x8907
-#endif
-
-#ifndef SIOCSHWTSTAMP
-# define SIOCSHWTSTAMP 0x89b0
-#endif
-
 static void usage(const char *error)
 {
        if (error)
index 84f28f1..5943c81 100644 (file)
@@ -6,6 +6,8 @@
  */
 
 /*
+ * - ARM little endian
+ *
  * RSEQ_SIG uses the udf A32 instruction with an uncommon immediate operand
  * value 0x5de3. This traps if user-space reaches this instruction by mistake,
  * and the uncommon operand ensures the kernel does not move the instruction
  * def3        udf    #243      ; 0xf3
  * e7f5        b.n    <7f5>
  *
- * pre-ARMv6 big endian code:
- * e7f5        b.n    <7f5>
- * def3        udf    #243      ; 0xf3
+ * - ARMv6+ big endian (BE8):
  *
  * ARMv6+ -mbig-endian generates mixed endianness code vs data: little-endian
- * code and big-endian data. Ensure the RSEQ_SIG data signature matches code
- * endianness. Prior to ARMv6, -mbig-endian generates big-endian code and data
- * (which match), so there is no need to reverse the endianness of the data
- * representation of the signature. However, the choice between BE32 and BE8
- * is done by the linker, so we cannot know whether code and data endianness
- * will be mixed before the linker is invoked.
+ * code and big-endian data. The data value of the signature needs to have its
+ * byte order reversed to generate the trap instruction:
+ *
+ * Data: 0xf3def5e7
+ *
+ * Translates to this A32 instruction pattern:
+ *
+ * e7f5def3    udf    #24035    ; 0x5de3
+ *
+ * Translates to this T16 instruction pattern:
+ *
+ * def3        udf    #243      ; 0xf3
+ * e7f5        b.n    <7f5>
+ *
+ * - Prior to ARMv6 big endian (BE32):
+ *
+ * Prior to ARMv6, -mbig-endian generates big-endian code and data
+ * (which match), so the endianness of the data representation of the
+ * signature should not be reversed. However, the choice between BE32
+ * and BE8 is done by the linker, so we cannot know whether code and
+ * data endianness will be mixed before the linker is invoked. So rather
+ * than try to play tricks with the linker, the rseq signature is simply
+ * data (not a trap instruction) prior to ARMv6 on big endian. This is
+ * why the signature is expressed as data (.word) rather than as
+ * instruction (.inst) in assembler.
  */
 
-#define RSEQ_SIG_CODE  0xe7f5def3
-
-#ifndef __ASSEMBLER__
-
-#define RSEQ_SIG_DATA                                                  \
-       ({                                                              \
-               int sig;                                                \
-               asm volatile ("b 2f\n\t"                                \
-                             "1: .inst " __rseq_str(RSEQ_SIG_CODE) "\n\t" \
-                             "2:\n\t"                                  \
-                             "ldr %[sig], 1b\n\t"                      \
-                             : [sig] "=r" (sig));                      \
-               sig;                                                    \
-       })
-
-#define RSEQ_SIG       RSEQ_SIG_DATA
-
+#ifdef __ARMEB__
+#define RSEQ_SIG    0xf3def5e7      /* udf    #24035    ; 0x5de3 (ARMv6+) */
+#else
+#define RSEQ_SIG    0xe7f5def3      /* udf    #24035    ; 0x5de3 */
 #endif
 
 #define rseq_smp_mb()  __asm__ __volatile__ ("dmb" ::: "memory", "cc")
@@ -125,8 +131,7 @@ do {                                                                        \
                __rseq_str(table_label) ":\n\t"                         \
                ".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
                ".word " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \
-               ".arm\n\t"                                              \
-               ".inst " __rseq_str(RSEQ_SIG_CODE) "\n\t"               \
+               ".word " __rseq_str(RSEQ_SIG) "\n\t"                    \
                __rseq_str(label) ":\n\t"                               \
                teardown                                                \
                "b %l[" __rseq_str(abort_label) "]\n\t"
index 73818f1..68092d1 100644 (file)
@@ -79,6 +79,7 @@ int sort_size;
 int sort_active;
 int set_debug;
 int show_ops;
+int sort_partial;
 int show_activity;
 int output_lines = -1;
 int sort_loss;
@@ -110,7 +111,7 @@ static void fatal(const char *x, ...)
 static void usage(void)
 {
        printf("slabinfo 4/15/2011. (c) 2007 sgi/(c) 2011 Linux Foundation.\n\n"
-               "slabinfo [-aADefhilnosrStTvz1LXBU] [N=K] [-dafzput] [slab-regexp]\n"
+               "slabinfo [-aABDefhilLnoPrsStTUvXz1] [N=K] [-dafzput] [slab-regexp]\n"
                "-a|--aliases           Show aliases\n"
                "-A|--activity          Most active slabs first\n"
                "-B|--Bytes             Show size in bytes\n"
@@ -124,6 +125,7 @@ static void usage(void)
                "-n|--numa              Show NUMA information\n"
                "-N|--lines=K           Show the first K slabs\n"
                "-o|--ops               Show kmem_cache_ops\n"
+               "-P|--partial           Sort by number of partial slabs\n"
                "-r|--report            Detailed report on single slabs\n"
                "-s|--shrink            Shrink slabs\n"
                "-S|--Size              Sort by size\n"
@@ -131,9 +133,9 @@ static void usage(void)
                "-T|--Totals            Show summary information\n"
                "-U|--Unreclaim         Show unreclaimable slabs only\n"
                "-v|--validate          Validate slabs\n"
+               "-X|--Xtotals           Show extended summary information\n"
                "-z|--zero              Include empty slabs\n"
                "-1|--1ref              Single reference\n"
-               "-X|--Xtotals           Show extended summary information\n"
 
                "\n"
                "-d  | --debug          Switch off all debug options\n"
@@ -146,6 +148,8 @@ static void usage(void)
                "    p | P              Poisoning\n"
                "    u | U              Tracking\n"
                "    t | T              Tracing\n"
+
+               "\nSorting options (--Loss, --Size, --Partial) are mutually exclusive\n"
        );
 }
 
@@ -1047,6 +1051,8 @@ static void sort_slabs(void)
                                result = slab_activity(s1) < slab_activity(s2);
                        else if (sort_loss)
                                result = slab_waste(s1) < slab_waste(s2);
+                       else if (sort_partial)
+                               result = s1->partial < s2->partial;
                        else
                                result = strcasecmp(s1->name, s2->name);
 
@@ -1307,33 +1313,46 @@ static void output_slabs(void)
        }
 }
 
+static void _xtotals(char *heading, char *underline,
+                    int loss, int size, int partial)
+{
+       printf("%s%s", heading, underline);
+       line = 0;
+       sort_loss = loss;
+       sort_size = size;
+       sort_partial = partial;
+       sort_slabs();
+       output_slabs();
+}
+
 static void xtotals(void)
 {
+       char *heading, *underline;
+
        totals();
 
        link_slabs();
        rename_slabs();
 
-       printf("\nSlabs sorted by size\n");
-       printf("--------------------\n");
-       sort_loss = 0;
-       sort_size = 1;
-       sort_slabs();
-       output_slabs();
+       heading = "\nSlabs sorted by size\n";
+       underline = "--------------------\n";
+       _xtotals(heading, underline, 0, 1, 0);
+
+       heading = "\nSlabs sorted by loss\n";
+       underline = "--------------------\n";
+       _xtotals(heading, underline, 1, 0, 0);
+
+       heading = "\nSlabs sorted by number of partial slabs\n";
+       underline = "---------------------------------------\n";
+       _xtotals(heading, underline, 0, 0, 1);
 
-       printf("\nSlabs sorted by loss\n");
-       printf("--------------------\n");
-       line = 0;
-       sort_loss = 1;
-       sort_size = 0;
-       sort_slabs();
-       output_slabs();
        printf("\n");
 }
 
 struct option opts[] = {
        { "aliases", no_argument, NULL, 'a' },
        { "activity", no_argument, NULL, 'A' },
+       { "Bytes", no_argument, NULL, 'B'},
        { "debug", optional_argument, NULL, 'd' },
        { "display-activity", no_argument, NULL, 'D' },
        { "empty", no_argument, NULL, 'e' },
@@ -1341,21 +1360,21 @@ struct option opts[] = {
        { "help", no_argument, NULL, 'h' },
        { "inverted", no_argument, NULL, 'i'},
        { "slabs", no_argument, NULL, 'l' },
+       { "Loss", no_argument, NULL, 'L'},
        { "numa", no_argument, NULL, 'n' },
+       { "lines", required_argument, NULL, 'N'},
        { "ops", no_argument, NULL, 'o' },
-       { "shrink", no_argument, NULL, 's' },
+       { "partial", no_argument, NULL, 'p'},
        { "report", no_argument, NULL, 'r' },
+       { "shrink", no_argument, NULL, 's' },
        { "Size", no_argument, NULL, 'S'},
        { "tracking", no_argument, NULL, 't'},
        { "Totals", no_argument, NULL, 'T'},
+       { "Unreclaim", no_argument, NULL, 'U'},
        { "validate", no_argument, NULL, 'v' },
+       { "Xtotals", no_argument, NULL, 'X'},
        { "zero", no_argument, NULL, 'z' },
        { "1ref", no_argument, NULL, '1'},
-       { "lines", required_argument, NULL, 'N'},
-       { "Loss", no_argument, NULL, 'L'},
-       { "Xtotals", no_argument, NULL, 'X'},
-       { "Bytes", no_argument, NULL, 'B'},
-       { "Unreclaim", no_argument, NULL, 'U'},
        { NULL, 0, NULL, 0 }
 };
 
@@ -1367,18 +1386,18 @@ int main(int argc, char *argv[])
 
        page_size = getpagesize();
 
-       while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTSN:LXBU",
+       while ((c = getopt_long(argc, argv, "aABd::DefhilLnN:oPrsStTUvXz1",
                                                opts, NULL)) != -1)
                switch (c) {
-               case '1':
-                       show_single_ref = 1;
-                       break;
                case 'a':
                        show_alias = 1;
                        break;
                case 'A':
                        sort_active = 1;
                        break;
+               case 'B':
+                       show_bytes = 1;
+                       break;
                case 'd':
                        set_debug = 1;
                        if (!debug_opt_scan(optarg))
@@ -1399,45 +1418,48 @@ int main(int argc, char *argv[])
                case 'i':
                        show_inverted = 1;
                        break;
+               case 'l':
+                       show_slab = 1;
+                       break;
+               case 'L':
+                       sort_loss = 1;
+                       break;
                case 'n':
                        show_numa = 1;
                        break;
+               case 'N':
+                       if (optarg) {
+                               output_lines = atoi(optarg);
+                               if (output_lines < 1)
+                                       output_lines = 1;
+                       }
+                       break;
                case 'o':
                        show_ops = 1;
                        break;
                case 'r':
                        show_report = 1;
                        break;
+               case 'P':
+                       sort_partial = 1;
+                       break;
                case 's':
                        shrink = 1;
                        break;
-               case 'l':
-                       show_slab = 1;
+               case 'S':
+                       sort_size = 1;
                        break;
                case 't':
                        show_track = 1;
                        break;
-               case 'v':
-                       validate = 1;
-                       break;
-               case 'z':
-                       skip_zero = 0;
-                       break;
                case 'T':
                        show_totals = 1;
                        break;
-               case 'S':
-                       sort_size = 1;
-                       break;
-               case 'N':
-                       if (optarg) {
-                               output_lines = atoi(optarg);
-                               if (output_lines < 1)
-                                       output_lines = 1;
-                       }
+               case 'U':
+                       unreclaim_only = 1;
                        break;
-               case 'L':
-                       sort_loss = 1;
+               case 'v':
+                       validate = 1;
                        break;
                case 'X':
                        if (output_lines == -1)
@@ -1445,11 +1467,11 @@ int main(int argc, char *argv[])
                        extended_totals = 1;
                        show_bytes = 1;
                        break;
-               case 'B':
-                       show_bytes = 1;
+               case 'z':
+                       skip_zero = 0;
                        break;
-               case 'U':
-                       unreclaim_only = 1;
+               case '1':
+                       show_single_ref = 1;
                        break;
                default:
                        fatal("%s: Invalid option '%c'\n", argv[0], optopt);
index 8e48117..be5eae1 100644 (file)
@@ -7,4 +7,3 @@ initramfs_data.cpio.gz
 initramfs_data.cpio.bz2
 initramfs_data.cpio.lzma
 initramfs_list
-include
index 4a70ae4..6a89eb0 100644 (file)
@@ -56,3 +56,5 @@ $(deps_initramfs): klibcdirs
 $(obj)/$(datafile_y): $(obj)/gen_init_cpio $(deps_initramfs) klibcdirs
        $(Q)$(initramfs) -l $(ramfs-input) > $(obj)/$(datafile_d_y)
        $(call if_changed,initfs)
+
+subdir-$(CONFIG_UAPI_HEADER_TEST) += include
diff --git a/usr/include/.gitignore b/usr/include/.gitignore
new file mode 100644 (file)
index 0000000..a0991ff
--- /dev/null
@@ -0,0 +1,3 @@
+*
+!.gitignore
+!Makefile
diff --git a/usr/include/Makefile b/usr/include/Makefile
new file mode 100644 (file)
index 0000000..cd8daa2
--- /dev/null
@@ -0,0 +1,132 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+# Unlike the kernel space, exported headers are written in standard C.
+#  - Forbid C++ style comments
+#  - Use '__inline__', '__asm__' instead of 'inline', 'asm'
+#
+# -std=c90 (equivalent to -ansi) catches the violation of those.
+# We cannot go as far as adding -Wpedantic since it emits too many warnings.
+UAPI_CFLAGS := -std=c90 -Wall -Werror=implicit-function-declaration
+
+override c_flags = $(UAPI_CFLAGS) -Wp,-MD,$(depfile) -I$(objtree)/usr/include
+
+# The following are excluded for now because they fail to build.
+#
+# Do not add a new header to the blacklist without legitimate reason.
+# Please consider to fix the header first.
+#
+# Sorted alphabetically.
+header-test- += asm/ipcbuf.h
+header-test- += asm/msgbuf.h
+header-test- += asm/sembuf.h
+header-test- += asm/shmbuf.h
+header-test- += asm/signal.h
+header-test- += asm/ucontext.h
+header-test- += drm/vmwgfx_drm.h
+header-test- += linux/am437x-vpfe.h
+header-test- += linux/android/binder.h
+header-test- += linux/android/binderfs.h
+header-test-$(CONFIG_CPU_BIG_ENDIAN) += linux/byteorder/big_endian.h
+header-test-$(CONFIG_CPU_LITTLE_ENDIAN) += linux/byteorder/little_endian.h
+header-test- += linux/coda.h
+header-test- += linux/coda_psdev.h
+header-test- += linux/dvb/audio.h
+header-test- += linux/dvb/osd.h
+header-test- += linux/elfcore.h
+header-test- += linux/errqueue.h
+header-test- += linux/fsmap.h
+header-test- += linux/hdlc/ioctl.h
+header-test- += linux/ivtv.h
+header-test- += linux/jffs2.h
+header-test- += linux/kexec.h
+header-test- += linux/matroxfb.h
+header-test- += linux/netfilter_bridge/ebtables.h
+header-test- += linux/netfilter_ipv4/ipt_LOG.h
+header-test- += linux/netfilter_ipv6/ip6t_LOG.h
+header-test- += linux/nfc.h
+header-test- += linux/nilfs2_ondisk.h
+header-test- += linux/omap3isp.h
+header-test- += linux/omapfb.h
+header-test- += linux/patchkey.h
+header-test- += linux/phonet.h
+header-test- += linux/reiserfs_xattr.h
+header-test- += linux/scc.h
+header-test- += linux/sctp.h
+header-test- += linux/signal.h
+header-test- += linux/sysctl.h
+header-test- += linux/usb/audio.h
+header-test- += linux/v4l2-mediabus.h
+header-test- += linux/v4l2-subdev.h
+header-test- += linux/videodev2.h
+header-test- += linux/vm_sockets.h
+header-test- += misc/ocxl.h
+header-test- += mtd/mtd-abi.h
+header-test- += mtd/mtd-user.h
+header-test- += scsi/scsi_bsg_fc.h
+header-test- += scsi/scsi_netlink.h
+header-test- += scsi/scsi_netlink_fc.h
+header-test- += sound/asequencer.h
+header-test- += sound/asoc.h
+header-test- += sound/asound.h
+header-test- += sound/compress_offload.h
+header-test- += sound/emu10k1.h
+header-test- += sound/sfnt_info.h
+header-test- += sound/sof/eq.h
+header-test- += sound/sof/fw.h
+header-test- += sound/sof/header.h
+header-test- += sound/sof/manifest.h
+header-test- += sound/sof/trace.h
+header-test- += xen/evtchn.h
+header-test- += xen/gntdev.h
+header-test- += xen/privcmd.h
+
+# More headers are broken in some architectures
+
+ifeq ($(SRCARCH),arc)
+header-test- += linux/bpf_perf_event.h
+endif
+
+ifeq ($(SRCARCH),ia64)
+header-test- += asm/setup.h
+header-test- += asm/sigcontext.h
+header-test- += asm/perfmon.h
+header-test- += asm/perfmon_default_smpl.h
+header-test- += linux/if_bonding.h
+endif
+
+ifeq ($(SRCARCH),mips)
+header-test- += asm/stat.h
+endif
+
+ifeq ($(SRCARCH),powerpc)
+header-test- += asm/stat.h
+header-test- += linux/bpf_perf_event.h
+endif
+
+ifeq ($(SRCARCH),riscv)
+header-test- += linux/bpf_perf_event.h
+endif
+
+ifeq ($(SRCARCH),s390)
+header-test- += asm/runtime_instr.h
+header-test- += asm/zcrypt.h
+endif
+
+ifeq ($(SRCARCH),sparc)
+header-test- += asm/stat.h
+header-test- += asm/uctx.h
+header-test- += asm/fbio.h
+header-test- += asm/openpromio.h
+endif
+
+# asm-generic/*.h is used by asm/*.h, and should not be included directly
+header-test- += asm-generic/%
+
+# The rest are compile-tested
+header-test-y += $(filter-out $(header-test-), \
+                       $(patsubst $(obj)/%,%, $(wildcard \
+                       $(addprefix $(obj)/, *.h */*.h */*/*.h */*/*/*.h))))
+
+# For GNU Make <= 4.2.1, $(wildcard $(obj)/*/) matches to not only directories
+# but also regular files. Use $(filter %/, ...) just in case.
+clean-dirs += $(patsubst $(obj)/%/,%,$(filter %/, $(wildcard $(obj)/*/)))
index 1be486d..e2bb5bd 100644 (file)
@@ -237,10 +237,10 @@ static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx)
 
                switch (index) {
                case TIMER_VTIMER:
-                       cnt_ctl = read_sysreg_el0(cntv_ctl);
+                       cnt_ctl = read_sysreg_el0(SYS_CNTV_CTL);
                        break;
                case TIMER_PTIMER:
-                       cnt_ctl = read_sysreg_el0(cntp_ctl);
+                       cnt_ctl = read_sysreg_el0(SYS_CNTP_CTL);
                        break;
                case NR_KVM_TIMERS:
                        /* GCC is braindead */
@@ -350,20 +350,20 @@ static void timer_save_state(struct arch_timer_context *ctx)
 
        switch (index) {
        case TIMER_VTIMER:
-               ctx->cnt_ctl = read_sysreg_el0(cntv_ctl);
-               ctx->cnt_cval = read_sysreg_el0(cntv_cval);
+               ctx->cnt_ctl = read_sysreg_el0(SYS_CNTV_CTL);
+               ctx->cnt_cval = read_sysreg_el0(SYS_CNTV_CVAL);
 
                /* Disable the timer */
-               write_sysreg_el0(0, cntv_ctl);
+               write_sysreg_el0(0, SYS_CNTV_CTL);
                isb();
 
                break;
        case TIMER_PTIMER:
-               ctx->cnt_ctl = read_sysreg_el0(cntp_ctl);
-               ctx->cnt_cval = read_sysreg_el0(cntp_cval);
+               ctx->cnt_ctl = read_sysreg_el0(SYS_CNTP_CTL);
+               ctx->cnt_cval = read_sysreg_el0(SYS_CNTP_CVAL);
 
                /* Disable the timer */
-               write_sysreg_el0(0, cntp_ctl);
+               write_sysreg_el0(0, SYS_CNTP_CTL);
                isb();
 
                break;
@@ -429,14 +429,14 @@ static void timer_restore_state(struct arch_timer_context *ctx)
 
        switch (index) {
        case TIMER_VTIMER:
-               write_sysreg_el0(ctx->cnt_cval, cntv_cval);
+               write_sysreg_el0(ctx->cnt_cval, SYS_CNTV_CVAL);
                isb();
-               write_sysreg_el0(ctx->cnt_ctl, cntv_ctl);
+               write_sysreg_el0(ctx->cnt_ctl, SYS_CNTV_CTL);
                break;
        case TIMER_PTIMER:
-               write_sysreg_el0(ctx->cnt_cval, cntp_cval);
+               write_sysreg_el0(ctx->cnt_cval, SYS_CNTP_CVAL);
                isb();
-               write_sysreg_el0(ctx->cnt_ctl, cntp_ctl);
+               write_sysreg_el0(ctx->cnt_ctl, SYS_CNTP_CTL);
                break;
        case NR_KVM_TIMERS:
                BUG();
index bd5c559..f645c0f 100644 (file)
@@ -93,9 +93,9 @@ int kvm_arch_hardware_setup(void)
        return 0;
 }
 
-void kvm_arch_check_processor_compat(void *rtn)
+int kvm_arch_check_processor_compat(void)
 {
-       *(int *)rtn = 0;
+       return 0;
 }
 
 
@@ -1332,6 +1332,8 @@ static void cpu_hyp_reset(void)
 
 static void cpu_hyp_reinit(void)
 {
+       kvm_init_host_cpu_context(&this_cpu_ptr(&kvm_host_data)->host_ctxt);
+
        cpu_hyp_reset();
 
        if (is_kernel_in_hyp_mode())
@@ -1569,7 +1571,6 @@ static int init_hyp_mode(void)
                kvm_host_data_t *cpu_data;
 
                cpu_data = per_cpu_ptr(&kvm_host_data, cpu);
-               kvm_init_host_cpu_context(&cpu_data->host_ctxt, cpu);
                err = create_hyp_mappings(cpu_data, cpu_data + 1, PAGE_HYP);
 
                if (err) {
index 198e517..38b4c91 100644 (file)
@@ -129,7 +129,7 @@ static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache,
        if (cache->nobjs >= min)
                return 0;
        while (cache->nobjs < max) {
-               page = (void *)__get_free_page(PGALLOC_GFP);
+               page = (void *)__get_free_page(GFP_PGTABLE_USER);
                if (!page)
                        return -ENOMEM;
                cache->objects[cache->nobjs++] = page;
index da74076..3dd8238 100644 (file)
 #include <kvm/arm_pmu.h>
 #include <kvm/arm_vgic.h>
 
+static void kvm_pmu_create_perf_event(struct kvm_vcpu *vcpu, u64 select_idx);
+
+#define PERF_ATTR_CFG1_KVM_PMU_CHAINED 0x1
+
 /**
- * kvm_pmu_get_counter_value - get PMU counter value
+ * kvm_pmu_idx_is_64bit - determine if select_idx is a 64bit counter
  * @vcpu: The vcpu pointer
  * @select_idx: The counter index
  */
-u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
+static bool kvm_pmu_idx_is_64bit(struct kvm_vcpu *vcpu, u64 select_idx)
 {
-       u64 counter, reg, enabled, running;
-       struct kvm_pmu *pmu = &vcpu->arch.pmu;
-       struct kvm_pmc *pmc = &pmu->pmc[select_idx];
+       return (select_idx == ARMV8_PMU_CYCLE_IDX &&
+               __vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_LC);
+}
 
-       reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
-             ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
-       counter = __vcpu_sys_reg(vcpu, reg);
+static struct kvm_vcpu *kvm_pmc_to_vcpu(struct kvm_pmc *pmc)
+{
+       struct kvm_pmu *pmu;
+       struct kvm_vcpu_arch *vcpu_arch;
+
+       pmc -= pmc->idx;
+       pmu = container_of(pmc, struct kvm_pmu, pmc[0]);
+       vcpu_arch = container_of(pmu, struct kvm_vcpu_arch, pmu);
+       return container_of(vcpu_arch, struct kvm_vcpu, arch);
+}
+
+/**
+ * kvm_pmu_pmc_is_chained - determine if the pmc is chained
+ * @pmc: The PMU counter pointer
+ */
+static bool kvm_pmu_pmc_is_chained(struct kvm_pmc *pmc)
+{
+       struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
 
-       /* The real counter value is equal to the value of counter register plus
+       return test_bit(pmc->idx >> 1, vcpu->arch.pmu.chained);
+}
+
+/**
+ * kvm_pmu_idx_is_high_counter - determine if select_idx is a high/low counter
+ * @select_idx: The counter index
+ */
+static bool kvm_pmu_idx_is_high_counter(u64 select_idx)
+{
+       return select_idx & 0x1;
+}
+
+/**
+ * kvm_pmu_get_canonical_pmc - obtain the canonical pmc
+ * @pmc: The PMU counter pointer
+ *
+ * When a pair of PMCs are chained together we use the low counter (canonical)
+ * to hold the underlying perf event.
+ */
+static struct kvm_pmc *kvm_pmu_get_canonical_pmc(struct kvm_pmc *pmc)
+{
+       if (kvm_pmu_pmc_is_chained(pmc) &&
+           kvm_pmu_idx_is_high_counter(pmc->idx))
+               return pmc - 1;
+
+       return pmc;
+}
+
+/**
+ * kvm_pmu_idx_has_chain_evtype - determine if the event type is chain
+ * @vcpu: The vcpu pointer
+ * @select_idx: The counter index
+ */
+static bool kvm_pmu_idx_has_chain_evtype(struct kvm_vcpu *vcpu, u64 select_idx)
+{
+       u64 eventsel, reg;
+
+       select_idx |= 0x1;
+
+       if (select_idx == ARMV8_PMU_CYCLE_IDX)
+               return false;
+
+       reg = PMEVTYPER0_EL0 + select_idx;
+       eventsel = __vcpu_sys_reg(vcpu, reg) & ARMV8_PMU_EVTYPE_EVENT;
+
+       return eventsel == ARMV8_PMUV3_PERFCTR_CHAIN;
+}
+
+/**
+ * kvm_pmu_get_pair_counter_value - get PMU counter value
+ * @vcpu: The vcpu pointer
+ * @pmc: The PMU counter pointer
+ */
+static u64 kvm_pmu_get_pair_counter_value(struct kvm_vcpu *vcpu,
+                                         struct kvm_pmc *pmc)
+{
+       u64 counter, counter_high, reg, enabled, running;
+
+       if (kvm_pmu_pmc_is_chained(pmc)) {
+               pmc = kvm_pmu_get_canonical_pmc(pmc);
+               reg = PMEVCNTR0_EL0 + pmc->idx;
+
+               counter = __vcpu_sys_reg(vcpu, reg);
+               counter_high = __vcpu_sys_reg(vcpu, reg + 1);
+
+               counter = lower_32_bits(counter) | (counter_high << 32);
+       } else {
+               reg = (pmc->idx == ARMV8_PMU_CYCLE_IDX)
+                     ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + pmc->idx;
+               counter = __vcpu_sys_reg(vcpu, reg);
+       }
+
+       /*
+        * The real counter value is equal to the value of counter register plus
         * the value perf event counts.
         */
        if (pmc->perf_event)
                counter += perf_event_read_value(pmc->perf_event, &enabled,
                                                 &running);
 
-       return counter & pmc->bitmask;
+       return counter;
+}
+
+/**
+ * kvm_pmu_get_counter_value - get PMU counter value
+ * @vcpu: The vcpu pointer
+ * @select_idx: The counter index
+ */
+u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
+{
+       u64 counter;
+       struct kvm_pmu *pmu = &vcpu->arch.pmu;
+       struct kvm_pmc *pmc = &pmu->pmc[select_idx];
+
+       counter = kvm_pmu_get_pair_counter_value(vcpu, pmc);
+
+       if (kvm_pmu_pmc_is_chained(pmc) &&
+           kvm_pmu_idx_is_high_counter(select_idx))
+               counter = upper_32_bits(counter);
+
+       else if (!kvm_pmu_idx_is_64bit(vcpu, select_idx))
+               counter = lower_32_bits(counter);
+
+       return counter;
 }
 
 /**
@@ -51,6 +166,23 @@ void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val)
        reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
              ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
        __vcpu_sys_reg(vcpu, reg) += (s64)val - kvm_pmu_get_counter_value(vcpu, select_idx);
+
+       /* Recreate the perf event to reflect the updated sample_period */
+       kvm_pmu_create_perf_event(vcpu, select_idx);
+}
+
+/**
+ * kvm_pmu_release_perf_event - remove the perf event
+ * @pmc: The PMU counter pointer
+ */
+static void kvm_pmu_release_perf_event(struct kvm_pmc *pmc)
+{
+       pmc = kvm_pmu_get_canonical_pmc(pmc);
+       if (pmc->perf_event) {
+               perf_event_disable(pmc->perf_event);
+               perf_event_release_kernel(pmc->perf_event);
+               pmc->perf_event = NULL;
+       }
 }
 
 /**
@@ -63,15 +195,23 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
 {
        u64 counter, reg;
 
-       if (pmc->perf_event) {
-               counter = kvm_pmu_get_counter_value(vcpu, pmc->idx);
+       pmc = kvm_pmu_get_canonical_pmc(pmc);
+       if (!pmc->perf_event)
+               return;
+
+       counter = kvm_pmu_get_pair_counter_value(vcpu, pmc);
+
+       if (kvm_pmu_pmc_is_chained(pmc)) {
+               reg = PMEVCNTR0_EL0 + pmc->idx;
+               __vcpu_sys_reg(vcpu, reg) = lower_32_bits(counter);
+               __vcpu_sys_reg(vcpu, reg + 1) = upper_32_bits(counter);
+       } else {
                reg = (pmc->idx == ARMV8_PMU_CYCLE_IDX)
                       ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + pmc->idx;
-               __vcpu_sys_reg(vcpu, reg) = counter;
-               perf_event_disable(pmc->perf_event);
-               perf_event_release_kernel(pmc->perf_event);
-               pmc->perf_event = NULL;
+               __vcpu_sys_reg(vcpu, reg) = lower_32_bits(counter);
        }
+
+       kvm_pmu_release_perf_event(pmc);
 }
 
 /**
@@ -87,8 +227,9 @@ void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu)
        for (i = 0; i < ARMV8_PMU_MAX_COUNTERS; i++) {
                kvm_pmu_stop_counter(vcpu, &pmu->pmc[i]);
                pmu->pmc[i].idx = i;
-               pmu->pmc[i].bitmask = 0xffffffffUL;
        }
+
+       bitmap_zero(vcpu->arch.pmu.chained, ARMV8_PMU_MAX_COUNTER_PAIRS);
 }
 
 /**
@@ -101,15 +242,8 @@ void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu)
        int i;
        struct kvm_pmu *pmu = &vcpu->arch.pmu;
 
-       for (i = 0; i < ARMV8_PMU_MAX_COUNTERS; i++) {
-               struct kvm_pmc *pmc = &pmu->pmc[i];
-
-               if (pmc->perf_event) {
-                       perf_event_disable(pmc->perf_event);
-                       perf_event_release_kernel(pmc->perf_event);
-                       pmc->perf_event = NULL;
-               }
-       }
+       for (i = 0; i < ARMV8_PMU_MAX_COUNTERS; i++)
+               kvm_pmu_release_perf_event(&pmu->pmc[i]);
 }
 
 u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
@@ -124,13 +258,13 @@ u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
 }
 
 /**
- * kvm_pmu_enable_counter - enable selected PMU counter
+ * kvm_pmu_enable_counter_mask - enable selected PMU counters
  * @vcpu: The vcpu pointer
  * @val: the value guest writes to PMCNTENSET register
  *
  * Call perf_event_enable to start counting the perf event
  */
-void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val)
+void kvm_pmu_enable_counter_mask(struct kvm_vcpu *vcpu, u64 val)
 {
        int i;
        struct kvm_pmu *pmu = &vcpu->arch.pmu;
@@ -144,6 +278,18 @@ void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val)
                        continue;
 
                pmc = &pmu->pmc[i];
+
+               /*
+                * For high counters of chained events we must recreate the
+                * perf event with the long (64bit) attribute set.
+                */
+               if (kvm_pmu_pmc_is_chained(pmc) &&
+                   kvm_pmu_idx_is_high_counter(i)) {
+                       kvm_pmu_create_perf_event(vcpu, i);
+                       continue;
+               }
+
+               /* At this point, pmc must be the canonical */
                if (pmc->perf_event) {
                        perf_event_enable(pmc->perf_event);
                        if (pmc->perf_event->state != PERF_EVENT_STATE_ACTIVE)
@@ -153,13 +299,13 @@ void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val)
 }
 
 /**
- * kvm_pmu_disable_counter - disable selected PMU counter
+ * kvm_pmu_disable_counter_mask - disable selected PMU counters
  * @vcpu: The vcpu pointer
  * @val: the value guest writes to PMCNTENCLR register
  *
  * Call perf_event_disable to stop counting the perf event
  */
-void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val)
+void kvm_pmu_disable_counter_mask(struct kvm_vcpu *vcpu, u64 val)
 {
        int i;
        struct kvm_pmu *pmu = &vcpu->arch.pmu;
@@ -173,6 +319,18 @@ void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val)
                        continue;
 
                pmc = &pmu->pmc[i];
+
+               /*
+                * For high counters of chained events we must recreate the
+                * perf event with the long (64bit) attribute unset.
+                */
+               if (kvm_pmu_pmc_is_chained(pmc) &&
+                   kvm_pmu_idx_is_high_counter(i)) {
+                       kvm_pmu_create_perf_event(vcpu, i);
+                       continue;
+               }
+
+               /* At this point, pmc must be the canonical */
                if (pmc->perf_event)
                        perf_event_disable(pmc->perf_event);
        }
@@ -262,17 +420,6 @@ void kvm_pmu_sync_hwstate(struct kvm_vcpu *vcpu)
        kvm_pmu_update_state(vcpu);
 }
 
-static inline struct kvm_vcpu *kvm_pmc_to_vcpu(struct kvm_pmc *pmc)
-{
-       struct kvm_pmu *pmu;
-       struct kvm_vcpu_arch *vcpu_arch;
-
-       pmc -= pmc->idx;
-       pmu = container_of(pmc, struct kvm_pmu, pmc[0]);
-       vcpu_arch = container_of(pmu, struct kvm_vcpu_arch, pmu);
-       return container_of(vcpu_arch, struct kvm_vcpu, arch);
-}
-
 /**
  * When the perf event overflows, set the overflow status and inform the vcpu.
  */
@@ -329,17 +476,15 @@ void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
  */
 void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
 {
-       struct kvm_pmu *pmu = &vcpu->arch.pmu;
-       struct kvm_pmc *pmc;
        u64 mask;
        int i;
 
        mask = kvm_pmu_valid_counter_mask(vcpu);
        if (val & ARMV8_PMU_PMCR_E) {
-               kvm_pmu_enable_counter(vcpu,
+               kvm_pmu_enable_counter_mask(vcpu,
                       __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask);
        } else {
-               kvm_pmu_disable_counter(vcpu, mask);
+               kvm_pmu_disable_counter_mask(vcpu, mask);
        }
 
        if (val & ARMV8_PMU_PMCR_C)
@@ -349,11 +494,6 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
                for (i = 0; i < ARMV8_PMU_CYCLE_IDX; i++)
                        kvm_pmu_set_counter_value(vcpu, i, 0);
        }
-
-       if (val & ARMV8_PMU_PMCR_LC) {
-               pmc = &pmu->pmc[ARMV8_PMU_CYCLE_IDX];
-               pmc->bitmask = 0xffffffffffffffffUL;
-       }
 }
 
 static bool kvm_pmu_counter_is_enabled(struct kvm_vcpu *vcpu, u64 select_idx)
@@ -363,50 +503,75 @@ static bool kvm_pmu_counter_is_enabled(struct kvm_vcpu *vcpu, u64 select_idx)
 }
 
 /**
- * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
+ * kvm_pmu_create_perf_event - create a perf event for a counter
  * @vcpu: The vcpu pointer
- * @data: The data guest writes to PMXEVTYPER_EL0
  * @select_idx: The number of selected counter
- *
- * When OS accesses PMXEVTYPER_EL0, that means it wants to set a PMC to count an
- * event with given hardware event number. Here we call perf_event API to
- * emulate this action and create a kernel perf event for it.
  */
-void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
-                                   u64 select_idx)
+static void kvm_pmu_create_perf_event(struct kvm_vcpu *vcpu, u64 select_idx)
 {
        struct kvm_pmu *pmu = &vcpu->arch.pmu;
-       struct kvm_pmc *pmc = &pmu->pmc[select_idx];
+       struct kvm_pmc *pmc;
        struct perf_event *event;
        struct perf_event_attr attr;
-       u64 eventsel, counter;
+       u64 eventsel, counter, reg, data;
+
+       /*
+        * For chained counters the event type and filtering attributes are
+        * obtained from the low/even counter. We also use this counter to
+        * determine if the event is enabled/disabled.
+        */
+       pmc = kvm_pmu_get_canonical_pmc(&pmu->pmc[select_idx]);
+
+       reg = (pmc->idx == ARMV8_PMU_CYCLE_IDX)
+             ? PMCCFILTR_EL0 : PMEVTYPER0_EL0 + pmc->idx;
+       data = __vcpu_sys_reg(vcpu, reg);
 
        kvm_pmu_stop_counter(vcpu, pmc);
        eventsel = data & ARMV8_PMU_EVTYPE_EVENT;
 
        /* Software increment event does't need to be backed by a perf event */
        if (eventsel == ARMV8_PMUV3_PERFCTR_SW_INCR &&
-           select_idx != ARMV8_PMU_CYCLE_IDX)
+           pmc->idx != ARMV8_PMU_CYCLE_IDX)
                return;
 
        memset(&attr, 0, sizeof(struct perf_event_attr));
        attr.type = PERF_TYPE_RAW;
        attr.size = sizeof(attr);
        attr.pinned = 1;
-       attr.disabled = !kvm_pmu_counter_is_enabled(vcpu, select_idx);
+       attr.disabled = !kvm_pmu_counter_is_enabled(vcpu, pmc->idx);
        attr.exclude_user = data & ARMV8_PMU_EXCLUDE_EL0 ? 1 : 0;
        attr.exclude_kernel = data & ARMV8_PMU_EXCLUDE_EL1 ? 1 : 0;
        attr.exclude_hv = 1; /* Don't count EL2 events */
        attr.exclude_host = 1; /* Don't count host events */
-       attr.config = (select_idx == ARMV8_PMU_CYCLE_IDX) ?
+       attr.config = (pmc->idx == ARMV8_PMU_CYCLE_IDX) ?
                ARMV8_PMUV3_PERFCTR_CPU_CYCLES : eventsel;
 
-       counter = kvm_pmu_get_counter_value(vcpu, select_idx);
-       /* The initial sample period (overflow count) of an event. */
-       attr.sample_period = (-counter) & pmc->bitmask;
+       counter = kvm_pmu_get_pair_counter_value(vcpu, pmc);
 
-       event = perf_event_create_kernel_counter(&attr, -1, current,
+       if (kvm_pmu_idx_has_chain_evtype(vcpu, pmc->idx)) {
+               /**
+                * The initial sample period (overflow count) of an event. For
+                * chained counters we only support overflow interrupts on the
+                * high counter.
+                */
+               attr.sample_period = (-counter) & GENMASK(63, 0);
+               event = perf_event_create_kernel_counter(&attr, -1, current,
+                                                        kvm_pmu_perf_overflow,
+                                                        pmc + 1);
+
+               if (kvm_pmu_counter_is_enabled(vcpu, pmc->idx + 1))
+                       attr.config1 |= PERF_ATTR_CFG1_KVM_PMU_CHAINED;
+       } else {
+               /* The initial sample period (overflow count) of an event. */
+               if (kvm_pmu_idx_is_64bit(vcpu, pmc->idx))
+                       attr.sample_period = (-counter) & GENMASK(63, 0);
+               else
+                       attr.sample_period = (-counter) & GENMASK(31, 0);
+
+               event = perf_event_create_kernel_counter(&attr, -1, current,
                                                 kvm_pmu_perf_overflow, pmc);
+       }
+
        if (IS_ERR(event)) {
                pr_err_once("kvm: pmu event creation failed %ld\n",
                            PTR_ERR(event));
@@ -416,6 +581,57 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
        pmc->perf_event = event;
 }
 
+/**
+ * kvm_pmu_update_pmc_chained - update chained bitmap
+ * @vcpu: The vcpu pointer
+ * @select_idx: The number of selected counter
+ *
+ * Update the chained bitmap based on the event type written in the
+ * typer register.
+ */
+static void kvm_pmu_update_pmc_chained(struct kvm_vcpu *vcpu, u64 select_idx)
+{
+       struct kvm_pmu *pmu = &vcpu->arch.pmu;
+       struct kvm_pmc *pmc = &pmu->pmc[select_idx];
+
+       if (kvm_pmu_idx_has_chain_evtype(vcpu, pmc->idx)) {
+               /*
+                * During promotion from !chained to chained we must ensure
+                * the adjacent counter is stopped and its event destroyed
+                */
+               if (!kvm_pmu_pmc_is_chained(pmc))
+                       kvm_pmu_stop_counter(vcpu, pmc);
+
+               set_bit(pmc->idx >> 1, vcpu->arch.pmu.chained);
+       } else {
+               clear_bit(pmc->idx >> 1, vcpu->arch.pmu.chained);
+       }
+}
+
+/**
+ * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
+ * @vcpu: The vcpu pointer
+ * @data: The data guest writes to PMXEVTYPER_EL0
+ * @select_idx: The number of selected counter
+ *
+ * When OS accesses PMXEVTYPER_EL0, that means it wants to set a PMC to count an
+ * event with given hardware event number. Here we call perf_event API to
+ * emulate this action and create a kernel perf event for it.
+ */
+void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
+                                   u64 select_idx)
+{
+       u64 reg, event_type = data & ARMV8_PMU_EVTYPE_MASK;
+
+       reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
+             ? PMCCFILTR_EL0 : PMEVTYPER0_EL0 + select_idx;
+
+       __vcpu_sys_reg(vcpu, reg) = event_type;
+
+       kvm_pmu_update_pmc_chained(vcpu, select_idx);
+       kvm_pmu_create_perf_event(vcpu, select_idx);
+}
+
 bool kvm_arm_support_pmu_v3(void)
 {
        /*
index be3c9cd..87927f7 100644 (file)
@@ -401,8 +401,16 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
                feature = smccc_get_arg1(vcpu);
                switch(feature) {
                case ARM_SMCCC_ARCH_WORKAROUND_1:
-                       if (kvm_arm_harden_branch_predictor())
+                       switch (kvm_arm_harden_branch_predictor()) {
+                       case KVM_BP_HARDEN_UNKNOWN:
+                               break;
+                       case KVM_BP_HARDEN_WA_NEEDED:
                                val = SMCCC_RET_SUCCESS;
+                               break;
+                       case KVM_BP_HARDEN_NOT_REQUIRED:
+                               val = SMCCC_RET_NOT_REQUIRED;
+                               break;
+                       }
                        break;
                case ARM_SMCCC_ARCH_WORKAROUND_2:
                        switch (kvm_arm_have_ssbd()) {
@@ -430,42 +438,103 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 
 int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
 {
-       return 1;               /* PSCI version */
+       return 3;               /* PSCI version and two workaround registers */
 }
 
 int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 {
-       if (put_user(KVM_REG_ARM_PSCI_VERSION, uindices))
+       if (put_user(KVM_REG_ARM_PSCI_VERSION, uindices++))
+               return -EFAULT;
+
+       if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1, uindices++))
+               return -EFAULT;
+
+       if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2, uindices++))
                return -EFAULT;
 
        return 0;
 }
 
+#define KVM_REG_FEATURE_LEVEL_WIDTH    4
+#define KVM_REG_FEATURE_LEVEL_MASK     (BIT(KVM_REG_FEATURE_LEVEL_WIDTH) - 1)
+
+/*
+ * Convert the workaround level into an easy-to-compare number, where higher
+ * values mean better protection.
+ */
+static int get_kernel_wa_level(u64 regid)
+{
+       switch (regid) {
+       case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
+               switch (kvm_arm_harden_branch_predictor()) {
+               case KVM_BP_HARDEN_UNKNOWN:
+                       return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
+               case KVM_BP_HARDEN_WA_NEEDED:
+                       return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL;
+               case KVM_BP_HARDEN_NOT_REQUIRED:
+                       return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED;
+               }
+               return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
+       case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
+               switch (kvm_arm_have_ssbd()) {
+               case KVM_SSBD_FORCE_DISABLE:
+                       return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
+               case KVM_SSBD_KERNEL:
+                       return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL;
+               case KVM_SSBD_FORCE_ENABLE:
+               case KVM_SSBD_MITIGATED:
+                       return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
+               case KVM_SSBD_UNKNOWN:
+               default:
+                       return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN;
+               }
+       }
+
+       return -EINVAL;
+}
+
 int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
-       if (reg->id == KVM_REG_ARM_PSCI_VERSION) {
-               void __user *uaddr = (void __user *)(long)reg->addr;
-               u64 val;
+       void __user *uaddr = (void __user *)(long)reg->addr;
+       u64 val;
 
+       switch (reg->id) {
+       case KVM_REG_ARM_PSCI_VERSION:
                val = kvm_psci_version(vcpu, vcpu->kvm);
-               if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)))
-                       return -EFAULT;
+               break;
+       case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
+               val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
+               break;
+       case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
+               val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
 
-               return 0;
+               if (val == KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL &&
+                   kvm_arm_get_vcpu_workaround_2_flag(vcpu))
+                       val |= KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED;
+               break;
+       default:
+               return -ENOENT;
        }
 
-       return -EINVAL;
+       if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)))
+               return -EFAULT;
+
+       return 0;
 }
 
 int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
-       if (reg->id == KVM_REG_ARM_PSCI_VERSION) {
-               void __user *uaddr = (void __user *)(long)reg->addr;
-               bool wants_02;
-               u64 val;
+       void __user *uaddr = (void __user *)(long)reg->addr;
+       u64 val;
+       int wa_level;
 
-               if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)))
-                       return -EFAULT;
+       if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)))
+               return -EFAULT;
+
+       switch (reg->id) {
+       case KVM_REG_ARM_PSCI_VERSION:
+       {
+               bool wants_02;
 
                wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features);
 
@@ -482,6 +551,54 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
                        vcpu->kvm->arch.psci_version = val;
                        return 0;
                }
+               break;
+       }
+
+       case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
+               if (val & ~KVM_REG_FEATURE_LEVEL_MASK)
+                       return -EINVAL;
+
+               if (get_kernel_wa_level(reg->id) < val)
+                       return -EINVAL;
+
+               return 0;
+
+       case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
+               if (val & ~(KVM_REG_FEATURE_LEVEL_MASK |
+                           KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED))
+                       return -EINVAL;
+
+               wa_level = val & KVM_REG_FEATURE_LEVEL_MASK;
+
+               if (get_kernel_wa_level(reg->id) < wa_level)
+                       return -EINVAL;
+
+               /* The enabled bit must not be set unless the level is AVAIL. */
+               if (wa_level != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL &&
+                   wa_level != val)
+                       return -EINVAL;
+
+               /* Are we finished or do we need to check the enable bit ? */
+               if (kvm_arm_have_ssbd() != KVM_SSBD_KERNEL)
+                       return 0;
+
+               /*
+                * If this kernel supports the workaround to be switched on
+                * or off, make sure it matches the requested setting.
+                */
+               switch (wa_level) {
+               case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL:
+                       kvm_arm_set_vcpu_workaround_2_flag(vcpu,
+                           val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED);
+                       break;
+               case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
+                       kvm_arm_set_vcpu_workaround_2_flag(vcpu, true);
+                       break;
+               }
+
+               return 0;
+       default:
+               return -ENOENT;
        }
 
        return -EINVAL;
index 2e6fc7c..58e4f88 100644 (file)
@@ -184,9 +184,7 @@ int kvm_set_irq_routing(struct kvm *kvm,
 
        nr_rt_entries += 1;
 
-       new = kzalloc(sizeof(*new) + (nr_rt_entries * sizeof(struct hlist_head)),
-                     GFP_KERNEL_ACCOUNT);
-
+       new = kzalloc(struct_size(new, map, nr_rt_entries), GFP_KERNEL_ACCOUNT);
        if (!new)
                return -ENOMEM;
 
index 2f2d24a..b4ab59d 100644 (file)
@@ -95,7 +95,7 @@ EXPORT_SYMBOL_GPL(halt_poll_ns_shrink);
  *     kvm->lock --> kvm->slots_lock --> kvm->irq_lock
  */
 
-DEFINE_SPINLOCK(kvm_lock);
+DEFINE_MUTEX(kvm_lock);
 static DEFINE_RAW_SPINLOCK(kvm_count_lock);
 LIST_HEAD(vm_list);
 
@@ -680,9 +680,9 @@ static struct kvm *kvm_create_vm(unsigned long type)
        if (r)
                goto out_err;
 
-       spin_lock(&kvm_lock);
+       mutex_lock(&kvm_lock);
        list_add(&kvm->vm_list, &vm_list);
-       spin_unlock(&kvm_lock);
+       mutex_unlock(&kvm_lock);
 
        preempt_notifier_inc();
 
@@ -728,9 +728,9 @@ static void kvm_destroy_vm(struct kvm *kvm)
        kvm_uevent_notify_change(KVM_EVENT_DESTROY_VM, kvm);
        kvm_destroy_vm_debugfs(kvm);
        kvm_arch_sync_events(kvm);
-       spin_lock(&kvm_lock);
+       mutex_lock(&kvm_lock);
        list_del(&kvm->vm_list);
-       spin_unlock(&kvm_lock);
+       mutex_unlock(&kvm_lock);
        kvm_free_irq_routing(kvm);
        for (i = 0; i < KVM_NR_BUSES; i++) {
                struct kvm_io_bus *bus = kvm_get_bus(kvm, i);
@@ -1790,7 +1790,7 @@ void kvm_vcpu_unmap(struct kvm_vcpu *vcpu, struct kvm_host_map *map,
        if (!map->hva)
                return;
 
-       if (map->page)
+       if (map->page != KVM_UNMAPPED_PAGE)
                kunmap(map->page);
 #ifdef CONFIG_HAS_IOMEM
        else
@@ -4031,13 +4031,13 @@ static int vm_stat_get(void *_offset, u64 *val)
        u64 tmp_val;
 
        *val = 0;
-       spin_lock(&kvm_lock);
+       mutex_lock(&kvm_lock);
        list_for_each_entry(kvm, &vm_list, vm_list) {
                stat_tmp.kvm = kvm;
                vm_stat_get_per_vm((void *)&stat_tmp, &tmp_val);
                *val += tmp_val;
        }
-       spin_unlock(&kvm_lock);
+       mutex_unlock(&kvm_lock);
        return 0;
 }
 
@@ -4050,12 +4050,12 @@ static int vm_stat_clear(void *_offset, u64 val)
        if (val)
                return -EINVAL;
 
-       spin_lock(&kvm_lock);
+       mutex_lock(&kvm_lock);
        list_for_each_entry(kvm, &vm_list, vm_list) {
                stat_tmp.kvm = kvm;
                vm_stat_clear_per_vm((void *)&stat_tmp, 0);
        }
-       spin_unlock(&kvm_lock);
+       mutex_unlock(&kvm_lock);
 
        return 0;
 }
@@ -4070,13 +4070,13 @@ static int vcpu_stat_get(void *_offset, u64 *val)
        u64 tmp_val;
 
        *val = 0;
-       spin_lock(&kvm_lock);
+       mutex_lock(&kvm_lock);
        list_for_each_entry(kvm, &vm_list, vm_list) {
                stat_tmp.kvm = kvm;
                vcpu_stat_get_per_vm((void *)&stat_tmp, &tmp_val);
                *val += tmp_val;
        }
-       spin_unlock(&kvm_lock);
+       mutex_unlock(&kvm_lock);
        return 0;
 }
 
@@ -4089,12 +4089,12 @@ static int vcpu_stat_clear(void *_offset, u64 val)
        if (val)
                return -EINVAL;
 
-       spin_lock(&kvm_lock);
+       mutex_lock(&kvm_lock);
        list_for_each_entry(kvm, &vm_list, vm_list) {
                stat_tmp.kvm = kvm;
                vcpu_stat_clear_per_vm((void *)&stat_tmp, 0);
        }
-       spin_unlock(&kvm_lock);
+       mutex_unlock(&kvm_lock);
 
        return 0;
 }
@@ -4115,7 +4115,7 @@ static void kvm_uevent_notify_change(unsigned int type, struct kvm *kvm)
        if (!kvm_dev.this_device || !kvm)
                return;
 
-       spin_lock(&kvm_lock);
+       mutex_lock(&kvm_lock);
        if (type == KVM_EVENT_CREATE_VM) {
                kvm_createvm_count++;
                kvm_active_vms++;
@@ -4124,7 +4124,7 @@ static void kvm_uevent_notify_change(unsigned int type, struct kvm *kvm)
        }
        created = kvm_createvm_count;
        active = kvm_active_vms;
-       spin_unlock(&kvm_lock);
+       mutex_unlock(&kvm_lock);
 
        env = kzalloc(sizeof(*env), GFP_KERNEL_ACCOUNT);
        if (!env)
@@ -4221,6 +4221,11 @@ static void kvm_sched_out(struct preempt_notifier *pn,
        kvm_arch_vcpu_put(vcpu);
 }
 
+static void check_processor_compat(void *rtn)
+{
+       *(int *)rtn = kvm_arch_check_processor_compat();
+}
+
 int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align,
                  struct module *module)
 {
@@ -4252,9 +4257,7 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align,
                goto out_free_0a;
 
        for_each_online_cpu(cpu) {
-               smp_call_function_single(cpu,
-                               kvm_arch_check_processor_compat,
-                               &r, 1);
+               smp_call_function_single(cpu, check_processor_compat, &r, 1);
                if (r < 0)
                        goto out_free_1;
        }